diff -u --recursive --new-file v2.1.22/linux/CREDITS linux/CREDITS
--- v2.1.22/linux/CREDITS	Wed Jan 15 19:45:38 1997
+++ linux/CREDITS	Sun Jan 26 12:07:03 1997
@@ -664,6 +664,15 @@
 S: RG6 2NU
 S: United Kingdom
 
+N: Jakub Jelinek
+E: jj@sunsite.mff.cuni.cz
+W: http://sunsite.mff.cuni.cz/~jj
+D: Sparc hacker, SILO, mc
+D: Maintain sunsite.mff.cuni.cz
+S: Na Orechovce 7
+S: 160 00 Praha 6
+S: Czech Republic
+
 N: Michael K. Johnson
 E: johnsonm@redhat.com
 W: http://www.redhat.com/~johnsonm
diff -u --recursive --new-file v2.1.22/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.1.22/linux/Documentation/Configure.help	Thu Jan 23 21:06:45 1997
+++ linux/Documentation/Configure.help	Sat Jan 25 20:52:22 1997
@@ -31,16 +31,18 @@
 #
 # If you add a help text to this file, please try to be as gentle as
 # possible. Don't use unexplained acronyms and generally write for the
-# hypothetical user who has just bought a PC, removed Windows,
-# installed Linux and is now recompiling the kernel for the first
-# time. Tell them what to do if they're unsure. Technical information
-# should go in a README in the Documentation directory. Mention all 
-# the relevant READMEs and HOWTOs in the help text.
+# hypothetical ignorant but intelligent user who has just bought a PC,
+# removed Windows, installed Linux and is now recompiling the kernel
+# for the first time. Tell them what to do if they're
+# unsure. Technical information should go in a README in the
+# Documentation directory. Mention all the relevant READMEs and HOWTOs
+# in the help text.
 #
 # All this was shamelessly stolen from several different sources. Many
 # thanks to all the contributors.  Feel free to use these help texts
 # in your own kernel configuration tools. The texts are copyrighted
-# (c) 1995,1996 by Axel Boldt and governed by the GNU Public License.
+# (c) 1995-1997 by Axel Boldt and others and governed by the GNU
+# Public License.
 
 Prompt for development and/or incomplete code/drivers
 CONFIG_EXPERIMENTAL
@@ -54,14 +56,17 @@
   avoid "Why doesn't this work?" type mail messages. However, active
   testing and use of these systems is welcomed. Just be aware that it
   may not meet the normal level of reliability or it may fail to work
-  in some special cases. Detailed bug reports from people familiar with
-  the kernel internals are usually welcomed by the developers. 
+  in some special cases. Detailed bug reports from people familiar
+  with the kernel internals are usually welcomed by the developers
+  (before submitting bug reports, please read the documents README,
+  MAINTAINERS, Documentation/BUG-HUNTING, and
+  Documentation/oops-tracing.txt in the kernel source).  
   Unless you intend to help test and develop a feature or driver that
-  falls into this category, or you have a situation that requires using 
-  these features you should probably say N here, which will cause this 
-  configure script to present you with fewer choices. If you say Y here,
-  you will be offered the choice of using features or drivers that are
-  currently considered to be in the alpha-test phase.
+  falls into this category, or you have a situation that requires
+  using these features you should probably say N here, which will
+  cause this configure script to present you with fewer choices. If
+  you say Y here, you will be offered the choice of using features or
+  drivers that are currently considered to be in the alpha-test phase.
 
 Kernel math emulation
 CONFIG_MATH_EMULATION
@@ -70,61 +75,65 @@
   a math coprocessor built in, 486SX and 386 do not, unless you added
   a 487DX or 387, respectively.  (The messages during boot time can
   give you some hints here ["man dmesg"]) Everyone needs either a
-  coprocessor or this emulation. If you enable this emulation even
+  coprocessor or this emulation. If you say Y here even
   though you have a coprocessor, the coprocessor will be used
   nevertheless. (This behavior can be changed with the kernel command
   line option "no387", which comes handy if your coprocessor is
-  broken. See the documentation of your boot loader (lilo or loadlin)
-  about how to pass options to the kernel at boot time. The lilo
-  procedure is also explained in the SCSI-HOWTO, available via ftp
-  (user: anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO.) This
-  means that it is a good idea to say Y here if you intend to use this
-  kernel on different machines. More information about the internals
-  of Linux math coprocessor emulation can be found in
-  arch/i386/math-emu/README. If you are not sure, say Y; apart from
-  resulting in a 45kB bigger kernel, it won't hurt.
+  broken. Try "man bootparam" or see the documentation of your boot
+  loader (lilo or loadlin) about how to pass options to the kernel at
+  boot time. The lilo procedure is also explained in the SCSI-HOWTO,
+  available via ftp (user: anonymous) in
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO.) This means that it is a good
+  idea to say Y here if you intend to use this kernel on different
+  machines. More information about the internals of Linux math
+  coprocessor emulation can be found in arch/i386/math-emu/README. If
+  you are not sure, say Y; apart from resulting in a 45kB bigger
+  kernel, it won't hurt.
 
 Normal floppy disk support
 CONFIG_BLK_DEV_FD
   If you want to use your floppy disk drive(s) under Linux, say
   Y. Information about this driver, especially important for IBM
-  Thinkpad users, is contained in drivers/block/README.fd.  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
+  Thinkpad users, is contained in drivers/block/README.fd. This file
+  also contains the location of the Floppy driver FAQ as well as
+  location of the fdutils package used to configure additional
+  parameters of the driver at run time. This driver is also available
+  as a module ( = code which can be inserted in and removed from the
+  running kernel whenever you want). The module will be called
+  floppy.o. If you want to compile it as a module, say M here and read
   Documentation/modules.txt.
   
 RAM disk support
 CONFIG_BLK_DEV_RAM
-  Enabling this option will allow you to use a portion of your RAM
-  memory as a block device, so that you can make filesystems on it,
-  read and write to it and do all the other things that normal block
-  devices (such as harddrives) can do.  It is usually used to load and
+  Saying Y here will allow you to use a portion of your RAM memory as
+  a block device, so that you can make filesystems on it, read and
+  write to it and do all the other things that you can do with normal
+  block devices (such as harddrives).  It is usually used to load and
   store a copy of a minimal root file system off of a floppy into RAM
   during the initial install of Linux.  Note that the kernel command
   line option "ramdisk=XX" is now obsolete.  For details, read
   Documentation/ramdisk.txt. If you want to compile this as a module (
   = code which can be inserted in and removed from the running kernel
-  whenever you want), say M and read Documentation/modules.txt.  Most
-  normal users won't need the RAM disk functionality, and can thus say
-  N here.
+  whenever you want), say M and read Documentation/modules.txt. The
+  module will be called rd.o. Most normal users won't need the RAM
+  disk functionality, and can thus say N here.
 
 Initial RAM disk (initrd) support
 CONFIG_BLK_DEV_INITRD
   The initial RAM disk is a RAM disk that is loaded by the boot loader
-  (LOADLIN or LILO) and that is mounted as root before the normal boot
+  (loadlin or lilo) and that is mounted as root before the normal boot
   procedure. It is typically used to load modules needed to mount the
   "real" root file system, etc. See Documentation/initrd.txt for
   details.
 
 Loop device support
 CONFIG_BLK_DEV_LOOP
-  Enabling this option will allow you to mount a file as a file
-  system.  This is useful if you want to check an ISO9660 file system
-  before burning the CD, or want to use floppy images without first
-  writing them to floppy.  This option also allows one to mount a
-  filesystem with encryption.  To use these features, you need a
-  recent version of mount (available via ftp (user: anonymous) from
+  Saying Y here will allow you to mount a file as a file system.  This
+  is useful if you want to check an ISO9660 file system before burning
+  the CD, or want to use floppy images without first writing them to
+  floppy.  This option also allows one to mount a filesystem with
+  encryption.  To use these features, you need a recent version of
+  mount (available via ftp (user: anonymous) from
   ftp.win.tue.nl/pub/linux/util/).  Note that this loop device has
   nothing to do with the loopback device used for network connections
   from the machine to itself.  Most users will answer N here.
@@ -146,7 +155,7 @@
 Old harddisk (MFM/RLL/IDE) driver
 CONFIG_BLK_DEV_HD_ONLY
   There are two drivers for MFM/RLL/IDE disks.  Most people use the
-  newer enhanced driver, but the old one is still around for two
+  newer enhanced driver, but this old one is still around for two
   reasons.  Some older systems have strange timing problems and seem
   to work only with the old driver (which itself does not work with
   some newer systems).  The other reason is that the old driver is
@@ -160,8 +169,8 @@
 Use old disk-only driver on primary interface
 CONFIG_BLK_DEV_HD_IDE
   There are two drivers for MFM/RLL/IDE disks.  Most people use just
-  the new enhanced driver by itself.  This option installs the old
-  harddisk driver to control the primary IDE/disk interface in the
+  the new enhanced driver by itself.  This option however installs the
+  old harddisk driver to control the primary IDE/disk interface in the
   system, leaving the new enhanced IDE driver take care of only the
   2nd/3rd/4th IDE interfaces. Doing this will prevent you from having
   an IDE/ATAPI CDROM or tape drive connected to the primary IDE
@@ -178,7 +187,8 @@
   old harddisk driver instead, say Y.  If you want to compile this
   driver as a module ( = code which can be inserted in and removed
   from the running kernel whenever you want), say M here and read
-  Documentation/modules.txt. If unsure, say Y.
+  Documentation/modules.txt. The module will be called ide-disk.o. If
+  unsure, say Y.
 
 Include IDE/ATAPI CDROM support
 CONFIG_BLK_DEV_IDECD
@@ -187,19 +197,19 @@
   SCSI protocol.  Most new CDROM drives use ATAPI, including the
   NEC-260, Mitsumi FX400, Sony 55E, and just about all non-SCSI
   double(2X), quad(4X), and six(6X) speed drives.  At boot time, the
-  CDROM drive will be identified along with other IDE devices, as "hdb"
-  or "hdc", or something similar.
-  If this is your only CDROM drive, you can say N to all other CDROM
-  options, but be sure to say Y to the ISO9660 filesystem.  Read the
-  CDROM-HOWTO, available via ftp (user: anonymous) in
+  CDROM drive will be identified along with other IDE devices, as
+  "hdb" or "hdc", or something similar.  If this is your only CDROM
+  drive, you can say N to all other CDROM options, but be sure to say
+  Y to "ISO9660 cdrom filesystem support".  Read the CDROM-HOWTO,
+  available via ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/HOWTO and the file
   Documentation/cdrom/ide-cd.  Note that older versions of lilo (the
   linux boot loader) cannot properly deal with IDE/ATAPI CDROMs, so
   install lilo-16 or higher, available from
-  sunsite.unc.edu:/pub/Linux/system/Linux-boot/lilo.
-  If you want to compile the driver as a module ( = code which
-  can be inserted in and removed from the running kernel whenever you
-  want), say M here and read Documentation/modules.txt.
+  sunsite.unc.edu:/pub/Linux/system/Linux-boot/lilo.  If you want to
+  compile the driver as a module ( = code which can be inserted in and
+  removed from the running kernel whenever you want), say M here and
+  read Documentation/modules.txt. The module will be called ide-cd.o.
 
 Include IDE/ATAPI TAPE support
 CONFIG_BLK_DEV_IDETAPE
@@ -212,7 +222,7 @@
   Documentation/ide.txt files for usage information.  If you want to
   compile the driver as a module ( = code which can be inserted in and
   removed from the running kernel whenever you want), say M here and
-  read Documentation/modules.txt.
+  read Documentation/modules.txt. The module will be called ide-tape.o.
 
 Include IDE/ATAPI FLOPPY support
 CONFIG_BLK_DEV_IDEFLOPPY
@@ -224,7 +234,8 @@
   something similar. If you want to compile the driver as a module ( =
   code which can be inserted in and removed from the running kernel
   whenever you want), say M here and read Documentation/modules.txt.
-
+  The module will be called ide-floppy.o.
+  
 SCSI emulation support
 CONFIG_BLK_DEV_IDESCSI
   This will provide SCSI host adapter emulation for IDE ATAPI devices,
@@ -272,10 +283,14 @@
 
 Intel 82371 PIIX (Triton I/II) DMA support
 CONFIG_BLK_DEV_TRITON
-  This will improve performance if you have an Intel PCI Triton I/II
-  IDE interface chipset (i82371FB or i82371SB). For details, read the
-  comments at the beginning of drivers/block/triton.c and
-  Documentation/ide.txt. If unsure, say N.
+  If your PCI system uses an IDE harddrive (as opposed to SCSI, say)
+  and includes the Intel Triton I/II IDE interface chipset (i82371FB
+  or i82371SB), you will want to enable this option to allow use of
+  bus-mastering DMA data transfers. Read the comments at the beginning
+  of drivers/block/triton.c.  You can get the latest version of the
+  hdparm utility via ftp (user: anonymous) from
+  sunsite.unc.edu/pub/Linux/kernel/patches/diskdrives/; it is used to
+  tune your harddisk. It is safe to say Y to this question.
 
 Other IDE chipset support
 CONFIG_IDE_CHIPSETS
@@ -351,17 +366,18 @@
   include a driver for these, say Y. If you want to compile the driver
   as a module ( = code which can be inserted in and removed from the
   running kernel whenever you want), say M here and read
-  Documentation/modules.txt. It's pretty unlikely that you have one of
-  these: say N.
+  Documentation/modules.txt. The module will be called xd.o. It's
+  pretty unlikely that you have one of these: say N.
 
 SyQuest EZ parallel port disk support
 CONFIG_BLK_DEV_EZ
-  If you have a parallel port version of SyQuest's EZ135 or EZ230 removable
-  media devices you can use this driver.  Answer Y to build the driver into
-  the kernel, or M if you would like to build it as a loadable module.
-  Read the file linux/Documentation/ez.txt.  If you have several different
-  devices that will share a common parallel port you should build them all
-  as modules.
+  If you have a parallel port version of SyQuest's EZ135 or EZ230
+  removable media devices you can use this driver.  Answer Y to build
+  the driver into the kernel, or M if you would like to build it as a
+  loadable module. The module will be called ez.o.  Read the file
+  linux/Documentation/ez.txt.  If you have several different devices
+  that will share a common parallel port you should build them all as
+  modules.
 
 Multiple devices driver support
 CONFIG_BLK_DEV_MD
@@ -374,23 +390,25 @@
 
 Linear (append) mode
 CONFIG_MD_LINEAR
-  If you enable this, then your multiple devices driver will be able
-  to use the so-called linear mode, i.e. it will combine the harddisk
+  If you say Y here, then your multiple devices driver will be able to
+  use the so-called linear mode, i.e. it will combine the harddisk
   partitions by simply appending one to the other. If you want to
   compile this as a module ( = code which can be inserted in and
   removed from the running kernel whenever you want), say M here and
-  read Documentation/modules.txt. If unsure, say Y.
+  read Documentation/modules.txt. The module will be called
+  linear.o. If unsure, say Y.
 
 RAID-0 (striping) mode
 CONFIG_MD_STRIPED
-  If you enable this, then your multiple devices driver will be able
-  to use the so-called raid0 mode, i.e. it will combine the harddisk
+  If you say Y here, then your multiple devices driver will be able to
+  use the so-called raid0 mode, i.e. it will combine the harddisk
   partitions into one logical device in such a fashion as to fill them
   up evenly, one chunk here and one chunk there. This will increase
   the throughput rate if the partitions reside on distinct disks.  If
   you want to compile this as a module ( = code which can be inserted
   in and removed from the running kernel whenever you want), say M
-  here and read Documentation/modules.txt. If unsure, say Y.
+  here and read Documentation/modules.txt. The module will be called
+  raid0.o. If unsure, say Y.
 
 Support for Deskstation RPC44 
 CONFIG_DESKSTATION_RPC44
@@ -496,7 +514,7 @@
   you want to configure your Linux box as a firewall for a local
   network, say Y here. If your local network is TCP/IP based, you will
   then also have to say Y to "IP: firewalling", below.  
-  You also need to say Y here and enable "IP firewalling" below in
+  You also need to say Y here and say Y to "IP firewalling" below in
   order to be able to use IP masquerading (i.e. local computers can
   chat with an outside host, but that outside host is made to think
   that it is talking to the firewall box -- makes the local network
@@ -556,22 +574,23 @@
   which is command line driven, and ARC, which uses menus and arrow
   keys. The usual way to load Linux on an Alpha machine is to use MILO
   (a bootloader that lets you pass command line parameters to the
-  kernel just like LILO does) which can be loaded either from ARC or
-  can be installed directly as a permanent firmware replacement from
-  floppy (which requires changing a certain jumper on the
-  motherboard). If you want to do either of these, say N here. If MILO
-  doesn't work on your system (true for Jensen motherboards), you can
-  bypass it altogether and boot Linux directly from an SRM console;
-  say Y here in order to do that. Note that you won't be able to boot
-  from an IDE disk using SRM. If unsure, say N. Details about the
-  Linux/Alpha booting process are contained in the Linux/Alpha FAQ,
-  accessible on the WWW from http://www.azstarnet.com/~axplinux/ (To
-  browse the WWW, you need to have access to a machine on the Internet
-  that has one of the programs lynx, netscape or Mosaic).
+  kernel just like lilo does for the 386 architecture) which can be
+  loaded either from ARC or can be installed directly as a permanent
+  firmware replacement from floppy (which requires changing a certain
+  jumper on the motherboard). If you want to do either of these, say N
+  here. If MILO doesn't work on your system (true for Jensen
+  motherboards), you can bypass it altogether and boot Linux directly
+  from an SRM console; say Y here in order to do that. Note that you
+  won't be able to boot from an IDE disk using SRM. If unsure, say
+  N. Details about the Linux/Alpha booting process are contained in
+  the Linux/Alpha FAQ, accessible on the WWW from
+  http://www.azstarnet.com/~axplinux/ (To browse the WWW, you need to
+  have access to a machine on the Internet that has one of the
+  programs lynx, netscape or Mosaic).
 
 Echo console messages on /dev/ttyS1
 CONFIG_SERIAL_ECHO
-  If you enable this option, all kernel messages that would usually go
+  If you say Y here, all kernel messages that would usually go
   to the console will also be sent to the device /dev/ttyS1 which
   corresponds to a serial port; this could be useful if you attached
   a terminal or printer to that port.
@@ -580,10 +599,10 @@
 CONFIG_TGA_CONSOLE
   Many Alpha systems (e.g the Multia) are shipped with a graphics card
   that implements the TGA interface (much like the VGA standard, but
-  older TGA adaptors are *not* VGA compatible).  On such systems, this
-  option needs to be enabled so that the TGA driver rather than the
-  standard VGA driver is used.  Note that, at this time, there is no X
-  server for these systems. If unsure, try N.
+  older TGA adaptors are *not* VGA compatible).  On such systems, you
+  should say Y here so that the TGA driver rather than the standard
+  VGA driver is used.  Note that, at this time, there is no X server
+  for these systems. If unsure, try N.
 
 PCI bios support
 CONFIG_PCI
@@ -613,23 +632,12 @@
   Documentation/mca.txt before attempting to build an MCA bus kernel.
   Note that this is still experimental code.
 
-Intel 82371 PIIX (Triton I/II) DMA support
-CONFIG_BLK_DEV_TRITON
-  If your PCI system uses an IDE harddrive (as opposed to SCSI, say)
-  and includes the Intel 430FX PCI Triton chipset, you will want to
-  enable this option to allow use of bus-mastering DMA data transfers.
-  Read the comments at the beginning of drivers/block/triton.c.  You
-  can get the latest version of the hdparm utility via ftp (user:
-  anonymous) from
-  sunsite.unc.edu/pub/Linux/kernel/patches/diskdrives/; it is used to
-  tune your harddisk. It is safe to say Y to this question.
-
 System V IPC
 CONFIG_SYSVIPC
   Inter Process Communication is a suite of library functions and system
   calls which let processes (= running programs) synchronize and
   exchange information. It is generally considered to be a good thing,
-  and some programs won't run unless you enable this. In particular,
+  and some programs won't run unless you say Y here. In particular,
   if you want to run the DOS emulator dosemu under Linux (read the
   DOSEMU-HOWTO, available via ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/HOWTO), you'll need to say Y here. You
@@ -637,7 +645,7 @@
   sunsite.unc.edu:/pub/Linux/docs/man/info.tar.gz (extract with "tar
   xzvf filename"). These docs are in the info format which is used to
   document GNU software and can be read from within emacs ("Ctrl-h i")
-  or with the program info ("man info"). Enabling this option enlarges
+  or with the program info ("man info"). Saying Y here enlarges
   your kernel by about 7kB. Just say Y.
 
 Kernel support for ELF binaries
@@ -661,8 +669,9 @@
   file Documentation/Changes for location and latest version). If you
   want to compile this as a module ( = code which can be inserted in
   and removed from the running kernel whenever you want), say M here
-  and read Documentation/modules.txt. Saying M or N here is dangerous
-  because some crucial programs on your system might be in ELF format.
+  and read Documentation/modules.txt. The module will be called
+  binfmt_elf.o. Saying M or N here is dangerous because some crucial
+  programs on your system might be in ELF format.
 
 Kernel support for A.OUT binaries
 CONFIG_BINFMT_AOUT
@@ -677,57 +686,66 @@
   wish to ensure that absolutely none of your programs will use this
   older executable format. If you don't know what to answer at this
   point then answer Y. If someone told you "You need a kernel with
-  QMAGIC support" then you'll have to say Y here. You may answer M 
-  to compile a.out support as a module and later load the module when
-  you want to use a program or library in a.out format. Saying M or N
-  here is dangerous though, because some crucial programs on your
-  system might still be in A.OUT format.
+  QMAGIC support" then you'll have to say Y here. You may answer M to
+  compile a.out support as a module and later load the module when you
+  want to use a program or library in a.out format. The module will be
+  called binfmt_aout.o. Saying M or N here is dangerous though,
+  because some crucial programs on your system might still be in A.OUT
+  format.
 
 Kernel support for JAVA binaries
 CONFIG_BINFMT_JAVA
-  JAVA is an object oriented programming language developed by SUN;
-  JAVA programs are compiled into "JAVA bytecode" binaries which can
-  then be interpreted by run time systems on many different operating
-  systems.  These JAVA binaries are becoming a universal executable
-  format. Saying Y here allows you to execute a JAVA bytecode binary
-  just like any other Linux program: by typing in its name. As more
-  and more Java programs become available, the use for this will
-  gradually increase. You can even execute HTML files containing JAVA
-  applets (= JAVA binaries) if those files start with the string
-  "<!--applet-->". If you want to use this, read
-  Documentation/java.txt and the Java on Linux HOWTO, available via
-  ftp (user: anonymous) at sunsite.unc.edu:/pub/Linux/docs/HOWTO. You
-  will then need to install the run time system contained in the Java
-  Developers Kit (JDK) as described in the HOWTO. If you disable this
-  option it will reduce your kernel by about 4kB. This is not much and
-  by itself does not warrant removing support. However its removal is
-  a good idea if you do not have the JDK installed. If you don't know
-  what to answer at this point then answer Y. You may answer M for
-  module support and later load the module when you install the JDK or
-  find an interesting Java program that you can't live without.
+  JAVA(tm) is an object oriented programming language developed by
+  SUN; JAVA programs are compiled into "JAVA bytecode" binaries which
+  can then be interpreted by run time systems on many different
+  operating systems.  These JAVA binaries are becoming a universal
+  executable format. If you want to execute JAVA binaries, read the
+  Java on Linux HOWTO, available via ftp (user: anonymous) at
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO. You will then need to install
+  the run time system contained in the Java Developers Kit (JDK) as
+  described in the HOWTO. This is completely independent of the Linux
+  kernel and you do NOT need to say Y here for this to work.
+  Saying Y here allows you to execute a JAVA bytecode binary just like
+  any other Linux program: by simply typing in its name. (You also
+  need to have the JDK installed for this to work).  As more and more
+  Java programs become available, the use for this will gradually
+  increase. You can even execute HTML files containing JAVA applets (=
+  JAVA binaries) if those files start with the string
+  "<!--applet-->". If you want to use this, say Y here and read
+  Documentation/java.txt. If you disable this option it will reduce
+  your kernel by about 4kB. This is not much and by itself does not
+  warrant removing support. However its removal is a good idea if you
+  do not have the JDK installed. You may answer M for module support
+  and later load the module when you install the JDK or find an
+  interesting Java program that you can't live without. The module
+  will be called binfmt_java.o. If you don't know what to answer at
+  this point then answer Y.
 
 Processor type
 CONFIG_M386
-  This is the processor type of your CPU. It is used for optimizing
-  purposes. In order to compile a kernel that can run on all CPU types
-  (albeit not optimally fast), you can specify "386" here.  If you
-  specify "486" or "Pentium" or "PPro", then the kernel will run on
-  486 and Pentium (=586) and Pentium Pro (=686) CPUs. In rare cases,
-  it can make sense to specify "Pentium" even if running a 486: the
-  kernel will be smaller but slower. On the other hand, if you use a
-  compiler before gcc 2.7 (say "gcc -v" to find out), then you have to
-  say "386" or "486" here even if running on a Pentium or PPro
-  machine. If you don't know what to do, say "386".
+  This is the processor type of your CPU. This information is used for
+  optimizing purposes. In order to compile a kernel that can run on
+  all Intel CPU types (albeit not optimally fast), you can specify
+  "386" here.  If you specify one of "486" or "Pentium" or "PPro",
+  then the kernel will run on all of these CPUs: 486 and Pentium
+  (=586) and Pentium Pro (=686). In rare cases, it can make sense to
+  specify "Pentium" even if running on a 486: the kernel will be
+  smaller but slower. If you don't know what to do, say "386".
 
 Video mode selection support
 CONFIG_VIDEO_SELECT
-  This enables support for text mode selection on kernel startup. If you
-  want to take advantage of some high-resolution text mode your card's
-  BIOS offers, but the traditional Linux utilities like SVGATextMode
-  don't, you can enable this and set the mode using the "vga=" option
-  from your boot loader (LILO or LOADLIN) or set "vga=ask" which brings
-  up a video mode menu on kernel startup. Read Documentation/svga.txt
-  for more information. If unsure, say N.
+  This enables support for text mode selection on kernel startup. If
+  you want to take advantage of some high-resolution text mode your
+  card's BIOS offers, but the traditional Linux utilities like
+  SVGATextMode don't, you can say Y here and set the mode using the
+  "vga=" option from your boot loader (lilo or loadlin) or set
+  "vga=ask" which brings up a video mode menu on kernel startup. Try
+  "man bootparam" or see the documentation of your boot loader about
+  how to pass options to the kernel. The lilo procedure is also
+  explained in the SCSI-HOWTO, available via ftp (user: anonymous) in
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO.  Read Documentation/svga.txt
+  for more information about the Video mode selection support. If
+  unsure, say N.
 
 Compile the kernel into the ELF object format 
 CONFIG_ELF_KERNEL
@@ -763,7 +781,7 @@
 Set version information on all symbols for modules
 CONFIG_MODVERSIONS
   Usually, modules have to be recompiled whenever you switch to a new
-  kernel. Enabling this option makes it possible, and safe, to use the
+  kernel. Saying Y here makes it possible, and safe, to use the
   same modules even after compiling a new kernel; this requires the
   program modprobe. All the software needed for module support is in
   the modules package (check the file Documentation/Changes for
@@ -800,12 +818,12 @@
   resolution (ARP) cache inside the kernel works well.  However,
   maintaining an internal ARP cache does not work well for very large
   switched networks, and will use a lot of kernel memory if TCP/IP
-  connections are made to many machines on the network.  By enabling
-  this option, the kernel's internal ARP cache will never grow to more
-  than 256 entries (the oldest entries are expired in a LIFO manner)
-  and communication will be attempted with an external ARP daemon,
-  arpd.  This code is still experimental.  If you do enable arpd
-  support, you should obtain a copy of arpd from
+  connections are made to many machines on the network.  By saying Y
+  here, the kernel's internal ARP cache will never grow to more than
+  256 entries (the oldest entries are expired in a LIFO manner) and
+  communication will be attempted with an external ARP daemon, arpd.
+  This code is still experimental.  If you do say Y here, you
+  should obtain a copy of arpd from
   http://www.loran.com/~layes/arpd/index.html.  If unsure, say N.
 
 TCP/IP networking
@@ -840,8 +858,8 @@
   local network from the internet. The Firewall-HOWTO tells you how to
   do this. If your setup is more complex, say you are connected to
   three networks and you want to act as a firewall between two of them
-  and route traffic for the others, you need to say Y here and enable
-  IP firewalling below. If you intend to use IP masquerading (i.e. IP
+  and route traffic for the others, you need to say Y here and Y to 
+  "IP firewalling" below. If you intend to use IP masquerading (i.e. IP
   traffic from one of the local computers and destined for an outside
   host is changed by your box so that it appears to come from you),
   you'll have to say Y here and also to IP firewalling and IP
@@ -891,7 +909,7 @@
   ipfwadm tool (available via ftp (user: anonymous) from
   ftp.xos.nl/pub/linux/ipfwadm/) to allow selective blocking of
   internet traffic based on type, origin and destination.  You need to
-  enable IP firewalling in order to be able to use IP masquerading
+  say Y to "IP firewalling" in order to be able to use IP masquerading
   (i.e. local computers can chat with an outside host, but that
   outside host is made to think that it is talking to the firewall box
   -- makes the local network completely invisible and avoids the need
@@ -935,11 +953,12 @@
   appear on a different network than it physically is, or to use
   mobile-IP facilities (allowing laptops to seamlessly move between
   networks without changing their IP addresses; check out
-  http://anchor.cs.binghamton.edu/~mobileip/LJ/index.html). Enabling
-  this option will produce two modules ( = code which can be inserted
-  in and removed from the running kernel whenever you want), one
-  encapsulator and one decapsulator. You can read details in
-  drivers/net/README.tunnel. Most people can say N.
+  http://anchor.cs.binghamton.edu/~mobileip/LJ/index.html). Saying Y
+  to this option will produce two modules ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  one encapsulator and one decapsulator. The module will be called
+  ipip.o. You can read details in drivers/net/README.tunnel. Most
+  people can say N.
   
 IP: firewall packet logging
 CONFIG_IP_FIREWALL_VERBOSE
@@ -992,18 +1011,17 @@
   that the IP packets were too large and cut them in pieces) will be
   reassembled (defragmented) before being processed, even if they are
   about to be forwarded.  This option is highly recommended if you
-  have enabled the masquerading support (CONFIG_IP_MASQUERADE),
-  because that facility requires that second and further fragments can
-  be related to TCP or UDP port numbers, which are only stored in the
-  first fragment.  When using IP firewall support
-  (CONFIG_IP_FIREWALL), you might also want to enable this option, to
+  have said Y to "IP: masquerading" because that facility requires
+  that second and further fragments can be related to TCP or UDP port
+  numbers, which are only stored in the first fragment.  When using
+  "IP: firewalling" support , you might also want to say Y here, to
   have a more reliable firewall (otherwise second and further
-  fragments will always be accepted by the firewall).  When using
-  transparent proxying (CONFIG_IP_TRANSPARENT_PROXY), this option is
-  implicit, although it is safe to say Y here. Do not say Y to this
-  option except when running either a firewall that is the sole link
-  to your network or a transparent proxy. Never ever say Y to this for
-  a normal router or host.
+  fragments will always be accepted by the firewall).  When using "IP:
+  transparent proxying", this option is implicit, although it is safe
+  to say Y here. Do not say Y to this option except when running
+  either a firewall that is the sole link to your network or a
+  transparent proxy. Never ever say Y to this for a normal router or
+  host.
 
 IP: aliasing support
 CONFIG_IP_ALIAS
@@ -1037,8 +1055,8 @@
 CONFIG_INET_PCTCP
   If you have been having difficulties telneting to your Linux machine
   from a DOS system that uses (broken) PC/TCP networking software (all
-  versions up to OnNet 2.0) over your local ethernet  try enabling this
-  option.  Everyone else says N. People having problems with NCSA telnet
+  versions up to OnNet 2.0) over your local ethernet try saying Y
+  here.  Everyone else says N. People having problems with NCSA telnet
   should see the file linux/Documentation/networking/ncsa-telnet.
 
 Reverse ARP
@@ -1060,8 +1078,9 @@
   http://web.syr.edu/~jmwobus/comfaqs/dhcp.faq.html for details.  If
   you want to compile RARP support as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
-  say M here and read Documentation/modules.txt.  If you don't
-  understand a word of the above, say N and rest in peace.
+  say M here and read Documentation/modules.txt. The module will be
+  called rarp.o.  If you don't understand a word of the above, say N
+  and rest in peace.
 
 Assume subnets are local
 CONFIG_INET_SNARL
@@ -1136,13 +1155,16 @@
   Protocol IP version 6 (also called IPng "IP next
   generation"). Features of this new protocol include: expanded
   address space, authentication and privacy, and seamless
-  interoperability with the current version of IP. For details, see
-  http://playground.sun.com/pub/ipng/html/ipng-main.html and the file
-  net/ipv6/README in the kernel source.  The IPv6 support 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.  It's
-  safe to say N for now.
+  interoperability with the current version of IP. For general
+  information about IPv6, see
+  http://playground.sun.com/pub/ipng/html/ipng-main.html; for specific
+  information about IPv6 under Linux read the HOWTO at
+  http://www.terra.net/ipv6/ and the file net/ipv6/README in the
+  kernel source.  The IPv6 support is also available as a module ( =
+  code which can be inserted in and removed from the running kernel
+  whenever you want). The module will be called ipv6.o. If you want to
+  compile it as a module, say M here and read
+  Documentation/modules.txt.  It's safe to say N for now.
 
 The IPX protocol
 CONFIG_IPX
@@ -1161,26 +1183,34 @@
   IPX-HOWTO in sunsite.unc.edu:/pub/Linux/docs/howto. The IPX driver
   would enlarge your kernel by about 5 kB. 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.
-  Unless you want to integrate your Linux box with a local Novell
-  network, say N.
+  from the running kernel whenever you want). The module will be
+  called ipx.o. If you want to compile it as a module, say M here
+  and read Documentation/modules.txt.  Unless you want to integrate
+  your Linux box with a local Novell network, say N.
 
 Full internal IPX network
 CONFIG_IPX_INTERN
+  Every IPX network has an address that identifies it. Sometimes it is
+  useful to give an IPX "network" address to your Linux box as well
+  (for example if your box is acting as a fileserver for different IPX
+  networks: it will then be accessible form everywhere using the same
+  address).  The way this is done is to create a virtual internal
+  "network" inside your box and to assign an IPX address to this
+  network. Say Y here if you want to do this; read the IPX-HOWTO at
+  sunsite.unc.edu:/pub/Linux/docs/howto for details.  
   The full internal IPX network enables you to allocate sockets on
   different virtual nodes of the internal network. This is done by
-  evaluating the field sipx_node of the socket address given to the bind
-  call. So applications should always initialize the node field to 0
-  when binding a socket on the primary network. In this case the socket
-  is assigned the default node that has been given to the kernel when
-  the internal network was created.
-  By enabling the full internal IPX network the cross-forwarding of
-  packets targeted at 'special' sockets to sockets listening on the
-  primary network is disabled. This might break existing applications,
-  especially RIP/SAP daemons. A RIP/SAP daemon that works well with the
-  full internal net can be found on ftp.gwdg.de:/pub/linux/misc/ncpfs.
-  If you don't know what you are doing, say N.
+  evaluating the field sipx_node of the socket address given to the
+  bind call. So applications should always initialize the node field
+  to 0 when binding a socket on the primary network. In this case the
+  socket is assigned the default node that has been given to the
+  kernel when the internal network was created.  By enabling the full
+  internal IPX network the cross-forwarding of packets targeted at
+  'special' sockets to sockets listening on the primary network is
+  disabled. This might break existing applications, especially RIP/SAP
+  daemons. A RIP/SAP daemon that works well with the full internal net
+  can be found on ftp.gwdg.de:/pub/linux/misc/ncpfs.  If you don't
+  know what you are doing, say N.
 
 IPX Type 20 Routing
 CONFIG_IPX_PPROP_ROUTING
@@ -1198,11 +1228,11 @@
 CONFIG_ATALK
   Appletalk is the way Apple computers speak to each other on a
   network. EtherTalk is the name used for appletalk over ethernet and
-  Localtalk is appletalk over the apple serial links. If your linux box 
-  is connected to such a network and you want to join the conversation,
-  say Y. You will need to use the netatalk package so that your Linux
-  box can act as a print and file server for macs as well as access
-  appletalk printers. Check out
+  Localtalk is appletalk over the apple serial links. If your linux
+  box is connected to such a network and you want to join the
+  conversation, say Y. You will need to use the netatalk package so
+  that your Linux box can act as a print and file server for macs as
+  well as access appletalk printers. Check out
   http://artoo.hitchcock.org/~flowerpt/projects/linux-netatalk/ on the
   WWW for details (to browse the WWW, you need to have access to a
   machine on the Internet that has one of the programs lynx, netscape
@@ -1210,13 +1240,14 @@
   sunsite.unc.edu:/pub/Linux/docs/HOWTO contains valuable information
   as well. 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. I hear that the GNU boycott of Apple is
-  over, so even politically correct people are allowed to say Y here.
-  At the time the kernel is released the localtalk drivers are not
-  yet ready to ship. The kernel however supports localtalk and when
-  such drivers become available all you will need to do is download
-  and install the localtalk driver.
+  want). The module will be called appletalk.o. If you want to compile
+  it as a module, say M here and read Documentation/modules.txt. I
+  hear that the GNU boycott of Apple is over, so even politically
+  correct people are allowed to say Y here.  At the time the kernel is
+  released the localtalk drivers are not yet ready to ship. The kernel
+  however supports localtalk and when such drivers become available
+  all you will need to do is download and install the localtalk
+  driver.
 
 Amateur Radio AX.25 Level 2
 CONFIG_AX25
@@ -1234,7 +1265,7 @@
   have to say Y to one of those drivers. Information about where to
   get supporting software for Linux amateur radio as well as
   information about how to configure an AX.25 port is contained in the
-  HAM-HOWTO, available via ftp (user: anonymous) in
+  AX25-HOWTO, available via ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/HOWTO. You might also want to check
   out the file Documentation/networking/ax25.txt in the kernel
   source. More information about digital amateur radio in general is
@@ -1242,25 +1273,25 @@
   browse the WWW, you need to have access to a machine on the Internet
   that has one of the programs lynx, netscape or Mosaic).  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.
+  removed from the running kernel whenever you want). The module will
+  be called ax25.o. If you want to compile it as a module, say M here
+  and read Documentation/modules.txt.
 
 Amateur Radio NET/ROM
 CONFIG_NETROM
   NET/ROM is a network layer protocol on top of AX.25 useful for
   routing.  A comprehensive listing of all the software for Linux
   amateur radio users as well as information about how to configure an
-  AX.25 port is contained in the HAM-HOWTO, available via ftp (user:
+  AX.25 port is contained in the AX25-HOWTO, available via ftp (user:
   anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO. You also might
   want to check out the file Documentation/networking/ax25.txt. More
   information about digital amateur radio in general is on the WWW at
   http://www.tapr.org/tapr/html/pkthome.html (To browse the WWW, you
   need to have access to a machine on the Internet that has one of the
-  programs lynx, netscape or Mosaic).
-  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
+  programs lynx, netscape or Mosaic).  This driver is also available
+  as a module ( = code which can be inserted in and removed from the
+  running kernel whenever you want). The module will be called
+  netrom.o. If you want to compile it as a module, say M here and read
   Documentation/modules.txt.
 
 AX.25 over Ethernet
@@ -1278,7 +1309,7 @@
   particular, essentially an alternative to NET/ROM.  A comprehensive
   listing of all the software for Linux amateur radio users as well as
   information about how to configure an AX.25 port is contained in the
-  HAM-HOWTO, available via ftp (user: anonymous) in
+  AX25-HOWTO, available via ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/HOWTO. You also might want to check
   out the file Documentation/networking/ax25.txt. More information
   about digital amateur radio in general is on the WWW at
@@ -1286,9 +1317,57 @@
   need to have access to a machine on the Internet that has one of the
   programs lynx, netscape or Mosaic).  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.
+  running kernel whenever you want). The module will be called
+  rose.o. If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.
+
+CCITT X.25 Packet Layer
+CONFIG_X25
+  X.25 is a set of standardized network protocols, similar in scope to
+  frame relay; the one physical line from your box to the entry point
+  to the X.25 network can carry several logical point-to-point
+  connections (called "virtual circuits") to other computers connected
+  to the X.25 network. Governments, banks, and other organizations
+  tend to use it to connect to each other or to form Wide Area
+  Networks. Many countries have public X.25 networks.  X.25 consists
+  of two protocols: the higher level Packet Layer Protocol (PLP) (say
+  Y here if you want that) and the lower level data link layer
+  protocol LAPB (say Y to "LAPB Data Link Driver" below if you want
+  that). You can read more about X.25 at
+  http://www.sangoma.com/x25.html and
+  http://www.cisco.com/univercd/data/doc/software/11_0/rpcg/cx25.htm.
+  Information about X.25 for Linux is contained in the files
+  Documentation/networking/x25.txt and
+  Documentation/networking/x25-iface.txt.  One connects to an X.25
+  network either with a dedicated network card using the X.21 protocol
+  (not yet supported by Linux) or one can do X.25 over ethernet using
+  an ordinary ethernet card and either the 802.2 LLC protocol (say Y
+  to "802.2 LLC" below) or LAPB over ethernet (say Y to "LAPB Data
+  Link Driver" and "LAPB over Ethernet driver" below).  If you want to
+  compile this driver as a module though ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt. The module will be
+  called x25.o. If unsure, say N.
+
+LAPB Data Link Driver (EXPERIMENTAL) 
+CONFIG_LAPB
+  Link Access Procedure, Balanced (LAPB) is the data link layer part
+  of the X.25 protocol. It offers a reliable connection service to
+  exchange data frames with one other host, and it is used to
+  transport higher level protocols (mostly X.25 Packet Layer, but
+  others are possible as well).  If you want to use LAPB connections
+  over ethernet, say Y here and to "LAPB over Ethernet driver" below.
+  Read Documentation/networking/lapb-module.txt for technical details.
+  If you want to compile this driver as a module though ( = code which
+  can be inserted in and removed from the running kernel whenever you
+  want), say M here and read Documentation/modules.txt. The module
+  will be called lapb.o.  If unsure, say N.
 
+802.2 LLC (VERY EXPERIMENTAL)
+CONFIG_LLC
+  This is a Logical Link Layer protocol used for X.25 connections over
+  ethernet, using ordinary ethernet cards. 
+  
 Bridging (EXPERIMENTAL)
 CONFIG_BRIDGE
   If you say Y here, then your Linux box will be able to act as an
@@ -1313,7 +1392,7 @@
   of the kernel or modules and user processes; the user processes are
   able to read from and write to character special files in the /dev
   directory having major mode 36. So far, the kernel uses it to
-  publish some network related information if you enable "Routing
+  publish some network related information if you say Y to "Routing
   messages", below. It is also used by the firewall code if you say Y
   to "Kernel/User network link driver" further down.  You also need to
   say Y here if you want to use arpd, a daemon that helps keep the
@@ -1322,7 +1401,7 @@
 
 Routing messages
 CONFIG_RTNETLINK
-  If you enable this and create a character special file /dev/route
+  If you say Y here and create a character special file /dev/route
   with major number 36 and minor number 0 using mknod ("man mknod"),
   you can read some network related routing information from that
   file. Everything you write to that file will be discarded.
@@ -1338,9 +1417,9 @@
   SCSI-HOWTO, available via ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/HOWTO.  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 and
-  Documentation/scsi.txt.
+  from the running kernel whenever you want). The module will be
+  called scsi_mod.o. If you want to compile it as a module, say M here
+  and read Documentation/modules.txt and Documentation/scsi.txt.
 
 SCSI disk support
 CONFIG_BLK_DEV_SD
@@ -1350,8 +1429,9 @@
   sunsite.unc.edu:/pub/Linux/docs/HOWTO. This is NOT for SCSI
   CDROMs. 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 and Documentation/scsi.txt.
+  want). The module will be called sd_mod.o. If you want to compile it
+  as a module, say M here and read Documentation/modules.txt and
+  Documentation/scsi.txt.
   
 SCSI tape support
 CONFIG_CHR_DEV_ST
@@ -1360,20 +1440,20 @@
   sunsite.unc.edu:/pub/Linux/docs/HOWTO and drivers/scsi/README.st in
   the kernel source. This is NOT for SCSI CDROMs. 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 and
-  Documentation/scsi.txt .
+  from the running kernel whenever you want). The module will be
+  called st.o. If you want to compile it as a module, say M here
+  and read Documentation/modules.txt and Documentation/scsi.txt .
 
 SCSI CDROM support
 CONFIG_BLK_DEV_SR
   If you want to use a SCSI CDROM under Linux, say Y and read the
   SCSI-HOWTO and the CDROM-HOWTO from
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO. Also make sure to enable the
-  ISO9660 filesystem later. 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 and
-  Documentation/scsi.txt .
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO. Also make sure to say Y to
+  "ISO9660 cdrom filesystem support" later. This driver is also
+  available as a module ( = code which can be inserted in and removed
+  from the running kernel whenever you want). The module will be
+  called sr_mod.o. If you want to compile it as a module, say M here
+  and read Documentation/modules.txt and Documentation/scsi.txt .
 
 Enable vendor-specific extensions (for SCSI CDROM)
 CONFIG_BLK_DEV_SR_VENDOR
@@ -1397,7 +1477,8 @@
   sunsite.unc.edu:/pub/Linux/docs/HOWTO. If you want to compile this
   as a module ( = code which can be inserted in and removed from the
   running kernel whenever you want), say M here and read
-  Documentation/modules.txt and Documentation/scsi.txt.
+  Documentation/modules.txt and Documentation/scsi.txt. The module
+  will be called sg.o. If unsure, say N.
 
 Probe all LUNs on each SCSI device
 CONFIG_SCSI_MULTI_LUN
@@ -1411,7 +1492,7 @@
 Verbose SCSI error reporting (kernel size +=12K)
 CONFIG_SCSI_CONSTANTS
   The error messages regarding your SCSI hardware will be easier to
-  understand if you enable this; it will enlarge your kernel by about
+  understand if you say Y here; it will enlarge your kernel by about
   12KB. If in doubt, say Y.
 
 AdvanSys SCSI support
@@ -1421,7 +1502,8 @@
   drivers/scsi/advansys.c. 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.
+  here and read Documentation/modules.txt. The module will be called
+  advansys.o.
 
 Adaptec AHA152X/2825 support
 CONFIG_SCSI_AHA152X
@@ -1431,9 +1513,9 @@
   sunsite.unc.edu:/pub/Linux/docs/HOWTO. You might also want to read
   the comments at the top of drivers/scsi/aha152x.c. 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.
+  removed from the running kernel whenever you want). The module will
+  be called aha152x.o. If you want to compile it as a module, say M here
+  and read Documentation/modules.txt.
 
 Adaptec AHA1542 support
 CONFIG_SCSI_AHA1542
@@ -1441,11 +1523,12 @@
   3.4 of the SCSI-HOWTO, available via ftp (user: anonymous) at
   sunsite.unc.edu:/pub/Linux/docs/HOWTO.  Note that Trantor was
   recently purchased by Adaptec, and some former Trantor products are
-  being sold under the Adaptec name. If it doesn't work out of
-  the box, you may have to change some settings in
-  drivers/scsi/aha1542.h.  If you want to compile this as a module ( =
-  code which can be inserted in and removed from the running kernel
-  whenever you want), say M here and read Documentation/modules.txt.
+  being sold under the Adaptec name. If it doesn't work out of the
+  box, you may have to change some settings in drivers/scsi/aha1542.h.
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt. The module will be
+  called aha1542.o.
  
 Adaptec AHA1740 support
 CONFIG_SCSI_AHA1740
@@ -1455,8 +1538,9 @@
   the box, you may have to change some settings in
   drivers/scsi/aha1740.h. 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.
+  whenever you want). The module will be called aha17400.o. If you
+  want to compile it as a module, say M here and read
+  Documentation/modules.txt.
 
 Adaptec AHA274X/284X/294X support
 CONFIG_SCSI_AIC7XXX
@@ -1466,7 +1550,8 @@
   doesn't work out of the box, you may have to change some settings in
   drivers/scsi/aic7xxx.h.  If you want to compile this as a module ( =
   code which can be inserted in and removed from the running kernel
-  whenever you want), say M here and read Documentation/modules.txt.
+  whenever you want), say M here and read
+  Documentation/modules.txt. The module will be called aic7xxx.o.
 
 BusLogic SCSI support
 CONFIG_SCSI_BUSLOGIC
@@ -1481,8 +1566,9 @@
   correctly without modification, please contact the author.  You can
   build this driver also as a module ( = code which can be inserted in
   and removed from the running kernel whenever you want), but only a
-  single instance may be loaded. If you want to compile it as a
-  module, say M here and read Documentation/modules.txt.
+  single instance may be loaded. The module will be called
+  BusLogic.o. If you want to compile it as a module, say M here and
+  read Documentation/modules.txt.
 
 DTC3180/3280 SCSI support
 CONFIG_SCSI_DTC3280
@@ -1491,8 +1577,9 @@
   sunsite.unc.edu:/pub/Linux/docs/HOWTO and the file
   drivers/scsi/README.dtc3x80.  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.
+  kernel whenever you want). The module will be called dtc.o. If you
+  want to compile it as a module, say M here and read
+  Documentation/modules.txt.
 
 EATA-DMA (DPT, NEC, AT&T, SNI, AST, Olivetti, Alphatronix) support
 CONFIG_SCSI_EATA_DMA
@@ -1500,12 +1587,13 @@
   Adaptors like the SmartCache III/IV, SmartRAID controller families
   and the DPT PM2011B and PM2012B controllers.  Note that there is
   also another driver for the same hardware: "EATA ISA/EISA/PCI
-  support". You should enable only one of them. Please read the
+  support". You should only say Y to one of them. Please read the
   SCSI-HOWTO, available via ftp (user: anonymous) at
   sunsite.unc.edu:/pub/Linux/docs/HOWTO.  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.
+  from the running kernel whenever you want). The module will be
+  called eata_dma.o. If you want to compile it as a module, say M here
+  and read Documentation/modules.txt.
 
 EATA-PIO (old DPT PM2001, PM2012A) support
 CONFIG_SCSI_EATA_PIO
@@ -1518,34 +1606,48 @@
   sunsite.unc.edu:/pub/Linux/docs/HOWTO.  If you want to compile this
   as a module ( = code which can be inserted in and removed from the
   running kernel whenever you want), say M here and read
-  Documentation/modules.txt.
+  Documentation/modules.txt. The module will be called eata_pio.o.
 
 UltraStor 14F/34F support
 CONFIG_SCSI_U14_34F
   This is support for the UltraStor 14F and 34F SCSI-2 host adapters.
-  The source at drivers/scsi/u14-34f.c contains some information about 
-  this hardware. If the driver doesn't work out of the box, you may have 
-  to change some settings in drivers/scsi/u14-34f.c.
-  Read the SCSI-HOWTO, available via ftp (user: anonymous) at 
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO. Note that there is also another
-  driver for the same hardware: "UltraStor SCSI support", below.
-  You should enable both only if you want 24F support as well. 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.
+  The source at drivers/scsi/u14-34f.c contains some information about
+  this hardware. If the driver doesn't work out of the box, you may
+  have to change some settings in drivers/scsi/u14-34f.c.  Read the
+  SCSI-HOWTO, available via ftp (user: anonymous) at
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO. Note that there is also
+  another driver for the same hardware: "UltraStor SCSI support",
+  below.  You should say Y to both only if you want 24F support as
+  well. This driver is also available as a module ( = code which can
+  be inserted in and removed from the running kernel whenever you
+  want). The module will be called u14-34f.o. If you want to compile
+  it as a module, say M here and read Documentation/modules.txt.
+
+enable linked commands
+CONFIG_SCSI_U14_34F_LINKED_COMMANDS
+  This is a feature of SCSI-2 which improves performance: the host
+  adaptor can send a whole list of commands to a device in one
+  batch. Some SCSI devices might not implement this properly, so the
+  save answer is N.
+
+maximum number of queued commands
+CONFIG_SCSI_U14_34F_MAX_TAGS
+  This specifies how many SCSI commands can be maximally queued for a
+  given SCSI device. Go with the default unless you know what you're
+  doing. Minimum is 2 and maximum is 8.
 
 Future Domain 16xx SCSI support
 CONFIG_SCSI_FUTURE_DOMAIN
   This is support for Future Domain's 16-bit SCSI host adaptors
-  (TMC-1660/1680, TMC-1650/1670, TMC-3260, TMC-1610M/MER/MEX) and other
-  adaptors based on the Future Domain chipsets (Quantum ISA-200S,
-  ISA-250MG; Adaptec AHA-2920; and at least one IBM board).  It is
-  explained in section 3.7 of the SCSI-HOWTO, available via ftp (user:
-  anonymous) at sunsite.unc.edu:/pub/Linux/docs/HOWTO.  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.
+  (TMC-1660/1680, TMC-1650/1670, TMC-3260, TMC-1610M/MER/MEX) and
+  other adaptors based on the Future Domain chipsets (Quantum
+  ISA-200S, ISA-250MG; Adaptec AHA-2920; and at least one IBM board).
+  It is explained in section 3.7 of the SCSI-HOWTO, available via ftp
+  (user: anonymous) at sunsite.unc.edu:/pub/Linux/docs/HOWTO.  This
+  driver is also available as a module ( = code which can be inserted
+  in and removed from the running kernel whenever you want). The
+  module will be called fdomain.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
 
 Generic NCR5380/53c400 SCSI support
 CONFIG_SCSI_GENERIC_NCR5380
@@ -1556,8 +1658,9 @@
   the box, you may have to change some settings in
   drivers/scsi/g_NCR5380.h. 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.
+  kernel whenever you want). The module will be called g_NCR5380.o. If
+  you want to compile it as a module, say M here and read
+  Documentation/modules.txt.
  
 Enable NCR53c400 extensions
 CONFIG_SCSI_GENERIC_NCR53C400
@@ -1566,8 +1669,7 @@
   the Trantor T130B in its default configuration; you might have to
   pass a command line option to the kernel at boot time if it doesn't
   detect your card. See the file drivers/scsi/README.g_NCR5380 for
-  details. If you want to compile it as a module, say M here and read
-  Documentation/modules.txt.
+  details.
 
 NCR5380/53c400 mapping method (use Port for T130B)
 CONFIG_SCSI_G_NCR5380_PORT
@@ -1584,8 +1686,9 @@
   box, you may have to change some settings in
   drivers/scsi/53c7,8xx.h. 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.
+  whenever you want). The module will be called 53c7,8xx.o. If you
+  want to compile it as a module, say M here and read
+  Documentation/modules.txt.
 
 always negotiate synchronous transfers
 CONFIG_SCSI_NCR53C7xx_sync
@@ -1602,7 +1705,7 @@
 allow DISCONNECT
 CONFIG_SCSI_NCR53C7xx_DISCONNECT
   This enables the disconnect/reconnect feature of the NCR SCSI
-  controller.  When this is enabled, a slow SCSI device will not lock
+  controller.  When you say Y here, a slow SCSI device will not lock
   the SCSI bus while processing a request, allowing simultaneous use
   of e.g. a SCSI hard disk and SCSI tape or CD-ROM drive, and
   providing much better performance when using slow and fast SCSI
@@ -1685,17 +1788,21 @@
 IBMMCA SCSI support
 CONFIG_SCSI_IBMMCA
   If your computer sports an MCA bus system architecture (IBM PS/2)
-  with an SCSI harddrive, say Y here.
+  with an SCSI harddrive, say Y here. This driver is also available as
+  a module ( = code which can be inserted in and removed from the
+  running kernel whenever you want). The module will be called
+  ibmmca.o. If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.
 
 Always IN2000 SCSI support
 CONFIG_SCSI_IN2000
-  This is support for an ISA bus SCSI host adaptor. You'll find
-  more information in drivers/scsi/in2000.readme. If it doesn't
-  work out of the box, you may have to change the jumpers for IRQ
-  or address selection. If you want to compile this as a module 
-  ( = code which can be inserted in and removed from the running
-  kernel whenever you want), say M here and read 
-  Documentation/modules.txt.
+  This is support for an ISA bus SCSI host adaptor. You'll find more
+  information in drivers/scsi/in2000.readme. If it doesn't work out of
+  the box, you may have to change the jumpers for IRQ or address
+  selection. If you want to compile this as a module ( = code which
+  can be inserted in and removed from the running kernel whenever you
+  want), say M here and read Documentation/modules.txt. The module
+  will be called in2000.o.
 
 PAS16 SCSI support
 CONFIG_SCSI_PAS16
@@ -1703,7 +1810,12 @@
   3.10 of the SCSI-HOWTO, available via ftp (user: anonymous) at
   sunsite.unc.edu:/pub/Linux/docs/HOWTO. If it doesn't work out of the
   box, you may have to change some settings in drivers/scsi/pas16.h.
- 
+  This driver is also available as
+  a module ( = code which can be inserted in and removed from the
+  running kernel whenever you want). The module will be called
+  pas16.o. If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.
+
 Qlogic FAS SCSI support
 CONFIG_SCSI_QLOGIC_FAS
   This driver works only with the ISA, VLB, and PCMCIA versions of the
@@ -1715,8 +1827,9 @@
   the SCSI-HOWTO, available via ftp (user: anonymous) at
   sunsite.unc.edu:/pub/Linux/docs/HOWTO. 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.
+  running kernel whenever you want). The module will be called
+  qlogicfas.o. If you want to compile it as a module, say M here and
+  read Documentation/modules.txt.
 
 Qlogic ISP SCSI support (EXPERIMENTAL)
 CONFIG_SCSI_QLOGIC_ISP
@@ -1729,20 +1842,21 @@
   available via ftp (user: anonymous) at
   sunsite.unc.edu:/pub/Linux/docs/HOWTO. 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.
+  running kernel whenever you want). The module will be called
+  qlogicisp.o. If you want to compile it as a module, say M here and
+  read Documentation/modules.txt.
 
 Seagate ST-02 and Future Domain TMC-8xx SCSI support
 CONFIG_SCSI_SEAGATE
-  These are 8-bit SCSI controllers; the ST-01 is also supported by this
-  driver.  It is explained in section 3.9 of the SCSI-HOWTO, available
-  via ftp (user: anonymous) at
+  These are 8-bit SCSI controllers; the ST-01 is also supported by
+  this driver.  It is explained in section 3.9 of the SCSI-HOWTO,
+  available via ftp (user: anonymous) at
   sunsite.unc.edu:/pub/Linux/docs/HOWTO. If it doesn't work out of the
   box, you may have to change some settings in drivers/scsi/seagate.h.
   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.
+  want). The module will be called seagate.o. If you want to compile
+  it as a module, say M here and read Documentation/modules.txt.
 
 Trantor T128/T128F/T228 SCSI support
 CONFIG_SCSI_T128
@@ -1750,9 +1864,12 @@
   3.11 of the SCSI-HOWTO, available via ftp (user: anonymous) at
   sunsite.unc.edu:/pub/Linux/docs/HOWTO.  If it doesn't work out of
   the box, you may have to change some settings in
-  drivers/scsi/t128.h. Note that Trantor was recently purchased by
-  Adaptec, and some former Trantor products are being sold under the
-  Adaptec name.
+  drivers/scsi/t128.h. Note that Trantor was purchased by Adaptec, and
+  some former Trantor products are being sold under the Adaptec
+  name. This driver is also available as a module ( = code which can
+  be inserted in and removed from the running kernel whenever you
+  want). The module will be called t128.o. If you want to compile it
+  as a module, say M here and read Documentation/modules.txt.
 
 UltraStor SCSI support
 CONFIG_SCSI_ULTRASTOR
@@ -1763,7 +1880,8 @@
   box, you may have to change some settings in
   drivers/scsi/ultrastor.h. If you want to compile this as a module (
   = code which can be inserted in and removed from the running kernel
-  whenever you want), say M here and read Documentation/modules.txt.
+  whenever you want), say M here and read
+  Documentation/modules.txt. The module will be called ultrastor.o.
   Note that there is also another driver for the same hardware:
   "UltraStor 14F/34F support", above.
  
@@ -1772,25 +1890,46 @@
   This driver supports the Western Digital 7000 SCSI host adaptor.
   Some information is in the source: drivers/scsi/wd7000.c.  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.
+  in and removed from the running kernel whenever you want). The
+  module will be called wd7000.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
 
 EATA ISA/EISA/PCI (DPT and generic EATA/DMA-compliant boards) support
 CONFIG_SCSI_EATA
   This driver supports all the EATA/DMA-compliant SCSI host adapters
-  and does not need any BIOS32 service.
-  DPT ISA and all EISA i/o addresses are probed looking for the "EATA"
-  signature. If "PCI bios support" is enabled, the addresses of all
-  the PCI SCSI controllers reported by BIOS32 are probed as well.
-  Note that there is also another driver for the same hardware:
-  "EATA-DMA support". You should enable only one of them.
-  You want to read the start of drivers/scsi/eata.c and the
-  SCSI-HOWTO, available via ftp (user: anonymous) at
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO.  If you want to compile this
-  as a module ( = code which can be inserted in and removed from the
-  running kernel whenever you want), say M here and read
-  Documentation/modules.txt.
+  and does not need any BIOS32 service.  DPT ISA and all EISA i/o
+  addresses are probed looking for the "EATA" signature. If you said Y
+  to "PCI bios support", the addresses of all the PCI SCSI controllers
+  reported by BIOS32 are probed as well.  Note that there is also
+  another driver for the same hardware available: "EATA-DMA
+  support". You should say Y to only one of them.  You want to read
+  the start of drivers/scsi/eata.c and the SCSI-HOWTO, available via
+  ftp (user: anonymous) at sunsite.unc.edu:/pub/Linux/docs/HOWTO.  If
+  you want to compile this as a module ( = code which can be inserted
+  in and removed from the running kernel whenever you want), say M
+  here and read Documentation/modules.txt. The module will be called
+  eata.o.
+
+enable tagged command queuing
+CONFIG_SCSI_EATA_TAGGED_QUEUE
+  This is a feature of SCSI-2 which improves performance: the host
+  adaptor can send several SCSI commands to a device's queue even if
+  previous commands haven't finished yet. Some SCSI devices don't
+  implement this properly, so the save answer is N.
+
+enable linked commands
+CONFIG_SCSI_EATA_LINKED_COMMANDS
+  This is a feature of SCSI-2 which improves performance: the host
+  adaptor can send a whole list of commands to a device in one
+  batch. Some SCSI devices might not implement this properly, so the
+  save answer is N.
+
+maximum number of queued commands
+CONFIG_SCSI_EATA_MAX_TAGS
+  This specifies how many SCSI commands can be maximally queued for a
+  given SCSI device. Go with the default unless you know what you're
+  doing. Minimum is 2 and maximum is 16. This number will only have an
+  effect if you said Y to "enable tagged command queuing", above.
 
 NCR53c406a SCSI support
 CONFIG_SCSI_NCR53C406A
@@ -1800,7 +1939,8 @@
   anonymous) at sunsite.unc.edu:/pub/Linux/docs/HOWTO.  If you want to
   compile this driver as a module ( = code which can be inserted in
   and removed from the running kernel whenever you want), say M here
-  and read Documentation/modules.txt.
+  and read Documentation/modules.txt. The module will be called
+  NCR53c406.o.
 
 AM53/79C974 PCI SCSI support
 CONFIG_SCSI_AM53C974
@@ -1810,7 +1950,8 @@
   sunsite.unc.edu:/pub/Linux/docs/HOWTO, is for you. If you want to
   compile this driver as a module ( = code which can be inserted in
   and removed from the running kernel whenever you want), say M here
-  and read Documentation/modules.txt.
+  and read Documentation/modules.txt. The module will be called
+  AM53C974.o.
 
 IOMEGA Parallel Port ZIP drive SCSI support
 CONFIG_SCSI_PPA
@@ -1825,9 +1966,10 @@
   drive, a parallel printer or PLIP on the same parallel port, you
   should compile the drivers as modules and only insert them as
   needed. To compile this driver as a module, say M here and read
-  Documentation/modules.txt. Note that you can say N here if you have
-  the SCSI version of the ZIP drive: it will be supported
-  automatically if you enabled the generic "SCSI disk support", above.
+  Documentation/modules.txt. The module will be called ppa.o. Note
+  that you can say N here if you have the SCSI version of the ZIP
+  drive: it will be supported automatically if you said Y to the
+  generic "SCSI disk support", above.
 
 Network device support?
 CONFIG_NETDEVICES
@@ -1873,16 +2015,17 @@
   this device is consigned into oblivion) with a configurable IP
   address. It is most commonly used in order to make your currently
   inactive SLIP address seem like a real address for local
-  programs. If you use SLIP or PPP, you might want to enable it. Read
+  programs. If you use SLIP or PPP, you might want to say Y here. Read
   about it in the Network Administrator's Guide, available via ftp
   (user: anonymous) from sunsite.unc.edu:/pub/Linux/docs/LDP. Since
   this thing comes often handy, the default is Y. It won't enlarge
   your kernel either. What a deal.  If you want to compile this as a
   module ( = code which can be inserted in and removed from the
   running kernel whenever you want), say M here and read
-  Documentation/modules.txt. If you want to use more than one dummy
-  device at a time, you need to compile it as a module. Instead of
-  'dummy', it will they will then be called 'dummy0', 'dummy1' etc.
+  Documentation/modules.txt. The module will be called dummy.o. If you
+  want to use more than one dummy device at a time, you need to
+  compile it as a module. Instead of 'dummy', it will they will then
+  be called 'dummy0', 'dummy1' etc.
   
 SLIP (serial line) support
 CONFIG_SLIP
@@ -1908,7 +2051,8 @@
   want to compile this as a module ( = code which can be inserted in
   and removed from the running kernel whenever you want), say M here
   and read Documentation/modules.txt as well as
-  Documentation/networking/net-modules.txt.
+  Documentation/networking/net-modules.txt. The module will be called
+  slip.o.
   
 CSLIP compressed headers
 CONFIG_SLIP_COMPRESSED
@@ -1944,11 +2088,23 @@
 CONFIG_NET_RADIO
   Radio based interfaces for Linux. This includes amateur radio
   (AX.25), support for wireless ethernet and other systems. Note that
-  the answer to this question won't directly affect the kernel:
-  saying N will just cause this configure script to skip all the
-  questions about radio interfaces. Some user-level drivers for scarab
-  devices which don't require special kernel support are available via
-  ftp (user: anonymous) from shadow.cabi.net. If unsure, say N.
+  the answer to this question won't directly affect the kernel: saying
+  N will just cause this configure script to skip all the questions
+  about radio interfaces. Some user-level drivers for scarab devices
+  which don't require special kernel support are available via ftp
+  (user: anonymous) from shadow.cabi.net. 
+  If unsure, say N.
+
+AX.25 network interfaces
+CONFIG_NET_HAM
+  Say Y here if you want support for a device that connects your Linux
+  box to your amateur radio (HAM). AX.25 is the protocol used for
+  digital traffic over amateur radio connections. You might want to
+  read the HAM-HOWTO and the AX25-HOWTO, both available via ftp (user:
+  anonymous) from sunsite.unc.edu:/pub/Linux/docs/HOWTO. Note that the
+  answer to this question won't directly affect the kernel: saying N
+  will just cause this configure script to skip all the questions
+  about amateur radio interfaces.
 
 PPP (point-to-point) support
 CONFIG_PPP
@@ -1961,17 +2117,19 @@
   anonymous) from sunsite.unc.edu:/pub/Linux/system/Network/serial/).
   To use PPP, you need an additional program called pppd as described
   in Documentation/networking/ppp.txt and in the PPP-HOWTO, available
-  from sunsite.unc.edu:/pub/Linux/docs/HOWTO. Note that you don't need
-  this option if you just want to run term (term is a program which
-  gives you almost full Internet connectivity if you have a regular
-  dial up shell account on some Internet connected UNIX computer. Read
-  the Term-HOWTO). The PPP option enlarges your kernel by about
-  16kB. 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 said Y to "Version information on all symbols" above,
-  then you cannot compile the PPP driver into the kernel; you can only
-  compile it as a module. If you want to compile it as a module, say M
-  here and read Documentation/modules.txt as well as
+  from sunsite.unc.edu:/pub/Linux/docs/HOWTO. If you upgrade from an
+  older kernel, you might need to upgrade pppd as well.  Note that you
+  don't need "PPP support" if you just want to run term (term is a
+  program which gives you almost full Internet connectivity if you
+  have a regular dial up shell account on some Internet connected UNIX
+  computer. Read the Term-HOWTO). The PPP option enlarges your kernel
+  by about 16kB. 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 said Y to "Version information on all
+  symbols" above, then you cannot compile the PPP driver into the
+  kernel; you can then only compile it as a module. The module will be
+  called ppp.o. 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. Note that, no matter what
   you do, the BSD compression code (used to compress the IP packets
   sent over the serial line; has to be supported at the other end as
@@ -1996,7 +2154,7 @@
   except that it makes the kernel a bit bigger. You can also compile
   this as a module ( = code which can be inserted in and removed from
   the running kernel whenever you want), say M here and read
-  Documentation/modules.txt.
+  Documentation/modules.txt. The module will be called strip.o.
 
 WIC (Radio IP bridge)
 CONFIG_WIC
@@ -2004,59 +2162,77 @@
   to say N.  If you want to compile this driver as a module though ( =
   code which can be inserted in and removed from the running kernel
   whenever you want), say M here and read Documentation/modules.txt.
+  The module will be called wic.o.
+  
+CONFIG_LAPBETHER
+LAPB over Ethernet driver
+  This is a driver for a pseudo device (usually called /dev/lapb0)
+  which allows you to open an LAPB point-to-point connection to some
+  other computer on your ethernet network. In order to do this, you
+  need to say Y or M to the driver for your ethernet card as well as
+  to "LAPB Data Link Driver".  If you want to compile this driver as a
+  module ( = code which can be inserted in and removed from the
+  running kernel whenever you want), say M here and read
+  Documentation/modules.txt. The module will be called lapbether.o.
+  If unsure, say N.
 
 Z8530 SCC driver for AX.25
 CONFIG_SCC
   These cards are used to connect your Linux box to an amateur radio
   in order to communicate with other computers.  If you want to use
-  this, read Documentation/networking/z8530drv.txt and the AX.25-HOWTO,
-  available via ftp (user: anonymous) at
+  this, read Documentation/networking/z8530drv.txt and the
+  AX.25-HOWTO, available via ftp (user: anonymous) at
   sunsite.unc.edu:/pub/Linux/docs/HOWTO.  Also make sure to say Y to
   "Amateur Radio AX.25 Level 2" support. If you want to compile this
   as a module ( = code which can be inserted in and removed from the
   running kernel whenever you want), say M here and read
-  Documentation/modules.txt.
+  Documentation/modules.txt. The module will be called scc.o.
 
 BAYCOM ser12 and par96 driver for AX.25
 CONFIG_BAYCOM
   This is an experimental driver for Baycom style simple amateur radio
   modems that connect to either a serial interface or a parallel
   interface. The driver supports the ser12 and par96 designs. To
-  configure the driver, use the sethdlc utility available
-  in the standard ax25 utilities package. For information on the modems,
-  see http://www.baycom.de and drivers/net/README.baycom.
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read Documentation/modules.txt. This is recommended.
+  configure the driver, use the sethdlc utility available in the
+  standard ax25 utilities package. For information on the modems, see
+  http://www.baycom.de and drivers/net/README.baycom. If you want to
+  compile this driver as a module ( = code which can be inserted in
+  and removed from the running kernel whenever you want), say M here
+  and read Documentation/modules.txt. This is recommended. The module
+  will be called baycom.o.
 
 Soundcard modem driver for AX.25
 CONFIG_SOUNDMODEM
-  This experimental driver allows a standard SoundBlaster or 
+  This experimental driver allows a standard SoundBlaster or
   WindowsSoundSystem compatible soundcard to be used as a packet radio
-  modem. To configure the driver, use the sethdlc, smdiag and smmixer
-  utilities available in the standard ax25 utilities package. For
-  informations on how to key the transmitter, see
+  modem, to send digital traffic over amateur radio. To configure the
+  driver, use the sethdlc, smdiag and smmixer utilities available in
+  the standard ax25 utilities package. For information on how to key
+  the transmitter, see
   http://www.ife.ee.ethz.ch/~sailer/pcf/ptt_circ/ptt.html and
-  drivers/net/README.soundmodem. If you want to compile this as a
-  module ( = code which can be inserted in and removed from the
+  drivers/net/README.soundmodem. If you want to compile this driver as
+  a module ( = code which can be inserted in and removed from the
   running kernel whenever you want), say M here and read
-  Documentation/modules.txt. This is recommended.
+  Documentation/modules.txt. This is recommended. The module will be
+  called soundmodem.o.
 
 Soundcard modem support for SoundBlaster and compatible cards
 CONFIG_SOUNDMODEM_SBC
-  This option enables the soundmodem driver to use SoundBlaster
-  and compatible cards. Dual mode cards (i.e. WSS cards with a
-  SoundBlaster emulation) should be used in WSS mode because
-  this results in usually better performance.
+  This option enables the soundmodem driver to use SoundBlaster and
+  compatible cards. If you have a dual mode card (i.e. a WSS cards
+  with a SoundBlaster emulation) you should say N here and Y to
+  "Soundcard modem support for WSS and Crystal cards", below, because
+  this usually results in better performance.
 
 Soundcard modem support for WSS and Crystal cards
 CONFIG_SOUNDMODEM_WSS
   This option enables the soundmodem driver to use WindowsSoundSystem
   compatible cards. These cards feature a codec chip from either
-  Analog Devices (such as AD1848, AD1845, AD1812) or Crystal Semiconductors
-  (such as CS4248, CS423x). This option also supports the WSS full duplex
-  operation which currently works with Crystal CS423x chips. If you don't
-  need full duplex operation, do not enable it to save performance.
+  Analog Devices (such as AD1848, AD1845, AD1812) or Crystal
+  Semiconductors (such as CS4248, CS423x). This option also supports
+  the WSS full duplex operation which currently works with Crystal
+  CS423x chips. If you don't need full duplex operation, do not enable
+  it to save performance.
 
 Soundcard modem support for 1200 baud AFSK modulation
 CONFIG_SOUNDMODEM_AFSK1200
@@ -2064,30 +2240,35 @@
   compatible to popular modems using TCM3105 or AM7911. The demodulator
   requires about 12% of the CPU power of a Pentium 75 CPU per channel.
 
-Soundcard modem support for 1200 baud AFSK modulation
+Soundmodem 1200 baud AFSK using floating point
 CONFIG_SOUNDMODEM_AFSK1200_FP
   This option enables floating point calculations to be used for the
   AFSK1200 baud modem. The Intel Pentium is a perverted chip because
-  integer multiplications are, altough easier to implement in silicon,
-  an order of a magnitude slower than floating point calculations.
+  integer multiplications are, although easier to implement in silicon,
+  an order of magnitude slower than floating point calculations.
   Enabling this option uses a highly optimized assembler routine for
-  correlations, modelled after the one published by Phil Karn, KA9Q.
-  This reduces the computing power needed on Intel Pentium chips to about
-  50%. On the other hand, Pentium clones with faster integer multiply and
-  slower floating point multiply will probably take longer with this
-  option turned on. As a rule of thumb, enable it for Intel Pentium and
-  Pentium Pro processors, and disable it for anything else.
+  correlations, modeled after the one published by Phil Karn, KA9Q.
+  This reduces the computing power needed on Intel Pentium chips to
+  about 50%. On the other hand, Pentium clones with faster integer
+  multiply and slower floating point multiply will probably take
+  longer with this option turned on. As a rule of thumb, enable it for
+  Intel Pentium and Pentium Pro processors, and disable it for
+  anything else.
   I (sailer@ife.ee.ethz.ch) am very interested in figures. If you are
-  willing to give me a feedback, please compile the driver once with this
-  option enabled and once with it disabled, and send me the cycle counter
-  numbers obtained with both compilations, and your exact chip. The cycle
-  counter numbers can be optained by a recent sethdlc utility.
+  willing to give me a feedback, please compile the driver once with
+  this option enabled and once with it disabled, and send me the cycle
+  counter numbers obtained with both compilations, and your exact
+  chip. The cycle counter numbers can be obtained with a recent
+  sethdlc utility.
 
 Soundcard modem support for 9600 baud FSK G3RUH modulation
 CONFIG_SOUNDMODEM_FSK9600
   This option enables the soundmodem driver 9600 baud FSK modem,
   compatible to the G3RUH standard. The demodulator requires about 4%
-  of the CPU power of a Pentium 75 CPU per channel.
+  of the CPU power of a Pentium 75 CPU per channel. You can say Y to
+  both 1200 baud AFSK and 9600 baud FSK if you want (but obviously you
+  can only use one protocol at a time, depending on what the other end
+  can understand).
 
 Serial port KISS driver for AX.25
 CONFIG_MKISS
@@ -2098,7 +2279,8 @@
   case, you also have to say Y to "Amateur Radio AX.25 Level 2"
   support.  If you want to compile this driver as a module ( = code
   which can be inserted in and removed from the running kernel
-  whenever you want), say M here and read Documentation/modules.txt.
+  whenever you want), say M here and read
+  Documentation/modules.txt. The module will be called mkiss.o.
 
 PLIP (parallel port) support
 CONFIG_PLIP
@@ -2122,25 +2304,25 @@
   your kernel by about 8kB. If you want to compile this as a module (
   = code which can be inserted in and removed from the running kernel
   whenever you want), say M here and read Documentation/modules.txt as
-  well as Documentation/networking/net-modules.txt. If you want to use
-  both a parallel printer and PLIP, there are two cases: 1) If the
-  printer and the PLIP cable are to use the same parallel port
-  (presumably because you have just one), it is best to compile both
-  drivers as modules and load and unload them as needed. 2) To use
-  different parallel ports for the printer and the PLIP cable, you can
-  say Y to the printer driver, specify the base address of the
-  parallel port(s) to use for the printer(s) with the "lp" kernel
-  command line option. (See the documentation of your boot loader
-  (lilo or loadlin) about how to pass options to the kernel at boot
-  time. The lilo procedure is also explained in the SCSI-HOWTO,
-  available via ftp (user: anonymous) in
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO.) The standard base addresses
-  as well as the syntax of the "lp" command line option can be found
-  in drivers/char/lp.c. You can then say Y to this PLIP driver or,
-  preferably, M in which case Documentation/networking/net-modules.txt
-  tells you how to specify the port and IRQ to be used by PLIP at
-  module load time.
-  It's safe to say N here.
+  well as Documentation/networking/net-modules.txt. The module will be
+  called plip.o. If you want to use both a parallel printer and PLIP,
+  there are two cases: 1) If the printer and the PLIP cable are to use
+  the same parallel port (presumably because you have just one), it is
+  best to compile both drivers as modules and load and unload them as
+  needed. 2) In order to use different parallel ports for the printer
+  and the PLIP cable, you can say Y to the printer driver and specify
+  the base address of the parallel port(s) to use for the printer(s)
+  with the "lp" kernel command line option. (Try "man bootparam" or
+  see the documentation of your boot loader (lilo or loadlin) about
+  how to pass options to the kernel at boot time. The lilo procedure
+  is also explained in the SCSI-HOWTO, available via ftp (user:
+  anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO.) The standard
+  base addresses as well as the syntax of the "lp" command line option
+  can be found in drivers/char/lp.c. You can then say Y to this PLIP
+  driver or, preferably, M in which case
+  Documentation/networking/net-modules.txt tells you how to specify
+  the port and IRQ to be used by PLIP at module load time.  It's safe
+  to say N here.
 
 EQL (serial line load balancing) support
 CONFIG_EQUALIZER
@@ -2153,8 +2335,9 @@
   EQL Linux driver or with a Livingston Portmaster 2e. Say Y if you
   want this and read drivers/net/README.eql. 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.
+  from the running kernel whenever you want). The module will be
+  called eql.o. If you want to compile it as a module, say M here
+  and read Documentation/modules.txt.
 
 Frame Relay (DLCI) support
 CONFIG_DLCI
@@ -2172,8 +2355,9 @@
   the net-tools package as explained in
   Documentation/networking/framerelay.txt. 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.
+  from the running kernel whenever you want). The module will be
+  called dlci.o. If you want to compile it as a module, say M here
+  and read Documentation/modules.txt.
 
 Max open DLCI
 CONFIG_DLCI_COUNT 
@@ -2191,12 +2375,13 @@
 Sangoma S502A FRAD support
 CONFIG_SDLA
   Say Y here if you need a driver for the Sangoma S502A, S502E, and
-  S508 Frame Relay Access Devices. These are multi-protocol
-  cards, but only frame relay is supported by the driver at this
-  time. Please read Documentation/framerelay.txt. 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.
+  S508 Frame Relay Access Devices. These are multi-protocol cards, but
+  only frame relay is supported by the driver at this time. Please
+  read Documentation/framerelay.txt. This driver is also available as
+  a module ( = code which can be inserted in and removed from the
+  running kernel whenever you want). The module will be called
+  sdla.o. If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.
 
 Sun LANCE Ethernet support
 CONFIG_SUN_LANCE
@@ -2238,8 +2423,9 @@
   the Ethernet-HOWTO, available via ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/HOWTO. 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
+  running kernel whenever you want). The module will be called
+  wd.o. 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
@@ -2251,15 +2437,16 @@
   the Ethernet-HOWTO, available via ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/HOWTO.  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
+  from the running kernel whenever you want). The module will be
+  called smc-ultra.o. 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.
-  Important: There have been many reports that, with some motherboards
-  mixing an SMC Ultra and an Adaptec AHA1542 SCSI card causes corruption
-  problems with many operating systems.
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.  Important: There have
+  been many reports that, with some motherboards mixing an SMC Ultra
+  and an Adaptec AHA1542 SCSI card causes corruption problems with
+  many operating systems.
 
 SMC 9194 Support
 CONFIG_SMC9194
@@ -2270,10 +2457,11 @@
   the Ethernet-HOWTO, available via ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/HOWTO.  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
+  from the running kernel whenever you want). The module will be
+  called smc9194.o. 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.
 
@@ -2281,9 +2469,10 @@
 CONFIG_LANCE
   If you have a network (ethernet) card of this type, say Y and read
   the Ethernet-HOWTO, available via ftp (user: anonymous) in
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO. 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.
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO. Some LinkSys cards are of
+  this type. 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.
 
 3COM cards
 CONFIG_NET_VENDOR_3COM
@@ -2302,13 +2491,16 @@
   If you have a network (ethernet) card of this type, say Y and read
   the Ethernet-HOWTO, available via ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/HOWTO.  Also, consider buying a new
-  card, since the 3c501 is slow and obsolete. This driver is also 
+  card, since the 3c501 is slow, broken, and obsolete: you will have
+  problems. Some people suggest to ping ("man ping") a nearby machine
+  every minute ("man cron") when using this card.  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 
+  from the running kernel whenever you want). The module will be
+  called 3c501.o. 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 - and don't use 3c501s.
 
 3c503 support
@@ -2317,8 +2509,9 @@
   the Ethernet-HOWTO, available via ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/HOWTO. 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
+  running kernel whenever you want). The module will be called
+  3c503.o. 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
@@ -2333,9 +2526,9 @@
   compile this as a module ( = code which can be inserted in and
   removed from the running kernel whenever you want), 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
+  Documentation/networking/net-modules.txt. The module will be called
+  3c505.o. 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.
 
 3c507 support
@@ -2344,20 +2537,23 @@
   the Ethernet-HOWTO, available via ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/HOWTO. 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
+  running kernel whenever you want). The module will be called
+  3c507.o. 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.
 
-3c523 support CONFIG_ELMC
+3c523 support 
+CONFIG_ELMC
   If you have a network (ethernet) card of this type, say Y and read
   the Ethernet-HOWTO, available via ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/HOWTO. 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
+  running kernel whenever you want). The module will be called
+  3c523.o. 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
@@ -2371,9 +2567,9 @@
   If you want to compile this as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
   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
+  Documentation/networking/net-modules.txt. The module will be called
+  3c509.o. 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. If your card is not
   working you may need to use the DOS setup disk to disable Plug &
   Play mode, and to select the default media type.
@@ -2384,13 +2580,13 @@
   the Ethernet-HOWTO, available via ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/HOWTO. More specific information is
   in Documentation/networking/vortex.txt and in the comments at the
-  beginning of drivers/net/3c59x.c. If you want to compile this
-  as a module ( = code which can be inserted in and removed from the
+  beginning of drivers/net/3c59x.c. If you want to compile this as a
+  module ( = code which can be inserted in and removed from the
   running kernel whenever you want), 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
+  Documentation/networking/net-modules.txt. The module will be called
+  3c59x.o. 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
 
 Other ISA cards
@@ -2411,13 +2607,14 @@
 ARCnet support
 CONFIG_ARCNET
   If you have a network card of this type, say Y and check out the
-  (arguably) beautiful poetry in Documentation/networking/arcnet.txt. 
+  (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
+  from the running kernel whenever you want). The module will be
+  called arcnet.o. 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
@@ -2425,14 +2622,14 @@
   
 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
+  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 say Y here 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)
@@ -2440,8 +2637,8 @@
   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
+  arcnet.com packet driver, Amigas running AmiTCP, and some variants
+  of NetBSD.  You do not need to say Y here 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
@@ -2454,8 +2651,9 @@
   the Ethernet-HOWTO, available via ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/HOWTO. 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
+  running kernel whenever you want). The module will be called
+  e2100.o. 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
@@ -2469,9 +2667,9 @@
   drivers/net/depca.c.  If you want to compile this as a module ( =
   code which can be inserted in and removed from the running kernel
   whenever you want), 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
+  well as Documentation/networking/net-modules.txt. The module will be
+  called depca.o. 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.
 
 EtherWorks 3 support
@@ -2483,9 +2681,9 @@
   If you want to compile this as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
   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
+  Documentation/networking/net-modules.txt. The module will be called
+  ewrk3.o. 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.
 
 SEEQ8005 support
@@ -2505,19 +2703,20 @@
   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
+  Documentation/networking/net-modules.txt. The module will be called
+  at1700.o. 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.
 
 FMV-181/182/183/184 support
 CONFIG_FMV18X
   If you have a Fujitsu FMV-181/182/183/184 network (ethernet) card,
-  say Y and read the Ethernet-HOWTO, available via ftp (user: anonymous)
-  in sunsite.unc.edu:/pub/Linux/docs/HOWTO. 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
+  say Y and read the Ethernet-HOWTO, available via ftp (user:
+  anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO. This driver is
+  also available as a module ( = code which can be inserted in and
+  removed from the running kernel whenever you want). The module will
+  be called fmv18x.o. 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
@@ -2531,8 +2730,9 @@
   the Ethernet-HOWTO, available via ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/HOWTO. 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
+  running kernel whenever you want). The module will be called
+  eepro.o. 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
@@ -2549,16 +2749,21 @@
   module ( = code which can be inserted in and removed from the
   running kernel whenever you want), 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
+  Documentation/networking/net-modules.txt. The module will be called
+  eexpress.o. 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.
 
 NI5210 support
 CONFIG_NI52
   If you have a network (ethernet) card of this type, say Y and read
   the Ethernet-HOWTO, available via ftp (user: anonymous) in
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO. If you plan to use more than
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO. This driver is also available
+  as a module ( = code which can be inserted in and removed from the
+  running kernel whenever you want). The module will be called
+  ni52.o. 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.
 
@@ -2568,15 +2773,15 @@
   the Ethernet-HOWTO, available via ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/HOWTO. 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
+  Documentation/networking/net-modules.txt. The module will be called
+  ni65.o. 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.
 
 Ottawa PI and PI/2 support
 CONFIG_PI
   This is a driver for the Ottawa Amateur Radio Club PI and PI2 cards,
-  which are commonly used to send internet traffic over amateur radio. 
+  which are commonly used to send internet traffic over amateur radio.
   More information about these cards is on the WWW at
   http://hydra.carleton.ca/info/pi2.html (To browse the WWW, you need
   to have access to a machine on the Internet that has one of the
@@ -2587,7 +2792,7 @@
   the protocol used for digital traffic over radio links. If you want
   to compile this as a module ( = code which can be inserted in and
   removed from the running kernel whenever you want), say M here and
-  read Documentation/modules.txt.
+  read Documentation/modules.txt. The module will be called pi2.o.
 
 Gracilis PackeTwin support
 CONFIG_PT
@@ -2600,7 +2805,8 @@
   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.
+  Documentation/networking/net-modules.txt. The module will be called
+  pt.o.
 
 WaveLAN support
 CONFIG_WAVELAN
@@ -2611,8 +2817,9 @@
   more specific information is contained in
   drivers/net/README.wavelan. 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
+  running kernel whenever you want). The module will be called
+  wavelan.o. 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
@@ -2624,8 +2831,9 @@
   the Ethernet-HOWTO, available via ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/HOWTO. 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
+  running kernel whenever you want). The module will be called
+  hp-plus.o. 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
@@ -2637,8 +2845,9 @@
   the Ethernet-HOWTO, available via ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/HOWTO. 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
+  running kernel whenever you want). The module will be called
+  hp.o. 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
@@ -2652,19 +2861,21 @@
   as a module ( = code which can be inserted in and removed from the
   running kernel whenever you want), 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
+  Documentation/networking/net-modules.txt. The module will be called
+  hp100.o. 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.
 
 NE2000/NE1000 support
 CONFIG_NE2000
   If you have a network (ethernet) card of this type, say Y and read
   the Ethernet-HOWTO, available via ftp (user: anonymous) in
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO. 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
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO. Many ethernet cards without a
+  specific driver are compatible with NE2000. This driver is also
+  available as a module ( = code which can be inserted in and removed
+  from the running kernel whenever you want). The module will be
+  called ne.o. 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
@@ -2698,8 +2909,9 @@
   the Ethernet-HOWTO, available via ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/HOWTO. 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
+  running kernel whenever you want). The module will be called
+  ac3200.o. 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
@@ -2711,8 +2923,9 @@
   the Ethernet-HOWTO, available via ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/HOWTO. 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
+  running kernel whenever you want). The module will be called
+  es3210.o. 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
@@ -2726,22 +2939,23 @@
   as a module ( = code which can be inserted in and removed from the
   running kernel whenever you want), 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
+  Documentation/networking/net-modules.txt. The module will be called
+  apricot.o. 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.
 
 DE425, DE434, DE435 support
 CONFIG_DE4X5
   This is support for the DIGITAL series of PCI/EISA ethernet
   cards. These include the DE425, DE434, DE435, DE450 and DE500
-  models. If you have a network card of this type, say Y and read
-  the Ethernet-HOWTO, available via ftp (user: anonymous) in
+  models. If you have a network card of this type, say Y and read the
+  Ethernet-HOWTO, available via ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/HOWTO.  More specific information is
   contained in drivers/net/README.de4x5. 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
+  running kernel whenever you want). The module will be called
+  de4x5.o. 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
@@ -2751,29 +2965,32 @@
 CONFIG_DEC_ELCP
   This driver is developed for the SMC EtherPower series ethernet
   cards and also works with cards based on the DECchip
-  21040/21041/21140 (Tulip series) chips. (If your card is NOT SMC
-  EtherPower 10/100 PCI (smc9332dst), you can also try the driver from
-  "DE425, DE434, DE435 support", above.) However, most people with a
-  network card of this type will say Y here. Do read the
-  Ethernet-HOWTO, available via ftp (user: anonymous) in
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO. More specific information is
-  contained in Documentation/networking/tulip.txt. 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.
+  21040/21041/21140 (Tulip series) chips. Some LinkSys PCI cards are
+  of this type. (If your card is NOT SMC EtherPower 10/100 PCI
+  (smc9332dst), you can also try the driver from "DE425, DE434, DE435
+  support", above.) However, most people with a network card of this
+  type will say Y here. Do read the Ethernet-HOWTO, available via ftp
+  (user: anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO. More
+  specific information is contained in
+  Documentation/networking/tulip.txt. This driver is also available as
+  a module ( = code which can be inserted in and removed from the
+  running kernel whenever you want). The module will be called
+  tulip.o. 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.
 
 Digi Intl. RightSwitch support
 CONFIG_DGRS
   This is support for the Digi International RightSwitch series of
   PCI/EISA ethernet switch cards.  These include the SE-4 and the SE-6
-  models. If you have a network card of this type, say Y and read
-  the Ethernet-HOWTO, available via ftp (user: anonymous) in
+  models. If you have a network card of this type, say Y and read the
+  Ethernet-HOWTO, available via ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/HOWTO.  More specific information is
   contained in drivers/net/README.dgrs. 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
+  running kernel whenever you want). The module will be called
+  dgrs.o. 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
@@ -2785,8 +3002,9 @@
   the Ethernet-HOWTO, available via ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/HOWTO. 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
+  running kernel whenever you want). The module will be called
+  eth16i.o. 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
@@ -2840,11 +3058,12 @@
   sunsite.unc.edu:/pub/Linux/docs/HOWTO if you want to use this.  If
   you want to compile this as a module ( = code which can be inserted
   in and removed from the running kernel whenever you want), say M
-  here and read Documentation/modules.txt. If you intend to use this
-  pocket adaptor as well as a parallel printer, you should compile
-  both drivers as modules. 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.
+  here and read Documentation/modules.txt. The module will be called
+  de600.o. If you intend to use this pocket adaptor as well as a
+  parallel printer, you should compile both drivers as modules. 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.
 
 D-Link DE620 pocket adaptor support
 CONFIG_DE620
@@ -2854,11 +3073,12 @@
   sunsite.unc.edu:/pub/Linux/docs/HOWTO if you want to use this.  If
   you want to compile this as a module ( = code which can be inserted
   in and removed from the running kernel whenever you want), say M
-  here and read Documentation/modules.txt. If you intend to use this
-  pocket adaptor as well as a parallel printer, you should compile
-  both drivers as modules. 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.
+  here and read Documentation/modules.txt. The module will be called
+  de620.o. If you intend to use this pocket adaptor as well as a
+  parallel printer, you should compile both drivers as modules. 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.
  
 Token Ring driver support
 CONFIG_TR
@@ -2874,14 +3094,21 @@
   almost definitely fail if more than one active Token Ring card is
   present. 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.
+  want). The module will be called ibmtr.o. If you want to compile it
+  as a module, say M here and read Documentation/modules.txt.
 
 Traffic Shaper (EXPERIMENTAL)
 CONFIG_SHAPER
-  The traffic shaper is a virtual network device that allows you to limit
-  the rate of data flow over another device. See
-  Documentation/networking/shaper.txt for more information.
+  The traffic shaper is a virtual network device that allows you to
+  limit the rate of outgoing data flow over another network
+  device. See Documentation/networking/shaper.txt for more
+  information.  To set up and configure shaper devices, you need the
+  shapecfg program, available via ftp (user: anonymous) from
+  shadow.cabi.net/pub/Linux in the shaper package.  This driver is
+  also available as a module ( = code which can be inserted in and
+  removed from the running kernel whenever you want). The module will
+  be called shaper.o. If you want to compile it as a module, say M
+  here and read Documentation/modules.txt. If unsure, say N.
 
 FDDI driver support
 CONFIG_FDDI
@@ -2927,23 +3154,37 @@
   will not be auto detected by the kernel at boot time; you have to
   provide the interface address as an option to the kernel at boot
   time as described in Documentation/cdrom/cdu31a or fill in your
-  parameters into linux/drivers/cdrom/cdu31a.c. See the documentation
-  of your boot loader (lilo or loadlin) about how to pass options to
-  the kernel. The lilo procedure is also explained in the SCSI-HOWTO.
+  parameters into linux/drivers/cdrom/cdu31a.c. Try "man bootparam" or
+  see the documentation of your boot loader (lilo or loadlin) about
+  how to pass options to the kernel. The lilo procedure is also
+  explained in the SCSI-HOWTO. If you say Y here, you should also say
+  Y to "ISO9660 cdrom filesystem support" below, because that's the
+  filesystem used on CDROMs. This driver is also available as a module
+  ( = code which can be inserted in and removed from the running
+  kernel whenever you want). The module will be called cdu31a.o. If
+  you want to compile it as a module, say M here and read
+  Documentation/modules.txt.
 
 Standard Mitsumi [no XA/Multisession] CDROM support
 CONFIG_MCD
   This is the older of the two drivers for the older Mitsumi models
-  LU-005, FX-001 and FX-001D. This is not the right driver for the 
-  FX-001DE and the triple or quad speed models (all these are IDE/ATAPI
-  models).
-  With the old LU-005 model, the whole drive chassis slides out for
-  cd insertion.  The FX-xxx models use a motorized tray type mechanism.
-  Note that this driver does not support XA or MultiSession CDs (PhotoCDs).
-  There is a new driver (next question) which can do this. If you want
-  that one, say N here.
-  If the driver doesn't work out of the box, you might want to have
-  a look at linux/include/linux/mcd.h.
+  LU-005, FX-001 and FX-001D. This is not the right driver for the
+  FX-001DE and the triple or quad speed models (all these are
+  IDE/ATAPI models).
+  With the old LU-005 model, the whole drive chassis slides out for cd
+  insertion.  The FX-xxx models use a motorized tray type mechanism.
+  Note that this driver does not support XA or MultiSession CDs
+  (PhotoCDs).  There is a new driver (next question) which can do
+  this. If you want that one, say N here.
+  If the driver doesn't work out of the box, you might want to have a
+  look at linux/include/linux/mcd.h.  If you say Y here, you should
+  also say Y to "ISO9660 cdrom filesystem support" below, because
+  that's the filesystem used on CDROMs. Please also read the file
+  Documentation/cdrom/mcd. This driver is also available as a module (
+  = code which can be inserted in and removed from the running kernel
+  whenever you want). The module will be called mcd.o. If you want to
+  compile it as a module, say M here and read
+  Documentation/modules.txt.
 
 Mitsumi [XA/MultiSession] support
 CONFIG_MCDX
@@ -2952,7 +3193,14 @@
   FX-001 or FX-001D CDROM drive. In addition, this driver uses much less
   kernel memory than the old one, if that is a concern. This driver is
   able to support more than one drive, but each drive needs a separate
-  interface card. Check out Documentation/cdrom/mcdx.
+  interface card.
+  If you say Y here, you should also say Y to "ISO9660 cdrom
+  filesystem support" below, because that's the filesystem used on
+  CDROMs. Please also read the file Documentation/cdrom/mcdx. This
+  driver is also available as a module ( = code which can be inserted
+  in and removed from the running kernel whenever you want). The
+  module will be called mcdx.o. If you want to compile it as a module,
+  say M here and read Documentation/modules.txt.
 
 Matsushita/Panasonic/Creative, Longshine, TEAC CDROM support
 CONFIG_SBPCD
@@ -2978,14 +3226,22 @@
   card can support up to four CDROM drives; if you say Y here, you
   will be asked how many controllers you have. If compiled as a
   module, only one interface card (but with up to four drives) is
-  usable.
+  usable. 
+  If you say Y here, you should also say Y to "ISO9660 cdrom
+  filesystem support" below, because that's the filesystem used on
+  CDROMs. Please also read the file Documentation/cdrom/sbpcd. This
+  driver is also available as a module ( = code which can be inserted
+  in and removed from the running kernel whenever you want). The
+  module will be called sbpcd.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
 
 Matsushita/Panasonic, ... second CDROM controller support
 CONFIG_SBPCD2
   Say Y here only if you have two CDROM controller boards of this type
   (usually only if you have more than four drives). You should enter
   the parameters for the second, third and fourth interface card into
-  linux/include/linux/sbpcd.h before compiling the new kernel.
+  linux/include/linux/sbpcd.h before compiling the new kernel. Read
+  the file Documentation/cdrom/sbpcd.
 
 Aztech/Orchid/Okano/Wearnes/TXC/CyDROM  CDROM support
 CONFIG_AZTCD
@@ -2993,32 +3249,60 @@
   CD-3110, Okano or Wearnes CDD110, Conrad TXC, or CyCDROM CR520 or
   CR540 CDROM drive.  This driver - just like all these CDROM drivers
   - is NOT for CDROM drives with IDE/ATAPI interface, such as Aztech
-  CDA269-031SE.
+  CDA269-031SE. If you say Y here, you should also say Y to "ISO9660
+  cdrom filesystem support" below, because that's the filesystem used
+  on CDROMs. Please also read the file Documentation/cdrom/aztcd. This
+  driver is also available as a module ( = code which can be inserted
+  in and removed from the running kernel whenever you want). The
+  module will be called aztcd.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
 
 Sony CDU535 CDROM support
 CONFIG_CDU535
-  This is the driver for the older Sony CDU-535 and CDU-531 CDROM drives.
+  This is the driver for the older Sony CDU-535 and CDU-531 CDROM
+  drives.  If you say Y here, you should also say Y to "ISO9660 cdrom
+  filesystem support" below, because that's the filesystem used on
+  CDROMs. Please also read the file Documentation/cdrom/sonycd535. 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you
+  want). The module will be called sonycd535.o. If you want to compile
+  it as a module, say M here and read Documentation/modules.txt.
 
 Goldstar R420 CDROM support
 CONFIG_GSCD
-  If this is your CDROM drive, say Y here.
-  As described in linux/Documentation/cdrom/gscd, you might have to
-  change a setting in the file include/linux/gscd.h before compiling
-  the kernel.
+  If this is your CDROM drive, say Y here.  As described in
+  linux/Documentation/cdrom/gscd, you might have to change a setting
+  in the file include/linux/gscd.h before compiling the kernel. Please
+  read the file Documentation/cdrom/gscd. If you say Y here, you
+  should also say Y to "ISO9660 cdrom filesystem support" below,
+  because that's the filesystem used on CDROMs. This driver is also
+  available as a module ( = code which can be inserted in and removed
+  from the running kernel whenever you want). The module will be
+  called gscd.o. If you want to compile it as a module, say M here and
+  read Documentation/modules.txt.
 
 MicroSolutions backpack CDROM support
 CONFIG_BPCD
   MicroSolutions backpack CDROM is an external drive that connects to
-  the parallel port.  The bpcd driver supports model 164550 (and perhaps
-  other models).  Say Y if you have one of these, and read the
-  file linux/Documentation/cdrom/bpcd.  If you have several different
-  devices that will share a common parallel port, say M and build them
-  as modules.
+  the parallel port.  This driver supports model 164550 (and perhaps
+  other models).  Say Y if you have one of these, and read the file
+  Documentation/cdrom/bpcd. If you say Y here, you should also say Y
+  to "ISO9660 cdrom filesystem support" below, because that's the
+  filesystem used on CDROMs. If you have several different devices
+  that will share a common parallel port, say M and build them as
+  modules. This module will be called bpcd.o.
 
 Philips/LMS CM206 CDROM support
 CONFIG_CM206
   If you have a Philips/LMS CDROM drive cm206 in combination with a
-  cm260 host adapter card, say Y here.
+  cm260 host adapter card, say Y here.  Please also read the file
+  Documentation/cdrom/cm206. If you say Y here, you should also say Y
+  to "ISO9660 cdrom filesystem support" below, because that's the
+  filesystem used on CDROMs. This driver is also available as a module
+  ( = code which can be inserted in and removed from the running
+  kernel whenever you want). The module will be called cm206.o. If you
+  want to compile it as a module, say M here and read
+  Documentation/modules.txt.
 
 Optics Storage DOLPHIN 8000AT CDROM support
 CONFIG_OPTCD
@@ -3026,40 +3310,44 @@
   compatible interface. It also works with the Lasermate CR328A. If
   you have one of those, say Y. This driver does not work for the
   Optics Storage 8001 drive; use the IDE-ATAPI CDROM driver for that
-  one. 
+  one. Please read the file Documentation/cdrom/optcd. 
+  If you say Y here, you should also say Y to "ISO9660 cdrom
+  filesystem support" below, because that's the filesystem used on
+  CDROMs. This driver is also available as a module ( = code which can
+  be inserted in and removed from the running kernel whenever you
+  want). The module will be called optcd.o. If you want to compile it
+  as a module, say M here and read Documentation/modules.txt.
 
 Sanyo CDR-H94A CDROM support
 CONFIG_SJCD
-  If this is your CDROM drive, say Y here. Command line option
-  (or 'append=' option in /etc/lilo.conf) is:
-                sjcd=<port>
-  Here 'port' is the base i/o address used by the drive. It defaults
-  to port=0x340.
+  If this is your CDROM drive, say Y here and read the file
+  Documentation/cdrom/sjcd. You should then also say Y to "ISO9660
+  cdrom filesystem support" below, because that's the filesystem used
+  on CDROMs. This driver is also available as a module ( = code which
+  can be inserted in and removed from the running kernel whenever you
+  want). The module will be called sjcd.o. If you want to compile it
+  as a module, say M here and read Documentation/modules.txt.
 
 Soft configurable cdrom interface card support
 CONFIG_CDI_INIT
   If you want to include boot-time initialization of any cdrom
-  interface card that is software configurable, say Y here.
-  Currently only the ISP16/MAD16/Mozart cards are supported.
+  interface card that is software configurable, say Y here.  Currently
+  only the ISP16/MAD16/Mozart soundcards with built-in cdrom
+  interfaces are supported.  Note that the answer to this question
+  doesn't directly affect the kernel: saying N will just cause this
+  configure script to skip all the questions about these CDROM drives.
 
 ISP16/MAD16/Mozart soft configurable cdrom interface support
 CONFIG_ISP16_CDI
-  If you want any of these cdrom interface cards based on the
-  OPTi 82C928 or 82C929 chips get detected and possibly configured
-  at boot time, please say Y. Boot time command line options (or
-  'append=' options in /etc/lilo.conf) are:
-                isp16=<port>,<irq>,<dma>,<drive_type>
-  Here 'port','irq' and 'dma' are the base i/o address, irq number and
-  dma line assumed to be used by the attached cdrom
-  drive. 'drive_type' is the type of cdrom drive or its emulation
-  mode. Valid values for drive_type include: Sanyo, Panasonic (same as
-  Sanyo), Sony and Mitsumi.  Default values are: port=0x340, irq=0,
-  dma=0, drive_type=Sanyo.
-  The command line
-                isp16=noisp16
-  will skip detection and configuration after all.
-  N.B. options are case sensitive. 
-  Read Documentation/cdrom/isp16 for details. 
+  These are soundcards with with built-in cdrom interfaces using the
+  OPTi 82C928 or 82C929 chips. Say Y here to have them detected and
+  possibly configured at boot time. In addition, You'll have to say Y
+  to a driver for the particular cdrom drive you have attached to the
+  card. Read Documentation/cdrom/isp16 for details.  This driver is
+  also available as a module ( = code which can be inserted in and
+  removed from the running kernel whenever you want). The module will
+  be called isp16.o. If you want to compile it as a module, say M here
+  and read Documentation/modules.txt.
 
 Quota support
 CONFIG_QUOTA
@@ -3081,11 +3369,12 @@
   leaner. You don't want to use it on your harddisk because of certain
   built-in restrictions. This option will enlarge your kernel by about
   25 kB. Everyone should say Y or M so that they are able to read this
-  common floppy format.  If you want to compile this as a module
-  ( = code which can be inserted in and removed from the
-  running kernel whenever you want), say M here and read
-  Documentation/modules.txt. Note that the filesystem of your root
-  partition cannot be compiled as a module.
+  common floppy format.  If you want to compile this as a module ( =
+  code which can be inserted in and removed from the running kernel
+  whenever you want), say M here and read
+  Documentation/modules.txt. The module will be called minix.o. Note
+  that the filesystem of your root partition cannot be compiled as a
+  module.
 
 Second extended fs support
 CONFIG_EXT2_FS
@@ -3102,27 +3391,33 @@
   transition to a *real* Linux partition later. Another (rare) case
   which doesn't require ext2fs is a diskless Linux box which mounts
   all files over the network using NFS (in this case it's sufficient
-  to enable NFS filesystem support below; if you are planning to do
-  this, have a look at the netboot package in
-  /pub/Linux/system/Linux-boot/, available via ftp (user: anonymous)
-  from sunsite.unc.edu, extract with "tar xzvf filename"). There is a
-  short ext2fs-FAQ, available via ftp (user: anonymous) in
+  to say Y to "NFS filesystem support" below). There is a short
+  ext2fs-FAQ, available via ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/faqs. This option will enlarge your
-  kernel by about 41 kB. Default is Y.
+  kernel by about 41 kB. If you want to compile this filesystem as a
+  module ( = code which can be inserted in and removed from the
+  running kernel whenever you want), say M here and read
+  Documentation/modules.txt. The module will be called ext2.o. Be
+  aware however that the filesystem of your root partition cannot be
+  compiled as a module, and so this could be dangerous. Most everyone
+  wants to say Y here.
 
 fat fs support
 CONFIG_FAT_FS
   If you want to use one of the FAT-based filesystems (the MS-DOS,
-  VFAT (Windows'95) and UMSDOS filesystems), then you must include
-  FAT support. This is not a filesystem in itself, but it provides
-  the foundation for the other filesystems. This option will enlarge
-  your kernel about 24 kB. If unsure, say Y. If you want to compile
-  this as a module however ( = code which can be inserted in and 
-  removed from the running kernel whenever you want), say M here and
-  read Documentation/modules.txt. Note that if you compile the FAT
-  support as a module, you cannot compile any of the FAT-based file-
-  systems into the kernel - they will have to be modules as well.
-  The filesystem of your root partition cannot be a module.
+  VFAT (Windows'95) and UMSDOS (used to run Linux on top of an
+  ordinary DOS partition) filesystems), then you must include FAT
+  support. This is not a filesystem in itself, but it provides the
+  foundation for the other filesystems. This option will enlarge your
+  kernel by about 24 kB. If unsure, say Y. If you want to compile this
+  as a module however ( = code which can be inserted in and removed
+  from the running kernel whenever you want), say M here and read
+  Documentation/modules.txt. The module will be called fat.o. Note
+  that if you compile the FAT support as a module, you cannot compile
+  any of the FAT-based filesystems into the kernel - they will have to
+  be modules as well.  The filesystem of your root partition cannot be
+  a module, so don't say M here if you intend to use UMSDOS as your
+  root filesystem.
 
 msdos fs support
 CONFIG_MSDOS_FS
@@ -3148,8 +3443,8 @@
   work if you said Y to "fat fs support" as well. If you want to
   compile this as a module however ( = code which can be inserted in
   and removed from the running kernel whenever you want), say M here
-  and read Documentation/modules.txt. Note that the filesystem of your
-  root partition cannot be a module.
+  and read Documentation/modules.txt. The module will be called
+  msdos.o.
 
 vfat fs support
 CONFIG_VFAT_FS
@@ -3159,11 +3454,12 @@
   partitions. It does not support Windows'95 compressed filesystems.
   You cannot use the VFAT filesystem for your root partition; use
   UMSDOS instead. This option enlarges your kernel by about 10 kB and
-  it only works if you enabled the "fat fs support" above. Please read
+  it only works if you said Y to the "fat fs support" above. Please read
   the file Documentation/filesystems/vfat.txt for details.
   If unsure, say N. If you want to compile this as a module ( = code 
   which can be inserted in and removed from the running kernel whenever 
-  you want), say M here and read Documentation/modules.txt.
+  you want), say M here and read Documentation/modules.txt. The module
+  will be called vfat.o.
 
 umsdos: Unix like fs on top of std MSDOS fs
 CONFIG_UMSDOS_FS
@@ -3177,14 +3473,14 @@
   is to write files with long unix filenames to MSDOS floppies; it
   also allows unix style softlinks and owner/permissions of files on
   MSDOS floppies. You will need a program called umssync in order to
-  make use of umsdos. Read Documentation/filesystems/umsdos.txt. This
+  make use of umsdos; read Documentation/filesystems/umsdos.txt. This
   option enlarges your kernel by about 25 kB and it only works if you
-  enabled both "fat fs support" and "msdos fs support" above. If
-  unsure, say N.  If you want to compile this as a module ( = code
-  which can be inserted in and removed from the running kernel
-  whenever you want), say M here and read
-  Documentation/modules.txt. Note that the filesystem of your root
-  partition cannot be a module.
+  said Y to both "fat fs support" and "msdos fs support" above. If you
+  want to compile this as a module ( = code which can be inserted in
+  and removed from the running kernel whenever you want), say M here
+  and read Documentation/modules.txt. The module will be called
+  umsdos.o. Note that the filesystem of your root partition cannot be
+  a module, so this could be dangerous. If unsure, say N.
 
 /proc filesystem support
 CONFIG_PROC_FS
@@ -3199,21 +3495,22 @@
   example, "cat /proc/interrupts" gives information about what the
   different IRQs are used for at the moment (there is a small number
   of Interrupt ReQuest lines in your computer that are used by the
-  periphery to gain the CPU's attention - often a source of trouble if
-  two devices are mistakenly configured to use the same IRQ). Several
-  programs depend on this, so everyone should say Y here.
+  attached devices to gain the CPU's attention - often a source of
+  trouble if two devices are mistakenly configured to use the same
+  IRQ). Several programs depend on this, so everyone should say Y
+  here.
   
 NFS filesystem support
 CONFIG_NFS_FS
   If you are connected to some other (usually local) Unix computer
-  (using SLIP, PLIP, PPP or ethernet) and want to mount files
-  residing on that computer (the NFS server) using the Network
-  File Sharing protocol, say Y. "Mounting files" means that the client
-  can access the files with usual UNIX commands as if they were
-  sitting on the client's harddisk. For this to work, the server must
-  run the programs nfsd and mountd (but does not need to have NFS
-  filesystem support enabled). NFS is explained in the Network
-  Administrator's Guide, available via ftp (user: anonymous) in
+  (using SLIP, PLIP, PPP or ethernet) and want to mount files residing
+  on that computer (the NFS server) using the Network File Sharing
+  protocol, say Y. "Mounting files" means that the client can access
+  the files with usual UNIX commands as if they were sitting on the
+  client's harddisk. For this to work, the server must run the
+  programs nfsd and mountd (but does not need to have NFS filesystem
+  support enabled). NFS is explained in the Network Administrator's
+  Guide, available via ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/LDP, and on its man page: "man
   nfs". There is also a NFS-FAQ in
   sunsite.unc.edu:/pub/Linux/docs/faqs which presumes that you know
@@ -3221,11 +3518,15 @@
   to TCP/IP networking also. This option would enlarge your kernel by
   about 27 kB. This filesystem 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. If you configure a diskless
-  machine which will mount its root filesystem over nfs, you cannot
-  compile this driver as a module. If you don't know what all this is
-  about, say N.
+  whenever you want). The module is called nfs.o. If you want to
+  compile it as a module, say M here and read
+  Documentation/modules.txt. If you configure a diskless machine which
+  will mount its root filesystem over nfs (in order to do that, check
+  out the netboot package, available via ftp (user: anonymous) from
+  sunsite.unc.edu in /pub/Linux/system/Linux-boot/, extract with "tar
+  xzvf filename", and say Y to "Root file system on NFS" below), then
+  you cannot compile this driver as a module. If you don't know what
+  all this is about, say N.
 
 Root file system on NFS
 CONFIG_ROOT_NFS
@@ -3270,7 +3571,7 @@
   kernel by about 27 kB; otherwise say N.  If you want to compile this
   as a module ( = code which can be inserted in and removed from the
   running kernel whenever you want), say M here and read
-  Documentation/modules.txt.
+  Documentation/modules.txt. The module will be called isofs.o.
 
 OS/2 HPFS filesystem support (read only)
 CONFIG_HPFS_FS
@@ -3282,17 +3583,18 @@
   able to read them. Read Documentation/filesystems/hpfs.txt. This
   filesystem 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. If unsure, say N.
+  want). The module is called hpfs.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt. If unsure,
+  say N.
   
 System V and Coherent filesystem support
 CONFIG_SYSV_FS
   SCO, Xenix and Coherent are commercial Unix systems for intel
-  machines. Enabling this option would allow you to read and write to
-  and from their floppies and harddisk partitions. If you have a
-  floppy or harddisk partition like that, it is probable that they
-  contain binaries from those other Unix systems; in order to run
-  these binaries, you will want to install iBCS2 (iBCS2 [Intel Binary
+  machines. Saying Y here would allow you to read and write to and
+  from their floppies and harddisk partitions. If you have a floppy or
+  harddisk partition like that, it is probable that they contain
+  binaries from those other Unix systems; in order to run these
+  binaries, you will want to install iBCS2 (iBCS2 [Intel Binary
   Compatibility Standard] is a kernel module which lets you run SCO,
   Xenix, Wyse, Unix Ware, Dell Unix and System V programs under Linux
   and is often needed to run commercial software, most prominently
@@ -3309,70 +3611,71 @@
   kernel by about 34 kB. If you want to compile this as a module ( =
   code which can be inserted in and removed from the running kernel
   whenever you want), say M here and read
-  Documentation/modules.txt. If you haven't heard about all of this
-  before, it's safe to say N.
+  Documentation/modules.txt. The module will be called sysv.o. If you
+  haven't heard about all of this before, it's safe to say N.
 
 BSD UFS filesystem support (read only)
 CONFIG_UFS_FS
   BSD and derivate versions of Unix (such as SunOS, FreeBSD, NetBSD
   and NeXTstep) use a filesystem called UFS. Some System V Unixes can
-  create and mount partitions and diskettes using this filesystem
-  as well. Enabling this option allows you to mount these partitions
-  and diskettes read-only. If you only intend to mount files from
-  some other Unix over the network using NFS, you don't need the
-  UFS filesystem support (but you need nfs filesystem support
+  create and mount partitions and diskettes using this filesystem as
+  well. Saying Y here allows you to mount these partitions and
+  diskettes read-only. If you only intend to mount files from some
+  other Unix over the network using NFS, you don't need the UFS
+  filesystem support (but you need nfs filesystem support
   obviously). Note that this option is generally not needed for
   floppies, since a good portable way to transport files and
-  directories between unixes (and even other operating systems)
-  is given by the tar program ("man tar"). When accessing NeXTstep
-  files, you may need to convert them from the NeXT character set
-  to the Latin1 character set; use GNU recode for this purpose.
-  Say Y to build UFS support into your kernel. If you want to compile
-  this as a module ( = code which can be inserted in and removed from
-  the running kernel whenever you want), say M here and read
-  Documentation/modules.txt. If you haven't heard about all of this
-  before, it's safe to say N.
+  directories between unixes (and even other operating systems) is
+  given by the tar program ("man tar"). When accessing NeXTstep files,
+  you may need to convert them from the NeXT character set to the
+  Latin1 character set; use GNU recode for this purpose.  Say Y to
+  build UFS support into your kernel. If you want to compile this as a
+  module ( = code which can be inserted in and removed from the
+  running kernel whenever you want), say M here and read
+  Documentation/modules.txt. The module will be called ufs.o. If you
+  haven't heard about all of this before, it's safe to say N.
 
 BSD disklabel (FreeBSD partition tables) support
 CONFIG_BSD_DISKLABEL
   FreeBSD uses its own partition scheme on your PC. It requires only
   one entry in the primary partition table of your disk and manages it
   similarly to DOS extended partitions, putting in its first sector a
-  new partition table in disklabel format. Enabling this option allows
-  you to read these disklabels and further mount FreeBSD partitions on
-  your Linux box if you also have configured BSD ufs filesystem
-  support. If you don't know what all this is about, say N.
+  new partition table in disklabel format. Saying Y here allows you to
+  read these disklabels and further mount FreeBSD partitions on your
+  Linux box if you also have configured BSD ufs filesystem support. If
+  you don't know what all this is about, say N.
 
 SMD disklabel (Sun partition tables) support
 CONFIG_SMD_DISKLABEL
   Like most systems, SunOS uses its own partition table format,
-  incompatible with all others. Enabling this option allows you to read
-  these partition tables and further mount SunOS disks on your Linux
-  box if you also have configured BSD ufs filesystem support. This is
-  mainly used to carry data from a Sparc under SunOS to your Linux box
-  via a removable medium like magneto-optical or ZIP drives. If you
-  don't know what all this is about, say N.
+  incompatible with all others. Saying Y here allows you to read these
+  partition tables and further mount SunOS disks on your Linux box if
+  you also have configured BSD ufs filesystem support. This is mainly
+  used to carry data from a Sparc under SunOS to your Linux box via a
+  removable medium like magneto-optical or ZIP drives. If you don't
+  know what all this is about, say N.
 
 SMB filesystem support (to mount WfW shares etc..)
 CONFIG_SMB_FS
   SMB (Server Message Buffer) is the protocol Windows for Workgroups
-  (WfW), Windows NT and Lan Manager use to talk to each other over an
-  ethernet. Enabling this allows you to mount their filesystems (often
-  called "shares") and access them just like any other unix
-  directory. For details, read Documentation/filesystems/smbfs.txt.
-  Note: if you just want your box to act as an SMB *server* and make
-  files and printing services available to Windows clients (which need
-  to have a TCP/IP stack), you don't need to enable this filesystem
-  support; you can use the program samba (available via ftp (user:
-  anonymous) in sunsite.unc.edu:/pub/Linux/system/Network/samba) for
-  that. General information about how to connect Linux, Windows
-  machines and Macs is on the WWW at
-  http://eats.com/linux_mac_win.html (to browse the WWW, you need to
-  have access to a machine on the Internet that has one of the
-  programs lynx, netscape or Mosaic).  If you want to compile the SMB
-  support as a module ( = code which can be inserted in and removed
-  from the running kernel whenever you want), say M here and read
-  Documentation/modules.txt. Most people say N, however.
+  (WfW), Windows 95, Windows NT and Lan Manager use to share files and
+  printers over local networks. Saying Y here allows you to mount
+  their filesystems (often called "shares" in this context) and access
+  them just like any other unix directory. For details, read
+  Documentation/filesystems/smbfs.txt.  Note: if you just want your
+  box to act as an SMB *server* and make files and printing services
+  available to Windows clients (which need to have a TCP/IP stack),
+  you don't need to say Y here; you can use the program samba
+  (available via ftp (user: anonymous) in
+  sunsite.unc.edu:/pub/Linux/system/Network/samba) for that. General
+  information about how to connect Linux, Windows machines and Macs is
+  on the WWW at http://eats.com/linux_mac_win.html (to browse the WWW,
+  you need to have access to a machine on the Internet that has one of
+  the programs lynx, netscape or Mosaic).  If you want to compile the
+  SMB support as a module ( = code which can be inserted in and
+  removed from the running kernel whenever you want), say M here and
+  read Documentation/modules.txt. The module will be called
+  smbfs.o. Most people say N, however.
 
 SMB Win95 bug work-around
 CONFIG_SMB_WIN95
@@ -3384,41 +3687,47 @@
 NCP filesystem support (to mount NetWare volumes)
 CONFIG_NCP_FS
   NCP (NetWare Core Protocol) is a protocol that runs over IPX and is
-  used by Novel NetWare clients to talk to file servers. It is to IPX
-  what nfs is to tcp/ip, if that helps. Enabling this option allows
-  you to mount NetWare file server volumes and to access them just
-  like any other Unix directory. For details, please read the file
+  used by Novell NetWare clients to talk to file servers. It is to IPX
+  what nfs is to tcp/ip, if that helps. Saying Y here allows you to
+  mount NetWare file server volumes and to access them just like any
+  other Unix directory. For details, please read the file
   Documentation/filesystems/ncpfs.txt in the kernel source and the
   IPX-HOWTO on sunsite.unc.edu:/pub/Linux/docs/howto.  If you want to
   compile this as a module ( = code which can be inserted in and
   removed from the running kernel whenever you want), say M here and
-  read Documentation/modules.txt.
+  read Documentation/modules.txt. The module will be called
+  ncpfs.o. Say N unless you are connected to a Novell network.
 
-Amiga FFS filesystem support (EXPERIMENTAL)
+Amiga FFS filesystem support
 CONFIG_AFFS_FS
-  The Fast File System (FFS) is the common filesystem used on harddisks
-  by Amiga (tm) Systems since AmigaOS Version 1.3 (34.20). It's also
-  possible to mount diskfiles used by the Un*X Amiga Emulator by Bernd
-  Schmidt (http://www-users.informatik.rwth-aachen.de/~crux/uae.html)
-  If you want to do the latter, you will also need the loop device
-  support. Say Y if you want to be able to read and write files from
-  and to an Amiga FFS partition of your harddrive. Amiga floppies
-  however cannot be read with this driver due to an incompatibility of
-  the floppy controller used in an Amiga and the standard floppy
-  controller in PCs and workstations. Read
-  Documentation/filesystems/affs.txt. This filesystem 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.
-  If unsure, say N.
+  The Fast File System (FFS) is the common filesystem used on
+  harddisks by Amiga(tm) Systems since AmigaOS Version 1.3
+  (34.20). With this driver you can also mount diskfiles used by the
+  Un*X Amiga Emulator by Bernd Schmidt
+  (http://www-users.informatik.rwth-aachen.de/~crux/uae.html).  If you
+  want to do the latter, you will also need to say Y to "Loop device
+  support", above. Say Y if you want to be able to read and write
+  files from and to an Amiga FFS partition on your harddrive. Amiga
+  floppies however cannot be read with this driver due to an
+  incompatibility of the floppy controller used in an Amiga and the
+  standard floppy controller in PCs and workstations. Read
+  Documentation/filesystems/affs.txt. This filesystem is also
+  available as a module ( = code which can be inserted in and removed
+  from the running kernel whenever you want). The module is called
+  affs.o. If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say N.
 
-ROMFS filesystem support (EXPERIMENTAL)
+ROM filesystem support
 CONFIG_ROMFS_FS
-  This is a special file system intended for installation disks or
-  otherwise prebuilt medias.  It has very low overhead and low memory
-  requirements.  However, it's read-only (one particular reason of the
-  smallness), so you need extra programs to prepare disks in this
-  format.  If you are not sure, just say N, you don't need it.
+  This is a very small read-only filesystem mainly intended for
+  initial ram disks of installation disk, but it could be used for
+  other read-only media as well. Read
+  Documentation/filesystems/romfs.txt for details. This filesystem is
+  also available as a module ( = code which can be inserted in and
+  removed from the running kernel whenever you want). The module is
+  called romfs.o. If you want to compile it as a module, say M here
+  and read Documentation/modules.txt.  If you don't know whether you
+  need it, then you don't need it: say N.
 
 Standard/generic serial support
 CONFIG_SERIAL
@@ -3427,15 +3736,17 @@
   setting up dedicated ethernet WWW/ftp servers, or users that have
   one of the various bus mice instead of a serial mouse.  (Note that
   the Cyclades and Stallion multi serial port drivers do not need this
-  driver built in for them to work. They are completely independent of
-  each other.)  If you want to compile this driver as a module, say M
-  here and read Documentation/modules.txt.  [WARNING: Do not compile
-  this driver as a module if you are using non-standard serial ports,
-  since the configuration information will be lost when kerneld
-  automatically unloads the driver.  This limitation may be lifted in
-  the future.]  Most people will say Y or M here, so that they can use
-  serial mice, modems and similar devices connecting to the standard
-  serial ports.
+  driver built in for them to work.)  If you want to compile this
+  driver as a module, say M here and read
+  Documentation/modules.txt. The module will be called
+  serial.o. [WARNING: Do not compile this driver as a module if you
+  are using non-standard serial ports, since the configuration
+  information will be lost when kerneld automatically unloads the
+  driver.  This limitation may be lifted in the future.] BTW: If you
+  have a mouseman serial mouse which is not recognized by the X window
+  system, try running gpm first.  Most people will say Y or M here, so
+  that they can use serial mice, modems and similar devices connecting
+  to the standard serial ports.
 
 Digiboard PC/Xx Support
 CONFIG_DIGI
@@ -3443,16 +3754,19 @@
   that give you many serial ports. You would need something like this
   to connect more than two modems to your linux box, for instance in
   order to become a BBS. If you have a card like that, say Y here and
-  read the file Documentation/digiboard.txt.
+  read the file Documentation/digiboard.txt. If you want to compile
+  this driver as a module, say M here and read
+  Documentation/modules.txt. The module will be called pcxx.o.
 
 SDL RISCom/8 card support
 CONFIG_RISCOM8
   This is a driver for the SDL Communications RISCom/8 multiport card,
-  that give you many serial ports. You would need something like this
-  to connect more than two modems to your linux box, for instance in
-  order to become a BBS. If you have a card like that, say Y here and
-  read the file Documentation/riscom8.txt. Also it's possible to say
-  M here and compile this driver as kernel loadable module.
+  which gives you many serial ports. You would need something like
+  this to connect more than two modems to your linux box, for instance
+  in order to become a BBS. If you have a card like that, say Y here
+  and read the file Documentation/riscom8.txt. Also it's possible to
+  say M here and compile this driver as kernel loadable module; the
+  module will be called riscom8.o.
 
 Cyclades async mux support
 CONFIG_CYCLADES
@@ -3461,9 +3775,10 @@
   your linux box, for instance in order to become a BBS. If you want
   to compile this as a module ( = code which can be inserted in and
   removed from the running kernel whenever you want), say M here and
-  read Documentation/modules.txt. If you haven't heard about it, it's
-  safe to say N. (As of 1.3.9x kernels, this driver's minor numbers
-  start at 0 instead of 32.)
+  read Documentation/modules.txt. The module will be called
+  cyclades.o. If you haven't heard about it, it's safe to say N. (As
+  of 1.3.9x kernels, this driver's minor numbers start at 0 instead of
+  32.)
 
 Stallion multiport serial support 
 CONFIG_STALDRV
@@ -3475,13 +3790,13 @@
   heard about all this, it's safe to say N.
  
 Stallion EasyIO or EC8/32 support 
-CONFIG_STALLION n
+CONFIG_STALLION
   If you have an EasyIO or EasyConnection 8/32 multiport Stallion
   card, then this is for you; say Y. Make sure to read
   drivers/char/README.stallion. If you want to compile this as a
   module ( = code which can be inserted in and removed from the
   running kernel whenever you want), say M here and read
-  Documentation/modules.txt.
+  Documentation/modules.txt. The module will be called stallion.o.
 
 Stallion EC8/64, ONboard, Brumby support
 CONFIG_ISTALLION
@@ -3489,7 +3804,8 @@
   serial multiport card, say Y here. Make sure to read
   drivers/char/README.stallion. To compile it as a module ( = code
   which can be inserted in and removed from the running kernel
-  whenever you want), say M here and read Documentation/modules.txt.
+  whenever you want), say M here and read
+  Documentation/modules.txt. The module will be called istallion.o.
 
 Hayes ESP serial port support
 CONFIG_ESPSERIAL
@@ -3497,19 +3813,22 @@
   to transfer data to and from the host.  Make sure to read
   drivers/char/README.esp. To compile this driver as a module ( = code
   which can be inserted in and removed from the running kernel
-  whenever you want), say M here and read Documentation/modules.txt.
+  whenever you want), say M here and read
+  Documentation/modules.txt. The module will be called esp.o.
+  If unsure, say N.
 
 Hayes ESP serial port DMA channel
 CONFIG_ESPSERIAL_DMA_CHANNEL
-  This is the DMA channel to be used to transfer data to and from the host.
-  One DMA channel is shared between all the ESP ports.   Valid values are
-  1 and 3.
+  This is the DMA channel to be used to transfer data to and from the
+  host.  One DMA channel is shared between all the ESP ports.  Valid
+  values are 1 and 3.
 
 Hayes ESP serial port trigger level
 CONFIG_ESPSERIAL_TRIGGER_LEVEL
-  This is the trigger level (in bytes) of the transmit FIFO and the receive
-  FIFO.  Larger values may result in fewer interrupts; however, a value too
-  high could result in data loss.  Valid values are 1 through 1015.
+  This is the trigger level (in bytes) of the transmit FIFO and the
+  receive FIFO.  Larger values may result in fewer interrupts;
+  however, a value too high could result in data loss.  Valid values
+  are 1 through 1015.
 
 Parallel printer support
 CONFIG_PRINTER
@@ -3520,17 +3839,18 @@
   sunsite.unc.edu:/pub/Linux/docs/HOWTO.  If you want to compile this
   as a module ( = code which can be inserted in and removed from the
   running kernel whenever you want), say M here and read
-  Documentation/modules.txt. If you want to use both a parallel
-  printer and PLIP, there are two cases: 1) If the printer and the
-  PLIP cable are to use the same parallel port (presumably because you
-  have just one), it is best to compile both drivers as modules and
-  load and unload them as needed. 2) To use different parallel ports
-  for the printer and the PLIP cable, you can say Y to this printer
-  driver, specify the base address of the parallel port(s) to use for
-  the printer(s) with the "lp" kernel command line option. (See the
-  documentation of your boot loader (lilo or loadlin) about how to
-  pass options to the kernel at boot time. The lilo procedure is also
-  explained in the SCSI-HOWTO, available via ftp (user: anonymous) in
+  Documentation/modules.txt. The module will be called plip.o. If you
+  want to use both a parallel printer and PLIP, there are two cases:
+  1) If the printer and the PLIP cable are to use the same parallel
+  port (presumably because you have just one), it is best to compile
+  both drivers as modules and load and unload them as needed. 2) To
+  use different parallel ports for the printer and the PLIP cable, you
+  can say Y to this printer driver, specify the base address of the
+  parallel port(s) to use for the printer(s) with the "lp" kernel
+  command line option. (Try "man bootparam" or see the documentation
+  of your boot loader (lilo or loadlin) about how to pass options to
+  the kernel at boot time. The lilo procedure is also explained in the
+  SCSI-HOWTO, available via ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/HOWTO.) The standard base addresses
   as well as the syntax of the "lp" command line option can be found
   in drivers/char/lp.c. You can then say Y to the PLIP driver or,
@@ -3563,8 +3883,9 @@
   sunsite.unc.edu:/pub/Linux/docs/HOWTO.  If you want to compile this
   as a module ( = code which can be inserted in and removed from the
   running kernel whenever you want), say M here and read
-  Documentation/modules.txt. If you are unsure, say N and read the
-  HOWTO nevertheless: it will tell you what you have. 
+  Documentation/modules.txt. The module will be called busmouse.o. If
+  you are unsure, say N and read the HOWTO nevertheless: it will tell
+  you what you have.
 
 PS/2 mouse (aka "auxiliary device") support
 CONFIG_PSMOUSE
@@ -3583,9 +3904,9 @@
   sunsite.unc.edu:/pub/Linux/system/Misc, solves this problem. If you
   want to compile this mouse driver as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
-  say M here and read Documentation/modules.txt. If you are unsure,
-  say N and read the HOWTO nevertheless: it will tell you what you
-  have.
+  say M here and read Documentation/modules.txt. The module will be
+  called psaux.o. If you are unsure, say N and read the HOWTO
+  nevertheless: it will tell you what you have.
 
 C&T 82C710 mouse port support (as on TI Travelmate)
 CONFIG_82C710_MOUSE
@@ -3602,10 +3923,11 @@
   (user: anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO.  If you
   want to compile this as a module ( = code which can be inserted in
   and removed from the running kernel whenever you want), say M here
-  and read Documentation/modules.txt. If you are unsure, say N and
-  read the HOWTO nevertheless: it will tell you what you have. Also be
-  aware that several vendors talk about 'Microsoft busmouse' and
-  actually mean PS/2 busmouse - so count the pins on the connector.
+  and read Documentation/modules.txt. The module will be called
+  msbusmouse.o. If you are unsure, say N and read the HOWTO
+  nevertheless: it will tell you what you have. Also be aware that
+  several vendors talk about 'Microsoft busmouse' and actually mean
+  PS/2 busmouse - so count the pins on the connector.
 
 ATIXL busmouse support
 CONFIG_ATIXL_BUSMOUSE
@@ -3615,8 +3937,9 @@
   anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO.  If you want to
   compile this as a module ( = code which can be inserted in and
   removed from the running kernel whenever you want), say M here and
-  read Documentation/modules.txt. If you are unsure, say N and read
-  the HOWTO nevertheless: it will tell you what you have. 
+  read Documentation/modules.txt. The module will be called
+  atixlmouse.o. If you are unsure, say N and read the HOWTO
+  nevertheless: it will tell you what you have.
 
 Support for user miscellaneous modules
 CONFIG_UMISC
@@ -3631,7 +3954,8 @@
   If you have a non-SCSI tape drive like that, say Y. Or, if you want
   to compile this driver as a module ( = code which can be inserted in
   and removed from the running kernel whenever you want), say M here
-  and read Documentation/modules.txt.
+  and read Documentation/modules.txt. The module will be called
+  tpqic02.o.
 
 Do you want runtime configuration for QIC-02
 CONFIG_QIC02_DYNCONF
@@ -3648,16 +3972,17 @@
   If you have a tape drive that is connected to your floppy
   controller, say Y here. Some tape drives (like the Iomega Ditto
   3200) come with a high speed controller of its own.  These drives
-  (and their companion controller) is also supported. If you have a
-  special controller (such as the CMS FC-10, FC-20, Iomega Mach-II, or
-  Ditto Dash), you must configure it by editing the file
+  (and their companion controller) are also supported by this driver,
+  so say Y if you have one. If you have a special controller (such as
+  the CMS FC-10, FC-20, Iomega Mach-II, or Ditto Dash), you must say Y
+  here and configure it by editing the file
   drivers/char/ftape/Makefile. If you want to use such a tape drive on
   a PCI-bus based system, please read the file
   drivers/char/ftape/README.PCI. This driver is also available as a
   runtime loadable 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.
+  Documentation/modules.txt. The module will be called ftape.o.
 
 Zilog serial support
 CONFIG_SUN_ZS
@@ -3681,11 +4006,21 @@
   also don't have compliant BIOSes, and this driver will cause those
   machines to panic during the boot phase (typically, these machines
   are using a data segment of 0040, which is reserved for the Linux
-  kernel). If you get random kernel OOPSes that don't seem to be
-  related to anything and you have a motherboard with APM support, try
-  disabling/enabling this option. Generally, if you don't have a
-  battery in your machine, there isn't much point in using this
-  driver.
+  kernel). Generally, if you don't have a battery in your machine,
+  there isn't much point in using this driver and you should say N.
+  If you get random kernel OOPSes or reboots that don't seem to be
+  related to anything, try disabling/enabling this option. Some other
+  things to try when experiencing seemingly random, "weird" problems:
+   1) passing the "no-hlt" option to the kernel 
+   2) passing the "no-387" option to the kernel 
+   3) passing the "mem=4M" option to the kernel (thereby disabling 
+      all but the first 4M of RAM)
+   4) Reading the sig11 FAQ at http://www.bitwizard.nl/sig11/
+   5) disabling the cache from your BIOS settings
+   6) installing a better fan
+   7) exchanging RAM chips 
+   8) exchanging the motherboard.
+
 
 Ignore USER SUSPEND
 CONFIG_APM_IGNORE_USER_SUSPEND
@@ -3737,28 +4072,32 @@
 
 Watchdog Timer Support 
 CONFIG_WATCHDOG
-  If you enable this option and create a character special file
-  /dev/watchdog with major number 10 and minor number 130 using mknod
-  ("man mknod"), you will get a watchdog, i.e.: subsequently opening
-  the file and failing to write to it for longer than 1 minute will
-  result in rebooting the machine. This could be useful for a
-  networked machine that needs to come back online as fast as possible
-  after a lock-up. There's a watchdog implementation entirely in
-  software (which can sometimes fail to reboot the machine) and a
-  driver for hardware watchdog boards, which are more robust and can
-  also keep track of the temperature inside your computer. For
-  details, read Documentation/watchdog.txt in the kernel source. If
-  unsure, say N. 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.
+  If you say Y here (and to one of the following options) and create a
+  character special file /dev/watchdog with major number 10 and minor
+  number 130 using mknod ("man mknod"), you will get a watchdog, i.e.:
+  subsequently opening the file and failing to write to it for longer
+  than 1 minute will result in rebooting the machine. This could be
+  useful for a networked machine that needs to come back online as
+  fast as possible after a lock-up. There's both a watchdog
+  implementation entirely in software (which can sometimes fail to
+  reboot the machine) and a driver for hardware watchdog boards, which
+  are more robust and can also keep track of the temperature inside
+  your computer. For details, read Documentation/watchdog.txt in the
+  kernel source.
+  The watchdog is usually used together with the watchdog daemon which
+  is available via ftp (user: anonymous) from
+  tsx-11.mit.edu/pub/linux/sources/sbin/. This daemon can also monitor
+  NFS connections and can reboot the machine when the process table is
+  full.
+  If unsure, say N.
 
 Disable watchdog shutdown on close
 CONFIG_WATCHDOG_NOWAYOUT
-  The default watchdog behaviour is to stop the timer if the process
-  managing it closes the file /dev/watchdog. It's always remotely
-  possible that this process might get killed. If you enable this
-  option, the watchdog cannot be stopped once it has been started.
+  The default watchdog behaviour (which you get if you say N here) is
+  to stop the timer if the process managing it closes the file
+  /dev/watchdog. It's always remotely possible that this process might
+  get killed. If you say Y here, the watchdog cannot be stopped once
+  it has been started.
 
 WDT Watchdog timer
 CONFIG_WDT
@@ -3768,7 +4107,7 @@
   source at the top of drivers/char/wdt.c. If you want to compile this
   as a module ( = code which can be inserted in and removed from the
   running kernel whenever you want), say M here and read
-  Documentation/modules.txt.
+  Documentation/modules.txt. The module will be called wdt.o.
 
 WDT501 features
 CONFIG_WDT_501
@@ -3791,7 +4130,8 @@
   from. Equally it's a lot cheaper to install. 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.
+  it as a module, say M here and read Documentation/modules.txt. The
+  module will be called softdog.o.
 
 Berkshire Products PC Watchdog
 CONFIG_PCWATCHDOG
@@ -3799,46 +4139,28 @@
   This card simply watches your kernel to make sure it doesn't freeze,
   and if it does, it resets your computer after a certain amount of
   time.  This driver is like the WDT501 driver but for different
-  hardware. The PC watchdog cards can be ordered from
-  http://www.berkprod.com. Some example rc.local files are available
-  from ftp.bitgate.com. 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.  Most people will say N.
-
-Support for Revision A cards
-CONFIG_PCWD_REV_A
-  This gives you support for revision A or B of the Berkshire PC Watchdog
-  Card.  The way to tell if you have an A or B style card is to check the
-  manual on page 22.  If it doesn't say "Port 3" at the top, you have a
-  revision A or B card.  Also, if your card doesn't have an audible beep,
-  chances are you have a revision A or B card.
-
-Support for Revision C cards
-CONFIG_PCWD_REV_C
-  This card gives you an audible beep.  It also has support for disabling
-  the card, enabling it, getting firmware versions, and a few other options.
-
-Show card state on reset
-CONFIG_PCWD_SHOW_PREVSTAT
-  Enabling this option will display the previous reset state of your card.
-  It will also give a little more verbose data about the card, or your
-  system's previous status before reset.
+  hardware. Please read Documentation/pcwd-watchdog.txt. The PC
+  watchdog cards can be ordered from http://www.berkprod.com. Some
+  example rc.local files are available from ftp.bitgate.com. This
+  driver is also available as a module ( = code which can be inserted
+  in and removed from the running kernel whenever you want). The
+  module is called pcwd.o. If you want to compile it as a module, say
+  M here and read Documentation/modules.txt.  Most people will say N.
 
 Enhanced Real Time Clock Support
 CONFIG_RTC
-  If you enable this option and create a character special file
-  /dev/rtc with major number 10 and minor number 135 using mknod ("man
-  mknod"), you will get access to the real time clock built into your
+  If you say Y here and create a character special file /dev/rtc with
+  major number 10 and minor number 135 using mknod ("man mknod"), you
+  will get access to the real time clock built into your
   computer. Every PC has such a clock built in. It can be used to
   generate signals from as low as 1Hz up to 8192Hz, and can also be
   used as a 24 hour alarm.  It reports status information via the file
   /proc/rtc and its behaviour is set by various ioctls on
   /dev/rtc. People running SMP (= multiprocessor) versions of Linux
-  should enable this option to read and set the RTC clock in a SMP
-  compatible fashion. If you think you have a use for such a device
-  (such as periodic data sampling), then say Y here, and go read the
-  file Documentation/rtc.txt for details.
+  should say Y here to read and set the RTC clock in a SMP compatible
+  fashion. If you think you have a use for such a device (such as
+  periodic data sampling), then say Y here, and go read the file
+  Documentation/rtc.txt for details.
 
 Sound card support
 CONFIG_SOUND
@@ -3857,11 +4179,6 @@
   that are at
   sunsite.unc.edu:/pub/Linux/kernel/patches/console/pcsndrv-X.X.tar.gz,
   to be extracted with "tar xzvf filename".
-  This driver is also available as a module ( = code which can be inserted
-  in and removed from the running kernel whenever you want) on the
-  Motorola 680x0 architecture. If you are compiling a kernel for
-  Linux/m68k and want to compile this driver as a module, say M here
-  and read Documentation/modules.txt.
 
 ProAudioSpectrum 16 support
 CONFIG_PAS
@@ -3890,14 +4207,14 @@
 
 Gravis Ultrasound support
 CONFIG_GUS
-  Enable this option for any type of Gravis Ultrasound card, including
+  Say Y here for any type of Gravis Ultrasound card, including
   the GUS or GUS MAX.
 
 MPU-401 support (NOT for SB16)
 CONFIG_MPU401
   Be careful with this question. The MPU401 interface is supported by
   all soundcards. However, some natively supported cards have their
-  own driver for MPU401. Enabling the MPU401 option with these cards
+  own driver for MPU401. Enabling this MPU401 option with these cards
   will cause a conflict. Also, enabling MPU401 on a system that
   doesn't really have a MPU401 could cause some trouble. If your card
   was in the list of supported cards, look at the card specific
@@ -3919,8 +4236,8 @@
 16 bit sampling option of GUS (_NOT_ GUS MAX)
 CONFIG_GUS16
   Answer Y if you have installed the 16 bit sampling daughtercard on
-  your GUS.  Answer N if you have a GUS MAX, since enabling this
-  option disables GUS MAX support.
+  your GUS.  Answer N if you have a GUS MAX, since saying Y here
+  disables GUS MAX support.
 
 GUS MAX support
 CONFIG_GUSMAX
@@ -3947,7 +4264,7 @@
      synthesizers (OPL2, OPL3 and OPL4), 6850 UART MIDI Interface.
   For cards having native support in VoxWare, consult the card
   specific instructions in drivers/sound/Readme.cards. Some drivers
-  have their own MSS support and enabling this option will cause a
+  have their own MSS support and saying Y to this option will cause a
   conflict.
 
 Ensoniq Soundscape support
@@ -3972,11 +4289,11 @@
 
 Support for Crystal CS4232 based (PnP) cards
 CONFIG_CS4232
-  Enable this if you have a card based on the Crystal CS4232 chip set.
+  Say Y here if you have a card based on the Crystal CS4232 chip set.
 
 Support for Turtle Beach Wave Front (Maui, Tropez) synthesizers
 CONFIG_MAUI
-  Enable this option if you have a Turtle Beach Wave Front, Maui, or 
+  Say Y here if you have a Turtle Beach Wave Front, Maui, or 
   Tropez sound card.
 
 Support for Crystal CS4232 based (PnP) cards
@@ -4007,15 +4324,32 @@
 
 SB32/AWE support
 CONFIG_AWE32_SYNTH
-Enable this option if you have a SB32 or SB AWE soundcard. See
-linux/drivers/sound/lowlevel/README.awe for more info.
+  Say Y here if you have a SB32 or SB AWE soundcard. See
+  linux/drivers/sound/lowlevel/README.awe for more info.
+
+Additional low level drivers
+CONFIG_LOWLEVEL_SOUND
+  If you need additional low level sound drivers which are not part
+  of USS/Lite (UNIX Sound System), say Y.  The only such driver at
+  present is the ACI driver for the miroSOUND PCM12 and PCM20.
+
+ACI mixer (miroPCM12)
+CONFIG_ACI_MIXER
+  Audio Command Interface (ACI) driver.  ACI is a protocol used to
+  communicate with the microcontroller on some sound cards produced
+  by miro, e.g. the miroSOUND PCM12 and PCM20.  The main function
+  of the ACI is to control the mixer and to get a product
+  identification.  This Voxware ACI driver currently only supports
+  the ACI functions on the miroSOUND PCM12 card.  On the PCM20, ACI
+  also controls the radio tuner on this card, however this is not
+  yet supported in this software.
 
 Kernel profiling support
 CONFIG_PROFILE
   This is for kernel hackers who want to know how much time the kernel
   spends in the various procedures. The information is stored in
-  /proc/profile (enable the /proc filesystem!) and in order to read
-  it, you need the readprofile package from sunsite.unc.edu. Its
+  /proc/profile (say Y to "/proc filesystem support"!) and in order to
+  read it, you need the readprofile package from sunsite.unc.edu. Its
   manpage gives information regarding the format of profiling data. To
   become a kernel hacker, you can start with the Kernel Hacker's Guide
   at http://www.redhat.com:8080/HyperNews/get/khg.html. Mere mortals
@@ -4025,35 +4359,43 @@
 CONFIG_PROFILE_SHIFT
   This is used to adjust the granularity with which the addresses of
   executed instructions get recorded in /proc/profile. But since you
-  enabled "Kernel profiling support", you must be a kernel hacker and
+  said Y to "Kernel profiling support", you must be a kernel hacker and
   hence you know what this is about :-)
 
 ISDN subsystem
 CONFIG_ISDN
-  ISDN ("Integrated Services Digital Networks", called RNIS in
-  France) is a special type of fully digital telephone line; it's
-  mostly used to connect to your Internet service provider (with SLIP
-  or PPP). The main advantage is that the speed is higher than
-  ordinary modem/telephone connections. It only works if your computer
-  is equipped with an ISDN card and both you and your service provider
-  purchased an ISDN line from your phone company.  For details, read
-  http://alumni.caltech.edu/~dank/isdn/ on the WWW. (To browse the
-  WWW, you need to have access to a machine on the Internet that has
-  one of the programs lynx, netscape or Mosaic.)  This driver allows
-  you to use an ISDN-card for networking connections and as dialin/out
-  device. The isdn-tty's have a built in AT-compatible modem
-  emulator. Network devices support autodial, channel-bundling,
+  ISDN ("Integrated Services Digital Networks", called RNIS in France)
+  is a special type of fully digital telephone service; it's mostly
+  used to connect to your Internet service provider (with SLIP or
+  PPP). The main advantage is that the speed is higher than ordinary
+  modem/telephone connections, and that you can have voice
+  conversations while downloading stuff. It only works if your
+  computer is equipped with an ISDN card and both you and your service
+  provider purchased an ISDN line from the phone company.  For
+  details, read http://alumni.caltech.edu/~dank/isdn/ on the WWW. (To
+  browse the WWW, you need to have access to a machine on the Internet
+  that has one of the programs lynx, netscape or Mosaic.)  This driver
+  allows you to use an ISDN-card for networking connections and as
+  dialin/out device. The isdn-tty's have a built in AT-compatible
+  modem emulator. Network devices support autodial, channel-bundling,
   callback and caller-authentication without having a daemon
   running. A reduced T.70 protocol is supported with tty's suitable
   for German BTX. On D-Channel, the protocols EDSS1 and 1TR6 are
-  supported. See Documentation/isdn/README for more information.
+  supported. See Documentation/isdn/README for more information.  If
+  you want to compile the ISDN as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt. The module will be
+  called isdn.o.  If unsure, say N.
 
 Support synchronous PPP
 CONFIG_ISDN_PPP
-  This enables synchronous PPP via ISDN. This protocol is used by
-  Cisco or Sun for example. So you want say Y here if the other end of
-  your ISDN connection supports it. You will need a special version of
-  pppd (called ipppd) for using this feature. See
+  Over digital connections such as ISDN, there is no need to
+  synchronize sender and recipient's clocks with start and stop bits
+  as is done over telephone lines. Instead, one can use "synchronous
+  PPP". Saying Y here will include this protocol. This protocol is
+  used by Cisco and Sun for example. So you want to say Y here if the
+  other end of your ISDN connection supports it. You will need a
+  special version of pppd (called ipppd) for using this feature. See
   Documentation/isdn/README.syncppp and Documentation/isdn/syncPPP.FAQ
   for more information.
 
@@ -4069,13 +4411,13 @@
 
 Support audio via ISDN
 CONFIG_ISDN_AUDIO
-  With this option enabled, the modem-emulator supports a subset
-  of the EIA Class 8 Voice commands. Using a getty with voice-support
+  If you say Y here, the modem-emulator will support a subset of the
+  EIA Class 8 Voice commands. Using a getty with voice-support
   (mgetty+sendfax by gert@greenie.muc.de with an extension, available
-  with the ISDN utility package for example), you will be able
-  to use your Linux box as an ISDN-answering machine. Of course, this
-  must be supported by the lowlevel driver also. Currently, the Teles
-  driver is the only voice-supporting one. See
+  with the ISDN utility package for example), you will be able to use
+  your Linux box as an ISDN-answering machine. Of course, this must be
+  supported by the lowlevel driver also. Currently, the Teles driver
+  is the only voice-supporting one. See
   Documentation/isdn/README.audio for more information.
 
 ICN 2B and 4B support
@@ -4086,7 +4428,10 @@
   this card, additional firmware is necessary, which has to be
   downloaded into the card using a utility which is distributed
   separately.  See Documentation/isdn/README and README.icn for more
-  information.
+  information. If you want to compile this as a module ( = code which
+  can be inserted in and removed from the running kernel whenever you
+  want), say M here and read Documentation/modules.txt. The module
+  will be called icn.o.
 
 Teles, NICCY1016PC, Creatix support
 CONFIG_ISDN_DRV_TELES
@@ -4095,7 +4440,10 @@
   support a 16.0-type using EDSS1-protocol. See
   Documentation/isdn/README on how to configure it using 16.3, a
   different D-channel protocol, or non-standard irq/port/shmem
-  settings.
+  settings. If you want to compile this as a module ( = code which can
+  be inserted in and removed from the running kernel whenever you
+  want), say M here and read Documentation/modules.txt. The module
+  will be called teles.o.
 
 PCBIT-D support
 CONFIG_ISDN_DRV_PCBIT
@@ -4104,12 +4452,15 @@
   firmware is necessary, which has to be downloaded into the card
   using a utility which is distributed separately.  See
   Documentation/isdn/README and Documentation/isdn/README.pcbit for
-  more information.
+  more information. If you want to compile this as a module ( = code
+  which can be inserted in and removed from the running kernel
+  whenever you want), say M here and read
+  Documentation/modules.txt. The module will be called pcbit.o.
 
 Support for AP1000 multicomputer
 CONFIG_AP1000
   This enables support for a sparc based parallel multi-computer
-  called an AP1000+. For details on our efforts to port Linux to this
+  called AP1000+. For details on our efforts to port Linux to this
   machine see http://cap.anu.edu.au/cap/projects/linux or mail to
   hackers@cafe.anu.edu.au
 
@@ -4150,29 +4501,30 @@
 
 68020 support
 CONFIG_M68020
-  If you anticipate running this kernel on a computer with a MC68020 processor,
-  say Y.  Otherwise, say N.  Note that the 68020 requires a 68851 MMU 
-  (= memory management unit) to run Linux/m68k.
+  If you anticipate running this kernel on a computer with a MC68020
+  processor, say Y.  Otherwise, say N.  Note that the 68020 requires a
+  68851 MMU (= memory management unit) to run Linux/m68k.
 
 68030 support
 CONFIG_M68030
-  If you anticipate running this kernel on a computer with a MC68030 processor,
-  say Y.  Otherwise, say N.  Note that a MC68EC030 will not work, as it does
-  not include an MMU (= memory management unit).
+  If you anticipate running this kernel on a computer with a MC68030
+  processor, say Y.  Otherwise, say N.  Note that a MC68EC030 will not
+  work, as it does not include an MMU (= memory management unit).
 
 68040 support
 CONFIG_M68040
-  If you anticipate running this kernel on a computer with a MC68LC040 or
-  MC68040 processor, say Y.  Otherwise, say N.  Note that an MC68EC040 will
-  not work, as it does not include an MMU (= memory management unit).
+  If you anticipate running this kernel on a computer with a MC68LC040
+  or MC68040 processor, say Y.  Otherwise, say N.  Note that an
+  MC68EC040 will not work, as it does not include an MMU (= memory
+  management unit).
 
 Use -m68040 flag for 68040 specific optimizations
 CONFIG_OPTIMIZE_040
   If you will only be running this kernel on a 68040-series processor,
-  this will make the kernel run somewhat faster.  However, it will no longer
-  run on a 68020 or 68030, no matter whether you included 68020 and 68030
-  support or not.  Say N unless the only processor you are compiling support
-  for is the 68040 (or 68LC040).
+  this will make the kernel run somewhat faster.  However, it will no
+  longer run on a 68020 or 68030, no matter whether you included 68020
+  and 68030 support or not.  Say N unless the only processor you are
+  compiling support for is the 68040 (or 68LC040).
 
 68060 support
 CONFIG_M68060
@@ -4182,10 +4534,10 @@
 Use -m68060 flag for 68060 specific optimizations
 CONFIG_OPTIMIZE_060
   If you will only be running this kernel on a 68060-series processor,
-  this will make the kernel run somewhat faster.  However, it will no longer
-  run on a 68020, 68030 or 68040, no matter whether you included support
-  for those processors or not.  Say N unless the only processor you are
-  compiling support for is the 68060.
+  this will make the kernel run somewhat faster.  However, it will no
+  longer run on a 68020, 68030 or 68040, no matter whether you
+  included support for those processors or not.  Say N unless the only
+  processor you are compiling support for is the 68060.
 
 Advanced processor options
 CONFIG_ADVANCED_CPU
@@ -4222,9 +4574,10 @@
 
 Amiga ECS chipset support
 CONFIG_AMIFB_ECS
-  This enables support for the Enhanced Chip Set, found in later A500's,
-  later A2000's, the A600, the A3000, the A3000T and CDTV.  If you intend to
-  run Linux on any of these systems, say Y; otherwise say N.
+  This enables support for the Enhanced Chip Set, found in later
+  A500's, later A2000's, the A600, the A3000, the A3000T and CDTV.  If
+  you intend to run Linux on any of these systems, say Y; otherwise
+  say N.
 
 Amiga AGA chipset support
 CONFIG_AMIFB_AGA
@@ -4242,10 +4595,10 @@
 
 Amiga GSP (TMS340x0) support
 CONFIG_AMIGA_GSP
-  Include support for Amiga graphics cards that use the Texas Instruments
-  TMS340x0 GSP (= graphics signal processor) chips.  Say Y if you want
-  to use a DMI Resolver or Commodore A2410 (Lowell) graphics card on
-  an Amiga; otherwise, say N.
+  Include support for Amiga graphics cards that use the Texas
+  Instruments TMS340x0 GSP (= graphics signal processor) chips.  Say Y
+  if you want to use a DMI Resolver or Commodore A2410 (Lowell)
+  graphics card on an Amiga; otherwise, say N.
 
 DMI Resolver support
 CONFIG_GSP_RESOLVER
@@ -4259,19 +4612,17 @@
 
 Amiga Zorro II ramdisk support
 CONFIG_AMIGA_Z2RAM
-  This enables support for using Chip RAM and Zorro II RAM as a ramdisk
-  or as a swap partition.  Say Y if you want to include this driver in
-  the kernel.
-  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
+  This enables support for using Chip RAM and Zorro II RAM as a
+  ramdisk or as a swap partition.  Say Y if you want to include this
+  driver in the kernel.  This driver is also available as a module ( =
+  code which can be inserted in and removed from the running kernel
+  whenever you want). The module is called z2ram.o. If you want to
+  compile it as a module, say M here and read
   Documentation/modules.txt.
 
 Atari ACSI support
 CONFIG_ATARI_ACSI
-  This enables support for the Atari ACSI interface. This driver is
-  also available as a module ( = code which can be inserted in and
-  removed from the running kernel whenever you want). The driver
+  This enables support for the Atari ACSI interface. The driver
   supports hard disks and CD-ROMs, which have 512-byte sectors, or can
   be switched to that mode. Due to the ACSI command format, only disks
   up to 1 GB are supported. Special support for certain ACSI to SCSI
@@ -4279,7 +4630,10 @@
   driver is also the basis for certain other drivers for devices
   attached to the ACSI bus: Atari SLM laser printer, BioNet-100
   Ethernet, and PAMsNet Ethernet. If you want to use one of these
-  devices, you need ACSI support, too.
+  devices, you need ACSI support, too. This driver is
+  also available as a module ( = code which can be inserted in and
+  removed from the running kernel whenever you want). The module will
+  be called acsi.o.
 
 Probe all LUNs on each ACSI device
 CONFIG_ACSI_MULTI_LUN
@@ -4295,44 +4649,44 @@
   If you have an Atari SLM laser printer, say Y to include support for
   it in the kernel. Otherwise, say N. This driver is also available as
   a module ( = code which can be inserted in and removed from the
-  running kernel whenever you want).
-  Be warned: the driver needs much ST-RAM and can cause problems due
-  to that fact!
+  running kernel whenever you want). The module will be called
+  acsi_slm.o.  Be warned: the driver needs much ST-RAM and can cause
+  problems due to that fact!
 
 A3000 WD33C93A support
 CONFIG_A3000_SCSI
-  If you have an Amiga 3000 and have SCSI devices connected to the built-in
-  SCSI controller, say Y.  Otherwise, say N.
-  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.
+  If you have an Amiga 3000 and have SCSI devices connected to the
+  built-in SCSI controller, say Y.  Otherwise, say N.  This driver is
+  also available as a module ( = code which can be inserted in and
+  removed from the running kernel whenever you want). The module is
+  called wd33c93.o. If you want to compile it as a module, say M here
+  and read Documentation/modules.txt.
 
 A2091 WD33C93A support
 CONFIG_A2091_SCSI
-  If you have a Commodore A2091 SCSI controller, say Y.  Otherwise, say N.
-  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.
+  If you have a Commodore A2091 SCSI controller, say Y.  Otherwise,
+  say N.  This driver is also available as a module ( = code which can
+  be inserted in and removed from the running kernel whenever you
+  want). The module is called wd33c93.o. If you want to compile it as
+  a module, say M here and read Documentation/modules.txt.
 
 GVP Series II WD33C93A support
 CONFIG_GVP11_SCSI
-  If you have a Great Valley Products Series II SCSI controller, say Y.
-  Also say Y if you have a later model of GVP SCSI controller (such as
-  the GVP A4008 or a Combo board).  Otherwise, say N.
+  If you have a Great Valley Products Series II SCSI controller, say
+  Y.  Also say Y if you have a later model of GVP SCSI controller
+  (such as the GVP A4008 or a Combo board).  Otherwise, say N.
   This driver does NOT work for the T-Rex series of accelerators from
   TekMagic and GVP-M.
-  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.
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you
+  want). The module will be called gvp11.o. If you want to compile it
+  as a module, say M here and read Documentation/modules.txt.
 
 Cyberstorm SCSI support
 CONFIG_CYBERSTORM_SCSI
-  If you have an Amiga with an original (MkI) Phase5 Cyberstorm accelerator
-  board and the optional Cyberstorm SCSI controller, say Y.  Otherwise,
-  say N.
+  If you have an Amiga with an original (MkI) Phase5 Cyberstorm
+  accelerator board and the optional Cyberstorm SCSI controller, say
+  Y.  Otherwise, say N.
 
 Cyberstorm II SCSI support
 CONFIG_CYBERSTORMII_SCSI
@@ -4341,13 +4695,15 @@
 
 Blizzard 2060 SCSI support
 CONFIG_BLZ2060_SCSI
-  If you have an Amiga with a Phase5 Blizzard 2060 accelerator board and
-  want to use the onboard SCSI controller, say Y.  Otherwise, say N.
+  If you have an Amiga with a Phase5 Blizzard 2060 accelerator board
+  and want to use the onboard SCSI controller, say Y.  Otherwise, say
+  N.
 
 Blizzard 1230IV/1260 SCSI support
 CONFIG_BLZ1230_SCSI
-  If you have an Amiga 1200 with a Phase5 Blizzard 1230IV or Blizzard 1260
-  accelerator, and the optional SCSI module, say Y.  Otherwise, say N.
+  If you have an Amiga 1200 with a Phase5 Blizzard 1230IV or Blizzard
+  1260 accelerator, and the optional SCSI module, say Y.  Otherwise,
+  say N.
 
 Atari native SCSI support
 CONFIG_ATARI_SCSI
@@ -4355,44 +4711,45 @@
   Falcon, ...) say Y to get it supported. Of course also, if you have
   an compatible SCSI controller (e.g. for Medusa). 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.
-  This driver supports both styles of NCR integration into the system:
-  the TT style (separate DMA), and the Falcon style (via ST-DMA,
-  replacing ACSI). It does NOT support other schemes, like in the
-  Hades (without DMA).
+  from the running kernel whenever you want). The module is called
+  atari_scsi.o. If you want to compile it as a module, say M here and
+  read Documentation/modules.txt.  This driver supports both styles of
+  NCR integration into the system: the TT style (separate DMA), and
+  the Falcon style (via ST-DMA, replacing ACSI). It does NOT support
+  other schemes, like in the Hades (without DMA).
 
 Long delays for Toshiba CD-ROMs
 CONFIG_ATARI_SCSI_TOSHIBA_DELAY
   This option increases the delay after a SCSI arbitration to
-  accomodate some flakey Toshiba CD-ROM drives. Say Y if you intend to
+  accommodate some flaky Toshiba CD-ROM drives. Say Y if you intend to
   use a Toshiba CD-ROM drive; otherwise, the option is not needed and
   would impact performance a bit, so say N.
 
 Ariadne support
 CONFIG_ARIADNE
-  If you have a VillageTronics Ariadne Ethernet adapter, say Y.  Otherwise,
-  say N.
-  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.
+  If you have a VillageTronics Ariadne Ethernet adapter, say Y.
+  Otherwise, say N.
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you
+  want). The module is called ariadne.o. If you want to compile it as
+  a module, say M here and read Documentation/modules.txt.
 
 A2065 support
 CONFIG_A2065
-  If you have a Commodore A2065 Ethernet adapter, say Y.  Otherwise, say N.
-  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.
+  If you have a Commodore A2065 Ethernet adapter, say Y.  Otherwise,
+  say N.
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you
+  want). The module is called a2065.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
 
 Hydra support
 CONFIG_HYDRA
   If you have a Hydra Ethernet adapter, say Y.  Otherwise, say N.
-  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.
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you
+  want). The module is called hydra.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
 
 Atari Lance support
 CONFIG_ATARILANCE
@@ -4415,34 +4772,34 @@
 Multiface Card III parallel support
 CONFIG_MULTIFACE_III_LP
   If you have a Multiface III card for your Amiga, and want to use its
-  parallel port in Linux, say Y.  Otherwise, say N.
-  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.
+  parallel port in Linux, say Y.  Otherwise, say N.  This driver is
+  also available as a module ( = code which can be inserted in and
+  removed from the running kernel whenever you want). The module is
+  called lp_m68k.o. If you want to compile it as a module, say M here
+  and read Documentation/modules.txt.
 
 Amiga mouse support
 CONFIG_AMIGAMOUSE
-  If you want to be able to use an Amiga mouse in Linux, say Y.
-  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.
+  If you want to be able to use an Amiga mouse in Linux, say Y.  This
+  driver is also available as a module ( = code which can be inserted
+  in and removed from the running kernel whenever you want). The
+  module is called amigamouse.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
 
 Amiga Copper Console
 CONFIG_COPCON
-  This configures the console to use the Amiga's graphics coprocessor for
-  scrolling, instead of using the CPU.  This option markedly improves
-  response times in the high color modes (5 bitplanes and up).  If you
-  would like to use this, say Y; otherwise, say N.
+  This configures the console to use the Amiga's graphics coprocessor
+  for scrolling, instead of using the CPU.  This option markedly
+  improves response times in the high color modes (5 bitplanes and
+  up).  If you would like to use this, say Y; otherwise, say N.
 
 Atari mouse support
 CONFIG_ATARIMOUSE
-  If you want to be able to use an Atari mouse in Linux, say Y.
-  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.
+  If you want to be able to use an Atari mouse in Linux, say Y.  This
+  driver is also available as a module ( = code which can be inserted
+  in and removed from the running kernel whenever you want). The
+  module is called atarimouse.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
 
 Atari MFP serial support
 CONFIG_ATARI_MFPSER
@@ -4450,7 +4807,7 @@
   Linux, say Y. The driver equally supports all kinds of MFP serial
   ports and automatically detects whether Serial1 is available. 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
+  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.
   Note for Falcon users: You also have an MFP port, it's just not
@@ -4470,17 +4827,18 @@
 Atari MIDI serial support
 CONFIG_ATARI_MIDI
   If you want to use your Atari's MIDI port in Linux, say Y.
-  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
+  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.
 
 Amiga builtin serial support
 CONFIG_AMIGA_BUILTIN_SERIAL
-  If you want to use your Amiga's built-in serial port in Linux, say Y.
-  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
+  If you want to use your Amiga's built-in serial port in Linux, say
+  Y.
+  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.
 
 GVP IO-Extender support
@@ -4490,7 +4848,8 @@
 
 Multiface Card III serial support
 CONFIG_MULTIFACE_III_TTY
-  If you want to use a Multiface III card's serial port in Linux, say Y.
+  If you want to use a Multiface III card's serial port in Linux, say
+  Y.
   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
@@ -4498,12 +4857,13 @@
 
 Amiga or Atari DMA sound support
 CONFIG_DMASOUND
-  If you want to use the internal audio of your Atari or Amiga in Linux,
-  answer Y to this question.  This will provide a Sun-like /dev/audio,
-  compatible with the Linux/i386 sound system.  Otherwise, say N.
-  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
+  If you want to use the internal audio of your Atari or Amiga in
+  Linux, answer Y to this question.  This will provide a Sun-like
+  /dev/audio, compatible with the Linux/i386 sound system.  Otherwise,
+  say N.
+  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.
 
 MSDOS partition support
@@ -4514,20 +4874,6 @@
   Say Y if you need this feature; users who are only using their
   system-native partitioning scheme can say N here.
 
-Sparc ESP SCSI support
-CONFIG_SCSI_SUNESP
-  This is the driver for the Sun ESP SCSI host adapter. The ESP
-  chipset is present in most SPARC-based computers.
-
-Sparc /dev/openprom compatibility driver
-CONFIG_SUN_OPENPROMIO
-  This driver provides user programs with an interface to the Sparc
-  PROM device tree. The driver implements a SunOS-compatible
-  interface and a NetBSD-compatible interface. If you want to
-  compile this as a module ( = code which can be inserted in and
-  removed from the running kernel whenever you want), say M and read
-  Documentation/modules.txt. If unsure, say Y.
-
 # need an empty line after last entry, for sed script in Configure.
 
 #
@@ -4557,7 +4903,7 @@
 # LocalWords:  TR Sony CDU caddyless cdu Mitsumi MCD cd mcd XA MultiSession CDA
 # LocalWords:  Matsushita Panasonic SBPCD Soundblaster Longshine sbpcd Aztech
 # LocalWords:  Okano Wearnes AZTCD CDD SE aztcd sonycd Goldstar GSCD Philips fs
-# LocalWords:  LMS OPTCD Sanyo SJCD minix faqs msdos harddrive mtools
+# LocalWords:  LMS OPTCD Sanyo SJCD minix faqs xiafs XIA msdos harddrive mtools
 # LocalWords:  std softlinks umssync NetworkFileSharing nfsd mountd CDs HPFS TI
 # LocalWords:  hpfs SYSV SCO intel iBCS Wyse WordPerfect tsx mit unixes sysv NR
 # LocalWords:  SMB WfW Cyclades async mux Logitech busmouse MouseSystem aka AST
@@ -4625,4 +4971,20 @@
 # LocalWords:  smmixer ptt circ soundmodem MKISS FDDI DEFEA DEFPA DEFXX redhat
 # LocalWords:  HyperNews khg mconv sed lina wuftpd MicroChannel netlink irc cum
 # LocalWords:  raudio realaudio PPROP NETBIOS GUI IBMMCA ELMC Racal Interlan fi
-# LocalWords:  eth shapecfg src esp PCWD PREVSTAT
+# LocalWords:  eth shapecfg src esp PCWD PREVSTAT bootparam sig bitwizard SBC
+# LocalWords:  downloads AFSK TCM FP Karn KA FSK RUH LinkSys cron mouseman LLC
+# LocalWords:  SyQuest SyQuest's CCITT MicroSolutions BPCD bpcd ESPSERIAL PROM
+# LocalWords:  SUNESP openprom OPENPROMIO quango themall al TT MC MMU LC RMW AA
+# LocalWords:  INSNS Ataris AutoConfig ZORRO OCS AMIFB Agnus Denise ECS CDTV GB
+# LocalWords:  AGA Cybervision CYBER GSP TMS DMI Zorro ACSI ROMs SLM BioNet GVP
+# LocalWords:  PAMsNet TekMagic Cyberstorm MkI CYBERSTORMII MkII BLZ onboard cx
+# LocalWords:  VillageTronics ATARILANCE RieblCard PAMCard VME MFP sangoma LAPB
+# LocalWords:  Rhotron BioData's Multiface AMIGAMOUSE COPCON Amiga's bitplanes
+# LocalWords:  ATARIMOUSE MFPSER SCC's MegaSTE ESCC Atari's GVPIOEXT DMASOUND
+# LocalWords:  fdutils cisco univercd rpcg htm iface lapb LAPBETHER tpqic qic
+# LocalWords:  SYNTH xd en binfmt aout ipip terra ipx fileserver sd sr sg wic
+# LocalWords:  ibmmca lapbether mkiss dlci sdla fmv eepro eexpress ni hp ne es
+# LocalWords:  ibmtr isofs ROMFS romfs pcxx cyclades istallion psaux msbusmouse
+# LocalWords:  atixlmouse sbin softdog pcwd USS Lite ACI miroSOUND PCM miroPCM
+# LocalWords:  microcontroller miro Voxware downloading teles acsi slm gvp
+# LocalWords:  atari ariadne amigamouse atarimouse builtin
diff -u --recursive --new-file v2.1.22/linux/Documentation/cdrom/cdrom-standard.tex linux/Documentation/cdrom/cdrom-standard.tex
--- v2.1.22/linux/Documentation/cdrom/cdrom-standard.tex	Mon Dec 30 15:39:02 1996
+++ linux/Documentation/cdrom/cdrom-standard.tex	Sun Jan 26 12:07:03 1997
@@ -1,5 +1,5 @@
 \documentclass{article}
-\def\version{$Id: cdrom-standard.tex,v 1.6 1996/12/23 21:17:44 david Exp $}
+\def\version{$Id: cdrom-standard.tex,v 1.6 1996/12/29 20:45:18 davem Exp $}
 
 \evensidemargin=0pt
 \oddsidemargin=0pt
@@ -994,6 +994,10 @@
 
 \def\versionlog{
 $Log: cdrom-standard.tex,v $
+Revision 1.6  1996/12/29 20:45:18  davem
+Merge to 2.1.18, versioned module symbols are
+disabled until new modutils is released.
+
 Revision 1.6  1996/12/23 21:17:44  david
 Added reasons for speed selection.
 
diff -u --recursive --new-file v2.1.22/linux/Makefile linux/Makefile
--- v2.1.22/linux/Makefile	Thu Jan 23 21:06:45 1997
+++ linux/Makefile	Sun Jan 26 12:11:20 1997
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 1
-SUBLEVEL = 22
+SUBLEVEL = 23
 
 ARCH = i386
 
@@ -176,12 +176,19 @@
 		$(ARCHIVES) \
 		$(FILESYSTEMS) \
 		$(DRIVERS) \
-		$(LIBS) -o vmlinux
+		$(LIBS) \
+		-o vmlinux
 	$(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( a \)\|\(\.\.ng$$\)' | sort > System.map
 
 symlinks:
 	rm -f include/asm
 	( cd include ; ln -sf asm-$(ARCH) asm)
+	@if [ ! -d modules ]; then \
+		mkdir modules; \
+	fi
+	@if [ ! -d include/linux/modules ]; then \
+		mkdir include/linux/modules; \
+	fi
 
 oldconfig: symlinks
 	$(CONFIG_SHELL) scripts/Configure -d arch/$(ARCH)/config.in
@@ -315,7 +322,7 @@
 	rm -f core `find . -type f -name 'core' -print`
 	rm -f vmlinux System.map
 	rm -f .tmp* drivers/sound/configure
-	rm -f modules/*
+	rm -f `find modules/ -type f -print`
 	rm -f submenu*
 
 mrproper: clean
@@ -331,7 +338,8 @@
 	rm -f .depend `find . -name .depend -print`
 	rm -f .hdepend scripts/mkdep
 	rm -f $(TOPDIR)/include/linux/modversions.h
-	rm -f $(TOPDIR)/include/linux/modules/*
+	rm -rf $(TOPDIR)/include/linux/modules
+	rm -rf modules
 
 
 distclean: mrproper
diff -u --recursive --new-file v2.1.22/linux/Rules.make linux/Rules.make
--- v2.1.22/linux/Rules.make	Wed Jan 15 19:45:39 1997
+++ linux/Rules.make	Sun Jan 26 12:07:03 1997
@@ -107,6 +107,9 @@
 ifdef MOD_SUB_DIRS
 	set -e; for i in $(MOD_SUB_DIRS); do $(MAKE) -C $$i modules; done
 endif
+ifdef MOD_IN_SUB_DIRS
+	set -e; for i in $(MOD_IN_SUB_DIRS); do $(MAKE) -C $$i modules; done
+endif
 ifneq "$(strip $(MOD_LIST_NAME))" ""
 	rm -f $$TOPDIR/modules/$(MOD_LIST_NAME)
 ifdef MOD_SUB_DIRS
@@ -115,6 +118,9 @@
 endif
 ifneq "$(strip $(ALL_MOBJS))" ""
 	echo $(ALL_MOBJS) >> $$TOPDIR/modules/$(MOD_LIST_NAME)
+endif
+ifneq "$(strip $(MOD_TO_LIST))" ""
+	echo $(MOD_TO_LIST) >> $$TOPDIR/modules/$(MOD_LIST_NAME)
 endif
 endif
 ifneq "$(strip $(ALL_MOBJS))" ""
diff -u --recursive --new-file v2.1.22/linux/arch/alpha/kernel/alpha_ksyms.c linux/arch/alpha/kernel/alpha_ksyms.c
--- v2.1.22/linux/arch/alpha/kernel/alpha_ksyms.c	Wed Jan 15 19:45:39 1997
+++ linux/arch/alpha/kernel/alpha_ksyms.c	Sun Jan 26 13:40:45 1997
@@ -10,9 +10,15 @@
 #include <linux/string.h>
 #include <linux/user.h>
 #include <linux/elfcore.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+
 #include <asm/io.h>
 #include <asm/hwrpb.h>
 #include <asm/uaccess.h>
+#include <asm/processor.h>
+#include <asm/checksum.h>
 
 
 extern void bcopy (const char *src, char *dst, int len);
@@ -58,6 +64,7 @@
 EXPORT_SYMBOL(strncmp);
 EXPORT_SYMBOL(strncpy);
 EXPORT_SYMBOL(strnlen);
+EXPORT_SYMBOL(strncat);
 EXPORT_SYMBOL(strstr);
 EXPORT_SYMBOL(strtok);
 EXPORT_SYMBOL(strchr);
@@ -72,6 +79,11 @@
 EXPORT_SYMBOL(hwrpb);
 EXPORT_SYMBOL(wrusp);
 EXPORT_SYMBOL(__kernel_thread);
+EXPORT_SYMBOL(start_thread);
+
+EXPORT_SYMBOL(csum_tcpudp_magic);
+EXPORT_SYMBOL(ip_fast_csum);
+EXPORT_SYMBOL(ip_compute_csum);
 
 /*
  * The following are specially called from the uaccess assembly stubs.
diff -u --recursive --new-file v2.1.22/linux/arch/alpha/kernel/bios32.c linux/arch/alpha/kernel/bios32.c
--- v2.1.22/linux/arch/alpha/kernel/bios32.c	Thu Dec 12 17:02:40 1996
+++ linux/arch/alpha/kernel/bios32.c	Sun Jan 26 12:07:03 1997
@@ -24,6 +24,8 @@
  * within the United States, $35 abroad.
  */
 #include <linux/config.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #if 0
 # define DBG_DEVS(args)		printk args
@@ -1217,6 +1219,7 @@
 	unsigned int uint;
 	long err = 0;
 
+	lock_kernel();
 	switch (len) {
 	    case 1:
 		err = pcibios_read_config_byte(bus, dfn, off, &ubyte);
@@ -1240,6 +1243,7 @@
 		err = -EINVAL;
 		break;
 	}
+	unlock_kernel();
 	return err;
 }
 asmlinkage int sys_pciconfig_write(
@@ -1254,6 +1258,7 @@
 	unsigned int uint;
 	long err = 0;
 
+	lock_kernel();
 	switch (len) {
 	    case 1:
 		err = get_user(ubyte, buf);
@@ -1286,6 +1291,7 @@
 		err = -EINVAL;
 		break;
 	}
+	unlock_kernel();
 	return err;
 }
 
diff -u --recursive --new-file v2.1.22/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S
--- v2.1.22/linux/arch/alpha/kernel/entry.S	Mon Dec 30 15:39:02 1996
+++ linux/arch/alpha/kernel/entry.S	Sun Jan 26 12:07:03 1997
@@ -199,6 +199,8 @@
 .align 3
 .ent	kernel_clone
 kernel_clone:
+	.frame $30, 0, $26
+	.prologue 0
 	subq $30,6*8,$30
 	stq $31,0($30)
 	stq $26,8($30)
@@ -221,17 +223,19 @@
 .globl	__kernel_thread
 .ent	__kernel_thread
 __kernel_thread:
+	.frame $30, 4*8, $26
 	subq $30,4*8,$30
-	stq $9,0($30)
-	stq $10,8($30)
-	stq $26,16($30)
+	stq $10,16($30)
+	stq $9,8($30)
+	stq $26,0($30)
+	.prologue 0
 	bis $17,$17,$9		/* save fn */
 	bis $18,$18,$10		/* save arg */
 	bsr $26,kernel_clone
 	bne $20,1f		/* $20 is non-zero in child */
-	ldq $9,0($30)
-	ldq $10,8($30)
-	ldq $26,16($30)
+	ldq $26,0($30)
+	ldq $9,8($30)
+	ldq $10,16($30)
 	addq $30,4*8,$30
 	ret $31,($26),1
 /* this is in child: look out as we don't have any stack here.. */
@@ -718,7 +722,7 @@
 	.quad do_entSys, sys_ptrace, do_entSys, do_entSys, do_entSys
 	.quad do_entSys, do_entSys, do_entSys, sys_access, do_entSys
 	.quad do_entSys, sys_sync, sys_kill, do_entSys, sys_setpgid
-	.quad do_entSys, sys_dup, sys_pipe, do_entSys, do_entSys
+	.quad do_entSys, sys_dup, sys_pipe, osf_set_program_attributes, do_entSys
 	.quad sys_open, do_entSys, sys_getxgid, osf_sigprocmask, do_entSys
 /*50*/	.quad do_entSys, sys_acct, sys_sigpending, do_entSys, sys_ioctl
 	.quad do_entSys, do_entSys, sys_symlink, sys_readlink, sys_execve
@@ -729,7 +733,7 @@
 	/* map BSD's setpgrp to sys_setpgid for binary compatibility: */
 	.quad sys_setgroups, do_entSys, sys_setpgid, sys_setitimer, do_entSys
 	.quad do_entSys, sys_getitimer, sys_gethostname, sys_sethostname, sys_getdtablesize
-	.quad sys_dup2, sys_newfstat, sys_fcntl, sys_select, do_entSys
+	.quad sys_dup2, sys_newfstat, sys_fcntl, sys_select, sys_poll
 	.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
@@ -759,7 +763,7 @@
 	.quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
 	.quad do_entSys, do_entSys, do_entSys, sys_getpgid, sys_getsid
 	.quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
-	.quad do_entSys, do_entSys, do_entSys, do_entSys, osf_proplist_syscall
+	.quad do_entSys, osf_sysinfo, do_entSys, do_entSys, osf_proplist_syscall
 	.quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
 /*250*/	.quad do_entSys, osf_usleep_thread, do_entSys, do_entSys, sys_sysfs
 	.quad do_entSys, osf_getsysinfo, osf_setsysinfo, do_entSys, do_entSys
diff -u --recursive --new-file v2.1.22/linux/arch/alpha/kernel/osf_sys.c linux/arch/alpha/kernel/osf_sys.c
--- v2.1.22/linux/arch/alpha/kernel/osf_sys.c	Tue Oct 29 19:58:01 1996
+++ linux/arch/alpha/kernel/osf_sys.c	Sun Jan 26 14:26:39 1997
@@ -14,6 +14,8 @@
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 #include <linux/stddef.h>
 #include <linux/unistd.h>
 #include <linux/ptrace.h>
@@ -43,6 +45,26 @@
 
 extern asmlinkage int sys_umount(char *);
 extern asmlinkage int sys_swapon(const char *specialfile, int swap_flags);
+extern asmlinkage unsigned long sys_brk(unsigned long);
+
+/*
+ * This is pure guess-work..
+ */
+asmlinkage int osf_set_program_attributes(
+	unsigned long text_start, unsigned long text_len,
+	unsigned long bss_start, unsigned long bss_len)
+{
+	struct mm_struct *mm;
+
+	lock_kernel();
+	mm = current->mm;
+	mm->end_code = bss_start + bss_len;
+	mm->brk = bss_start + bss_len;
+	printk("set_program_attributes(%lx %lx %lx %lx)\n",
+		text_start, text_len, bss_start, bss_len);
+	unlock_kernel();
+	return 0;
+}
 
 /*
  * OSF/1 directory handling functions...
@@ -134,12 +156,17 @@
 	extern int sys_getpriority(int, int);
 	int prio;
 
+	/*
+	 * We don't need to aquire the kernel lock here, because
+	 * all of these operations are local. sys_getpriority
+	 * will get the lock as required..
+	 */
 	prio = sys_getpriority(which, who);
-	if (prio < 0)
-		return prio;
-
-	regs.r0 = 0;		/* special return: no errors */
-	return 20 - prio;
+	if (prio >= 0) {
+		regs.r0 = 0;		/* special return: no errors */
+		prio = 20 - prio;
+	}
+	return prio;
 }
 
 
@@ -151,25 +178,39 @@
 	return 0;
 }
 
+/*
+ * No need to aquire the kernel lock, we're local..
+ */
 asmlinkage unsigned long sys_getxuid(int a0, int a1, int a2, int a3, int a4, int a5,
 				     struct pt_regs regs)
 {
-	(&regs)->r20 = current->euid;
-	return current->uid;
+	struct task_struct * tsk = current;
+	(&regs)->r20 = tsk->euid;
+	return tsk->uid;
 }
 
 asmlinkage unsigned long sys_getxgid(int a0, int a1, int a2, int a3, int a4, int a5,
 				     struct pt_regs regs)
 {
-	(&regs)->r20 = current->egid;
-	return current->gid;
+	struct task_struct * tsk = current;
+	(&regs)->r20 = tsk->egid;
+	return tsk->gid;
 }
 
 asmlinkage unsigned long sys_getxpid(int a0, int a1, int a2, int a3, int a4, int a5,
 				     struct pt_regs regs)
 {
-	(&regs)->r20 = current->p_opptr->pid;
-	return current->pid;
+	struct task_struct *tsk = current;
+
+	/* 
+	 * This isn't strictly "local" any more and we should actually
+	 * aquire the kernel lock. The "p_opptr" pointer might change
+	 * if the parent goes away (or due to ptrace). But any race
+	 * isn't actually going to matter, as if the parent happens
+	 * to change we can happily return either of the pids.
+	 */
+	(&regs)->r20 = tsk->p_opptr->pid;
+	return tsk->pid;
 }
 
 asmlinkage unsigned long osf_mmap(unsigned long addr, unsigned long len,
@@ -177,15 +218,20 @@
 				  unsigned long off)
 {
 	struct file *file = NULL;
+	unsigned long ret = -EBADF;
 
+	lock_kernel();
 	if (flags & (MAP_HASSEMAPHORE | MAP_INHERIT | MAP_UNALIGNED))
 		printk("%s: unimplemented OSF mmap flags %04lx\n", current->comm, flags);
 	if (!(flags & MAP_ANONYMOUS)) {
 		if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
-			return -EBADF;
+			goto out;
 	}
 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-	return do_mmap(file, addr, len, prot, flags, off);
+	ret = do_mmap(file, addr, len, prot, flags, off);
+out:
+	unlock_kernel();
+	return ret;
 }
 
 
@@ -228,22 +274,27 @@
 	struct inode *inode;
 	int retval;
 
+	lock_kernel();
 	if (bufsiz > sizeof(struct osf_statfs))
 		 bufsiz = sizeof(struct osf_statfs);
 	retval = verify_area(VERIFY_WRITE, buffer, bufsiz);
 	if (retval)
-		return retval;
+		goto out;
 	retval = namei(path, &inode);
 	if (retval)
-		return retval;
+		goto out;
+	retval = -ENOSYS;
 	if (!inode->i_sb->s_op->statfs) {
 		iput(inode);
-		return -ENOSYS;
+		goto out;
 	}
 	inode->i_sb->s_op->statfs(inode->i_sb, &linux_stat, sizeof(linux_stat));
 	linux_to_osf_statfs(&linux_stat, buffer);
 	iput(inode);
-	return 0;
+	retval = 0;
+out:
+	unlock_kernel();
+	return retval;
 }
 
 asmlinkage int osf_fstatfs(unsigned long fd, struct osf_statfs *buffer, unsigned long bufsiz)
@@ -253,20 +304,27 @@
 	struct inode *inode;
 	int retval;
 
+	lock_kernel();
 	retval = verify_area(VERIFY_WRITE, buffer, bufsiz);
 	if (retval)
-		return retval;
+		goto out;
 	if (bufsiz > sizeof(struct osf_statfs))
 		 bufsiz = sizeof(struct osf_statfs);
+	retval = -EBADF;
 	if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
-		return -EBADF;
+		goto out;
+	retval = -ENOENT;
 	if (!(inode = file->f_inode))
-		return -ENOENT;
+		goto out;
+	retval = -ENOSYS;
 	if (!inode->i_sb->s_op->statfs)
-		return -ENOSYS;
+		goto out;
 	inode->i_sb->s_op->statfs(inode->i_sb, &linux_stat, sizeof(linux_stat));
 	linux_to_osf_statfs(&linux_stat, buffer);
-	return 0;
+	retval = 0;
+out:
+	unlock_kernel();
+	return retval;
 }
 
 /*
@@ -414,9 +472,9 @@
 
 asmlinkage int osf_mount(unsigned long typenr, char *path, int flag, void *data)
 {
-	int retval;
+	int retval = -EINVAL;
 
-	retval = -EINVAL;
+	lock_kernel();
 	switch (typenr) {
 	case 1:
 		retval = osf_ufs_mount(path, (struct ufs_args *) data, flag);
@@ -430,12 +488,18 @@
 	default:
 		printk("osf_mount(%ld, %x)\n", typenr, flag);
 	}
+	unlock_kernel();
 	return retval;
 }
 
 asmlinkage int osf_umount(char *path, int flag)
 {
-	return sys_umount(path);
+	int ret;
+
+	lock_kernel();
+	ret = sys_umount(path);
+	unlock_kernel();
+	return ret;
 }
 
 /*
@@ -449,11 +513,12 @@
 	unsigned long ticks;
 	int retval;
 
+	lock_kernel();
 	retval = verify_area(VERIFY_READ, sleep, sizeof(*sleep));
 	if (retval)
-		return retval;
+		goto out;
 	if (remain && (retval = verify_area(VERIFY_WRITE, remain, sizeof(*remain))))
-		return retval;
+		goto out;
 	copy_from_user(&tmp, sleep, sizeof(*sleep));
 	ticks = tmp.tv_usec;
 	ticks = (ticks + (1000000 / HZ) - 1) / (1000000 / HZ);
@@ -461,8 +526,9 @@
 	current->timeout = ticks + jiffies;
 	current->state = TASK_INTERRUPTIBLE;
 	schedule();
+	retval = 0;
 	if (!remain)
-		return 0;
+		goto out;
 	ticks = jiffies;
 	if (ticks < current->timeout)
 		ticks = current->timeout - ticks;
@@ -472,26 +538,38 @@
 	tmp.tv_sec = ticks / HZ;
 	tmp.tv_usec = ticks % HZ;
 	copy_to_user(remain, &tmp, sizeof(*remain));
-	return 0;
+out:
+	unlock_kernel();
+	return retval;
 }
 
 asmlinkage int osf_utsname(char *name)
 {
-	int error = verify_area(VERIFY_WRITE, name, 5 * 32);
+	int error;
+
+	lock_kernel();
+	error = verify_area(VERIFY_WRITE, name, 5 * 32);
 	if (error)
-		return error;
+		goto out;
 	copy_to_user(name + 0, system_utsname.sysname, 32);
 	copy_to_user(name + 32, system_utsname.nodename, 32);
 	copy_to_user(name + 64, system_utsname.release, 32);
 	copy_to_user(name + 96, system_utsname.version, 32);
 	copy_to_user(name + 128, system_utsname.machine, 32);
-	return 0;
+out:
+	unlock_kernel();
+	return error;
 }
 
 asmlinkage int osf_swapon(const char *path, int flags, int lowat, int hiwat)
 {
+	int ret;
+
 	/* for now, simply ignore lowat and hiwat... */
-	return sys_swapon(path, flags);
+	lock_kernel();
+	ret = sys_swapon(path, flags);
+	unlock_kernel();
+	return ret;
 }
 
 asmlinkage unsigned long sys_getpagesize(void)
@@ -510,11 +588,15 @@
 	int fd[2];
 	int error;
 
+	lock_kernel();
 	error = do_pipe(fd);
 	if (error)
-		return error;
+		goto out;
 	(&regs)->r20 = fd[1];
-	return fd[0];
+	error = fd[0];
+out:
+	unlock_kernel();
+	return error;
 }
 
 /*
@@ -525,9 +607,10 @@
 	unsigned len;
 	int i, error;
 
+	lock_kernel();
 	error = verify_area(VERIFY_WRITE, name, namelen);
 	if (error)
-		return error;
+		goto out;
 
 	len = namelen;
 	if (namelen > 32)
@@ -538,23 +621,29 @@
 		if (system_utsname.domainname[i] == '\0')
 			break;
 	}
-	return 0;
+out:
+	unlock_kernel();
+	return error;
 }
 
 
 asmlinkage long osf_shmat(int shmid, void *shmaddr, int shmflg)
 {
 	unsigned long raddr;
-	int err;
+	long err;
 
+	lock_kernel();
 	err = sys_shmat(shmid, shmaddr, shmflg, &raddr);
 	if (err)
-		return err;
+		goto out;
 	/*
 	 * This works because all user-level addresses are
 	 * non-negative longs!
 	 */
-	return raddr;
+	err = raddr;
+out:
+	unlock_kernel();
+	return err;
 }
 
 
@@ -628,46 +717,44 @@
 	long error;
 	int *min_buf_size_ptr;
 
+	lock_kernel();
 	switch (code) {
 	case PL_SET:
 		error = verify_area(VERIFY_READ, &args->set.nbytes,
 				    sizeof(args->set.nbytes));
-		if (error)
-			return error;
-		return args->set.nbytes;
-
+		if (!error)
+			error = args->set.nbytes;
+		break;
 	case PL_FSET:
 		error = verify_area(VERIFY_READ, &args->fset.nbytes,
 				    sizeof(args->fset.nbytes));
-		if (error)
-			return error;
-		return args->fset.nbytes;
-
+		if (!error)
+			error = args->fset.nbytes;
+		break;
 	case PL_GET:
 		get_user(min_buf_size_ptr, &args->get.min_buf_size);
 		error = verify_area(VERIFY_WRITE, min_buf_size_ptr,
 				    sizeof(*min_buf_size_ptr));
-		if (error)
-			return error;
-		put_user(0, min_buf_size_ptr);
-		return 0;
-
+		if (!error)
+			put_user(0, min_buf_size_ptr);
+		break;
 	case PL_FGET:
 		get_user(min_buf_size_ptr, &args->fget.min_buf_size);
 		error = verify_area(VERIFY_WRITE, min_buf_size_ptr,
 				    sizeof(*min_buf_size_ptr));
-		if (error)
-			return error;
-		put_user(0, min_buf_size_ptr);
-		return 0;
-
+		if (!error)
+			put_user(0, min_buf_size_ptr);
+		break;
 	case PL_DEL:
 	case PL_FDEL:
-		return 0;
-
+		error = 0;
+		break;
 	default:
-		return -EOPNOTSUPP;
-	}
+		error = -EOPNOTSUPP;
+		break;
+	};
+	unlock_kernel();
+	return error;
 }
 
 /*
@@ -684,6 +771,7 @@
 	asmlinkage unsigned long sys_create_module(char *, unsigned long);
 	long retval;
 
+	lock_kernel();
 	retval = sys_create_module(module_name, size);
 	/*
 	 * we get either a module address or an error number,
@@ -692,28 +780,68 @@
 	 * much larger.
 	 */
 	if (retval + 1000 > 0)
-		return retval;
+		goto out;
 
 	/* tell entry.S:syscall_error that this is NOT an error: */
 	regs.r0 = 0;
+out:
+	unlock_kernel();
 	return retval;
 }
 
+asmlinkage long osf_sysinfo(int command, char *buf, long count)
+{
+	static char * sysinfo_table[] = {
+		system_utsname.sysname,
+		system_utsname.nodename,
+		system_utsname.release,
+		system_utsname.version,
+		system_utsname.machine,
+		"alpha",	/* instruction set architecture */
+		"dummy",	/* hardware serial number */
+		"dummy",	/* hardware manufacturer */
+		"dummy",	/* secure RPC domain */
+	};
+	unsigned long offset;
+	char *res;
+	long len, err = -EINVAL;
+
+	lock_kernel();
+	offset = command-1;
+	if (offset >= sizeof(sysinfo_table)/sizeof(char *)) {
+		/* Digital unix has a few unpublished interfaces here */
+		printk("sysinfo(%d)", command);
+		goto out;
+	}
+	res = sysinfo_table[offset];
+	len = strlen(res)+1;
+	if (len > count)
+		len = count;
+	if (copy_to_user(buf, res, len))
+		err = -EFAULT;
+	else
+		err = 0;
+out:
+	unlock_kernel();
+	return err;
+}
 
 asmlinkage unsigned long osf_getsysinfo(unsigned long op, void *buffer, unsigned long nbytes,
 					int *start, void *arg)
 {
 	extern unsigned long rdfpcr(void);
 	unsigned long fpcw;
+	unsigned long ret = -EOPNOTSUPP;
 
+	lock_kernel();
 	switch (op) {
 	case 45:		/* GSI_IEEE_FP_CONTROL */
 		/* build and return current fp control word: */
 		fpcw = current->tss.flags & IEEE_TRAP_ENABLE_MASK;
 		fpcw |= ((rdfpcr() >> 52) << 17) & IEEE_STATUS_MASK;
 		put_user(fpcw, (unsigned long *) buffer);
-		return 0;
-
+		ret = 0;
+		break;
 	case 46:		/* GSI_IEEE_STATE_AT_SIGNAL */
 		/*
 		 * Not sure anybody will ever use this weird stuff.  These
@@ -721,11 +849,11 @@
 		 * be used when a signal handler starts executing.
 		 */
 		break;
-
 	default:
 		break;
 	}
-	return -EOPNOTSUPP;
+	unlock_kernel();
+	return ret;
 }
 
 
@@ -733,15 +861,17 @@
 					int *start, void *arg)
 {
 	unsigned long fpcw;
+	unsigned long ret = -EOPNOTSUPP;
 
+	lock_kernel();
 	switch (op) {
 	case 14:		/* SSI_IEEE_FP_CONTROL */
 		/* update trap enable bits: */
 		get_user(fpcw, (unsigned long *) buffer);
 		current->tss.flags &= ~IEEE_TRAP_ENABLE_MASK;
 		current->tss.flags |= (fpcw & IEEE_TRAP_ENABLE_MASK);
-		return 0;
-
+		ret = 0;
+		break;
 	case 15:		/* SSI_IEEE_STATE_AT_SIGNAL */
 	case 16:		/* SSI_IEEE_IGNORE_STATE_AT_SIGNAL */
 		/*
@@ -752,5 +882,6 @@
 	default:
 		break;
 	}
-	return -EOPNOTSUPP;
+	unlock_kernel();
+	return ret;
 }
diff -u --recursive --new-file v2.1.22/linux/arch/alpha/kernel/process.c linux/arch/alpha/kernel/process.c
--- v2.1.22/linux/arch/alpha/kernel/process.c	Sun Dec 22 16:37:20 1996
+++ linux/arch/alpha/kernel/process.c	Sun Jan 26 14:26:39 1997
@@ -13,6 +13,8 @@
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 #include <linux/stddef.h>
 #include <linux/unistd.h>
 #include <linux/ptrace.h>
@@ -31,6 +33,9 @@
 #include <asm/system.h>
 #include <asm/io.h>
 
+/*
+ * No need to aquire the kernel lock, we're entirely local..
+ */
 asmlinkage int sys_sethae(unsigned long hae, unsigned long a1, unsigned long a2,
 	unsigned long a3, unsigned long a4, unsigned long a5,
 	struct pt_regs regs)
@@ -41,14 +46,21 @@
 
 asmlinkage int sys_idle(void)
 {
+	int ret = -EPERM;
+
+	lock_kernel();
 	if (current->pid != 0)
-		return -EPERM;
+		goto out;
 
 	/* endless idle loop with no priority at all */
 	current->counter = -100;
 	for (;;) {
 		schedule();
 	}
+	ret = 0;
+out:
+	unlock_kernel();
+	return ret;
 }
 
 void hard_reset_now(void)
@@ -246,10 +258,13 @@
 	int error;
 	char * filename;
 
+	lock_kernel();
 	error = getname((char *) a0, &filename);
 	if (error)
-		return error;
+		goto out;
 	error = do_execve(filename, (char **) a1, (char **) a2, &regs);
 	putname(filename);
+out:
+	unlock_kernel();
 	return error;
 }
diff -u --recursive --new-file v2.1.22/linux/arch/alpha/kernel/ptrace.c linux/arch/alpha/kernel/ptrace.c
--- v2.1.22/linux/arch/alpha/kernel/ptrace.c	Tue Oct 29 19:58:01 1996
+++ linux/arch/alpha/kernel/ptrace.c	Sun Jan 26 13:40:45 1997
@@ -8,6 +8,8 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
@@ -487,27 +489,30 @@
 			   int a4, int a5, struct pt_regs regs)
 {
 	struct task_struct *child;
-	struct user * dummy;
-
-	dummy = NULL;
+	long ret;
 
+	lock_kernel();
 	DBG(DBG_MEM, ("request=%ld pid=%ld addr=0x%lx data=0x%lx\n",
 		      request, pid, addr, data));
+	ret = -EPERM;
 	if (request == PTRACE_TRACEME) {
 		/* are we already being traced? */
 		if (current->flags & PF_PTRACED)
-			return -EPERM;
+			goto out;
 		/* set the ptrace bit in the process flags. */
 		current->flags |= PF_PTRACED;
-		return 0;
+		ret = 0;
+		goto out;
 	}
 	if (pid == 1)		/* you may not mess with init */
-		return -EPERM;
+		goto out;
+	ret = -ESRCH;
 	if (!(child = get_task(pid)))
-		return -ESRCH;
+		goto out;
 	if (request == PTRACE_ATTACH) {
+		ret = -EPERM;
 		if (child == current)
-			return -EPERM;
+			goto out;
 		if ((!child->dumpable ||
 		     (current->uid != child->euid) ||
 		     (current->uid != child->suid) ||
@@ -515,10 +520,10 @@
 		     (current->gid != child->egid) ||
 		     (current->gid != child->sgid) ||
 		     (current->gid != child->gid)) && !suser())
-			return -EPERM;
+			goto out;
 		/* the same process cannot be attached many times */
 		if (child->flags & PF_PTRACED)
-			return -EPERM;
+			goto out;
 		child->flags |= PF_PTRACED;
 		if (child->p_pptr != current) {
 			REMOVE_LINKS(child);
@@ -526,20 +531,22 @@
 			SET_LINKS(child);
 		}
 		send_sig(SIGSTOP, child, 1);
-		return 0;
+		ret = 0;
+		goto out;
 	}
+	ret = -ESRCH;
 	if (!(child->flags & PF_PTRACED)) {
 		DBG(DBG_MEM, ("child not traced\n"));
-		return -ESRCH;
+		goto out;
 	}
 	if (child->state != TASK_STOPPED) {
 		DBG(DBG_MEM, ("child process not stopped\n"));
 		if (request != PTRACE_KILL)
-			return -ESRCH;
+			goto out;
 	}
 	if (child->p_pptr != current) {
 		DBG(DBG_MEM, ("child not parent of this process\n"));
-		return -ESRCH;
+		goto out;
 	}
 
 	switch (request) {
@@ -547,37 +554,41 @@
 		case PTRACE_PEEKTEXT: /* read word at location addr. */
 		case PTRACE_PEEKDATA: {
 			unsigned long tmp;
-			int res;
 
-			res = read_long(child, addr, &tmp);
+			ret = read_long(child, addr, &tmp);
 			DBG(DBG_MEM, ("peek %#lx->%#lx\n", addr, tmp));
-			if (res < 0)
-				return res;
+			if (ret < 0)
+				goto out;
 			regs.r0 = 0;	/* special return: no errors */
-			return tmp;
+			ret = tmp;
+			goto out;
 		}
 
 	/* read register number ADDR. */
 		case PTRACE_PEEKUSR:
 			regs.r0 = 0;	/* special return: no errors */
 			DBG(DBG_MEM, ("peek $%ld=%#lx\n", addr, regs.r0));
-			return get_reg(child, addr);
+			ret = get_reg(child, addr);
+			goto out;
 
 	/* when I and D space are separate, this will have to be fixed. */
 		case PTRACE_POKETEXT: /* write the word at location addr. */
 		case PTRACE_POKEDATA:
 			DBG(DBG_MEM, ("poke %#lx<-%#lx\n", addr, data));
-			return write_long(child, addr, data);
+			ret = write_long(child, addr, data);
+			goto out;
 
 		case PTRACE_POKEUSR: /* write the specified register */
 			DBG(DBG_MEM, ("poke $%ld<-%#lx\n", addr, data));
-			return put_reg(child, addr, data);
+			ret = put_reg(child, addr, data);
+			goto out;
 
 		case PTRACE_SYSCALL: /* continue and stop at next
 					(return from) syscall */
 		case PTRACE_CONT: { /* restart after signal. */
+			ret = -EIO;
 			if ((unsigned long) data > NSIG)
-				return -EIO;
+				goto out;
 			if (request == PTRACE_SYSCALL)
 				child->flags |= PF_TRACESYS;
 			else
@@ -586,7 +597,8 @@
 			wake_up_process(child);
         /* make sure single-step breakpoint is gone. */
 			ptrace_cancel_bpt(child);
-			return data;
+			ret = data;
+			goto out;
 		}
 
 /*
@@ -601,23 +613,27 @@
 			}
         /* make sure single-step breakpoint is gone. */
 			ptrace_cancel_bpt(child);
-			return 0;
+			ret = 0;
+			goto out;
 		}
 
 		case PTRACE_SINGLESTEP: {  /* execute single instruction. */
+			ret = -EIO;
 			if ((unsigned long) data > NSIG)
-				return -EIO;
+				goto out;
 			child->debugreg[4] = -1;	/* mark single-stepping */
 			child->flags &= ~PF_TRACESYS;
 			wake_up_process(child);
 			child->exit_code = data;
 	/* give it a chance to run. */
-			return 0;
+			ret = 0;
+			goto out;
 		}
 
 		case PTRACE_DETACH: { /* detach a process that was attached. */
+			ret = -EIO;
 			if ((unsigned long) data > NSIG)
-				return -EIO;
+				goto out;
 			child->flags &= ~(PF_PTRACED|PF_TRACESYS);
 			wake_up_process(child);
 			child->exit_code = data;
@@ -626,19 +642,25 @@
 			SET_LINKS(child);
         /* make sure single-step breakpoint is gone. */
 			ptrace_cancel_bpt(child);
-			return 0;
+			ret = 0;
+			goto out;
 		}
 
 		default:
-		  return -EIO;
+		  ret = -EIO;
+		  goto out;
 	  }
+out:
+	unlock_kernel();
+	return ret;
 }
 
 asmlinkage void syscall_trace(void)
 {
+	lock_kernel();
 	if ((current->flags & (PF_PTRACED|PF_TRACESYS))
 			!= (PF_PTRACED|PF_TRACESYS))
-		return;
+		goto out;
 	current->exit_code = SIGTRAP;
 	current->state = TASK_STOPPED;
 	notify_parent(current);
@@ -651,4 +673,6 @@
 	if (current->exit_code)
 		current->signal |= (1 << (current->exit_code - 1));
 	current->exit_code = 0;
+out:
+	unlock_kernel();
 }
diff -u --recursive --new-file v2.1.22/linux/arch/alpha/kernel/signal.c linux/arch/alpha/kernel/signal.c
--- v2.1.22/linux/arch/alpha/kernel/signal.c	Tue Oct 29 19:58:01 1996
+++ linux/arch/alpha/kernel/signal.c	Sun Jan 26 14:26:39 1997
@@ -12,6 +12,8 @@
 #include <linux/ptrace.h>
 #include <linux/unistd.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/bitops.h>
 #include <asm/uaccess.h>
@@ -38,6 +40,9 @@
  *
  * We change the range to -1 .. 1 in order to let gcc easily
  * use the conditional move instructions.
+ *
+ * Note that we don't need to aquire the kernel lock for SMP
+ * operation, as all of this is local to this thread.
  */
 asmlinkage unsigned long osf_sigprocmask(int how, unsigned long newmask,
 	long a2, long a3, long a4, long a5, struct pt_regs regs)
@@ -73,14 +78,20 @@
  */
 asmlinkage int do_sigsuspend(unsigned long mask, struct pt_regs * regs, struct switch_stack * sw)
 {
-	unsigned long oldmask = current->blocked;
+	unsigned long oldmask;
+
+	lock_kernel();
+	oldmask = current->blocked;
 	current->blocked = mask & _BLOCKABLE;
 	while (1) {
 		current->state = TASK_INTERRUPTIBLE;
 		schedule();
 		if (do_signal(oldmask,regs, sw, 0, 0))
-			return -EINTR;
+			goto out;
 	}
+out:
+	unlock_kernel();
+	return -EINTR;
 }
 
 /*
@@ -93,6 +104,7 @@
 	int i;
 
 	/* verify that it's a good sigcontext before using it */
+	lock_kernel();
 	if (verify_area(VERIFY_READ, sc, sizeof(*sc)))
 		do_exit(SIGSEGV);
 	get_user(ps, &sc->sc_ps);
@@ -145,6 +157,7 @@
 	/* send SIGTRAP if we're single-stepping: */
 	if (ptrace_cancel_bpt (current))
 		send_sig(SIGTRAP, current, 1);
+	unlock_kernel();
 }
 
 /*
@@ -279,10 +292,13 @@
 	struct switch_stack * sw,
 	unsigned long r0, unsigned long r19)
 {
-	unsigned long mask = ~current->blocked;
+	unsigned long mask;
 	unsigned long signr, single_stepping;
 	struct sigaction * sa;
+	int ret;
 
+	lock_kernel();
+	mask = ~current->blocked;
 	single_stepping = ptrace_cancel_bpt(current);
 
 	while ((signr = current->signal & mask) != 0) {
@@ -356,7 +372,8 @@
 		if (single_stepping) {
 			ptrace_set_bpt(current);	/* re-set breakpoint */
 		}
-		return 1;
+		ret = 1;
+		goto out;
 	}
 	if (r0 &&
 	    (regs->r0 == ERESTARTNOHAND ||
@@ -369,5 +386,8 @@
 	if (single_stepping) {
 		ptrace_set_bpt(current);	/* re-set breakpoint */
 	}
-	return 0;
+	ret = 0;
+out:
+	unlock_kernel();
+	return ret;
 }
diff -u --recursive --new-file v2.1.22/linux/arch/alpha/kernel/traps.c linux/arch/alpha/kernel/traps.c
--- v2.1.22/linux/arch/alpha/kernel/traps.c	Wed Jan 15 19:45:39 1997
+++ linux/arch/alpha/kernel/traps.c	Sun Jan 26 12:07:04 1997
@@ -21,15 +21,16 @@
 		   unsigned long *r9_15)
 {
 	long i;
-	unsigned long sp;
+	unsigned long sp, ra;
 	unsigned int * pc;
 
 	if (regs->ps & 8)
 		return;
 	printk("%s(%d): %s %ld\n", current->comm, current->pid, str, err);
 	sp = (unsigned long) (regs+1);
+	__get_user(ra, (unsigned long *)sp);
 	printk("pc = [<%016lx>] ps = %04lx\n", regs->pc, regs->ps);
-	printk("rp = [<%016lx>] sp = %016lx\n", regs->r26, sp);
+	printk("rp = [<%016lx>] ra = [<%016lx>]\n", regs->r26, ra);
 	printk("r0 = %016lx  r1 = %016lx\n", regs->r0, regs->r1);
 	printk("r2 = %016lx  r3 = %016lx\n", regs->r2, regs->r3);
 	printk("r4 = %016lx  r5 = %016lx\n", regs->r4, regs->r5);
@@ -49,13 +50,17 @@
 	printk("r20= %016lx  r21= %016lx\n", regs->r20, regs->r21);
 	printk("r22= %016lx  r23= %016lx\n", regs->r22, regs->r23);
 	printk("r24= %016lx  r25= %016lx\n", regs->r24, regs->r25);
-	printk("r26= %016lx  r27= %016lx\n", regs->r26, regs->r27);
-	printk("r28= %016lx  r29= %016lx\n", regs->r28, regs->gp);
+	printk("r27= %016lx  r28= %016lx\n", regs->r27, regs->r28);
+	printk("gp = %016lx  sp = %016lx\n", regs->gp, sp);
 
 	printk("Code:");
 	pc = (unsigned int *) regs->pc;
-	for (i = -3; i < 6; i++)
-		printk("%c%08x%c",i?' ':'<',pc[i],i?' ':'>');
+	for (i = -3; i < 6; i++) {
+		unsigned int insn;
+		if (__get_user(insn, pc+i))
+			break;
+		printk("%c%08x%c",i?' ':'<',insn,i?' ':'>');
+	}
 	printk("\n");
 	do_exit(SIGSEGV);
 }
diff -u --recursive --new-file v2.1.22/linux/arch/alpha/mm/extable.c linux/arch/alpha/mm/extable.c
--- v2.1.22/linux/arch/alpha/mm/extable.c	Mon Dec 30 15:39:02 1996
+++ linux/arch/alpha/mm/extable.c	Thu Jan 23 21:01:28 1997
@@ -34,6 +34,8 @@
         return 0;
 }
 
+register unsigned long gp __asm__("$29");
+
 unsigned
 search_exception_table(unsigned long addr)
 {
@@ -41,7 +43,6 @@
 
 #ifndef CONFIG_MODULE
 	/* There is only the kernel to search.  */
-	register unsigned long gp __asm__("$29");
 	ret = search_one_table(__start___ex_table, __stop___ex_table - 1,
 			       addr - gp);
 	if (ret) return ret;
diff -u --recursive --new-file v2.1.22/linux/arch/alpha/mm/init.c linux/arch/alpha/mm/init.c
--- v2.1.22/linux/arch/alpha/mm/init.c	Sun Dec 22 16:37:20 1996
+++ linux/arch/alpha/mm/init.c	Sun Jan 26 12:07:04 1997
@@ -171,6 +171,11 @@
 	return;
 }
 
+void free_initmem(void)
+{
+	/* To be written */
+}
+
 void si_meminfo(struct sysinfo *val)
 {
 	int i;
diff -u --recursive --new-file v2.1.22/linux/arch/i386/Makefile linux/arch/i386/Makefile
--- v2.1.22/linux/arch/i386/Makefile	Wed Jan 15 19:45:39 1997
+++ linux/arch/i386/Makefile	Sun Jan 26 12:07:04 1997
@@ -111,7 +111,6 @@
 
 archclean:
 	@$(MAKEBOOT) clean
-	$(MAKE) -C arch/$(ARCH)/kernel clean
 
 archdep:
 	@$(MAKEBOOT) dep
diff -u --recursive --new-file v2.1.22/linux/arch/i386/kernel/Makefile linux/arch/i386/kernel/Makefile
--- v2.1.22/linux/arch/i386/kernel/Makefile	Wed Jan 15 19:45:40 1997
+++ linux/arch/i386/kernel/Makefile	Sun Jan 26 12:07:04 1997
@@ -7,9 +7,6 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-#.S.s:
-#	$(CPP) -D__ASSEMBLY__ -traditional $< -o $*.s
-
 ifdef SMP
 .S.o:
 	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
@@ -31,7 +28,7 @@
 
 ifdef SMP
 
-O_OBJS += smp.o
+O_OBJS += smp.o trampoline.o
 
 head.o: head.S $(TOPDIR)/include/linux/tasks.h
 	$(CC) -D__ASSEMBLY__ -D__SMP__ -traditional -c $*.S -o $*.o
@@ -42,31 +39,5 @@
 	$(CC) -D__ASSEMBLY__ -traditional -c $*.S -o $*.o
 
 endif
-
-hexify:
-	$(HOSTCC) hexify.c -o hexify
-
-smp.c: trampoline.hex
-
-trampoline.hex: trampoline hexify
-	(dd if=trampoline bs=1 skip=32 | ./hexify >trampoline.hex )
-
-trampoline: trampoline.o trampoline32.o
-	$(LD86) -s -o $@ trampoline.o trampoline32.o
-
-trampoline.o: trampoline.s
-	$(AS86) -o $@ $<
-
-trampoline32.o: trampoline32.s
-	$(AS386) -o $@ $<
-
-trampoline.s: trampoline.S $(CONFIGURE) $(TOPDIR)/include/linux/config.h Makefile
-	$(CPP) -D__SMP__ -traditional $< -o $@
-
-trampoline32.s: trampoline32.S $(CONFIGURE) $(TOPDIR)/include/linux/config.h Makefile
-	$(CPP) -D__SMP__ -traditional $< -o $@
-
-clean:
-	rm -f trampoline hexify trampoline.hex
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.22/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S
--- v2.1.22/linux/arch/i386/kernel/entry.S	Mon Dec 30 15:39:03 1996
+++ linux/arch/i386/kernel/entry.S	Sun Jan 26 12:07:04 1997
@@ -97,98 +97,7 @@
 	mov %dx,%ds; \
 	mov %dx,%es;
 
-#ifdef	__SMP__
-
-#define GET_PROCESSOR_ID \
-	movl SYMBOL_NAME(apic_reg), %edx; \
-	movl 32(%edx), %eax;\
-	movl %eax,SYMBOL_NAME(apic_retval); \
-	shrl $24,%eax; \
-	andb $0x0F,%al;
-
-/*
- *	Get the processor ID multiplied by 4
- */
-
-#define GET_PROCESSOR_OFFSET(x) \
-	movl SYMBOL_NAME(apic_reg), x ; \
-	movl 32( x ), x ; \
-	shrl $22, x ; \
-	andl $0x3C, x ;
-
-/* macro LEAVE_KERNEL decrements kernel_counter and resets kernel_flag and
-   saves processor variables if zero */
-#define	LEAVE_KERNEL \
-	pushfl; \
-	cli; \
-	GET_PROCESSOR_ID \
-	btrl $ SMP_FROM_SYSCALL,SYMBOL_NAME(smp_proc_in_lock)(,%eax,4); \
-	decl SYMBOL_NAME(syscall_count); \
-	decl SYMBOL_NAME(kernel_counter); \
-	jnz 1f;	\
-	movb $(NO_PROC_ID), SYMBOL_NAME(active_kernel_processor); \
-	lock; \
-	btrl $0, SYMBOL_NAME(kernel_flag); \
-1:	popfl;
-
-/* macro ENTER_KERNEL waits for entering the kernel, increments
-   kernel_counter, and reloads the processor variables if necessary
-   uses : %eax, %edx (pushed and popped)
-
-   Note: We go to great pains to minimise the number of locked operations.
-   We want to spin without locking, and lock when we attempt an update.
-   The pentium has a MESI cache so the spin without lock will exit when
-   another CPU write invalidates our cache, and the lock is avoided when
-   possible so we don't play ping-pong games with the cache line.
-
-*/
-
-#ifndef __SMP_PROF__
-
-#define SMP_PROF_A
-#define SMP_PROF_B
-
-#else
-
-#define SMP_PROF_A movl $0,SYMBOL_NAME(smp_spins_syscall_cur)(,%eax,4);
-#define SMP_PROF_B incl SYMBOL_NAME(smp_spins_syscall)(,%eax,4); \
-        incl SYMBOL_NAME(smp_spins_syscall_cur)(,%eax,4);
-#endif
-
-#define	ENTER_KERNEL \
-	pushl %eax; \
-	pushl %edx; \
-	pushfl; \
-	cli; \
-	GET_PROCESSOR_ID \
-	btsl $ SMP_FROM_SYSCALL,SYMBOL_NAME(smp_proc_in_lock)(,%eax,4); \
-	SMP_PROF_A \
-1:	lock; \
-	btsl $0, SYMBOL_NAME(kernel_flag); \
-	jnc 3f; \
-	cmpb SYMBOL_NAME(active_kernel_processor), %al; \
-	je 4f; \
-2:	SMP_PROF_B \
-	btl %al, SYMBOL_NAME(smp_invalidate_needed); \
-	jnc 5f; \
-	lock; \
-	btrl %al, SYMBOL_NAME(smp_invalidate_needed); \
-	jnc 5f; \
-	movl %cr3,%edx; \
-	movl %edx,%cr3; \
-5:	btl $0, SYMBOL_NAME(kernel_flag); \
-	jc 2b; \
-	jmp 1b; \
-3:	movb %al, SYMBOL_NAME(active_kernel_processor); \
-4:	incl SYMBOL_NAME(kernel_counter); \
-	incl SYMBOL_NAME(syscall_count); \
-	popfl; \
-	popl %edx; \
-	popl %eax;
-
-
 #define RESTORE_ALL \
-	LEAVE_KERNEL \
 	popl %ebx; \
 	popl %ecx; \
 	popl %edx; \
@@ -201,38 +110,30 @@
 	addl $4,%esp; \
 	iret
 
-#define GET_CURRENT \
-	GET_PROCESSOR_OFFSET(%ebx) \
-	movl SYMBOL_NAME(current_set)(%ebx),%ebx
+#ifdef	__SMP__
+/* Get the processor ID multiplied by 4 */
+#define GET_PROCESSOR_OFFSET(reg) \
+	movl SYMBOL_NAME(apic_reg), reg; \
+	movl 32(reg), reg; \
+	shrl $22, reg; \
+	andl $0x3C, reg;
+
+#define GET_CURRENT(reg) \
+	GET_PROCESSOR_OFFSET(reg) \
+	movl SYMBOL_NAME(current_set)(reg),reg
 
 #else
 
-#define GET_CURRENT \
-	movl SYMBOL_NAME(current_set),%ebx
+#define GET_CURRENT(reg) \
+	movl SYMBOL_NAME(current_set),reg
 
-#define RESTORE_ALL \
-	popl %ebx; \
-	popl %ecx; \
-	popl %edx; \
-	popl %esi; \
-	popl %edi; \
-	popl %ebp; \
-	popl %eax; \
-	pop %ds; \
-	pop %es; \
-	addl $4,%esp; \
-	iret
 #endif
 
-
 ENTRY(lcall7)
 	pushfl			# We get a different stack layout with call gates,
 	pushl %eax		# which has to be cleaned up later..
 	SAVE_ALL
-	GET_CURRENT
-#ifdef __SMP__
-	ENTER_KERNEL
-#endif
+	GET_CURRENT(%ebx)
 	movl EIP(%esp),%eax	# due to call gates, this is eflags, not eip..
 	movl CS(%esp),%edx	# this is eip..
 	movl EFLAGS(%esp),%ecx	# and this is cs..
@@ -240,12 +141,7 @@
 	movl %edx,EIP(%esp)	# Now we move them to their "normal" places
 	movl %ecx,CS(%esp)	#
 	movl %esp,%eax
-#ifdef __SMP__
-	GET_PROCESSOR_OFFSET(%edx)	# Processor offset into edx
-	movl SYMBOL_NAME(current_set)(,%edx),%edx
-#else
-	movl SYMBOL_NAME(current_set),%edx
-#endif
+	GET_CURRENT(%edx)
 	pushl %eax
 	movl exec_domain(%edx),%edx	# Get the execution domain
 	movl 4(%edx),%edx	# Get the lcall7 handler for the domain
@@ -253,12 +149,23 @@
 	popl %eax
 	jmp ret_from_sys_call
 
+#ifdef __SMP__
+	ALIGN
+	.globl	ret_from_smpfork
+ret_from_smpfork:
+	GET_CURRENT(%ebx)
+	movl	$NO_PROC_ID, SYMBOL_NAME(active_kernel_processor)
+	lock
+	btrl	$0, SYMBOL_NAME(kernel_flag)
+	sti
+	jmp	9f
+#endif /* __SMP__ */
+
 	ALIGN
 handle_bottom_half:
-	incl SYMBOL_NAME(intr_count)
-	call SYMBOL_NAME(do_bottom_half)
-	decl SYMBOL_NAME(intr_count)
-	jmp 9f
+	pushl $9f
+	jmp SYMBOL_NAME(do_bottom_half)
+
 	ALIGN
 reschedule:
 	pushl $ret_from_sys_call
@@ -267,10 +174,7 @@
 ENTRY(system_call)
 	pushl %eax			# save orig_eax
 	SAVE_ALL
-	GET_CURRENT
-#ifdef __SMP__
-	ENTER_KERNEL
-#endif
+	GET_CURRENT(%ebx)
 	cmpl $(NR_syscalls),%eax
 	jae badsys
 	testb $0x20,flags(%ebx)		# PF_TRACESYS
@@ -280,9 +184,7 @@
 	ALIGN
 	.globl ret_from_sys_call
 ret_from_sys_call:
-#ifdef __SMP__
-	GET_CURRENT
-#endif
+	GET_CURRENT(%ebx)
 	cmpl $0,SYMBOL_NAME(intr_count)
 	jne 1f
 9:	movl SYMBOL_NAME(bh_mask),%eax
@@ -358,10 +260,7 @@
 	movl $(KERNEL_DS),%edx
 	mov %dx,%ds
 	mov %dx,%es
-	GET_CURRENT
-#ifdef __SMP__
-	ENTER_KERNEL
-#endif
+	GET_CURRENT(%ebx)
 	call *%ecx
 	addl $8,%esp
 	jmp ret_from_sys_call
@@ -374,10 +273,7 @@
 ENTRY(device_not_available)
 	pushl $-1		# mark this as an int
 	SAVE_ALL
-	GET_CURRENT
-#ifdef __SMP__
-	ENTER_KERNEL
-#endif
+	GET_CURRENT(%ebx)
 	pushl $ret_from_sys_call
 	movl %cr0,%eax
 	testl $0x4,%eax			# EM (math emulation bit)
@@ -630,6 +526,7 @@
 	.long SYMBOL_NAME(sys_getresuid)	/* 165 */
 	.long SYMBOL_NAME(sys_vm86)
 	.long SYMBOL_NAME(sys_query_module)
-	.rept NR_syscalls-167
+	.long SYMBOL_NAME(sys_poll)
+	.rept NR_syscalls-168
 		.long SYMBOL_NAME(sys_ni_syscall)
 	.endr
diff -u --recursive --new-file v2.1.22/linux/arch/i386/kernel/hexify.c linux/arch/i386/kernel/hexify.c
--- v2.1.22/linux/arch/i386/kernel/hexify.c	Mon Oct  2 14:25:10 1995
+++ linux/arch/i386/kernel/hexify.c	Thu Jan  1 02:00:00 1970
@@ -1,31 +0,0 @@
-#include <stdio.h>
-
-
-void main()
-{
-	int c;
-	int comma=0;
-	int count=0;
-	while((c=getchar())!=EOF)
-	{
-		unsigned char x=c;
-		if(comma)
-			printf(",");
-		else
-			comma=1;
-		if(count==8)
-		{
-			count=0;
-			printf("\n");
-		}
-		if(count==0)
-			printf("\t");
-		printf("0x%02X",c);
-		count++;
-	}
-	if(count)
-		printf("\n");
-	exit(0);
-}
-
-		
diff -u --recursive --new-file v2.1.22/linux/arch/i386/kernel/i386_ksyms.c linux/arch/i386/kernel/i386_ksyms.c
--- v2.1.22/linux/arch/i386/kernel/i386_ksyms.c	Wed Jan 15 19:45:40 1997
+++ linux/arch/i386/kernel/i386_ksyms.c	Sun Jan 26 12:07:04 1997
@@ -4,6 +4,7 @@
 #include <linux/user.h>
 #include <linux/elfcore.h>
 #include <linux/mca.h>
+#include <linux/sched.h>
 
 #include <asm/semaphore.h>
 #include <asm/processor.h>
@@ -12,6 +13,7 @@
 
 extern void dump_thread(struct pt_regs *, struct user *);
 extern int dump_fpu(elf_fpregset_t *);
+extern void __lock_kernel(void);
 
 /* platform dependent support */
 EXPORT_SYMBOL(EISA_bus);
@@ -28,11 +30,10 @@
 #ifdef __SMP__
 EXPORT_SYMBOL(apic_reg);	/* Needed internally for the I386 inlines */
 EXPORT_SYMBOL(cpu_data);
-EXPORT_SYMBOL(syscall_count);
 EXPORT_SYMBOL(kernel_flag);
-EXPORT_SYMBOL(kernel_counter);
 EXPORT_SYMBOL(active_kernel_processor);
 EXPORT_SYMBOL(smp_invalidate_needed);
+EXPORT_SYMBOL_NOVERS(__lock_kernel);
 #endif
 
 #ifdef CONFIG_MCA
diff -u --recursive --new-file v2.1.22/linux/arch/i386/kernel/ioport.c linux/arch/i386/kernel/ioport.c
--- v2.1.22/linux/arch/i386/kernel/ioport.c	Wed Oct  9 08:55:17 1996
+++ linux/arch/i386/kernel/ioport.c	Sun Jan 26 12:07:04 1997
@@ -10,6 +10,9 @@
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 /* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */
 static void set_bitmap(unsigned long *bitmap, short base, short extent, int new_value)
@@ -50,15 +53,19 @@
  */
 asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on)
 {
-	if (from + num <= from)
-		return -EINVAL;
-	if (from + num > IO_BITMAP_SIZE*32)
-		return -EINVAL;
-	if (!suser())
-		return -EPERM;
+	int ret = -EINVAL;
 
+	lock_kernel();
+	if ((from + num <= from) || (from + num > IO_BITMAP_SIZE*32))
+		goto out;
+	ret = -EPERM;
+	if (!suser())
+		goto out;
 	set_bitmap((unsigned long *)current->tss.io_bitmap, from, num, !turn_on);
-	return 0;
+	ret = 0;
+out:
+	unlock_kernel();
+	return ret;
 }
 
 unsigned int *stack;
@@ -79,11 +86,17 @@
 	     long eflags, long esp, long ss)
 {
 	unsigned int level = ebx;
+	int ret = -EINVAL;
 
+	lock_kernel();
 	if (level > 3)
-		return -EINVAL;
+		goto out;
+	ret = -EPERM;
 	if (!suser())
-		return -EPERM;
+		goto out;
 	*(&eflags) = (eflags & 0xffffcfff) | (level << 12);
-	return 0;
+	ret = 0;
+out:
+	unlock_kernel();
+	return ret;
 }
diff -u --recursive --new-file v2.1.22/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c
--- v2.1.22/linux/arch/i386/kernel/irq.c	Thu Jan 23 21:06:46 1997
+++ linux/arch/i386/kernel/irq.c	Sun Jan 26 12:07:04 1997
@@ -25,6 +25,8 @@
 #include <linux/timex.h>
 #include <linux/malloc.h>
 #include <linux/random.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -346,6 +348,8 @@
 	struct irqaction * action = *(irq + irq_action);
 	int do_random = 0;
 
+	lock_kernel();
+	intr_count++;
 #ifdef __SMP__
 	if(smp_threads_ready && active_kernel_processor!=smp_processor_id())
 		panic("IRQ %d: active processor set wrongly(%d not %d).\n", irq, active_kernel_processor, smp_processor_id());
@@ -362,6 +366,8 @@
 	}
 	if (do_random & SA_SAMPLE_RANDOM)
 		add_interrupt_randomness(irq);
+	intr_count--;
+	unlock_kernel();
 }
 
 /*
@@ -374,6 +380,8 @@
 	struct irqaction * action = *(irq + irq_action);
 	int do_random = 0;
 	
+	lock_kernel();
+	intr_count++;
 #ifdef __SMP__
 	/* IRQ 13 is allowed - that's a flush tlb */
 	if(smp_threads_ready && active_kernel_processor!=smp_processor_id() && irq!=13)
@@ -391,6 +399,8 @@
 	}
 	if (do_random & SA_SAMPLE_RANDOM)
 		add_interrupt_randomness(irq);
+	intr_count--;
+	unlock_kernel();
 }
 
 int setup_x86_irq(int irq, struct irqaction * new)
diff -u --recursive --new-file v2.1.22/linux/arch/i386/kernel/ldt.c linux/arch/i386/kernel/ldt.c
--- v2.1.22/linux/arch/i386/kernel/ldt.c	Thu Jan  2 15:55:14 1997
+++ linux/arch/i386/kernel/ldt.c	Sun Jan 26 12:07:04 1997
@@ -8,6 +8,8 @@
 #include <linux/sched.h>
 #include <linux/string.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 #include <linux/vmalloc.h>
 
 #include <asm/uaccess.h>
@@ -117,11 +119,17 @@
 
 asmlinkage int sys_modify_ldt(int func, void *ptr, unsigned long bytecount)
 {
+	int ret;
+
+	lock_kernel();
 	if (func == 0)
-		return read_ldt(ptr, bytecount);
-	if (func == 1)
-		return write_ldt(ptr, bytecount, 1);
-	if (func == 0x11)
-		return write_ldt(ptr, bytecount, 0);
-	return -ENOSYS;
+		ret = read_ldt(ptr, bytecount);
+	else if (func == 1)
+		ret = write_ldt(ptr, bytecount, 1);
+	else  if (func == 0x11)
+		ret = write_ldt(ptr, bytecount, 0);
+	else
+		ret = -ENOSYS;
+	unlock_kernel();
+	return ret;
 }
diff -u --recursive --new-file v2.1.22/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c
--- v2.1.22/linux/arch/i386/kernel/process.c	Wed Jan 15 19:45:40 1997
+++ linux/arch/i386/kernel/process.c	Sun Jan 26 13:40:45 1997
@@ -15,6 +15,8 @@
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 #include <linux/stddef.h>
 #include <linux/unistd.h>
 #include <linux/ptrace.h>
@@ -34,7 +36,11 @@
 #include <asm/io.h>
 #include <asm/ldt.h>
 
+#ifdef __SMP__
+asmlinkage void ret_from_smpfork(void) __asm__("ret_from_smpfork");
+#else
 asmlinkage void ret_from_sys_call(void) __asm__("ret_from_sys_call");
+#endif
 
 #ifdef CONFIG_APM
 extern int  apm_do_idle(void);
@@ -91,9 +97,11 @@
 asmlinkage int sys_idle(void)
 {
         unsigned long start_idle = 0;
+	int ret = -EPERM;
 
+	lock_kernel();
 	if (current->pid != 0)
-		return -EPERM;
+		goto out;
 	/* endless idle loop with no priority at all */
 	current->counter = -100;
 	for (;;) 
@@ -118,6 +126,10 @@
 			start_idle = 0;
 		schedule();
 	}
+	ret = 0;
+out:
+	unlock_kernel();
+	return ret;
 }
 
 #else
@@ -129,15 +141,21 @@
  
 asmlinkage int sys_idle(void)
 {
+	int ret = -EPERM;
+
+	lock_kernel();
 	if(current->pid != 0)
-		return -EPERM;
+		goto out;
 #ifdef __SMP_PROF__
 	smp_spins_sys_idle[smp_processor_id()]+=
 	  smp_spins_syscall_cur[smp_processor_id()];
 #endif
 	current->counter= -100;
 	schedule();
-	return 0;
+	ret = 0;
+out:
+	unlock_kernel();
+	return ret;
 }
 
 /*
@@ -150,9 +168,10 @@
 	{
 		if(cpu_data[smp_processor_id()].hlt_works_ok && !hlt_counter && !need_resched)
 			__asm("hlt");
-                if(0==(0x7fffffff & smp_process_available)) 
+                if(0==(read_smp_counter(&smp_process_available))) 
                 	continue;
-                while(0x80000000 & smp_process_available);
+                while(0x80000000 & smp_process_available)
+			;
 	        cli();
                 while(set_bit(31,&smp_process_available))
                 	while(test_bit(31,&smp_process_available))
@@ -163,7 +182,7 @@
                 	if(clear_bit(smp_processor_id(), &smp_invalidate_needed))
                 		local_flush_tlb();
                 }
-                if (0==(0x7fffffff & smp_process_available)){
+                if (0==(read_smp_counter(&smp_process_available))) {
                         clear_bit(31,&smp_process_available);
                         sti();
                         continue;
@@ -473,13 +492,18 @@
 	p->tss.tr = _TSS(nr);
 	childregs = ((struct pt_regs *) (p->kernel_stack_page + PAGE_SIZE)) - 1;
 	p->tss.esp = (unsigned long) childregs;
+#ifdef __SMP__
+	p->tss.eip = (unsigned long) ret_from_smpfork;
+	p->tss.eflags = regs->eflags & 0xffffcdff;  /* iopl always 0 for a new process */
+#else
 	p->tss.eip = (unsigned long) ret_from_sys_call;
+	p->tss.eflags = regs->eflags & 0xffffcfff;  /* iopl always 0 for a new process */
+#endif
 	p->tss.ebx = (unsigned long) p;
 	*childregs = *regs;
 	childregs->eax = 0;
 	childregs->esp = esp;
 	p->tss.back_link = 0;
-	p->tss.eflags = regs->eflags & 0xffffcfff;	/* iopl is always 0 for a new process */
 	p->tss.ldt = _LDT(nr);
 	if (p->ldt) {
 		p->ldt = (struct desc_struct*) vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
@@ -568,19 +592,28 @@
 
 asmlinkage int sys_fork(struct pt_regs regs)
 {
-	return do_fork(SIGCHLD, regs.esp, &regs);
+	int ret;
+
+	lock_kernel();
+	ret = do_fork(SIGCHLD, regs.esp, &regs);
+	unlock_kernel();
+	return ret;
 }
 
 asmlinkage int sys_clone(struct pt_regs regs)
 {
 	unsigned long clone_flags;
 	unsigned long newsp;
+	int ret;
 
+	lock_kernel();
 	clone_flags = regs.ebx;
 	newsp = regs.ecx;
 	if (!newsp)
 		newsp = regs.esp;
-	return do_fork(clone_flags, newsp, &regs);
+	ret = do_fork(clone_flags, newsp, &regs);
+	unlock_kernel();
+	return ret;
 }
 
 /*
@@ -591,10 +624,13 @@
 	int error;
 	char * filename;
 
+	lock_kernel();
 	error = getname((char *) regs.ebx, &filename);
 	if (error)
-		return error;
+		goto out;
 	error = do_execve(filename, (char **) regs.ecx, (char **) regs.edx, &regs);
 	putname(filename);
+out:
+	unlock_kernel();
 	return error;
 }
diff -u --recursive --new-file v2.1.22/linux/arch/i386/kernel/ptrace.c linux/arch/i386/kernel/ptrace.c
--- v2.1.22/linux/arch/i386/kernel/ptrace.c	Thu Jan  2 15:55:15 1997
+++ linux/arch/i386/kernel/ptrace.c	Sun Jan 26 12:07:04 1997
@@ -6,6 +6,8 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
@@ -362,26 +364,29 @@
 asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
 {
 	struct task_struct *child;
-	struct user * dummy;
-	int i;
-
-	dummy = NULL;
+	struct user * dummy = NULL;
+	int i, ret;
 
+	lock_kernel();
+	ret = -EPERM;
 	if (request == PTRACE_TRACEME) {
 		/* are we already being traced? */
 		if (current->flags & PF_PTRACED)
-			return -EPERM;
+			goto out;
 		/* set the ptrace bit in the process flags. */
 		current->flags |= PF_PTRACED;
-		return 0;
+		ret = 0;
+		goto out;
 	}
 	if (pid == 1)		/* you may not mess with init */
-		return -EPERM;
+		goto out;
+	ret = -ESRCH;
 	if (!(child = get_task(pid)))
-		return -ESRCH;
+		goto out;
+	ret = -EPERM;
 	if (request == PTRACE_ATTACH) {
 		if (child == current)
-			return -EPERM;
+			goto out;
 		if ((!child->dumpable ||
 		    (current->uid != child->euid) ||
 		    (current->uid != child->suid) ||
@@ -389,10 +394,10 @@
 	 	    (current->gid != child->egid) ||
 	 	    (current->gid != child->sgid) ||
 	 	    (current->gid != child->gid)) && !suser())
-			return -EPERM;
+			goto out;
 		/* the same process cannot be attached many times */
 		if (child->flags & PF_PTRACED)
-			return -EPERM;
+			goto out;
 		child->flags |= PF_PTRACED;
 		if (child->p_pptr != current) {
 			REMOVE_LINKS(child);
@@ -400,37 +405,39 @@
 			SET_LINKS(child);
 		}
 		send_sig(SIGSTOP, child, 1);
-		return 0;
+		ret = 0;
+		goto out;
 	}
+	ret = -ESRCH;
 	if (!(child->flags & PF_PTRACED))
-		return -ESRCH;
+		goto out;
 	if (child->state != TASK_STOPPED) {
 		if (request != PTRACE_KILL)
-			return -ESRCH;
+			goto out;
 	}
 	if (child->p_pptr != current)
-		return -ESRCH;
+		goto out;
 
 	switch (request) {
 	/* when I and D space are separate, these will need to be fixed. */
 		case PTRACE_PEEKTEXT: /* read word at location addr. */ 
 		case PTRACE_PEEKDATA: {
 			unsigned long tmp;
-			int res;
 
-			res = read_long(child, addr, &tmp);
-			if (res < 0)
-				return res;
-			return put_user(tmp,(unsigned long *) data);
+			ret = read_long(child, addr, &tmp);
+			if (ret >= 0)
+				ret = put_user(tmp,(unsigned long *) data);
+			goto out;
 		}
 
 	/* read the word at location addr in the USER area. */
 		case PTRACE_PEEKUSR: {
 			unsigned long tmp;
 
+			ret = -EIO;
 			if ((addr & 3) || addr < 0 || 
 			    addr > sizeof(struct user) - 3)
-				return -EIO;
+				goto out;
 
 			tmp = 0;  /* Default return condition */
 			if(addr < 17*sizeof(long))
@@ -441,21 +448,26 @@
 				addr = addr >> 2;
 				tmp = child->debugreg[addr];
 			};
-			return put_user(tmp,(unsigned long *) data);
+			ret = put_user(tmp,(unsigned long *) data);
+			goto out;
 		}
 
       /* when I and D space are separate, this will have to be fixed. */
 		case PTRACE_POKETEXT: /* write the word at location addr. */
 		case PTRACE_POKEDATA:
-			return write_long(child,addr,data);
+			ret = write_long(child,addr,data);
+			goto out;
 
 		case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
+			ret = -EIO;
 			if ((addr & 3) || addr < 0 || 
 			    addr > sizeof(struct user) - 3)
-				return -EIO;
+				goto out;
 
-			if (addr < 17*sizeof(long))
-				return putreg(child, addr, data);
+			if (addr < 17*sizeof(long)) {
+				ret = putreg(child, addr, data);
+				goto out;
+			}
 
 		  /* We need to be very careful here.  We implicitly
 		     want to modify a portion of the task_struct, and we
@@ -470,26 +482,30 @@
 			  if(addr < (long) &dummy->u_debugreg[4] &&
 			     ((unsigned long) data) >= 0xbffffffd) return -EIO;
 			  
+			  ret = -EIO;
 			  if(addr == (long) &dummy->u_debugreg[7]) {
 				  data &= ~DR_CONTROL_RESERVED;
 				  for(i=0; i<4; i++)
 					  if ((0x5f54 >> ((data >> (16 + 4*i)) & 0xf)) & 1)
-						  return -EIO;
+						  goto out;
 			  };
 
 			  addr -= (long) &dummy->u_debugreg;
 			  addr = addr >> 2;
 			  child->debugreg[addr] = data;
-			  return 0;
+			  ret = 0;
+			  goto out;
 		  };
-		  return -EIO;
+		  ret = -EIO;
+		  goto out;
 
 		case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
 		case PTRACE_CONT: { /* restart after signal. */
 			long tmp;
 
+			ret = -EIO;
 			if ((unsigned long) data > NSIG)
-				return -EIO;
+				goto out;
 			if (request == PTRACE_SYSCALL)
 				child->flags |= PF_TRACESYS;
 			else
@@ -499,7 +515,8 @@
 	/* make sure the single step bit is not set. */
 			tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
 			put_stack_long(child, EFL_OFFSET,tmp);
-			return 0;
+			ret = 0;
+			goto out;
 		}
 
 /*
@@ -510,35 +527,39 @@
 		case PTRACE_KILL: {
 			long tmp;
 
+			ret = 0;
 			if (child->state == TASK_ZOMBIE)	/* already dead */
-				return 0;
+				goto out;
 			wake_up_process(child);
 			child->exit_code = SIGKILL;
 	/* make sure the single step bit is not set. */
 			tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
 			put_stack_long(child, EFL_OFFSET, tmp);
-			return 0;
+			goto out;
 		}
 
 		case PTRACE_SINGLESTEP: {  /* set the trap flag. */
 			long tmp;
 
+			ret = -EIO;
 			if ((unsigned long) data > NSIG)
-				return -EIO;
+				goto out;
 			child->flags &= ~PF_TRACESYS;
 			tmp = get_stack_long(child, EFL_OFFSET) | TRAP_FLAG;
 			put_stack_long(child, EFL_OFFSET, tmp);
 			wake_up_process(child);
 			child->exit_code = data;
 	/* give it a chance to run. */
-			return 0;
+			ret = 0;
+			goto out;
 		}
 
 		case PTRACE_DETACH: { /* detach a process that was attached. */
 			long tmp;
 
+			ret = -EIO;
 			if ((unsigned long) data > NSIG)
-				return -EIO;
+				goto out;
 			child->flags &= ~(PF_PTRACED|PF_TRACESYS);
 			wake_up_process(child);
 			child->exit_code = data;
@@ -548,19 +569,25 @@
 			/* make sure the single step bit is not set. */
 			tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
 			put_stack_long(child, EFL_OFFSET, tmp);
-			return 0;
+			ret = 0;
+			goto out;
 		}
 
 		default:
-			return -EIO;
+			ret = -EIO;
+			goto out;
 	}
+out:
+	unlock_kernel();
+	return ret;
 }
 
 asmlinkage void syscall_trace(void)
 {
+	lock_kernel();
 	if ((current->flags & (PF_PTRACED|PF_TRACESYS))
 			!= (PF_PTRACED|PF_TRACESYS))
-		return;
+		goto out;
 	current->exit_code = SIGTRAP;
 	current->state = TASK_STOPPED;
 	notify_parent(current);
@@ -573,4 +600,6 @@
 	if (current->exit_code)
 		current->signal |= (1 << (current->exit_code - 1));
 	current->exit_code = 0;
+out:
+	unlock_kernel();
 }
diff -u --recursive --new-file v2.1.22/linux/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c
--- v2.1.22/linux/arch/i386/kernel/signal.c	Thu Jan  2 15:55:15 1997
+++ linux/arch/i386/kernel/signal.c	Sun Jan 26 12:07:04 1997
@@ -8,6 +8,8 @@
 
 #include <linux/sched.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/errno.h>
@@ -30,8 +32,11 @@
 asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, unsigned long set)
 {
 	unsigned long mask;
-	struct pt_regs * regs = (struct pt_regs *) &restart;
+	struct pt_regs * regs;
+	int res = -EINTR;
 
+	lock_kernel();
+	regs = (struct pt_regs *) &restart;
 	mask = current->blocked;
 	current->blocked = set & _BLOCKABLE;
 	regs->eax = -EINTR;
@@ -39,8 +44,11 @@
 		current->state = TASK_INTERRUPTIBLE;
 		schedule();
 		if (do_signal(mask,regs))
-			return -EINTR;
+			goto out;
 	}
+out:
+	unlock_kernel();
+	return res;
 }
 
 static inline void restore_i387_hard(struct _fpstate *buf)
@@ -100,7 +108,9 @@
 __asm__("mov %w0,%%" #seg: :"r" (tmp)); }
 	struct sigcontext * context;
 	struct pt_regs * regs;
+	int res;
 
+	lock_kernel();
 	regs = (struct pt_regs *) &__unused;
 	context = (struct sigcontext *) regs->esp;
 	if (verify_area(VERIFY_READ, context, sizeof(*context)))
@@ -126,7 +136,9 @@
 			goto badframe;
 		restore_i387(buf);
 	}
-	return context->eax;
+	res = context->eax;
+	unlock_kernel();
+	return res;
 badframe:
 	do_exit(SIGSEGV);
 }
@@ -295,10 +307,13 @@
  */
 asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
 {
-	unsigned long mask = ~current->blocked;
+	unsigned long mask;
 	unsigned long signr;
 	struct sigaction * sa;
+	int res;
 
+	lock_kernel();
+	mask = ~current->blocked;
 	while ((signr = current->signal & mask)) {
 		/*
 		 *	This stops gcc flipping out. Otherwise the assembler
@@ -371,7 +386,8 @@
 			}
 		}
 		handle_signal(signr, sa, oldmask, regs);
-		return 1;
+		res = 1;
+		goto out;
 	}
 
 	/* Did we come from a system call? */
@@ -384,5 +400,8 @@
 			regs->eip -= 2;
 		}
 	}
-	return 0;
+	res = 0;
+out:
+	unlock_kernel();
+	return res;
 }
diff -u --recursive --new-file v2.1.22/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c
--- v2.1.22/linux/arch/i386/kernel/smp.c	Wed Dec 18 15:58:34 1996
+++ linux/arch/i386/kernel/smp.c	Sun Jan 26 12:07:04 1997
@@ -21,6 +21,7 @@
  *		Erich Boleyn	:	MP v1.4 and additional changes.
  *	Matthias Sattler	:	Changes for 2.1 kernel map.
  *	Michel Lespinasse	:	Changes for 2.1 kernel map.
+ *	Michael Chastain	:	Change trampoline.S to gnu as.
  *
  */
 
@@ -34,6 +35,8 @@
 #include <linux/mc146818rtc.h>
 #include <asm/i82489.h>
 #include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/interrupt.h>
 #include <asm/pgtable.h>
 #include <asm/bitops.h>
 #include <asm/pgtable.h>
@@ -140,7 +143,7 @@
 #endif
 
 volatile unsigned long  smp_proc_in_lock[NR_CPUS] = {0,};/* for computing process time */
-volatile unsigned long smp_process_available=0;
+volatile int smp_process_available=0;
 
 /*#define SMP_DEBUG*/
 
@@ -506,9 +509,8 @@
  *	Trampoline 80x86 program as an array.
  */
 
-static unsigned char trampoline_data[]={ 
-#include  "trampoline.hex"
-};
+extern unsigned char trampoline_data [];
+extern unsigned char trampoline_end  [];
 
 /*
  *	Currently trivial. Write the real->protected mode
@@ -518,7 +520,7 @@
  
 static void install_trampoline(unsigned char *mp)
 {
-	memcpy(mp,trampoline_data,sizeof(trampoline_data));
+	memcpy(mp, trampoline_data, trampoline_end - trampoline_data);
 }
 
 /*
@@ -634,19 +636,25 @@
 	 *	Until we are ready for SMP scheduling
 	 */
 	load_ldt(0);
-/*	printk("Testing faulting...\n");
-	*(long *)0=1;		 OOPS... */
 	local_flush_tlb();
 	
-	while(!smp_commenced);
+	while(!task[cpuid] || current_set[cpuid] != task[cpuid])
+		barrier();
+
+	if (cpu_number_map[cpuid] == -1)
+		while(1);
+
+	local_flush_tlb();
+	load_TR(cpu_number_map[cpuid]);
+
+	while(!smp_commenced)
+		barrier();
 	
 	local_flush_tlb();
 	
-	if (cpu_number_map[cpuid] == -1)
-		while(1);
 	SMP_PRINTK(("Commenced..\n"));
 	local_flush_tlb();
-	load_TR(cpu_number_map[cpuid]);
+	sti();
 }
 
 /*
@@ -1253,27 +1261,20 @@
 
 void smp_reschedule_irq(int cpl, struct pt_regs *regs)
 {
-/*#define DEBUGGING_SMP_RESCHED*/
-#ifdef DEBUGGING_SMP_RESCHED
-	static int ct=0;
-	if(ct==0)
-	{
-		printk("Beginning scheduling on CPU#%d\n",smp_processor_id());
-		udelay(1000000);
-		ct=1;
-	}
-#endif	
+	lock_kernel();
+	intr_count++;
 	if(smp_processor_id()!=active_kernel_processor)
 		panic("SMP Reschedule on CPU #%d, but #%d is active.\n",
 			smp_processor_id(), active_kernel_processor);
 
 	need_resched=1;
 
-	/*
-	 *	Clear the IPI
-	 */
+	/* Clear the IPI */
 	apic_read(APIC_SPIV);		/* Dummy read */
 	apic_write(APIC_EOI, 0);	/* Docs say use 0 for future compatibility */
+
+	intr_count--;
+	unlock_kernel();
 }	
 
 /*
diff -u --recursive --new-file v2.1.22/linux/arch/i386/kernel/sys_i386.c linux/arch/i386/kernel/sys_i386.c
--- v2.1.22/linux/arch/i386/kernel/sys_i386.c	Thu Jan  2 15:55:15 1997
+++ linux/arch/i386/kernel/sys_i386.c	Sun Jan 26 12:07:04 1997
@@ -9,6 +9,8 @@
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 #include <linux/sem.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
@@ -28,11 +30,13 @@
 	int fd[2];
 	int error;
 
+	lock_kernel();
 	error = do_pipe(fd);
 	if (!error) {
 		if (copy_to_user(fildes, fd, 2*sizeof(int)))
 			error = -EFAULT;
 	}
+	unlock_kernel();
 	return error;
 }
 
@@ -53,18 +57,22 @@
 
 asmlinkage int old_mmap(struct mmap_arg_struct *arg)
 {
-	int error;
+	int error = -EFAULT;
 	struct file * file = NULL;
 	struct mmap_arg_struct a;
 
+	lock_kernel();
 	if (copy_from_user(&a, arg, sizeof(a)))
-			return -EFAULT; 
+			goto out;
 	if (!(a.flags & MAP_ANONYMOUS)) {
+		error = -EBADF;
 		if (a.fd >= NR_OPEN || !(file = current->files->fd[a.fd]))
-			return -EBADF;
+			goto out;
 	}
 	a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 	error = do_mmap(file, a.addr, a.len, a.prot, a.flags, a.offset);
+out:
+	unlock_kernel();
 	return error;
 }
 
@@ -79,10 +87,15 @@
 asmlinkage int old_select(struct sel_arg_struct *arg)
 {
 	struct sel_arg_struct a;
+	int ret = -EFAULT;
 
+	lock_kernel();
 	if (copy_from_user(&a, arg, sizeof(a)))
-		return -EFAULT;
-	return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp);
+		goto out;
+	ret = sys_select(a.n, a.inp, a.outp, a.exp, a.tvp);
+out:
+	unlock_kernel();
+	return ret;
 }
 
 /*
@@ -92,53 +105,68 @@
  */
 asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth)
 {
-	int version;
+	int version, ret;
 
+	lock_kernel();
 	version = call >> 16; /* hack for backward compatibility */
 	call &= 0xffff;
 
 	if (call <= SEMCTL)
 		switch (call) {
 		case SEMOP:
-			return sys_semop (first, (struct sembuf *)ptr, second);
+			ret = sys_semop (first, (struct sembuf *)ptr, second);
+			goto out;
 		case SEMGET:
-			return sys_semget (first, second, third);
+			ret = sys_semget (first, second, third);
+			goto out;
 		case SEMCTL: {
 			union semun fourth;
+			ret = -EINVAL;
 			if (!ptr)
-				return -EINVAL;
+				goto out;
+			ret = -EFAULT;
 			if (get_user(fourth.__pad, (void **) ptr))
-				return -EFAULT;	
-			return sys_semctl (first, second, third, fourth);
+				goto out;	
+			ret = sys_semctl (first, second, third, fourth);
+			goto out;
 			}
 		default:
-			return -EINVAL;
+			ret = -EINVAL;
+			goto out;
 		}
 	if (call <= MSGCTL) 
 		switch (call) {
 		case MSGSND:
-			return sys_msgsnd (first, (struct msgbuf *) ptr, 
-					   second, third);
+			ret = sys_msgsnd (first, (struct msgbuf *) ptr, 
+					  second, third);
+			goto out;
 		case MSGRCV:
 			switch (version) {
 			case 0: {
 				struct ipc_kludge tmp;
+				ret = -EINVAL;
 				if (!ptr)
-					return -EINVAL;
+					goto out;
+				ret = -EFAULT;
 				if (copy_from_user(&tmp,(struct ipc_kludge *) ptr, 
 								   sizeof (tmp)))
-					return -EFAULT; 	
-				return sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third);
+					goto out; 	
+				ret = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third);
+				goto out;
 				}
 			case 1: default:
-				return sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third);
+				ret = sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third);
+				goto out;
 			}
 		case MSGGET:
-			return sys_msgget ((key_t) first, second);
+			ret = sys_msgget ((key_t) first, second);
+			goto out;
 		case MSGCTL:
-			return sys_msgctl (first, second, (struct msqid_ds *) ptr);
+			ret = sys_msgctl (first, second, (struct msqid_ds *) ptr);
+			goto out;
 		default:
-			return -EINVAL;
+			ret = -EINVAL;
+			goto out;
 		}
 	if (call <= SHMCTL) 
 		switch (call) {
@@ -146,25 +174,35 @@
 			switch (version) {
 			case 0: default: {
 				ulong raddr;
-				int err;
-				err = sys_shmat (first, (char *) ptr, second, &raddr);
-				if (err)
-					return err;
-				return put_user (raddr, (ulong *) third);
+				ret = sys_shmat (first, (char *) ptr, second, &raddr);
+				if (ret)
+					goto out;
+				ret = put_user (raddr, (ulong *) third);
+				goto out;
 			}
 			case 1:	/* iBCS2 emulator entry point */
+				ret = -EINVAL;
 				if (get_fs() != get_ds())
-					return -EINVAL;
-				return sys_shmat (first, (char *) ptr, second, (ulong *) third);
+					goto out;
+				ret = sys_shmat (first, (char *) ptr, second, (ulong *) third);
+				goto out;
 			}
 		case SHMDT: 
-			return sys_shmdt ((char *)ptr);
+			ret = sys_shmdt ((char *)ptr);
+			goto out;
 		case SHMGET:
-			return sys_shmget (first, second, third);
+			ret = sys_shmget (first, second, third);
+			goto out;
 		case SHMCTL:
-			return sys_shmctl (first, second, (struct shmid_ds *) ptr);
+			ret = sys_shmctl (first, second, (struct shmid_ds *) ptr);
+			goto out;
 		default:
-			return -EINVAL;
+			ret = -EINVAL;
+			goto out;
 		}
-	return -EINVAL;
+	else
+		ret = -EINVAL;
+out:
+	unlock_kernel();
+	return ret;
 }
diff -u --recursive --new-file v2.1.22/linux/arch/i386/kernel/trampoline.S linux/arch/i386/kernel/trampoline.S
--- v2.1.22/linux/arch/i386/kernel/trampoline.S	Thu Dec 12 19:36:58 1996
+++ linux/arch/i386/kernel/trampoline.S	Sun Jan 26 12:07:04 1997
@@ -1,86 +1,107 @@
-!
-!	Trampoline.S	Derived from Setup.S by Linus Torvalds
-!
-!	Entry: CS:IP point to the start of our code, we are 
-!	in real mode with no stack, but the rest of the 
-!	trampoline page to make our stack and everything else
-!	is a mystery.
-!
-!	In fact we don't actually need a stack so we don't
-!	set one up.
-!
-!	We jump into the boot/compressed/head.S code. So you'd
-!	better be running a compressed kernel image or you
-!	won't get very far.
-!
-#define __ASSEMBLY__
+/*
+ *
+ *	Trampoline.S	Derived from Setup.S by Linus Torvalds
+ *
+ *	4 Jan 1997 Michael Chastain: changed to gnu as.
+ *
+ *	Entry: CS:IP point to the start of our code, we are 
+ *	in real mode with no stack, but the rest of the 
+ *	trampoline page to make our stack and everything else
+ *	is a mystery.
+ *
+ *	In fact we don't actually need a stack so we don't
+ *	set one up.
+ *
+ *	We jump into the boot/compressed/head.S code. So you'd
+ *	better be running a compressed kernel image or you
+ *	won't get very far.
+ *
+ *	On entry to trampoline_data, the processor is in real mode
+ *	with 16-bit addressing and 16-bit data.  CS has some value
+ *	and IP is zero.  Thus, data addresses need to be absolute
+ *	(no relocation) and are taken with regard to r_base.
+ *
+ *	On the transition to protected mode, this page appears at
+ *	address 8192, so protected mode addresses are with regard
+ *	to p_base.
+ *
+ *	If you work on this file, check the object module with objdump
+ *	--full-contents --reloc to make sure there are no relocation
+ *	entries.
+ */
+
+#include <linux/linkage.h>
 #include <asm/segment.h>
 
-.text
-	extrn startup32
+.data
+
+.code16
+
+ENTRY(trampoline_data)
+r_base = .
+p_base = . - 8192
+
+	mov	%cs, %ax	# Code and data in the same place
+	mov	%ax, %ds
+
+	mov	%ax, %cx	# Pass stack info to the 32bit boot
+	shl	$4, %cx		# Segment -> Offset
+	add	$4096, %cx	# End of page is wanted
+
+	mov	$1, %bx		# Flag an SMP trampoline
+	cli			# We should be safe anyway
+
+	movl	$0xA5A5A5A5, trampoline_data - r_base
+				# write marker for master knows we're running
+
+	lidt	idt_48 - r_base	# load idt with 0, 0
+	lgdt	gdt_48 - r_base	# load gdt with whatever is appropriate
 
-entry start
-start:
-!	nop
-!	jmp start	! 	Test
-	mov ax,cs	!	Code and data in the same place
-	mov ds,ax	!
-	mov cx,ax	!	Pass stack info to the 32bit boot
-	add cx,cx
-	add cx,cx
-	add cx,cx
-	add cx,cx	!	Segment -> Offset
-	add cx, #4096   !	End of page is wanted
-	mov     bx,#1	!	Flag an SMP trampoline
-	cli		!	We should be safe anyway
-
-	lidt	idt_48	!	load idt with 0,0
-	lgdt	gdt_48	!	load gdt with whatever is appropriate
-
-	xor	ax,ax	
-	inc	ax	!	protected mode (PE) bit
-	lmsw	ax	!	Into protected mode
+	xor	%ax, %ax
+	inc	%ax		# protected mode (PE) bit
+	lmsw	%ax		# into protected mode
 	jmp	flush_instr
 flush_instr:
-	jmpi	8192+startup32,KERNEL_CS	!	Jump to the 32bit trampoline code
-!	jmpi	0x100000,KERNEL_CS		!	Jump into the 32bit startup
-!	.byte   0x66,0x67			!	32bit
-!	.byte	0xea,0x00,0x00,0x10,0x00,0x10,0x00	!jmpi	.0x100000,KERNEL_CS
+	ljmp	$KERNEL_CS, $0x00100000
+				# jump to startup_32
 
+idt_48:
+	.word	0			# idt limit = 0
+	.word	0, 0			# idt base = 0L
+
+gdt_48:
+	.word	0x0800			# gdt limit = 2048, 256 GDT entries
+	.word	gdt - p_base, 0x0	# gdt base = gdt (first SMP CPU)
+					# we load the others with first table
+					# saves rewriting gdt_48 for each
 gdt:
-	.word	0,0,0,0		! dummy
+	.word	0, 0, 0, 0	# dummy
 
-	.word	0,0,0,0		! unused
+	.word	0, 0, 0, 0	# unused
 
-!walken modif
-        .word   0xFFFF          ! 4Gb - (0x100000*0x1000 = 4Gb)
-        .word   0x0000          ! base address=0
-        .word   0x9A00          ! code read/exec
-        .word   0x00CF          ! granularity=4096, 386 (+5th nibble of limit)
-
-        .word   0xFFFF          ! 4Gb - (0x100000*0x1000 = 4Gb)
-        .word   0x0000          ! base address=0
-        .word   0x9200          ! data read/write
-        .word   0x00CF          ! granularity=4096, 386 (+5th nibble of limit)
-!walken modif
-
-!	.word	0x07FF		! 8Mb - limit=2047 (2048*4096=8Mb)
-!	.word	0x0000		! base address=0
-!	.word	0x9A00		! code read/exec
-!	.word	0x00C0		! granularity=4096, 386
-
-!	.word	0x07FF		! 8Mb - limit=2047 (2048*4096=8Mb)
-!	.word	0x0000		! base address=0
-!	.word	0x9200		! data read/write
-!	.word	0x00C0		! granularity=4096, 386
+# walken modif
 
-idt_48:
-	.word	0			! idt limit=0
-	.word	0,0			! idt base=0L
+	.word	0xFFFF		# 4 Gb - (0x100000*0x1000 = 4Gb)
+	.word	0x0000		# base address = 0
+	.word	0x9A00		# code read / exec
+	.word	0x00CF		# granularity = 4096, 386 (+5th nibble of limit)
 
-gdt_48:
-	.word	0x800		! gdt limit=2048, 256 GDT entries
-	.word	8192+gdt,0x0	! gdt base = 8192+gdt (first SMP CPU)
-				! we load the others with the first table
-				! saves rewriting gdt_48 for each
+	.word	0xFFFF		# 4 Gb - (0x100000*0x1000 = 4Gb)
+	.word	0x0000		# base address = 0
+	.word	0x9200		# data read / write
+	.word	0x00CF		# granularity = 4096, 386 (+5th nibble of limit)
+
+# walken modif
+
+#	.word	0x07FF		# 8 Mb - limit = 2047 (2048 * 4096 = 8 Mb)
+#	.word	0x0000		# base address = 0
+#	.word	0x9A00		# code read / exec
+#	.word	0x00C0		# granularity = 4096, 386
+
+#	.word	0x07FF		# 8 Mb - limit = 2047 (2048 * 4096 = 8 Mb)
+#	.word	0x0000		# base address = 0
+#	.word	0x9200		# data read / write
+#	.word	0x00C0		# granularity = 4096, 386
 
+.globl SYMBOL_NAME(trampoline_end)
+SYMBOL_NAME_LABEL(trampoline_end)
diff -u --recursive --new-file v2.1.22/linux/arch/i386/kernel/trampoline32.S linux/arch/i386/kernel/trampoline32.S
--- v2.1.22/linux/arch/i386/kernel/trampoline32.S	Mon Oct 30 10:30:17 1995
+++ linux/arch/i386/kernel/trampoline32.S	Thu Jan  1 02:00:00 1970
@@ -1,20 +0,0 @@
-!
-!	32bit side of the trampoline code
-!
-#define __ASSEMBLY__
-#include <asm/segment.h>
-!
-!
-!	Anything but a relative address here will be wrong by 8K...
-!
-	.globl startup32
-.text
-startup32:
-!	Run the kernel
-	mov	eax,#KERNEL_DS
-	mov	ds,ax
-	mov	eax,#0xA5A5A5A5
-	mov	[8192],eax
-	jmpi	0x100000,KERNEL_CS
-l1:
-	.byte	0xEA,0x00,0x00,0x10,0x00,0x10,0x00
diff -u --recursive --new-file v2.1.22/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c
--- v2.1.22/linux/arch/i386/kernel/traps.c	Thu Dec 12 19:36:58 1996
+++ linux/arch/i386/kernel/traps.c	Sun Jan 26 12:07:04 1997
@@ -20,6 +20,8 @@
 #include <linux/config.h>
 #include <linux/timer.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -38,24 +40,29 @@
 #define DO_ERROR(trapnr, signr, str, name, tsk) \
 asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
 { \
+	lock_kernel(); \
 	tsk->tss.error_code = error_code; \
 	tsk->tss.trap_no = trapnr; \
 	force_sig(signr, tsk); \
 	die_if_kernel(str,regs,error_code); \
+	unlock_kernel(); \
 }
 
 #define DO_VM86_ERROR(trapnr, signr, str, name, tsk) \
 asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
 { \
+	lock_kernel(); \
 	if (regs->eflags & VM_MASK) { \
 		if (!handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, trapnr)) \
-			return; \
+			goto out; \
 		/* else fall through */ \
 	} \
 	tsk->tss.error_code = error_code; \
 	tsk->tss.trap_no = trapnr; \
 	force_sig(signr, tsk); \
 	die_if_kernel(str,regs,error_code); \
+out: \
+	unlock_kernel(); \
 }
 
 #define get_seg_byte(seg,addr) ({ \
@@ -194,18 +201,22 @@
 
 asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
 {
+	lock_kernel();
 	if (regs->eflags & VM_MASK) {
 		handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code);
-		return;
+		goto out;
 	}
 	die_if_kernel("general protection",regs,error_code);
 	current->tss.error_code = error_code;
 	current->tss.trap_no = 13;
 	force_sig(SIGSEGV, current);	
+out:
+	unlock_kernel();
 }
 
 asmlinkage void do_nmi(struct pt_regs * regs, long error_code)
 {
+	lock_kernel();
 #ifdef CONFIG_SMP_NMI_INVAL
 	smp_flush_tlb_rcv();
 #else
@@ -215,13 +226,15 @@
 	printk("power saving mode enabled.\n");
 #endif	
 #endif
+	unlock_kernel();
 }
 
 asmlinkage void do_debug(struct pt_regs * regs, long error_code)
 {
+	lock_kernel();
 	if (regs->eflags & VM_MASK) {
 		handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1);
-		return;
+		goto out;
 	}
 	force_sig(SIGTRAP, current);
 	current->tss.trap_no = 1;
@@ -231,9 +244,11 @@
 		__asm__("movl %0,%%db7"
 			: /* no output */
 			: "r" (0));
-		return;
+		goto out;
 	}
 	die_if_kernel("debug",regs,error_code);
+out:
+	unlock_kernel();
 }
 
 /*
@@ -245,6 +260,7 @@
 {
 	struct task_struct * task;
 
+	lock_kernel();
 	clts();
 #ifdef __SMP__
 	task = current;
@@ -253,7 +269,7 @@
 	last_task_used_math = NULL;
 	if (!task) {
 		__asm__("fnclex");
-		return;
+		goto out;
 	}
 #endif
 	/*
@@ -266,18 +282,26 @@
 	force_sig(SIGFPE, task);
 	task->tss.trap_no = 16;
 	task->tss.error_code = 0;
+#ifndef __SMP__
+out:
+#endif
+	unlock_kernel();
 }
 
 asmlinkage void do_coprocessor_error(struct pt_regs * regs, long error_code)
 {
+	lock_kernel();
 	ignore_irq13 = 1;
 	math_error();
+	unlock_kernel();
 }
 
 asmlinkage void do_spurious_interrupt_bug(struct pt_regs * regs,
 					  long error_code)
 {
+	lock_kernel();
 	printk("Ignoring P6 Local APIC Spurious Interrupt Bug...\n");
+	unlock_kernel();
 }
 
 /*
@@ -289,6 +313,7 @@
  */
 asmlinkage void math_state_restore(void)
 {
+	lock_kernel();
 	__asm__ __volatile__("clts");		/* Allow maths ops (or we recurse) */
 
 /*
@@ -301,7 +326,7 @@
  */
 #ifndef __SMP__
 	if (last_task_used_math == current)
-		return;
+		goto out;
 	if (last_task_used_math)
 		__asm__("fnsave %0":"=m" (last_task_used_math->tss.i387));
 	else
@@ -320,16 +345,22 @@
 		current->used_math = 1;
 	}
 	current->flags|=PF_USEDFPU;		/* So we fnsave on switch_to() */
+#ifndef __SMP__
+out:
+#endif
+	unlock_kernel();
 }
 
 #ifndef CONFIG_MATH_EMULATION
 
 asmlinkage void math_emulate(long arg)
 {
-  printk("math-emulation not enabled and no coprocessor found.\n");
-  printk("killing %s.\n",current->comm);
-  force_sig(SIGFPE,current);
-  schedule();
+	lock_kernel();
+	printk("math-emulation not enabled and no coprocessor found.\n");
+	printk("killing %s.\n",current->comm);
+	force_sig(SIGFPE,current);
+	schedule();
+	unlock_kernel();
 }
 
 #endif /* CONFIG_MATH_EMULATION */
diff -u --recursive --new-file v2.1.22/linux/arch/i386/kernel/vm86.c linux/arch/i386/kernel/vm86.c
--- v2.1.22/linux/arch/i386/kernel/vm86.c	Thu Dec 12 19:36:58 1996
+++ linux/arch/i386/kernel/vm86.c	Sun Jan 26 12:07:05 1997
@@ -10,6 +10,8 @@
 #include <linux/string.h>
 #include <linux/ptrace.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -62,8 +64,10 @@
 
 asmlinkage struct pt_regs * save_v86_state(struct kernel_vm86_regs * regs)
 {
+	struct pt_regs *ret;
 	unsigned long tmp;
 
+	lock_kernel();
 	if (!current->tss.vm86_info) {
 		printk("no vm86_info: BAD\n");
 		do_exit(SIGSEGV);
@@ -79,7 +83,9 @@
 	}
 	current->tss.esp0 = current->saved_kernel_stack;
 	current->saved_kernel_stack = 0;
-	return KVM86->regs32;
+	ret = KVM86->regs32;
+	unlock_kernel();
+	return ret;
 }
 
 static void mark_screen_rdonly(struct task_struct * tsk)
@@ -126,21 +132,27 @@
 					 * This remains on the stack until we
 					 * return to 32 bit user space.
 					 */
-	struct task_struct *tsk = current;
-	int tmp;
+	struct task_struct *tsk;
+	int tmp, ret = -EPERM;
 
+	lock_kernel();
+	tsk = current;
 	if (tsk->saved_kernel_stack)
-		return -EPERM;
+		goto out;
 	tmp  = copy_from_user(&info, v86, VM86_REGS_SIZE1);
 	tmp += copy_from_user(&info.regs.VM86_REGS_PART2, &v86->regs.VM86_REGS_PART2,
 		(long)&info.vm86plus - (long)&info.regs.VM86_REGS_PART2);
+	ret = -EFAULT;
 	if (tmp)
-		return -EFAULT;
+		goto out;
 	memset(&info.vm86plus, 0, (int)&info.regs32 - (int)&info.vm86plus);
 	info.regs32 = (struct pt_regs *) &v86;
 	tsk->tss.vm86_info = v86;
 	do_sys_vm86(&info, tsk);
-	return 0;	/* we never return here */
+	ret = 0;	/* we never return here */
+out:
+	unlock_kernel();
+	return ret;
 }
 
 
@@ -151,37 +163,46 @@
 					 * This remains on the stack until we
 					 * return to 32 bit user space.
 					 */
-	struct task_struct *tsk = current;
-	int tmp;
+	struct task_struct *tsk;
+	int tmp, ret;
 
+	lock_kernel();
+	tsk = current;
 	switch (subfunction) {
 		case VM86_REQUEST_IRQ:
 		case VM86_FREE_IRQ:
 		case VM86_GET_IRQ_BITS:
 		case VM86_GET_AND_RESET_IRQ:
-			return do_vm86_irq_handling(subfunction,(int)v86);
+			ret = do_vm86_irq_handling(subfunction,(int)v86);
+			goto out;
 		case VM86_PLUS_INSTALL_CHECK:
 			/* NOTE: on old vm86 stuff this will return the error
 			   from verify_area(), because the subfunction is
 			   interpreted as (invalid) address to vm86_struct.
 			   So the installation check works.
 			 */
-			return 0;
+			ret = 0;
+			goto out;
 	}
 
 	/* we come here only for functions VM86_ENTER, VM86_ENTER_NO_BYPASS */
+	ret = -EPERM;
 	if (tsk->saved_kernel_stack)
-		return -EPERM;
+		goto out;
 	tmp  = copy_from_user(&info, v86, VM86_REGS_SIZE1);
 	tmp += copy_from_user(&info.regs.VM86_REGS_PART2, &v86->regs.VM86_REGS_PART2,
 		(long)&info.regs32 - (long)&info.regs.VM86_REGS_PART2);
+	ret = -EFAULT;
 	if (tmp)
-		return -EFAULT;
+		goto out;
 	info.regs32 = (struct pt_regs *) &subfunction;
 	info.vm86plus.is_vm86pus = 1;
 	tsk->tss.vm86_info = (struct vm86_struct *)v86;
 	do_sys_vm86(&info, tsk);
-	return 0;	/* we never return here */
+	ret = 0;	/* we never return here */
+out:
+	unlock_kernel();
+	return ret;
 }
 
 
@@ -232,6 +253,7 @@
 	tsk->tss.screen_bitmap = info->screen_bitmap;
 	if (info->flags & VM86_SCREEN_BITMAP)
 		mark_screen_rdonly(tsk);
+	unlock_kernel();
 	__asm__ __volatile__(
 		"xorl %%eax,%%eax; mov %%ax,%%fs; mov %%ax,%%gs\n\t"
 		"movl %0,%%esp\n\t"
@@ -247,6 +269,7 @@
 
 	regs32 = save_v86_state(regs16);
 	regs32->eax = retval;
+	unlock_kernel();
 	__asm__ __volatile__("movl %0,%%esp\n\t"
 		"jmp ret_from_sys_call"
 		: : "r" (regs32), "b" (current));
@@ -408,20 +431,27 @@
 
 int handle_vm86_trap(struct kernel_vm86_regs * regs, long error_code, int trapno)
 {
+	int ret;
+
+	lock_kernel();
 	if (VMPI.is_vm86pus) {
 		if ( (trapno==3) || (trapno==1) )
 			return_to_32bit(regs, VM86_TRAP + (trapno << 8));
 		do_int(regs, trapno, (unsigned char *) (regs->ss << 4), SP(regs));
-		return 1;
+		ret = 1;
+		goto out;
 	}
+	ret = 0;
 	if (trapno !=1)
-		return 0; /* we let this handle by the calling routine */
+		goto out; /* we let this handle by the calling routine */
 	if (current->flags & PF_PTRACED)
 		current->blocked &= ~(1 << (SIGTRAP-1));
 	send_sig(SIGTRAP, current, 1);
 	current->tss.trap_no = trapno;
 	current->tss.error_code = error_code;
-	return 0;
+out:
+	unlock_kernel();
+	return ret;
 }
 
 
@@ -436,8 +466,9 @@
 #define VM86_FAULT_RETURN \
 	if (VMPI.force_return_for_pic  && (VEFLAGS & IF_MASK)) \
 		return_to_32bit(regs, VM86_PICRETURN); \
-	return;
+	goto out;
 	                                   
+	lock_kernel();
 	csp = (unsigned char *) (regs->cs << 4);
 	ssp = (unsigned char *) (regs->ss << 4);
 	sp = SP(regs);
@@ -501,7 +532,7 @@
 				return_to_32bit(regs, VM86_INTx + (intno << 8));
 		}
 		do_int(regs, intno, ssp, sp);
-		return;
+		goto out;
 	}
 
 	/* iret */
@@ -534,6 +565,8 @@
 	default:
 		return_to_32bit(regs, VM86_UNKNOWN);
 	}
+out:
+	unlock_kernel();
 }
 
 /* ---------------- vm86 special IRQ passing stuff ----------------- */
@@ -554,18 +587,19 @@
 	int irq_bit;
 	unsigned long flags;
 	
+	lock_kernel();
 	save_flags(flags);
 	cli();
 	irq_bit = 1 << intno;
-	if ((irqbits & irq_bit) || ! vm86_irqs[intno].tsk) {
-		restore_flags(flags);
-		return;
-	}
+	if ((irqbits & irq_bit) || ! vm86_irqs[intno].tsk)
+		goto out;
 	irqbits |= irq_bit;
 	if (vm86_irqs[intno].sig)
 		send_sig(vm86_irqs[intno].sig, vm86_irqs[intno].tsk, 1);
 	/* else user will poll for IRQs */
+out:
 	restore_flags(flags);
+	unlock_kernel();
 }
 
 static inline void free_vm86_irq(int irqnumber)
diff -u --recursive --new-file v2.1.22/linux/arch/i386/lib/Makefile linux/arch/i386/lib/Makefile
--- v2.1.22/linux/arch/i386/lib/Makefile	Mon Sep  9 16:09:16 1996
+++ linux/arch/i386/lib/Makefile	Sun Jan 26 12:07:05 1997
@@ -11,6 +11,6 @@
 endif
 
 L_TARGET = lib.a
-L_OBJS  = checksum.o semaphore.o
+L_OBJS  = checksum.o semaphore.o locks.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.22/linux/arch/i386/lib/locks.S linux/arch/i386/lib/locks.S
--- v2.1.22/linux/arch/i386/lib/locks.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/i386/lib/locks.S	Sun Jan 26 12:07:05 1997
@@ -0,0 +1,33 @@
+/* locks.S: Wheee... I'm coding Intel assembly...
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/linkage.h>
+
+	/* Caller does atomic increment on current->lock_depth,
+	 * if it was found to originally be zero then we get here,
+	 * %eax contains callers PC and %edx holds this cpu ID.
+	 */
+ENTRY(__lock_kernel)
+	pushl	%eax		! return address
+1:
+	lock
+	btsl	$0, SYMBOL_NAME(kernel_flag)
+	jnc	3f
+2:
+	btl	%dl, SYMBOL_NAME(smp_invalidate_needed)
+	jnc	0f
+	lock
+	btrl	%dl, SYMBOL_NAME(smp_invalidate_needed)
+	jnc	0f
+	movl	%cr3, %eax
+	movl	%eax, %cr3
+0:
+	btl	$0, SYMBOL_NAME(kernel_flag)
+	jc	2b
+	jmp	1b
+
+3:
+	movb	%dl, SYMBOL_NAME(active_kernel_processor)
+	ret
diff -u --recursive --new-file v2.1.22/linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c
--- v2.1.22/linux/arch/i386/mm/fault.c	Wed Dec 18 15:58:34 1996
+++ linux/arch/i386/mm/fault.c	Sun Jan 26 12:07:05 1997
@@ -14,6 +14,8 @@
 #include <linux/ptrace.h>
 #include <linux/mman.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -96,6 +98,8 @@
 	unsigned long fixup;
 	int write;
 
+	lock_kernel();
+
 	/* get the address */
 	__asm__("movl %%cr2,%0":"=r" (address));
 	down(&mm->mmap_sem);
@@ -154,7 +158,7 @@
 		if (bit < 32)
 			tsk->tss.screen_bitmap |= 1 << bit;
 	}
-	return;
+	goto out;
 
 /*
  * Something tried to access memory that isn't in our memory map..
@@ -167,7 +171,7 @@
 	if ((fixup = search_exception_table(regs->eip)) != 0) {
 		printk(KERN_DEBUG "Exception at [<%lx>] (%lx)\n", regs->eip, fixup);
 		regs->eip = fixup;
-		return;
+		goto out;
 	}
 
 	if (error_code & 4) {
@@ -175,7 +179,7 @@
 		tsk->tss.error_code = error_code;
 		tsk->tss.trap_no = 14;
 		force_sig(SIGSEGV, tsk);
-		return;
+		goto out;
 	}
 /*
  * Oops. The kernel tried to access some bad page. We'll have to
@@ -188,7 +192,7 @@
 		pg0[0] = pte_val(mk_pte(0, PAGE_SHARED));
 		flush_tlb();
 		printk("This processor honours the WP bit even when in supervisor mode. Good.\n");
-		return;
+		goto out;
 	}
 	if (address < PAGE_SIZE) {
 		printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
@@ -209,4 +213,6 @@
 	}
 	die_if_kernel("Oops", regs, error_code);
 	do_exit(SIGKILL);
+out:
+	unlock_kernel();
 }
diff -u --recursive --new-file v2.1.22/linux/arch/i386/mm/init.c linux/arch/i386/mm/init.c
--- v2.1.22/linux/arch/i386/mm/init.c	Sun Dec 22 16:37:20 1996
+++ linux/arch/i386/mm/init.c	Sun Jan 26 12:07:05 1997
@@ -289,6 +289,11 @@
 	return;
 }
 
+void free_initmem(void)
+{
+	/* To be written */
+}
+
 void si_meminfo(struct sysinfo *val)
 {
 	int i;
diff -u --recursive --new-file v2.1.22/linux/arch/m68k/kernel/m68k_ksyms.c linux/arch/m68k/kernel/m68k_ksyms.c
--- v2.1.22/linux/arch/m68k/kernel/m68k_ksyms.c	Wed Jan 15 19:45:40 1997
+++ linux/arch/m68k/kernel/m68k_ksyms.c	Sun Jan 26 12:07:05 1997
@@ -20,32 +20,32 @@
 
 /* platform dependent support */
 
-EXPORT_SYMBOLS(memcmp);
-EXPORT_SYMBOLS(m68k_machtype);
-EXPORT_SYMBOLS(m68k_cputype);
-EXPORT_SYMBOLS(m68k_is040or060);
-EXPORT_SYMBOLS(cache_push);
-EXPORT_SYMBOLS(cache_push_v);
-EXPORT_SYMBOLS(cache_clear);
-EXPORT_SYMBOLS(mm_vtop);
-EXPORT_SYMBOLS(mm_ptov);
-EXPORT_SYMBOLS(mm_end_of_chunk);
-EXPORT_SYMBOLS(m68k_debug_device);
-EXPORT_SYMBOLS(request_irq);
-EXPORT_SYMBOLS(free_irq);
-EXPORT_SYMBOLS(dump_fpu);
-EXPORT_SYMBOLS(dump_thread);
-EXPORT_SYMBOLS(strnlen);
-EXPORT_SYMBOLS(strrchr);
-EXPORT_SYMBOLS(strstr);
+EXPORT_SYMBOL(memcmp);
+EXPORT_SYMBOL(m68k_machtype);
+EXPORT_SYMBOL(m68k_cputype);
+EXPORT_SYMBOL(m68k_is040or060);
+EXPORT_SYMBOL(cache_push);
+EXPORT_SYMBOL(cache_push_v);
+EXPORT_SYMBOL(cache_clear);
+EXPORT_SYMBOL(mm_vtop);
+EXPORT_SYMBOL(mm_ptov);
+EXPORT_SYMBOL(mm_end_of_chunk);
+EXPORT_SYMBOL(m68k_debug_device);
+EXPORT_SYMBOL(request_irq);
+EXPORT_SYMBOL(free_irq);
+EXPORT_SYMBOL(dump_fpu);
+EXPORT_SYMBOL(dump_thread);
+EXPORT_SYMBOL(strnlen);
+EXPORT_SYMBOL(strrchr);
+EXPORT_SYMBOL(strstr);
 
 /* The following are special because they're not called
    explicitly (the C compiler generates them).  Fortunately,
    their interface isn't gonna change any time soon now, so
    it's OK to leave it out of version control.  */
-EXPORT_SYMBOLS_NOVERS(__ashrdi3);
-EXPORT_SYMBOLS_NOVERS(memcpy);
-EXPORT_SYMBOLS_NOVERS(memset);
+EXPORT_SYMBOL_NOVERS(__ashrdi3);
+EXPORT_SYMBOL_NOVERS(memcpy);
+EXPORT_SYMBOL_NOVERS(memset);
 
-EXPORT_SYMBOLS_NOVERS(__down_failed);
-EXPORT_SYMBOLS_NOVERS(__up_wakeup);
+EXPORT_SYMBOL_NOVERS(__down_failed);
+EXPORT_SYMBOL_NOVERS(__up_wakeup);
diff -u --recursive --new-file v2.1.22/linux/arch/m68k/kernel/process.c linux/arch/m68k/kernel/process.c
--- v2.1.22/linux/arch/m68k/kernel/process.c	Sun Dec 22 16:37:22 1996
+++ linux/arch/m68k/kernel/process.c	Sun Jan 26 12:07:05 1997
@@ -14,6 +14,8 @@
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 #include <linux/stddef.h>
 #include <linux/unistd.h>
 #include <linux/ptrace.h>
@@ -34,13 +36,20 @@
  */
 asmlinkage int sys_idle(void)
 {
+	int ret = -EPERM;
+
+	lock_kernel();
 	if (current->pid != 0)
-		return -EPERM;
+		goto out;
 
 	/* endless idle loop with no priority at all */
 	current->counter = -100;
 	for (;;)
 		schedule();
+	ret = 0;
+out:
+	unlock_kernel();
+	return ret;
 }
 
 void hard_reset_now(void)
@@ -86,20 +95,29 @@
 
 asmlinkage int m68k_fork(struct pt_regs *regs)
 {
-	return do_fork(SIGCHLD, rdusp(), regs);
+	int ret;
+
+	lock_kernel();
+	ret = do_fork(SIGCHLD, rdusp(), regs);
+	unlock_kernel();
+	return ret;
 }
 
 asmlinkage int m68k_clone(struct pt_regs *regs)
 {
 	unsigned long clone_flags;
 	unsigned long newsp;
+	int ret;
 
+	lock_kernel();
 	/* syscall2 puts clone_flags in d1 and usp in d2 */
 	clone_flags = regs->d1;
 	newsp = regs->d2;
 	if (!newsp)
 	  newsp  = rdusp();
-	return do_fork(clone_flags, newsp, regs);
+	ret = do_fork(clone_flags, newsp, regs);
+	unlock_kernel();
+	return ret;
 }
 
 void release_thread(struct task_struct *dead_task)
@@ -224,10 +242,13 @@
 	char * filename;
 	struct pt_regs *regs = (struct pt_regs *) &name;
 
+	lock_kernel();
 	error = getname(name, &filename);
 	if (error)
-		return error;
+		goto out;
 	error = do_execve(filename, argv, envp, regs);
 	putname(filename);
+out:
+	unlock_kernel();
 	return error;
 }
diff -u --recursive --new-file v2.1.22/linux/arch/m68k/kernel/ptrace.c linux/arch/m68k/kernel/ptrace.c
--- v2.1.22/linux/arch/m68k/kernel/ptrace.c	Fri Nov 22 18:28:17 1996
+++ linux/arch/m68k/kernel/ptrace.c	Sun Jan 26 12:07:05 1997
@@ -14,6 +14,8 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
@@ -322,25 +324,29 @@
 asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
 {
 	struct task_struct *child;
-	struct user * dummy;
-
-	dummy = NULL;
+	struct user * dummy = NULL;
+	int ret;
 
+	lock_kernel();
+	ret = -EPERM;
 	if (request == PTRACE_TRACEME) {
 		/* are we already being traced? */
 		if (current->flags & PF_PTRACED)
-			return -EPERM;
+			goto out;
 		/* set the ptrace bit in the process flags. */
 		current->flags |= PF_PTRACED;
-		return 0;
+		ret = 0;
+		goto out;
 	}
 	if (pid == 1)		/* you may not mess with init */
-		return -EPERM;
+		goto out;
+	ret = -ESRCH;
 	if (!(child = get_task(pid)))
-		return -ESRCH;
+		goto out;
+	ret = -EPERM;
 	if (request == PTRACE_ATTACH) {
 		if (child == current)
-			return -EPERM;
+			goto out;
 		if ((!child->dumpable ||
 		    (current->uid != child->euid) ||
 		    (current->uid != child->suid) ||
@@ -348,10 +354,10 @@
 	 	    (current->gid != child->egid) ||
 		    (current->gid != child->sgid) ||
 	 	    (current->gid != child->gid)) && !suser())
-			return -EPERM;
+			goto out;
 		/* the same process cannot be attached many times */
 		if (child->flags & PF_PTRACED)
-			return -EPERM;
+			goto out;
 		child->flags |= PF_PTRACED;
 		if (child->p_pptr != current) {
 			REMOVE_LINKS(child);
@@ -359,39 +365,42 @@
 			SET_LINKS(child);
 		}
 		send_sig(SIGSTOP, child, 1);
-		return 0;
+		ret = 0;
+		goto out;
 	}
+	ret = -ESRCH;
 	if (!(child->flags & PF_PTRACED))
-		return -ESRCH;
+		goto out;
 	if (child->state != TASK_STOPPED) {
 		if (request != PTRACE_KILL)
-			return -ESRCH;
+			goto out;
 	}
 	if (child->p_pptr != current)
-		return -ESRCH;
+		goto out;
 
 	switch (request) {
 	/* when I and D space are separate, these will need to be fixed. */
 		case PTRACE_PEEKTEXT: /* read word at location addr. */ 
 		case PTRACE_PEEKDATA: {
 			unsigned long tmp;
-			int res;
 
-			res = read_long(child, addr, &tmp);
-			if (res < 0)
-				return res;
-			return put_user(tmp, (unsigned long *) data);
+			ret = read_long(child, addr, &tmp);
+			if (ret >= 0)
+				ret = put_user(tmp, (unsigned long *) data);
+			goto out;
 		}
 
 	/* read the word at location addr in the USER area. */
 		case PTRACE_PEEKUSR: {
 			unsigned long tmp;
 			
+			ret = -EIO;
 			if ((addr & 3) || addr < 0 || addr >= sizeof(struct user))
-				return -EIO;
+				goto out;
 			
 			tmp = 0;  /* Default return condition */
 			addr = addr >> 2; /* temporary hack. */
+			ret = -EIO;
 			if (addr < 19) {
 				tmp = get_reg(child, addr);
 				if (addr == PT_SR)
@@ -400,23 +409,26 @@
 			else if (addr >= 21 && addr < 49)
 				tmp = child->tss.fp[addr - 21];
 			else
-				return -EIO;
-			return put_user(tmp,(unsigned long *) data);
+				goto out;
+			ret = put_user(tmp,(unsigned long *) data);
+			goto out;
 		}
 
       /* when I and D space are separate, this will have to be fixed. */
 		case PTRACE_POKETEXT: /* write the word at location addr. */
 		case PTRACE_POKEDATA:
-			return write_long(child,addr,data);
+			ret = write_long(child,addr,data);
+			goto out;
 
 		case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
+			ret = -EIO;
 			if ((addr & 3) || addr < 0 || addr >= sizeof(struct user))
-				return -EIO;
+				goto out;
 
 			addr = addr >> 2; /* temporary hack. */
 			    
 			if (addr == PT_ORIG_D0)
-				return -EIO;
+				goto out;
 			if (addr == PT_SR) {
 				data &= SR_MASK;
 				data <<= 16;
@@ -424,22 +436,24 @@
 			}
 			if (addr < 19) {
 				if (put_reg(child, addr, data))
-					return -EIO;
-				return 0;
+					goto out;
+				ret = 0;
+				goto out;
 			}
 			if (addr >= 21 && addr < 48)
 			{
 				child->tss.fp[addr - 21] = data;
-				return 0;
+				ret = 0;
 			}
-			return -EIO;
+			goto out;
 
 		case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
 		case PTRACE_CONT: { /* restart after signal. */
 			long tmp;
 
+			ret = -EIO;
 			if ((unsigned long) data >= NSIG)
-				return -EIO;
+				goto out;
 			if (request == PTRACE_SYSCALL)
 				child->flags |= PF_TRACESYS;
 			else
@@ -449,7 +463,8 @@
 			/* make sure the single step bit is not set. */
 			tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16);
 			put_reg(child, PT_SR, tmp);
-			return 0;
+			ret = 0;
+			goto out;
 		}
 
 /*
@@ -460,21 +475,23 @@
 		case PTRACE_KILL: {
 			long tmp;
 
+			ret = 0;
 			if (child->state == TASK_ZOMBIE) /* already dead */
-				return 0;
+				goto out;
 			wake_up_process(child);
 			child->exit_code = SIGKILL;
 	/* make sure the single step bit is not set. */
 			tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16);
 			put_reg(child, PT_SR, tmp);
-			return 0;
+			goto out;
 		}
 
 		case PTRACE_SINGLESTEP: {  /* set the trap flag. */
 			long tmp;
 
+			ret = -EIO;
 			if ((unsigned long) data >= NSIG)
-				return -EIO;
+				goto out;
 			child->flags &= ~PF_TRACESYS;
 			tmp = get_reg(child, PT_SR) | (TRACE_BITS << 16);
 			put_reg(child, PT_SR, tmp);
@@ -482,14 +499,16 @@
 			wake_up_process(child);
 			child->exit_code = data;
 	/* give it a chance to run. */
-			return 0;
+			ret = 0;
+			goto out;
 		}
 
 		case PTRACE_DETACH: { /* detach a process that was attached. */
 			long tmp;
 
+			ret = -EIO;
 			if ((unsigned long) data >= NSIG)
-				return -EIO;
+				goto out;
 			child->flags &= ~(PF_PTRACED|PF_TRACESYS);
 			wake_up_process(child);
 			child->exit_code = data;
@@ -499,19 +518,25 @@
 			/* make sure the single step bit is not set. */
 			tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16);
 			put_reg(child, PT_SR, tmp);
-			return 0;
+			ret = 0;
+			goto out;
 		}
 
 		default:
-			return -EIO;
+			ret = -EIO;
+			goto out;
 	}
+out:
+	unlock_kernel();
+	return ret;
 }
 
 asmlinkage void syscall_trace(void)
 {
+	lock_kernel();
 	if ((current->flags & (PF_PTRACED|PF_TRACESYS))
 			!= (PF_PTRACED|PF_TRACESYS))
-		return;
+		goto out;
 	current->exit_code = SIGTRAP;
 	current->state = TASK_STOPPED;
 	notify_parent(current);
@@ -524,5 +549,6 @@
 	if (current->exit_code)
 		current->signal |= (1 << (current->exit_code - 1));
 	current->exit_code = 0;
-	return;
+out:
+	unlock_kernel();
 }
diff -u --recursive --new-file v2.1.22/linux/arch/m68k/kernel/sys_m68k.c linux/arch/m68k/kernel/sys_m68k.c
--- v2.1.22/linux/arch/m68k/kernel/sys_m68k.c	Sun Dec 22 16:37:22 1996
+++ linux/arch/m68k/kernel/sys_m68k.c	Sun Jan 26 12:07:05 1997
@@ -9,6 +9,8 @@
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 #include <linux/sem.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
@@ -31,15 +33,18 @@
 	int fd[2];
 	int error;
 
+	lock_kernel();
 	error = verify_area(VERIFY_WRITE,fildes,8);
 	if (error)
-		return error;
+		goto out;
 	error = do_pipe(fd);
 	if (error)
-		return error;
+		goto out;
 	put_user(fd[0],0+fildes);
 	put_user(fd[1],1+fildes);
-	return 0;
+out:
+	unlock_kernel();
+	return error;
 }
 
 /*
@@ -64,16 +69,20 @@
 	struct file * file = NULL;
 	struct mmap_arg_struct a;
 
+	lock_kernel();
 	error = verify_area(VERIFY_READ, arg, sizeof(*arg));
 	if (error)
-		return error;
+		goto out;
 	copy_from_user(&a, arg, sizeof(a));
 	if (!(a.flags & MAP_ANONYMOUS)) {
+		error = -EBADF;
 		if (a.fd >= NR_OPEN || !(file = current->files->fd[a.fd]))
-			return -EBADF;
+			goto out;
 	}
 	a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 	error = do_mmap(file, a.addr, a.len, a.prot, a.flags, a.offset);
+out:
+	unlock_kernel();
 	return error;
 }
 
@@ -89,10 +98,15 @@
 asmlinkage int old_select(struct sel_arg_struct *arg)
 {
 	struct sel_arg_struct a;
+	int ret = -EFAULT;
 
+	lock_kernel();
 	if (copy_from_user(&a, arg, sizeof(a)))
-		return -EFAULT;
-	return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp);
+		goto out;
+	ret = sys_select(a.n, a.inp, a.outp, a.exp, a.tvp);
+out:
+	unlock_kernel();
+	return ret;
 }
 
 /*
@@ -102,7 +116,7 @@
  */
 asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth)
 {
-	int version;
+	int version, ret;
 
 	version = call >> 16; /* hack for backward compatibility */
 	call &= 0xffff;
@@ -110,46 +124,58 @@
 	if (call <= SEMCTL)
 		switch (call) {
 		case SEMOP:
-			return sys_semop (first, (struct sembuf *)ptr, second);
+			ret = sys_semop (first, (struct sembuf *)ptr, second);
+			goto out;
 		case SEMGET:
-			return sys_semget (first, second, third);
+			ret = sys_semget (first, second, third);
+			goto out;
 		case SEMCTL: {
 			union semun fourth;
-			int err;
+			ret = -EINVAL;
 			if (!ptr)
-				return -EINVAL;
-			if ((err = verify_area (VERIFY_READ, ptr, sizeof(long))))
-				return err;
+				goto out;
+			if ((ret = verify_area (VERIFY_READ, ptr, sizeof(long))))
+				goto out;
 			get_user(fourth.__pad, (void **)ptr);
-			return sys_semctl (first, second, third, fourth);
+			ret = sys_semctl (first, second, third, fourth);
+			goto out;
 			}
 		default:
-			return -EINVAL;
+			ret = -EINVAL;
+			goto out;
 		}
 	if (call <= MSGCTL) 
 		switch (call) {
 		case MSGSND:
-			return sys_msgsnd (first, (struct msgbuf *) ptr, 
-					   second, third);
+			ret = sys_msgsnd (first, (struct msgbuf *) ptr, 
+					  second, third);
+			goto out;
 		case MSGRCV:
 			switch (version) {
 			case 0: {
 				struct ipc_kludge tmp;
+				ret = -EINVAL;
 				if (!ptr)
-					return -EINVAL;
+					goto out;
+				ret = -EFAULT;
 				if (copy_from_user (&tmp, ptr, sizeof (tmp)))
-					return -EFAULT;
-				return sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third);
+					goto out;
+				ret = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third);
+				goto out;
 				}
 			case 1: default:
-				return sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third);
+				ret = sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third);
+				goto out;
 			}
 		case MSGGET:
-			return sys_msgget ((key_t) first, second);
+			ret = sys_msgget ((key_t) first, second);
+			goto out;
 		case MSGCTL:
-			return sys_msgctl (first, second, (struct msqid_ds *) ptr);
+			ret = sys_msgctl (first, second, (struct msqid_ds *) ptr);
+			goto out;
 		default:
-			return -EINVAL;
+			ret = -EINVAL;
+			goto out;
 		}
 	if (call <= SHMCTL) 
 		switch (call) {
@@ -157,30 +183,40 @@
 			switch (version) {
 			case 0: default: {
 				ulong raddr;
-				int err;
-				if ((err = verify_area(VERIFY_WRITE, (ulong*) third, sizeof(ulong))))
-					return err;
-				err = sys_shmat (first, (char *) ptr, second, &raddr);
-				if (err)
-					return err;
+				if ((ret = verify_area(VERIFY_WRITE, (ulong*) third, sizeof(ulong))))
+					goto out;
+				ret = sys_shmat (first, (char *) ptr, second, &raddr);
+				if (ret)
+					goto out;
 				put_user (raddr, (ulong *) third);
-				return 0;
+				ret = 0;
+				goto out;
 				}
 			case 1:	/* iBCS2 emulator entry point */
+				ret = -EINVAL;
 				if (get_fs() != get_ds())
-					return -EINVAL;
-				return sys_shmat (first, (char *) ptr, second, (ulong *) third);
+					goto out;
+				ret = sys_shmat (first, (char *) ptr, second, (ulong *) third);
+				goto out;
 			}
 		case SHMDT: 
-			return sys_shmdt ((char *)ptr);
+			ret = sys_shmdt ((char *)ptr);
+			goto out;
 		case SHMGET:
-			return sys_shmget (first, second, third);
+			ret = sys_shmget (first, second, third);
+			goto out;
 		case SHMCTL:
-			return sys_shmctl (first, second, (struct shmid_ds *) ptr);
+			ret = sys_shmctl (first, second, (struct shmid_ds *) ptr);
+			goto out;
 		default:
-			return -EINVAL;
+			ret = -EINVAL;
+			goto out;
 		}
-	return -EINVAL;
+	else
+		ret = -EINVAL;
+out:
+	unlock_kernel();
+	return ret;
 }
 
 asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
@@ -496,60 +532,63 @@
 asmlinkage int
 sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
 {
-  struct vm_area_struct *vma;
-
-  if (scope < FLUSH_SCOPE_LINE || scope > FLUSH_SCOPE_ALL
-      || cache & ~FLUSH_CACHE_BOTH)
-    return -EINVAL;
+	struct vm_area_struct *vma;
+	int ret = -EINVAL;
 
-  if (scope == FLUSH_SCOPE_ALL)
-    {
-      /* Only the superuser may flush the whole cache. */
-      if (!suser ())
-	return -EPERM;
-    }
-  else
-    {
-      /* Verify that the specified address region actually belongs to
-	 this process.  */
-      vma = find_vma (current->mm, addr);
-      if (vma == NULL || addr < vma->vm_start || addr + len > vma->vm_end)
-	return -EINVAL;
-    }
+	lock_kernel();
+	if (scope < FLUSH_SCOPE_LINE || scope > FLUSH_SCOPE_ALL ||
+	    cache & ~FLUSH_CACHE_BOTH)
+		goto out;
+
+	if (scope == FLUSH_SCOPE_ALL) {
+		/* Only the superuser may flush the whole cache. */
+		ret = -EPERM;
+		if (!suser ())
+			goto out;
+	} else {
+		/* Verify that the specified address region actually belongs to
+		 * this process.
+		 */
+		vma = find_vma (current->mm, addr);
+		ret = -EINVAL;
+		if (vma == NULL || addr < vma->vm_start || addr + len > vma->vm_end)
+			goto out;
+	}
 
-  if (CPU_IS_020_OR_030) {
-    if (scope == FLUSH_SCOPE_LINE)
-      {
-	unsigned long cacr;
-	__asm__ ("movec %%cacr, %0" : "=r" (cacr));
-	if (cache & FLUSH_CACHE_INSN)
-	  cacr |= 4;
-	if (cache & FLUSH_CACHE_DATA)
-	  cacr |= 0x400;
-	len >>= 4;
-	while (len--)
-	  {
-	    __asm__ __volatile__ ("movec %1, %%caar\n\t"
-				  "movec %0, %%cacr"
-				  : /* no outputs */
-				  : "r" (cacr), "r" (addr));
-	    addr += 16;
-	  }
-      }
-    else
-      {
-	/* Flush the whole cache, even if page granularity is requested.  */
-	unsigned long cacr;
-	__asm__ ("movec %%cacr, %0" : "=r" (cacr));
-	if (cache & FLUSH_CACHE_INSN)
-	  cacr |= 8;
-	if (cache & FLUSH_CACHE_DATA)
-	  cacr |= 0x800;
-	__asm__ __volatile__ ("movec %0, %%cacr" : : "r" (cacr));
-      }
-    return 0;
-  } else if (CPU_IS_040)
-    return cache_flush_040 (addr, scope, cache, len);
-  else if (CPU_IS_060)
-    return cache_flush_060 (addr, scope, cache, len);
+	if (CPU_IS_020_OR_030) {
+		if (scope == FLUSH_SCOPE_LINE) {
+			unsigned long cacr;
+			__asm__ ("movec %%cacr, %0" : "=r" (cacr));
+			if (cache & FLUSH_CACHE_INSN)
+				cacr |= 4;
+			if (cache & FLUSH_CACHE_DATA)
+				cacr |= 0x400;
+			len >>= 4;
+			while (len--) {
+				__asm__ __volatile__ ("movec %1, %%caar\n\t"
+						      "movec %0, %%cacr"
+						      : /* no outputs */
+						      : "r" (cacr), "r" (addr));
+				addr += 16;
+			}
+		} else {
+			/* Flush the whole cache, even if page granularity requested. */
+			unsigned long cacr;
+			__asm__ ("movec %%cacr, %0" : "=r" (cacr));
+			if (cache & FLUSH_CACHE_INSN)
+				cacr |= 8;
+			if (cache & FLUSH_CACHE_DATA)
+				cacr |= 0x800;
+			__asm__ __volatile__ ("movec %0, %%cacr" : : "r" (cacr));
+		}
+		ret = 0;
+		goto out;
+	} else if (CPU_IS_040) {
+		ret = cache_flush_040 (addr, scope, cache, len);
+	} else if (CPU_IS_060) {
+		ret = cache_flush_060 (addr, scope, cache, len);
+	}
+out:
+	unlock_kernel();
+	return ret;
 }
diff -u --recursive --new-file v2.1.22/linux/arch/m68k/mm/init.c linux/arch/m68k/mm/init.c
--- v2.1.22/linux/arch/m68k/mm/init.c	Sun Dec 22 16:37:23 1996
+++ linux/arch/m68k/mm/init.c	Sun Jan 26 12:07:05 1997
@@ -477,6 +477,11 @@
 	       datapages << (PAGE_SHIFT-10));
 }
 
+void free_initmem(void)
+{
+	/* To be written */
+}
+
 void si_meminfo(struct sysinfo *val)
 {
     unsigned long i;
diff -u --recursive --new-file v2.1.22/linux/arch/mips/kernel/ipc.c linux/arch/mips/kernel/ipc.c
--- v2.1.22/linux/arch/mips/kernel/ipc.c	Wed Dec 13 12:39:43 1995
+++ linux/arch/mips/kernel/ipc.c	Sun Jan 26 12:07:05 1997
@@ -10,6 +10,8 @@
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 #include <linux/sem.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
@@ -25,57 +27,67 @@
 asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth)
 {
 #ifdef CONFIG_SYSVIPC
-	int version;
+	int version, ret;
 
+	lock_kernel();
 	version = call >> 16; /* hack for backward compatibility */
 	call &= 0xffff;
 
 	if (call <= SEMCTL)
 		switch (call) {
 		case SEMOP:
-			return sys_semop (first, (struct sembuf *)ptr, second);
+			ret = sys_semop (first, (struct sembuf *)ptr, second);
+			goto out;
 		case SEMGET:
-			return sys_semget (first, second, third);
+			ret = sys_semget (first, second, third);
+			goto out;
 		case SEMCTL: {
 			union semun fourth;
-			int err;
+			ret = -EINVAL;
 			if (!ptr)
-				return -EINVAL;
-			if ((err = verify_area (VERIFY_READ, ptr, sizeof(long))))
-				return err;
+				goto out;
+			if ((ret = verify_area (VERIFY_READ, ptr, sizeof(long))))
+				goto out;
 			fourth.__pad = (void *) get_fs_long(ptr);
-			return sys_semctl (first, second, third, fourth);
+			ret = sys_semctl (first, second, third, fourth);
+			goto out;
 			}
 		default:
-			return -EINVAL;
+			ret = -EINVAL;
+			goto out;
 		}
 	if (call <= MSGCTL) 
 		switch (call) {
 		case MSGSND:
-			return sys_msgsnd (first, (struct msgbuf *) ptr, 
-					   second, third);
+			ret = sys_msgsnd (first, (struct msgbuf *) ptr, 
+					  second, third);
+			goto out;
 		case MSGRCV:
 			switch (version) {
 			case 0: {
 				struct ipc_kludge tmp;
-				int err;
 				if (!ptr)
 					return -EINVAL;
-				if ((err = verify_area (VERIFY_READ, ptr, sizeof(tmp))))
-					return err;
+				if ((ret = verify_area (VERIFY_READ, ptr, sizeof(tmp))))
+					goto out;
 				memcpy_fromfs (&tmp,(struct ipc_kludge *) ptr,
 					       sizeof (tmp));
-				return sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third);
+				ret = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third);
+				goto out;
 				}
 			case 1: default:
-				return sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third);
+				ret = sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third);
+				goto out;
 			}
 		case MSGGET:
-			return sys_msgget ((key_t) first, second);
+			ret = sys_msgget ((key_t) first, second);
+			goto out;
 		case MSGCTL:
-			return sys_msgctl (first, second, (struct msqid_ds *) ptr);
+			ret = sys_msgctl (first, second, (struct msqid_ds *) ptr);
+			goto out;
 		default:
-			return -EINVAL;
+			ret = -EINVAL;
+			goto out;
 		}
 	if (call <= SHMCTL) 
 		switch (call) {
@@ -83,30 +95,40 @@
 			switch (version) {
 			case 0: default: {
 				ulong raddr;
-				int err;
-				if ((err = verify_area(VERIFY_WRITE, (ulong*) third, sizeof(ulong))))
-					return err;
-				err = sys_shmat (first, (char *) ptr, second, &raddr);
-				if (err)
-					return err;
+				if ((ret = verify_area(VERIFY_WRITE, (ulong*) third, sizeof(ulong))))
+					goto out;
+				ret = sys_shmat (first, (char *) ptr, second, &raddr);
+				if (ret)
+					goto out;
 				put_fs_long (raddr, (ulong *) third);
-				return 0;
+				ret = 0;
+				goto out;
 				}
 			case 1:	/* iBCS2 emulator entry point */
+				ret = -EINVAL;
 				if (get_fs() != get_ds())
-					return -EINVAL;
-				return sys_shmat (first, (char *) ptr, second, (ulong *) third);
+					goto out;
+				ret = sys_shmat (first, (char *) ptr, second, (ulong *) third);
+				goto out;
 			}
 		case SHMDT: 
-			return sys_shmdt ((char *)ptr);
+			ret = sys_shmdt ((char *)ptr);
+			goto out;
 		case SHMGET:
-			return sys_shmget (first, second, third);
+			ret = sys_shmget (first, second, third);
+			goto out;
 		case SHMCTL:
-			return sys_shmctl (first, second, (struct shmid_ds *) ptr);
+			ret = sys_shmctl (first, second, (struct shmid_ds *) ptr);
+			goto out;
 		default:
-			return -EINVAL;
+			ret = -EINVAL;
+			goto out;
 		}
-	return -EINVAL;
+	else
+		ret = -EINVAL;
+out:
+	unlock_kernel();
+	return ret;
 #else /* CONFIG_SYSVIPC */
 	return -ENOSYS;
 #endif /* CONFIG_SYSVIPC */
diff -u --recursive --new-file v2.1.22/linux/arch/mips/kernel/signal.c linux/arch/mips/kernel/signal.c
--- v2.1.22/linux/arch/mips/kernel/signal.c	Mon Mar 11 09:39:33 1996
+++ linux/arch/mips/kernel/signal.c	Sun Jan 26 12:07:05 1997
@@ -5,6 +5,8 @@
  */
 #include <linux/sched.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/errno.h>
@@ -29,8 +31,11 @@
 asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, unsigned long set)
 {
 	unsigned long mask;
-	struct pt_regs * regs = (struct pt_regs *) &restart;
+	struct pt_regs * regs;
+	int ret = -EINTR;
 
+	lock_kernel();
+	regs = (struct pt_regs *) &restart;
 	mask = current->blocked;
 	current->blocked = set & _BLOCKABLE;
 	regs->reg2 = -EINTR;
@@ -38,8 +43,11 @@
 		current->state = TASK_INTERRUPTIBLE;
 		schedule();
 		if (do_signal(mask,regs))
-			return -EINTR;
+			goto out;
 	}
+out:
+	unlock_kernel();
+	return ret;
 }
 
 /*
@@ -48,7 +56,9 @@
 asmlinkage int sys_sigreturn(struct pt_regs *regs)
 {
 	struct sigcontext_struct *context;
+	int ret;
 
+	lock_kernel();
 	/*
 	 * We don't support fixing ADEL/ADES exceptions for signal stack frames.
 	 * No big loss - who doesn't care about the alignment of this stack
@@ -99,10 +109,14 @@
 	 * disable syscall checks
 	 */
 	regs->orig_reg2 = -1;
-	return context->sc_v0;
+	goto out;
 
 badframe:
 	do_exit(SIGSEGV);
+out:
+	ret = context->sc_v0;
+	unlock_kernel();
+	return ret;
 }
 
 /*
@@ -239,13 +253,16 @@
  */
 asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
 {
-	unsigned long mask = ~current->blocked;
+	unsigned long mask;
 	unsigned long handler_signal = 0;
 	struct sc *frame = NULL;
 	unsigned long pc = 0;
 	unsigned long signr;
 	struct sigaction * sa;
+	int ret;
 
+	lock_kernel();
+	mask = ~current->blocked;
 	while ((signr = current->signal & mask)) {
 		signr = ffz(~signr);
 		clear_bit(signr, &current->signal);
@@ -331,8 +348,9 @@
 		regs->reg2 = regs->orig_reg2;
 		regs->cp0_epc -= 8;
 	}
+	ret = 0;
 	if (!handler_signal)		/* no handler will be called - return 0 */
-		return 0;
+		goto out;
 	pc = regs->cp0_epc;
 	frame = (struct sc *) regs->reg29;
 	signr = 1;
@@ -353,5 +371,8 @@
 	regs->reg31 = (unsigned long) frame->code;	/* Return address */
 	regs->cp0_epc = pc;		/* "return" to the first handler */
 
-	return 1;
+	ret = 1;
+out:
+	unlock_kernel();
+	return ret;
 }
diff -u --recursive --new-file v2.1.22/linux/arch/mips/kernel/syscall.c linux/arch/mips/kernel/syscall.c
--- v2.1.22/linux/arch/mips/kernel/syscall.c	Fri Apr 12 09:49:30 1996
+++ linux/arch/mips/kernel/syscall.c	Sun Jan 26 12:07:05 1997
@@ -9,6 +9,8 @@
  */
 #include <linux/linkage.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 #include <linux/mman.h>
 #include <linux/sched.h>
 #include <linux/unistd.h>
@@ -28,32 +30,43 @@
 	int fd[2];
 	int error;
 
+	lock_kernel();
 	error = do_pipe(fd);
 	if (error)
-		return error;
+		goto out;
 	regs->reg2 = fd[0];
 	regs->reg3 = fd[1];
-	return 0;
+out:
+	unlock_kernel();
+	return error;
 }
 
 asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len, int prot,
                                   int flags, int fd, off_t offset)
 {
 	struct file * file = NULL;
+	int ret = -EBADF;
 
+	lock_kernel();
 	if (flags & MAP_RENAME) {
 		if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
-			return -EBADF;
+			goto out;
 	}
 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 
-	return do_mmap(file, addr, len, prot, flags, offset);
+	ret = do_mmap(file, addr, len, prot, flags, offset);
+out:
+	unlock_kernel();
+	return ret;
 }
 
 asmlinkage int sys_idle(void)
 {
+	int ret = -EPERM;
+
+	lock_kernel();
 	if (current->pid != 0)
-		return -EPERM;
+		goto out;
 
 	/* endless idle loop with no priority at all */
 	current->counter = -100;
@@ -67,23 +80,36 @@
 				".set\tmips0\n\t");
 		schedule();
 	}
+	ret = 0;
+out:
+	unlock_kernel();
+	return ret;
 }
 
 asmlinkage int sys_fork(struct pt_regs *regs)
 {
-	return do_fork(SIGCHLD, regs->reg29, regs);
+	int ret;
+
+	lock_kernel();
+	ret = do_fork(SIGCHLD, regs->reg29, regs);
+	unlock_kernel();
+	return ret;
 }
 
 asmlinkage int sys_clone(struct pt_regs *regs)
 {
 	unsigned long clone_flags;
 	unsigned long newsp;
+	int ret;
 
+	lock_kernel();
 	clone_flags = regs->reg4;
 	newsp = regs->reg5;
 	if (!newsp)
 		newsp = regs->reg29;
-	return do_fork(clone_flags, newsp, regs);
+	ret = do_fork(clone_flags, newsp, regs);
+	unlock_kernel();
+	return ret;
 }
 
 /*
@@ -94,12 +120,15 @@
 	int error;
 	char * filename;
 
+	lock_kernel();
 	error = getname((char *) regs->reg4, &filename);
 	if (error)
-		return error;
+		goto out;
 	error = do_execve(filename, (char **) regs->reg5,
 	                  (char **) regs->reg6, regs);
 	putname(filename);
+out:
+	unlock_kernel();
 	return error;
 }
 
diff -u --recursive --new-file v2.1.22/linux/arch/mips/kernel/sysmips.c linux/arch/mips/kernel/sysmips.c
--- v2.1.22/linux/arch/mips/kernel/sysmips.c	Wed Dec 13 12:39:44 1995
+++ linux/arch/mips/kernel/sysmips.c	Sun Jan 26 12:07:05 1997
@@ -10,6 +10,8 @@
 #include <linux/errno.h>
 #include <linux/linkage.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 #include <linux/sched.h>
 #include <linux/string.h>
 #include <linux/utsname.h>
@@ -54,44 +56,51 @@
 	char	*name;
 	int	flags, len, retval = -EINVAL;
 
+	lock_kernel();
 	switch(cmd)
 	{
 	case SETNAME:
+		retval = -EPERM;
 		if (!suser())
-			return -EPERM;
+			goto out;
 		name = (char *) arg1;
 		len = get_max_hostname((unsigned long)name);
-		if (retval < 0)
-			return len;
+		retval = len;
+		if (len < 0)
+			goto out;
 		len = strnlen_user(name, retval);
+		retval = -EINVAL;
 		if (len == 0 || len > __NEW_UTS_LEN)
-			return -EINVAL;
+			goto out;
 		memcpy_fromfs(system_utsname.nodename, name, len);
 		system_utsname.nodename[len] = '\0';
-		return 0;
+		retval = 0;
+		goto out;
 	case MIPS_ATOMIC_SET:
 		p = (int *) arg1;
-		retval = verify_area(VERIFY_WRITE, p, sizeof(*p));
-		if(retval)
-			return -EINVAL;
+		retval = -EINVAL;
+		if(verify_area(VERIFY_WRITE, p, sizeof(*p)))
+			goto out;
 		save_flags(flags);
 		cli();
 		retval = *p;
 		*p = arg2;
 		restore_flags(flags);
-		return retval;
+		goto out;
 	case MIPS_FIXADE:
 		if (arg1)
 			current->tss.mflags |= MF_FIXADE;
 		else
 			current->tss.mflags |= MF_FIXADE;
 		retval = 0;
-		break;
+		goto out;
 	case FLUSH_CACHE:
 		sys_cacheflush(0, ~0, BCACHE);
-		break;
+		retval = 0;
+		goto out;
 	}
-
+out:
+	unlock_kernel();
 	return retval;
 }
 
diff -u --recursive --new-file v2.1.22/linux/arch/mips/mm/init.c linux/arch/mips/mm/init.c
--- v2.1.22/linux/arch/mips/mm/init.c	Wed Oct  9 08:55:18 1996
+++ linux/arch/mips/mm/init.c	Sun Jan 26 12:07:05 1997
@@ -281,6 +281,11 @@
 	return;
 }
 
+void free_initmem(void)
+{
+	/* To be written */
+}
+
 void si_meminfo(struct sysinfo *val)
 {
 	int i;
diff -u --recursive --new-file v2.1.22/linux/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c
--- v2.1.22/linux/arch/ppc/kernel/process.c	Sun Dec 22 16:37:23 1996
+++ linux/arch/ppc/kernel/process.c	Sun Jan 26 12:07:05 1997
@@ -14,6 +14,8 @@
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 #include <linux/stddef.h>
 #include <linux/unistd.h>
 #include <linux/ptrace.h>
@@ -133,19 +135,30 @@
 
 asmlinkage int sys_debug(unsigned long r3)
 {
-  if ( !strcmp(current->comm,"crashme"))
-    printk("sys_debug(): r3 (syscall) %d\n", r3);
+	lock_kernel();
+	if (!strcmp(current->comm,"crashme"))
+		printk("sys_debug(): r3 (syscall) %d\n", r3);
+	unlock_kernel();
+	return 0;
 }
 
 asmlinkage int sys_idle(void)
 {
-  if (current->pid != 0)
-    return -EPERM;
-  /* endless idle loop with no priority at all */
-  current->counter = -100;
-  for (;;) {
-    schedule();
-  }
+	int ret = -EPERM;
+
+	lock_kernel();
+	if (current->pid != 0)
+		goto out;
+
+	/* endless idle loop with no priority at all */
+	current->counter = -100;
+	for (;;) {
+		schedule();
+	}
+	ret = 0;
+out:
+	unlock_kernel();
+	return ret;
 }
 
 void show_regs(struct pt_regs * regs)
@@ -232,7 +245,12 @@
 
 asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6, struct pt_regs *regs)
 {
-  return do_fork(SIGCHLD, regs->gpr[1], regs);
+	int ret;
+
+	lock_kernel();
+	ret = do_fork(SIGCHLD, regs->gpr[1], regs);
+	unlock_kernel();
+	return ret;
 }
 
 asmlinkage int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
@@ -242,6 +260,7 @@
 	int error;
 	char * filename;
 
+	lock_kernel();
 	/* getname does it's own verification of the address
 	   when it calls get_max_filename() but
 	   it will assume it's valid if get_fs() == KERNEL_DS
@@ -265,9 +284,7 @@
 #endif
 	error = getname((char *) a0, &filename);
 	if (error)
-	{
-	  return error;
-	}
+		goto out;
 	flush_instruction_cache();
 	error = do_execve(filename, (char **) a1, (char **) a2, regs);
 #if 0
@@ -277,6 +294,8 @@
 }
 #endif
 	putname(filename);
+out:
+	unlock_kernel();
 	return error;
 }
 
@@ -284,7 +303,10 @@
 {
 	unsigned long clone_flags = p1;
 	int res;
+
+	lock_kernel();
 	res = do_fork(clone_flags, regs->gpr[1], regs);
+	unlock_kernel();
 	return res;
 }
 
@@ -339,9 +361,9 @@
 inline void start_thread(struct pt_regs * regs,
                          unsigned long eip, unsigned long esp)
 {
-  regs->nip = eip;
-  regs->gpr[1] = esp;
-  regs->msr = MSR_USER;
-  set_fs(USER_DS);
+	regs->nip = eip;
+	regs->gpr[1] = esp;
+	regs->msr = MSR_USER;
+	set_fs(USER_DS);
 }
 
diff -u --recursive --new-file v2.1.22/linux/arch/ppc/kernel/ptrace.c linux/arch/ppc/kernel/ptrace.c
--- v2.1.22/linux/arch/ppc/kernel/ptrace.c	Wed Dec 18 15:58:43 1996
+++ linux/arch/ppc/kernel/ptrace.c	Sun Jan 26 12:07:05 1997
@@ -18,6 +18,8 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
@@ -376,34 +378,37 @@
 asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
 {
 	struct task_struct *child;
-	struct user * dummy;
-
-	dummy = NULL;
+	struct user * dummy = NULL;
+	int ret = -EPERM;
 
+	lock_kernel();
 	if (request == PTRACE_TRACEME) {
 		/* are we already being traced? */
 		if (current->flags & PF_PTRACED)
-			return -EPERM;
+			goto out;
 		/* set the ptrace bit in the process flags. */
 		current->flags |= PF_PTRACED;
-		return 0;
+		ret = 0;
+		goto out;
 	}
 	if (pid == 1)		/* you may not mess with init */
-		return -EPERM;
+		goto out;
+	ret = -ESRCH;
 	if (!(child = get_task(pid)))
-		return -ESRCH;
+		goto out;
+	ret = -EPERM;
 	if (request == PTRACE_ATTACH) {
 		if (child == current)
-			return -EPERM;
+			goto out;
 		if ((!child->dumpable ||
 		    (current->uid != child->euid) ||
 		    (current->uid != child->uid) ||
 	 	    (current->gid != child->egid) ||
 	 	    (current->gid != child->gid)) && !suser())
-			return -EPERM;
+			goto out;
 		/* the same process cannot be attached many times */
 		if (child->flags & PF_PTRACED)
-			return -EPERM;
+			goto out;
 		child->flags |= PF_PTRACED;
 		if (child->p_pptr != current) {
 			REMOVE_LINKS(child);
@@ -411,73 +416,75 @@
 			SET_LINKS(child);
 		}
 		send_sig(SIGSTOP, child, 1);
-		return 0;
+		ret = 0;
+		goto out;
 	}
+	ret = -ESRCH;
 	if (!(child->flags & PF_PTRACED))
-		return -ESRCH;
+		goto out;
 	if (child->state != TASK_STOPPED) {
 		if (request != PTRACE_KILL)
-			return -ESRCH;
+			goto out;
 	}
 	if (child->p_pptr != current)
-		return -ESRCH;
+		goto out;
 
 	switch (request) {
 	/* If I and D space are separate, these will need to be fixed. */
 		case PTRACE_PEEKTEXT: /* read word at location addr. */ 
 		case PTRACE_PEEKDATA: {
 			unsigned long tmp;
-			int res;
 
-			res = read_long(child, addr, &tmp);
-			if (res < 0)
-				return res;
-			res = verify_area(VERIFY_WRITE, (void *) data, sizeof(long));
-			if (!res)
+			ret = read_long(child, addr, &tmp);
+			if (ret < 0)
+				goto out;
+			ret = verify_area(VERIFY_WRITE, (void *) data, sizeof(long));
+			if (!ret)
 				put_user(tmp, (unsigned long *) data);
-			return res;
+			goto out;
 		}
 
 	/* read the word at location addr in the USER area. */
 		case PTRACE_PEEKUSR: {
 			unsigned long tmp;
-			int res;
 			
 			if ((addr & 3) || addr < 0 || addr >= sizeof(struct user))
 				return -EIO;
 			
-			res = verify_area(VERIFY_WRITE, (void *) data,
+			ret = verify_area(VERIFY_WRITE, (void *) data,
 					  sizeof(long));
-			if (res)
-				return res;
+			if (ret)
+				goto out;
 			tmp = 0;  /* Default return condition */
 			addr = addr >> 2; /* temporary hack. */
-			if (addr < PT_FPR0) {
+			if (addr < PT_FPR0)
 				tmp = get_reg(child, addr);
-			}
 #if 0			
 			else if (addr >= PT_FPR0 && addr < PT_FPR31)
 				tmp = child->tss.fpr[addr - PT_FPR0];
 #endif				
 			else
-				return -EIO;
-			put_user(tmp,(unsigned long *) data);
-			return 0;
+				ret = -EIO;
+			if(!ret)
+				put_user(tmp,(unsigned long *) data);
+			goto out;
 		}
 
       /* If I and D space are separate, this will have to be fixed. */
 		case PTRACE_POKETEXT: /* write the word at location addr. */
 		case PTRACE_POKEDATA:
-			return write_long(child,addr,data);
+			ret = write_long(child,addr,data);
+			goto out;
 
 		case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
+			ret = -EIO;
 			if ((addr & 3) || addr < 0 || addr >= sizeof(struct user))
-				return -EIO;
+				goto out;
 
 			addr = addr >> 2; /* temporary hack. */
 			    
 			if (addr == PT_ORIG_R3)
-				return -EIO;
+				goto out;
 #if 0 /* Let this check be in 'put_reg' */				
 			if (addr == PT_SR) {
 				data &= SR_MASK;
@@ -487,22 +494,24 @@
 #endif			
 			if (addr < PT_FPR0) {
 				if (put_reg(child, addr, data))
-					return -EIO;
-				return 0;
+					goto out;
+				ret = 0;
+				goto out;
 			}
 #if 0			
-			if (addr >= 21 && addr < 48)
-			{
+			if (addr >= 21 && addr < 48) {
 				child->tss.fp[addr - 21] = data;
-				return 0;
+				ret = 0;
+				goto out;
 			}
 #endif			
-			return -EIO;
+			goto out;
 
 		case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
 		case PTRACE_CONT: { /* restart after signal. */
+			ret = -EIO;
 			if ((unsigned long) data >= NSIG)
-				return -EIO;
+				goto out;
 			if (request == PTRACE_SYSCALL)
 				child->flags |= PF_TRACESYS;
 			else
@@ -511,7 +520,8 @@
 			wake_up_process(child);
 			/* make sure the single step bit is not set. */
 			clear_single_step(child);
-			return 0;
+			ret = 0;
+			goto out;
 		}
 
 /*
@@ -520,29 +530,33 @@
  * exit.
  */
 		case PTRACE_KILL: {
+			ret = 0;
 			if (child->state == TASK_ZOMBIE) /* already dead */
-				return 0;
+				goto out;
 			wake_up_process(child);
 			child->exit_code = SIGKILL;
 			/* make sure the single step bit is not set. */
 			clear_single_step(child);
-			return 0;
+			goto out;
 		}
 
 		case PTRACE_SINGLESTEP: {  /* set the trap flag. */
+			ret = -EIO;
 			if ((unsigned long) data >= NSIG)
-				return -EIO;
+				goto out;
 			child->flags &= ~PF_TRACESYS;
 			set_single_step(child);
 			wake_up_process(child);
 			child->exit_code = data;
 			/* give it a chance to run. */
-			return 0;
+			ret = 0;
+			goto out;
 		}
 
 		case PTRACE_DETACH: { /* detach a process that was attached. */
+			ret = -EIO;
 			if ((unsigned long) data >= NSIG)
-				return -EIO;
+				goto out;
 			child->flags &= ~(PF_PTRACED|PF_TRACESYS);
 			wake_up_process(child);
 			child->exit_code = data;
@@ -551,19 +565,25 @@
 			SET_LINKS(child);
 			/* make sure the single step bit is not set. */
 			clear_single_step(child);
-			return 0;
+			ret = 0;
+			goto out;
 		}
 
 		default:
-			return -EIO;
+			ret = -EIO;
+			goto out;
 	}
+out:
+	unlock_kernel();
+	return ret;
 }
 
 asmlinkage void syscall_trace(void)
 {
+	lock_kernel();
 	if ((current->flags & (PF_PTRACED|PF_TRACESYS))
 			!= (PF_PTRACED|PF_TRACESYS))
-		return;
+		goto out;
 	current->exit_code = SIGTRAP;
 	current->state = TASK_STOPPED;
 	notify_parent(current);
@@ -576,5 +596,6 @@
 	if (current->exit_code)
 		current->signal |= (1 << (current->exit_code - 1));
 	current->exit_code = 0;
-	return;
+out:
+	unlock_kernel();
 }
diff -u --recursive --new-file v2.1.22/linux/arch/ppc/kernel/signal.c linux/arch/ppc/kernel/signal.c
--- v2.1.22/linux/arch/ppc/kernel/signal.c	Wed Dec 18 15:58:43 1996
+++ linux/arch/ppc/kernel/signal.c	Sun Jan 26 12:07:05 1997
@@ -8,6 +8,8 @@
 
 #include <linux/sched.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/errno.h>
@@ -28,7 +30,9 @@
 asmlinkage int sys_sigsuspend(unsigned long set, int p2, int p3, int p4, int p6, int p7, struct pt_regs *regs)
 {
 	unsigned long mask;
+	int ret = -EINTR;
 
+	lock_kernel();
 	mask = current->blocked;
 	current->blocked = set & _BLOCKABLE;
 	regs->gpr[3] = -EINTR;
@@ -39,15 +43,20 @@
 		current->state = TASK_INTERRUPTIBLE;
 		schedule();
 		if (do_signal(mask,regs))
-			return -EINTR;
+			goto out;
 	}
+out:
+	unlock_kernel();
+	return ret;
 }
 
 asmlinkage int sys_sigreturn(struct pt_regs *regs)
 {
 	struct sigcontext_struct *sc;
 	struct pt_regs *int_regs;
-	int signo;
+	int signo, ret;
+
+	lock_kernel();
 #if 1 	
 	if (verify_area(VERIFY_READ, (void *) regs->gpr[1], sizeof(sc))
 	    || (regs->gpr[1] >=KERNELBASE))
@@ -58,8 +67,8 @@
 	int_regs = sc->regs;
 	signo = sc->signal;
 	sc++;  /* Pop signal 'context' */
-	if (sc == (struct sigcontext_struct *)(int_regs))
-	{ /* Last stacked signal */
+	if (sc == (struct sigcontext_struct *)(int_regs)) {
+		/* Last stacked signal */
 #if 0	
 		/* This doesn't work - it blows away the return address! */
 		memcpy(regs, int_regs, sizeof(*regs));
@@ -76,20 +85,24 @@
 			regs->nip -= 4; /* Back up & retry system call */
 			regs->result = 0;
 		}
-		return (regs->result);
-	} else
-	{ /* More signals to go */
+		ret = (regs->result);
+	} else { /* More signals to go */
 		regs->gpr[1] = (unsigned long)sc;
 		regs->gpr[3] = sc->signal;
 		regs->gpr[4] = sc->regs;
 		regs->link = (unsigned long)((sc->regs)+1);
 		regs->nip = sc->handler;
-		return (sc->signal);
+		ret = sc->signal;
 	}
+	goto out;
+
 badframe:
 	/*printk("sys_sigreturn(): badstack regs %x cur %s/%d\n",
 	 regs,current->comm,current->pid);*/
-  do_exit(SIGSEGV);
+	do_exit(SIGSEGV);
+out:
+	unlock_kernel();
+	return ret;
 }
 
 
@@ -104,159 +117,167 @@
  */
 asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
 {
-  unsigned long mask = ~current->blocked;
-  unsigned long handler_signal = 0;
-  unsigned long *frame = NULL;
-  unsigned long *trampoline;
-  unsigned long *regs_ptr;
-  unsigned long nip = 0;
-  unsigned long signr;
-  int bitno;
-  struct sigcontext_struct *sc;
-  struct sigaction * sa;
-  int s;
-
-  while ((signr = current->signal & mask)) {
-    for (bitno = 0;  bitno < 32;  bitno++)
-    {
-      if (signr & (1<<bitno)) break;
-    }
-    signr = bitno;
-
-    current->signal &= ~(1<<signr);  /* Clear bit */
-    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;
-      /* check for SIGCHLD: it's special */
-      while (sys_waitpid(-1,NULL,WNOHANG) > 0)
-	/* nothing */;
-      continue;
-    }
-    if (sa->sa_handler == SIG_DFL) {
-      if (current->pid == 1)
-	continue;
-      switch (signr) {
-      case SIGCONT: case SIGCHLD: case SIGWINCH:
-	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 &
-	      SA_NOCLDSTOP))
-	  notify_parent(current);
-	schedule();
-	continue;
-
-      case SIGQUIT: case SIGILL: case SIGTRAP:
-      case SIGIOT: case SIGFPE: case SIGSEGV:
-	if (current->binfmt && current->binfmt->core_dump) {
-	  if (current->binfmt->core_dump(signr, regs))
-	    signr |= 0x80;
+	unsigned long mask;
+	unsigned long handler_signal = 0;
+	unsigned long *frame = NULL;
+	unsigned long *trampoline, *regs_ptr;
+	unsigned long nip = 0;
+	unsigned long signr;
+	struct sigcontext_struct *sc;
+	struct sigaction * sa;
+	int bitno, s, ret;
+
+	lock_kernel();
+	mask = ~current->blocked;
+	while ((signr = current->signal & mask)) {
+		for (bitno = 0;  bitno < 32;  bitno++)
+			if (signr & (1<<bitno))
+				break;
+		signr = bitno;
+
+		current->signal &= ~(1<<signr);  /* Clear bit */
+		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;
+			/* check for SIGCHLD: it's special */
+			while (sys_waitpid(-1,NULL,WNOHANG) > 0)
+				/* nothing */;
+			continue;
+		}
+		if (sa->sa_handler == SIG_DFL) {
+			if (current->pid == 1)
+				continue;
+			switch (signr) {
+			case SIGCONT: case SIGCHLD: case SIGWINCH:
+				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 &
+				      SA_NOCLDSTOP))
+					notify_parent(current);
+				schedule();
+				continue;
+
+			case SIGQUIT: case SIGILL: case SIGTRAP:
+			case SIGIOT: case SIGFPE: case SIGSEGV:
+				if (current->binfmt && current->binfmt->core_dump) {
+					if (current->binfmt->core_dump(signr, regs))
+						signr |= 0x80;
+				}
+				/* fall through */
+			default:
+				current->signal |= _S(signr & 0x7f);
+				do_exit(signr);
+			}
+		}
+
+		/* handle signal */
+		if ((int)regs->orig_gpr3 >= 0) {
+			if ((int)regs->result == -ERESTARTNOHAND ||
+			    ((int)regs->result == -ERESTARTSYS &&
+			     !(sa->sa_flags & SA_RESTART)))
+				(int)regs->result = -EINTR;
+		}
+		handler_signal |= 1 << (signr-1);
+		mask &= ~sa->sa_mask;
 	}
-	/* fall through */
-      default:
-	current->signal |= _S(signr & 0x7f);
-	do_exit(signr);
-      }
-    }
-    /* handle signal */
-    
-    if ((int)regs->orig_gpr3 >= 0) {
-      if ((int)regs->result == -ERESTARTNOHAND ||
-	  ((int)regs->result == -ERESTARTSYS && !(sa->sa_flags & SA_RESTART)))
-	(int)regs->result = -EINTR;
-    }
-    handler_signal |= 1 << (signr-1);
-    mask &= ~sa->sa_mask;
-  }
-  if (!handler_signal)		/* no handler will be called - return 0 */
-  {
-    return 0;
-  }
-
-
-  nip = regs->nip;
-  frame = (unsigned long *) regs->gpr[1];
-  /* Build trampoline code on stack */
-  frame -= 2;
-  trampoline = frame;
+	ret = 0;
+	if (!handler_signal)		/* no handler will be called - return 0 */
+		goto out;
+
+	nip = regs->nip;
+	frame = (unsigned long *) regs->gpr[1];
+
+	/* Build trampoline code on stack */
+	frame -= 2;
+	trampoline = frame;
 #if 1
-  /* verify stack is valid for writing regs struct */
-  if (verify_area(VERIFY_WRITE,(void *)frame, sizeof(long)*2+sizeof(*regs))
-      || (frame >= KERNELBASE ))
-    goto badframe;
+	/* verify stack is valid for writing regs struct */
+	if (verify_area(VERIFY_WRITE,(void *)frame, sizeof(long)*2+sizeof(*regs))
+	    || (frame >= KERNELBASE ))
+		goto badframe;
 #endif
-  trampoline[0] = 0x38007777;  /* li r0,0x7777 */
-  trampoline[1] = 0x44000002;  /* sc           */
-  frame -= sizeof(*regs) / sizeof(long);
-  regs_ptr = frame;
-  memcpy(regs_ptr, regs, sizeof(*regs));
-  signr = 1;
-  sa = current->sig->action;
+	trampoline[0] = 0x38007777;  /* li r0,0x7777 */
+	trampoline[1] = 0x44000002;  /* sc           */
+	frame -= sizeof(*regs) / sizeof(long);
+	regs_ptr = frame;
+	memcpy(regs_ptr, regs, sizeof(*regs));
+	signr = 1;
+	sa = current->sig->action;
   
-  
-  for (mask = 1 ; mask ; sa++,signr++,mask += mask) {
-    if (mask > handler_signal)
-      break;
-    if (!(mask & handler_signal))
-      continue;
+	for (mask = 1 ; mask ; sa++,signr++,mask += mask) {
+		if (mask > handler_signal)
+			break;
+		if (!(mask & handler_signal))
+			continue;
 
-    frame -= sizeof(struct sigcontext_struct) / sizeof(long);
+		frame -= sizeof(struct sigcontext_struct) / sizeof(long);
 #if 1
-    if (verify_area(VERIFY_WRITE,(void *)frame,
-		    sizeof(struct sigcontext_struct)/sizeof(long)))
-      goto badframe;
+		if (verify_area(VERIFY_WRITE,(void *)frame,
+				sizeof(struct sigcontext_struct)/sizeof(long)))
+			goto badframe;
 #endif    
-    sc = (struct sigcontext_struct *)frame;
-    nip = (unsigned long) sa->sa_handler;
+		sc = (struct sigcontext_struct *)frame;
+		nip = (unsigned long) sa->sa_handler;
 #if 0 /* Old compiler */		
-    nip = *(unsigned long *)nip;
+		nip = *(unsigned long *)nip;
 #endif		
-    if (sa->sa_flags & SA_ONESHOT)
-      sa->sa_handler = NULL;
-    sc->handler = nip;
-    sc->oldmask = current->blocked;
-    sc->regs = (unsigned long)regs_ptr;
-    sc->signal = signr;
-    current->blocked |= sa->sa_mask;
-    regs->gpr[3] = signr;
-    regs->gpr[4] = (unsigned long)regs_ptr;
-  }
-  regs->link = (unsigned long)trampoline;
-  regs->nip = nip;
-  regs->gpr[1] = (unsigned long)sc;
-  /* The DATA cache must be flushed here to insure coherency */
-  /* between the DATA & INSTRUCTION caches.  Since we just */
-  /* created an instruction stream using the DATA [cache] space */
-  /* and since the instruction cache will not look in the DATA */
-  /* cache for new data, we have to force the data to go on to */
-  /* memory and flush the instruction cache to force it to look */
-  /* there.  The following function performs this magic */
-  flush_instruction_cache();
-  return 1;
+		if (sa->sa_flags & SA_ONESHOT)
+			sa->sa_handler = NULL;
+		sc->handler = nip;
+		sc->oldmask = current->blocked;
+		sc->regs = (unsigned long)regs_ptr;
+		sc->signal = signr;
+		current->blocked |= sa->sa_mask;
+		regs->gpr[3] = signr;
+		regs->gpr[4] = (unsigned long)regs_ptr;
+	}
+	regs->link = (unsigned long)trampoline;
+	regs->nip = nip;
+	regs->gpr[1] = (unsigned long)sc;
+
+	/* The DATA cache must be flushed here to insure coherency
+	 * between the DATA & INSTRUCTION caches.  Since we just
+	 * created an instruction stream using the DATA [cache] space
+	 * and since the instruction cache will not look in the DATA
+	 * cache for new data, we have to force the data to go on to
+	 * memory and flush the instruction cache to force it to look
+	 * there.  The following function performs this magic
+	 */
+	flush_instruction_cache();
+	ret = 1;
+	goto out;
+
 badframe:
-  /*  printk("do_signal(): badstack signr %d frame %x regs %x cur %s/%d\n",
-	 signr,frame,regs,current->comm,current->pid);*/
-  do_exit(SIGSEGV);
+#if 0
+	printk("do_signal(): badstack signr %d frame %x regs %x cur %s/%d\n",
+	       signr, frame, regs, current->comm, current->pid);
+#endif
+	do_exit(SIGSEGV);
+
+out:
+	unlock_kernel();
+	return ret;
 }
diff -u --recursive --new-file v2.1.22/linux/arch/ppc/kernel/stubs.c linux/arch/ppc/kernel/stubs.c
--- v2.1.22/linux/arch/ppc/kernel/stubs.c	Wed Dec 18 15:58:43 1996
+++ linux/arch/ppc/kernel/stubs.c	Sun Jan 26 12:07:05 1997
@@ -1,24 +1,56 @@
 /*#include <linux/in.h>*/
 #include <linux/autoconf.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
-void sys_iopl(void) { panic("sys_iopl"); }
-void sys_vm86(void) { panic("sys_vm86"); }
-void sys_modify_ldt(void) { panic("sys_modify_ldt"); }
+void sys_iopl(void)
+{
+	lock_kernel();
+	panic("sys_iopl");
+	unlock_kernel();
+}
+void sys_vm86(void)
+{
+	lock_kernel();
+	panic("sys_vm86");
+	unlock_kernel();
+}
+void sys_modify_ldt(void)
+{
+	lock_kernel();
+	panic("sys_modify_ldt");
+	unlock_kernel();
+}
 
-void sys_ipc(void) {panic("sys_ipc"); }
-void sys_newselect(void) {panic("sys_newselect"); }
+void sys_ipc(void)
+{
+	lock_kernel();
+	panic("sys_ipc");
+	unlock_kernel();
+}
+
+void sys_newselect(void)
+{
+	lock_kernel();
+	panic("sys_newselect");
+	unlock_kernel();
+}
 
 #ifndef CONFIG_MODULES
 void
 scsi_register_module(void)
 {
+	lock_kernel();
 	panic("scsi_register_module");
+	unlock_kernel();
 }
 
 void
 scsi_unregister_module(void)
 {
+	lock_kernel();
 	panic("scsi_unregister_module");
+	unlock_kernel();
 }
 #endif
 
diff -u --recursive --new-file v2.1.22/linux/arch/ppc/kernel/syscalls.c linux/arch/ppc/kernel/syscalls.c
--- v2.1.22/linux/arch/ppc/kernel/syscalls.c	Wed Dec 18 15:58:43 1996
+++ linux/arch/ppc/kernel/syscalls.c	Sun Jan 26 12:07:05 1997
@@ -12,6 +12,8 @@
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 #include <linux/sem.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
@@ -26,27 +28,33 @@
 asmlinkage int sys_pipe(unsigned long * fildes)
 {
 	int error;
+
+	lock_kernel();
 	error = verify_area(VERIFY_WRITE,fildes,8);
 	if (error)
-		return error;
+		goto out;
 	error = do_pipe(fildes);
-	if (error)
-		return error;
-	return 0;
+out:
+	unlock_kernel();
+	return error;
 }
 
 asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len, int prot,
                                   int flags, int fd, off_t offset)
 {
 	struct file * file = NULL;
+	int ret = -EBADF;
 
+	lock_kernel();
 	if (!(flags & MAP_ANONYMOUS)) {
 		if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
-			return -EBADF;
+			goto out;
 	}
 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-
-	return do_mmap(file, addr, len, prot, flags, offset);
+	ret = do_mmap(file, addr, len, prot, flags, offset);
+out:
+	unlock_kernel();
+	return ret;
 }
 
 /*
@@ -62,21 +70,27 @@
 	long a,b,c,d,e;
 	struct file * file = NULL;
 
+	lock_kernel();
 	error = verify_area(VERIFY_READ, buffer, 6*sizeof(long));
 	if (error)
-		return error;
+		goto out;
 	get_user(flags,buffer+3);
 	if (!(flags & MAP_ANONYMOUS)) {
 		unsigned long fd;
 		get_user(fd,buffer+4);
+		error = -EBADF;
 		if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
-			return -EBADF;
+			goto out;
 	}
 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+	error = -EFAULT;
 	if ( get_user(a,buffer) || get_user(b,buffer+1) ||
 	     get_user(c,buffer+2)||get_user(d,buffer+5)	)
-	  return -EFAULT;
-	return do_mmap(file,a,b,c, flags, d);
+		goto out;
+	error = do_mmap(file,a,b,c, flags, d);
+out:
+	unlock_kernel();
+	return error;
 }
 
 extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
@@ -89,15 +103,19 @@
 	fd_set *exp;
 	struct timeval *tvp;
 
+	lock_kernel();
 	n = verify_area(VERIFY_READ, buffer, 5*sizeof(unsigned long));
 	if (n)
-		return n;
+		goto out;
 	get_user(n,buffer);
 	get_user(inp,buffer+1);
 	get_user(outp,buffer+2);
 	get_user(exp,buffer+3);
 	get_user(tvp,buffer+4);
-	return sys_select(n, inp, outp, exp, tvp);
+	n = sys_select(n, inp, outp, exp, tvp);
+out:
+	unlock_kernel();
+	return n;
 }
 #if 0
 
@@ -108,57 +126,68 @@
  */
 asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth)
 {
-	int version;
+	int version, ret;
 
+	lock_kernel();
 	version = call >> 16; /* hack for backward compatibility */
 	call &= 0xffff;
 
 	if (call <= SEMCTL)
 		switch (call) {
 		case SEMOP:
-			return sys_semop (first, (struct sembuf *)ptr, second);
+			ret = sys_semop (first, (struct sembuf *)ptr, second);
+			goto out;
 		case SEMGET:
-			return sys_semget (first, second, third);
+			ret = sys_semget (first, second, third);
+			goto out;
 		case SEMCTL: {
 			union semun fourth;
-			int err;
+			ret = -EINVAL;
 			if (!ptr)
-				return -EINVAL;
-			if ((err = verify_area (VERIFY_READ, ptr, sizeof(long))))
-				return err;
+				goto out;
+			if ((ret = verify_area (VERIFY_READ, ptr, sizeof(long))))
+				goto out;
 			fourth.__pad = (void *) get_fs_long(ptr);
-			return sys_semctl (first, second, third, fourth);
+			ret = sys_semctl (first, second, third, fourth);
+			goto out;
 			}
 		default:
-			return -EINVAL;
+			ret = -EINVAL;
+			goto out;
 		}
 	if (call <= MSGCTL) 
 		switch (call) {
 		case MSGSND:
-			return sys_msgsnd (first, (struct msgbuf *) ptr, 
-					   second, third);
+			ret = sys_msgsnd (first, (struct msgbuf *) ptr, 
+					  second, third);
+			goto out;
 		case MSGRCV:
 			switch (version) {
 			case 0: {
 				struct ipc_kludge tmp;
-				int err;
+				ret = -EINVAL;
 				if (!ptr)
-					return -EINVAL;
-				if ((err = verify_area (VERIFY_READ, ptr, sizeof(tmp))))
-					return err;
+					goto out;
+				if ((ret = verify_area (VERIFY_READ, ptr, sizeof(tmp))))
+					goto out;
 				memcpy_fromfs (&tmp,(struct ipc_kludge *) ptr,
 					       sizeof (tmp));
-				return sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third);
+				ret = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third);
+				goto out;
 				}
 			case 1: default:
-				return sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third);
+				ret = sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third);
+				goto out;
 			}
 		case MSGGET:
-			return sys_msgget ((key_t) first, second);
+			ret = sys_msgget ((key_t) first, second);
+			goto out;
 		case MSGCTL:
-			return sys_msgctl (first, second, (struct msqid_ds *) ptr);
+			ret = sys_msgctl (first, second, (struct msqid_ds *) ptr);
+			goto out;
 		default:
-			return -EINVAL;
+			ret = -EINVAL;
+			goto out;
 		}
 	if (call <= SHMCTL) 
 		switch (call) {
@@ -166,29 +195,39 @@
 			switch (version) {
 			case 0: default: {
 				ulong raddr;
-				int err;
-				if ((err = verify_area(VERIFY_WRITE, (ulong*) third, sizeof(ulong))))
-					return err;
-				err = sys_shmat (first, (char *) ptr, second, &raddr);
-				if (err)
-					return err;
+				if ((ret = verify_area(VERIFY_WRITE, (ulong*) third, sizeof(ulong))))
+					goto out;
+				ret = sys_shmat (first, (char *) ptr, second, &raddr);
+				if (ret)
+					goto out;
 				put_fs_long (raddr, (ulong *) third);
-				return 0;
+				ret = 0;
+				goto out;
 				}
 			case 1:	/* iBCS2 emulator entry point */
+				ret = -EINVAL;
 				if (get_fs() != get_ds())
-					return -EINVAL;
-				return sys_shmat (first, (char *) ptr, second, (ulong *) third);
+					goto out;
+				ret = sys_shmat (first, (char *) ptr, second, (ulong *) third);
+				goto out;
 			}
 		case SHMDT: 
-			return sys_shmdt ((char *)ptr);
+			ret = sys_shmdt ((char *)ptr);
+			goto out;
 		case SHMGET:
-			return sys_shmget (first, second, third);
+			ret = sys_shmget (first, second, third);
+			goto out;
 		case SHMCTL:
-			return sys_shmctl (first, second, (struct shmid_ds *) ptr);
+			ret = sys_shmctl (first, second, (struct shmid_ds *) ptr);
+			goto out;
 		default:
-			return -EINVAL;
+			ret = -EINVAL;
+			goto out;
 		}
-	return -EINVAL;
+	else
+		ret = -EINVAL;
+out:
+	unlock_kernel();
+	return ret;
 }
 #endif
diff -u --recursive --new-file v2.1.22/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c
--- v2.1.22/linux/arch/ppc/mm/init.c	Wed Dec 18 15:58:43 1996
+++ linux/arch/ppc/mm/init.c	Sun Jan 26 12:07:06 1997
@@ -174,6 +174,11 @@
   return;
 }
 
+void free_initmem(void)
+{
+	/* To be written */
+}
+
 void si_meminfo(struct sysinfo *val)
 {
 	int i;
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/Makefile linux/arch/sparc/Makefile
--- v2.1.22/linux/arch/sparc/Makefile	Sun Dec 22 16:37:23 1996
+++ linux/arch/sparc/Makefile	Sun Jan 26 12:07:06 1997
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.22 1996/12/18 06:17:39 tridge Exp $
+# $Id: Makefile,v 1.23 1997/01/02 14:14:17 jj Exp $
 # sparc/Makefile
 #
 # Makefile for the architecture dependent flags and dependencies on the
@@ -18,7 +18,8 @@
 #CFLAGS := $(CFLAGS) -g -pipe
 CFLAGS := $(CFLAGS) -pipe
 
-LINKFLAGS = -N -Ttext 0xf0004000
+#LINKFLAGS = -N -Ttext 0xf0004000
+LINKFLAGS = -T arch/sparc/vmlinux.lds
 
 HEAD := arch/sparc/kernel/head.o
 
@@ -30,9 +31,6 @@
 LIBS := $(TOPDIR)/lib/lib.a $(LIBS) $(TOPDIR)/arch/sparc/prom/promlib.a \
 	$(TOPDIR)/arch/sparc/lib/lib.a
 
-INITOBJ = $(TOPDIR)/arch/sparc/kernel/initobj.o
-FINITOBJ = $(TOPDIR)/arch/sparc/kernel/finitobj.o
-
 ifdef CONFIG_AP1000
 SUBDIRS := $(SUBDIRS) arch/sparc/ap1000 mpp
 ARCHIVES := $(TOPDIR)/arch/sparc/ap1000/ap1000lib.o $(TOPDIR)/mpp/mpplib.o $(ARCHIVES) 
@@ -41,6 +39,5 @@
 endif
 
 archclean:
-	rm -f $(TOPDIR)/arch/sparc/boot/boot
 
 archdep:
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/ap1000/Makefile linux/arch/sparc/ap1000/Makefile
--- v2.1.22/linux/arch/sparc/ap1000/Makefile	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/ap1000/Makefile	Sun Jan 26 12:07:06 1997
@@ -0,0 +1,20 @@
+# Makefile for the AP1000 files in the Linux kernel
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+
+.S.s:
+	$(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s
+.S.o:
+	$(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o
+
+all: ap1000lib.o
+
+O_TARGET := ap1000lib.o
+O_OBJS   := bnet.o timer.o util.o dma.o kgdb.o irq.o \
+	msc.o hw.o tnet.o sync.o mpp.o \
+	apmmu.o aplib.o approm.o
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/ap1000/apinline.h linux/arch/sparc/ap1000/apinline.h
--- v2.1.22/linux/arch/sparc/ap1000/apinline.h	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/ap1000/apinline.h	Sun Jan 26 12:07:06 1997
@@ -0,0 +1,86 @@
+  /*
+   * Copyright 1996 The Australian National University.
+   * Copyright 1996 Fujitsu Laboratories Limited
+   * 
+   * This software may be distributed under the terms of the Gnu
+   * Public License version 2 or later
+  */
+/* inline utilities to support the AP1000 code */
+
+#if 0
+/* MMU bypass access */
+
+static inline unsigned long phys_9_in(unsigned long paddr)
+{
+	unsigned long word;
+
+	__asm__ __volatile__("lda [%1] %2, %0\n\t" :
+			     "=r" (word) :
+			     "r" (paddr), "i" (0x29) :
+			     "memory");
+	return word;
+}
+
+static inline void phys_9_out(unsigned long paddr, unsigned long word)
+{
+	__asm__ __volatile__("sta %0, [%1] %2\n\t" : :
+			     "r" (word), "r" (paddr), "i" (0x29) :
+			     "memory");
+}
+
+static inline unsigned long phys_b_in(unsigned long paddr)
+{
+	unsigned long word;
+
+	__asm__ __volatile__("lda [%1] %2, %0\n\t" :
+			     "=r" (word) :
+			     "r" (paddr), "i" (0x2b) :
+			     "memory");
+	return word;
+}
+
+static inline void phys_b_out(unsigned long paddr, unsigned long word)
+{
+	__asm__ __volatile__("sta %0, [%1] %2\n\t" : :
+			     "r" (word), "r" (paddr), "i" (0x2b) :
+			     "memory");
+}
+
+static inline unsigned long phys_c_in(unsigned long paddr)
+{
+	unsigned long word;
+
+	__asm__ __volatile__("lda [%1] %2, %0\n\t" :
+			     "=r" (word) :
+			     "r" (paddr), "i" (0x2b) :
+			     "memory");
+	return word;
+}
+
+static inline void phys_c_out(unsigned long paddr, unsigned long word)
+{
+	__asm__ __volatile__("sta %0, [%1] %2\n\t" : :
+			     "r" (word), "r" (paddr), "i" (0x2b) :
+			     "memory");
+}
+
+#undef BIF_IN
+#undef BIF_OUT
+#undef DMA_IN
+#undef DMA_OUT
+#undef MSC_IN
+#undef MSC_OUT
+#undef MC_IN
+#undef MC_OUT
+
+#define BIF_IN(reg) phys_9_in(reg)
+#define BIF_OUT(reg,v) phys_9_out(reg,v)
+#define DMA_IN(reg) phys_9_in(reg)
+#define DMA_OUT(reg,v) phys_9_out(reg,v)
+#define MC_IN(reg) phys_b_in((reg) - MC_BASE0)
+#define MC_OUT(reg,v) phys_b_out((reg) - MC_BASE0,v)
+#define MSC_IN(reg) phys_c_in((reg) - MSC_BASE0)
+#define MSC_OUT(reg,v) phys_c_out((reg) - MSC_BASE0,v)
+#endif
+
+
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/ap1000/aplib.c linux/arch/sparc/ap1000/aplib.c
--- v2.1.22/linux/arch/sparc/ap1000/aplib.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/ap1000/aplib.c	Sun Jan 26 12:07:06 1997
@@ -0,0 +1,496 @@
+  /*
+   * Copyright 1996 The Australian National University.
+   * Copyright 1996 Fujitsu Laboratories Limited
+   * 
+   * This software may be distributed under the terms of the Gnu
+   * Public License version 2 or later
+  */
+
+/* kernel based aplib.
+
+   This was initially implemented in user space, but we eventually
+   relented when we discovered some really nasty MSC hardware bugs and
+   decided to disallow access to the device registers by users. Pity :-(
+
+   Andrew Tridgell, November 1996 
+*/
+
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+
+#include <asm/page.h>
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/segment.h>
+#include <asm/uaccess.h>
+
+ #include <asm/ap1000/pgtapmmu.h>
+#include <asm/ap1000/apreg.h>
+#include <asm/ap1000/apservice.h>
+#include <asm/ap1000/aplib.h>
+
+
+extern int *tnet_rel_cid_table;
+extern unsigned _cid, _ncel, _ncelx, _ncely, _cidx, _cidy;
+
+
+/* this is used to stop the task hogging the MSC while paging in data */
+static inline void page_in(char *addr,long size)
+{
+	unsigned sum = 0;
+	while (size > 0) {
+		sum += *(volatile char *)addr;
+		addr += PAGE_SIZE;
+		size -= PAGE_SIZE;
+	}
+}
+
+
+/* this sets up the aplib structures using info passed in from user space
+   it should only be called once, and should be the first aplib call 
+   it should be followed by APLIB_SYNC 
+   */
+static inline int aplib_init(struct aplib_init *init)
+{
+	struct aplib_struct *aplib;
+	int error,i;
+	int old_uid;
+
+	error = verify_area(VERIFY_READ,init,sizeof(*init));
+	if (error) return error;
+	error = verify_area(VERIFY_READ,init->phys_cells,
+			    sizeof(int)*init->numcells);
+	if (error) return error;
+	error = verify_area(VERIFY_WRITE,
+			    init->ringbuffer,
+			    init->ringbuf_size * sizeof(int));
+	if (error) return error;
+	error = verify_area(VERIFY_WRITE,
+			    (char *)APLIB_PAGE_BASE,
+			    APLIB_PAGE_LEN);
+	if (error) return error;
+
+	if (!MPP_IS_PAR_TASK(current->taskid))
+		return -EINVAL;
+
+	if (current->aplib)
+		return -EINVAL;
+
+	aplib = current->aplib = (struct aplib_struct *)APLIB_PAGE_BASE;
+
+	/* lock the aplib structure in memory */
+	old_uid = current->euid;
+	current->euid = 0;
+	memset(aplib,0,APLIB_PAGE_LEN);
+	error = sys_mlock(aplib,APLIB_PAGE_LEN);
+	current->euid = old_uid;
+	if (error) {
+		printk("mlock1 failed\n");
+		return error;
+	}
+
+	/* lock the ringbuffer in memory */
+	old_uid = current->euid;
+	current->euid = 0;
+	memset(init->ringbuffer,0,init->ringbuf_size*4);
+	error = sys_mlock(init->ringbuffer,init->ringbuf_size*4);
+	current->euid = old_uid;
+	if (error) {
+		printk("mlock2 failed\n");
+		return error;
+	}
+
+	aplib->ringbuf = init->ringbuffer;
+	aplib->ringbuf_size = init->ringbuf_size;
+	aplib->numcells = init->numcells;
+	aplib->cid = init->cid;
+	aplib->tid = current->taskid;
+	aplib->numcells_x = init->numcells_x;
+	aplib->numcells_y = init->numcells_y;
+	aplib->cidx = init->cid % init->numcells_x;
+	aplib->cidy = init->cid / init->numcells_x;
+
+	aplib->physical_cid = (unsigned *)(aplib+1);
+	aplib->rel_cid      = aplib->physical_cid + init->numcells;
+
+	if ((char *)(aplib->rel_cid + init->numcells) >
+	    (char *)(APLIB_PAGE_BASE + APLIB_PAGE_LEN)) {
+		return -ENOMEM;
+	}
+
+	memcpy(aplib->physical_cid,init->phys_cells,
+	       sizeof(int)*init->numcells);
+
+	/* initialise the relative cid table */
+	for (i=0;i<aplib->numcells;i++) 
+		aplib->rel_cid[i] = 
+			tnet_rel_cid_table[aplib->physical_cid[i]];
+
+	return 0;
+}
+
+
+/* n == which sync line (ignored)
+   returns logical or of the stat values across the cells (1 bit resolution) 
+
+   This has to be done very carefully as the tasks can startup on the cells
+   in any order, so we don't know which tasks have started up when this
+   is called
+*/
+static inline int aplib_sync(int n,int stat)
+{
+	struct aplib_struct *aplib = current->aplib;
+	static int sync_flags[MPP_NUM_TASKS];
+	int i,err;
+	int tsk = current->taskid;
+
+	stat &= 1;
+
+	if (aplib->numcells < 2) 
+		return stat;
+
+	tsk -= MPP_TASK_BASE;
+
+	if (aplib->cid == 0) {
+		if ((err=wait_on_int(&sync_flags[tsk],
+				     aplib->numcells-1,5)))
+			return err;
+		sync_flags[tsk] = 0;
+		if (aplib->numcells == _ncel) {
+			ap_bput(0,0,0,(u_long)&sync_flags[tsk],0);
+		} else {
+			for (i=1;i<aplib->numcells;i++)
+				ap_put(aplib->physical_cid[i],
+				       0,0,0,(u_long)&sync_flags[tsk],0);
+		}
+	} else {
+		ap_put(aplib->physical_cid[0],
+		       0,0,0,(u_long)&sync_flags[tsk],0);
+		if ((err=wait_on_int(&sync_flags[tsk],1,5)))
+			return err;
+		sync_flags[tsk] = 0;
+	}
+
+	/* I haven't written the xy_ calls yet ... */
+	/* aplib_xy_ior(stat,&stat); */
+
+	return stat;
+}
+
+
+
+static inline void _putget(unsigned q,
+			   unsigned rcell,
+			   unsigned *src_addr,
+			   unsigned size,unsigned *dest_addr,
+			   unsigned *dest_flag,unsigned *src_flag)
+{
+	unsigned flags;
+	volatile unsigned *entry = (volatile unsigned *)q;
+
+	save_flags(flags); cli();
+
+	*entry = rcell;
+	*entry = size;
+	*entry = (unsigned)dest_addr;
+	*entry = 0;
+	*entry = (unsigned)dest_flag;
+	*entry = (unsigned)src_flag;
+	*entry = (unsigned)src_addr;
+	*entry = 0;
+
+	restore_flags(flags);
+}
+
+
+/* a basic put() operation. Note the avoidance of odd word boundaries
+   and transfers sizes beyond what the hardware can deal with */
+static inline int aplib_put(struct aplib_putget *put)
+{
+	int error;
+	struct aplib_struct *aplib = current->aplib;
+
+	error = verify_area(VERIFY_WRITE,put,sizeof(*put));
+	if (error) return error;
+
+	if (put->cid >= aplib->numcells) 
+		return -EINVAL;
+
+	do {
+		int n;
+
+		if (put->size && (((unsigned)put->src_addr) & 4)) {
+			n = 1;
+		} else if (put->size > MAX_PUT_SIZE) {
+			n = MAX_PUT_SIZE;
+		} else {
+			n = put->size;
+		}
+
+		put->size -= n;
+
+		page_in((char *)put->src_addr,n<<2);
+
+		_putget(MSC_PUT_QUEUE,
+			aplib->rel_cid[put->cid],
+			put->src_addr,
+			n,
+			put->dest_addr,
+			put->size?0:put->dest_flag,
+			put->size?0:put->src_flag);
+
+		put->dest_addr += n;
+		put->src_addr += n;
+	} while (put->size);
+
+	if (put->ack) {
+		aplib->ack_request++;
+		_putget(MSC_GET_QUEUE,
+			aplib->rel_cid[put->cid], 
+			0, 0, 0,
+			&aplib->ack_flag, 0);
+	}
+
+	return 0;
+}
+
+
+/* a basic get() operation */
+static inline int aplib_get(struct aplib_putget *get)
+{
+	struct aplib_struct *aplib = current->aplib;
+	int error = verify_area(VERIFY_WRITE,get,sizeof(*get));
+	if (error) return error;
+
+	if (get->cid >= aplib->numcells) 
+		return -EINVAL;
+
+	do {
+		int n;
+
+		if (get->size && (((unsigned)get->src_addr) & 4)) {
+			n = 1;
+		} else if (get->size > MAX_PUT_SIZE) {
+			n = MAX_PUT_SIZE;
+		} else {
+			n = get->size;
+		}
+
+		get->size -= n;
+
+		page_in((char *)get->dest_addr,n<<2);
+
+		_putget(MSC_GET_QUEUE,
+			aplib->rel_cid[get->cid],
+			get->src_addr,
+			n,
+			get->dest_addr,
+			get->size?0:get->dest_flag,
+			get->size?0:get->src_flag);
+		
+		get->dest_addr += n;
+		get->src_addr += n;
+	} while (get->size);
+
+	return 0;
+}
+
+
+/* we have received a protocol message - now do the get 
+ This function is called from interrupt level with interrupts
+ disabled 
+
+ note that send->size is now in words
+*/
+void aplib_bigrecv(unsigned *msgp)
+{
+	struct aplib_struct *aplib;
+	struct aplib_send *send = (struct aplib_send *)(msgp+2);
+	unsigned tid = (msgp[1]&0x3FF);
+	unsigned cid = (msgp[0]>>22)&0x1FF;
+	unsigned octx, ctx;
+	struct task_struct *tsk;
+	unsigned room;
+
+	tsk = task[tid];
+	if (!tsk || !tsk->aplib)
+		return;
+
+	octx = apmmu_get_context();
+	ctx = MPP_TASK_TO_CTX(tid);
+	if (octx != ctx)
+		apmmu_set_context(ctx);
+	aplib = tsk->aplib;
+
+	if (aplib->write_pointer < aplib->read_pointer) 
+		room = aplib->read_pointer - (aplib->write_pointer+1);
+	else
+		room = aplib->ringbuf_size - 
+			((aplib->write_pointer+1)-aplib->read_pointer);
+
+	if (room < (send->size+2)) {
+		send_sig(SIGLOST,tsk,1);		
+		goto finished;
+	}
+
+	aplib->ringbuf[aplib->write_pointer++] = send->info1;
+	aplib->ringbuf[aplib->write_pointer++] = send->info2;
+
+	/* now finally do the get() */
+	_putget(MSC_GET_QUEUE,
+		aplib->rel_cid[cid],
+		send->src_addr,
+		send->size,
+		&aplib->ringbuf[aplib->write_pointer],
+		&aplib->rbuf_flag2,
+		send->flag_addr);
+
+	aplib->write_pointer += send->size;
+	if (aplib->write_pointer >= aplib->ringbuf_size)
+		aplib->write_pointer -= aplib->ringbuf_size;
+	
+finished:
+        if (octx != ctx)
+                apmmu_set_context(octx);
+}
+
+
+/* note the 8 byte alignment fix for the MSC bug */
+static inline int aplib_send(struct aplib_send *send)
+{
+	struct aplib_struct *aplib = current->aplib;
+	int wordSize;
+	int byteAlign, byteFix;
+	u_long src;
+	u_long info1, info2;
+	volatile unsigned *q = (volatile unsigned *)MSC_SEND_QUEUE_S;
+	extern long system_recv_flag;
+	int error;
+	unsigned flags, rcell;
+	unsigned flag_ptr;
+
+	error = verify_area(VERIFY_WRITE,send,sizeof(*send));
+	if (error) return error;
+
+	if (send->cid >= aplib->numcells) 
+		return -EINVAL;
+
+	if (send->tag == RBUF_SYSTEM || send->tag == RBUF_BIGSEND)
+		return -EINVAL;
+
+	error = verify_area(VERIFY_READ,(char *)send->src_addr,send->size);
+	if (error) return error;
+
+	page_in((char *)send->src_addr,send->size);
+
+	rcell = aplib->rel_cid[send->cid];
+
+	byteAlign = send->src_addr & 0x3;
+	byteFix = send->size & 0x3;
+
+	wordSize = (send->size + byteAlign + 3) >> 2;
+
+	src = send->src_addr & ~3;
+
+	/* this handles the MSC alignment bug */
+	if (wordSize > 1 &&
+	    (src & 4)) {
+		info1 |= 0x80000000;
+		src -= 4;
+		wordSize++;
+	}
+	
+	info1 = (aplib->cid<<22) | (byteFix<<20) | wordSize;
+	info2 = (send->tag<<28) | (byteAlign<<26) | 
+		(send->type<<10) | aplib->tid;
+	flag_ptr = (unsigned)&send->flag;
+
+	if (send->size > SMALL_SEND_THRESHOLD) {
+		send->info1 = info1;
+		send->info2 = info2;
+		send->size = wordSize;
+		send->src_addr = src;
+		send->flag_addr = (unsigned)&send->flag;
+		flag_ptr = 0;
+
+		wordSize = sizeof(*send)>>2;
+		src = (unsigned)send;
+		
+		info1 = (aplib->cid<<22) | wordSize;
+		info2 = (RBUF_BIGSEND<<28) | aplib->tid;
+	}
+
+	save_flags(flags); cli();
+
+	*q = rcell;
+	*q = wordSize;
+	*q = (u_long)&system_recv_flag;
+	*q = flag_ptr;
+	*q = (u_long)src;
+	*q = 0;
+	*q = info1;
+	*q = info2;
+
+	restore_flags(flags);
+
+	return 0;
+}
+
+
+static inline int aplib_probe(void)
+{
+	tnet_check_completion();
+	return 0;
+}
+
+static inline int aplib_poll(unsigned counter)
+{
+	struct aplib_struct *aplib = current->aplib;
+
+	while (counter == aplib->rbuf_flag1 + aplib->rbuf_flag2) {
+		tnet_check_completion();
+		if (need_resched) break;
+		if (current->signal & ~current->blocked) break;
+	}
+	return 0;
+}
+
+int sys_aplib(unsigned call,int a1,int a2,int a3,int a4)
+{
+
+	if (!current->aplib && call != APLIB_INIT)
+		return -EINVAL;
+
+	switch (call) {
+	case APLIB_INIT:
+		return aplib_init((struct aplib_init *)a1);
+
+	case APLIB_SYNC:
+		return aplib_sync(a1,a2);
+
+	case APLIB_PUT:
+		return aplib_put((struct aplib_putget *)a1);
+
+	case APLIB_GET:
+		return aplib_get((struct aplib_putget *)a1);
+
+	case APLIB_SEND:
+		return aplib_send((struct aplib_send *)a1);
+
+	case APLIB_PROBE:
+		return aplib_probe();
+
+	case APLIB_POLL:
+		return aplib_poll((unsigned)a1);
+	}
+
+	return -EINVAL;
+}
+
+
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/ap1000/apmmu.c linux/arch/sparc/ap1000/apmmu.c
--- v2.1.22/linux/arch/sparc/ap1000/apmmu.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/ap1000/apmmu.c	Sun Jan 26 12:07:06 1997
@@ -0,0 +1,1190 @@
+  /*
+   * Copyright 1996 The Australian National University.
+   * Copyright 1996 Fujitsu Laboratories Limited
+   * 
+   * This software may be distributed under the terms of the Gnu
+   * Public License version 2 or later
+  */
+/* 
+ * apmmu.c:  mmu routines for the AP1000
+ *
+ * based on srmmu.c 
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/vmalloc.h>
+#include <linux/init.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/smp.h>
+#include <asm/mbus.h>
+#include <asm/cache.h>
+#include <asm/oplib.h>
+#include <asm/sbus.h>
+#include <asm/iommu.h>
+#include <asm/asi.h>
+#include <asm/msi.h>
+#include <asm/a.out.h>
+#include <asm/ap1000/pgtapmmu.h>
+#include <asm/viking.h>
+
+
+static unsigned long (*mmu_getpage)(void);
+static void (*ctxd_set)(ctxd_t *ctxp, pgd_t *pgdp);
+static void (*pmd_set)(pmd_t *pmdp, pte_t *ptep);
+
+static void (*flush_page_for_dma)(unsigned long page);
+static void (*flush_cache_page_to_uncache)(unsigned long page);
+static void (*flush_tlb_page_for_cbit)(unsigned long page);
+
+extern void mc_tlb_flush_all(void);
+
+
+static struct apmmu_stats {
+	int invall;
+	int invpg;
+	int invrnge;
+	int invmm;
+} module_stats;
+
+static char *apmmu_name;
+
+static ctxd_t *apmmu_ctx_table_phys;
+static ctxd_t *apmmu_context_table;
+
+static unsigned long ap_mem_size;
+static unsigned long mempool;
+
+
+static inline unsigned long apmmu_v2p(unsigned long vaddr)
+{
+	if (KERNBASE <= vaddr &&
+	    (KERNBASE + ap_mem_size > vaddr)) {
+		return (vaddr - KERNBASE);
+	}
+	return 0xffffffffUL;
+}
+
+static inline unsigned long apmmu_p2v(unsigned long paddr)
+{
+	if (ap_mem_size > paddr)
+		return (paddr + KERNBASE);
+	return 0xffffffffUL;
+}
+
+/* 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 apmmu_swap(unsigned long *addr, unsigned long value)
+{
+	/* the AP1000 has its memory on bus 8, not 0 like suns do */
+	if ((value&0xF0000000) == 0)
+		value |= MEM_BUS_SPACE<<28;
+	__asm__ __volatile__("swap [%2], %0\n\t" :
+			     "=&r" (value) :
+			     "0" (value), "r" (addr));
+	return value;
+}
+
+/* Functions really use this, not apmmu_swap directly. */
+#define apmmu_set_entry(ptr, newentry) \
+        apmmu_swap((unsigned long *) (ptr), (newentry))
+
+
+/* The very generic APMMU page table operations. */
+static unsigned int apmmu_pmd_align(unsigned int addr) { return APMMU_PMD_ALIGN(addr); }
+static unsigned int apmmu_pgdir_align(unsigned int addr) { return APMMU_PGDIR_ALIGN(addr); }
+
+static unsigned long apmmu_vmalloc_start(void)
+{
+	return APMMU_VMALLOC_START;
+}
+
+static inline int apmmu_device_memory(unsigned long x) 
+{
+	return ((x & 0xF0000000) != 0);
+}
+
+static unsigned long apmmu_pgd_page(pgd_t pgd)
+{ return apmmu_device_memory(pgd_val(pgd))?~0:apmmu_p2v((pgd_val(pgd) & APMMU_PTD_PMASK) << 4); }
+
+static unsigned long apmmu_pmd_page(pmd_t pmd)
+{ return apmmu_device_memory(pmd_val(pmd))?~0:apmmu_p2v((pmd_val(pmd) & APMMU_PTD_PMASK) << 4); }
+
+static unsigned long apmmu_pte_page(pte_t pte)
+{ return apmmu_device_memory(pte_val(pte))?~0:apmmu_p2v((pte_val(pte) & APMMU_PTE_PMASK) << 4); }
+
+static int apmmu_pte_none(pte_t pte)          
+{ return !(pte_val(pte) & 0xFFFFFFF); }
+
+static int apmmu_pte_present(pte_t pte)
+{ return ((pte_val(pte) & APMMU_ET_MASK) == APMMU_ET_PTE); }
+
+static void apmmu_pte_clear(pte_t *ptep)      { set_pte(ptep, __pte(0)); }
+
+static int apmmu_pmd_none(pmd_t pmd)          
+{ return !(pmd_val(pmd) & 0xFFFFFFF); }
+
+static int apmmu_pmd_bad(pmd_t pmd)
+{ return (pmd_val(pmd) & APMMU_ET_MASK) != APMMU_ET_PTD; }
+
+static int apmmu_pmd_present(pmd_t pmd)
+{ return ((pmd_val(pmd) & APMMU_ET_MASK) == APMMU_ET_PTD); }
+
+static void apmmu_pmd_clear(pmd_t *pmdp)      { set_pte((pte_t *)pmdp, __pte(0)); }
+
+static int apmmu_pgd_none(pgd_t pgd)          
+{ return !(pgd_val(pgd) & 0xFFFFFFF); }
+
+static int apmmu_pgd_bad(pgd_t pgd)
+{ return (pgd_val(pgd) & APMMU_ET_MASK) != APMMU_ET_PTD; }
+
+static int apmmu_pgd_present(pgd_t pgd)
+{ return ((pgd_val(pgd) & APMMU_ET_MASK) == APMMU_ET_PTD); }
+
+static void apmmu_pgd_clear(pgd_t * pgdp)     { set_pte((pte_t *)pgdp, __pte(0)); }
+
+static int apmmu_pte_write(pte_t pte)         { return pte_val(pte) & APMMU_WRITE; }
+static int apmmu_pte_dirty(pte_t pte)         { return pte_val(pte) & APMMU_DIRTY; }
+static int apmmu_pte_young(pte_t pte)         { return pte_val(pte) & APMMU_REF; }
+
+static pte_t apmmu_pte_wrprotect(pte_t pte)   { return __pte(pte_val(pte) & ~APMMU_WRITE);}
+static pte_t apmmu_pte_mkclean(pte_t pte)     { return __pte(pte_val(pte) & ~APMMU_DIRTY);}
+static pte_t apmmu_pte_mkold(pte_t pte)       { return __pte(pte_val(pte) & ~APMMU_REF);}
+static pte_t apmmu_pte_mkwrite(pte_t pte)     { return __pte(pte_val(pte) | APMMU_WRITE);}
+static pte_t apmmu_pte_mkdirty(pte_t pte)     { return __pte(pte_val(pte) | APMMU_DIRTY);}
+static pte_t apmmu_pte_mkyoung(pte_t pte)     { return __pte(pte_val(pte) | APMMU_REF);}
+
+/*
+ * 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 pte_t apmmu_mk_pte(unsigned long page, pgprot_t pgprot)
+{ return __pte(((apmmu_v2p(page)) >> 4) | pgprot_val(pgprot)); }
+
+static pte_t apmmu_mk_pte_phys(unsigned long page, pgprot_t pgprot)
+{ return __pte(((page) >> 4) | pgprot_val(pgprot)); }
+
+static pte_t apmmu_mk_pte_io(unsigned long page, pgprot_t pgprot, int space)
+{
+	return __pte(((page) >> 4) | (space << 28) | pgprot_val(pgprot));
+}
+
+static void apmmu_ctxd_set(ctxd_t *ctxp, pgd_t *pgdp)
+{ 
+	set_pte((pte_t *)ctxp, (APMMU_ET_PTD | (apmmu_v2p((unsigned long) pgdp) >> 4)));
+}
+
+static void apmmu_pgd_set(pgd_t * pgdp, pmd_t * pmdp)
+{
+	set_pte((pte_t *)pgdp, (APMMU_ET_PTD | (apmmu_v2p((unsigned long) pmdp) >> 4)));
+}
+
+static void apmmu_pmd_set(pmd_t * pmdp, pte_t * ptep)
+{
+	set_pte((pte_t *)pmdp, (APMMU_ET_PTD | (apmmu_v2p((unsigned long) ptep) >> 4)));
+}
+
+static pte_t apmmu_pte_modify(pte_t pte, pgprot_t newprot)
+{
+	return __pte((pte_val(pte) & APMMU_CHG_MASK) | pgprot_val(newprot));
+}
+
+/* to find an entry in a top-level page table... */
+static pgd_t *apmmu_pgd_offset(struct mm_struct * mm, unsigned long address)
+{
+	return mm->pgd + ((address >> APMMU_PGDIR_SHIFT) & (APMMU_PTRS_PER_PGD - 1));
+}
+
+/* Find an entry in the second-level page table.. */
+static pmd_t *apmmu_pmd_offset(pgd_t * dir, unsigned long address)
+{
+	return (pmd_t *) apmmu_pgd_page(*dir) + ((address >> APMMU_PMD_SHIFT) & (APMMU_PTRS_PER_PMD - 1));
+}
+
+/* Find an entry in the third-level page table.. */ 
+static pte_t *apmmu_pte_offset(pmd_t * dir, unsigned long address)
+{
+	return (pte_t *) apmmu_pmd_page(*dir) + ((address >> PAGE_SHIFT) & (APMMU_PTRS_PER_PTE - 1));
+}
+
+/* This must update the context table entry for this process. */
+static void apmmu_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdp) 
+{
+	if(tsk->mm->context != NO_CONTEXT) {
+		flush_cache_mm(current->mm);
+		ctxd_set(&apmmu_context_table[tsk->mm->context], pgdp);
+		flush_tlb_mm(current->mm);
+	}
+}
+
+
+/* Accessing the MMU control register. */
+static inline unsigned int apmmu_get_mmureg(void)
+{
+        unsigned int retval;
+	__asm__ __volatile__("lda [%%g0] %1, %0\n\t" :
+			     "=r" (retval) :
+			     "i" (ASI_M_MMUREGS));
+	return retval;
+}
+
+static inline void apmmu_set_mmureg(unsigned long regval)
+{
+	__asm__ __volatile__("sta %0, [%%g0] %1\n\t" : :
+			     "r" (regval), "i" (ASI_M_MMUREGS) : "memory");
+
+}
+
+static inline void apmmu_set_ctable_ptr(unsigned long paddr)
+{
+	paddr = ((paddr >> 4) & APMMU_CTX_PMASK);
+        paddr |= (MEM_BUS_SPACE<<28);
+	__asm__ __volatile__("sta %0, [%1] %2\n\t" : :
+			     "r" (paddr), "r" (APMMU_CTXTBL_PTR),
+			     "i" (ASI_M_MMUREGS) :
+			     "memory");
+}
+
+static inline void apmmu_flush_whole_tlb(void)
+{
+	__asm__ __volatile__("sta %%g0, [%0] %1\n\t": :
+			     "r" (0x400),        /* Flush entire TLB!! */
+			     "i" (ASI_M_FLUSH_PROBE) : "memory");
+
+}
+
+/* These flush types are not available on all chips... */
+static inline void apmmu_flush_tlb_ctx(void)
+{
+	__asm__ __volatile__("sta %%g0, [%0] %1\n\t": :
+			     "r" (0x300),        /* Flush TLB ctx.. */
+			     "i" (ASI_M_FLUSH_PROBE) : "memory");
+
+}
+
+static inline void apmmu_flush_tlb_region(unsigned long addr)
+{
+	addr &= APMMU_PGDIR_MASK;
+	__asm__ __volatile__("sta %%g0, [%0] %1\n\t": :
+			     "r" (addr | 0x200), /* Flush TLB region.. */
+			     "i" (ASI_M_FLUSH_PROBE) : "memory");
+
+}
+
+
+static inline void apmmu_flush_tlb_segment(unsigned long addr)
+{
+	addr &= APMMU_PMD_MASK;
+	__asm__ __volatile__("sta %%g0, [%0] %1\n\t": :
+			     "r" (addr | 0x100), /* Flush TLB segment.. */
+			     "i" (ASI_M_FLUSH_PROBE) : "memory");
+
+}
+
+static inline void apmmu_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");
+
+}
+
+static inline unsigned long apmmu_hwprobe(unsigned long vaddr)
+{
+	unsigned long retval;
+
+	vaddr &= PAGE_MASK;
+	__asm__ __volatile__("lda [%1] %2, %0\n\t" :
+			     "=r" (retval) :
+			     "r" (vaddr | 0x400), "i" (ASI_M_FLUSH_PROBE));
+
+	return retval;
+}
+
+
+
+static inline void apmmu_uncache_page(unsigned long addr)
+{
+	pgd_t *pgdp = apmmu_pgd_offset(init_task.mm, addr);
+	pmd_t *pmdp;
+	pte_t *ptep;
+
+	if((pgd_val(*pgdp) & APMMU_ET_MASK) == APMMU_ET_PTE) {
+		ptep = (pte_t *) pgdp;
+	} else {
+		pmdp = apmmu_pmd_offset(pgdp, addr);
+		if((pmd_val(*pmdp) & APMMU_ET_MASK) == APMMU_ET_PTE) {
+			ptep = (pte_t *) pmdp;
+		} else {
+			ptep = apmmu_pte_offset(pmdp, addr);
+		}
+	}
+
+	flush_cache_page_to_uncache(addr);
+	set_pte(ptep, __pte((pte_val(*ptep) & ~APMMU_CACHE)));
+	flush_tlb_page_for_cbit(addr);
+}
+
+static inline void apmmu_recache_page(unsigned long addr)
+{
+	pgd_t *pgdp = apmmu_pgd_offset(init_task.mm, addr);
+	pmd_t *pmdp;
+	pte_t *ptep;
+
+	if((pgd_val(*pgdp) & APMMU_ET_MASK) == APMMU_ET_PTE) {
+		ptep = (pte_t *) pgdp;
+	} else {
+		pmdp = apmmu_pmd_offset(pgdp, addr);
+		if((pmd_val(*pmdp) & APMMU_ET_MASK) == APMMU_ET_PTE) {
+			ptep = (pte_t *) pmdp;
+		} else {
+			ptep = apmmu_pte_offset(pmdp, addr);
+		}
+	}
+	set_pte(ptep, __pte((pte_val(*ptep) | APMMU_CACHE)));
+	flush_tlb_page_for_cbit(addr);
+}
+
+static unsigned long apmmu_getpage(void)
+{
+	unsigned long page = get_free_page(GFP_KERNEL);
+
+	return page;
+}
+
+static inline void apmmu_putpage(unsigned long page)
+{
+	free_page(page);
+}
+
+/* The easy versions. */
+#define NEW_PGD() (pgd_t *) mmu_getpage()
+#define NEW_PMD() (pmd_t *) mmu_getpage()
+#define NEW_PTE() (pte_t *) mmu_getpage()
+#define FREE_PGD(chunk) apmmu_putpage((unsigned long)(chunk))
+#define FREE_PMD(chunk) apmmu_putpage((unsigned long)(chunk))
+#define FREE_PTE(chunk) apmmu_putpage((unsigned long)(chunk))
+
+/*
+ * 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.
+ */
+static void apmmu_pte_free_kernel(pte_t *pte)
+{
+	FREE_PTE(pte);
+}
+
+static pte_t *apmmu_pte_alloc_kernel(pmd_t *pmd, unsigned long address)
+{
+	address = (address >> PAGE_SHIFT) & (APMMU_PTRS_PER_PTE - 1);
+	if(apmmu_pmd_none(*pmd)) {
+		pte_t *page = NEW_PTE();
+		if(apmmu_pmd_none(*pmd)) {
+			if(page) {
+				pmd_set(pmd, page);
+				return page + address;
+			}
+			pmd_set(pmd, BAD_PAGETABLE);
+			return NULL;
+		}
+		FREE_PTE(page);
+	}
+	if(apmmu_pmd_bad(*pmd)) {
+		printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
+		pmd_set(pmd, BAD_PAGETABLE);
+		return NULL;
+	}
+	return (pte_t *) apmmu_pmd_page(*pmd) + address;
+}
+
+static void apmmu_pmd_free_kernel(pmd_t *pmd)
+{
+	FREE_PMD(pmd);
+}
+
+static pmd_t *apmmu_pmd_alloc_kernel(pgd_t *pgd, unsigned long address)
+{
+	address = (address >> APMMU_PMD_SHIFT) & (APMMU_PTRS_PER_PMD - 1);
+	if(apmmu_pgd_none(*pgd)) {
+		pmd_t *page;
+		page = NEW_PMD();
+		if(apmmu_pgd_none(*pgd)) {
+			if(page) {
+				pgd_set(pgd, page);
+				return page + address;
+			}
+			pgd_set(pgd, (pmd_t *) BAD_PAGETABLE);
+			return NULL;
+		}
+		FREE_PMD(page);
+	}
+	if(apmmu_pgd_bad(*pgd)) {
+		printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd));
+		pgd_set(pgd, (pmd_t *) BAD_PAGETABLE);
+		return NULL;
+	}
+	return (pmd_t *) pgd_page(*pgd) + address;
+}
+
+static void apmmu_pte_free(pte_t *pte)
+{
+	FREE_PTE(pte);
+}
+
+static pte_t *apmmu_pte_alloc(pmd_t * pmd, unsigned long address)
+{
+	address = (address >> PAGE_SHIFT) & (APMMU_PTRS_PER_PTE - 1);
+	if(apmmu_pmd_none(*pmd)) {
+		pte_t *page = NEW_PTE();
+		if(apmmu_pmd_none(*pmd)) {
+			if(page) {
+				pmd_set(pmd, page);
+				return page + address;
+			}
+			pmd_set(pmd, BAD_PAGETABLE);
+			return NULL;
+		}
+		FREE_PTE(page);
+	}
+	if(apmmu_pmd_bad(*pmd)) {
+		printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
+		pmd_set(pmd, BAD_PAGETABLE);
+		return NULL;
+	}
+	return ((pte_t *) apmmu_pmd_page(*pmd)) + address;
+}
+
+/* Real three-level page tables on APMMU. */
+static void apmmu_pmd_free(pmd_t * pmd)
+{
+	FREE_PMD(pmd);
+}
+
+static pmd_t *apmmu_pmd_alloc(pgd_t * pgd, unsigned long address)
+{
+	address = (address >> APMMU_PMD_SHIFT) & (APMMU_PTRS_PER_PMD - 1);
+	if(apmmu_pgd_none(*pgd)) {
+		pmd_t *page = NEW_PMD();
+		if(apmmu_pgd_none(*pgd)) {
+			if(page) {
+				pgd_set(pgd, page);
+				return page + address;
+			}
+			pgd_set(pgd, (pmd_t *) BAD_PAGETABLE);
+			return NULL;
+		}
+		FREE_PMD(page);
+	}
+	if(apmmu_pgd_bad(*pgd)) {
+		printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd));
+		pgd_set(pgd, (pmd_t *) BAD_PAGETABLE);
+		return NULL;
+	}
+	return (pmd_t *) apmmu_pgd_page(*pgd) + address;
+}
+
+static void apmmu_pgd_free(pgd_t *pgd)
+{
+	FREE_PGD(pgd);
+}
+
+static pgd_t *apmmu_pgd_alloc(void)
+{
+	return NEW_PGD();
+}
+
+static void apmmu_pgd_flush(pgd_t *pgdp)
+{
+}
+
+static void apmmu_set_pte_cacheable(pte_t *ptep, pte_t pteval)
+{
+	apmmu_set_entry(ptep, pte_val(pteval));
+}
+
+static void apmmu_quick_kernel_fault(unsigned long address)
+{
+	printk("Kernel faults at addr=0x%08lx\n", address);
+	printk("PTE=%08lx\n", apmmu_hwprobe((address & PAGE_MASK)));
+	die_if_kernel("APMMU bolixed...", current->tss.kregs);
+}
+
+static inline void alloc_context(struct task_struct *tsk)
+{
+	struct mm_struct *mm = tsk->mm;
+	struct ctx_list *ctxp;
+
+        if (tsk->taskid >= MPP_TASK_BASE) {
+		mm->context = MPP_CONTEXT_BASE + (tsk->taskid - MPP_TASK_BASE);
+		return;
+	}
+
+	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");
+	flush_cache_mm(ctxp->ctx_mm);
+	flush_tlb_mm(ctxp->ctx_mm);
+	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;
+}
+
+static inline void free_context(int context)
+{
+	struct ctx_list *ctx_old;
+
+	if (context >= MPP_CONTEXT_BASE)
+		return; /* nothing to do! */
+	
+	ctx_old = ctx_list_pool + context;
+	remove_from_ctx_list(ctx_old);
+	add_to_free_ctxlist(ctx_old);
+}
+
+
+static void apmmu_switch_to_context(struct task_struct *tsk)
+{
+	if(tsk->mm->context == NO_CONTEXT) {
+		alloc_context(tsk);
+		flush_cache_mm(current->mm);
+		ctxd_set(&apmmu_context_table[tsk->mm->context], tsk->mm->pgd);
+		flush_tlb_mm(current->mm);
+	}
+	apmmu_set_context(tsk->mm->context);
+}
+
+static char *apmmu_lockarea(char *vaddr, unsigned long len)
+{
+	return vaddr;
+}
+
+static void apmmu_unlockarea(char *vaddr, unsigned long len)
+{
+}
+
+struct task_struct *apmmu_alloc_task_struct(void)
+{
+	return (struct task_struct *) kmalloc(sizeof(struct task_struct), GFP_KERNEL);
+}
+
+static unsigned long apmmu_alloc_kernel_stack(struct task_struct *tsk)
+{
+	unsigned long kstk = __get_free_pages(GFP_KERNEL, 1, 0);
+
+	if(!kstk)
+		kstk = (unsigned long) vmalloc(PAGE_SIZE << 1);
+
+	return kstk;
+}
+
+static void apmmu_free_task_struct(struct task_struct *tsk)
+{
+	kfree(tsk);
+}
+
+static void apmmu_free_kernel_stack(unsigned long stack)
+{
+	if(stack < VMALLOC_START)
+		free_pages(stack, 1);
+	else
+		vfree((char *)stack);
+}
+
+static void apmmu_null_func(void)
+{
+}
+
+static inline void mc_tlb_flush_all(void)
+{
+	unsigned long long *tlb4k;
+	int i;
+	
+	tlb4k = (unsigned long long *)MC_MMU_TLB4K;
+	for (i = MC_MMU_TLB4K_SIZE/4; i > 0; --i) {
+		tlb4k[0] = 0;
+		tlb4k[1] = 0;
+		tlb4k[2] = 0;
+		tlb4k[3] = 0;
+		tlb4k += 4;
+	}
+}
+
+static inline void mc_tlb_flush_page(unsigned vaddr,int ctx) 
+{
+	if (ctx == SYSTEM_CONTEXT || MPP_IS_PAR_CTX(ctx)) {
+		*(((unsigned long long *)MC_MMU_TLB4K) + ((vaddr>>12)&0xFF)) = 0;
+	}
+}
+
+static inline void mc_tlb_flush_ctx(int ctx) 
+{
+	unsigned long long *tlb4k = (unsigned long long *)MC_MMU_TLB4K;
+	if (ctx == SYSTEM_CONTEXT || MPP_IS_PAR_CTX(ctx)) {
+		int i;
+		for (i=0; i<MC_MMU_TLB4K_SIZE;i++)
+			if (((tlb4k[i] >> 5) & 0xFFF) == ctx) tlb4k[i] = 0;
+	}
+}
+
+static inline void mc_tlb_flush_region(unsigned start,int ctx)
+{
+	mc_tlb_flush_ctx(ctx);
+}
+
+static inline void mc_tlb_flush_segment(unsigned start,int ctx)
+{
+	mc_tlb_flush_ctx(ctx);
+}
+
+static void viking_flush_tlb_all(void)
+{
+	module_stats.invall++;
+	flush_user_windows(); 	
+	apmmu_flush_whole_tlb();
+	mc_tlb_flush_all();
+}
+
+static void viking_flush_tlb_mm(struct mm_struct *mm)
+{
+	int octx;
+
+	module_stats.invmm++;
+
+	if(mm->context != NO_CONTEXT) {
+		flush_user_windows();
+		octx = apmmu_get_context();
+		if (octx != mm->context) 
+			apmmu_set_context(mm->context);
+		apmmu_flush_tlb_ctx();
+		mc_tlb_flush_ctx(mm->context);
+		if (octx != mm->context)
+			apmmu_set_context(octx);
+	}
+}
+
+static void viking_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
+{
+	int octx;
+
+	module_stats.invrnge++;
+
+	if(mm->context != NO_CONTEXT) {
+		flush_user_windows();
+		octx = apmmu_get_context();
+		if (octx != mm->context)
+			apmmu_set_context(mm->context);
+		if((end - start) < APMMU_PMD_SIZE) {
+			start &= PAGE_MASK;
+			while(start < end) {
+				apmmu_flush_tlb_page(start);
+				mc_tlb_flush_page(start,mm->context);
+				start += PAGE_SIZE;
+			}
+		} else if((end - start) < APMMU_PGDIR_SIZE) {
+			start &= APMMU_PMD_MASK;
+			while(start < end) {
+				apmmu_flush_tlb_segment(start);
+				mc_tlb_flush_segment(start,mm->context);
+				start += APMMU_PMD_SIZE;
+			}
+		} else {
+			start &= APMMU_PGDIR_MASK;
+			while(start < end) {
+				apmmu_flush_tlb_region(start);
+				mc_tlb_flush_region(start,mm->context);
+				start += APMMU_PGDIR_SIZE;
+			}
+		}
+		if (octx != mm->context)
+			apmmu_set_context(octx);
+	}
+}
+
+static void viking_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
+{
+	int octx;
+	struct mm_struct *mm = vma->vm_mm;
+
+	module_stats.invpg++;
+	if(mm->context != NO_CONTEXT) {
+		flush_user_windows();
+		octx = apmmu_get_context();
+		if (octx != mm->context)
+			apmmu_set_context(mm->context);
+		apmmu_flush_tlb_page(page);
+		mc_tlb_flush_page(page,mm->context);
+		if (octx != mm->context)
+			apmmu_set_context(octx);
+	}
+}
+
+static void viking_flush_tlb_page_for_cbit(unsigned long page)
+{
+	apmmu_flush_tlb_page(page);
+	mc_tlb_flush_page(page,apmmu_get_context());
+}
+
+/* Some dirty hacks to abstract away the painful boot up init. */
+static inline unsigned long apmmu_early_paddr(unsigned long vaddr)
+{
+	return (vaddr - KERNBASE);
+}
+
+static inline void apmmu_early_pgd_set(pgd_t *pgdp, pmd_t *pmdp)
+{
+	set_pte((pte_t *)pgdp, __pte((APMMU_ET_PTD | (apmmu_early_paddr((unsigned long) pmdp) >> 4))));
+}
+
+static inline void apmmu_early_pmd_set(pmd_t *pmdp, pte_t *ptep)
+{
+	set_pte((pte_t *)pmdp, __pte((APMMU_ET_PTD | (apmmu_early_paddr((unsigned long) ptep) >> 4))));
+}
+
+static inline unsigned long apmmu_early_pgd_page(pgd_t pgd)
+{
+	return ((pgd_val(pgd) & APMMU_PTD_PMASK) << 4) + KERNBASE;
+}
+
+static inline unsigned long apmmu_early_pmd_page(pmd_t pmd)
+{
+	return ((pmd_val(pmd) & APMMU_PTD_PMASK) << 4) + KERNBASE;
+}
+
+static inline pmd_t *apmmu_early_pmd_offset(pgd_t *dir, unsigned long address)
+{
+	return (pmd_t *) apmmu_early_pgd_page(*dir) + ((address >> APMMU_PMD_SHIFT) & (APMMU_PTRS_PER_PMD - 1));
+}
+
+static inline pte_t *apmmu_early_pte_offset(pmd_t *dir, unsigned long address)
+{
+	return (pte_t *) apmmu_early_pmd_page(*dir) + ((address >> PAGE_SHIFT) & (APMMU_PTRS_PER_PTE - 1));
+}
+
+__initfunc(static inline void apmmu_allocate_ptable_skeleton(unsigned long start, unsigned long end))
+{
+	pgd_t *pgdp;
+	pmd_t *pmdp;
+	pte_t *ptep;
+
+	while(start < end) {
+		pgdp = apmmu_pgd_offset(init_task.mm, start);
+		if(apmmu_pgd_none(*pgdp)) {
+			pmdp = sparc_init_alloc(&mempool, APMMU_PMD_TABLE_SIZE);
+			apmmu_early_pgd_set(pgdp, pmdp);
+		}
+		pmdp = apmmu_early_pmd_offset(pgdp, start);
+		if(apmmu_pmd_none(*pmdp)) {
+			ptep = sparc_init_alloc(&mempool, APMMU_PTE_TABLE_SIZE);
+			apmmu_early_pmd_set(pmdp, ptep);
+		}
+		start = (start + APMMU_PMD_SIZE) & APMMU_PMD_MASK;
+	}
+}
+
+
+__initfunc(static void make_page(unsigned virt_page, unsigned phys_page, unsigned prot))
+{
+	pgd_t *pgdp;
+	pmd_t *pmdp;
+	pte_t *ptep;
+	unsigned start = virt_page<<12;
+
+	pgdp = apmmu_pgd_offset(init_task.mm, start);
+	if(apmmu_pgd_none(*pgdp)) {
+		pmdp = sparc_init_alloc(&mempool, APMMU_PMD_TABLE_SIZE);
+		apmmu_early_pgd_set(pgdp, pmdp);
+	}
+	pmdp = apmmu_early_pmd_offset(pgdp, start);
+	if(apmmu_pmd_none(*pmdp)) {
+		ptep = sparc_init_alloc(&mempool, APMMU_PTE_TABLE_SIZE);
+		apmmu_early_pmd_set(pmdp, ptep);
+	}
+	ptep = apmmu_early_pte_offset(pmdp, start);
+	*ptep = __pte((phys_page<<8) | prot);
+}
+
+
+__initfunc(static void make_large_page(unsigned virt_page, unsigned phys_page, unsigned prot))
+{
+	pgd_t *pgdp;
+	unsigned start = virt_page<<12;
+
+	pgdp = apmmu_pgd_offset(init_task.mm, start);
+	*pgdp = __pgd((phys_page<<8) | prot);
+}
+
+
+__initfunc(static void ap_setup_mappings(void))
+{
+	unsigned Srwe = APMMU_PRIV | APMMU_VALID;
+	unsigned SrweUr = 0x14 | APMMU_VALID; /* weird! */
+
+	/* LBus */
+	make_large_page(0xfb000,0x9fb000,Srwe);
+	make_large_page(0xff000,0x9ff000,SrweUr); 
+	make_large_page(0xfc000,0x911000,Srwe);
+
+	/* MC Register */
+	make_page(0xfa000,0xb00000,SrweUr);
+	make_page(0xfa001,0xb00001,Srwe);
+	make_page(0xfa002,0xb00002,Srwe);
+	make_page(0xfa003,0xb00003,Srwe);
+	make_page(0xfa004,0xb00004,Srwe);
+	make_page(0xfa005,0xb00005,Srwe);
+	make_page(0xfa006,0xb00006,Srwe);
+	make_page(0xfa007,0xb00007,Srwe);
+  
+	/* MSC+ Register */
+	make_page(0xfa008,0xc00000,SrweUr);
+	make_page(0xfa009,0xc00001,Srwe);
+	make_page(0xfa00a,0xc00002,Srwe);
+	make_page(0xfa00b,0xc00003,Srwe);
+	make_page(0xfa00c,0xc00004,Srwe);
+	make_page(0xfa00d,0xc00005,Srwe); /* RBMPR 0 */
+	make_page(0xfa00e,0xc00006,Srwe);  /* RBMPR 1 */
+	make_page(0xfa00f,0xc00007,Srwe);  /* RBMPR 2 */
+
+	/* user queues */
+	make_page(MSC_PUT_QUEUE>>PAGE_SHIFT,  0xa00000,Srwe); 
+	make_page(MSC_GET_QUEUE>>PAGE_SHIFT,  0xa00001,Srwe); 
+	make_page(MSC_SEND_QUEUE>>PAGE_SHIFT, 0xa00040,Srwe); 
+	make_page(MSC_XY_QUEUE>>PAGE_SHIFT,   0xa00640,Srwe); 
+	make_page(MSC_X_QUEUE>>PAGE_SHIFT,    0xa00240,Srwe); 
+	make_page(MSC_Y_QUEUE>>PAGE_SHIFT,    0xa00440,Srwe); 
+	make_page(MSC_XYG_QUEUE>>PAGE_SHIFT,  0xa00600,Srwe); 
+	make_page(MSC_XG_QUEUE>>PAGE_SHIFT,   0xa00200,Srwe); 
+	make_page(MSC_YG_QUEUE>>PAGE_SHIFT,   0xa00400,Srwe); 
+	make_page(MSC_CSI_QUEUE>>PAGE_SHIFT,  0xa02004,Srwe); 
+	make_page(MSC_FOP_QUEUE>>PAGE_SHIFT,  0xa02005,Srwe); 
+	
+	/* system queues */
+	make_page(MSC_PUT_QUEUE_S>>PAGE_SHIFT,  0xa02000,Srwe); /* system put */
+	make_page(MSC_CPUT_QUEUE_S>>PAGE_SHIFT, 0xa02020,Srwe); /* system creg put */
+	make_page(MSC_GET_QUEUE_S>>PAGE_SHIFT,  0xa02001,Srwe); /* system get */
+	make_page(MSC_CGET_QUEUE_S>>PAGE_SHIFT, 0xa02021,Srwe); /* system creg get */
+	make_page(MSC_SEND_QUEUE_S>>PAGE_SHIFT, 0xa02040,Srwe); /* system send */
+	make_page(MSC_BSEND_QUEUE_S>>PAGE_SHIFT,0xa02640,Srwe); /* system send broad */
+	make_page(MSC_XYG_QUEUE_S>>PAGE_SHIFT,  0xa02600,Srwe); /* system put broad */  
+	make_page(MSC_CXYG_QUEUE_S>>PAGE_SHIFT, 0xa02620,Srwe); /* system put broad */  
+	
+	/* Direct queue access entries for refilling the MSC send queue */
+	make_page(MSC_SYSTEM_DIRECT>>PAGE_SHIFT, 0xa08000,Srwe);
+	make_page(MSC_USER_DIRECT>>PAGE_SHIFT, 0xa08001,Srwe);
+	make_page(MSC_REMOTE_DIRECT>>PAGE_SHIFT, 0xa08002,Srwe);
+	make_page(MSC_REPLY_DIRECT>>PAGE_SHIFT, 0xa08003,Srwe);
+	make_page(MSC_REMREPLY_DIRECT>>PAGE_SHIFT, 0xa08004,Srwe);
+
+	/* As above with end-bit set */
+	make_page(MSC_SYSTEM_DIRECT_END>>PAGE_SHIFT, 0xa0c000,Srwe);
+	make_page(MSC_USER_DIRECT_END>>PAGE_SHIFT, 0xa0c001,Srwe);
+	make_page(MSC_REMOTE_DIRECT_END>>PAGE_SHIFT, 0xa0c002,Srwe);
+	make_page(MSC_REPLY_DIRECT_END>>PAGE_SHIFT, 0xa0c003,Srwe);
+	make_page(MSC_REMREPLY_DIRECT_END>>PAGE_SHIFT, 0xa0c004,Srwe);
+}
+
+__initfunc(static void map_kernel(void))
+{
+	int phys;
+
+	/* the AP+ only ever has one bank of memory starting at address 0 */
+	ap_mem_size = sp_banks[0].num_bytes;
+	for (phys=0; phys < sp_banks[0].num_bytes; phys += APMMU_PGDIR_SIZE)
+		make_large_page((KERNBASE+phys)>>12,
+				(phys>>12),
+				APMMU_CACHE|APMMU_PRIV|APMMU_VALID);
+	init_task.mm->mmap->vm_start = page_offset = KERNBASE;
+	stack_top = page_offset - PAGE_SIZE;
+}
+
+extern unsigned long free_area_init(unsigned long, unsigned long);
+extern unsigned long sparc_context_init(unsigned long, int);
+
+extern int physmem_mapped_contig;
+extern int linux_num_cpus;
+
+void (*poke_apmmu)(void);
+
+__initfunc(unsigned long apmmu_paging_init(unsigned long start_mem, unsigned long end_mem))
+{
+	int i;
+
+	physmem_mapped_contig = 1;   /* for init.c:taint_real_pages()   */
+
+        num_contexts = AP_NUM_CONTEXTS;
+	mempool = PAGE_ALIGN(start_mem);
+	memset(swapper_pg_dir, 0, PAGE_SIZE);
+
+	apmmu_allocate_ptable_skeleton(KERNBASE, end_mem);
+	mempool = PAGE_ALIGN(mempool);
+	map_kernel();
+        ap_setup_mappings();
+
+	/* the MSC wants this aligned on a 16k boundary */
+	apmmu_context_table = 
+	  sparc_init_alloc(&mempool, 
+			   num_contexts*sizeof(ctxd_t)<0x4000?
+			   0x4000:
+			   num_contexts*sizeof(ctxd_t));
+	apmmu_ctx_table_phys = (ctxd_t *) apmmu_v2p((unsigned long) apmmu_context_table);
+	for(i = 0; i < num_contexts; i++)
+		ctxd_set(&apmmu_context_table[i], swapper_pg_dir);
+
+	start_mem = PAGE_ALIGN(mempool);
+
+	flush_cache_all();
+	apmmu_set_ctable_ptr((unsigned long) apmmu_ctx_table_phys);
+	flush_tlb_all();
+	poke_apmmu();
+
+	/* on the AP we don't put the top few contexts into the free
+	   context list as these are reserved for parallel tasks */
+	start_mem = sparc_context_init(start_mem, MPP_CONTEXT_BASE);
+	start_mem = free_area_init(start_mem, end_mem);
+
+	return PAGE_ALIGN(start_mem);
+}
+
+static char apmmuinfo[512];
+
+static char *apmmu_mmu_info(void)
+{
+	sprintf(apmmuinfo, "MMU type\t: %s\n"
+		"invall\t\t: %d\n"
+		"invmm\t\t: %d\n"
+		"invrnge\t\t: %d\n"
+		"invpg\t\t: %d\n"
+		"contexts\t: %d\n"
+		, apmmu_name,
+		module_stats.invall,
+		module_stats.invmm,
+		module_stats.invrnge,
+		module_stats.invpg,
+		num_contexts
+		);
+	return apmmuinfo;
+}
+
+static void apmmu_update_mmu_cache(struct vm_area_struct * vma, unsigned long address, pte_t pte)
+{
+}
+
+static void apmmu_exit_hook(void)
+{
+	struct mm_struct *mm = current->mm;
+
+	if(mm->context != NO_CONTEXT && mm->count == 1) {
+		ctxd_set(&apmmu_context_table[mm->context], swapper_pg_dir);
+		viking_flush_tlb_mm(mm);
+		free_context(mm->context);
+		mm->context = NO_CONTEXT;
+	}
+}
+
+static void apmmu_flush_hook(void)
+{
+	if(current->tss.flags & SPARC_FLAG_KTHREAD) {
+		alloc_context(current);
+		ctxd_set(&apmmu_context_table[current->mm->context], current->mm->pgd);
+		viking_flush_tlb_mm(current->mm);
+		apmmu_set_context(current->mm->context);
+	}
+}
+
+__initfunc(static void poke_viking(void))
+{
+	unsigned long mreg = apmmu_get_mmureg();
+
+	mreg |= VIKING_SPENABLE;
+	mreg |= (VIKING_ICENABLE | VIKING_DCENABLE);
+	mreg &= ~VIKING_ACENABLE;
+        mreg &= ~VIKING_SBENABLE;
+	mreg |= VIKING_TCENABLE;
+	apmmu_set_mmureg(mreg);
+}
+
+__initfunc(static void init_viking(void))
+{
+	apmmu_name = "TI Viking/AP1000";
+
+	flush_cache_page_to_uncache = apmmu_null_func;
+	flush_page_for_dma = apmmu_null_func;
+
+	flush_cache_all = apmmu_null_func;
+	flush_cache_mm = apmmu_null_func;
+	flush_cache_page = apmmu_null_func;
+	flush_cache_range = apmmu_null_func;
+
+	flush_tlb_all = viking_flush_tlb_all;
+	flush_tlb_mm = viking_flush_tlb_mm;
+	flush_tlb_page = viking_flush_tlb_page;
+	flush_tlb_range = viking_flush_tlb_range;
+
+	flush_page_to_ram = apmmu_null_func;
+	flush_sig_insns = apmmu_null_func;
+	flush_tlb_page_for_cbit = viking_flush_tlb_page_for_cbit;
+
+	poke_apmmu = poke_viking;
+}
+
+
+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);
+
+__initfunc(static void patch_window_trap_handlers(void))
+{
+	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);
+	PATCH_BRANCH(sparc_ttable[SP_TRAP_DACC].inst_three, srmmu_fault);
+}
+
+/* Load up routines and constants for sun4m mmu */
+__initfunc(void ld_mmu_apmmu(void))
+{
+	/* First the constants */
+	pmd_shift = APMMU_PMD_SHIFT;
+	pmd_size = APMMU_PMD_SIZE;
+	pmd_mask = APMMU_PMD_MASK;
+	pgdir_shift = APMMU_PGDIR_SHIFT;
+	pgdir_size = APMMU_PGDIR_SIZE;
+	pgdir_mask = APMMU_PGDIR_MASK;
+
+	ptrs_per_pte = APMMU_PTRS_PER_PTE;
+	ptrs_per_pmd = APMMU_PTRS_PER_PMD;
+	ptrs_per_pgd = APMMU_PTRS_PER_PGD;
+
+	page_none = APMMU_PAGE_NONE;
+	page_shared = APMMU_PAGE_SHARED;
+	page_copy = APMMU_PAGE_COPY;
+	page_readonly = APMMU_PAGE_RDONLY;
+	page_kernel = APMMU_PAGE_KERNEL;
+	pg_iobits = APMMU_VALID | APMMU_WRITE | APMMU_REF;
+	    
+	/* Functions */
+	mmu_getpage = apmmu_getpage;
+	set_pte = apmmu_set_pte_cacheable;
+	switch_to_context = apmmu_switch_to_context;
+	pmd_align = apmmu_pmd_align;
+	pgdir_align = apmmu_pgdir_align;
+	vmalloc_start = apmmu_vmalloc_start;
+
+	pte_page = apmmu_pte_page;
+	pmd_page = apmmu_pmd_page;
+	pgd_page = apmmu_pgd_page;
+
+	sparc_update_rootmmu_dir = apmmu_update_rootmmu_dir;
+
+	pte_none = apmmu_pte_none;
+	pte_present = apmmu_pte_present;
+	pte_clear = apmmu_pte_clear;
+
+	pmd_none = apmmu_pmd_none;
+	pmd_bad = apmmu_pmd_bad;
+	pmd_present = apmmu_pmd_present;
+	pmd_clear = apmmu_pmd_clear;
+
+	pgd_none = apmmu_pgd_none;
+	pgd_bad = apmmu_pgd_bad;
+	pgd_present = apmmu_pgd_present;
+	pgd_clear = apmmu_pgd_clear;
+
+	mk_pte = apmmu_mk_pte;
+	mk_pte_phys = apmmu_mk_pte_phys;
+	pgd_set = apmmu_pgd_set;
+	mk_pte_io = apmmu_mk_pte_io;
+	pte_modify = apmmu_pte_modify;
+	pgd_offset = apmmu_pgd_offset;
+	pmd_offset = apmmu_pmd_offset;
+	pte_offset = apmmu_pte_offset;
+	pte_free_kernel = apmmu_pte_free_kernel;
+	pmd_free_kernel = apmmu_pmd_free_kernel;
+	pte_alloc_kernel = apmmu_pte_alloc_kernel;
+	pmd_alloc_kernel = apmmu_pmd_alloc_kernel;
+	pte_free = apmmu_pte_free;
+	pte_alloc = apmmu_pte_alloc;
+	pmd_free = apmmu_pmd_free;
+	pmd_alloc = apmmu_pmd_alloc;
+	pgd_free = apmmu_pgd_free;
+	pgd_alloc = apmmu_pgd_alloc;
+	pgd_flush = apmmu_pgd_flush;
+
+	pte_write = apmmu_pte_write;
+	pte_dirty = apmmu_pte_dirty;
+	pte_young = apmmu_pte_young;
+	pte_wrprotect = apmmu_pte_wrprotect;
+	pte_mkclean = apmmu_pte_mkclean;
+	pte_mkold = apmmu_pte_mkold;
+	pte_mkwrite = apmmu_pte_mkwrite;
+	pte_mkdirty = apmmu_pte_mkdirty;
+	pte_mkyoung = apmmu_pte_mkyoung;
+	update_mmu_cache = apmmu_update_mmu_cache;
+	mmu_exit_hook = apmmu_exit_hook;
+	mmu_flush_hook = apmmu_flush_hook;
+	mmu_lockarea = apmmu_lockarea;
+	mmu_unlockarea = apmmu_unlockarea;
+
+	mmu_get_scsi_one = NULL;
+	mmu_get_scsi_sgl = NULL;
+	mmu_release_scsi_one = NULL;
+	mmu_release_scsi_sgl = NULL;
+
+	mmu_info = apmmu_mmu_info;
+        mmu_v2p = apmmu_v2p;
+        mmu_p2v = apmmu_p2v;
+
+	/* Task struct and kernel stack allocating/freeing. */
+	alloc_kernel_stack = apmmu_alloc_kernel_stack;
+	alloc_task_struct = apmmu_alloc_task_struct;
+	free_kernel_stack = apmmu_free_kernel_stack;
+	free_task_struct = apmmu_free_task_struct;
+
+	quick_kernel_fault = apmmu_quick_kernel_fault;
+
+	ctxd_set = apmmu_ctxd_set;
+	pmd_set = apmmu_pmd_set;
+
+	init_viking();
+	patch_window_trap_handlers();
+}
+
+
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/ap1000/approm.c linux/arch/sparc/ap1000/approm.c
--- v2.1.22/linux/arch/sparc/ap1000/approm.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/ap1000/approm.c	Sun Jan 26 12:07:06 1997
@@ -0,0 +1,148 @@
+  /*
+   * Copyright 1996 The Australian National University.
+   * Copyright 1996 Fujitsu Laboratories Limited
+   * 
+   * This software may be distributed under the terms of the Gnu
+   * Public License version 2 or later
+  */
+/*
+ * fake a really simple Sun prom for the AP+
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <asm/oplib.h>
+#include <asm/idprom.h> 
+#include <asm/machines.h> 
+#include <asm/ap1000/apservice.h> 
+
+static struct linux_romvec ap_romvec;
+static struct idprom ap_idprom;
+
+struct property {
+	char *name;
+	char *value;
+	int length;
+};
+
+struct node {
+	int level;
+	struct property *properties;
+};
+
+struct property null_properties = { NULL, NULL, -1 };
+
+struct property root_properties[] = {
+	{"device_type", "cpu", 4},
+	{"idprom",      (char *)&ap_idprom, sizeof(ap_idprom)},
+	{"banner-name", "Fujitsu AP1000+", 16},
+	{NULL, NULL, -1}
+};
+
+struct node nodes[] = {
+	{ 0, &null_properties }, 
+	{ 0, root_properties },
+	{ -1,&null_properties }
+};
+
+
+static int no_nextnode(int node)
+{
+	if (nodes[node].level == nodes[node+1].level)
+		return node+1;
+	return -1;
+}
+
+static int no_child(int node)
+{
+	if (nodes[node].level == nodes[node+1].level-1)
+		return node+1;
+	return -1;
+}
+
+static struct property *find_property(int node,char *name)
+{
+	struct property *prop = &nodes[node].properties[0];
+	while (prop && prop->name) {
+		if (strcmp(prop->name,name) == 0) return prop;
+		prop++;
+	}
+	return NULL;
+}
+
+static int no_proplen(int node,char *name)
+{
+	struct property *prop = find_property(node,name);
+	if (prop) return prop->length;
+	return -1;
+}
+
+static int no_getprop(int node,char *name,char *value)
+{
+	struct property *prop = find_property(node,name);
+	if (prop) {
+		memcpy(value,prop->value,prop->length);
+		return 1;
+	}
+	return -1;
+}
+
+static int no_setprop(int node,char *name,char *value,int len)
+{
+	return -1;
+}
+
+static char *no_nextprop(int node,char *name)
+{
+	struct property *prop = find_property(node,name);
+	if (prop) return prop[1].name;
+	return NULL;
+}
+
+
+static struct linux_nodeops ap_nodeops = {
+	no_nextnode,
+	no_child,
+	no_proplen,
+	no_getprop,
+	no_setprop,
+	no_nextprop
+};
+
+
+	
+static unsigned char calc_idprom_cksum(struct idprom *idprom)
+{
+        unsigned char cksum, i, *ptr = (unsigned char *)idprom;
+
+        for (i = cksum = 0; i <= 0x0E; i++)
+                cksum ^= *ptr++;
+
+        return cksum;
+}
+
+static int synch_hook;
+
+
+struct linux_romvec *ap_prom_init(void)
+{
+	memset(&ap_romvec,0,sizeof(ap_romvec));
+
+	ap_romvec.pv_romvers = 42;
+	ap_romvec.pv_nodeops = &ap_nodeops;
+	ap_romvec.pv_reboot = ap_reboot;
+	ap_romvec.pv_synchook = &synch_hook;
+
+	ap_idprom.id_format = 1;
+	ap_idprom.id_sernum = mpp_cid();
+	ap_idprom.id_machtype = SM_SUN4M_OBP;
+	ap_idprom.id_cksum = calc_idprom_cksum(&ap_idprom);
+
+	return &ap_romvec;
+}
+
+
+
+
+
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/ap1000/bnet.c linux/arch/sparc/ap1000/bnet.c
--- v2.1.22/linux/arch/sparc/ap1000/bnet.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/ap1000/bnet.c	Sun Jan 26 12:07:06 1997
@@ -0,0 +1,1204 @@
+  /*
+   * Copyright 1996 The Australian National University.
+   * Copyright 1996 Fujitsu Laboratories Limited
+   * 
+   * This software may be distributed under the terms of the Gnu
+   * Public License version 2 or later
+  */
+/* routines to control the AP1000 bif interface. This is the interface
+   used to talk to the front end processor */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <asm/ap1000/apservice.h>
+#include <asm/ap1000/apreg.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <asm/irq.h>
+#include <linux/skbuff.h>
+
+#define NET_DEBUG 0
+
+#define DUMMY_MSG_LEN 100
+#define DUMMY_MSG_WAIT 30
+
+#define MAX_CELLS 128
+
+#define HAVE_BIF() (BIF_IN(BIF_SDCSR) & BIF_SDCSR_BG)
+#define BIF_BUSY() (BIF_IN(BIF_SDCSR) & BIF_SDCSR_BB)
+
+#define SNET_ARBITRATION 0
+#define TOKEN_ARBITRATION 1
+
+#define DEBUG(x) 
+
+#if TOKEN_ARBITRATION
+static int have_token = 0;
+#endif
+
+extern struct cap_init cap_init;
+
+static int interrupt_driven = 0;
+static int use_dma = 0;
+struct pt_regs *bif_pt_regs = NULL;
+enum dma_state {DMA_IDLE,DMA_INCOMING,DMA_OUTGOING};
+static enum dma_state dma_state = DMA_IDLE;
+
+static int net_started = 0;
+static int waiting_for_bif = 0;
+static int queue_length = 0;
+
+static int drop_ip_packets = 0;
+
+#define DMA_THRESHOLD 64
+
+static struct cap_request bread_req;
+
+int tnet_ip_enabled = 1;
+
+#define BIF_DATA_WAITING() (BIF_IN(BIF_SDCSR) & BIF_SDCSR_RB)
+
+#define ROUND4(x)	(((x) + 3) & -4)
+
+static void bif_intr_receive(struct cap_request *req1);
+
+
+/* read some data from the bif */
+void read_bif(char *buf,int size) 
+{
+	unsigned *ibuf = (unsigned *)buf;
+	unsigned avail;
+
+	DEBUG(("|read_bif %d\n",size));
+	
+	if (dma_state != DMA_IDLE) ap_dma_wait(DMA_CH2);  
+	
+	size = (size+3) >> 2;
+
+	while (size > 4) {
+		while (!(avail=(BIF_IN(BIF_SDCSR) >> BIF_SDCSR_RB_SHIFT) & 7))
+			;
+		if (avail & 4) {
+			ibuf[0] = BIF_IN(BIF_DATA);
+			ibuf[1] = BIF_IN(BIF_DATA);
+			ibuf[2] = BIF_IN(BIF_DATA);
+			ibuf[3] = BIF_IN(BIF_DATA);
+			size -= 4; ibuf += 4;
+			continue;
+		}
+
+		if (avail & 2) {
+			ibuf[0] = BIF_IN(BIF_DATA);
+			ibuf[1] = BIF_IN(BIF_DATA);
+			size -= 2; ibuf += 2;
+			continue;
+		}
+		*ibuf++ = BIF_IN(BIF_DATA);
+		size--;
+	}
+
+	while (size--) {
+		while (!(BIF_IN(BIF_SDCSR) & BIF_SDCSR_RB)) ;
+		*ibuf++ = BIF_IN(BIF_DATA);
+	}
+
+	DEBUG(("|read bif done\n"));
+}
+
+/* throw out some data from the bif. This is usually called when we
+ don't have the resources to handle it immediately */
+void bif_toss(int size) 
+{
+	unsigned flags;
+	save_flags(flags); cli();
+
+	DEBUG(("|bif toss %d\n",size));
+
+	while (size>0) {
+		while (!BIF_DATA_WAITING());
+		BIF_IN(BIF_DATA);
+		size -= 4;
+	}    
+
+	DEBUG(("|bif toss done\n"));
+
+	restore_flags(flags);
+}
+
+
+static void bif_reset_interrupts(void)
+{
+	BIF_OUT(BIF_INTR,AP_INTR_WENABLE << BIF_INTR_GET_SH);
+	BIF_OUT(BIF_INTR,AP_INTR_WENABLE << BIF_INTR_HEADER_SH);
+}
+
+static void bif_mask_interrupts(void)
+{
+	BIF_OUT(BIF_INTR,(AP_INTR_MASK|AP_INTR_WENABLE) << BIF_INTR_GET_SH);
+	BIF_OUT(BIF_INTR,(AP_INTR_MASK|AP_INTR_WENABLE) << BIF_INTR_HEADER_SH);
+}
+
+static void attn_enable(void)
+{
+	BIF_OUT(BIF_INTR,AP_INTR_WENABLE << BIF_INTR_ATTN_SH);
+}
+
+static void attn_mask(void)
+{
+	BIF_OUT(BIF_INTR,(AP_INTR_MASK|AP_INTR_WENABLE) << BIF_INTR_ATTN_SH);
+}
+
+
+void ap_bif_status(void)
+{
+	static int bif_sdcsr;
+	static int bif_intr;
+	static int bif_mhocr;
+	static int bif_x0sk;
+	static int bif_xsk;
+	static int bif_xsz;
+	static int bif_y0sk;
+	static int bif_ysk;
+	static int bif_ysz;
+	static int bif_cx0sk;
+	static int bif_cxsk;
+	static int bif_cxsz;
+	static int bif_cy0sk;
+	static int bif_cysk;
+	static int bif_cysz;
+	static int bif_ttl;
+	static int bif_cttl;
+	static int bif_header;
+	
+	bif_sdcsr = BIF_IN(BIF_SDCSR);
+	bif_intr  = BIF_IN(BIF_INTR);
+	bif_mhocr = BIF_IN(BIF_MHOCR);
+	
+	bif_x0sk  = BIF_IN(BIF_X0SK);
+	bif_xsk   = BIF_IN(BIF_XSK);
+	bif_xsz   = BIF_IN(BIF_XSZ);
+	bif_y0sk  = BIF_IN(BIF_Y0SK);
+	bif_ysk   = BIF_IN(BIF_YSK);
+	bif_ysz   = BIF_IN(BIF_YSZ);
+	
+	bif_cx0sk  = BIF_IN(BIF_CX0SK);
+	bif_cxsk   = BIF_IN(BIF_CXSK);
+	bif_cxsz   = BIF_IN(BIF_CXSZ);
+	bif_cy0sk  = BIF_IN(BIF_CY0SK);
+	bif_cysk   = BIF_IN(BIF_CYSK);
+	bif_cysz   = BIF_IN(BIF_CYSZ);
+	
+	bif_ttl   = BIF_IN(BIF_TTL);
+	bif_cttl  = BIF_IN(BIF_CTTL);
+	bif_header = BIF_IN(BIF_HEADER);
+
+	printk("|\t***** BIF REG. *****\n");
+	printk("|\tBIF_SDCSR  = %08x  ", bif_sdcsr);
+	if(bif_sdcsr & BIF_SDCSR_CN) printk("|<BUS DISCONNECT>");
+	if(bif_sdcsr & BIF_SDCSR_FN) printk("|<SC/GA ENABLE>");
+	if(bif_sdcsr & BIF_SDCSR_DE) printk("|<DMA ENABLE>");
+	if(bif_sdcsr & BIF_SDCSR_DR) printk("|<GATHER>");
+	if(bif_sdcsr & BIF_SDCSR_BB) printk("|<BUS BSY>");
+	if(bif_sdcsr & BIF_SDCSR_BR) printk("|<BUS REQ>");
+	if(bif_sdcsr & BIF_SDCSR_BG) printk("|<BUS GET>");
+	if(bif_sdcsr & BIF_SDCSR_ER) printk("|<ERROR:");
+	if(bif_sdcsr & BIF_SDCSR_SP) printk("|SYNC PARITY:");
+	if(bif_sdcsr & BIF_SDCSR_LP) printk("|LBUS PARITY:");
+	if(bif_sdcsr & BIF_SDCSR_LR) printk("|READ EMPTY FIFO:");
+	if(bif_sdcsr & BIF_SDCSR_LW) printk("|WRITE FULL FIFO:");
+	if(bif_sdcsr & BIF_SDCSR_AL) printk("|READ ENDBIT:");
+	if(bif_sdcsr & BIF_SDCSR_SS) printk("|SET MASK SSTAT:");
+	if(bif_sdcsr & BIF_SDCSR_SC) printk("|CLR SSYNC ILLEGALLY:");
+	if(bif_sdcsr & BIF_SDCSR_SY) printk("|REQ SSYNC ILLEGALLY:");
+	if(bif_sdcsr & BIF_SDCSR_FS) printk("|SET MASK FSTAT:");
+	if(bif_sdcsr & BIF_SDCSR_FC) printk("|CLR FSYNC ILLEGALLY:");
+	if(bif_sdcsr & BIF_SDCSR_FY) printk("|REQ FSYNC ILLEGALLY:");
+	if(bif_sdcsr & BIF_SDCSR_CP) printk("|BNET PARITY:");
+	if(bif_sdcsr & BIF_SDCSR_FP) printk("|FE NOT SET WHEN SC/GA:");
+	if(bif_sdcsr & BIF_SDCSR_PS) printk("|RECV PACKET ILLEGALLY:");
+	if(bif_sdcsr & BIF_SDCSR_RA) printk("|CHANGE FE ILLEGALLY:");
+	if(bif_sdcsr & BIF_SDCSR_PA) printk("|SEND/RECV ILLEGALLY:");
+	if(bif_sdcsr & BIF_SDCSR_DL) printk("|DATA LOST:");
+	if(bif_sdcsr & BIF_SDCSR_ER) printk("|>");
+	if(bif_sdcsr & BIF_SDCSR_PE) printk("|<SYNC PARITY ENABLE>");
+	printk("|\n");
+	printk("|\tBIF_INTR   = %08x\n", bif_intr);
+	printk("|\tBIF_MHOCR  = %08x\n", bif_mhocr);
+
+	printk("|\tBIF_X0SK   = %08x\n", bif_x0sk);
+	printk("|\tBIF_XSK    = %08x\n", bif_xsk);
+	printk("|\tBIF_XSZ    = %08x\n", bif_xsz);
+	printk("|\tBIF_Y0SK   = %08x\n", bif_y0sk);
+	printk("|\tBIF_YSK    = %08x\n", bif_ysk);
+	printk("|\tBIF_YSZ    = %08x\n", bif_ysz);
+	printk("|\tBIF_CX0SK  = %08x\n", bif_cx0sk);
+	printk("|\tBIF_CXSK   = %08x\n", bif_cxsk);
+	printk("|\tBIF_CXSZ   = %08x\n", bif_cxsz);
+	printk("|\tBIF_CY0SK  = %08x\n", bif_cy0sk);
+	printk("|\tBIF_CYSK   = %08x\n", bif_cysk);
+	printk("|\tBIF_CYSZ   = %08x\n", bif_cysz);
+
+	printk("|\tBIF_TTL    = %08x\n", bif_ttl);
+	printk("|\tBIF_CTTL   = %08x\n", bif_cttl);
+	printk("|\tBIF_HEADER = %08x\n", bif_header);
+}
+
+
+void bif_led_status(void)
+{
+#if 1
+	static int i = 0;
+	unsigned char res = 0;
+
+	switch (i) {
+	case 0: 
+	case 2: 
+		res = 0xff;
+		break;
+	case 1: 
+	case 3: 
+		res = 0;
+		break;
+	default:
+		res = 0xFF & (BIF_IN(BIF_SDCSR) >> (((i-4)/4)*8));
+	}
+	i = (i+1) % 20;
+
+	ap_led(res);
+#endif
+}
+
+static void get_bif(void)
+{
+	if (HAVE_BIF())
+		return;
+
+	drop_ip_packets = 1;
+
+	DEBUG(("|get_bif started\n"));
+
+	if (dma_state != DMA_IDLE) 
+		ap_dma_wait(DMA_CH2);  
+
+#if SNET_ARBITRATION
+	/* wait till the host doesn't want the BIF anymore, tossing
+	   any data that arrives */
+	while (BIF_IN(FSTT_CLR) & HOST_STATUS_BIT) 
+		if (BIF_IN(BIF_SDCSR) & BIF_SDCSR_RB)
+			bif_intr_receive(NULL);
+	waiting_for_bif = 0;
+#endif
+
+#if TOKEN_ARBITRATION
+	BIF_OUT(FSTT_CLR,HOST_STATUS_BIT);
+#endif
+
+	/* request the BIF */
+	BIF_OUT(BIF_SDCSR,BIF_SDCSR_BR);
+
+	/* loop waiting for us to get the BIF, tossing any data */
+	while (!HAVE_BIF())
+		if (BIF_IN(BIF_SDCSR) & BIF_SDCSR_RB)
+			bif_intr_receive(NULL);
+
+	bif_reset_interrupts();
+	if (!interrupt_driven)
+		bif_mask_interrupts();
+
+	drop_ip_packets = 0;
+
+#if TOKEN_ARBITRATION
+	BIF_OUT(FSTT_SET,HOST_STATUS_BIT);
+#endif
+
+	DEBUG(("|get_bif done\n"));
+}
+
+
+/* write a message to the front end over the Bnet. This can be in
+   multiple parts, as long as the first part sets "start" and the last
+   part sets "end". The bus will be grabbed while this is going on 
+   */
+static void write_bif(char *buf,int size,int start,int end)
+{
+	unsigned *ibuf;
+	unsigned avail;
+
+	DEBUG(("|write_bif %d %d %d\n",size,start,end));
+
+	if (start) {
+		/* a dma op may be in progress */
+		if (dma_state != DMA_IDLE) ap_dma_wait(DMA_CH2);
+	}
+
+	size = (size+3) >> 2;
+	ibuf = (unsigned *)buf;
+	if (end) size--;
+
+	while (size > 4) {
+		while (!(avail=(BIF_IN(BIF_SDCSR) >> BIF_SDCSR_TB_SHIFT) & 7))
+			;
+		if (avail & 4) {
+			BIF_OUT(BIF_DATA,ibuf[0]);
+			BIF_OUT(BIF_DATA,ibuf[1]);
+			BIF_OUT(BIF_DATA,ibuf[2]);
+			BIF_OUT(BIF_DATA,ibuf[3]);
+			size -= 4; ibuf += 4;
+			continue;
+		}
+
+		if (avail & 2) {
+			BIF_OUT(BIF_DATA,ibuf[0]);
+			BIF_OUT(BIF_DATA,ibuf[1]);
+			size -= 2; ibuf += 2;
+			continue;
+		}
+		BIF_OUT(BIF_DATA,ibuf[0]);
+		ibuf++; size--;
+	}
+
+	while (size--) {
+		while (!(BIF_IN(BIF_SDCSR) & BIF_SDCSR_TB)) ;
+		BIF_OUT(BIF_DATA,ibuf[0]);
+		ibuf++;
+	}
+
+	if (end) {
+		while (!(BIF_IN(BIF_SDCSR) & BIF_SDCSR_TB)) ;
+		BIF_OUT(BIF_EDATA,*ibuf);
+	}
+
+	DEBUG(("|write bif done\n"));
+}
+
+#if TOKEN_ARBITRATION
+static void forward_token(void)
+{
+	struct cap_request req;
+	req.cid = mpp_cid();
+	req.type = REQ_BIF_TOKEN;
+	req.size = sizeof(req);
+	if (req.cid == cap_init.numcells - 1)
+		req.header = MAKE_HEADER(HOST_CID);
+	else
+		req.header = MAKE_HEADER(req.cid + 1);
+	
+	write_bif((char *)&req,sizeof(req),1,1);
+	have_token = 0;
+}
+#endif
+
+static void release_bif(void)
+{
+	static int dummy[DUMMY_MSG_LEN];
+
+	waiting_for_bif = 0;
+
+#if SNET_ARBITRATION
+	/* mask the attention interrupt */
+	attn_mask();
+#endif
+
+	/* maybe we don't have it?? */
+	if (!HAVE_BIF())
+		return;
+
+	DEBUG(("|release bif started\n"));
+
+	if (dma_state != DMA_IDLE) ap_dma_wait(DMA_CH2);  
+
+#if TOKEN_ARBITRATION
+	if (have_token) 
+		forward_token();	
+#endif
+
+#if 1
+	/* send a dummy message to ensure FIFO flushing
+	   (suggestion from woods to overcome bif release
+	   hardware bug) */
+	dummy[0] = 0xEEEE4000;
+	write_bif((char *)dummy,DUMMY_MSG_LEN,1,1);
+#endif
+	/* wait till the send FIFO is completely empty */
+	while (!((BIF_IN(BIF_SDCSR) & BIF_SDCSR_TB) == BIF_SDCSR_TB)) ;   
+
+	/* wait another few us */
+	udelay(DUMMY_MSG_WAIT);
+
+	/* send release-data */
+	BIF_OUT(BIF_DATA,BIF_HEADER_RS);
+	
+	/* wait until we don't have the bus */
+	while (HAVE_BIF()) ;
+
+	DEBUG(("|release bif done\n"));
+}
+
+
+/* wait for a particular request type - throwing away anything else! */
+void ap_wait_request(struct cap_request *req,int type)
+{
+	drop_ip_packets = 1;
+	do {
+		while (!BIF_DATA_WAITING())
+			if (HAVE_BIF()) release_bif();
+		read_bif((char *)req,sizeof(*req));		
+		if (req->type != type) {
+			bif_intr_receive(req);
+		}
+	} while (req->type != type);
+	drop_ip_packets = 0;
+}
+
+
+void write_bif_polled(char *buf1,int len1,char *buf2,int len2)
+{
+	unsigned flags;
+	save_flags(flags); cli();
+
+	get_bif();
+	write_bif(buf1,len1,1,(buf2&&len2)?0:1);
+	if (buf2 && len2)
+		write_bif(buf2,len2,0,1);
+	release_bif();
+	restore_flags(flags);
+}
+
+static void want_bif(void)
+{
+	unsigned flags;
+
+	save_flags(flags); cli();
+
+	/* maybe we've already got it */
+	if (HAVE_BIF()) {
+		waiting_for_bif = 0;
+		restore_flags(flags);
+		return;
+	}
+
+#if SNET_ARBITRATION	
+	if (interrupt_driven)
+		attn_enable();
+
+	/* check if the host wants it */
+	if (BIF_IN(FSTT_CLR) & HOST_STATUS_BIT) {
+		/* the host wants it - don't get it yet  */
+		waiting_for_bif = 1;
+	} else {
+		/* the host doesn't want it - just set bus request */
+		waiting_for_bif = 0;
+		BIF_OUT(BIF_SDCSR,BIF_SDCSR_BR);
+		while (!HAVE_BIF() && !BIF_BUSY()) ;
+		DEBUG(("|set bif request\n"));
+	}
+	restore_flags(flags);
+	return;
+#endif
+
+#if TOKEN_ARBITRATION
+	if (net_started && !have_token) {
+		BIF_OUT(FSTT_CLR,HOST_STATUS_BIT);
+		restore_flags(flags);
+		return;
+	}
+	BIF_OUT(FSTT_SET,HOST_STATUS_BIT);
+#endif
+
+	BIF_OUT(BIF_SDCSR,BIF_SDCSR_BR);
+	restore_flags(flags);
+}
+
+#define BIF_NOCOPY (1<<0)
+
+/* a queue of requests that need to be sent over the bif. Needs to be
+modified sometime to allow the direct queueing of skb's */
+struct bif_queue {
+	volatile struct bif_queue *next;
+	struct cap_request req;
+	char *data;
+	int data_size;
+	int flags;
+};
+
+static volatile struct bif_queue *bif_queue_top = NULL;
+static volatile struct bif_queue *bif_queue_end = NULL;
+
+static struct sk_buff *skb_out = NULL;
+static struct sk_buff *skb_in = NULL;
+static char *bif_dma_data = NULL;
+static int bif_dma_out_size = 0;
+
+
+/* send waiting elements. Called mainly when we get a bif "bus get"
+   interrupt to say we now have the bus */
+static void bif_intr_runqueue(void)
+{
+	unsigned flags;
+	
+	/* if I don't have the bus then return */
+	if (!HAVE_BIF())
+		return;
+	
+	if (dma_state != DMA_IDLE) return;
+	
+	save_flags(flags); cli();
+	
+	while (bif_queue_top) {
+		volatile struct bif_queue *q = bif_queue_top;
+		bif_queue_top = q->next;
+
+		/* printk("|queue run (length=%d)\n",queue_length); */
+		queue_length--;
+
+		if (!q->data) {
+			/* use programmed IO for small requests */
+			write_bif((char *)&q->req,sizeof(q->req),1,1);
+			kfree_s((char *)q,sizeof(*q));
+			continue;
+		}
+
+		if (q->flags & BIF_NOCOPY) {
+			write_bif((char *)&q->req,sizeof(q->req),1,0);
+		}
+
+		if (use_dma && q->data_size > DMA_THRESHOLD) {
+			dma_state = DMA_OUTGOING;
+			if (q->req.type == REQ_IP) {
+				skb_out = (struct sk_buff *)q->data;
+				ap_dma_go(DMA_CH2,(unsigned)skb_out->data,
+					  q->data_size,DMA_DCMD_TD_MD);
+			} else {
+				if (!(q->flags & BIF_NOCOPY)) {
+					bif_dma_data = q->data;
+					bif_dma_out_size = q->data_size;
+				}
+				ap_dma_go(DMA_CH2,(unsigned)q->data,
+					  q->data_size,DMA_DCMD_TD_MD);
+			}
+			kfree_s((char *)q,sizeof(*q));
+			restore_flags(flags);
+			return; /* wait for DMA to complete */
+		} 
+
+		if (q->req.type == REQ_IP) {
+			struct sk_buff *skb = (struct sk_buff *)q->data;
+			write_bif(skb->data,q->data_size,1,1);       
+			dev_kfree_skb(skb, FREE_WRITE);
+		} else {
+			write_bif(q->data,q->data_size,1,1);
+			if (!(q->flags & BIF_NOCOPY))
+				kfree_s(q->data,q->data_size);	
+		}
+		kfree_s((char *)q,sizeof(*q));
+	}
+  
+	/* I don't want the bus now */
+	release_bif(); 
+	restore_flags(flags);
+}
+
+
+static void queue_attach(struct bif_queue *q)
+{
+	unsigned flags;
+	save_flags(flags); cli();
+	
+	/* attach it to the end of the queue */
+	if (!bif_queue_top) {
+		bif_queue_top = q;
+	} else {
+		bif_queue_end->next = q;
+	}
+	bif_queue_end = q;
+
+	queue_length++;
+
+	/* printk("|queue add (length=%d)\n",queue_length); */
+
+	/* tell the bus we want access */
+	want_bif();
+
+	restore_flags(flags);  
+}
+
+
+/* queue an element for sending over the bif. */
+int bif_queue(struct cap_request *req,char *buf,int bufsize)
+{
+	struct bif_queue *q;
+
+	if (req->header == 0)
+		req->header = MAKE_HEADER(HOST_CID);
+	
+	/* if we aren't running interrupt driven then just send it 
+	   immediately */
+	if (!interrupt_driven) {
+		write_bif_polled((char *)req,sizeof(*req),buf,bufsize);
+		return(0);
+	}
+
+	/* allocate a queue element */
+	q = (struct bif_queue *)kmalloc(sizeof(*q), GFP_ATOMIC);
+	if (!q) {
+		/* yikes! */
+		return(-ENOMEM);
+	}
+	
+	q->flags = 0;
+	q->data = NULL;
+	q->data_size = 0;
+	
+	if (buf && bufsize>0) {
+		q->data_size = bufsize+sizeof(*req);
+		q->data = (char *)kmalloc(q->data_size,GFP_ATOMIC);
+		if (!q->data) {
+			kfree_s(q,sizeof(*q));
+			return(-ENOMEM);
+		}
+	}
+
+	q->req = *req;
+	if (buf&&bufsize) {
+		memcpy(q->data,(char *)req,sizeof(*req));
+		memcpy(q->data+sizeof(*req),buf,bufsize);
+	}
+	q->next = NULL;
+	
+	queue_attach(q);
+
+	return(0);
+}
+
+
+/* queue an element for sending over the bif. */
+int bif_queue_nocopy(struct cap_request *req,char *buf,int bufsize)
+{
+	struct bif_queue *q;
+
+	if (req->header == 0)
+		req->header = MAKE_HEADER(HOST_CID);
+	
+	/* allocate a queue element */
+	q = (struct bif_queue *)kmalloc(sizeof(*q), GFP_ATOMIC);
+	if (!q) {
+		return(-ENOMEM);
+	}
+	
+	q->data = buf;
+	q->data_size = bufsize;
+	q->flags = BIF_NOCOPY;
+	q->req = *req;
+	q->next = NULL;
+	
+	queue_attach(q);
+
+	return(0);
+}
+
+
+/* put an IP packet into the bif queue */
+int bif_send_ip(int cid, struct sk_buff *skb)
+{
+	struct cap_request *req = (struct cap_request *)skb->data;
+	struct bif_queue *q;
+	u_long destip;
+
+	destip = *(u_long *)(skb->data+sizeof(*req)+16);
+
+	if (cid != -1) {
+		req->header = MAKE_HEADER(cid);
+	} else if (destip == (cap_init.baseIP | ~cap_init.netmask)) {
+		req->header = BIF_HEADER_IN | BIF_HEADER_BR;    
+	} else {
+		req->header = MAKE_HEADER(HOST_CID);    
+	}
+	
+	/* allocate a queue element */
+	q = (struct bif_queue *)kmalloc(sizeof(*q), GFP_ATOMIC);
+	if (!q) {
+		/* yikes! */
+		dev_kfree_skb(skb, FREE_WRITE);
+		return(-ENOMEM);
+	}
+	
+	req->size = ROUND4(skb->len);
+	req->cid = mpp_cid();
+	req->type = REQ_IP;
+
+	q->data = (char *)skb;
+	q->data_size = req->size;
+	q->next = NULL;
+	q->req = *req;
+	q->flags = 0;
+	
+	queue_attach(q);
+	
+	return(0);
+}
+
+
+/* send an OPENNET request to tell the front end to open the apnet
+   network interface */
+void start_apnet(void)
+{
+	struct cap_request req;
+	req.cid = mpp_cid();
+	req.type = REQ_OPENNET;
+	req.size = sizeof(req);
+	req.header = MAKE_HEADER(HOST_CID);
+	
+	bif_queue(&req,NULL,0);
+	printk("sent start_apnet request\n");
+}
+
+/* we have received an IP packet - pass it to the bif network
+   interface code */
+static void reply_ip(struct cap_request *req)
+{
+	if (drop_ip_packets || 
+	    !(skb_in = dev_alloc_skb(req->size - sizeof(*req)))) {
+		bif_toss(req->size - sizeof(*req));
+		return;
+	}
+
+	if (use_dma && req->size > DMA_THRESHOLD) {
+		dma_state = DMA_INCOMING;
+		ap_dma_go(DMA_CH2,
+			  (unsigned)skb_put(skb_in,req->size - sizeof(*req)),
+			  req->size - sizeof(*req),DMA_DCMD_TD_DM);
+	} else {
+		read_bif(skb_put(skb_in,req->size - sizeof(*req)),
+			 req->size - sizeof(*req));
+		bif_rx(skb_in);
+		skb_in = NULL;
+	}
+}
+
+
+/* we have received a bread block - DMA it in */
+static void reply_bread(struct cap_request *req)
+{
+	extern char *ap_buffer(struct cap_request *creq);
+	char *buffer;
+	
+	buffer = ap_buffer(req);
+	bread_req = *req;
+	
+	if (use_dma) {
+		dma_state = DMA_INCOMING;
+		ap_dma_go(DMA_CH2,
+			  (unsigned)buffer,req->size - sizeof(*req),
+			  DMA_DCMD_TD_DM);
+	} else {
+		read_bif(buffer,req->size - sizeof(*req));
+		ap_complete(&bread_req);
+		bread_req.type = -1;	  
+	}
+}
+
+
+static struct debug_key {
+	struct debug_key *next;
+	char key;
+	void (*fn)(void);
+	char *description;
+} *debug_keys = NULL;
+
+
+void show_debug_keys(void)
+{
+	struct debug_key *r;
+	for (r=debug_keys;r;r=r->next)
+		printk("%c: %s\n",r->key,r->description);
+}
+
+
+void bif_add_debug_key(char key,void (*fn)(void),char *description)
+{
+	struct debug_key *r,*r2;
+	r = (struct debug_key *)kmalloc(sizeof(*r),GFP_ATOMIC);
+	if (r) {
+		r->next = NULL;
+		r->key = key;
+		r->fn = fn;
+		r->description = description;
+		if (!debug_keys) {
+			debug_keys = r;
+		} else {
+			for (r2=debug_keys;
+			     r2->next && r2->key != key;r2=r2->next) ;
+
+			if (r2->key == key) {
+				r2->fn = fn;
+				r2->description = description;
+				kfree_s(r,sizeof(*r));
+			} else {
+				r2->next = r;
+			}
+		}
+	}
+}
+
+/* these are very useful for debugging ! */
+static void reply_putchar(struct cap_request *req)
+{  
+	struct debug_key *r;
+
+	char c = req->data[0];
+
+	ap_set_user(req->data[1]);
+
+	for (r=debug_keys;r;r=r->next)
+		if (r->key == c) {
+			r->fn();
+			break;
+		}      
+	if (!r)
+		printk("cell %d got character %d [%c]\n",mpp_cid(),(int)c,c);
+
+	ap_set_user(-1);
+}
+
+
+/* send a signal to a task by name or pid */
+static void reply_kill(struct cap_request *req)
+{  
+  int sig = req->data[0];
+  struct task_struct *p;
+  int len;
+  char name[32];
+
+  len = req->size - sizeof(*req);
+  if (len == 0) {
+    int pid = req->data[1];
+    for_each_task(p) 
+      if (p->pid == pid) {
+	send_sig(sig,p,1);
+	return;
+      }
+    printk("cell %d: no task with pid %d\n",mpp_cid(),pid);
+    return;
+  }
+
+  if (len > sizeof(name)-1) {
+    bif_toss(len);
+    return;
+  }
+
+  read_bif(name,len);
+  name[len] = 0;
+
+  for_each_task(p) 
+    if (strcmp(name,p->comm) == 0)
+      send_sig(sig,p,1);
+}
+
+
+static struct req_list {
+	struct req_list *next;
+	int type;
+	void (*fn)(struct cap_request *);
+} *reg_req_list = NULL;
+
+
+void bif_register_request(int type,void (*fn)(struct cap_request *))
+{
+	struct req_list *r,*r2;
+	r = (struct req_list *)kmalloc(sizeof(*r),GFP_ATOMIC);
+	if (r) {
+		r->next = NULL;
+		r->type = type;
+		r->fn = fn;
+		if (!reg_req_list) {
+			reg_req_list = r;
+		} else {
+			for (r2=reg_req_list;
+			     r2->next && r2->type != type;r2=r2->next) ;
+
+			if (r2->type == type) {
+				r2->fn = fn;
+				kfree_s(r,sizeof(*r));
+			} else {
+				r2->next = r;
+			}
+		}
+	}
+}
+
+
+
+/* a request has come in on the bif - process it */
+static void bif_intr_receive(struct cap_request *req1)
+{
+	struct req_list *r;
+	extern void ap_open_reply(struct cap_request *creq);  
+	struct cap_request req;
+
+	if (req1) {
+		req = *req1;
+	} else {
+		/* read the main cap request header */
+		read_bif((char *)&req,sizeof(req));
+	}
+
+	/* service it */
+	switch (req.type)
+	{
+	case REQ_PUTCHAR:
+		reply_putchar(&req);
+		break;
+	case REQ_KILL:
+		reply_kill(&req);
+		break;
+	case REQ_BREAK:
+		breakpoint();
+		break;
+	case REQ_IP:
+		reply_ip(&req);
+		break;
+#if TOKEN_ARBITRATION
+	case REQ_BIF_TOKEN:
+		have_token = 1;
+		want_bif();
+		break;
+#endif
+	case REQ_OPENNET:
+		net_started = 1;
+		break;
+	case REQ_BREAD:
+		reply_bread(&req);
+		break;
+	case REQ_BOPEN:
+		ap_open_reply(&req);
+		break;
+	case REQ_BWRITE:
+		ap_complete(&req);
+		break;
+	case REQ_SCHEDULE:
+		mpp_schedule(&req);
+		break;
+
+	default:
+		for (r=reg_req_list;r;r=r->next)
+			if (r->type == req.type) {
+				r->fn(&req);
+				return;
+			}
+		printk("Unknown request %d\n",req.type);
+		break;
+	}
+}
+
+
+static void bif_dma_complete(void)
+{
+	extern int bif_rx(struct sk_buff *skb);
+	enum dma_state old_state = dma_state;
+	unsigned a;
+	
+	a = DMA_IN(DMA2_DMST);
+	
+	if (a & DMA_DMST_AC) return;
+	
+	DMA_OUT(DMA2_DMST,AP_CLR_INTR_REQ<<DMA_INTR_NORMAL_SH);
+	DMA_OUT(DMA2_DMST,AP_CLR_INTR_REQ<<DMA_INTR_ERROR_SH);
+	
+	if (old_state == DMA_INCOMING) {
+		if (skb_in) bif_rx(skb_in);
+		skb_in = NULL;
+	}
+	if (bread_req.type != -1) {
+		ap_complete(&bread_req);
+		bread_req.type = -1;
+	}
+
+	if (bif_dma_data) {
+		kfree_s(bif_dma_data,bif_dma_out_size);
+		bif_dma_data = NULL;
+	}
+	
+	if (skb_out) {
+		dev_kfree_skb(skb_out, FREE_WRITE);
+		skb_out = NULL;
+	}
+	
+	dma_state = DMA_IDLE;
+	
+	if (a & (AP_INTR_REQ<<DMA_INTR_ERROR_SH)) {
+		printk("BIF: got dma error\n");
+	}
+}
+
+
+/* handle bif related interrupts. Currently handles 3 interrupts, the
+   bif header interrupt, the bif get interrupt and the dma transfer
+   complete interrupt */
+static void bif_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned flags;
+	
+	bif_pt_regs = regs;                       
+	
+	save_flags(flags); cli();
+
+	mac_dma_complete();
+
+	if (dma_state != DMA_IDLE) {
+		bif_dma_complete();
+	}
+	
+	bif_reset_interrupts();
+	
+	while (dma_state == DMA_IDLE && BIF_DATA_WAITING()) {
+		bif_intr_receive(NULL);
+	}
+
+	if (dma_state != DMA_IDLE) {
+		bif_dma_complete();
+	}
+	
+	if (dma_state == DMA_IDLE && bif_queue_top && !HAVE_BIF()) {
+		want_bif();
+	}
+	
+	if (dma_state == DMA_IDLE && HAVE_BIF()) { 
+		waiting_for_bif = 0;
+		bif_intr_runqueue(); 
+	}
+
+	if (dma_state == DMA_IDLE && HAVE_BIF()) {
+		release_bif();
+	}
+
+	restore_flags(flags);
+	bif_pt_regs = NULL;
+}
+
+
+/* handle the attention interrupt - used for BIF arbitration */
+static void attn_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned flags;
+
+	save_flags(flags); cli();
+
+	attn_enable();
+
+#if SNET_ARBITRATION
+	attn_mask();
+	DEBUG(("|bif attn irq %d\n",irq));
+
+	if (waiting_for_bif)
+		want_bif();
+
+	DEBUG(("|bif attn irq %d done\n",irq));
+#endif
+
+	bif_interrupt(irq,dev_id,regs);
+	restore_flags(flags);
+}
+
+
+void bif_timer(void)
+{
+#if 1
+	if (interrupt_driven)
+		bif_interrupt(0,NULL,NULL);
+#endif
+}
+
+static void tnet_ip_enable(void)
+{ 
+	tnet_ip_enabled = 1; 
+	printk("tnet_ip_enabled=%d\n",tnet_ip_enabled);
+}
+
+static void tnet_ip_disable(void)
+{ 
+	tnet_ip_enabled = 0; 
+	printk("tnet_ip_enabled=%d\n",tnet_ip_enabled);
+}
+
+/* initialise the bif code */
+void ap_bif_init(void)
+{
+	int res;
+	unsigned long flags;
+	printk("doing ap_bif_init()\n");
+	
+	bif_add_debug_key('+',tnet_ip_enable,"enable Tnet based IP");
+	bif_add_debug_key('-',tnet_ip_disable,"disable Tnet based IP");
+	
+	save_flags(flags); cli();
+	
+	/* register the BIF interrupt */
+	if ((res=request_irq(APBIF_IRQ, bif_interrupt, 
+			     SA_INTERRUPT, "apbif", NULL))) {
+		printk("Failed to install bif interrupt handler\n");
+		restore_flags(flags);
+		return;
+	}
+
+	/* and the bus get interrupt */
+	if ((res=request_irq(APBIFGET_IRQ, bif_interrupt, 
+			     SA_INTERRUPT, "apbifget", NULL))) {
+		printk("Failed to install bifget interrupt handler\n");
+		restore_flags(flags);
+		return;
+	}
+
+	/* dma complete interrupt */
+	if ((res=request_irq(APDMA_IRQ, bif_interrupt, SA_INTERRUPT, 
+			     "apdma", NULL))) {
+		printk("Failed to install bifdma interrupt handler\n");
+		restore_flags(flags);
+		return;
+	}
+
+	/* attention interrupt */
+	if ((res=request_irq(APATTN_IRQ, attn_interrupt, SA_INTERRUPT, 
+			     "apattn", NULL))) {
+		printk("Failed to install apattn interrupt handler\n");
+		restore_flags(flags);
+		return;
+	}
+
+	printk("Installed bif handlers\n");
+
+	/* enable dma-request */
+	BIF_OUT(BIF_SDCSR,BIF_SDCSR_DE);
+	
+	DMA_OUT(DMA2_DCMD,DMA_DCMD_SA);	
+	DMA_OUT(DMA2_DMST,DMA_DMST_RST);
+	DMA_OUT(DMA2_DMST,AP_CLR_INTR_REQ<<DMA_INTR_NORMAL_SH);
+	DMA_OUT(DMA2_DMST,AP_CLR_INTR_MASK<<DMA_INTR_NORMAL_SH);
+	DMA_OUT(DMA2_DMST,AP_CLR_INTR_REQ<<DMA_INTR_ERROR_SH);
+	DMA_OUT(DMA2_DMST,AP_CLR_INTR_MASK<<DMA_INTR_ERROR_SH);
+
+	/* enable the attention interrupt */
+	attn_enable();
+	
+	DMA_OUT(DMA_BIF_BCMD,DMA_BCMD_SA);
+	DMA_OUT(DMA_BIF_BRST,DMA_DMST_RST);
+	
+	/* from now on we are interrupt driven */
+	bread_req.type = -1;
+	dma_state = DMA_IDLE;
+	interrupt_driven = 1;
+	use_dma = 1;
+	bif_reset_interrupts();
+
+	/* if theres something in the queue then we also want the bus */
+	if (bif_queue_top) 
+		want_bif();
+	
+	/* tell the host that networking is now OK */
+	start_apnet();
+	
+	printk("bif initialised\n");
+	
+	restore_flags(flags);
+}
+
+
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/ap1000/dma.c linux/arch/sparc/ap1000/dma.c
--- v2.1.22/linux/arch/sparc/ap1000/dma.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/ap1000/dma.c	Sun Jan 26 12:07:06 1997
@@ -0,0 +1,74 @@
+  /*
+   * Copyright 1996 The Australian National University.
+   * Copyright 1996 Fujitsu Laboratories Limited
+   * 
+   * This software may be distributed under the terms of the Gnu
+   * Public License version 2 or later
+  */
+/* dma routines for the AP1000 */
+#include <asm/ap1000/apservice.h>
+#include <asm/ap1000/apreg.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+
+#define DMA_MAX_TRANS_SIZE2 (0xfffffc)
+
+int ap_dma_wait(int ch)
+{
+	int i = 0;
+	while (DMA_IN(ch+DMA_DMST) & DMA_DMST_AC) i++;
+	return i;
+}
+
+/* send some data out a dma channel */
+int ap_dma_go(unsigned long ch,unsigned int p,int size,unsigned long cmd)
+{
+  int rest;
+
+  p = mmu_v2p(p);
+
+  cmd |= DMA_DCMD_ST | DMA_DCMD_TYP_AUTO;
+
+#if 0
+  if (ap_dma_wait(ch)) {
+	  printk("WARNING: dma started when not complete\n");
+  }
+
+  if (cmd == DMA_DCMD_TD_MD && !(BIF_IN(BIF_SDCSR) & BIF_SDCSR_BG)) {
+	  ap_led(0xAA);
+	  printk("attempt to dma without holding the bus\n");
+	  return -1;
+  }
+#endif
+
+  /* reset the dma system */
+  DMA_OUT(ch + DMA_DMST,DMA_DMST_RST);
+
+  if (size <= DMA_MAX_TRANS_SIZE) {
+    DMA_OUT(ch + DMA_MADDR,(unsigned long)p);
+    DMA_OUT(ch + DMA_HSKIP,1);
+    DMA_OUT(ch + DMA_VSKIP,1);
+    DMA_OUT(ch + DMA_DCMD,cmd | B2W(size));
+    return 0;
+  } 
+
+  if (size <= DMA_MAX_TRANS_SIZE2) {
+    if(size & 0x3) size += 4;
+    rest = (size & (DMA_TRANS_BLOCK_SIZE - 1)) >> 2;
+    if (rest) {
+      DMA_OUT(ch + DMA_HDRP,(unsigned)p);
+      p += rest << 2;
+    }
+    DMA_OUT(ch + DMA_MADDR,(unsigned)p);
+    DMA_OUT(ch + DMA_HSKIP,size >> (2 + 6));
+    DMA_OUT(ch + DMA_VSKIP,1);
+    DMA_OUT(ch + DMA_DCMD,cmd | (rest << 16) | 64);
+    return 0;
+  }
+
+  printk("AP1000 DMA operation too big (%d bytes) - aborting\n",size);
+  return(-1);
+}
+
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/ap1000/hw.c linux/arch/sparc/ap1000/hw.c
--- v2.1.22/linux/arch/sparc/ap1000/hw.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/ap1000/hw.c	Sun Jan 26 12:07:06 1997
@@ -0,0 +1,185 @@
+  /*
+   * Copyright 1996 The Australian National University.
+   * Copyright 1996 Fujitsu Laboratories Limited
+   * 
+   * This software may be distributed under the terms of the Gnu
+   * Public License version 2 or later
+  */
+/*
+ * Initialize the AP1000 hardware: BIF, MSC+, MC+, etc.
+ */
+
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/mpp.h>
+#include <asm/irq.h>
+#include <asm/ap1000/apservice.h>
+#include <asm/ap1000/apreg.h>
+
+#define APLOG 0
+
+/* these make using CellOS code easier */
+int cap_nopt0;
+int cap_cid0;
+int cap_ncel0;
+
+unsigned _cid, _ncel, _ncelx, _ncely, _cidx, _cidy;
+
+/* yuck - needed for sun4c! */
+static unsigned char dummy;
+unsigned char *auxio_register = &dummy;
+
+
+extern struct cap_init cap_init;
+
+static void unexpected_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+  ap_panic("** unexpected interrupt %d **\n",irq); 
+}
+
+static void ap_other_irqs(void)
+{
+	request_irq(3, unexpected_irq, SA_INTERRUPT, "unused", 0);
+	request_irq(5, unexpected_irq, SA_INTERRUPT, "unused", 0);
+	request_irq(12, unexpected_irq, SA_INTERRUPT, "unused", 0);
+	request_irq(15, unexpected_irq, SA_INTERRUPT, "unused", 0);
+}
+
+int ap_memory_size(void)
+{
+	if ((MSC_IN(MSC_SIMMCHK) & MSC_SIMMCHK_MASK) == 0) {
+		return 16*1024*1024; 
+	}
+	return 64*1024*1024;
+}
+
+static void show_registers(void)
+{
+	extern struct pt_regs *bif_pt_regs;
+	if (bif_pt_regs) 
+		show_regs(bif_pt_regs);
+	else
+		printk("unable to show registers\n");
+}
+
+
+static void check_alive(void)
+{
+	printk("Cell %d is alive\n",mpp_cid());	       
+}
+
+
+
+static void show_task(struct task_struct *t)
+{
+	printk("cell=%3d uid=%5d pid=%5d utime=%3d stime=%3d etime=%3d name=%s\n",
+	       mpp_cid(),
+	       t->uid,
+	       (int)t->pid,
+	       (int)t->utime,
+	       (int)t->stime,
+	       (jiffies - (int)t->start_time) / 100,
+	       t->comm);
+}
+
+static void show_ptasks(void)
+{
+	extern struct task_struct *task[];
+	int i;
+	int count=0;
+
+	for (i=MPP_TASK_BASE;i<NR_TASKS;i++)
+		if (task[i]) {
+			show_task(task[i]);
+			count++;
+		}
+	if (count == 0)
+		printk("no parallel tasks on cell %d\n",mpp_cid());
+}
+
+static void show_utasks(void)
+{
+	extern struct task_struct *task[];
+	int i;
+	int count=0;
+
+	for (i=0;i<NR_TASKS;i++)
+		if (task[i] && task[i]->uid > 1)  {
+			show_task(task[i]);
+			count++;
+		}
+
+	if (count == 0)
+		printk("no user tasks on cell %d\n",mpp_cid());
+}
+
+
+static void show_otasks(void)
+{
+	extern struct task_struct *task[];
+	int i;
+	int count=0;
+	extern int ap_current_uid;
+
+	for (i=0;i<NR_TASKS;i++)
+		if (task[i] && task[i]->uid == ap_current_uid)  {
+			show_task(task[i]);
+			count++;
+		}
+
+	if (count == 0)
+		printk("no tasks on cell %d\n",mpp_cid());
+}
+
+
+void do_panic(void)
+{
+	int *x = 0;
+	*x = 1; /* uggh */
+}
+
+
+void mpp_hw_init(void)
+{
+	extern void show_state(void);
+	extern void breakpoint(void);
+	extern void ctrl_alt_del(void);
+	extern void mac_print_state(void);
+	extern void show_debug_keys(void);
+	
+	bif_add_debug_key('c',check_alive,"check if a cell is alive");
+	bif_add_debug_key('k',show_debug_keys,"show the kernel debug keys");
+	bif_add_debug_key('p',show_registers,"show register info");
+	bif_add_debug_key('p',show_registers,"show register info");
+	bif_add_debug_key('m',show_mem,"detailed memory stats");
+	bif_add_debug_key('s',show_state,"detailed process stats");
+	bif_add_debug_key('D',ap_start_debugger,"launch the kernel debugger");
+	bif_add_debug_key('i',breakpoint,"send a breakpoint");
+	bif_add_debug_key('r',ctrl_alt_del,"run shutdown (doesn't work)");  
+	bif_add_debug_key('P',show_ptasks,"show running parallel tasks");  
+	bif_add_debug_key('U',show_utasks,"show all user tasks");  
+	bif_add_debug_key('O',show_otasks,"show own user tasks");  
+	bif_add_debug_key('^',do_panic,"panic :-)");  
+	
+	
+	cap_cid0 = BIF_IN(BIF_CIDR1);
+	cap_ncel0 = cap_init.numcells;
+	
+	_cid = cap_cid0;
+	_ncel = cap_ncel0;
+	_ncelx = _ncel<8?_ncel:8;
+	_ncely = ((_ncel-1) / _ncelx) + 1;
+	_cidx = _cid % _ncelx;
+	_cidy = _cid / _ncelx;
+	
+	ap_bif_init();
+	ap_msc_init();
+	ap_tnet_init();
+	ap_profile_init();
+	ap_other_irqs();
+	ap_ringbuf_init();
+#if APLOG
+	ap_log(NULL,-1);
+#endif
+}
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/ap1000/irq.c linux/arch/sparc/ap1000/irq.c
--- v2.1.22/linux/arch/sparc/ap1000/irq.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/ap1000/irq.c	Sun Jan 26 12:07:06 1997
@@ -0,0 +1,64 @@
+  /*
+   * Copyright 1996 The Australian National University.
+   * Copyright 1996 Fujitsu Laboratories Limited
+   * 
+   * This software may be distributed under the terms of the Gnu
+   * Public License version 2 or later
+  */
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/linkage.h>
+#include <linux/kernel_stat.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+#include <linux/malloc.h>
+
+#include <asm/ptrace.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/psr.h>
+#include <asm/vaddrs.h>
+#include <asm/timer.h>
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+#include <asm/traps.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/ap1000/apreg.h>
+
+extern void ap_clear_clock_irq(void);
+extern void ap_init_timers(void);
+
+static void ap_enable_irq(unsigned int irq_nr)
+{
+  /* printk("ENABLE IRQ %d IGNORED\n",irq_nr); */
+}
+
+static void ap_disable_irq(unsigned int irq_nr)
+{
+  printk("DISABLE IRQ %d IGNORED\n",irq_nr);
+}
+
+static void ap_clear_profile_irq(void)
+{
+  MC_OUT(MC_INTR,AP_CLR_INTR_REQ << MC_INTR_ITIM0_SH);
+}
+
+static void ap_load_profile_irq(unsigned limit)
+{
+  MC_OUT(MC_ITIMER0,limit); 
+}
+
+void ap_init_IRQ(void)
+{
+  enable_irq = ap_enable_irq;
+  disable_irq = ap_disable_irq;
+  clear_clock_irq = ap_clear_clock_irq;
+  clear_profile_irq = ap_clear_profile_irq;
+  load_profile_irq = ap_load_profile_irq;
+  init_timers = ap_init_timers;
+
+  sti(); /* the sun4m code does this, so we do too */
+}
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/ap1000/kgdb.c linux/arch/sparc/ap1000/kgdb.c
--- v2.1.22/linux/arch/sparc/ap1000/kgdb.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/ap1000/kgdb.c	Sun Jan 26 12:07:06 1997
@@ -0,0 +1,78 @@
+  /*
+   * Copyright 1996 The Australian National University.
+   * Copyright 1996 Fujitsu Laboratories Limited
+   * 
+   * This software may be distributed under the terms of the Gnu
+   * Public License version 2 or later
+  */
+/* routines to support remote kgdb to Linux/AP+ cells */
+
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <asm/ap1000/apservice.h>
+#include <asm/ap1000/apreg.h>
+
+static char out_buf[0x100];
+static int out_buf_pos = 0;
+
+static char in_buf[0x100];
+static int in_buf_pos = 0;
+static int in_buf_count = 0;
+
+static int hash_pos = -1;
+
+void ap_dbg_flush(void)
+{
+	struct cap_request req;
+	
+	if (out_buf_pos == 0) return;
+	
+	req.cid = mpp_cid();
+	req.type = REQ_PUTDEBUGSTRING;
+	req.size = sizeof(req) + out_buf_pos;
+	req.header = MAKE_HEADER(HOST_CID);
+	
+	write_bif_polled((char *)&req,sizeof(req),(char *)out_buf,out_buf_pos);
+	
+	out_buf_pos = 0;
+	hash_pos = -1;
+}
+
+/* called by the gdb stuff */
+void putDebugChar(char c)
+{
+	if (c == '#') hash_pos = out_buf_pos;
+	
+	out_buf[out_buf_pos++] = c;
+	if (out_buf_pos == sizeof(out_buf)) {
+		ap_dbg_flush();
+	}
+}
+
+/* used by gdb to get input */
+char getDebugChar(void)
+{
+	unsigned flags;
+	struct cap_request req;
+	
+	ap_dbg_flush();
+	
+	if (in_buf_count == 0) {
+		req.cid = mpp_cid();
+		req.type = REQ_GETDEBUGCHAR;
+		req.size = sizeof(req);
+		req.header = MAKE_HEADER(HOST_CID);
+		
+		save_flags(flags); cli();
+		write_bif_polled((char *)&req,sizeof(req),NULL,0);
+		ap_wait_request(&req,REQ_GETDEBUGCHAR);
+		read_bif(in_buf,req.size - sizeof(req));
+		in_buf_pos = 0;
+		in_buf_count = req.size - sizeof(req);
+		restore_flags(flags);
+	}
+	
+	in_buf_count--;
+	return(in_buf[in_buf_pos++]);
+}
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/ap1000/mpp.c linux/arch/sparc/ap1000/mpp.c
--- v2.1.22/linux/arch/sparc/ap1000/mpp.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/ap1000/mpp.c	Sun Jan 26 12:07:06 1997
@@ -0,0 +1,82 @@
+  /*
+   * Copyright 1996 The Australian National University.
+   * Copyright 1996 Fujitsu Laboratories Limited
+   * 
+   * This software may be distributed under the terms of the Gnu
+   * Public License version 2 or later
+  */
+/*
+ * simple mpp functions for the AP+
+ */
+
+#include <asm/ap1000/apreg.h>
+#include <asm/ap1000/apservice.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <asm/pgtable.h>
+
+extern int cap_cid0;
+extern int cap_ncel0;
+extern struct cap_init cap_init;
+
+static volatile int mpp_current_task = 0;
+static int gang_factor = DEF_GANG_FACTOR;
+static int last_task = 0;
+
+
+void mpp_schedule(struct cap_request *req)
+{
+	mpp_current_task = req->data[0];
+	need_resched = 1;
+	mark_bh(TQUEUE_BH);
+}
+
+
+void mpp_notify_schedule(struct task_struct *tsk)
+{
+	last_task = tsk->taskid;
+
+	msc_switch_check(tsk);
+
+	if (gang_factor == 0) return;
+
+	if (cap_cid0 == cap_init.bootcid && 
+	    mpp_current_task != tsk->taskid) {
+		struct cap_request req;
+
+		mpp_current_task = tsk->taskid;
+	
+		req.cid = mpp_cid();
+		req.type = REQ_SCHEDULE;
+		req.size = sizeof(req);
+ 		req.header = MAKE_HEADER(-1);
+		req.data[0] = mpp_current_task;
+		
+		bif_queue(&req,NULL,0);
+	}
+}
+
+
+int mpp_weight(struct task_struct *tsk)
+{
+	extern int block_parallel_tasks;
+
+	if (!MPP_IS_PAR_TASK(tsk->taskid)) return 0;
+
+	if (block_parallel_tasks) return -1000;
+
+	if (last_task && last_task != tsk->taskid && task[last_task] &&
+	    !msc_switch_ok()) return -1000;
+
+	if (cap_cid0 != cap_init.bootcid &&
+	    tsk->taskid != mpp_current_task) {
+		return -gang_factor;
+	}
+	return 0;
+}
+
+void mpp_set_gang_factor(int factor)
+{
+	gang_factor = factor;
+}
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/ap1000/msc.c linux/arch/sparc/ap1000/msc.c
--- v2.1.22/linux/arch/sparc/ap1000/msc.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/ap1000/msc.c	Sun Jan 26 12:07:06 1997
@@ -0,0 +1,1263 @@
+  /*
+   * Copyright 1996 The Australian National University.
+   * Copyright 1996 Fujitsu Laboratories Limited
+   * 
+   * This software may be distributed under the terms of the Gnu
+   * Public License version 2 or later
+  */
+/*
+ * Routines to control the AP1000+ Message Controller (MSC+)
+ * and Memory Controller (MC+).
+ *
+ */
+#include <linux/config.h>
+#define _APLIB_
+#include <asm/ap1000/apreg.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/ap1000/pgtapmmu.h>
+#include <linux/tasks.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+static void msc_interrupt_9(int irq, void *dev_id, struct pt_regs *regs);
+static void msc_interrupt_11(int irq, void *dev_id, struct pt_regs *regs);
+static void msc_set_ringbuf(int context);
+static void msc_update_read_ptr(int context,int overflow);
+static void fail_write(int context,int intr,unsigned vaddr);
+static void fail_read(int context,int intr,unsigned vaddr);
+static void msc_switch_from_check(struct task_struct *tsk);
+static void msc_status(void);
+
+#define DEBUG 0
+
+/*
+ * This describes how the 5 queues for outgoing requests
+ * are mapped into the 256 words of send queue RAM in the MSC+.
+ */
+#define NSENDQUEUES		5
+
+static struct send_queues {
+    int	base;		/* must be a multiple of size */
+    int size;		/* must be 32 or 64 */
+} send_queues[NSENDQUEUES] = {
+    {0, 64},		/* System put/send requests */
+    {192, 32},		/* Remote read/write requests */
+    {64, 64},		/* User put/send requests */
+    {224, 32},		/* Remote read replies */
+    {128, 64},		/* Get replies */
+};
+
+#define NR_RBUFS MSC_NR_RBUFS
+
+static struct {
+  unsigned rbmbwp;
+  unsigned rbmmode;
+  unsigned rbmrp;
+} ringbufs[MSC_NR_RBUFS] = {
+  {MSC_RBMBWP0, MSC_RBMMODE0, MSC_RBMRP0},
+  {MSC_RBMBWP1, MSC_RBMMODE1, MSC_RBMRP1},
+  {MSC_RBMBWP2, MSC_RBMMODE2, MSC_RBMRP2},
+};
+
+#define CTX_MASK	0xfff
+#define NULL_CONTEXT	CTX_MASK
+
+#define QOF_ORDER       3	/* 32kB queue overflow buffer */
+#define QOF_SIZE	((1<<QOF_ORDER)*PAGE_SIZE)
+#define QOF_ELT_SIZE	8	/* size of each queue element */
+#define QOF_REDZONE_SZ	8192	/* 8kB redzone, imposed by hardware */
+#define QOF_NELT	(QOF_SIZE / QOF_ELT_SIZE)
+#define QOF_RED_NELT	(QOF_REDZONE_SZ / QOF_ELT_SIZE)
+#define QOF_GREEN_NELT	((QOF_SIZE - QOF_REDZONE_SZ) / QOF_ELT_SIZE)
+
+#define MAKE_QBMPTR(qof, size) \
+	(MKFIELD((qof) >> 19, MSC_QBMP_BP) \
+	 + MKFIELD((qof) >> 3, MSC_QBMP_WP) \
+	 + MKFIELD(((qof) + (size) - 1) >> 13, MSC_QBMP_LIM))
+
+#define QBM_UPDATE_WP(wp)	\
+	MSC_OUT(MSC_QBMPTR, INSFIELD(MSC_IN(MSC_QBMPTR), (unsigned)(wp) >> 3, \
+				     MSC_QBMP_WP))
+
+/* Send queue overflow buffer structure */
+struct qof_elt {
+    unsigned info;
+    unsigned data;
+};
+
+/* Fields in qof_elt.info */
+#define QOF_QUEUE_SH	24		/* queue bits start at bit 24 */
+#define QOF_QUEUE_M	0x1f		/* 5 bits wide */
+#define QOF_ENDBIT	1		/* end bit in bit 0 */
+
+static struct qof_elt *qof_base=NULL; /* start of overflow buffer */
+static unsigned long  qof_phys;	/* physical start adrs of overflow buffer */
+static struct qof_elt *qof_rp;	/* read pointer for refills */
+static struct qof_elt *qof_new;	/* first element we haven't yet looked at */
+static int qof_present[NSENDQUEUES];/* # elts for each q in [qof_rp,qof_new) */
+
+/* this is used to flag when the msc is blocked, so we can't send 
+   messages on it without the possability of deadlock */
+int msc_blocked = 0;
+int block_parallel_tasks = 0;
+
+static int qbm_full_counter = 0;
+
+#define INTR_LIMIT 10000
+static int intr_counter = 0;
+static unsigned intr_mask;
+
+#define DUMMY_RINGBUF_ORDER 5
+#define DUMMY_RINGBUF_SIZE ((1<<DUMMY_RINGBUF_ORDER)*PAGE_SIZE)
+
+/* 
+ * The system ring buffer, used for inter-kernel comms 
+ */
+struct ringbuf_struct system_ringbuf = {NULL,NULL,SYSTEM_RINGBUF_ORDER,0,0,0,0};
+struct ringbuf_struct dummy_ringbuf = {NULL,NULL,DUMMY_RINGBUF_ORDER,0,0,0,0};
+unsigned system_read_ptr = (SYSTEM_RINGBUF_SIZE>>5)-1;
+unsigned dummy_read_ptr = (DUMMY_RINGBUF_SIZE>>5)-1;
+
+#define SQ_NEW_MODE(mode) do { \
+    MSC_OUT(MSC_SQCTRL, ((MSC_IN(MSC_SQCTRL) & ~MSC_SQC_RMODE) \
+			 | MSC_SQC_RMODE_ ## mode)); \
+    while ((MSC_IN(MSC_SQCTRL) & MSC_SQC_MODE) != MSC_SQC_MODE_ ## mode) \
+	/* hang */ ; \
+} while (0)
+
+/* Repack the queue overflow buffer if >= this many already-used entries */
+#define REPACK_THRESH	64
+
+
+static void refill_sq(void);
+static void repack_qof(void);
+static void shuffle_qof(void);
+static void async_callback(int, unsigned long, int, int);
+
+
+static void mask_all_interrupts(void)
+{
+    /* disable all MSC+ interrupts */
+    MSC_OUT(MSC_INTR, 
+	    (AP_SET_INTR_MASK << MSC_INTR_QBMFUL_SH) |
+	    (AP_SET_INTR_MASK << MSC_INTR_SQFILL_SH) |
+	    (AP_SET_INTR_MASK << MSC_INTR_RBMISS_SH) |
+	    (AP_SET_INTR_MASK << MSC_INTR_RBFULL_SH) |
+	    (AP_SET_INTR_MASK << MSC_INTR_RMASF_SH) |
+	    (AP_SET_INTR_MASK << MSC_INTR_RMASE_SH) |
+	    (AP_SET_INTR_MASK << MSC_INTR_SMASF_SH) |
+	    (AP_SET_INTR_MASK << MSC_INTR_SMASE_SH));
+}
+
+static inline int valid_task(struct task_struct *tsk)
+{
+  return(tsk && 
+	 !((tsk)->flags & PF_EXITING) && 
+	 tsk->mm && 
+	 tsk->mm->context != NO_CONTEXT);
+}
+
+static inline unsigned long apmmu_get_raw_ctable_ptr(void)
+{
+	unsigned int retval;
+
+	__asm__ __volatile__("lda [%1] %2, %0\n\t" :
+			     "=r" (retval) :
+			     "r" (APMMU_CTXTBL_PTR),
+			     "i" (ASI_M_MMUREGS));
+	return (retval);
+}
+
+static void mc_tlb_map(unsigned phys_page,unsigned vpage,int context)
+{
+    unsigned long long *tlb4k;
+    unsigned long long new_entry;
+    unsigned long *new_entryp = (unsigned long *)&new_entry;
+    tlb4k = ((unsigned long long *)MC_MMU_TLB4K) + (vpage & 0xFF);
+    new_entryp[0] = (phys_page&~7) >> 3;
+    new_entryp[1] = ((phys_page & 7) << 29) | (((vpage>>8)&0xFFF) << 17) | 
+	(context << 5) | 0x13; 
+    tlb4k[0] = new_entry;
+#if DEBUG
+    printk("mc_tlb_map(%x,%x,%x) %x %x at %x\n",
+	   phys_page,vpage,context,new_entryp[0],new_entryp[1],tlb4k);
+#endif
+}
+
+static void mc_tlb_unmap(unsigned vpage)
+{
+	unsigned long long *tlb4k = (unsigned long long *)MC_MMU_TLB4K;
+	tlb4k = ((unsigned long long *)MC_MMU_TLB4K) + (vpage & 0xFF);
+	tlb4k[0] = 0;
+}
+
+void mc_tlb_init(void)
+{
+	unsigned long long *tlb256k, *tlb4k;
+	int i;
+	
+	tlb4k = (unsigned long long *)MC_MMU_TLB4K;
+	for (i = MC_MMU_TLB4K_SIZE; i > 0; --i)
+		*tlb4k++ = 0;
+	tlb256k = (unsigned long long *)MC_MMU_TLB256K;
+	for (i = MC_MMU_TLB256K_SIZE; i > 0; --i)
+		*tlb256k++ = 0;
+}
+
+void ap_msc_init(void)
+{
+    int i, flags, res;
+    unsigned int qp;
+
+    bif_add_debug_key('M',msc_status,"MSC+ status");
+
+#if DEBUG
+    printk("MSC+ version %x\n", MSC_IN(MSC_VERSION));
+    printk("MC+  version %x\n", MC_IN(MC_VERSION));
+#endif
+
+    mc_tlb_init();
+
+    /* Set the MC's copy of the context table pointer */
+    MC_OUT(MC_CTP, apmmu_get_raw_ctable_ptr());
+
+    /* Initialize the send queue pointers */
+    qp = MSC_SQPTR0;
+    for (i = 0; i < 5; ++i) {
+	MSC_OUT(qp, ((send_queues[i].size == 64? MSC_SQP_MODE: 0)
+		     + ((send_queues[i].base >> 5) << MSC_SQP_BP_SH)));
+	qp += (MSC_SQPTR1 - MSC_SQPTR0);
+    }
+
+    /* Initialize the send queue RAM */
+    for (i = 0; i < 256; ++i)
+	MSC_OUT(MSC_SQRAM + i * 8, -1);
+
+    if (!qof_base) {
+      qof_base = (struct qof_elt *) __get_free_pages(GFP_ATOMIC, QOF_ORDER, 0);
+      for (i = MAP_NR(qof_base); i <= MAP_NR(((char*)qof_base)+QOF_SIZE-1);++i)
+	set_bit(PG_reserved, &mem_map[i].flags);
+    }
+
+    qof_phys = mmu_v2p((unsigned long) qof_base);
+    MSC_OUT(MSC_QBMPTR, MAKE_QBMPTR((unsigned long)qof_base, QOF_SIZE));
+    qof_rp = qof_base;
+    qof_new = qof_base;
+    for (i = 0; i < NSENDQUEUES; ++i)
+	qof_present[i] = 0;
+
+    SQ_NEW_MODE(NORMAL);	/* Set the send queue to normal mode */
+
+    /* Register interrupt handler for MSC+ */
+    save_flags(flags); cli();
+    res = request_irq(APMSC_IRQ, msc_interrupt_11, SA_INTERRUPT,
+		      "apmsc", NULL);
+    if (res != 0)
+	printk("couldn't register MSC interrupt 11: error=%d\n", res);
+    res = request_irq(APMAS_IRQ, msc_interrupt_9, SA_INTERRUPT,
+		      "apmas", NULL);
+    if (res != 0)
+	printk("couldn't register MSC interrupt 9: error=%d\n", res);
+    restore_flags(flags);
+
+    MSC_OUT(MSC_MASCTRL, 0);
+
+    /* Enable all MSC+ interrupts (for now) */
+    MSC_OUT(MSC_INTR, 
+	    (AP_CLR_INTR_MASK << MSC_INTR_QBMFUL_SH) |
+	    (AP_CLR_INTR_MASK << MSC_INTR_SQFILL_SH) |
+	    (AP_CLR_INTR_MASK << MSC_INTR_RBMISS_SH) |
+	    (AP_CLR_INTR_MASK << MSC_INTR_RBFULL_SH) |
+	    (AP_CLR_INTR_MASK << MSC_INTR_RMASF_SH) |
+	    (AP_CLR_INTR_MASK << MSC_INTR_RMASE_SH) |
+	    (AP_CLR_INTR_MASK << MSC_INTR_SMASF_SH) |
+	    (AP_CLR_INTR_MASK << MSC_INTR_SMASE_SH));
+
+    /* setup invalid contexts */
+    for (i=0; i<MSC_NR_RBUFS; i++)
+      MSC_OUT(ringbufs[i].rbmmode, NULL_CONTEXT);
+
+    MSC_OUT(MSC_SMASREG,0);
+    MSC_OUT(MSC_RMASREG,0);
+
+    if (!system_ringbuf.ringbuf) {
+      system_ringbuf.ringbuf = 
+	(void *)__get_free_pages(GFP_ATOMIC,SYSTEM_RINGBUF_ORDER,0);
+      for (i=MAP_NR(system_ringbuf.ringbuf);
+	   i<=MAP_NR(system_ringbuf.ringbuf+SYSTEM_RINGBUF_SIZE-1);i++)
+	set_bit(PG_reserved, &mem_map[i].flags);
+      system_ringbuf.write_ptr = mmu_v2p((unsigned)system_ringbuf.ringbuf)<<1;
+    }
+
+    if (!dummy_ringbuf.ringbuf) {
+      dummy_ringbuf.ringbuf = 
+	(void *)__get_free_pages(GFP_ATOMIC,DUMMY_RINGBUF_ORDER,0);
+      for (i=MAP_NR(dummy_ringbuf.ringbuf);
+	   i<=MAP_NR(dummy_ringbuf.ringbuf+DUMMY_RINGBUF_SIZE-1);i++)
+	set_bit(PG_reserved, &mem_map[i].flags);
+      dummy_ringbuf.write_ptr = mmu_v2p((unsigned)dummy_ringbuf.ringbuf)<<1;
+    }
+}
+
+
+static inline void qbmfill_interrupt(void)
+{
+	MSC_OUT(MSC_INTR, AP_CLR_INTR_MASK << MSC_INTR_QBMFUL_SH);
+	intr_mask &= ~(AP_INTR_REQ << MSC_INTR_QBMFUL_SH);
+
+	SQ_NEW_MODE(THRU);	/* set send queue ctrlr to through mode */
+	refill_sq();		/* refill the send queues */
+	SQ_NEW_MODE(NORMAL);	/* set send queue ctrlr back to normal mode */
+	/* dismiss the interrupt */
+	MSC_OUT(MSC_INTR, AP_CLR_INTR_REQ << MSC_INTR_SQFILL_SH);
+}
+
+static inline void qbmful_interrupt(void)
+{
+	int nvalid, ntot, q;
+
+	qbm_full_counter++;
+		
+#if DEBUG
+	printk("qbm full interrupt\n"); 
+#endif
+
+	SQ_NEW_MODE(THRU);	/* set send queue ctrlr to through mode */
+	/* stuff as much as we can into the send queue RAM */
+	refill_sq();
+	/* count how many valid words are left in the qof buffer */
+	nvalid = 0;
+	for (q = 0; q < NSENDQUEUES; ++q)
+		nvalid += qof_present[q];
+	if (nvalid >= QOF_GREEN_NELT) {
+#if DEBUG
+		printk("send queue overflow buffer overflow\n");
+#endif
+		MSC_OUT(MSC_INTR, AP_SET_INTR_MASK << MSC_INTR_QBMFUL_SH);
+		intr_mask |= (AP_INTR_REQ << MSC_INTR_QBMFUL_SH);
+		need_resched = 1;
+		block_parallel_tasks = 1;
+		mark_bh(TQUEUE_BH);
+	}
+	ntot = qof_new - qof_rp;	/* total # words of qof buf used */
+	if (ntot - nvalid >= REPACK_THRESH || ntot >= QOF_GREEN_NELT
+	    || (ntot > nvalid && nvalid >= QOF_GREEN_NELT - REPACK_THRESH)) {
+		repack_qof();
+		if (qof_new - qof_rp != nvalid) {
+			printk("MSC: qof_present wrong\n");
+		}
+	} else if (nvalid > 0) {
+		shuffle_qof();
+	}
+	/* N.B. if nvalid == 0, msc_refill_sq has already reset the QBM's WP */
+	SQ_NEW_MODE(NORMAL);
+
+	/* dismiss the interrupt */
+	MSC_OUT(MSC_INTR, AP_CLR_INTR_REQ << MSC_INTR_QBMFUL_SH);
+}
+
+
+static void msc_interrupt_11(int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned intr;
+	unsigned long flags;
+
+	save_flags(flags); cli();
+
+	if (intr_counter++ == INTR_LIMIT) {
+		mask_all_interrupts();
+		printk("too many MSC interrupts\n");
+		restore_flags(flags); 
+		return;
+	}
+
+	intr = MSC_IN(MSC_INTR);
+
+#if DEBUG
+	printk("CID(%d) msc_interrupt_11: intr = %x\n", mpp_cid(), intr);
+#endif
+
+	if (intr & (AP_INTR_REQ << MSC_INTR_RBMISS_SH)) {
+		int context;
+		context = MSC_IN(MSC_RMASREG) >> 20;
+		
+		msc_set_ringbuf(context);
+		MSC_OUT(MSC_INTR, AP_CLR_INTR_REQ << MSC_INTR_RBMISS_SH);
+	}
+	
+	if (intr & (AP_INTR_REQ << MSC_INTR_RBFULL_SH)) {
+		int context = MSC_IN(MSC_RMASREG) >> 20;
+		msc_update_read_ptr(context,1);	
+		MSC_OUT(MSC_INTR, AP_CLR_INTR_REQ << MSC_INTR_RBFULL_SH);
+	}
+	
+	if (intr & (AP_INTR_REQ << MSC_INTR_SQFILL_SH)) {
+		qbmfill_interrupt();
+	}
+	
+	if (intr & (AP_INTR_REQ << MSC_INTR_QBMFUL_SH)) {
+		qbmful_interrupt();
+	}
+
+	restore_flags(flags);
+}
+
+
+void msc_timer(void)
+{
+	/* unmask all the interrupts that are supposed to be unmasked */
+	intr_counter = 0;
+}
+
+/* assumes NSENDQUEUES == 5 */
+static int log2tbl[32] = {
+    -1,  0,  1, -1,  2, -1, -1, -1,
+     3, -1, -1, -1, -1, -1, -1, -1,
+     4, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1
+};
+
+static unsigned long direct_queues[NSENDQUEUES][2] = {
+    { MSC_SYSTEM_DIRECT, MSC_SYSTEM_DIRECT_END },
+    { MSC_REMOTE_DIRECT, MSC_REMOTE_DIRECT_END },
+    { MSC_USER_DIRECT, MSC_USER_DIRECT_END },
+    { MSC_REMREPLY_DIRECT, MSC_REMREPLY_DIRECT_END },
+    { MSC_REPLY_DIRECT, MSC_REPLY_DIRECT_END }
+};
+
+/*
+ * Copy entries from the queue overflow buffer back to the send queue.
+ * This must be called with the send queue controller in THRU mode.
+ */
+static void refill_sq(void)
+{
+    int notfull, use_old;
+    int q, kept_some;
+    int sqp, sqc;
+    struct qof_elt *rp, *qof_wp;
+    int freew[NSENDQUEUES];	/* # free words in each queue */
+
+    /* give parallel tasks another chance */
+    block_parallel_tasks = 0;
+
+    /* get the qbm's write pointer */
+    qof_wp = qof_base + (EXTFIELD(MSC_IN(MSC_QBMPTR), MSC_QBMP_WP)
+			 & ((QOF_SIZE - 1) >> 3));
+#if 0
+    printk("refill_sq: rp=%p new=%p wp=%p pres=[",
+	   qof_rp, qof_new, qof_wp);
+    for (q = 0; q < NSENDQUEUES; ++q)
+	printk("%d ", qof_present[q]);
+    printk("]\n");
+#endif
+
+    /* work out which send queues and aren't full */
+    notfull = 0;
+    use_old = 0;
+    for (q = 0; q < NSENDQUEUES; ++q) {
+	sqp = MSC_IN(MSC_SQPTR0 + q * 8);
+	freew[q] = (EXTFIELD(sqp, MSC_SQP_RP) - EXTFIELD(sqp, MSC_SQP_WP) - 1)
+	    & ((sqp & MSC_SQP_MODE)? 0x3f: 0x1f);
+	if (freew[q] > 0)
+	    notfull |= 1 << (q + QOF_QUEUE_SH);
+	use_old += (freew[q] < qof_present[q])? freew[q]: qof_present[q];
+    }
+
+    /*
+     * If there are useful entries in the old part of the overflow
+     * queue, process them.
+     */
+    kept_some = 0;
+    for (rp = qof_rp; rp < qof_new && use_old > 0; ++rp) {
+	if (rp->info & notfull) {
+	    /* Here's one we can stuff back into the send queue */
+	    q = log2tbl[EXTFIELD(rp->info, QOF_QUEUE)];
+	    if (q < 0) {
+		printk("bad queue bits in qof info (%x) at %p\n",
+		       rp->info, rp);
+		/* XXX just ignore this entry - should never happen */
+		rp->info = 0;
+		continue;
+	    }
+	    MSC_OUT(direct_queues[q][rp->info & QOF_ENDBIT],rp->data);
+	    if (--freew[q] == 0)
+		notfull &= ~(1 << (q + QOF_QUEUE_SH));
+	    --qof_present[q];
+	    --use_old;
+	    rp->info = 0;
+	} else if (!kept_some && rp->info != 0) {
+	    qof_rp = rp;
+	    kept_some = 1;
+	}
+    }
+
+    /* Trim off any further already-used items. */
+    if (!kept_some) {
+	for (; rp < qof_new; ++rp) {
+	    if (rp->info) {
+		qof_rp = rp;
+		kept_some = 1;
+		break;
+	    }
+	}
+    }
+
+    /*
+     * Now process everything that's arrived since we last updated qof_new.
+     */
+    for (rp = qof_new; rp < qof_wp; ++rp) {
+      if (rp->info == 0)
+	continue;
+	q = log2tbl[EXTFIELD(rp->info, QOF_QUEUE)];
+	if (q < 0) {
+	    printk("bad queue bits in qof info (%x) at %p\n", rp->info, rp);
+	    /* XXX just ignore this entry - should never happen */
+	    rp->info = 0;
+	    continue;
+	}
+	if (rp->info & notfull) {
+	  /* Another one to stuff back into the send queue. */
+	  MSC_OUT(direct_queues[q][rp->info & QOF_ENDBIT],rp->data);
+	  if (--freew[q] == 0)
+	    notfull &= ~(1 << (q + QOF_QUEUE_SH));
+	  rp->info = 0;
+	} else {
+	    ++qof_present[q];
+	    if (!kept_some) {
+		qof_rp = rp;
+		kept_some = 1;
+	    }
+	}
+    }
+
+    /* Update state and the MSC queue-spill flags. */
+    if (!kept_some) {
+	/* queue is empty; avoid unnecessary overflow interrupt later */
+	qof_rp = qof_new = qof_base;
+	QBM_UPDATE_WP(mmu_v2p((unsigned long)qof_base));
+    } else {
+	qof_new = qof_wp;
+    }
+
+    sqc = MSC_IN(MSC_SQCTRL);
+    for (q = 0; q < NSENDQUEUES; ++q)
+	if (qof_present[q] == 0 && freew[q] > 0)
+	    sqc &= ~(1 << (q + MSC_SQC_SPLF_SH));
+    MSC_OUT(MSC_SQCTRL, sqc);
+}
+
+/*
+ * Copy the valid entries from their current position
+ * in the queue overflow buffer to the beginning.
+ * This must be called with the send queue controller in THRU or BLOCKING mode.
+ */
+static void repack_qof(void)
+{
+    struct qof_elt *rp, *wp;
+
+    wp = qof_base;
+    for (rp = qof_rp; rp < qof_new; ++rp) {
+	if (rp->info) {
+	    if (rp > wp)
+		*wp = *rp;
+	    ++wp;
+	}
+    }
+    qof_rp = qof_base;
+    qof_new = wp;
+    QBM_UPDATE_WP(wp);
+}
+
+/*
+ * Copy all entries from their current position
+ * in the queue overflow buffer to the beginning.
+ * This must be called with the send queue controller in THRU or BLOCKING mode.
+ */
+static void shuffle_qof(void)
+{
+    int n;
+
+    n = qof_new - qof_rp;
+    memmove(qof_base, qof_rp, n * sizeof(struct qof_elt));
+    qof_rp = qof_base;
+    qof_new = qof_base + n;
+    QBM_UPDATE_WP(qof_new);
+}
+
+static inline void handle_signal(int context,unsigned vaddr)
+{
+  int signum = (vaddr - MSC_REM_SIGNAL) >> PAGE_SHIFT;
+  int taskid = MPP_CTX_TO_TASK(context);
+  if (MPP_IS_PAR_TASK(taskid) && valid_task(task[taskid])) {
+    send_sig(signum,task[taskid],1);
+#if DEBUG
+    printk("CID(%d) sent signal %d to task %d\n",mpp_cid(),signum,taskid);
+#endif
+  }
+}
+
+
+/*
+ * fail a msc write operation. We use Pauls dirty tlb trick to avoide
+ * the msc hardware bugs 
+ */
+static void fail_write(int context,int intr,unsigned vaddr)
+{
+	int tsk = MPP_CTX_TO_TASK(context);
+	int vpage = vaddr >> 12;
+#if DEBUG
+	printk("fail write tsk=%d intr=%x vaddr=%x RMASREG=%x errproc=%x\n",
+	       tsk,intr,vaddr,MSC_IN(MSC_RMASREG),MSC_IN(MSC_RHDERRPROC));
+#endif
+
+	mc_tlb_map(0x800000 | (mmu_v2p((unsigned)dummy_ringbuf.ringbuf)>>12),
+		   vpage,context);
+	MSC_OUT(MSC_MASCTRL, MSC_IN(MSC_MASCTRL) & ~MSC_MASC_RFEXIT);
+	MSC_OUT(MSC_INTR, AP_CLR_INTR_REQ << intr);
+
+	mc_tlb_unmap(vpage);	
+
+	if (MPP_IS_PAR_CTX(context) && valid_task(task[tsk])) {
+		if (vaddr - MSC_REM_SIGNAL < _NSIG*PAGE_SIZE) {
+			handle_signal(context,vaddr);
+		} else {
+			task[tsk]->tss.sig_address = vaddr;
+			task[tsk]->tss.sig_desc = SUBSIG_NOMAPPING;
+			send_sig(SIGSEGV, task[tsk], 1);
+		}
+	}
+}
+
+/*
+ * fail a msc read operation using the tlb trick */
+static void fail_read(int context,int intr,unsigned vaddr)
+{
+	int tsk = MPP_CTX_TO_TASK(context);  
+#if DEBUG
+	printk("fail read tsk=%d intr=%x\n",tsk,intr);
+#endif
+	
+	mc_tlb_map(0x800000 | (mmu_v2p((unsigned)dummy_ringbuf.ringbuf)>>12),
+		   vaddr>>12,context);
+	MSC_OUT(MSC_MASCTRL, MSC_IN(MSC_MASCTRL) & ~MSC_MASC_SFEXIT);
+	MSC_OUT(MSC_INTR, AP_CLR_INTR_REQ << intr);    
+	
+	mc_tlb_unmap(vaddr>>12);
+
+	if (MPP_IS_PAR_CTX(context) && valid_task(task[tsk])) {
+		if (vaddr - MSC_REM_SIGNAL < _NSIG*PAGE_SIZE) {
+			handle_signal(context,vaddr);
+		} else {
+			task[tsk]->tss.sig_address = vaddr;
+			task[tsk]->tss.sig_desc = SUBSIG_NOMAPPING;
+			send_sig(SIGSEGV, task[tsk], 1);
+		}
+	}	
+}
+
+static void async_callback(int tsk,unsigned long vaddr,int write,int ret)
+{
+	unsigned flags;
+	save_flags(flags); cli();
+
+	msc_blocked--;
+	if (write) {
+		intr_mask &= ~(AP_INTR_REQ << MSC_INTR_RMASF_SH);
+		if (ret) {
+			fail_write(MPP_TASK_TO_CTX(tsk),MSC_INTR_RMASF_SH,vaddr);
+			MSC_OUT(MSC_INTR, AP_CLR_INTR_MASK << MSC_INTR_RMASF_SH);
+			restore_flags(flags);
+			return;
+		}
+		MSC_OUT(MSC_MASCTRL, MSC_IN(MSC_MASCTRL) & ~MSC_MASC_RFEXIT);
+		MSC_OUT(MSC_INTR, AP_CLR_INTR_REQ << MSC_INTR_RMASF_SH);
+		MSC_OUT(MSC_INTR, AP_CLR_INTR_MASK << MSC_INTR_RMASF_SH);
+	} else {
+		intr_mask &= ~(AP_INTR_REQ << MSC_INTR_SMASF_SH);
+		if (ret) {
+			fail_read(MPP_TASK_TO_CTX(tsk),MSC_INTR_SMASF_SH,vaddr);
+			MSC_OUT(MSC_INTR, AP_CLR_INTR_MASK << MSC_INTR_SMASF_SH);
+			restore_flags(flags);
+			return;
+		}
+		MSC_OUT(MSC_MASCTRL, MSC_IN(MSC_MASCTRL) & ~MSC_MASC_SFEXIT);
+		MSC_OUT(MSC_INTR, AP_CLR_INTR_REQ << MSC_INTR_SMASF_SH);
+		MSC_OUT(MSC_INTR, AP_CLR_INTR_MASK << MSC_INTR_SMASF_SH);
+	}
+	restore_flags(flags);
+}
+
+
+
+static inline void msc_write_fault(void)
+{
+	unsigned context = MSC_IN(MSC_RMASREG) >> 20;
+	unsigned vaddr = MSC_IN(MSC_RMASTWP)<<12;
+	
+	if (context == SYSTEM_CONTEXT) {
+		fail_write(context,MSC_INTR_RMASF_SH,vaddr);
+		show_mapping_ctx(0,context,vaddr);
+		printk("ERROR: system write fault at %x\n",vaddr);
+		return;
+	}
+		
+	if (vaddr - MSC_REM_SIGNAL < _NSIG*PAGE_SIZE) {
+		fail_write(context,MSC_INTR_RMASF_SH,vaddr);
+		return;
+	}
+		
+	if (MPP_IS_PAR_CTX(context)) {
+		int tsk = MPP_CTX_TO_TASK(context);
+		if (valid_task(task[tsk]) && task[tsk]->ringbuf) {
+			MSC_OUT(MSC_INTR, 
+				AP_SET_INTR_MASK << MSC_INTR_RMASF_SH);
+			intr_mask |= (AP_INTR_REQ << MSC_INTR_RMASF_SH);
+#if DEBUG
+			show_mapping_ctx(0,context,vaddr);
+#endif
+			msc_blocked++;
+			async_fault(vaddr,1,tsk,async_callback);
+			return;
+		}
+	}
+	
+#if DEBUG
+	printk("CID(%d) mas write fault context=%x vaddr=%x\n",
+	       mpp_cid(),context,vaddr);
+#endif
+	
+	fail_write(context,MSC_INTR_RMASF_SH,vaddr);
+}
+
+
+static inline void msc_read_fault(void)
+{
+	unsigned context = MSC_IN(MSC_SMASREG) >> 20;
+	unsigned vaddr = MSC_IN(MSC_SMASTWP)<<12;
+		
+	if (context == SYSTEM_CONTEXT) {
+		fail_read(context,MSC_INTR_SMASF_SH,vaddr);
+		show_mapping_ctx(0,context,vaddr);
+		printk("ERROR: system read fault at %x\n",vaddr);
+		return;
+	}
+
+	if (MPP_IS_PAR_CTX(context)) {
+		int tsk = MPP_CTX_TO_TASK(context);
+		
+		if (vaddr - MSC_REM_SIGNAL < _NSIG*PAGE_SIZE) {
+			fail_read(context,MSC_INTR_SMASF_SH,vaddr);
+			return;
+		}
+
+		if (valid_task(task[tsk]) && task[tsk]->ringbuf) {
+			MSC_OUT(MSC_INTR, AP_SET_INTR_MASK << MSC_INTR_SMASF_SH);
+			intr_mask |= (AP_INTR_REQ << MSC_INTR_SMASF_SH);
+			msc_blocked++;
+			async_fault(vaddr,0,tsk,async_callback);
+			return;
+		}
+	}
+	
+#if DEBUG
+	printk("CID(%d) mas read fault context=%x vaddr=%x\n",
+	       mpp_cid(),context,vaddr);
+#endif
+	
+	fail_read(context,MSC_INTR_SMASF_SH,vaddr);
+}
+	
+
+
+static void msc_interrupt_9(int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned long flags;
+	unsigned intr, cnt, r;
+
+	save_flags(flags); cli();
+
+	if (intr_counter++ == INTR_LIMIT) {
+		mask_all_interrupts();
+		printk("too many MSC interrupts\n");
+		restore_flags(flags); 
+		return;
+	}
+
+	intr = MSC_IN(MSC_INTR) & ~intr_mask;    
+
+#if DEBUG
+	printk("CID(%d) msc_interrupt_9: intr = %x\n", mpp_cid(), intr);
+#endif
+	
+	if (intr & (AP_INTR_REQ << MSC_INTR_RMASF_SH)) {
+		msc_write_fault();
+	}
+	
+	if (intr & (AP_INTR_REQ << MSC_INTR_SMASF_SH)) {
+		msc_read_fault();
+	}
+
+	if (intr & (AP_INTR_REQ << MSC_INTR_RMASE_SH)) {
+		printk("recv mas error interrupt (write)\n");
+		printk("masctrl = %x\n", MSC_IN(MSC_MASCTRL));
+		printk("rmasadr = %x %x\n", MSC_IN(MSC_RMASADR),
+		       MSC_IN(MSC_RMASADR + 4));
+		printk("rmastwp = %x\n", MSC_IN(MSC_RMASTWP));
+		printk("rmasreg = %x\n", MSC_IN(MSC_RMASREG));
+		r = MSC_IN(MSC_RMASREG);
+		if ((r & MSC_MASR_AVIO) || (r & MSC_MASR_CMD) != MSC_MASR_CMD_XFER)
+			/* throw away the rest of the incoming data */
+			MSC_OUT(MSC_RHDERRPROC, 0);
+		/* clear the interrupt */
+		MSC_OUT(MSC_INTR, AP_CLR_INTR_REQ << MSC_INTR_RMASE_SH);
+	}
+	
+	if (intr & (AP_INTR_REQ << MSC_INTR_SMASE_SH)) {
+		printk("send mas error interrupt (read)\n");
+		printk("masctrl = %x\n", MSC_IN(MSC_MASCTRL));
+		printk("smasadr = %x %x\n", MSC_IN(MSC_SMASADR),
+		       MSC_IN(MSC_SMASADR + 4));
+		printk("smascnt = %x\n", MSC_IN(MSC_SMASCNT));
+		printk("smastwp = %x\n", MSC_IN(MSC_SMASTWP));
+		printk("smasreg = %x\n", MSC_IN(MSC_SMASREG));
+		/* supply dummy data */
+		cnt = MSC_IN(MSC_SMASCNT);
+		switch (MSC_IN(MSC_SMASREG) & MSC_MASR_CMD) {
+		case MSC_MASR_CMD_XFER:
+			MSC_OUT(MSC_HDGERRPROC, (EXTFIELD(cnt, MSC_SMCT_MCNT)
+						 + EXTFIELD(cnt, MSC_SMCT_ICNT)));
+			break;
+			/* case remote read: */
+		case MSC_MASR_CMD_FOP:
+		case MSC_MASR_CMD_CSI:
+			MSC_OUT(MSC_HDGERRPROC, 1);
+			break;
+		}
+		/* clear interrupt */
+		MSC_OUT(MSC_INTR, AP_CLR_INTR_REQ << MSC_INTR_SMASF_SH);
+	}
+	
+	restore_flags(flags);
+}
+
+/*
+ * remove access to a tasks ring buffer
+ */
+void msc_unset_ringbuf(int i)
+{
+	int ctx = MSC_IN(ringbufs[i].rbmmode) & CTX_MASK;
+	int tsk = MPP_CTX_TO_TASK(ctx);
+	struct ringbuf_struct *rbuf;
+  
+#if DEBUG
+	printk("msc_unset_ringbuf(%d) %x\n",i,ctx);
+#endif
+
+	MSC_OUT(ringbufs[i].rbmmode,NULL_CONTEXT);
+	if (ctx == SYSTEM_CONTEXT) { 
+		rbuf = &system_ringbuf;
+	} else if (ctx != NULL_CONTEXT && MPP_IS_PAR_CTX(ctx) && 
+		   valid_task(task[tsk]) && task[tsk]->ringbuf) {
+		rbuf = task[tsk]->ringbuf;
+	} else if (ctx != NULL_CONTEXT && MPP_IS_PAR_CTX(ctx) &&
+		   valid_task(task[tsk]) && task[tsk]->aplib) {
+		rbuf = &system_ringbuf;
+	} else {
+		rbuf = &dummy_ringbuf;
+	}
+
+	rbuf->write_ptr = MSC_IN(ringbufs[i].rbmbwp);
+}
+
+static void msc_update_read_ptr(int context,int overflow)
+{
+	int i;
+	unsigned new_read_ptr;
+
+	for (i=0;i<NR_RBUFS;i++) {
+		if ((MSC_IN(ringbufs[i].rbmmode)&CTX_MASK) == context) break;
+	}
+	if (i == NR_RBUFS) {
+		printk("didn't find context %d in msc_update_read_ptr()\n",
+		       context);
+		return;
+	}
+
+	if (context == SYSTEM_CONTEXT) {
+		tnet_check_completion();
+		if (overflow && MSC_IN(ringbufs[i].rbmrp) == system_read_ptr)
+			printk("system ringbuffer overflow\n");
+		new_read_ptr = system_read_ptr;
+	} else if (MPP_IS_PAR_CTX(context) && 
+		   valid_task(task[MPP_CTX_TO_TASK(context)]) &&
+		   task[MPP_CTX_TO_TASK(context)]->ringbuf) {
+		struct task_struct *tsk = task[MPP_CTX_TO_TASK(context)];
+		struct _kernel_cap_shared *_kernel;
+		unsigned soft_read_ptr;
+		unsigned octx;
+
+		octx = apmmu_get_context();
+		if (octx != context) 
+			apmmu_set_context(context);
+		_kernel = (struct _kernel_cap_shared *)(RBUF_VBASE + RBUF_SHARED_PAGE_OFF);
+		soft_read_ptr = _kernel->rbuf_read_ptr;
+		if (octx != context) 
+			apmmu_set_context(octx);
+
+		if (overflow && MSC_IN(ringbufs[i].rbmrp) == soft_read_ptr) {
+			/* send them a SIGLOST and wipe their ring buffer */
+			printk("ring buffer overflow for %s ctx=%x\n",
+			       tsk->comm,context);
+			send_sig(SIGLOST,tsk,1);
+			soft_read_ptr--;
+		}
+		new_read_ptr = soft_read_ptr;
+	} else if (MPP_IS_PAR_CTX(context) && 
+		   valid_task(task[MPP_CTX_TO_TASK(context)]) &&
+		   task[MPP_CTX_TO_TASK(context)]->aplib) {
+		tnet_check_completion();
+		if (overflow && MSC_IN(ringbufs[i].rbmrp) == system_read_ptr)
+                        printk("system ringbuffer overflow\n");
+                new_read_ptr = system_read_ptr;		
+	} else {
+		dummy_read_ptr = MSC_IN(ringbufs[i].rbmrp) - 1;
+		new_read_ptr = dummy_read_ptr - 1;
+#if DEBUG
+		if (overflow)
+			printk("reset dummy ring buffer for context %x\n",
+			       context);
+#endif
+	}
+
+
+	MSC_OUT(ringbufs[i].rbmrp,new_read_ptr);
+}
+
+/*
+ * give a task one of the system ring buffers 
+ * this is called on a context miss interrupt, so we can assume that
+ * the tasks context is not currently set in one of the ringbufs
+ */
+static void msc_set_ringbuf(int context)
+{
+	int i;
+	int ctx;
+	int mode;
+	unsigned write_ptr;
+	static unsigned next_ctx = 0;
+	struct ringbuf_struct *rbuf;
+
+	if (context == SYSTEM_CONTEXT) {
+		rbuf = &system_ringbuf;
+	} else if (MPP_IS_PAR_CTX(context) && 
+		   valid_task(task[MPP_CTX_TO_TASK(context)]) &&
+		   task[MPP_CTX_TO_TASK(context)]->ringbuf) {
+		struct task_struct *tsk = task[MPP_CTX_TO_TASK(context)];
+		rbuf = tsk->ringbuf;
+	} else if (MPP_IS_PAR_CTX(context) && 
+		   valid_task(task[MPP_CTX_TO_TASK(context)]) &&
+		   task[MPP_CTX_TO_TASK(context)]->aplib) {
+		rbuf = &system_ringbuf;
+	} else {
+		/* use the dummy ring buffer */
+		rbuf = &dummy_ringbuf;
+	}
+
+	for (i=0;i<NR_RBUFS; i++) {
+		ctx = MSC_IN(ringbufs[i].rbmmode)&CTX_MASK;
+		if (ctx == NULL_CONTEXT) break;
+	}
+	if (i == NR_RBUFS) {
+		i = next_ctx;
+		next_ctx = (i+1)%NR_RBUFS;
+	}
+
+	ctx = MSC_IN(ringbufs[i].rbmmode)&CTX_MASK;
+	if (ctx != NULL_CONTEXT) msc_unset_ringbuf(i);
+
+	write_ptr = rbuf->write_ptr;
+	mode = (rbuf->order - 5) >> 1;
+	
+	MSC_OUT(ringbufs[i].rbmmode,context | (mode << 12));
+	MSC_OUT(ringbufs[i].rbmbwp,write_ptr);
+
+	if (rbuf == &system_ringbuf) {
+		MSC_OUT(ringbufs[i].rbmrp,system_read_ptr);
+	} else {
+		msc_update_read_ptr(context,0);
+	}
+	
+#if DEBUG
+	printk("CID(%d) mapped ringbuf for context %d in slot %d\n",
+	       mpp_cid(),context,i);
+#endif
+}
+
+
+/*
+ * this is called when a task exits
+*/
+void exit_msc(struct task_struct *tsk)
+{
+	int i;
+
+	if (!MPP_IS_PAR_TASK(tsk->taskid))
+		return;
+
+#if DEBUG
+	printk("exit_msc(%d) ctx=%d\n",tsk->taskid,tsk->mm->context);
+#endif
+
+	for (i=0;i<NR_RBUFS; i++) {
+		int ctx = MSC_IN(ringbufs[i].rbmmode)&CTX_MASK;
+		if (ctx == MPP_TASK_TO_CTX(tsk->taskid))
+			msc_unset_ringbuf(i);
+	}
+	msc_switch_from_check(tsk);
+
+	/* stop it receiving new-style messages */
+	tsk->aplib = NULL;
+
+	exit_ringbuf(tsk);
+}
+
+
+static void msc_sq_pause(void)
+{
+	MSC_OUT(MSC_SQCTRL,MSC_IN(MSC_SQCTRL) | MSC_SQC_PAUSE);
+	while (!(MSC_IN(MSC_SQCTRL) & MSC_SQC_STABLE)) /* wait for stable bit */ ;
+}
+
+static void msc_sq_resume(void)
+{
+	MSC_OUT(MSC_SQCTRL,MSC_IN(MSC_SQCTRL) & ~MSC_SQC_PAUSE);
+}
+
+static void msc_switch_from_check(struct task_struct *tsk)
+{
+	int user_count;
+	unsigned flags;
+	struct ringbuf_struct *rbuf = NULL;
+	int octx, ctx;
+
+	if (valid_task(tsk) && tsk->ringbuf)
+		rbuf = tsk->ringbuf;
+	
+	/* it doesn't seem obvious why this field should contain count+1,
+	   but it does */
+	user_count = EXTFIELD(MSC_IN(MSC_QWORDCNT),MSC_QWDC_USRCNT) - 1;
+	
+	/* check if the user queue count is != 0 */
+	if (user_count == 0) return;
+
+	if (!rbuf)
+		printk("switching from dead task\n");
+	
+#if 1
+	printk("saving %d words MSC_QWORDCNT=%x\n",
+	       user_count,MSC_IN(MSC_QWORDCNT));
+#endif
+	
+	/* bugger - we have to do some messy work */
+	save_flags(flags); cli();
+
+	ctx = MPP_TASK_TO_CTX(tsk->taskid);
+	octx = apmmu_get_context();
+	if (octx != ctx)
+		apmmu_set_context(ctx);
+
+	msc_sq_pause();
+	
+	/* remember the expected length of the command - usually (always?) 8 */
+	if (rbuf)
+		rbuf->frag_len = EXTFIELD(MSC_IN(MSC_QWORDCNT),MSC_QWDC_USRLEN);
+	
+	/* pull words from the overflow first */
+	if (MSC_IN(MSC_SQCTRL) & MSC_SQC_USERF) {
+		/* we have overflowed */
+		struct qof_elt *qof_wp = qof_base + 
+			(EXTFIELD(MSC_IN(MSC_QBMPTR), MSC_QBMP_WP) & ((QOF_SIZE - 1) >> 3));
+		while (qof_wp != qof_rp && user_count) {
+			qof_wp--;
+			/* only grab elements in the user queue */
+			if (qof_wp->info && log2tbl[EXTFIELD(qof_wp->info, QOF_QUEUE)] == 2) {
+				if (qof_wp->info & 1) {
+					printk("MSC: end bit set - yikes!\n");
+				}
+				qof_wp->info = 0;
+				if (rbuf) {
+					rbuf->sq_fragment[--user_count] = qof_wp->data;
+					rbuf->frag_count++;
+				}
+				if (qof_wp < qof_new)
+					qof_present[2]--;
+			}
+		}
+#if DEBUG
+		if (rbuf)
+			printk("pulled %d elements from overflow (%d left)\n",
+			       rbuf->frag_count,user_count);
+#endif
+	}
+	
+	/* then pull words direct from the msc ram */
+	if (user_count) {
+		int wp = EXTFIELD(MSC_IN(MSC_SQPTR2),MSC_SQP_WP);
+		int i;
+		wp -= user_count;
+		if (wp < 0) wp += send_queues[2].size;
+		
+		for (i=0;i<user_count;i++) {
+			int wp2 = (wp + i)%send_queues[2].size;
+			if (rbuf)
+				rbuf->sq_fragment[i + rbuf->frag_count] = 
+					MSC_IN(MSC_SQRAM + (send_queues[2].base + wp2)*8);
+		}
+		
+		if (rbuf)
+			rbuf->frag_count += user_count;
+		
+		MSC_OUT(MSC_SQPTR2,INSFIELD(MSC_IN(MSC_SQPTR2),wp,MSC_SQP_WP));
+#if DEBUG
+		printk("saved %d words from msc ram\n",rbuf->frag_count);
+#endif
+	}
+  
+	/* reset the user count to 1 */
+	MSC_OUT(MSC_QWORDCNT,INSFIELD(MSC_IN(MSC_QWORDCNT),1,MSC_QWDC_USRCNT));
+	
+	msc_sq_resume();
+
+	if (octx != ctx)
+		apmmu_set_context(octx);
+
+	restore_flags(flags);
+}
+
+static void msc_switch_to_check(struct task_struct *tsk)
+{
+	int i;
+	unsigned flags;
+	int octx, ctx;
+	
+	if (!valid_task(tsk) || !tsk->ringbuf)
+		return;
+
+	save_flags(flags); cli();
+
+	
+	ctx = MPP_TASK_TO_CTX(tsk->taskid);
+	octx = apmmu_get_context();
+	if (octx != ctx)
+		apmmu_set_context(ctx);
+
+	/* if the task we are switching to has no saved words then 
+	   we're finished */
+	if (tsk->ringbuf->frag_count == 0) {
+		if (octx != ctx)
+			apmmu_set_context(octx);
+		restore_flags(flags);
+		return;
+	}
+	
+
+#if 1
+	printk("frag fill MSC_QWORDCNT=%x frag_count=%d\n",
+	       MSC_IN(MSC_QWORDCNT),tsk->ringbuf->frag_count);
+#endif	
+	
+	/* reset the user length */
+	MSC_OUT(MSC_QWORDCNT,INSFIELD(MSC_IN(MSC_QWORDCNT),
+				      tsk->ringbuf->frag_len,
+				      MSC_QWDC_USRLEN));
+	
+	/* push the words into the direct queue */
+	for (i=0;i<tsk->ringbuf->frag_count;i++)
+		MSC_OUT(MSC_USER_DIRECT,tsk->ringbuf->sq_fragment[i]);
+	
+	/* reset the user count */
+	MSC_OUT(MSC_QWORDCNT,INSFIELD(MSC_IN(MSC_QWORDCNT),
+				      1+tsk->ringbuf->frag_count,
+				      MSC_QWDC_USRCNT));
+	
+#if DEBUG
+	printk("frag fill done MSC_QWORDCNT=%x\n",
+	       MSC_IN(MSC_QWORDCNT));
+#endif
+	
+	tsk->ringbuf->frag_count = 0;
+	tsk->ringbuf->frag_len = 0;
+	if (octx != ctx)
+		apmmu_set_context(octx);
+	restore_flags(flags);
+}
+
+
+
+void msc_switch_check(struct task_struct *tsk)
+{
+	static int last_task = 0;
+
+	if (last_task == tsk->taskid) return;
+
+	if (MPP_IS_PAR_TASK(last_task))
+		msc_switch_from_check(task[last_task]);
+
+	msc_switch_to_check(tsk);
+	
+	last_task = tsk->taskid;
+}
+
+/* we want to try to avoid task switching while there are partial commands
+   in the send queues */
+int msc_switch_ok(void)
+{
+	if ((EXTFIELD(MSC_IN(MSC_QWORDCNT),MSC_QWDC_USRCNT) - 1))
+		return 0;
+
+	return 1;
+}
+
+/*
+ * print out the state of the msc
+*/
+static void msc_status(void)
+{
+	int i;
+
+	printk("MSC_SQCTRL=%x\n",MSC_IN(MSC_SQCTRL));
+  
+	for (i=0;i<5;i++)
+		printk("MSC_SQPTR%d=%x\n",i,MSC_IN(MSC_SQPTR0 + 8*i));  
+	printk("MSC_OPTADR=%x\n",MSC_IN(MSC_OPTADR));  
+	printk("MSC_MASCTRL=%x\n", MSC_IN(MSC_MASCTRL));
+	printk("MSC_SMASADR=%x_%x\n", MSC_IN(MSC_SMASADR),MSC_IN(MSC_SMASADR + 4));
+	printk("MSC_RMASADR=%x_%x\n", MSC_IN(MSC_RMASADR),MSC_IN(MSC_RMASADR + 4));
+	printk("MSC_PID=%x\n",MSC_IN(MSC_PID));
+	
+	printk("MSC_QWORDCNT=%x\n",MSC_IN(MSC_QWORDCNT));
+	
+	printk("MSC_INTR=%x\n",MSC_IN(MSC_INTR));
+	printk("MSC_CIDRANGE=%x\n",MSC_IN(MSC_CIDRANGE));
+	printk("MSC_QBMPTR=%x\n",MSC_IN(MSC_QBMPTR));
+	printk("MSC_SMASTWP=%x\n", MSC_IN(MSC_SMASTWP));
+	printk("MSC_RMASTWP=%x\n", MSC_IN(MSC_RMASTWP));
+	printk("MSC_SMASREG=%x\n", MSC_IN(MSC_SMASREG));
+	printk("MSC_RMASREG=%x\n", MSC_IN(MSC_RMASREG));
+	printk("MSC_SMASCNT=%x\n", MSC_IN(MSC_SMASCNT));
+	printk("MSC_IRL=%x\n", MSC_IN(MSC_IRL));
+	printk("MSC_SIMMCHK=%x\n", MSC_IN(MSC_SIMMCHK));
+	
+	for (i=0;i<3;i++) {
+		printk("RBMBWP%d=%x\n",i,MSC_IN(ringbufs[i].rbmbwp));
+		printk("RBMMODE%d=%x\n",i,MSC_IN(ringbufs[i].rbmmode));
+		printk("RBMRP%d=%x\n",i,MSC_IN(ringbufs[i].rbmrp));
+	}
+	
+	printk("DMA_GEN=%x\n",MSC_IN(DMA_GEN));
+
+	printk("qbm_full_counter=%d\n",qbm_full_counter);
+}
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/ap1000/sync.c linux/arch/sparc/ap1000/sync.c
--- v2.1.22/linux/arch/sparc/ap1000/sync.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/ap1000/sync.c	Sun Jan 26 12:07:06 1997
@@ -0,0 +1,55 @@
+  /*
+   * Copyright 1996 The Australian National University.
+   * Copyright 1996 Fujitsu Laboratories Limited
+   * 
+   * This software may be distributed under the terms of the Gnu
+   * Public License version 2 or later
+  */
+/* sync functions using the Tnet */
+
+#include <asm/ap1000/apreg.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/tasks.h>
+
+extern int cap_cid0;
+extern unsigned _ncel, _ncelx, _ncely, _cid;
+
+static volatile int sync_flags[MPP_NUM_TASKS];
+
+
+int ap_sync(int numcells, int *phys_map)
+{
+	int basecell;
+	int i,err;
+	int tsk = current->taskid;
+	
+	if (numcells < 2) return 0;
+
+	if (!MPP_IS_PAR_TASK(tsk)) {
+		printk("nonparallel task %d called ap_sync\n",tsk);
+		return 0;
+	}
+	tsk -= MPP_TASK_BASE;
+	
+	basecell = phys_map[0];
+	if (cap_cid0 == basecell) {    
+		if ((err=wait_on_int(&sync_flags[tsk],numcells-1,5)))
+			return err;
+		sync_flags[tsk] = 0;
+		if (numcells == _ncel) {
+			ap_bput(0,0,0,&sync_flags[tsk],0);
+		} else {
+			for (i=1;i<numcells;i++)
+				ap_put(phys_map[i],0,0,0,&sync_flags[tsk],0);
+		}
+		return 0;
+	}
+	
+	ap_put(basecell,0,0,0,&sync_flags[tsk],0);
+	if ((err=wait_on_int(&sync_flags[tsk],1,5)))
+		return err;
+	sync_flags[tsk] = 0;
+	return 0;
+}
+
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/ap1000/timer.c linux/arch/sparc/ap1000/timer.c
--- v2.1.22/linux/arch/sparc/ap1000/timer.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/ap1000/timer.c	Sun Jan 26 12:07:06 1997
@@ -0,0 +1,126 @@
+  /*
+   * Copyright 1996 The Australian National University.
+   * Copyright 1996 Fujitsu Laboratories Limited
+   * 
+   * This software may be distributed under the terms of the Gnu
+   * Public License version 2 or later
+  */
+/* routines to control the AP1000 timer chip */   
+
+#include <linux/time.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <asm/ap1000/apservice.h>
+#include <asm/ap1000/apreg.h>
+#include <asm/irq.h>
+
+#define INIT_TIM1	(781250/HZ)
+#define INIT_TIM0	(781250/(10*HZ))
+
+static unsigned long last_freerun;
+
+unsigned ap_freerun(void)
+{
+	return *((volatile unsigned long *)(MC_FREERUN + 4));
+}
+
+void ap_clear_clock_irq(void)
+{
+	MC_OUT(MC_INTR, AP_CLR_INTR_REQ << MC_INTR_ITIM1_SH);
+	last_freerun = *((unsigned long *)(MC_FREERUN + 4));
+	tnet_check_completion();
+#if 1
+	if ((((unsigned)jiffies) % (HZ/4)) == 0) {
+		msc_timer();
+		ap_xor_led(1);
+		bif_timer();
+		ap_dbg_flush();
+#if 0
+		bif_led_status();
+#endif
+	}
+#endif
+}
+
+
+void ap_gettimeofday(struct timeval *xt)
+{
+	unsigned long d;
+	unsigned v;
+	unsigned long new_freerun;
+
+	/* this is in 80ns units - we only use the low 32 bits 
+	   as 5mins is plenty for this stuff */
+	d = new_freerun = *((unsigned long *)(MC_FREERUN + 4)); 
+
+	if (d < last_freerun) {
+		/* wraparound */
+		d += ((~0) - last_freerun);
+	} else {
+		d -= last_freerun;
+	}
+
+	/* convert to microseconds */
+	v = ((d&0xffffff)*10)/125;
+	
+	/* only want microseconds/HZ */
+	v = v%(1000000/HZ);
+	
+	xt->tv_usec += v;
+
+	last_freerun = new_freerun;
+}
+
+
+static void profile_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+  if (prof_buffer && current->pid) {
+    extern int _stext;
+    unsigned long ip = instruction_pointer(regs);
+    ip -= (unsigned long) &_stext;
+    ip >>= prof_shift;
+    if (ip < prof_len)
+      prof_buffer[ip]++;
+  }  
+  MC_OUT(MC_INTR,AP_CLR_INTR_REQ << MC_INTR_ITIM0_SH);
+}
+
+void ap_profile_init(void)
+{
+  if (prof_shift) {
+    printk("Initialising profiling with prof_shift=%d\n",(int)prof_shift);
+    MC_OUT(MC_INTR,AP_CLR_INTR_REQ << MC_INTR_ITIM0_SH);
+    MC_OUT(MC_INTR,AP_CLR_INTR_MASK << MC_INTR_ITIM0_SH);
+  }
+}
+
+void ap_init_timers(void)
+{
+	extern void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs);
+	unsigned flags;
+
+	printk("Initialising ap1000 timer\n");
+
+	save_flags(flags); cli();
+	
+	request_irq(APTIM1_IRQ,
+		    timer_interrupt,
+		    (SA_INTERRUPT | SA_STATIC_ALLOC),
+		    "timer", NULL);
+	
+	request_irq(APTIM0_IRQ,
+		    profile_interrupt,
+		    (SA_INTERRUPT | SA_STATIC_ALLOC),
+		    "profile", NULL);
+	
+	ap_clear_clock_irq();
+	
+	MC_OUT(MC_ITIMER0,INIT_TIM0);
+	MC_OUT(MC_ITIMER1,INIT_TIM1);
+	MC_OUT(MC_INTR,AP_CLR_INTR_REQ << MC_INTR_ITIM1_SH);
+	MC_OUT(MC_INTR,AP_CLR_INTR_MASK << MC_INTR_ITIM1_SH);
+	MC_OUT(MC_INTR,AP_SET_INTR_MASK << MC_INTR_ITIM0_SH);
+	restore_flags(flags); 
+}
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/ap1000/tnet.c linux/arch/sparc/ap1000/tnet.c
--- v2.1.22/linux/arch/sparc/ap1000/tnet.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/ap1000/tnet.c	Sun Jan 26 12:07:06 1997
@@ -0,0 +1,709 @@
+  /*
+   * Copyright 1996 The Australian National University.
+   * Copyright 1996 Fujitsu Laboratories Limited
+   * 
+   * This software may be distributed under the terms of the Gnu
+   * Public License version 2 or later
+  */
+/* routines to control the AP1000 Tnet interface */
+
+#include <asm/ap1000/apreg.h>
+#include <asm/ap1000/aplib.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <asm/pgtable.h>
+#include <asm/pgtsrmmu.h>
+#include <stdarg.h>
+#include <linux/skbuff.h>
+
+
+/* message types for system messages */
+#define TNET_IP         0
+#define TNET_IP_SMALL   1
+#define TNET_RPC        2
+
+static struct {
+	int errors;
+	int alloc_errors;
+	int bytes_received;
+	int bytes_sent;
+	int packets_received;
+	int packets_sent;
+	int small_packets_received;
+	int small_packets_sent;
+} tnet_stats;
+
+extern int cap_cid0;
+extern int cap_ncel0;
+static u_long xy_global_head;
+
+extern unsigned _ncel, _ncelx, _ncely, _cid, _cidx, _cidy;
+
+extern struct ringbuf_struct system_ringbuf;
+extern u_long system_read_ptr;
+
+u_long system_recv_flag = 0;
+static u_long system_recv_count = 0;
+
+int *tnet_rel_cid_table;
+
+static int dummy=1;
+
+#define TNET_IP_THRESHOLD 100
+
+void tnet_check_completion(void);
+static void reschedule(void);
+static u_long tnet_add_completion(void (*fn)(int a1,...), 
+				  int a1,int a2);
+static void tnet_info(void);
+
+static struct {
+  int shift;
+  void (*fn)(void);
+} iports[4] = {
+  {MC_INTP_0_SH,tnet_check_completion},
+  {MC_INTP_1_SH,reschedule},
+  {MC_INTP_2_SH,NULL},
+  {MC_INTP_3_SH,NULL}};
+
+static inline int rel_cid(unsigned dst)
+{  
+	unsigned dstx, dsty;
+	unsigned dx,dy;
+
+	if (dst == _cid) return 0;
+
+	dstx = dst % _ncelx;
+	dsty = dst / _ncelx;
+	if (dstx >= _cidx)
+		dx = dstx - _cidx;
+	else
+		dx = (_ncelx - _cidx) + dstx;
+	
+	if (dsty >= _cidy)
+		dy = dsty - _cidy;
+	else
+		dy = (_ncely - _cidy) + dsty;
+	
+	return (dx<<8) | dy;
+}
+
+#define SAVE_PID() \
+  unsigned long flags; \
+  int saved_pid; \
+  save_flags(flags); cli(); \
+  saved_pid = MSC_IN(MSC_PID); \
+  MSC_OUT(MSC_PID,SYSTEM_CONTEXT);
+
+#define RESTORE_PID() \
+  MSC_OUT(MSC_PID,saved_pid); \
+  restore_flags(flags);
+
+
+void ap_put(int dest_cell,u_long local_addr,int size,
+	    u_long remote_addr,u_long dest_flag,u_long local_flag)
+{
+  volatile u_long *entry;
+  SAVE_PID();
+    
+  entry = (volatile u_long *)MSC_PUT_QUEUE_S;
+
+  *entry = tnet_rel_cid_table[dest_cell];
+  *entry = ((size+3) >> 2); 
+  *entry = (u_long)remote_addr;
+  *entry = 0;
+  *entry = (u_long)dest_flag;
+  *entry = (u_long)local_flag;
+  *entry = (u_long)local_addr;
+  *entry = 0;
+  RESTORE_PID();
+}
+
+/* remote_addr is physical 
+   local address is virtual 
+   both flags are virtual */
+void ap_phys_put(int dest_cell,u_long local_addr,int size,
+		 u_long remote_addr,u_long dest_flag,u_long local_flag)
+{
+  volatile u_long *entry;
+  SAVE_PID();
+
+  entry = (volatile u_long *)MSC_CPUT_QUEUE_S;
+
+  *entry = tnet_rel_cid_table[dest_cell];
+  *entry = ((size+3) >> 2); 
+  *entry = (u_long)remote_addr;
+  *entry = 0;
+  *entry = (u_long)dest_flag;
+  *entry = (u_long)local_flag;
+  *entry = (u_long)local_addr;
+  *entry = 0;
+  RESTORE_PID();
+}
+
+
+/* broadcast put - yeah! */
+void ap_bput(u_long local_addr,int size,
+	     u_long remote_addr,u_long dest_flag,u_long local_flag)
+{
+  volatile u_long *entry = (volatile u_long *)MSC_XYG_QUEUE_S;
+  SAVE_PID();
+
+  *entry = xy_global_head;
+  *entry = ((size+3) >> 2);
+  *entry = (u_long)remote_addr;
+  *entry = 0;
+  *entry = (u_long)dest_flag;
+  *entry = (u_long)local_flag;
+  *entry = (u_long)local_addr;
+  *entry = 0;
+  RESTORE_PID();
+}
+
+
+/* remote_addr is physical */
+void ap_phys_bput(u_long local_addr,int size,
+		  u_long remote_addr,u_long dest_flag,u_long local_flag)
+{
+  volatile u_long *entry = (volatile u_long *)MSC_CXYG_QUEUE_S;
+  SAVE_PID();
+
+  *entry = xy_global_head;
+  *entry = ((size+3) >> 2);
+  *entry = (u_long)remote_addr;
+  *entry = 0;
+  *entry = (u_long)dest_flag;
+  *entry = (u_long)local_flag;
+  *entry = (u_long)local_addr;
+  *entry = 0;
+  RESTORE_PID();
+}
+
+
+
+void ap_get(int dest_cell,u_long local_addr,int size,
+	    u_long remote_addr,u_long local_flag,u_long dest_flag)
+{
+  volatile u_long *entry;
+  SAVE_PID();
+    
+  entry = (u_long *)MSC_GET_QUEUE_S;
+
+  *entry = tnet_rel_cid_table[dest_cell];
+  *entry = (size+3) >> 2;           /* byte --> word */
+  *entry = (u_long)local_addr;
+  *entry = 0;
+  *entry = (u_long)local_flag;
+  *entry = (u_long)dest_flag;
+  *entry = (u_long)remote_addr;
+  *entry = 0;    
+  RESTORE_PID();
+}
+
+
+/* local_addr is physical 
+   remote_addr is virtual
+   both flags are virtual
+*/
+void ap_phys_get(int dest_cell,u_long local_addr,int size,
+		 u_long remote_addr,u_long local_flag,u_long dest_flag)
+{
+  volatile u_long *entry;
+  SAVE_PID();
+    
+  entry = (u_long *)MSC_CGET_QUEUE_S;
+
+  *entry = tnet_rel_cid_table[dest_cell];
+  *entry = (size+3) >> 2;           /* byte --> word */
+  *entry = (u_long)local_addr;
+  *entry = 0;
+  *entry = (u_long)local_flag;
+  *entry = (u_long)dest_flag;
+  *entry = (u_long)remote_addr;
+  *entry = 0;    
+  RESTORE_PID();
+}
+
+
+/*
+ * copy a message from the ringbuffer - being careful of wraparound
+*/
+static inline void tnet_copyin(unsigned *dest,unsigned *src,int size)
+{
+	unsigned *limit = (unsigned *)system_ringbuf.ringbuf + 
+		(SYSTEM_RINGBUF_SIZE>>2);
+	int size1 = limit - src;
+
+	if (size < size1)
+		size1 = size;
+
+	size -= size1;
+	while (size1--) {
+		*dest++ = *src++;
+	}
+	src = system_ringbuf.ringbuf;
+	while (size--) {
+		*dest++ = *src++;
+	}
+}
+
+
+/*
+  put some data into a tasks ringbuffer. size is in words.
+  */
+static inline void memcpy_to_rbuf(unsigned tid,unsigned *msgp,unsigned size)
+{
+	struct aplib_struct *aplib;
+	unsigned octx, ctx;
+	struct task_struct *tsk;
+	unsigned room;
+
+	tsk = task[tid];
+	if (!tsk || !tsk->aplib)
+		return;
+
+	octx = srmmu_get_context();
+	ctx = MPP_TASK_TO_CTX(tid);
+	if (octx != ctx)
+		srmmu_set_context(ctx);
+	aplib = tsk->aplib;
+
+	if (aplib->write_pointer < aplib->read_pointer) 
+		room = aplib->read_pointer - (aplib->write_pointer+1);
+	else
+		room = aplib->ringbuf_size - 
+			((aplib->write_pointer+1)-aplib->read_pointer);
+
+	if (room < size) {
+		send_sig(SIGLOST,tsk,1);		
+		goto finished;
+	}
+
+	tnet_copyin(&aplib->ringbuf[aplib->write_pointer], msgp, size);
+
+	aplib->write_pointer += size;
+	if (aplib->write_pointer >= aplib->ringbuf_size)
+		aplib->write_pointer -= aplib->ringbuf_size;
+
+	aplib->rbuf_flag1++;
+
+finished:
+	if (octx != ctx)
+		srmmu_set_context(octx);
+}
+
+
+
+/* a aplib message has arrived on the system message queue - process
+   it immediately and return the number of bytes taken by the message in
+   the system ringbuffer 
+
+   Note that this function may be called from interrupt level
+   */
+static inline void aplib_system_recv(unsigned *msgp)
+{
+	unsigned tag = msgp[1]>>28;
+	unsigned size, tid;
+
+	if (tag == RBUF_BIGSEND) {
+		aplib_bigrecv(msgp);
+		return;
+	}
+
+	size = (msgp[0]&0xFFFFF);
+	tid = (msgp[1]&0x3FF);
+
+	memcpy_to_rbuf(tid,msgp,size+2);
+}
+
+
+void tnet_ip_complete(struct sk_buff *skb,int from)
+{  
+#if IP_DEBUG
+	char *data = skb->data;
+	int i;
+	printk("CID(%d) tnet ip complete from %d\n",_cid,from);
+
+	for (i=0;i<skb->len;i+=4)
+		printk("(%08x)%c",*(int *)(data+i),i==32?'\n':' ');
+	printk("\n");
+#endif
+	/* ap_phys_put(from,(u_long)&dummy,4,MC_INTP_0,0,0); */
+	bif_rx(skb);
+	tnet_stats.bytes_received += skb->len;
+	tnet_stats.packets_received++;
+}
+
+
+static void tnet_ip_recv(int cid,u_long *info)
+{
+	u_long flag;
+	u_long ipsize = info[1];
+	u_long remote_addr = info[0];
+	u_long remote_flag = info[2];
+	struct sk_buff *skb = dev_alloc_skb(ipsize+8);
+	char *p;
+
+	if (!skb) {
+		ap_put(cid,0,0,0,remote_flag,0);
+		ap_phys_put(cid,(u_long)&dummy,4,MC_INTP_0,0,0);
+		tnet_stats.alloc_errors++;
+		return;
+	}
+
+	skb_reserve(skb,8); /* align on 16 byte boundary */
+
+	flag = tnet_add_completion(tnet_ip_complete,(int)skb,(int)cid);
+
+	p = (char *)skb_put(skb,ipsize);
+#if 0
+{
+	static unsigned count=0;
+	if (count%500 == 0)
+		printk("CID(%d) fetching %d bytes from %x to %x\n",
+		       _cid,ipsize,remote_addr,p);
+	count++;
+}
+#endif
+	ap_get(cid,p,ipsize,remote_addr,flag,remote_flag);
+	ap_phys_get(cid,MC_INTP_0,4,(u_long)&dummy,0,0);
+#if IP_DEBUG
+	printk("CID(%d) ip packet of length %ld from %ld\n",_cid,ipsize,cid);
+#endif
+}
+
+
+static void tnet_ip_recv_small(u_long *data,int size)
+{
+	struct sk_buff *skb = dev_alloc_skb(size+8);
+	if (skb) {
+		skb_reserve(skb,8);
+		tnet_copyin((unsigned *)skb_put(skb,size),(unsigned *)data,(size+3)>>2);
+		bif_rx(skb);
+		tnet_stats.bytes_received += size;
+		tnet_stats.packets_received++;
+		tnet_stats.small_packets_received++;
+	} else {
+		tnet_stats.alloc_errors++;
+	}
+}
+
+
+/* we've got an RPC from a remote cell */
+static void tnet_rpc_recv(u_long *data,int size)
+{
+	struct fnp {
+		void (*fn)();
+	} fnp;
+	fnp = *(struct fnp *)data;
+	fnp.fn(data,size);
+}
+
+/*
+ * receive messages from the system ringbuffer. We don't bother with
+ * all the niceities that are done in user space, we just always
+ * process the messages in order 
+ */
+static inline void tnet_recv(void)
+{
+	unsigned flags;
+	u_long from,*data,fix,align,size1,size,type;
+
+	if (system_recv_flag == system_recv_count) 
+		return;
+
+	save_flags(flags); cli();
+	while (system_recv_flag != system_recv_count) {
+		u_long read_ptr = 
+			(system_read_ptr + 1) % (SYSTEM_RINGBUF_SIZE>>5);  
+		u_long *msgp = 
+			((u_long *)system_ringbuf.ringbuf) + (read_ptr<<3);
+		u_long tag = (msgp[1]>>28) & 0xF;
+		size1 = (msgp[0]&0xFFFFF)<<2;
+
+		/* move our read pointer past this message */
+		system_read_ptr = (system_read_ptr + 
+				   ((size1+8+31)>>5))%(SYSTEM_RINGBUF_SIZE>>5);
+		system_recv_count++;		
+
+
+		if (tag != RBUF_SYSTEM) {
+			aplib_system_recv(msgp);
+			continue;
+		} 
+
+		from = msgp[0] >> 22;
+		data = msgp+2;
+		fix = (msgp[0]>>20)&3;
+		align = (msgp[1]>>26)&3;
+		size = ((size1 - align) & ~3) | fix;
+		type = (msgp[1]&0xFF);
+
+		switch (type) {
+		case TNET_IP:
+			tnet_ip_recv(from,data);
+			break;
+			
+		case TNET_IP_SMALL:
+			tnet_ip_recv_small(data,size);
+			break;
+			
+		case TNET_RPC:
+			tnet_rpc_recv(data,size);
+			break;
+			
+		default:
+			tnet_stats.errors++;
+			printk("unknown Tnet type %ld\n",type);
+		}
+
+#if DEBUG
+		printk("CID(%d) recvd %d bytes of type %d read_ptr=%x\n",
+		       _cid,size,type,system_read_ptr);
+#endif
+	}
+	restore_flags(flags);
+}
+
+
+#define COMPLETION_LIST_LENGTH 256
+
+static unsigned completion_list_rp = 0;
+static unsigned completion_list_wp = 0;
+
+static volatile struct completion_struct {
+  u_long flag;
+  void (*fn)(int a1,...);
+  u_long args[2];
+} completion_list[COMPLETION_LIST_LENGTH];
+
+
+void tnet_check_completion(void)
+{
+	struct completion_struct *cs;
+	unsigned flags;
+
+	tnet_recv();  
+
+	if (completion_list[completion_list_rp].flag != 2)
+		return;
+
+	save_flags(flags); cli();
+  
+	while (completion_list[completion_list_rp].flag == 2) {
+		cs = &completion_list[completion_list_rp];
+		cs->flag = 0;
+		if (++completion_list_rp == COMPLETION_LIST_LENGTH)
+			completion_list_rp = 0;
+
+		restore_flags(flags);
+
+		cs->fn(cs->args[0],cs->args[1]);
+
+		if (completion_list[completion_list_rp].flag != 2)
+			return;
+
+		save_flags(flags); cli();
+	}
+	
+	restore_flags(flags);
+}
+
+
+static u_long tnet_add_completion(void (*fn)(int a1,...),int a1,int a2)
+{
+        unsigned flags;
+        struct completion_struct *cs;
+	
+	save_flags(flags); cli();
+
+	while (completion_list[completion_list_wp].flag != 0)
+		tnet_check_completion();
+
+	cs = &completion_list[completion_list_wp];
+
+	if (++completion_list_wp == COMPLETION_LIST_LENGTH)
+		completion_list_wp = 0;
+
+	restore_flags(flags);
+
+        cs->flag = 1;
+        cs->fn = fn;
+	cs->args[0] = a1;
+	cs->args[1] = a2;
+
+        return (u_long)&cs->flag;
+}
+
+
+/* 
+ * send a message to the tnet ringuffer on another cell. When the send has
+ * completed call fn with the args supplied 
+ */
+static void tnet_send(long cid,long type,char *src_addr,long byteSize,
+		      int immediate,u_long flag)
+{
+	int wordSize;
+	int byteAlign, byteFix;
+	u_long src;
+	u_long info1, info2;
+	volatile u_long *entry = (volatile u_long *)MSC_SEND_QUEUE_S;
+	SAVE_PID();
+
+	byteAlign = ((u_long)src_addr) & 0x3;
+	byteFix = byteSize & 0x3;
+	
+	src = (u_long)src_addr & ~3;
+	
+	wordSize = (byteSize + byteAlign + 3) >> 2;
+	
+	info1 = (_cid << 22) | (byteFix << 20) | wordSize;
+	info2 = (RBUF_SYSTEM<<28) | (byteAlign << 26) | type;
+	
+	*entry = tnet_rel_cid_table[cid];
+	*entry = wordSize;
+	*entry = (u_long)&system_recv_flag;
+	*entry = flag;
+	*entry = (u_long)src;
+	*entry = 0;
+	*entry = info1;
+	*entry = info2;
+	RESTORE_PID();
+	
+	ap_phys_put(cid,(u_long)&dummy,4,MC_INTP_0,0,0);
+	if (immediate && flag) 
+		ap_phys_put(_cid,(u_long)&dummy,4,MC_INTP_0,0,0);
+}
+
+
+static void free_skb(struct sk_buff *skb, int op)
+{
+	dev_kfree_skb(skb,op);
+}
+
+void tnet_send_ip(int cid,struct sk_buff *skb)
+{
+	char *data = skb->data + sizeof(struct cap_request);
+	int size = skb->len - sizeof(struct cap_request);
+	u_long flag;
+#if IP_DEBUG
+	int i;
+	for (i=0;i<size;i+=4)
+		printk("[%08x]%c",*(int *)(data+i),i==32?'\n':' ');
+	printk("\n");
+#endif
+	if (size > TNET_IP_THRESHOLD) {
+		int *info = (int *)skb->data; /* re-use the header */
+		info[0] = (int)data;
+		info[1] = size;
+		info[2] = tnet_add_completion(free_skb,(int)skb,(int)FREE_WRITE);
+		tnet_send(cid,TNET_IP,info,sizeof(int)*3,0,0);
+	} else {
+		flag = tnet_add_completion(free_skb,
+					   (int)skb,(int)FREE_WRITE);
+		tnet_send(cid,TNET_IP_SMALL,data,size,0,flag);
+		tnet_stats.small_packets_sent++;
+	}
+	tnet_stats.packets_sent++;
+	tnet_stats.bytes_sent += size;
+#if IP_DEBUG
+	printk("CID(%d) sent IP of size %d to %d\n",_cid,size,cid);
+#endif
+}
+
+static void reschedule(void)
+{
+	need_resched = 1;  
+	mark_bh(TQUEUE_BH);
+}
+
+
+/* make a remote procedure call 
+   If free is set then free the data after sending it 
+   The first element of data is presumed to be a function pointer
+*/
+int tnet_rpc(int cell,char *data,int size,int free)
+{
+	unsigned flag=0;
+
+	if (free) {
+		flag = tnet_add_completion(kfree,data,0);
+	}
+
+	tnet_send(cell,TNET_RPC,data,size,0,flag);
+	return 0;
+}
+
+
+static void iport_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+	int i;
+	u_long intr = MC_IN(MC_INTR_PORT);
+
+	for (i=0;i<4;i++) {
+		if (intr & (AP_INTR_REQ << iports[i].shift)) {
+			MC_OUT(MC_INTR_PORT,AP_CLR_INTR_REQ << iports[i].shift);
+			if (iports[i].fn) iports[i].fn();
+		}
+	}
+}
+
+
+void ap_tnet_init(void)
+{
+	int i;
+
+	bif_add_debug_key('T',tnet_info,"Tnet status");
+
+	memset(completion_list,0,sizeof(completion_list));
+	
+	request_irq(APIPORT_IRQ, iport_irq, SA_INTERRUPT, "iport", 0);
+
+	for (i=0;i<4;i++) {
+		MC_OUT(MC_INTR_PORT,AP_CLR_INTR_REQ << iports[i].shift);
+		MC_OUT(MC_INTR_PORT,AP_CLR_INTR_MASK << iports[i].shift);
+	}    
+
+
+	tnet_rel_cid_table = (int *)kmalloc(sizeof(int)*_ncel,GFP_ATOMIC);
+	for (i=0;i<_ncel;i++)
+		tnet_rel_cid_table[i] = rel_cid(i);
+
+	if(_cid == 0) {
+		xy_global_head  = (((_ncelx -1) << 8) & 0xff00) | 
+			((_ncely - 1) & 0xff);
+	}
+	else {
+		for(i = 1; i < _ncel; i *= 2){
+			if(i & _cid) {	
+				int	rcidx = (_cid-i)%_ncelx - _cid%_ncelx;
+				int	rcidy = (_cid-i)/_ncelx - _cid/_ncelx;
+				xy_global_head  = ((rcidx << 8) & 0xff00) | 
+					(rcidy & 0xff);
+				break;	
+			}
+		}
+	}
+}
+
+static void tnet_info(void)
+{
+	struct completion_struct *cs;
+	
+	printk(
+	       "errors=%d  alloc_errors=%d
+bytes_received=%d  bytes_sent=%d
+packets_received=%d  packets_sent=%d
+small_received=%d  small_sent=%d
+",
+	       tnet_stats.errors, tnet_stats.alloc_errors,
+	       tnet_stats.bytes_received,
+	       tnet_stats.bytes_sent, tnet_stats.packets_received,
+	       tnet_stats.packets_sent, tnet_stats.small_packets_received,
+	       tnet_stats.small_packets_sent);
+
+	printk("recv_flag=%d recv_count=%d read_ptr=%d\n",
+	       system_recv_flag,system_recv_count,system_read_ptr);
+	printk("completion_list_rp=%d  completion_list_wp=%d\n",
+	       completion_list_rp,completion_list_wp);
+}
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/ap1000/util.c linux/arch/sparc/ap1000/util.c
--- v2.1.22/linux/arch/sparc/ap1000/util.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/ap1000/util.c	Sun Jan 26 12:07:06 1997
@@ -0,0 +1,436 @@
+  /*
+   * Copyright 1996 The Australian National University.
+   * Copyright 1996 Fujitsu Laboratories Limited
+   * 
+   * This software may be distributed under the terms of the Gnu
+   * Public License version 2 or later
+  */
+/* general utility functions for the AP1000 */
+
+#include <linux/sched.h>
+#include <asm/ap1000/apservice.h>
+#include <asm/ap1000/apreg.h>
+#include <asm/asi.h>
+#include <asm/delay.h>
+#include <asm/pgtable.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/mpp.h>
+
+#define APLOG 0
+
+struct cap_init cap_init;
+
+/* find what cell id we are running on */
+int mpp_cid(void)
+{
+  return(BIF_IN(BIF_CIDR1));
+}
+
+/* find how many cells there are */
+int mpp_num_cells(void)
+{
+  return(cap_init.numcells);
+}
+
+/* this can be used to ensure some data is readable before DMAing
+   it. */
+int ap_verify_data(char *d,int len)
+{
+	int res = 0;
+	while (len--) res += *d++;
+	return res;
+}
+
+/* How many bogo mips in the entire machine
+Dont worry about float because when it gets this big, its irrelevant */
+int mpp_agg_bogomips(void)
+{
+  return mpp_num_cells()*loops_per_sec/500000; /* cheat in working it out */
+}
+
+/* Puts multiprocessor configuration info into a buffer */
+int get_mppinfo(char *buffer)
+{
+  return sprintf(buffer,
+		 "Machine Type:\t\t: %s\nNumber of Cells\t\t: %d\nAggregate BogoMIPS\t: %d\n",
+		 "Fujitsu AP1000+",
+		 mpp_num_cells(),
+		 mpp_agg_bogomips());
+}
+
+#if APLOG
+static int do_logging = 0;
+
+
+void ap_log(char *buf,int len)
+{
+#define LOG_MAGIC 0x8736526
+	static char *logbase;
+	static char *logptr;
+	static int logsize = 1024;
+	int l,i;
+
+	if (buf == NULL && len == -1) {
+		logbase = kmalloc(logsize + 8,GFP_ATOMIC);
+		
+		if (!logbase) {
+			printk("log init failed\n");
+			return;
+		}
+		for (i=0;i<logsize;i++)
+			if (logbase[8+i] == '|')
+				logbase[8+i] = '_';
+
+		if ((*(int *)logbase) == LOG_MAGIC) {
+			int oldoffset = *(int *)(logbase + 4);
+			printk("==%3d== START OLD LOG ==\n",mpp_cid());
+			ap_write(1,logbase + 8 + oldoffset,logsize - oldoffset);
+			ap_write(1,logbase+8,oldoffset);
+			printk("==%3d== END OLD LOG ==\n",mpp_cid());
+		}
+		*(int *)logbase = LOG_MAGIC;
+		*(int *)(logbase+4) = 0;
+		logbase += 8;
+		logptr = logbase;
+		memset(logbase,0,logsize);
+		do_logging = 1;
+		return;
+	}
+
+	if (!do_logging) return;
+
+	while (len) {
+		l = logsize - (logptr - logbase);
+		if (l > len) l = len;
+		memcpy(logptr,buf,l);
+		len -= l;
+		logptr += l;
+		if (logptr == logbase + logsize) 
+			logptr = logbase;
+	}
+	*(int *)(logbase - 4) = (logptr - logbase);
+}
+#endif
+
+int ap_current_uid = -1;
+
+/* set output only to a particular uid */
+void ap_set_user(int uid)
+{
+	ap_current_uid = uid;
+}
+
+/* write some data to a filedescriptor on the front end */
+int ap_write(int fd,char *buf,int nbytes)
+{
+	struct cap_request req;
+
+	if (nbytes == 0) return 0;
+
+#if APLOG
+	ap_log(buf,nbytes);
+	
+	if (buf[0] == '|') return nbytes;
+#endif
+
+	req.cid = mpp_cid();
+	req.type = REQ_WRITE;
+	req.size = nbytes + sizeof(req);
+	req.data[0] = fd;
+	if (ap_current_uid == -1 && current && current->pid) {
+		req.data[1] = current->uid;
+	} else {
+		req.data[1] = ap_current_uid;
+	}
+	req.header = MAKE_HEADER(HOST_CID);
+	
+	bif_queue(&req,buf,nbytes);
+
+	return(nbytes);
+}
+
+/* write one character to stdout on the front end */
+int ap_putchar(char c)
+{
+  struct cap_request req;
+
+#if APLOG
+  ap_log(&c,1);
+#endif
+
+  req.cid = mpp_cid();
+  req.type = REQ_PUTCHAR;
+  req.size = sizeof(req);
+  req.data[0] = c;
+  req.header = MAKE_HEADER(HOST_CID);
+
+  bif_queue(&req,0,0);
+
+  return(0);
+}
+
+/* start the debugger (kgdb) on this cell */
+void ap_start_debugger(void)
+{
+	static int done = 0;
+	extern void set_debug_traps(void);
+	extern void breakpoint(void);
+	if (!done)
+		set_debug_traps();
+	done = 1;
+	breakpoint();
+}
+
+void ap_panic(char *msg,int a1,int a2,int a3,int a4,int a5)
+{
+	ap_led(0xAA);
+	printk(msg,a1,a2,a3,a4,a5);
+	ap_start_debugger();
+}
+
+void ap_printk(char *msg,int a1,int a2,int a3,int a4,int a5)
+{
+  printk(msg,a1,a2,a3,a4,a5);
+  /* bif_queue_flush(); */
+}
+
+/* get the command line arguments from the front end */
+void ap_getbootargs(char *buf)
+{
+    struct cap_request req;
+    int size;
+
+    req.cid = mpp_cid();
+    req.type = REQ_GETBOOTARGS;
+    req.size = sizeof(req);
+    req.header = MAKE_HEADER(HOST_CID);
+    
+    write_bif_polled((char *)&req,sizeof(req),NULL,0);
+
+    ap_wait_request(&req,REQ_GETBOOTARGS); 
+
+    size = req.size - sizeof(req);
+    if (size == 0)
+      buf[0] = '\0';
+    else {
+      read_bif(buf, size);
+    }
+
+    req.cid = mpp_cid();
+    req.type = REQ_INIT;
+    req.size = sizeof(req);
+    req.header = MAKE_HEADER(HOST_CID);
+
+    write_bif_polled((char *)&req,sizeof(req),NULL,0);
+
+    ap_wait_request(&req,REQ_INIT);
+
+    if (req.size != sizeof(req))
+      read_bif((char *)&cap_init,req.size - sizeof(req));
+    if ((req.size - sizeof(req)) != sizeof(cap_init))
+      printk("WARNING: Init structure is wrong size, recompile util.c\n");
+
+    if (cap_init.gdbcell == mpp_cid())
+      ap_start_debugger();
+
+    printk("Got command line arguments from server\n");
+}
+
+/* a useful utility for debugging pagetable setups */
+void show_mapping_ctx(unsigned *ctp,int context,unsigned Vm)
+{  
+  unsigned *pgtable;
+  int entry[3];
+  int level = 0;
+
+  if (!ctp) ctp = (unsigned *)mmu_p2v(srmmu_get_ctable_ptr());
+
+  printk("ctp=0x%x ",(int)ctp);
+
+  pgtable = ctp + context;
+
+  /* get the virtual page */
+  Vm = Vm>>12;
+
+  printk("Vm page 0x%x is ",Vm);  
+
+  entry[0] = Vm>>12;
+  entry[1] = (Vm>>6) & 0x3f;
+  entry[2] = Vm & 0x3f;
+
+  while (1) {
+
+#if 1
+    printk("(%08x) ",pgtable[0]);
+#endif
+
+  if ((pgtable[0] & 3) == 2) {
+    printk("mapped at level %d to 0x%x\n",level,pgtable[0]>>8);
+    return;
+  }
+
+  if ((pgtable[0] & 3) == 0) {
+    printk("unmapped at level %d\n",level);
+    return;
+  }
+
+  if ((pgtable[0] & 3) == 3) {
+    printk("invalid at level %d\n",level);
+    return;
+  }
+
+  if ((pgtable[0] & 3) == 1) {
+    pgtable = (unsigned *)(((pgtable[0]>>2)<<6)|0xf0000000);
+    pgtable += entry[level];
+    level++;
+  }
+  } 
+}
+
+
+
+static unsigned char current_led = 0;
+
+void ap_led(unsigned char d)
+{
+  unsigned paddr = 0x1000;
+  unsigned word = 0xff & ~d;
+  current_led = d;
+  __asm__ __volatile__("sta %0, [%1] %2\n\t" : :
+		       "r" (word), "r" (paddr), "i" (0x2c) :
+		       "memory");
+}
+
+void ap_xor_led(unsigned char d)
+{
+	ap_led(current_led ^ d);
+}
+
+void ap_set_led(unsigned char d)
+{
+	ap_led(current_led | d);
+}
+
+void ap_unset_led(unsigned char d)
+{
+	ap_led(current_led & ~d);
+}
+
+
+void kbd_put_char(char c)
+{
+  ap_putchar(c);
+}
+
+
+void ap_enter_irq(int irq)
+{
+  unsigned char v = current_led;
+  switch (irq) {
+  case 2: v |= (1<<1); break;
+  case 4: v |= (1<<2); break;
+  case 8: v |= (1<<3); break;
+  case 9: v |= (1<<4); break;
+  case 10: v |= (1<<5); break;
+  case 11: v |= (1<<6); break;
+  default: v |= (1<<7); break;
+  }
+  ap_led(v);
+}
+
+void ap_exit_irq(int irq)
+{
+  unsigned char v = current_led;
+  switch (irq) {
+  case 2: v &= ~(1<<1); break;
+  case 4: v &= ~(1<<2); break;
+  case 8: v &= ~(1<<3); break;
+  case 9: v &= ~(1<<4); break;
+  case 10: v &= ~(1<<5); break;
+  case 11: v &= ~(1<<6); break;
+  default: v &= ~(1<<7); break;
+  }
+  ap_led(v);
+}
+
+
+static struct wait_queue *timer_wait = NULL;
+
+static void wait_callback(unsigned long _ignored)
+{
+  wake_up(&timer_wait);
+}
+
+/* wait till x == *p */
+int wait_on_int(volatile int *p,int x,int interval)
+{
+	struct timer_list *timer = kmalloc(sizeof(*timer),GFP_KERNEL);
+	if (!timer) panic("out of memory in wait_on_int()\n");
+	timer->next = NULL;
+	timer->prev = NULL;
+	timer->data = 0;
+	timer->function = wait_callback;
+	while (*p != x) {
+		timer->expires = jiffies + interval;
+		add_timer(timer);
+		interruptible_sleep_on(&timer_wait);
+		del_timer(timer);
+		if (current->signal & ~current->blocked)
+			return -EINTR;
+	}
+	kfree_s(timer,sizeof(*timer));
+	return 0;
+}
+
+
+/* an ugly hack to get nfs booting from a central cell to work */
+void ap_nfs_hook(unsigned long server)
+{
+  unsigned cid = server - cap_init.baseIP;
+  if (cid < cap_init.bootcid + cap_init.numcells &&
+      cid != mpp_cid()) {
+    unsigned end = jiffies + 20*HZ;
+    /* we are booting from another cell */
+    printk("waiting for the master cell\n");
+    while (jiffies < end) ;
+    printk("continuing\n");
+  }
+}
+
+/* convert a IP address to a cell id */
+int ap_ip_to_cid(u_long ip)
+{
+  unsigned cid;
+
+  if ((ip & cap_init.netmask) != (cap_init.baseIP & cap_init.netmask))
+    return -1;
+
+  if ((ip & ~cap_init.netmask) == AP_ALIAS_IP)
+    cid = cap_init.bootcid;
+  else
+    cid = ip - cap_init.baseIP;
+  if (cid >= cap_init.bootcid + cap_init.numcells)
+    return -1;
+  return cid;
+}
+
+
+void ap_reboot(char *bootstr)
+{
+	printk("cell(%d) - don't know how to reboot\n",mpp_cid());
+	sti();
+	while (1) ;
+}
+
+
+void dumb_memset(char *buf,char val,int len)
+{
+	while (len--) *buf++ = val;
+}
+
+void ap_init_time(struct timeval *xtime)
+{
+	xtime->tv_sec = cap_init.init_time;
+	xtime->tv_usec = 0;
+}
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/config.in linux/arch/sparc/config.in
--- v2.1.22/linux/arch/sparc/config.in	Sun Dec 22 16:37:23 1996
+++ linux/arch/sparc/config.in	Sun Jan 26 12:07:06 1997
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.31 1996/12/18 06:18:35 tridge Exp $
+# $Id: config.in,v 1.32 1997/01/25 23:10:12 ecd Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
@@ -126,7 +126,7 @@
 		  bool ' Keepalive and linefill' CONFIG_SLIP_SMART
 		  bool ' Six bit SLIP encapsulation' CONFIG_SLIP_MODE_SLIP6
 		fi
-		bool 'Sun LANCE support' CONFIG_SUNLANCE
+		tristate 'Sun LANCE support' CONFIG_SUNLANCE
 		tristate 'Sun Happy Meal 10/100baseT support' CONFIG_HAPPYMEAL
 		tristate 'Sun QuadEthernet support' CONFIG_SUNQE
 		tristate 'MyriCOM Gigabit Ethernet support' CONFIG_MYRI_SBUS
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/defconfig linux/arch/sparc/defconfig
--- v2.1.22/linux/arch/sparc/defconfig	Wed Jan 15 19:45:40 1997
+++ linux/arch/sparc/defconfig	Sun Jan 26 12:07:06 1997
@@ -11,7 +11,7 @@
 # Loadable module support
 #
 CONFIG_MODULES=y
-# CONFIG_MODVERSIONS is not set
+CONFIG_MODVERSIONS=y
 CONFIG_KERNELD=y
 
 #
@@ -114,6 +114,7 @@
 CONFIG_ATALK=m
 # CONFIG_AX25 is not set
 CONFIG_X25=m
+# CONFIG_LAPB is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_LLC is not set
 
@@ -184,6 +185,7 @@
 CONFIG_HPFS_FS=m
 CONFIG_SYSV_FS=m
 CONFIG_AFFS_FS=m
+CONFIG_ROMFS_FS=m
 CONFIG_AMIGA_PARTITION=y
 CONFIG_UFS_FS=y
 CONFIG_BSD_DISKLABEL=y
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/kernel/Makefile linux/arch/sparc/kernel/Makefile
--- v2.1.22/linux/arch/sparc/kernel/Makefile	Wed Dec 18 15:58:43 1996
+++ linux/arch/sparc/kernel/Makefile	Sun Jan 26 12:07:06 1997
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.35 1996/11/13 05:09:15 davem Exp $
+# $Id: Makefile,v 1.37 1997/01/06 06:52:15 davem Exp $
 # Makefile for the linux kernel.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -27,7 +27,7 @@
 
 endif
 
-all: kernel.o head.o initobj.o finitobj.o
+all: kernel.o head.o
 
 O_TARGET := kernel.o
 IRQ_OBJS := irq.o sun4m_irq.o sun4c_irq.o
@@ -41,7 +41,7 @@
 OX_OBJS  := sparc_ksyms.o
 
 ifdef SMP
-O_OBJS += trampoline.o smp.o rirq.o
+O_OBJS += trampoline.o smp.o
 endif
 
 ifdef CONFIG_SUN_AUXIO
@@ -59,12 +59,5 @@
 	$(CC) -D__ASSEMBLY__ -ansi -c $*.S -o $*.o
 
 endif
-
-initobj.o: initobj.S
-	$(CC) -D__ASSEMBLY__ -ansi -c initobj.S -o initobj.o
-
-finitobj.o: initobj.S
-	$(CC) -D__ASSEMBLY__ -ansi -c finitobj.S -o finitobj.o
-
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/kernel/entry.S linux/arch/sparc/kernel/entry.S
--- v2.1.22/linux/arch/sparc/kernel/entry.S	Tue Dec 31 21:40:59 1996
+++ linux/arch/sparc/kernel/entry.S	Sun Jan 26 12:07:06 1997
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.129 1996/12/30 00:31:07 davem Exp $
+/* $Id: entry.S,v 1.131 1997/01/12 09:06:55 davem Exp $
  * arch/sparc/kernel/entry.S:  Sparc trap low-level entry points.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -54,7 +54,6 @@
 C_LABEL(trap_low):
 	rd	%wim, %l3
 	SAVE_ALL
-	ENTER_SYSCALL
 
 	sethi	%hi(in_trap_handler), %l4
 	ld	[%lo(in_trap_handler) + %l4], %l5
@@ -246,7 +245,6 @@
 floppy_dosoftint:
 	rd	%wim, %l3
 	SAVE_ALL
-	ENTER_IRQ
 
 	/* Set all IRQs off. */
 	or	%l0, PSR_PIL, %l4
@@ -257,10 +255,9 @@
 
 	mov	11, %o0			! floppy irq level (unused anyway)
 	mov	%g0, %o1		! devid is not used in fast interrupts
-	call	C_LABEL(floppy_interrupt)
+	call	C_LABEL(sparc_floppy_irq)
 	 add	%sp, REGWIN_SZ, %o2	! struct pt_regs *regs
 
-	LEAVE_IRQ
 	RESTORE_ALL
 	
 #endif /* (CONFIG_BLK_DEV_FD) */
@@ -269,7 +266,6 @@
 	.globl	bad_trap_handler
 bad_trap_handler:
 	SAVE_ALL
-	ENTER_SYSCALL
 
 	wr	%l0, PSR_ET, %psr
 	WRITE_PAUSE
@@ -290,27 +286,6 @@
 	.globl	real_irq_entry
 real_irq_entry:
 	SAVE_ALL
-#ifdef __SMP__
-	cmp	%l7, 9
-	bne	1f
-	 nop
-
-	GET_PROCESSOR_MID(l4, l5)
-	set	C_LABEL(sun4m_interrupts), %l5
-	ld	[%l5], %l5
-	sethi	%hi(0x02000000), %l6
-	sll	%l4, 12, %l4
-	add	%l5, %l4, %l5
-	ld	[%l5], %l4
-	andcc	%l4, %l6, %g0
-	be	1f
-	 nop
-
-	b,a	linux_trap_ipi9_sun4m
-
-1:
-#endif
-	ENTER_IRQ
 
 #ifdef __SMP__
 	cmp	%l7, 13
@@ -335,14 +310,9 @@
 
 #endif
 
-	/* start atomic operation with respect to software interrupts */
-	sethi	%hi(C_LABEL(intr_count)), %l6
-	ld	[%l6 + %lo(C_LABEL(intr_count))], %l5
 	or	%l0, PSR_PIL, %g2
-	add	%l5, 0x1, %l4
 	wr	%g2, 0x0, %psr
 	WRITE_PAUSE
-	st	%l4, [%l6 + %lo(C_LABEL(intr_count))]
 	wr	%g2, PSR_ET, %psr
 	WRITE_PAUSE
 	mov	%l7, %o0		! irq level
@@ -350,8 +320,7 @@
 	 add	%sp, REGWIN_SZ, %o1	! pt_regs ptr
 	wr	%l0, PSR_ET, %psr
 	WRITE_PAUSE
-	st	%l5, [%l6 + %lo(C_LABEL(intr_count))]
-	LEAVE_IRQ
+
 	RESTORE_ALL
 
 	/* This routine handles illegal instructions and privileged
@@ -361,7 +330,6 @@
 	.globl	bad_instruction
 bad_instruction:
 	SAVE_ALL
-	ENTER_SYSCALL
 
 	wr	%l0, PSR_ET, %psr		! re-enable traps
 	WRITE_PAUSE
@@ -378,7 +346,6 @@
 	.globl	priv_instruction
 priv_instruction:
 	SAVE_ALL
-	ENTER_SYSCALL
 
 	wr	%l0, PSR_ET, %psr
 	WRITE_PAUSE
@@ -400,7 +367,6 @@
 	 nop
 
 	SAVE_ALL
-	ENTER_SYSCALL
 
 	wr	%l0, PSR_ET, %psr
 	WRITE_PAUSE
@@ -413,7 +379,6 @@
 
 mna_fromuser:
 	SAVE_ALL
-	ENTER_SYSCALL
 
 	wr	%l0, PSR_ET, %psr		! re-enable traps
 	WRITE_PAUSE
@@ -429,7 +394,6 @@
 	.globl	fpd_trap_handler
 fpd_trap_handler:
 	SAVE_ALL
-	ENTER_SYSCALL
 
 	wr	%l0, PSR_ET, %psr		! re-enable traps
 	WRITE_PAUSE
@@ -469,7 +433,6 @@
 
 2:
 	SAVE_ALL
-	ENTER_SYSCALL
 
 	wr	%l0, PSR_ET, %psr		! re-enable traps
 	WRITE_PAUSE
@@ -487,7 +450,6 @@
 	.globl	do_tag_overflow
 do_tag_overflow:
 	SAVE_ALL
-	ENTER_SYSCALL
 
 	wr	%l0, PSR_ET, %psr		! re-enable traps
 	WRITE_PAUSE
@@ -505,7 +467,6 @@
 	.globl	do_watchpoint
 do_watchpoint:
 	SAVE_ALL
-	ENTER_SYSCALL
 
 	wr	%l0, PSR_ET, %psr		! re-enable traps
 	WRITE_PAUSE
@@ -523,7 +484,6 @@
 	.globl	do_reg_access
 do_reg_access:
 	SAVE_ALL
-	ENTER_SYSCALL
 
 	wr	%l0, PSR_ET, %psr		! re-enable traps
 	WRITE_PAUSE
@@ -541,7 +501,6 @@
 	.globl	do_cp_disabled
 do_cp_disabled:
 	SAVE_ALL
-	ENTER_SYSCALL
 
 	wr	%l0, PSR_ET, %psr		! re-enable traps
 	WRITE_PAUSE
@@ -559,7 +518,6 @@
 	.globl	do_bad_flush
 do_bad_flush:
 	SAVE_ALL
-	ENTER_SYSCALL
 
 	wr	%l0, PSR_ET, %psr		! re-enable traps
 	WRITE_PAUSE
@@ -577,7 +535,6 @@
 	.globl	do_cp_exception
 do_cp_exception:
 	SAVE_ALL
-	ENTER_SYSCALL
 
 	wr	%l0, PSR_ET, %psr		! re-enable traps
 	WRITE_PAUSE
@@ -595,7 +552,6 @@
 	.globl	do_hw_divzero
 do_hw_divzero:
 	SAVE_ALL
-	ENTER_SYSCALL
 
 	wr	%l0, PSR_ET, %psr		! re-enable traps
 	WRITE_PAUSE
@@ -612,7 +568,6 @@
 	.globl	do_flush_windows
 do_flush_windows:
 	SAVE_ALL
-	ENTER_SYSCALL
 
 	wr	%l0, PSR_ET, %psr
 	WRITE_PAUSE
@@ -683,7 +638,6 @@
 	.globl	linux_trap_nmi_sun4c
 linux_trap_nmi_sun4c:
 	SAVE_ALL
-	ENTER_SYSCALL
 
 	/* Ugh, we need to clear the IRQ line.  This is now
 	 * a very sun4c specific trap handler...
@@ -718,46 +672,9 @@
 	RESTORE_ALL
 
 #ifdef __SMP__
-
-	.align	4
-	.globl	linux_trap_ipi9_sun4m
-linux_trap_ipi9_sun4m:
-	sethi	%hi(0x02000000), %o2
-	GET_PROCESSOR_MID(o0, o1)
-	set	C_LABEL(sun4m_interrupts), %l5
-	ld	[%l5], %o5
-	sll	%o0, 12, %o0
-	add	%o5, %o0, %o5
-	st	%o2, [%o5 + 4]
-	WRITE_PAUSE
-
-	ld	[%o5], %g0
-	WRITE_PAUSE
-
-	/* IRQ's off else we deadlock. */
-	or	%l0, PSR_PIL, %l4
-	wr	%l4, 0x0, %psr
-	WRITE_PAUSE
-
-	wr	%l4, PSR_ET, %psr
-	WRITE_PAUSE
-
-	call	C_LABEL(smp_message_irq)
-	 nop
-
-	RESTORE_ALL_FASTIRQ
-
 	.align	4
 	.globl	linux_trap_ipi13_sun4m
 linux_trap_ipi13_sun4m:
-	/* NOTE: real_irq_entry saved state and grabbed klock already. */
-
-	/* 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))]
-
 	sethi	%hi(0x20000000), %o2
 	GET_PROCESSOR_MID(o0, o1)
 	set	C_LABEL(sun4m_interrupts), %l5
@@ -781,12 +698,6 @@
 	call	C_LABEL(smp_reschedule_irq)
 	 nop
 
-	sethi	%hi(C_LABEL(intr_count)), %l4
-	ld	[%l4 + %lo(C_LABEL(intr_count))], %l5
-	sub	%l5, 0x1, %l5
-	st	%l5, [%l4 + %lo(C_LABEL(intr_count))]
-
-	LEAVE_IRQ
 	RESTORE_ALL
 
 	.align	4
@@ -829,7 +740,7 @@
 	ld	[%l5], %g0
 	WRITE_PAUSE
 
-	RESTORE_ALL_FASTIRQ
+	RESTORE_ALL
 
 1:
 	sethi	%hi(0x80000000), %o2
@@ -855,7 +766,8 @@
 	call	C_LABEL(smp_message_irq)
 	 nop
 
-	RESTORE_ALL_FASTIRQ
+	b	ret_trap_lockless_ipi
+	 clr	%l6
 
 #endif
 
@@ -1104,7 +1016,6 @@
 
 sun4c_fault_fromuser:
 	SAVE_ALL
-	ENTER_SYSCALL
 	
 	mov	%l7, %o1		! Decode the info from %l7
 	mov	%l7, %o2
@@ -1139,7 +1050,6 @@
 	or	%l6, %l7, %l7			! l7 = [addr,write,txtfault]
 
 	SAVE_ALL
-	ENTER_SYSCALL
 
 	mov	%l7, %o1
 	mov	%l7, %o2
@@ -1355,6 +1265,20 @@
 	b	C_LABEL(ret_sys_call)
 	 ld	[%sp + REGWIN_SZ + PT_I0], %o0
 
+#ifdef __SMP__
+	.globl	C_LABEL(ret_from_smpfork)
+C_LABEL(ret_from_smpfork):
+	mov	NO_PROC_ID, %o5
+	sethi	%hi(C_LABEL(klock_info)), %o4
+	or	%o4, %lo(C_LABEL(klock_info)), %o4
+	stb	%o5, [%o4 + 1]
+	stb	%g0, [%o4 + 0]
+	wr	%l0, PSR_ET, %psr
+	WRITE_PAUSE
+	b	C_LABEL(ret_sys_call)
+	 ld	[%sp + REGWIN_SZ + PT_I0], %o0
+#endif
+
 	/* Linux native and SunOS system calls enter here... */
 	.align	4
 	.globl	linux_sparc_syscall
@@ -1372,7 +1296,6 @@
 syscall_is_too_hard:
 	SAVE_ALL_HEAD
 	 rd	%wim, %l3
-	ENTER_SYSCALL
 
 	wr	%l0, PSR_ET, %psr
 	mov	%i0, %o0
@@ -1462,7 +1385,6 @@
 1:	
 	SAVE_ALL_HEAD
 	 rd	%wim, %l3
-	ENTER_SYSCALL
 
 	wr	%l0, PSR_ET, %psr
 	nop
@@ -1535,7 +1457,6 @@
 bsd_is_too_hard:
 	rd	%wim, %l3
 	SAVE_ALL
-	ENTER_SYSCALL
 
 	wr	%l0, PSR_ET, %psr
 	WRITE_PAUSE
@@ -1703,7 +1624,6 @@
 breakpoint_trap:
 	rd	%wim,%l3
 	SAVE_ALL
-	ENTER_SYSCALL
 	wr 	%l0, PSR_ET, %psr
 	WRITE_PAUSE
 
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/kernel/finitobj.S linux/arch/sparc/kernel/finitobj.S
--- v2.1.22/linux/arch/sparc/kernel/finitobj.S	Wed Dec 18 15:58:43 1996
+++ linux/arch/sparc/kernel/finitobj.S	Thu Jan  1 02:00:00 1970
@@ -1,9 +0,0 @@
-#if defined (__svr4__) || defined (__ELF__)
-
-	.section	".text.init",#alloc,#execinstr
-	.globl	text_init_end
-text_init_end:
-	.section	".data.init",#alloc,#write
-	.globl	data_init_end
-data_init_end:
-#endif
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/kernel/head.S linux/arch/sparc/kernel/head.S
--- v2.1.22/linux/arch/sparc/kernel/head.S	Tue Dec 31 21:40:59 1996
+++ linux/arch/sparc/kernel/head.S	Sun Jan 26 12:07:06 1997
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.76 1996/12/30 00:31:09 davem Exp $
+/* $Id: head.S,v 1.78 1997/01/06 06:52:20 davem Exp $
  * head.S: The initial boot code for the Sparc port of Linux.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -19,6 +19,7 @@
 #include <asm/page.h>
 #include <asm/kdebug.h>
 #include <asm/winmacro.h>
+#include <asm/errno.h>
 
 	.data
 /* 
@@ -973,8 +974,8 @@
 		mov	0, %fp			/* And for good luck */
 
 		/* Zero out our BSS section. */
-		set	C_LABEL(edata) , %o0	! First address of BSS
-		set	C_LABEL(end) , %o1	! Last address of BSS
+		set	C_LABEL(__bss_start) , %o0	! First address of BSS
+		set	C_LABEL(end) , %o1		! Last address of BSS
 		add	%o0, 0x1, %o0
 1:	
 		stb	%g0, [%o0]
@@ -1052,17 +1053,6 @@
 		PATCH_INSN(rtrap_7win_patch4, rtrap_patch4)
 		PATCH_INSN(rtrap_7win_patch5, rtrap_patch5)
 
-#ifdef __SMP__
-
-		/* Patch for returning from an ipi... */
-		PATCH_INSN(rirq_7win_patch1, rirq_patch1)
-		PATCH_INSN(rirq_7win_patch2, rirq_patch2)
-		PATCH_INSN(rirq_7win_patch3, rirq_patch3)
-		PATCH_INSN(rirq_7win_patch4, rirq_patch4)
-		PATCH_INSN(rirq_7win_patch5, rirq_patch5)
-
-#endif
-
 		/* Patch for killing user windows from the register file. */
 		PATCH_INSN(kuw_patch1_7win, kuw_patch1)
 
@@ -1201,3 +1191,8 @@
 	.word	0
 	.word	t_irq14
 
+        .section        ".fixup",#alloc,#execinstr
+        .globl  __ret_efault
+__ret_efault:
+        ret
+         restore %g0, -EFAULT, %o0
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/kernel/initobj.S linux/arch/sparc/kernel/initobj.S
--- v2.1.22/linux/arch/sparc/kernel/initobj.S	Wed Dec 18 15:58:43 1996
+++ linux/arch/sparc/kernel/initobj.S	Thu Jan  1 02:00:00 1970
@@ -1,18 +0,0 @@
-#include <asm/errno.h>
-
-#if defined (__svr4__) || defined (__ELF__)
-
-	.section	".text.init",#alloc,#execinstr
-	.globl	text_init_begin
-text_init_begin:
-	.section	".data.init",#alloc,#write
-	.globl	data_init_begin
-data_init_begin:
-#endif
-
-	.section	".fixup",#alloc,#execinstr
-	.globl	__ret_efault
-__ret_efault:
-	ret
-	 restore %g0, -EFAULT, %o0
-
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/kernel/irq.c linux/arch/sparc/kernel/irq.c
--- v2.1.22/linux/arch/sparc/kernel/irq.c	Sun Dec 22 16:37:23 1996
+++ linux/arch/sparc/kernel/irq.c	Sun Jan 26 12:07:06 1997
@@ -1,4 +1,4 @@
-/*  $Id: irq.c,v 1.58 1996/12/18 06:33:41 tridge Exp $
+/*  $Id: irq.c,v 1.59 1997/01/06 06:52:21 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
@@ -21,6 +21,8 @@
 #include <linux/malloc.h>
 #include <linux/random.h>
 #include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/ptrace.h>
 #include <asm/processor.h>
@@ -204,6 +206,8 @@
 	struct irqaction * action;
 	unsigned int cpu_irq;
 	
+	lock_kernel();
+	intr_count++;
 	cpu_irq = irq & NR_IRQS;
 	action = *(cpu_irq + irq_action);
 	kstat.interrupts[cpu_irq]++;
@@ -213,7 +217,22 @@
 		action->handler(irq, action->dev_id, regs);
 		action = action->next;
 	} while (action);
+	intr_count--;
+	unlock_kernel();
 }
+
+#ifdef CONFIG_BLK_DEV_FD
+extern void floppy_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+
+void sparc_floppy_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+	lock_kernel();
+	intr_count++;
+	floppy_interrupt(irq, dev_id, regs);
+	intr_count--;
+	unlock_kernel();
+}
+#endif
 
 /* Fast IRQ's on the Sparc can only have one routine attached to them,
  * thus no sharing possible.
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/kernel/process.c linux/arch/sparc/kernel/process.c
--- v2.1.22/linux/arch/sparc/kernel/process.c	Tue Dec 31 21:40:59 1996
+++ linux/arch/sparc/kernel/process.c	Sun Jan 26 12:07:06 1997
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.87 1996/12/30 06:16:21 davem Exp $
+/*  $Id: process.c,v 1.89 1997/01/06 06:52:23 davem Exp $
  *  linux/arch/sparc/kernel/process.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -23,6 +23,8 @@
 #include <linux/user.h>
 #include <linux/a.out.h>
 #include <linux/config.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/auxio.h>
 #include <asm/oplib.h>
@@ -47,8 +49,11 @@
  */
 asmlinkage int sys_idle(void)
 {
+	int ret = -EPERM;
+
+	lock_kernel();
 	if (current->pid != 0)
-		return -EPERM;
+		goto out;
 
 	/* endless idle loop with no priority at all */
 	current->counter = -100;
@@ -85,7 +90,10 @@
 		}
 		schedule();
 	}
-	return 0;
+	ret = 0;
+out:
+	unlock_kernel();
+	return ret;
 }
 
 #else
@@ -95,13 +103,19 @@
  */
 asmlinkage int sys_idle(void)
 {
+	int ret = -EPERM;
+
+	lock_kernel();
 	if (current->pid != 0)
-		return -EPERM;
+		goto out;
 
 	/* endless idle loop with no priority at all */
 	current->counter = -100;
 	schedule();
-	return 0;
+	ret = 0;
+out:
+	unlock_kernel();
+	return ret;
 }
 
 /* This is being executed in task 0 'user space'. */
@@ -280,7 +294,6 @@
  */
 void exit_thread(void)
 {
-	kill_user_windows();
 #ifndef __SMP__
 	if(last_task_used_math == current) {
 #else
@@ -300,9 +313,7 @@
 
 void flush_thread(void)
 {
-	/* Make sure old user windows don't get in the way. */
-	kill_user_windows();
-
+	current->tss.w_saved = 0;
 	current->tss.sstk_info.cur_status = 0;
 	current->tss.sstk_info.the_stack = 0;
 
@@ -406,7 +417,11 @@
  *       allocate the task_struct and kernel stack in
  *       do_fork().
  */
+#ifdef __SMP__
+extern void ret_from_smpfork(void);
+#else
 extern void ret_from_syscall(void);
+#endif
 
 int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
 		struct task_struct *p, struct pt_regs *regs)
@@ -439,8 +454,13 @@
 	copy_regwin(new_stack, (((struct reg_window *) regs) - 1));
 
 	p->tss.ksp = p->saved_kernel_stack = (unsigned long) new_stack;
+#ifdef __SMP__
+	p->tss.kpc = (((unsigned long) ret_from_smpfork) - 0x8);
+	p->tss.kpsr = current->tss.fork_kpsr | PSR_PIL;
+#else
 	p->tss.kpc = (((unsigned long) ret_from_syscall) - 0x8);
 	p->tss.kpsr = current->tss.fork_kpsr;
+#endif
 	p->tss.kwim = current->tss.fork_kwim;
 	p->tss.kregs = childregs;
 
@@ -548,11 +568,14 @@
 	if(regs->u_regs[UREG_G1] == 0)
 		base = 1;
 
+	lock_kernel();
 	error = getname((char *) regs->u_regs[base + UREG_I0], &filename);
 	if(error)
-		return error;
+		goto out;
 	error = do_execve(filename, (char **) regs->u_regs[base + UREG_I1],
 			  (char **) regs->u_regs[base + UREG_I2], regs);
 	putname(filename);
+out:
+	unlock_kernel();
 	return error;
 }
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/kernel/ptrace.c linux/arch/sparc/kernel/ptrace.c
--- v2.1.22/linux/arch/sparc/kernel/ptrace.c	Sun Dec 22 16:37:23 1996
+++ linux/arch/sparc/kernel/ptrace.c	Sun Jan 26 12:07:06 1997
@@ -15,6 +15,8 @@
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/pgtable.h>
 #include <asm/system.h>
@@ -256,8 +258,7 @@
  * is a valid errno will mean setting the condition codes to indicate
  * an error return.  This doesn't work, so we have this hook.
  */
-static inline void
-pt_error_return(struct pt_regs *regs, unsigned long error)
+static inline void pt_error_return(struct pt_regs *regs, unsigned long error)
 {
 	regs->u_regs[UREG_I0] = error;
 	regs->psr |= PSR_C;
@@ -265,8 +266,7 @@
 	regs->npc += 4;
 }
 
-static inline void
-pt_succ_return(struct pt_regs *regs, unsigned long value)
+static inline void pt_succ_return(struct pt_regs *regs, unsigned long value)
 {
 	regs->u_regs[UREG_I0] = value;
 	regs->psr &= ~PSR_C;
@@ -497,6 +497,7 @@
 	unsigned long addr2 = regs->u_regs[UREG_I4];
 	struct task_struct *child;
 
+	lock_kernel();
 #ifdef DEBUG_PTRACE
 	{
 		char *s;
@@ -518,32 +519,33 @@
 		/* are we already being traced? */
 		if (current->flags & PF_PTRACED) {
 			pt_error_return(regs, EPERM);
-			return;
+			goto out;
 		}
 		/* set the ptrace bit in the process flags. */
 		current->flags |= PF_PTRACED;
 		pt_succ_return(regs, 0);
-		return;
+		goto out;
 	}
 #ifndef ALLOW_INIT_TRACING
 	if(pid == 1) {
 		/* Can't dork with init. */
 		pt_error_return(regs, EPERM);
-		return;
+		goto out;
 	}
 #endif
 	if(!(child = get_task(pid))) {
 		pt_error_return(regs, ESRCH);
-		return;
+		goto out;
 	}
 
-	if(request == PTRACE_SUNATTACH || request == PTRACE_ATTACH) {
+	if (((current->personality & PER_BSD) && (request == PTRACE_SUNATTACH))
+	    || (!(current->personality & PER_BSD) && (request == PTRACE_ATTACH))) {
 		if(child == current) {
 			/* Try this under SunOS/Solaris, bwa haha
 			 * You'll never be able to kill the process. ;-)
 			 */
 			pt_error_return(regs, EPERM);
-			return;
+			goto out;
 		}
 		if((!child->dumpable ||
 		    (current->uid != child->euid) ||
@@ -551,12 +553,12 @@
 		    (current->gid != child->egid) ||
 		    (current->gid != child->gid)) && !suser()) {
 			pt_error_return(regs, EPERM);
-			return;
+			goto out;
 		}
 		/* the same process cannot be attached many times */
 		if (child->flags & PF_PTRACED) {
 			pt_error_return(regs, EPERM);
-			return;
+			goto out;
 		}
 		child->flags |= PF_PTRACED;
 		if(child->p_pptr != current) {
@@ -566,22 +568,23 @@
 		}
 		send_sig(SIGSTOP, child, 1);
 		pt_succ_return(regs, 0);
-		return;
+		goto out;
 	}
-	if(!(child->flags & PF_PTRACED) && (request!=PTRACE_SUNATTACH) &&
-	   (request!=PTRACE_ATTACH)) {
+	if (!(child->flags & PF_PTRACED)
+	    && ((current->personality & PER_BSD) && (request != PTRACE_SUNATTACH))
+	    && (!(current->personality & PER_BSD) && (request != PTRACE_ATTACH))) {
 		pt_error_return(regs, ESRCH);
-		return;
+		goto out;
 	}
 	if(child->state != TASK_STOPPED) {
 		if(request != PTRACE_KILL) {
 			pt_error_return(regs, ESRCH);
-			return;
+			goto out;
 		}
 	}
 	if(child->p_pptr != current) {
 		pt_error_return(regs, ESRCH);
-		return;
+		goto out;
 	}
 	switch(request) {
 	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
@@ -592,24 +595,24 @@
 		/* Non-word alignment _not_ allowed on Sparc. */
 		if(addr & (sizeof(unsigned long) - 1)) {
 			pt_error_return(regs, EINVAL);
-			return;
+			goto out;
 		}
 		res = read_long(child, addr, &tmp);
 		if (res < 0) {
 			pt_error_return(regs, -res);
-			return;
+			goto out;
 		}
 		pt_os_succ_return(regs, tmp, (long *) data);
-		return;
+		goto out;
 	}
 
 	case PTRACE_PEEKUSR:
 		read_sunos_user(regs, addr, child, (long *) data);
-		return;
+		goto out;
 
 	case PTRACE_POKEUSR:
 		write_sunos_user(regs, addr, child);
-		return;
+		goto out;
 
 	case PTRACE_POKETEXT: /* write the word at location addr. */
 	case PTRACE_POKEDATA: {
@@ -619,7 +622,7 @@
 		/* Non-word alignment _not_ allowed on Sparc. */
 		if(addr & (sizeof(unsigned long) - 1)) {
 			pt_error_return(regs, EINVAL);
-			return;
+			goto out;
 		}
 		vma = find_extend_vma(child, addr);
 		res = write_long(child, addr, data);
@@ -627,7 +630,7 @@
 			pt_error_return(regs, -res);
 		else
 			pt_succ_return(regs, res);
-		return;
+		goto out;
 	}
 
 	case PTRACE_GETREGS: {
@@ -636,8 +639,10 @@
 		int rval;
 
 		rval = verify_area(VERIFY_WRITE, pregs, sizeof(struct pt_regs));
-		if(rval)
-			return pt_error_return(regs, -rval);
+		if(rval) {
+			pt_error_return(regs, -rval);
+			goto out;
+		}
 		__put_user(cregs->psr, (&pregs->psr));
 		__put_user(cregs->pc, (&pregs->pc));
 		__put_user(cregs->npc, (&pregs->npc));
@@ -648,7 +653,7 @@
 #ifdef DEBUG_PTRACE
 		printk ("PC=%x nPC=%x o7=%x\n", cregs->pc, cregs->npc, cregs->u_regs [15]);
 #endif
-		return;
+		goto out;
 	}
 
 	case PTRACE_SETREGS: {
@@ -661,8 +666,10 @@
 		 * bits in the psr.
 		 */
 		i = verify_area(VERIFY_READ, pregs, sizeof(struct pt_regs));
-		if(i)
-			return pt_error_return(regs, -i);
+		if(i) {
+			pt_error_return(regs, -i);
+			goto out;
+		}
 		__get_user(psr, (&pregs->psr));
 		__get_user(pc, (&pregs->pc));
 		__get_user(npc, (&pregs->npc));
@@ -678,7 +685,7 @@
 		for(i = 1; i < 16; i++)
 			__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]));
 		pt_succ_return(regs, 0);
-		return;
+		goto out;
 	}
 
 	case PTRACE_GETFPREGS: {
@@ -696,8 +703,10 @@
 		int i;
 
 		i = verify_area(VERIFY_WRITE, fps, sizeof(struct fps));
-		if(i)
-			return pt_error_return(regs, -i);
+		if(i) {
+			pt_error_return(regs, -i);
+			goto out;
+		}
 		for(i = 0; i < 32; i++)
 			__put_user(child->tss.float_regs[i], (&fps->regs[i]));
 		__put_user(child->tss.fsr, (&fps->fsr));
@@ -710,7 +719,7 @@
 			__put_user(child->tss.fpqueue[i].insn, (&fps->fpq[i].insn));
 		}
 		pt_succ_return(regs, 0);
-		return;
+		goto out;
 	}
 
 	case PTRACE_SETFPREGS: {
@@ -728,8 +737,10 @@
 		int i;
 
 		i = verify_area(VERIFY_READ, fps, sizeof(struct fps));
-		if(i)
-			return pt_error_return(regs, -i);
+		if(i) {
+			pt_error_return(regs, -i);
+			goto out;
+		}
 		copy_from_user(&child->tss.float_regs[0], &fps->regs[0], (32 * 4));
 		__get_user(child->tss.fsr, (&fps->fsr));
 		__get_user(child->tss.fpqdepth, (&fps->fpqd));
@@ -739,7 +750,7 @@
 			__get_user(child->tss.fpqueue[i].insn, (&fps->fpq[i].insn));
 		}
 		pt_succ_return(regs, 0);
-		return;
+		goto out;
 	}
 
 	case PTRACE_READTEXT:
@@ -750,17 +761,21 @@
 		int res, len = data;
 
 		res = verify_area(VERIFY_WRITE, dest, len);
-		if(res)
-			return pt_error_return(regs, -res);
+		if(res) {
+			pt_error_return(regs, -res);
+			goto out;
+		}
 		while(len) {
 			res = read_byte(child, src, &tmp);
-			if(res < 0)
-				return pt_error_return(regs, -res);
+			if(res < 0) {
+				pt_error_return(regs, -res);
+				goto out;
+			}
 			__put_user(tmp, dest);
 			src++; dest++; len--;
 		}
 		pt_succ_return(regs, 0);
-		return;
+		goto out;
 	}
 
 	case PTRACE_WRITETEXT:
@@ -770,19 +785,23 @@
 		int res, len = data;
 
 		res = verify_area(VERIFY_READ, src, len);
-		if(res)
-			return pt_error_return(regs, -res);
+		if(res) {
+			pt_error_return(regs, -res);
+			goto out;
+		}
 		while(len) {
 			unsigned long tmp;
 
 			__get_user(tmp, src);
 			res = write_byte(child, dest, tmp);
-			if(res < 0)
-				return pt_error_return(regs, -res);
+			if(res < 0) {
+				pt_error_return(regs, -res);
+				goto out;
+			}
 			src++; dest++; len--;
 		}
 		pt_succ_return(regs, 0);
-		return;
+		goto out;
 	}
 
 	case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */
@@ -791,12 +810,12 @@
 	case PTRACE_CONT: { /* restart after signal. */
 		if ((unsigned long) data > NSIG) {
 			pt_error_return(regs, EIO);
-			return;
+			goto out;
 		}
 		if (addr != 1) {
 			if (addr & 3) {
 				pt_error_return(regs, EINVAL);
-				return;
+				goto out;
 			}
 #ifdef DEBUG_PTRACE
 			printk ("Original: %08lx %08lx\n", child->tss.kregs->pc, child->tss.kregs->npc);
@@ -821,7 +840,7 @@
 #endif
 		wake_up_process(child);
 		pt_succ_return(regs, 0);
-		return;
+		goto out;
 	}
 
 /*
@@ -832,18 +851,18 @@
 	case PTRACE_KILL: {
 		if (child->state == TASK_ZOMBIE) {	/* already dead */
 			pt_succ_return(regs, 0);
-			return;
+			goto out;
 		}
 		wake_up_process(child);
 		child->exit_code = SIGKILL;
 		pt_succ_return(regs, 0);
-		return;
+		goto out;
 	}
 
 	case PTRACE_SUNDETACH: { /* detach a process that was attached. */
 		if ((unsigned long) data > NSIG) {
 			pt_error_return(regs, EIO);
-			return;
+			goto out;
 		}
 		child->flags &= ~(PF_PTRACED|PF_TRACESYS);
 		wake_up_process(child);
@@ -852,25 +871,28 @@
 		child->p_pptr = child->p_opptr;
 		SET_LINKS(child);
 		pt_succ_return(regs, 0);
-		return;
+		goto out;
 	}
 
 	/* PTRACE_DUMPCORE unsupported... */
 
 	default:
 		pt_error_return(regs, EIO);
-		return;
+		goto out;
 	}
+out:
+	unlock_kernel();
 }
 
 asmlinkage void syscall_trace(void)
 {
+	lock_kernel();
 #ifdef DEBUG_PTRACE
 	printk("%s [%d]: syscall_trace\n", current->comm, current->pid);
 #endif
 	if ((current->flags & (PF_PTRACED|PF_TRACESYS))
 			!= (PF_PTRACED|PF_TRACESYS))
-		return;
+		goto out;
 	current->exit_code = SIGTRAP;
 	current->state = TASK_STOPPED;
 	current->tss.flags ^= MAGIC_CONSTANT;
@@ -889,4 +911,6 @@
 		current->signal |= (1 << (current->exit_code - 1));
 	}
 	current->exit_code = 0;
+out:
+	unlock_kernel();
 }
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/kernel/rirq.S linux/arch/sparc/kernel/rirq.S
--- v2.1.22/linux/arch/sparc/kernel/rirq.S	Tue Nov 12 15:56:03 1996
+++ linux/arch/sparc/kernel/rirq.S	Thu Jan  1 02:00:00 1970
@@ -1,289 +0,0 @@
-/* rirq.S: Needed to return from an interrupt on SMP with no
- *         locks held or released.
- *
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#include <asm/cprefix.h>
-#include <asm/page.h>
-#include <asm/ptrace.h>
-#include <asm/psr.h>
-#include <asm/asi.h>
-#include <asm/smp.h>
-#include <asm/contregs.h>
-#include <asm/winmacro.h>
-#include <asm/asmmacro.h>
-
-#define t_psr     l0
-#define t_pc      l1
-#define t_npc     l2
-#define t_wim     l3
-#define twin_tmp1 l4
-#define twin_tmp2 l5
-#define twin_tmp3 l6
-#define curptr    g6
-
-	/* 7 WINDOW SPARC PATCH INSTRUCTIONS */
-	.globl	rirq_7win_patch1, rirq_7win_patch2, rirq_7win_patch3
-	.globl	rirq_7win_patch4, rirq_7win_patch5
-rirq_7win_patch1:	srl	%t_wim, 0x6, %twin_tmp2
-rirq_7win_patch2:	and	%twin_tmp2, 0x7f, %twin_tmp2
-rirq_7win_patch3:	srl	%g1, 7, %g2
-rirq_7win_patch4:	srl	%g2, 6, %g2
-rirq_7win_patch5:	and	%g1, 0x7f, %g1
-	/* END OF PATCH INSTRUCTIONS */
-
-	.globl	ret_irq_entry, rirq_patch1, rirq_patch2
-	.globl	rirq_patch3, rirq_patch4, rirq_patch5
-ret_irq_entry:
-	ld	[%sp + REGWIN_SZ + PT_PSR], %t_psr
-	andcc	%t_psr, PSR_PS, %g0
-	bne	ret_irq_kernel
-	 nop
-
-ret_irq_user:
-	wr	%t_psr, 0x0, %psr
-	WRITE_PAUSE
-
-	ld	[%curptr + THREAD_W_SAVED], %twin_tmp1
-	orcc	%g0, %twin_tmp1, %g0
-	be	ret_irq_nobufwins
-	 nop
-
-	/* User has toasty windows, must grab klock. */
-	ENTER_SYSCALL
-
-	wr	%t_psr, PSR_ET, %psr
-	WRITE_PAUSE
-
-	mov	1, %o1
-	call	C_LABEL(try_to_clear_window_buffer)
-	 add	%sp, REGWIN_SZ, %o0
-
-	/* We have klock, so we must return just like a normal trap. */
-	b	ret_trap_entry
-	 clr	%l5
-
-ret_irq_nobufwins:
-	/* Load up the user's out registers so we can pull
-	 * a window from the stack, if necessary.
-	 */
-	LOAD_PT_INS(sp)
-
-	/* If there are already live user windows in the
-	 * set we can return from trap safely.
-	 */
-	ld	[%curptr + THREAD_UMASK], %twin_tmp1
-	orcc	%g0, %twin_tmp1, %g0
-	bne	ret_irq_userwins_ok
-	 nop
-	
-		/* Calculate new %wim, we have to pull a register
-		 * window from the users stack.
-		 */
-ret_irq_pull_one_window:
-		rd	%wim, %t_wim
-		sll	%t_wim, 0x1, %twin_tmp1
-rirq_patch1:	srl	%t_wim, 0x7, %twin_tmp2
-		or	%twin_tmp2, %twin_tmp1, %twin_tmp2
-rirq_patch2:	and	%twin_tmp2, 0xff, %twin_tmp2
-
-		wr	%twin_tmp2, 0x0, %wim
-		WRITE_PAUSE
-
-				/* Here comes the architecture specific 
-				 * branch to the user stack checking routine
-				 * for return from traps.
-				 */
-				.globl	C_LABEL(rirq_mmu_patchme)
-C_LABEL(rirq_mmu_patchme):	b	C_LABEL(sun4c_reti_stackchk)
-				 andcc	%fp, 0x7, %g0	
-
-ret_irq_userwins_ok:
-	LOAD_PT_PRIV(sp, t_psr, t_pc, t_npc)
-	or	%t_pc, %t_npc, %g2
-	andcc	%g2, 0x3, %g0
-	bne	ret_irq_unaligned_pc
-	 nop
-
-	LOAD_PT_YREG(sp, g1)
-	LOAD_PT_GLOBALS(sp)
-
-	wr	%t_psr, 0x0, %psr
-	WRITE_PAUSE
-
-	jmp	%t_pc
-	rett	%t_npc
-	
-ret_irq_unaligned_pc:
-	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
-
-	/* User has unaligned crap, must grab klock. */
-	ENTER_SYSCALL
-
-	wr	%t_psr, PSR_ET, %psr
-	WRITE_PAUSE
-
-	call	C_LABEL(do_memaccess_unaligned)
-	 nop
-
-	/* We have klock, so we must return just like a normal trap. */
-	b	ret_trap_entry
-	 clr	%l5
-
-ret_irq_kernel:
-	wr	%t_psr, 0x0, %psr
-	WRITE_PAUSE
-
-		/* Will the rett land us in the invalid window? */
-		mov	2, %g1
-		sll	%g1, %t_psr, %g1
-rirq_patch3:	srl	%g1, 8, %g2
-		or	%g1, %g2, %g1
-		rd	%wim, %g2
-		andcc	%g2, %g1, %g0
-		be	1f		! Nope, just return from the trap
-		 nop
-
-		/* We have to grab a window before returning. */
-		sll	%g2, 0x1, %g1
-rirq_patch4:	srl	%g2, 7,  %g2
-		or	%g1, %g2, %g1
-rirq_patch5:	and	%g1, 0xff, %g1
-
-	wr	%g1, 0x0, %wim
-	WRITE_PAUSE
-
-	restore	%g0, %g0, %g0
-	LOAD_WINDOW(sp)
-	save	%g0, %g0, %g0
-
-	/* Reload the entire frame in case this is from a
-	 * kernel system call or whatever...
-	 */
-1:
-	LOAD_PT_ALL(sp, t_psr, t_pc, t_npc, g1)
-
-	wr	%t_psr, 0x0, %psr
-	WRITE_PAUSE
-
-	jmp	%t_pc
-	rett	%t_npc
-
-ret_irq_user_stack_is_bolixed:
-	wr	%t_wim, 0x0, %wim
-	WRITE_PAUSE
-
-	/* User has a toasty window, must grab klock. */
-	ENTER_SYSCALL
-
-	wr	%t_psr, PSR_ET, %psr
-	WRITE_PAUSE
-
-	call	C_LABEL(window_ret_fault)
-	 add	%sp, REGWIN_SZ, %o0
-
-	/* We have klock, so we must return just like a normal trap. */
-	b	ret_trap_entry
-	 clr	%l5
-
-	.globl	C_LABEL(sun4c_reti_stackchk)
-C_LABEL(sun4c_reti_stackchk):
-	be	1f
-	 and	%fp, 0xfff, %g1		! delay slot
-
-	b,a	ret_irq_user_stack_is_bolixed
-
-	/* See if we have to check the sanity of one page or two */
-1:
-	add	%g1, 0x38, %g1
-	sra	%fp, 29, %g2
-	add	%g2, 0x1, %g2
-	andncc	%g2, 0x1, %g0
-	be	1f
-	 andncc	%g1, 0xff8, %g0
-
-	/* %sp is in vma hole, yuck */
-	b,a	ret_irq_user_stack_is_bolixed
-
-1:
-	be	sun4c_reti_onepage	/* Only one page to check */
-	 lda	[%fp] ASI_PTE, %g2
-
-sun4c_reti_twopages:
-	add	%fp, 0x38, %g1
-	sra	%g1, 29, %g2
-	add	%g2, 0x1, %g2
-	andncc	%g2, 0x1, %g0
-	be	1f
-	 lda	[%g1] ASI_PTE, %g2
-
-	/* Second page is in vma hole */
-	b,a	ret_irq_user_stack_is_bolixed
-
-1:
-	srl	%g2, 29, %g2
-	andcc	%g2, 0x4, %g0
-	bne	sun4c_reti_onepage
-	 lda	[%fp] ASI_PTE, %g2
-
-	/* Second page has bad perms */
-	b,a	ret_irq_user_stack_is_bolixed
-
-sun4c_reti_onepage:
-	srl	%g2, 29, %g2
-	andcc	%g2, 0x4, %g0
-	bne	1f
-	 nop
-
-	/* A page had bad page permissions, losing... */
-	b,a	ret_irq_user_stack_is_bolixed
-
-	/* Whee, things are ok, load the window and continue. */
-1:
-	restore	%g0, %g0, %g0
-
-	LOAD_WINDOW(sp)
-
-	save	%g0, %g0, %g0
-	b,a	ret_irq_userwins_ok
-
-	.globl	C_LABEL(srmmu_reti_stackchk)
-C_LABEL(srmmu_reti_stackchk):
-	sethi	%hi(C_LABEL(page_offset)), %g1
-	bne	ret_irq_user_stack_is_bolixed
-	 ld	[%g1 + %lo(C_LABEL(page_offset))], %g1
-	cmp	%g1, %fp
-	bleu	ret_irq_user_stack_is_bolixed
-	 mov	AC_M_SFSR, %g1
-	lda	[%g1] ASI_M_MMUREGS, %g0
-
-	lda	[%g0] ASI_M_MMUREGS, %g1
-	or	%g1, 0x2, %g1
-	sta	%g1, [%g0] ASI_M_MMUREGS
-
-	restore	%g0, %g0, %g0
-
-	LOAD_WINDOW(sp)
-
-	save	%g0, %g0, %g0
-
-	andn	%g1, 0x2, %g1
-	sta	%g1, [%g0] ASI_M_MMUREGS
-
-	mov	AC_M_SFAR, %g2
-	lda	[%g2] ASI_M_MMUREGS, %g2
-
-	mov	AC_M_SFSR, %g1
-	lda	[%g1] ASI_M_MMUREGS, %g1
-	andcc	%g1, 0x2, %g0
-	bne	ret_irq_user_stack_is_bolixed
-	 nop
-
-	b,a	ret_irq_userwins_ok
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/kernel/rtrap.S linux/arch/sparc/kernel/rtrap.S
--- v2.1.22/linux/arch/sparc/kernel/rtrap.S	Tue Dec 31 21:40:59 1996
+++ linux/arch/sparc/kernel/rtrap.S	Sun Jan 26 12:07:07 1997
@@ -1,4 +1,4 @@
-/* $Id: rtrap.S,v 1.41 1996/12/28 18:14:21 davem Exp $
+/* $Id: rtrap.S,v 1.44 1997/01/14 05:56:17 davem Exp $
  * rtrap.S: Return from Sparc trap low-level code.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -46,25 +46,25 @@
 
 	.globl	ret_trap_entry, rtrap_patch1, rtrap_patch2
 	.globl	rtrap_patch3, rtrap_patch4, rtrap_patch5
+	.globl	C_LABEL(ret_trap_lockless_ipi)
 ret_trap_entry:
-	sethi	%hi(C_LABEL(intr_count)), %g2
-	ld	[%g2 + %lo(C_LABEL(intr_count))], %g3
-	orcc	%g0, %g3, %g0
-	bne	0f
-	 sethi	%hi(C_LABEL(bh_active)), %l3
-	sethi	%hi(C_LABEL(bh_mask)), %l4
+	sethi	%hi(C_LABEL(intr_count)), %g4
+	ld	[%g4 + %lo(C_LABEL(intr_count))], %g5
+	orcc	%g5, 0x0, %g0
+	sethi	%hi(C_LABEL(bh_active)), %l3
+	bne	C_LABEL(ret_trap_lockless_ipi)
+	 sethi	%hi(C_LABEL(bh_mask)), %l4
 9:
 	ld	[%l4 + %lo(C_LABEL(bh_mask))], %g5
 	ld	[%l3 + %lo(C_LABEL(bh_active))], %g4
-	sethi	%hi(C_LABEL(intr_count)), %l7
 	andcc	%g4, %g5, %g0
-	be	0f
-	 mov	1, %g7
+	be	C_LABEL(ret_trap_lockless_ipi)
+	 nop
 	call	C_LABEL(do_bottom_half)
-	 st	%g7, [%l7 + %lo(C_LABEL(intr_count))]
-	b	9b
-	 st	%g0, [%l7 + %lo(C_LABEL(intr_count))]
-0:
+	 nop
+	b,a	9b
+
+C_LABEL(ret_trap_lockless_ipi):
 	andcc	%t_psr, PSR_PS, %g0
 	be	1f
 	 sethi	%hi(C_LABEL(need_resched)), %twin_tmp1
@@ -164,8 +164,6 @@
 	LOAD_PT_YREG(sp, g1)
 	LOAD_PT_GLOBALS(sp)
 
-	LEAVE_SYSCALL
-
 	wr	%t_psr, 0x0, %psr
 	WRITE_PAUSE
 
@@ -219,8 +217,6 @@
 1:
 	LOAD_PT_ALL(sp, t_psr, t_pc, t_npc, g1)
 2:
-	LEAVE_SYSCALL
-
 	wr	%t_psr, 0x0, %psr
 	WRITE_PAUSE
 
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/kernel/setup.c linux/arch/sparc/kernel/setup.c
--- v2.1.22/linux/arch/sparc/kernel/setup.c	Tue Dec 31 21:40:59 1996
+++ linux/arch/sparc/kernel/setup.c	Sun Jan 26 12:07:07 1997
@@ -1,4 +1,4 @@
-/*  $Id: setup.c,v 1.79 1996/12/23 10:57:02 ecd Exp $
+/*  $Id: setup.c,v 1.80 1997/01/25 02:39:54 miguel Exp $
  *  linux/arch/sparc/kernel/setup.c
  *
  *  Copyright (C) 1995  David S. Miller (davem@caip.rutgers.edu)
@@ -12,7 +12,7 @@
 #include <linux/unistd.h>
 #include <linux/ptrace.h>
 #include <linux/malloc.h>
-#include <linux/smp.h>
+#include <asm/smp.h>
 #include <linux/user.h>
 #include <linux/a.out.h>
 #include <linux/tty.h>
@@ -183,11 +183,11 @@
 #ifdef CONFIG_SUN_SERIAL
 			case 'a':
 				rs_kgdb_hook(0);
-				printk("KGDB: Using serial line /dev/ttya.\n");
+				prom_printf("KGDB: Using serial line /dev/ttya.\n");
 				break;
 			case 'b':
 				rs_kgdb_hook(1);
-				printk("KGDB: Using serial line /dev/ttyb.\n");
+				prom_printf("KGDB: Using serial line /dev/ttyb.\n");
 				break;
 #endif
 #ifdef CONFIG_AP1000
@@ -327,6 +327,7 @@
 	}
 	if((boot_flags & BOOTME_KGDB)) {
 		set_debug_traps();
+		prom_printf ("Breakpoint!\n");
 		breakpoint();
 	}
 
@@ -440,8 +441,6 @@
 extern char *sparc_fpu_type[];
 
 extern char *smp_info(void);
-
-extern int linux_num_cpus;
 
 int get_cpuinfo(char *buffer)
 {
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/kernel/signal.c linux/arch/sparc/kernel/signal.c
--- v2.1.22/linux/arch/sparc/kernel/signal.c	Mon Dec 30 15:39:03 1996
+++ linux/arch/sparc/kernel/signal.c	Sun Jan 26 12:07:07 1997
@@ -1,9 +1,10 @@
-/*  $Id: signal.c,v 1.66 1996/12/20 07:54:58 davem Exp $
+/*  $Id: signal.c,v 1.71 1997/01/19 22:32:21 ecd Exp $
  *  linux/arch/sparc/kernel/signal.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  *  Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ *  Copyright (C) 1997 Eddie C. Dost   (ecd@skynet.be)
  */
 
 #include <linux/sched.h>
@@ -14,6 +15,8 @@
 #include <linux/ptrace.h>
 #include <linux/unistd.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 #include <asm/bitops.h>
@@ -67,10 +70,11 @@
  */
 
 struct new_signal_frame {
-	struct      sparc_stackf ss;
-	__siginfo_t info;
-	unsigned    long __pad;
-	unsigned    long insns [2];
+	struct sparc_stackf	ss;
+	__siginfo_t		info;
+	__siginfo_fpu_t		*fpu_save;
+	unsigned long		insns [2] __attribute__ ((aligned (8)));
+	__siginfo_fpu_t		fpu_state;
 };
 
 /* Align macros */
@@ -111,59 +115,86 @@
 
 asmlinkage void do_sigpause(unsigned int set, struct pt_regs *regs)
 {
+	lock_kernel();
 	_sigpause_common(set, regs);
+	unlock_kernel();
 }
 
 asmlinkage void do_sigsuspend (struct pt_regs *regs)
 {
+	lock_kernel();
 	_sigpause_common(regs->u_regs[UREG_I0], regs);
+	unlock_kernel();
+}
+
+
+static inline void
+restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
+{
+#ifdef __SMP__
+	if (current->flags & PF_USEDFPU)
+		regs->psr &= ~PSR_EF;
+#else
+	if (current == last_task_used_math) {
+		last_task_used_math = 0;
+		regs->psr &= ~PSR_EF;
+	}
+#endif
+	current->used_math = 1;
+	current->flags &= ~PF_USEDFPU;
+
+	copy_from_user(&current->tss.float_regs[0], &fpu->si_float_regs[0],
+		       (sizeof(unsigned long) * 64));
+	__get_user(current->tss.fsr, &fpu->si_fsr);
+	__get_user(current->tss.fpqdepth, &fpu->si_fpqdepth);
+	if (current->tss.fpqdepth != 0)
+		copy_from_user(&current->tss.fpqueue[0],
+			       &fpu->si_fpqueue[0],
+			       ((sizeof(unsigned long) +
+			       (sizeof(unsigned long *)))*16));
 }
 
 void do_new_sigreturn (struct pt_regs *regs)
 {
 	struct new_signal_frame *sf;
-	unsigned long up_psr;
+	unsigned long up_psr, pc, npc, mask;
 	
+	lock_kernel();
 	sf = (struct new_signal_frame *) regs->u_regs [UREG_FP];
+
 	/* 1. Make sure we are not getting garbage from the user */
 	if (verify_area (VERIFY_READ, sf, sizeof (*sf))){
 		do_exit (SIGSEGV);
-		return;
+		goto out;
 	}
 	if (((uint) sf) & 3){
 		do_exit (SIGSEGV);
-		return;
+		goto out;
 	}
-	if ((sf->info.si_regs.pc | sf->info.si_regs.npc) & 3){
+
+	__get_user(pc,  &sf->info.si_regs.pc);
+	__get_user(npc, &sf->info.si_regs.npc);
+
+	if ((pc | npc) & 3) {
 		do_exit (SIGSEGV);
-		return;
+		goto out;
 	}
 	
 	/* 2. Restore the state */
 	up_psr = regs->psr;
-	memcpy (regs, &sf->info.si_regs, sizeof (struct pt_regs));
+	copy_from_user(regs, &sf->info.si_regs, sizeof (struct pt_regs));
 
-	/* User can only change condition codes and FPU enabling in the %psr. */
-	regs->psr = (up_psr & ~(PSR_ICC | PSR_EF)) | (regs->psr & (PSR_ICC | PSR_EF));
-	
-	if (regs->psr & PSR_EF) {
-		regs->psr &= ~(PSR_EF);
-#ifndef __SMP__
-		if(current == last_task_used_math)
-			last_task_used_math = 0;
-#endif
-		current->used_math = 1;
-		current->flags &= ~(PF_USEDFPU);
-
-		/* Copy signal FPU state into thread struct FPU state. */
-		memcpy(&current->tss.float_regs[0], &sf->info.si_float_regs[0],
-		       (sizeof(unsigned long) * 64));
-		current->tss.fsr = sf->info.si_fsr;
-		if((current->tss.fpqdepth = sf->info.si_fpqdepth) != 0)
-		    memcpy(&current->tss.fpqueue[0], &sf->info.si_fpqueue[0],
-		           ((sizeof(unsigned long) + (sizeof(unsigned long *))) * 16));
-	}
-	current->blocked = sf->info.si_mask & _BLOCKABLE;
+	/* User can only change condition codes and FPU enabling in %psr. */
+	regs->psr = (up_psr & ~(PSR_ICC | PSR_EF))
+		  | (regs->psr & (PSR_ICC | PSR_EF));
+	
+	if (sf->fpu_save)
+		restore_fpu_state(regs, sf->fpu_save);
+
+	__get_user(mask, &sf->info.si_mask);
+	current->blocked = (mask & _BLOCKABLE);
+out:
+	unlock_kernel();
 }
 
 asmlinkage void do_sigreturn(struct pt_regs *regs)
@@ -171,10 +202,11 @@
 	struct sigcontext *scptr;
 	unsigned long pc, npc, psr;
 
+	lock_kernel();
 	synchronize_user_stack();
 	if (current->tss.new_signal){
 		do_new_sigreturn (regs);
-		return;
+		goto out;
 	}
 	scptr = (struct sigcontext *) regs->u_regs[UREG_I0];
 	/* Check sanity of the user arg. */
@@ -204,6 +236,8 @@
 	__get_user(psr, &scptr->sigc_psr);
 	regs->psr &= ~(PSR_ICC);
 	regs->psr |= (psr & PSR_ICC);
+out:
+	unlock_kernel();
 }
 
 /* Checks if the fp is valid */
@@ -287,77 +321,83 @@
 	regs->npc = (regs->pc + 4);
 }
 
-/* To align the structure properly. */
+
+static inline void
+save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
+{
+#ifdef __SMP__
+	if (current->flags & PF_USEDFPU) {
+		put_psr(get_psr() | PSR_EF);
+		fpsave(&current->tss.float_regs[0], &current->tss.fsr,
+		       &current->tss.fpqueue[0], &current->tss.fpqdepth);
+		regs->psr &= ~(PSR_EF);
+		current->flags &= ~(PF_USEDFPU);
+	}
+#else
+	if (current == last_task_used_math) {
+		put_psr(get_psr() | PSR_EF);
+		fpsave(&current->tss.float_regs[0], &current->tss.fsr,
+		       &current->tss.fpqueue[0], &current->tss.fpqdepth);
+		last_task_used_math = 0;
+		regs->psr &= ~(PSR_EF);
+	}
+#endif
+	copy_to_user(&fpu->si_float_regs[0], &current->tss.float_regs[0],
+		     (sizeof(unsigned long) * 64));
+	__put_user(current->tss.fsr, &fpu->si_fsr);
+	__put_user(current->tss.fpqdepth, &fpu->si_fpqdepth);
+	if (current->tss.fpqdepth != 0)
+		copy_to_user(&fpu->si_fpqueue[0], &current->tss.fpqueue[0],
+			     ((sizeof(unsigned long) +
+			     (sizeof(unsigned long *)))*16));
+	current->used_math = 0;
+}
+
 
 static inline void
 new_setup_frame(struct sigaction *sa, struct pt_regs *regs, int signo, unsigned long oldmask)
 {
 	struct new_signal_frame *sf;
+	int sigframe_size;
 
 	/* 1. Make sure everything is clean */
 	synchronize_user_stack();
-	sf = (struct new_signal_frame *) regs->u_regs[UREG_FP];
-	sf = (struct new_signal_frame *) (((unsigned long) sf)-NF_ALIGNEDSZ);
-	
-	if (invalid_frame_pointer (sf, sizeof(struct new_signal_frame))){
+
+	sigframe_size = NF_ALIGNEDSZ;
+	if (!current->used_math)
+		sigframe_size -= sizeof(__siginfo_fpu_t);
+
+	sf = (struct new_signal_frame *)(regs->u_regs[UREG_FP] - sigframe_size);
+
+	if (invalid_frame_pointer (sf, sigframe_size)){
 		do_exit(SIGILL);
 		return;
 	}
 
 	if (current->tss.w_saved != 0){
-		printk ("%s[%d]: Invalid user stack frame for signal delivery.\n",
-			current->comm, current->pid);
+		printk ("%s [%d]: Invalid user stack frame for "
+			"signal delivery.\n", current->comm, current->pid);
 		do_exit (SIGILL);
 		return;
 	}
 
 	/* 2. Save the current process state */
-	memcpy (&sf->info.si_regs, regs, sizeof (struct pt_regs));
-#ifdef __SMP__
-	if(current->flags & PF_USEDFPU) {
-		put_psr(get_psr() | PSR_EF);
-		fpsave (&sf->info.si_float_regs [0], &sf->info.si_fsr,
-			&sf->info.si_fpqueue[0], &sf->info.si_fpqdepth);
-
-		/* Save a copy into thread struct as well. */
-		memcpy(&current->tss.float_regs[0], &sf->info.si_float_regs[0],
-		       (sizeof(unsigned long) * 64));
-		current->tss.fsr = sf->info.si_fsr;
-		if((current->tss.fpqdepth = sf->info.si_fpqdepth) != 0)
-		    memcpy(&current->tss.fpqueue[0], &sf->info.si_fpqueue[0],
-			   ((sizeof(unsigned long) + (sizeof(unsigned long *))) * 16));
-
-		regs->psr &= ~(PSR_EF);
-		current->flags &= ~(PF_USEDFPU);
-	}
-#else
-	if(current == last_task_used_math) {
-		put_psr(get_psr() | PSR_EF);
-		fpsave (&sf->info.si_float_regs [0], &sf->info.si_fsr,
-			&sf->info.si_fpqueue[0], &sf->info.si_fpqdepth);
-
-		/* Save a copy into thread struct as well. */
-		memcpy(&current->tss.float_regs[0], &sf->info.si_float_regs[0],
-		       (sizeof(unsigned long) * 64));
-		current->tss.fsr = sf->info.si_fsr;
-		if((current->tss.fpqdepth = sf->info.si_fpqdepth) != 0)
-		    memcpy(&current->tss.fpqueue[0], &sf->info.si_fpqueue[0],
-			   ((sizeof(unsigned long) + (sizeof(unsigned long *))) * 16));
+	copy_to_user(&sf->info.si_regs, regs, sizeof (struct pt_regs));
 
-		last_task_used_math = NULL;
-		regs->psr &= ~(PSR_EF);
+	if (current->used_math) {
+		save_fpu_state(regs, &sf->fpu_state);
+		sf->fpu_save = &sf->fpu_state;
+	} else {
+		sf->fpu_save = NULL;
 	}
-#endif
 
-	/* This new thread of control has not used the FPU. */
-	current->used_math = 0;
-
-	sf->info.si_mask = oldmask;
-	memcpy (sf, (char *) regs->u_regs [UREG_FP], sizeof (struct reg_window));
+	__put_user(oldmask, &sf->info.si_mask);
+	copy_to_user(sf, (char *) regs->u_regs [UREG_FP],
+		     sizeof (struct reg_window));
 	
 	/* 3. return to kernel instructions */
-	sf->insns [0] = 0x821020d8; /* mov __NR_sigreturn,%g1 */
-	sf->insns [1] = 0x91d02010; /* t 0x10 */
+	__put_user(0x821020d8, &sf->insns [0]); /* mov __NR_sigreturn, %g1 */
+	__put_user(0x91d02010, &sf->insns [1]); /* t 0x10 */
 
 	/* 4. signal handler back-trampoline and parameters */
 	regs->u_regs[UREG_FP] = (unsigned long) sf;
@@ -373,6 +413,7 @@
 	flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
 }
 
+
 /* Setup a Solaris stack frame */
 static inline void
 setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
@@ -491,21 +532,23 @@
 {
 	svr4_gregset_t  *gr;
 	svr4_mcontext_t *mc;
+	int ret = -EFAULT;
 
+	lock_kernel();
 	synchronize_user_stack();
 	if (current->tss.w_saved){
 		printk ("Uh oh, w_saved is not zero (%ld)\n", current->tss.w_saved);
 		do_exit (SIGSEGV);
 	}
 	if(clear_user(uc, sizeof (*uc)))
-		return -EFAULT;
+		goto out;
 
 	/* Setup convenience variables */
 	mc = &uc->mcontext;
 	gr = &mc->greg;
 	
 	/* We only have < 32 signals, fill the first slot only */
-	__put_user(current->sig->action->sa_mask, &uc->sigmask.sigbits [0]);
+	__put_user(current->blocked, &uc->sigmask.sigbits [0]);
 
 	/* Store registers */
 	__put_user(regs->pc, &uc->mcontext.greg [SVR4_PC]);
@@ -525,7 +568,10 @@
 	/* The register file is not saved
 	 * we have already stuffed all of it with sync_user_stack
 	 */
-	return 0;
+	ret = 0;
+out:
+	unlock_kernel();
+	return ret;
 }
 
 
@@ -535,7 +581,9 @@
 	struct thread_struct *tp = &current->tss;
 	svr4_gregset_t  *gr;
 	unsigned long pc, npc, psr;
+	int ret = -EINTR;
 	
+	lock_kernel();
 	/* Fixme: restore windows, or is this already taken care of in
 	 * svr4_setup_frame when sync_user_windows is done?
 	 */
@@ -544,15 +592,18 @@
 	if (tp->w_saved){
 		printk ("Uh oh, w_saved is: 0x%lx\n", tp->w_saved);
 		do_exit(SIGSEGV);
+		goto out;
 	}
 	if (((uint) c) & 3){
 		printk ("Unaligned structure passed\n");
 		do_exit (SIGSEGV);
+		goto out;
 	}
 
 	if(!__access_ok((unsigned long)c, sizeof(*c))) {
 		/* Miguel, add nice debugging msg _here_. ;-) */
 		do_exit(SIGSEGV);
+		goto out;
 	}
 
 	/* Check for valid PC and nPC */
@@ -562,6 +613,7 @@
 	if((pc | npc) & 3) {
 	        printk ("setcontext, PC or nPC were bogus\n");
 		do_exit (SIGSEGV);
+		goto out;
 	}
 	/* Retrieve information from passed ucontext */
 	    /* note that nPC is ored a 1, this is used to inform entry.S */
@@ -578,8 +630,9 @@
 	/* Restore g[1..7] and o[0..7] registers */
 	copy_from_user(&regs->u_regs [UREG_G1], &(*gr)[SVR4_G1], sizeof (long) * 7);
 	copy_from_user(&regs->u_regs [UREG_I0], &(*gr)[SVR4_O0], sizeof (long) * 8);
-
-	return -EINTR;
+out:
+	unlock_kernel();
+	return ret;
 }
 
 static inline void handle_signal(unsigned long signr, struct sigaction *sa,
@@ -630,7 +683,9 @@
 	unsigned long signr, mask = ~current->blocked;
 	struct sigaction *sa;
 	int svr4_signal = current->personality == PER_SVR4;
+	int ret;
 	
+	lock_kernel();
 	while ((signr = current->signal & mask) != 0) {
 		signr = ffz(~signr);
 		clear_bit(signr, &current->signal);
@@ -701,7 +756,8 @@
 		if(restart_syscall)
 			syscall_restart(orig_i0, regs, sa);
 		handle_signal(signr, sa, oldmask, regs, svr4_signal);
-		return 1;
+		ret = 1;
+		goto out;
 	}
 	if(restart_syscall &&
 	   (regs->u_regs[UREG_I0] == ERESTARTNOHAND ||
@@ -712,22 +768,31 @@
 		regs->pc -= 4;
 		regs->npc -= 4;
 	}
-	return 0;
+	ret = 0;
+out:
+	unlock_kernel();
+	return ret;
 }
 
 asmlinkage int
 sys_sigstack(struct sigstack *ssptr, struct sigstack *ossptr)
 {
+	int ret = -EFAULT;
+
+	lock_kernel();
 	/* First see if old state is wanted. */
 	if(ossptr) {
 		if(copy_to_user(ossptr, &current->tss.sstk_info, sizeof(struct sigstack)))
-			return -EFAULT;
+			goto out;
 	}
 
 	/* Now see if we want to update the new state. */
 	if(ssptr) {
 		if(copy_from_user(&current->tss.sstk_info, ssptr, sizeof(struct sigstack)))
-			return -EFAULT;
+			goto out;
 	}
-	return 0;
+	ret = 0;
+out:
+	unlock_kernel();
+	return ret;
 }
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/kernel/smp.c linux/arch/sparc/kernel/smp.c
--- v2.1.22/linux/arch/sparc/kernel/smp.c	Sun Dec 22 16:37:23 1996
+++ linux/arch/sparc/kernel/smp.c	Sun Jan 26 12:07:07 1997
@@ -9,6 +9,7 @@
 #include <linux/kernel.h>
 #include <linux/tasks.h>
 #include <linux/smp.h>
+#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 
 #include <asm/delay.h>
@@ -16,6 +17,7 @@
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/oplib.h>
+#include <asm/atops.h>
 
 extern ctxd_t *srmmu_ctx_table_phys;
 extern int linux_num_cpus;
@@ -58,10 +60,8 @@
  * compared to the Alpha and the intel no?  Most Sparcs have 'swap'
  * instruction which is much better...
  */
-klock_t kernel_flag = KLOCK_CLEAR;
-volatile unsigned char active_kernel_processor = NO_PROC_ID;
-volatile unsigned long kernel_counter = 0;
-volatile unsigned long syscall_count = 0;
+struct klock_info klock_info = { KLOCK_CLEAR, 0, 0 };
+
 volatile unsigned long ipi_count;
 #ifdef __SMP_PROF__
 volatile unsigned long smp_spins[NR_CPUS]={0};
@@ -99,10 +99,10 @@
 	sprintf(smp_buf,
 "        CPU0\t\tCPU1\t\tCPU2\t\tCPU3\n"
 "State:  %s\t\t%s\t\t%s\t\t%s\n",
-(cpu_present_map & 1) ? ((active_kernel_processor == 0) ? "akp" : "online") : "offline",
-(cpu_present_map & 2) ? ((active_kernel_processor == 1) ? "akp" : "online") : "offline",
-(cpu_present_map & 4) ? ((active_kernel_processor == 2) ? "akp" : "online") : "offline",
-(cpu_present_map & 8) ? ((active_kernel_processor == 3) ? "akp" : "online") : "offline");
+(cpu_present_map & 1) ? ((klock_info.akp == 0) ? "akp" : "online") : "offline",
+(cpu_present_map & 2) ? ((klock_info.akp == 1) ? "akp" : "online") : "offline",
+(cpu_present_map & 4) ? ((klock_info.akp == 2) ? "akp" : "online") : "offline",
+(cpu_present_map & 8) ? ((klock_info.akp == 3) ? "akp" : "online") : "offline");
 	return smp_buf;
 }
 
@@ -150,31 +150,32 @@
 {
 	int cpuid = smp_processor_id();
 
-	sti();
 	local_flush_cache_all();
 	local_flush_tlb_all();
+	set_irq_udt(mid_xlate[boot_cpu_id]);
 	calibrate_delay();
 	smp_store_cpu_info(cpuid);
 	local_flush_cache_all();
 	local_flush_tlb_all();
-	cli();
 
 	/* Allow master to continue. */
 	swap((unsigned long *)&cpu_callin_map[cpuid], 1);
 	local_flush_cache_all();
 	local_flush_tlb_all();
-	while(!smp_commenced)
+
+	while(!task[cpuid] || current_set[cpuid] != task[cpuid])
 		barrier();
-	local_flush_cache_all();
-	local_flush_tlb_all();
 
 	/* Fix idle thread fields. */
 	__asm__ __volatile__("ld [%0], %%g6\n\t"
-			     : : "r" (&current_set[smp_processor_id()])
+			     : : "r" (&current_set[cpuid])
 			     : "memory" /* paranoid */);
 	current->mm->mmap->vm_page_prot = PAGE_SHARED;
 	current->mm->mmap->vm_start = PAGE_OFFSET;
 	current->mm->mmap->vm_end = init_task.mm->mmap->vm_end;
+	
+	while(!smp_commenced)
+		barrier();
 
 	local_flush_cache_all();
 	local_flush_tlb_all();
@@ -207,7 +208,6 @@
 	penguin_ctable.reg_size = 0;
 
 	sti();
-	cpu_present_map |= (1 << smp_processor_id());
 	cpu_present_map = 0;
 	for(i=0; i < linux_num_cpus; i++)
 		cpu_present_map |= (1<<i);
@@ -218,9 +218,9 @@
 	mid_xlate[boot_cpu_id] = (linux_cpus[boot_cpu_id].mid & ~8);
 	cpu_number_map[boot_cpu_id] = 0;
 	cpu_logical_map[0] = boot_cpu_id;
-	active_kernel_processor = boot_cpu_id;
+	klock_info.akp = klock_info.irq_udt = boot_cpu_id;
 	smp_store_cpu_info(boot_cpu_id);
-	set_irq_udt(0);
+	set_irq_udt(mid_xlate[boot_cpu_id]);
 	local_flush_cache_all();
 	if(linux_num_cpus == 1)
 		return;  /* Not an MP box. */
@@ -325,6 +325,8 @@
 	 * but is not critical.
 	 */
 	if(msg == MSG_RESCHEDULE) {
+		if(!smp_commenced)
+			return;
 		irq = 13;
 		if(smp_cpu_in_msg[p])
 			return;
@@ -338,7 +340,7 @@
 	 */
 	if(message_cpu != NO_PROC_ID && msg != MSG_STOP_CPU && msg != MSG_RESCHEDULE) {
 		printk("CPU #%d: Message pass %d but pass in progress by %d of %d\n",
-		      smp_processor_id(),msg,message_cpu, smp_msg_id);
+		       smp_processor_id(),msg,message_cpu, smp_msg_id);
 
 		/* I don't know how to gracefully die so that debugging
 		 * this doesn't completely eat up my filesystems...
@@ -402,6 +404,12 @@
 		 * until all processors disperse.  Else we have _big_ problems.
 		 */
 		return;
+	case 4:
+		/* For captures we hold smp_cpu_in_msg[] until all processors
+		 * released.  Else we have _big_ problems.
+		 */
+		message_cpu = NO_PROC_ID;
+		return;
 	}
 	smp_cpu_in_msg[p]--;
 	message_cpu = NO_PROC_ID;
@@ -445,7 +453,7 @@
 #endif
 	if(smp_processors_ready) {
 		save_and_cli(flags);
-		if(me != active_kernel_processor)
+		if(me != klock_info.akp)
 			goto cross_call_not_master;
 
 		/* Init function glue. */
@@ -514,8 +522,9 @@
 	return;
 
 cross_call_not_master:
-	printk("Cross call initiated by non master cpu\n");
-	printk("akp=%x me=%08lx\n", active_kernel_processor, me);
+	printk("Cross call initiated by non master cpu from [%p]\n",
+	       __builtin_return_address(0));
+	printk("akp=%x me=%08lx\n", klock_info.akp, me);
 	restore_flags(flags);
 	panic("penguin cross call");
 }
@@ -569,64 +578,137 @@
 /* Reschedule call back. */
 void smp_reschedule_irq(void)
 {
-	if(smp_processor_id() != active_kernel_processor)
+	lock_kernel();
+	intr_count++;
+	if(smp_processor_id() != klock_info.akp) {
 		panic("SMP Reschedule on CPU #%d, but #%d is active.\n",
-		      smp_processor_id(), active_kernel_processor);
-
+		      smp_processor_id(), klock_info.akp);
+	}
 	need_resched=1;
+	intr_count--;
+	unlock_kernel();
 }
 
-/* XXX FIXME: this still doesn't work right... XXX */
+#undef DEBUG_CAPTURE
 
-/* #define DEBUG_CAPTURE */
-
-static volatile unsigned long release = 1;
-static volatile int capture_level = 0;
+static struct capture_struct {
+	int capture_level;
+	volatile unsigned long processors_in[NR_CPUS];
+	volatile unsigned long processors_out[NR_CPUS];
+} cap_info = { 0, };
 
 void smp_capture(void)
 {
 	unsigned long flags;
+	int me = smp_processor_id();
+	int cpu;
 
-	if(!smp_activated || !smp_commenced)
+	if(!smp_processors_ready)
 		return;
+
+	if (me != klock_info.akp)
+		panic("SMP Capture on CPU #%d, but #%d is active.\n",
+		      me, klock_info.akp);
+
 #ifdef DEBUG_CAPTURE
-	printk("C<%d>", smp_processor_id());
+	printk("C%d(%d)<", smp_processor_id(), cap_info.capture_level);
 #endif
 	save_and_cli(flags);
-	if(!capture_level) {
-		release = 0;
-		smp_message_pass(MSG_ALL_BUT_SELF, MSG_CAPTURE, 0, 1);
+
+	if (! cap_info.capture_level++) {
+		int timeout;
+
+		/* Initialize Capture Info. */
+		for (cpu = 0; cpu < smp_num_cpus; cpu++) {
+			cap_info.processors_in[cpu] = 0;
+			cap_info.processors_out[cpu] = 0;
+		}
+		cap_info.processors_in[me] = 1;
+		cap_info.processors_out[me] = 1;
+
+		smp_message_pass(MSG_ALL_BUT_SELF, MSG_CAPTURE, 0, 4);
+
+		timeout = CCALL_TIMEOUT;
+		for (cpu = 0; cpu < smp_num_cpus; cpu++) {
+			while (!cap_info.processors_in[cpu] && timeout-- > 0)
+				barrier();
+			if (!cap_info.processors_in[cpu])
+				goto procs_time_out;
+#ifdef DEBUG_CAPTURE
+			printk("%d", cpu);
+#endif
+		}
 	}
-	capture_level++;
+#ifdef DEBUG_CAPTURE
+	printk(">");
+#endif
+	restore_flags(flags);
+	return;
+
+procs_time_out:
+	printk("smp_capture (%d): Wheee, penguin drops off the bus\n",
+		smp_processor_id());
+	printk("smp_capture: map: %ld %ld %ld %ld\n",
+		cap_info.processors_in[0], cap_info.processors_in[1],
+		cap_info.processors_in[2], cap_info.processors_in[3]);
+	smp_cpu_in_msg[me]--;
+	message_cpu = NO_PROC_ID;
 	restore_flags(flags);
 }
 
 void smp_release(void)
 {
 	unsigned long flags;
-	int i;
+	int me = smp_processor_id();
+	int cpu;
 
-	if(!smp_activated || !smp_commenced)
+	if(!smp_processors_ready)
 		return;
 #ifdef DEBUG_CAPTURE
-	printk("R<%d>", smp_processor_id());
+	printk("R%d(%d)<", smp_processor_id(), cap_info.capture_level);
 #endif
+
+	if (me != klock_info.akp)
+		panic("SMP Release on CPU #%d, but #%d is active.\n",
+		      me, klock_info.akp);
+
 	save_and_cli(flags);
-	if(!(capture_level - 1)) {
-		release = 1;
-		for(i = 0; i < smp_num_cpus; i++)
-			while(cpu_callin_map[i])
+
+	if (! --cap_info.capture_level) {
+		int timeout;
+
+		for (cpu = 0; cpu < smp_num_cpus; cpu++)
+			cap_info.processors_in[cpu] = 0;
+
+		timeout = CCALL_TIMEOUT;
+		for (cpu = 0; cpu < smp_num_cpus; cpu++) {
+			while (!cap_info.processors_out[cpu] && timeout-- > 0)
 				barrier();
+			if (!cap_info.processors_out[cpu])
+				goto procs_time_out;
+#ifdef DEBUG_CAPTURE
+			printk("%d", cpu);
+#endif
+		}
+
+		/* See wait case 4 in smp_message_pass()... */
+		smp_cpu_in_msg[me]--;
 	}
-	capture_level -= 1;
+#ifdef DEBUG_CAPTURE
+	printk(">");
+#endif
 	restore_flags(flags);
-}
+	return;
 
-/* Park a processor, we must watch for more IPI's to invalidate
- * our cache's and TLB's. And also note we can only wait for
- * "lock-less" IPI's and process those, as a result of such IPI's
- * being non-maskable traps being on is enough to receive them.
- */
+procs_time_out:
+	printk("smp_release (%d): Wheee, penguin drops off the bus\n",
+		smp_processor_id());
+	printk("smp_release: map: %ld %ld %ld %ld\n",
+		cap_info.processors_out[0], cap_info.processors_out[1],
+		cap_info.processors_out[2], cap_info.processors_out[3]);
+	smp_cpu_in_msg[me]--;
+	restore_flags(flags);
+}
 
 /* Message call back. */
 void smp_message_irq(void)
@@ -640,6 +722,14 @@
 		ccall_info.func(ccall_info.arg1, ccall_info.arg2, ccall_info.arg3,
 				ccall_info.arg4, ccall_info.arg5);
 		ccall_info.processors_out[i] = 1;
+		break;
+
+	case MSG_CAPTURE:
+		flush_user_windows();
+		cap_info.processors_in[i] = 1;
+		while (cap_info.processors_in[i])
+			barrier();
+		cap_info.processors_out[i] = 1;
 		break;
 
 		/*
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/kernel/solaris.c linux/arch/sparc/kernel/solaris.c
--- v2.1.22/linux/arch/sparc/kernel/solaris.c	Wed Dec 18 15:58:45 1996
+++ linux/arch/sparc/kernel/solaris.c	Sun Jan 26 12:07:07 1997
@@ -6,43 +6,22 @@
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/fcntl.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/errno.h>
 #include <asm/solerrno.h>
 
-#if 0
-/* Not used - actually translated in iBCS */
-unsigned long solaris_xlatb_rorl[] = {
-	0, SOL_EPERM, SOL_ENOENT, SOL_ESRCH, SOL_EINTR, SOL_EIO,
-	SOL_ENXIO, SOL_E2BIG, SOL_ENOEXEC, SOL_EBADF, SOL_ECHILD,
-	SOL_EAGAIN, SOL_ENOMEM, SOL_EACCES, SOL_EFAULT,
-	SOL_ENOTBLK, SOL_EBUSY, SOL_EEXIST, SOL_EXDEV, SOL_ENODEV,
-	SOL_ENOTDIR, SOL_EISDIR, SOL_EINVAL, SOL_ENFILE, SOL_EMFILE,
-	SOL_ENOTTY, SOL_ETXTBSY, SOL_EFBIG, SOL_ENOSPC, SOL_ESPIPE,
-	SOL_EROFS, SOL_EMLINK, SOL_EPIPE, SOL_EDOM, SOL_ERANGE,
-	SOL_EWOULDBLOCK, SOL_EINPROGRESS, SOL_EALREADY, SOL_ENOTSOCK,
-	SOL_EDESTADDRREQ, SOL_EMSGSIZE, SOL_EPROTOTYPE,	SOL_ENOPROTOOPT,
-	SOL_EPROTONOSUPPORT, SOL_ESOCKTNOSUPPORT, SOL_EOPNOTSUPP,
-	SOL_EPFNOSUPPORT, SOL_EAFNOSUPPORT, SOL_EADDRINUSE,
-	SOL_EADDRNOTAVAIL, SOL_ENETDOWN, SOL_ENETUNREACH, SOL_ENETRESET,
-	SOL_ECONNABORTED, SOL_ECONNRESET, SOL_ENOBUFS, SOL_EISCONN,
-	SOL_ENOTCONN, SOL_ESHUTDOWN, SOL_ETOOMANYREFS, SOL_ETIMEDOUT,
-	SOL_ECONNREFUSED, SOL_ELOOP, SOL_ENAMETOOLONG, SOL_EHOSTDOWN,
-	SOL_EHOSTUNREACH, SOL_ENOTEMPTY, SOL_EUSERS, SOL_EUSERS,
-	SOL_EDQUOT, SOL_ESTALE, SOL_EREMOTE, SOL_ENOSTR, SOL_ETIME,
-	SOL_ENOSR, SOL_ENOMSG, SOL_EBADMSG, SOL_EIDRM, SOL_EDEADLK,
-	SOL_ENOLCK, SOL_ENONET, SOL_EINVAL, SOL_ENOLINK, SOL_EADV,
-	SOL_ESRMNT, SOL_ECOMM, SOL_EPROTO, SOL_EMULTIHOP, SOL_EINVAL,
-	SOL_EREMCHG, SOL_ENOSYS
-};
-#endif
-
 extern asmlinkage int sys_open(const char *,int,int);
 
 asmlinkage int solaris_open(const char *filename, int flags, int mode)
 {
-	int newflags = flags & 0xf;
+	int newflags;
+	int ret;
 
+	lock_kernel();
+	newflags = flags & 0xf;
 	flags &= ~0xf;
 	if(flags & 0x8050)
 		newflags |= FASYNC;
@@ -56,7 +35,9 @@
 		newflags |= O_EXCL;
 	if(flags & 0x800)
 		newflags |= O_NOCTTY;
-	return sys_open(filename, newflags, mode);
+	ret = sys_open(filename, newflags, mode);
+	unlock_kernel();
+	return ret;
 }
 
 
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/kernel/sparc-stub.c linux/arch/sparc/kernel/sparc-stub.c
--- v2.1.22/linux/arch/sparc/kernel/sparc-stub.c	Tue Nov 12 15:56:03 1996
+++ linux/arch/sparc/kernel/sparc-stub.c	Sun Jan 26 12:07:07 1997
@@ -1,4 +1,4 @@
-/* $Id: sparc-stub.c,v 1.19 1996/09/30 02:21:48 davem Exp $
+/* $Id: sparc-stub.c,v 1.20 1997/01/06 06:52:31 davem Exp $
  * sparc-stub.c:  KGDB support for the Linux kernel.
  *
  * Modifications to run under Linux
@@ -97,6 +97,8 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/system.h>
 #include <asm/signal.h>
@@ -475,6 +477,7 @@
 	    "restore\n\t"
 	    "restore\n\t");
 
+	lock_kernel();
 	if (registers[PC] == (unsigned long)breakinst) {
 		/* Skip over breakpoint trap insn */
 		registers[PC] = registers[NPC];
@@ -646,6 +649,7 @@
  * some location may have changed something that is in the instruction cache.
  */
 			flush_cache_all();
+			unlock_kernel();
 			return;
 
 			/* kill the program */
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/kernel/sparc_ksyms.c linux/arch/sparc/kernel/sparc_ksyms.c
--- v2.1.22/linux/arch/sparc/kernel/sparc_ksyms.c	Wed Jan 15 19:45:40 1997
+++ linux/arch/sparc/kernel/sparc_ksyms.c	Sun Jan 26 12:07:07 1997
@@ -1,4 +1,4 @@
-/* $Id: sparc_ksyms.c,v 1.33 1996/12/29 20:46:01 davem Exp $
+/* $Id: sparc_ksyms.c,v 1.43 1997/01/26 07:12:30 davem Exp $
  * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -27,6 +27,7 @@
 #include <asm/uaccess.h>
 #ifdef CONFIG_SBUS
 #include <asm/sbus.h>
+#include <asm/dma.h>
 #endif
 #include <asm/a.out.h>
 
@@ -38,12 +39,12 @@
 
 extern int svr4_getcontext (svr4_ucontext_t *, struct pt_regs *);
 extern int svr4_setcontext (svr4_ucontext_t *, struct pt_regs *);
-extern int sunos_poll(struct poll * ufds, size_t nfds, int timeout);
 extern unsigned long sunos_mmap(unsigned long, unsigned long, unsigned long,
 				unsigned long, unsigned long, unsigned long);
 void _sigpause_common (unsigned int set, struct pt_regs *);
 extern void __copy_1page(void *, const void *);
-extern void *__memcpy(void *, const void *, __kernel_size_t);
+extern void __memcpy(void *, const void *, __kernel_size_t);
+extern void __memmove(void *, const void *, __kernel_size_t);
 extern void *__memset(void *, int, __kernel_size_t);
 extern void *bzero_1page(void *);
 extern void *__bzero(void *, size_t);
@@ -70,18 +71,34 @@
 extern int __sparc_dot_ ## sym (int) __asm__("." #sym);		\
 __EXPORT_SYMBOL(__sparc_dot_ ## sym, "." #sym)
 
+#define EXPORT_SYMBOL_PRIVATE(sym)				\
+extern int __sparc_priv_ ## sym (int) __asm__("__" ## #sym);	\
+const struct module_symbol __export_priv_##sym			\
+__attribute__((section("__ksymtab"))) =				\
+{ (unsigned long) &__sparc_priv_ ## sym, "__" ## #sym }
 
 /* used by various drivers */
 EXPORT_SYMBOL(sparc_cpu_model);
 #ifdef __SMP__
-EXPORT_SYMBOL(kernel_flag);
-EXPORT_SYMBOL(kernel_counter);
-EXPORT_SYMBOL(active_kernel_processor);
-EXPORT_SYMBOL(syscall_count);
+EXPORT_SYMBOL(klock_info);
 #endif
+EXPORT_SYMBOL_PRIVATE(_lock_kernel);
+EXPORT_SYMBOL_PRIVATE(_unlock_kernel);
 EXPORT_SYMBOL(page_offset);
 EXPORT_SYMBOL(stack_top);
 
+/* Atomic operations. */
+EXPORT_SYMBOL_PRIVATE(_xchg32);
+EXPORT_SYMBOL_PRIVATE(_atomic_add);
+EXPORT_SYMBOL_PRIVATE(_atomic_sub);
+
+/* Bit operations. */
+EXPORT_SYMBOL_PRIVATE(_set_bit);
+EXPORT_SYMBOL_PRIVATE(_clear_bit);
+EXPORT_SYMBOL_PRIVATE(_change_bit);
+EXPORT_SYMBOL_PRIVATE(_set_le_bit);
+EXPORT_SYMBOL_PRIVATE(_clear_le_bit);
+
 EXPORT_SYMBOL(udelay);
 EXPORT_SYMBOL(mstk48t02_regs);
 #if CONFIG_SUN_AUXIO
@@ -90,6 +107,7 @@
 EXPORT_SYMBOL(request_fast_irq);
 EXPORT_SYMBOL(sparc_alloc_io);
 EXPORT_SYMBOL(sparc_free_io);
+EXPORT_SYMBOL(io_remap_page_range);
 EXPORT_SYMBOL(mmu_v2p);
 EXPORT_SYMBOL(mmu_unlockarea);
 EXPORT_SYMBOL(mmu_lockarea);
@@ -102,6 +120,7 @@
 EXPORT_SYMBOL(srmmu_unmapioaddr);
 #if CONFIG_SBUS
 EXPORT_SYMBOL(SBus_chain);
+EXPORT_SYMBOL(dma_chain);
 #endif
 
 /* Solaris/SunOS binary compatibility */
@@ -109,7 +128,6 @@
 EXPORT_SYMBOL(svr4_getcontext);
 EXPORT_SYMBOL(_sigpause_common);
 EXPORT_SYMBOL(sunos_mmap);
-EXPORT_SYMBOL(sunos_poll);
 
 /* Should really be in linux/kernel/ksyms.c */
 EXPORT_SYMBOL(dump_thread);
@@ -124,7 +142,8 @@
 EXPORT_SYMBOL(prom_nextprop);
 EXPORT_SYMBOL(prom_getproplen);
 EXPORT_SYMBOL(prom_getproperty);
-EXPORT_SYMOBL(prom_setprop);
+EXPORT_SYMBOL(prom_node_has_property);
+EXPORT_SYMBOL(prom_setprop);
 EXPORT_SYMBOL(prom_nodeops);
 EXPORT_SYMBOL(prom_getbootargs);
 EXPORT_SYMBOL(prom_apply_obio_ranges);
@@ -138,7 +157,6 @@
 
 /* sparc library symbols */
 EXPORT_SYMBOL(bcopy);
-EXPORT_SYMBOL(memmove);
 EXPORT_SYMBOL(memscan);
 EXPORT_SYMBOL(strlen);
 EXPORT_SYMBOL(strnlen);
@@ -165,6 +183,7 @@
 EXPORT_SYMBOL(__memscan_generic);
 EXPORT_SYMBOL(__memcmp);
 EXPORT_SYMBOL(__strncmp);
+EXPORT_SYMBOL(__memmove);
 
 /* Moving data to/from userspace. */
 EXPORT_SYMBOL(__copy_user);
@@ -174,12 +193,13 @@
 /* No version information on this, heavily used in inline asm,
  * and will always be 'void __ret_efault(void)'.
  */
-EXPORT_SYMBOLNOVERS(__ret_efault);
+EXPORT_SYMBOL_NOVERS(__ret_efault);
 
 /* No version information on these, as gcc produces such symbols. */
 EXPORT_SYMBOL_NOVERS(memcmp);
 EXPORT_SYMBOL_NOVERS(memcpy);
 EXPORT_SYMBOL_NOVERS(memset);
+EXPORT_SYMBOL_NOVERS(memmove);
 EXPORT_SYMBOL_NOVERS(__ashrdi3);
 
 EXPORT_SYMBOL_DOT(rem);
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/kernel/sun4m_irq.c linux/arch/sparc/kernel/sun4m_irq.c
--- v2.1.22/linux/arch/sparc/kernel/sun4m_irq.c	Wed Dec 18 15:58:45 1996
+++ linux/arch/sparc/kernel/sun4m_irq.c	Sun Jan 26 12:07:08 1997
@@ -35,7 +35,6 @@
 
 static unsigned long dummy;
 
-extern int linux_num_cpus;
 struct sun4m_intregs *sun4m_interrupts;
 unsigned long *irq_rcvreg = &dummy;
 
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/kernel/sunos_ioctl.c linux/arch/sparc/kernel/sunos_ioctl.c
--- v2.1.22/linux/arch/sparc/kernel/sunos_ioctl.c	Tue Nov 12 15:56:03 1996
+++ linux/arch/sparc/kernel/sunos_ioctl.c	Sun Jan 26 12:07:08 1997
@@ -1,4 +1,4 @@
-/* $Id: sunos_ioctl.c,v 1.26 1996/10/31 00:59:06 davem Exp $
+/* $Id: sunos_ioctl.c,v 1.27 1997/01/06 06:52:33 davem Exp $
  * sunos_ioctl.c: The Linux Operating system: SunOS ioctl compatibility.
  * 
  * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -19,6 +19,8 @@
 #include <linux/if_arp.h>
 #include <linux/fs.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 #include <asm/kbio.h>
 
 #if 0
@@ -32,10 +34,11 @@
 asmlinkage int sunos_ioctl (int fd, unsigned long cmd, unsigned long arg)
 {
 	struct file *filp;
-	int ret;
+	int ret = -EBADF;
 
+	lock_kernel();
 	if (fd >= NR_OPEN || !(filp = current->files->fd [fd]))
-		return -EBADF;
+		goto out;
 
 	/* First handle an easy compat. case for tty ldisc. */
 	if(cmd == TIOCSETD) {
@@ -43,69 +46,95 @@
 		int tmp, oldfs;
 
 		p = (int *) arg;
+		ret = -EFAULT;
 		if(get_user(tmp, p))
-			return -EFAULT;
+			goto out;
 		if(tmp == 2) {
 			oldfs = get_fs();
 			set_fs(KERNEL_DS);
 			ret = sys_ioctl(fd, cmd, (int) &ntty);
 			set_fs(oldfs);
-			return (ret == -EINVAL ? -EOPNOTSUPP : ret);
+			ret = (ret == -EINVAL ? -EOPNOTSUPP : ret);
+			goto out;
 		}
 	}
 
 	/* Binary compatibility is good American knowhow fuckin' up. */
-	if(cmd == TIOCNOTTY)
-		return sys_setsid();
+	if(cmd == TIOCNOTTY) {
+		ret = sys_setsid();
+		goto out;
+	}
 
 	/* SunOS networking ioctls. */
 	switch (cmd) {
 	case _IOW('r', 10, struct rtentry):
-		return sys_ioctl(fd, SIOCADDRT, arg);
+		ret = sys_ioctl(fd, SIOCADDRT, arg);
+		goto out;
 	case _IOW('r', 11, struct rtentry):
-		return sys_ioctl(fd, SIOCDELRT, arg);
+		ret = sys_ioctl(fd, SIOCDELRT, arg);
+		goto out;
 	case _IOW('i', 12, struct ifreq):
-		return sys_ioctl(fd, SIOCSIFADDR, arg);
+		ret = sys_ioctl(fd, SIOCSIFADDR, arg);
+		goto out;
 	case _IOWR('i', 13, struct ifreq):
-		return sys_ioctl(fd, SIOCGIFADDR, arg);
+		ret = sys_ioctl(fd, SIOCGIFADDR, arg);
+		goto out;
 	case _IOW('i', 14, struct ifreq):
-		return sys_ioctl(fd, SIOCSIFDSTADDR, arg);
+		ret = sys_ioctl(fd, SIOCSIFDSTADDR, arg);
+		goto out;
 	case _IOWR('i', 15, struct ifreq):
-		return sys_ioctl(fd, SIOCGIFDSTADDR, arg);
+		ret = sys_ioctl(fd, SIOCGIFDSTADDR, arg);
+		goto out;
 	case _IOW('i', 16, struct ifreq):
-		return sys_ioctl(fd, SIOCSIFFLAGS, arg);
+		ret = sys_ioctl(fd, SIOCSIFFLAGS, arg);
+		goto out;
 	case _IOWR('i', 17, struct ifreq):
-		return sys_ioctl(fd, SIOCGIFFLAGS, arg);
+		ret = sys_ioctl(fd, SIOCGIFFLAGS, arg);
+		goto out;
 	case _IOW('i', 18, struct ifreq):
-		return sys_ioctl(fd, SIOCSIFMEM, arg);
+		ret = sys_ioctl(fd, SIOCSIFMEM, arg);
+		goto out;
 	case _IOWR('i', 19, struct ifreq):
-		return sys_ioctl(fd, SIOCGIFMEM, arg);
+		ret = sys_ioctl(fd, SIOCGIFMEM, arg);
+		goto out;
 	case _IOWR('i', 20, struct ifconf):
-		return sys_ioctl(fd, SIOCGIFCONF, arg);
+		ret = sys_ioctl(fd, SIOCGIFCONF, arg);
+		goto out;
 	case _IOW('i', 21, struct ifreq): /* SIOCSIFMTU */
-		return sys_ioctl(fd, SIOCSIFMTU, arg);
+		ret = sys_ioctl(fd, SIOCSIFMTU, arg);
+		goto out;
 	case _IOWR('i', 22, struct ifreq): /* SIOCGIFMTU */
-		return sys_ioctl(fd, SIOCGIFMTU, arg);
+		ret = sys_ioctl(fd, SIOCGIFMTU, arg);
+		goto out;
 
 	case _IOWR('i', 23, struct ifreq):
-		return sys_ioctl(fd, SIOCGIFBRDADDR, arg);
+		ret = sys_ioctl(fd, SIOCGIFBRDADDR, arg);
+		goto out;
 	case _IOW('i', 24, struct ifreq):
-		return sys_ioctl(fd, SIOCGIFBRDADDR, arg);
+		ret = sys_ioctl(fd, SIOCGIFBRDADDR, arg);
+		goto out;
 	case _IOWR('i', 25, struct ifreq):
-		return sys_ioctl(fd, SIOCGIFNETMASK, arg);
+		ret = sys_ioctl(fd, SIOCGIFNETMASK, arg);
+		goto out;
 	case _IOW('i', 26, struct ifreq):
-		return sys_ioctl(fd, SIOCSIFNETMASK, arg);
+		ret = sys_ioctl(fd, SIOCSIFNETMASK, arg);
+		goto out;
 	case _IOWR('i', 27, struct ifreq):
-		return sys_ioctl(fd, SIOCGIFMETRIC, arg);
+		ret = sys_ioctl(fd, SIOCGIFMETRIC, arg);
+		goto out;
 	case _IOW('i', 28, struct ifreq):
-		return sys_ioctl(fd, SIOCSIFMETRIC, arg);
+		ret = sys_ioctl(fd, SIOCSIFMETRIC, arg);
+		goto out;
 
 	case _IOW('i', 30, struct arpreq):
-		return sys_ioctl(fd, SIOCSARP, arg);
+		ret = sys_ioctl(fd, SIOCSARP, arg);
+		goto out;
 	case _IOWR('i', 31, struct arpreq):
-		return sys_ioctl(fd, SIOCGARP, arg);
+		ret = sys_ioctl(fd, SIOCGARP, arg);
+		goto out;
 	case _IOW('i', 32, struct arpreq):
-		return sys_ioctl(fd, SIOCDARP, arg);
+		ret = sys_ioctl(fd, SIOCDARP, arg);
+		goto out;
 
 	case _IOW('i', 40, struct ifreq): /* SIOCUPPER */
 	case _IOW('i', 41, struct ifreq): /* SIOCLOWER */
@@ -114,12 +143,15 @@
 	case _IOW('i', 46, struct ifreq): /* SIOCSSDSTATS */
 	case _IOW('i', 47, struct ifreq): /* SIOCSSESTATS */
 	case _IOW('i', 48, struct ifreq): /* SIOCSPROMISC */
-		return -EOPNOTSUPP;
+		ret = -EOPNOTSUPP;
+		goto out;
 
 	case _IOW('i', 49, struct ifreq):
-		return sys_ioctl(fd, SIOCADDMULTI, arg);
+		ret = sys_ioctl(fd, SIOCADDMULTI, arg);
+		goto out;
 	case _IOW('i', 50, struct ifreq):
-		return sys_ioctl(fd, SIOCDELMULTI, arg);
+		ret = sys_ioctl(fd, SIOCDELMULTI, arg);
+		goto out;
 
 	/* FDDI interface ioctls, unsupported. */
 		
@@ -133,20 +165,24 @@
 	case _IOW('i', 58, struct ifreq): /* SIOCFDGNETMAP */
 	case _IOW('i', 59, struct ifreq): /* SIOCFDGIOCTL */
 		printk("FDDI ioctl, returning EOPNOTSUPP\n");
-		return -EOPNOTSUPP;
+		ret = -EOPNOTSUPP;
+		goto out;
+
 	case _IOW('t', 125, int):
 		/* More stupid tty sunos ioctls, just
 		 * say it worked.
 		 */
-		return 0;
+		ret = 0;
+		goto out;
 	/* Non posix grp */
 	case _IOW('t', 118, int): {
 		int oldval, newval, *ptr;
 
 		cmd = TIOCSPGRP;
 		ptr = (int *) arg;
+		ret = -EFAULT;
 		if(get_user(oldval, ptr))
-			return -EFAULT;
+			goto out;
 		ret = sys_ioctl(fd, cmd, arg);
 		__get_user(newval, ptr);
 		if(newval == -1) {
@@ -155,7 +191,7 @@
 		}
 		if(ret == -ENOTTY)
 			ret = -EIO;
-		return ret;
+		goto out;
 	}
 
 	case _IOR('t', 119, int): {
@@ -163,8 +199,9 @@
 
 		cmd = TIOCGPGRP;
 		ptr = (int *) arg;
+		ret = -EFAULT;
 		if(get_user(oldval, ptr))
-			return -EFAULT;
+			goto out;
 		ret = sys_ioctl(fd, cmd, arg);
 		__get_user(newval, ptr);
 		if(newval == -1) {
@@ -173,7 +210,7 @@
 		}
 		if(ret == -ENOTTY)
 			ret = -EIO;
-		return ret;
+		goto out;
 	}
 	}
 
@@ -185,7 +222,10 @@
 
 	ret = sys_ioctl(fd, cmd, arg);
 	/* so stupid... */
-	return (ret == -EINVAL ? -EOPNOTSUPP : ret);
+	ret = (ret == -EINVAL ? -EOPNOTSUPP : ret);
+out:
+	unlock_kernel();
+	return ret;
 }
 
 
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/kernel/sys_solaris.c linux/arch/sparc/kernel/sys_solaris.c
--- v2.1.22/linux/arch/sparc/kernel/sys_solaris.c	Tue Nov 12 15:56:03 1996
+++ linux/arch/sparc/kernel/sys_solaris.c	Sun Jan 26 12:07:08 1997
@@ -11,19 +11,31 @@
 #include <linux/personality.h>
 #include <linux/ptrace.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 asmlinkage int
 do_solaris_syscall (struct pt_regs *regs)
 {
+	int ret;
+
+	lock_kernel();
 	current->personality = PER_SVR4;
 	current->exec_domain = lookup_exec_domain(PER_SVR4);
 
 	if (current->exec_domain && current->exec_domain->handler){
 		current->exec_domain->handler (regs);
-		current->exec_domain->use_count = 0;
-		return regs->u_regs [UREG_I0];
+
+		/* What is going on here?  Why do we do this? */
+
+		/* XXX current->exec_domain->use_count = 0; XXX */
+
+		ret = regs->u_regs [UREG_I0];
+	} else {
+		printk ("No solaris handler\n");
+		send_sig (SIGSEGV, current, 1);
+		ret = 0;
 	}
-	printk ("No solaris handler\n");
-	send_sig (SIGSEGV, current, 1);
-	return 0;
+	unlock_kernel();
+	return ret;
 }
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/kernel/sys_sparc.c linux/arch/sparc/kernel/sys_sparc.c
--- v2.1.22/linux/arch/sparc/kernel/sys_sparc.c	Tue Dec 31 21:40:59 1996
+++ linux/arch/sparc/kernel/sys_sparc.c	Sun Jan 26 12:07:08 1997
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.33 1996/12/24 08:59:33 davem Exp $
+/* $Id: sys_sparc.c,v 1.34 1997/01/06 06:52:35 davem Exp $
  * linux/arch/sparc/kernel/sys_sparc.c
  *
  * This file contains various random system calls that
@@ -17,6 +17,8 @@
 #include <linux/shm.h>
 #include <linux/stat.h>
 #include <linux/mman.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 #include <asm/ipc.h>
@@ -33,11 +35,19 @@
 
 asmlinkage unsigned long sparc_brk(unsigned long brk)
 {
+	unsigned long ret;
+
+	lock_kernel();
 	if(sparc_cpu_model == sun4c) {
-		if(brk >= 0x20000000 && brk < 0xe0000000)
-			return current->mm->brk;
+		if(brk >= 0x20000000 && brk < 0xe0000000) {
+			ret = current->mm->brk;
+			goto out;
+		}
 	}
-	return sys_brk(brk);
+	ret = sys_brk(brk);
+out:
+	unlock_kernel();
+	return ret;
 }
 
 /*
@@ -49,13 +59,15 @@
 	int fd[2];
 	int error;
 
+	lock_kernel();
 	error = do_pipe(fd);
-	if (error) {
-		return error;
-	} else {
-		regs->u_regs[UREG_I1] = fd[1];
-		return fd[0];
-	}
+	if (error)
+		goto out;
+	regs->u_regs[UREG_I1] = fd[1];
+	error = fd[0];
+out:
+	unlock_kernel();
+	return error;
 }
 
 /*
@@ -66,52 +78,67 @@
 
 asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth)
 {
-	int version;
+	int version, err;
 
+	lock_kernel();
 	version = call >> 16; /* hack for backward compatibility */
 	call &= 0xffff;
 
 	if (call <= SEMCTL)
 		switch (call) {
 		case SEMOP:
-			return sys_semop (first, (struct sembuf *)ptr, second);
+			err = sys_semop (first, (struct sembuf *)ptr, second);
+			goto out;
 		case SEMGET:
-			return sys_semget (first, second, third);
+			err = sys_semget (first, second, third);
+			goto out;
 		case SEMCTL: {
 			union semun fourth;
+			err = -EINVAL;
 			if (!ptr)
-				return -EINVAL;
+				goto out;
+			err = -EFAULT;
 			if(get_user(fourth.__pad, (void **)ptr))
-				return -EFAULT;
-			return sys_semctl (first, second, third, fourth);
+				goto out;
+			err = sys_semctl (first, second, third, fourth);
+			goto out;
 			}
 		default:
-			return -EINVAL;
+			err = -EINVAL;
+			goto out;
 		}
 	if (call <= MSGCTL) 
 		switch (call) {
 		case MSGSND:
-			return sys_msgsnd (first, (struct msgbuf *) ptr, 
-					   second, third);
+			err = sys_msgsnd (first, (struct msgbuf *) ptr, 
+					  second, third);
+			goto out;
 		case MSGRCV:
 			switch (version) {
 			case 0: {
 				struct ipc_kludge tmp;
+				err = -EINVAL;
 				if (!ptr)
-					return -EINVAL;
+					goto out;
+				err = -EFAULT;
 				if(copy_from_user(&tmp,(struct ipc_kludge *) ptr, sizeof (tmp)))
-					return -EFAULT;
-				return sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third);
+					goto out;
+				err = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third);
+				goto out;
 				}
 			case 1: default:
-				return sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third);
+				err = sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third);
+				goto out;
 			}
 		case MSGGET:
-			return sys_msgget ((key_t) first, second);
+			err = sys_msgget ((key_t) first, second);
+			goto out;
 		case MSGCTL:
-			return sys_msgctl (first, second, (struct msqid_ds *) ptr);
+			err = sys_msgctl (first, second, (struct msqid_ds *) ptr);
+			goto out;
 		default:
-			return -EINVAL;
+			err = -EINVAL;
+			goto out;
 		}
 	if (call <= SHMCTL) 
 		switch (call) {
@@ -119,28 +146,37 @@
 			switch (version) {
 			case 0: default: {
 				ulong raddr;
-				int err;
-
 				err = sys_shmat (first, (char *) ptr, second, &raddr);
 				if (err)
-					return err;
+					goto out;
+				err = -EFAULT;
 				if(put_user (raddr, (ulong *) third))
-					return -EFAULT;
-				return 0;
+					goto out;
+				err = 0;
+				goto out;
 				}
 			case 1:	/* iBCS2 emulator entry point */
-				return sys_shmat (first, (char *) ptr, second, (ulong *) third);
+				err = sys_shmat (first, (char *) ptr, second, (ulong *) third);
+				goto out;
 			}
 		case SHMDT: 
-			return sys_shmdt ((char *)ptr);
+			err = sys_shmdt ((char *)ptr);
+			goto out;
 		case SHMGET:
-			return sys_shmget (first, second, third);
+			err = sys_shmget (first, second, third);
+			goto out;
 		case SHMCTL:
-			return sys_shmctl (first, second, (struct shmid_ds *) ptr);
+			err = sys_shmctl (first, second, (struct shmid_ds *) ptr);
+			goto out;
 		default:
-			return -EINVAL;
+			err = -EINVAL;
+			goto out;
 		}
-	return -EINVAL;
+	else
+		err = -EINVAL;
+out:
+	unlock_kernel();
+	return err;
 }
 
 extern unsigned long get_unmapped_area(unsigned long addr, unsigned long len);
@@ -151,30 +187,37 @@
 	unsigned long off)
 {
 	struct file * file = NULL;
-	long retval;
+	unsigned long retval = -EBADF;
 
+	lock_kernel();
 	if (!(flags & MAP_ANONYMOUS)) {
 		if (fd >= NR_OPEN || !(file = current->files->fd[fd])){
-			return -EBADF;
+			goto out;
 	    }
 	}
+	retval = -ENOMEM;
 	if(!(flags & MAP_FIXED) && !addr) {
 		addr = get_unmapped_area(addr, len);
 		if(!addr){
-			return -ENOMEM;
+			goto out;
 		}
 	}
 
 	/* See asm-sparc/uaccess.h */
+	retval = -EINVAL;
 	if((len > (TASK_SIZE - PAGE_SIZE)) || (addr > (TASK_SIZE-len-PAGE_SIZE)))
-		return -EINVAL;
+		goto out;
 
 	if(sparc_cpu_model == sun4c) {
-		if(((addr >= 0x20000000) && (addr < 0xe0000000)))
-			return current->mm->brk;
+		if(((addr >= 0x20000000) && (addr < 0xe0000000))) {
+			retval = current->mm->brk;
+			goto out;
+		}
 	}
 
 	retval = do_mmap(file, addr, len, prot, flags, off);
+out:
+	unlock_kernel();
 	return retval;
 }
 
@@ -182,8 +225,10 @@
 asmlinkage unsigned long
 c_sys_nis_syscall (struct pt_regs *regs)
 {
+	lock_kernel();
 	printk ("Unimplemented SPARC system call %d\n",(int)regs->u_regs[1]);
 	show_regs (regs);
+	unlock_kernel();
 	return -ENOSYS;
 }
 
@@ -192,6 +237,7 @@
 asmlinkage void
 sparc_breakpoint (struct pt_regs *regs)
 {
+	lock_kernel();
 #ifdef DEBUG_SPARC_BREAKPOINT
         printk ("TRAP: Entering kernel PC=%x, nPC=%x\n", regs->pc, regs->npc);
 #endif
@@ -199,6 +245,7 @@
 #ifdef DEBUG_SPARC_BREAKPOINT
 	printk ("TRAP: Returning to space: PC=%x nPC=%x\n", regs->pc, regs->npc);
 #endif
+	unlock_kernel();
 }
 
 extern void check_pending(int signum);
@@ -207,33 +254,38 @@
 sparc_sigaction (int signum, const struct sigaction *action, struct sigaction *oldaction)
 {
 	struct sigaction new_sa, *p;
+	int err = -EINVAL;
 
+	lock_kernel();
 	if(signum < 0) {
 		current->tss.new_signal = 1;
 		signum = -signum;
 	}
 
 	if (signum<1 || signum>32)
-		return -EINVAL;
+		goto out;
 	p = signum - 1 + current->sig->action;
 	if (action) {
-		int err = verify_area(VERIFY_READ,action,sizeof(struct sigaction));
+		err = verify_area(VERIFY_READ,action,sizeof(struct sigaction));
 		if (err)
-			return err;
+			goto out;
+		err = -EINVAL;
 		if (signum==SIGKILL || signum==SIGSTOP)
-			return -EINVAL;
+			goto out;
+		err = -EFAULT;
 		if(copy_from_user(&new_sa, action, sizeof(struct sigaction)))
-			return -EFAULT;	
+			goto out;	
 		if (new_sa.sa_handler != SIG_DFL && new_sa.sa_handler != SIG_IGN) {
 			err = verify_area(VERIFY_READ, new_sa.sa_handler, 1);
 			if (err)
-				return err;
+				goto out;
 		}
 	}
 
 	if (oldaction) {
+		err = -EFAULT;
 		if (copy_to_user(oldaction, p, sizeof(struct sigaction)))
-			return -EFAULT;	
+			goto out;	
 	}
 
 	if (action) {
@@ -241,7 +293,10 @@
 		check_pending(signum);
 	}
 
-	return 0;
+	err = 0;
+out:
+	unlock_kernel();
+	return err;
 }
 
 #ifndef CONFIG_AP1000
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c
--- v2.1.22/linux/arch/sparc/kernel/sys_sunos.c	Wed Jan 15 19:45:40 1997
+++ linux/arch/sparc/kernel/sys_sunos.c	Sun Jan 26 12:07:08 1997
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos.c,v 1.71 1996/12/29 20:46:02 davem Exp $
+/* $Id: sys_sunos.c,v 1.75 1997/01/26 07:12:31 davem Exp $
  * sys_sunos.c: SunOS specific syscall compatibility support.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -8,22 +8,6 @@
  *
  * Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu)
  *
- * The sunos_poll routine is based on iBCS2's poll routine, this
- * is the copyright message for that file:
- *
- * This file contains the procedures for the handling of poll.
- *
- * Copyright (C) 1994 Eric Youngdale
- *
- * Created for Linux based loosely upon linux select code, which
- * in turn is loosely based upon Mathius Lattner's minix
- * patches by Peter MacDonald. Heavily edited by Linus.
- *
- * Poll is used by SVr4 instead of select, and it has considerably
- * more functionality.  Parts of it are related to STREAMS, and since
- * we do not have streams, we fake it.  In fact, select() still exists
- * under SVr4, but libc turns it into a poll() call instead.  We attempt
- * to do the inverse mapping.
  */
 
 #include <linux/kernel.h>
@@ -46,6 +30,8 @@
 #include <linux/malloc.h>
 #include <linux/pagemap.h>
 #include <linux/errno.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 #ifndef KERNEL_DS
@@ -79,19 +65,22 @@
 	struct file * file = NULL;
 	unsigned long retval, ret_type;
 
+	lock_kernel();
 	current->personality |= PER_BSD;
 	if(flags & MAP_NORESERVE) {
 		printk("%s: unimplemented SunOS MAP_NORESERVE mmap() flag\n",
 		       current->comm);
 		flags &= ~MAP_NORESERVE;
 	}
+	retval = -EBADF;
 	if(!(flags & MAP_ANONYMOUS))
 		if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
-			return -EBADF;
+			goto out;
+	retval = -ENOMEM;
 	if(!(flags & MAP_FIXED) && !addr) {
 		addr = get_unmapped_area(addr, len);
 		if(!addr)
-			return -ENOMEM;
+			goto out;
 	}
 	/* If this is ld.so or a shared library doing an mmap
 	 * of /dev/zero, transform it into an anonymous mapping.
@@ -108,19 +97,23 @@
 	flags &= ~_MAP_NEW;
 
 	/* See asm-sparc/uaccess.h */
+	retval = -EINVAL;
 	if((len > (TASK_SIZE - PAGE_SIZE)) || (addr > (TASK_SIZE-len-PAGE_SIZE)))
-		return -EINVAL;
+		goto out;
 
 	if(sparc_cpu_model == sun4c) {
-		if(((addr >= 0x20000000) && (addr < 0xe0000000)))
-			return current->mm->brk;
+		if(((addr >= 0x20000000) && (addr < 0xe0000000))) {
+			retval = current->mm->brk;
+			goto out;
+		}
 	}
 
 	retval = do_mmap(file, addr, len, prot, flags, off);
-	if(ret_type)
-		return retval;
-	else
-		return ((retval < PAGE_OFFSET) ? 0 : retval);
+	if(!ret_type)
+		retval = ((retval < PAGE_OFFSET) ? 0 : retval);
+out:
+	unlock_kernel();
+	return retval;
 }
 
 /* lmbench calls this, just say "yeah, ok" */
@@ -135,23 +128,26 @@
  */
 asmlinkage int sunos_brk(unsigned long brk)
 {
-	int freepages;
+	int freepages, retval = -ENOMEM;
 	unsigned long rlim;
 	unsigned long newbrk, oldbrk;
 
+	lock_kernel();
 	if(sparc_cpu_model == sun4c) {
-		if(brk >= 0x20000000 && brk < 0xe0000000)
-			return -ENOMEM;
+		if(brk >= 0x20000000 && brk < 0xe0000000) {
+			goto out;
+		}
 	}
 
 	if (brk < current->mm->end_code)
-		return -ENOMEM;
+		goto out;
 
 	newbrk = PAGE_ALIGN(brk);
 	oldbrk = PAGE_ALIGN(current->mm->brk);
+	retval = 0;
 	if (oldbrk == newbrk) {
 		current->mm->brk = brk;
-		return 0;
+		goto out;
 	}
 
 	/*
@@ -160,22 +156,23 @@
 	if (brk <= current->mm->brk) {
 		current->mm->brk = brk;
 		do_munmap(newbrk, oldbrk-newbrk);
-		return 0;
+		goto out;
 	}
 	/*
 	 * Check against rlimit and stack..
 	 */
+	retval = -ENOMEM;
 	rlim = current->rlim[RLIMIT_DATA].rlim_cur;
 	if (rlim >= RLIM_INFINITY)
 		rlim = ~0;
 	if (brk - current->mm->end_code > rlim)
-		return -ENOMEM;
+		goto out;
 
 	/*
 	 * Check against existing mmap mappings.
 	 */
 	if (find_vma_intersection(current->mm, oldbrk, newbrk+PAGE_SIZE))
-		return -ENOMEM;
+		goto out;
 
 	/*
 	 * stupid algorithm to decide if we have enough memory: while
@@ -190,7 +187,7 @@
 	freepages -= num_physpages >> 4;
 	freepages -= (newbrk-oldbrk) >> PAGE_SHIFT;
 	if (freepages < 0)
-		return -ENOMEM;
+		goto out;
 	/*
 	 * Ok, we have probably got enough memory - let it rip.
 	 */
@@ -198,20 +195,25 @@
 	do_mmap(NULL, oldbrk, newbrk-oldbrk,
 		PROT_READ|PROT_WRITE|PROT_EXEC,
 		MAP_FIXED|MAP_PRIVATE, 0);
-	return 0;
+	retval = 0;
+out:
+	unlock_kernel();
+	return retval;
 }
 
 asmlinkage unsigned long sunos_sbrk(int increment)
 {
 	int error;
-	unsigned long oldbrk = current->mm->brk;
+	unsigned long oldbrk;
 
 	/* This should do it hopefully... */
+	lock_kernel();
+	oldbrk = current->mm->brk;
 	error = sunos_brk(((int) current->mm->brk) + increment);
-	if(error)
-		return error;
-	else
-		return oldbrk;
+	if(!error)
+		error = oldbrk;
+	unlock_kernel();
+	return error;
 }
 
 /* XXX Completely undocumented, and completely magic...
@@ -221,8 +223,10 @@
  */
 asmlinkage unsigned long sunos_sstk(int increment)
 {
+	lock_kernel();
 	printk("%s: Call to sunos_sstk(increment<%d>) is unsupported\n",
 	       current->comm, increment);
+	unlock_kernel();
 	return -1;
 }
 
@@ -243,10 +247,11 @@
 asmlinkage void sunos_vadvise(unsigned long strategy)
 {
 	/* I wanna see who uses this... */
+	lock_kernel();
 	printk("%s: Advises us to use %s paging strategy\n",
 	       current->comm,
 	       strategy <= 3 ? vstrings[strategy] : "BOGUS");
-	return; /* We don't do diddly... */
+	unlock_kernel();
 }
 
 /* Same as vadvise, and just as bogus, but for a range of virtual
@@ -270,11 +275,12 @@
 			      unsigned long strategy)
 {
 	/* I wanna see who uses this... */
+	lock_kernel();
 	printk("%s: Advises us to use %s paging strategy for addr<%08lx> len<%08lx>\n",
 	       current->comm,
 	       strategy <= 4 ? mstrings[strategy] : "BOGUS",
 	       address, len);
-	return; /* We don't do diddly... */
+	unlock_kernel();
 }
 
 /* Places into character array, the status of all the pages in the passed
@@ -293,33 +299,39 @@
 	pmd_t *pmdp;
 	pte_t *ptep;
 	unsigned long limit;
-	int num_pages, pnum;
+	int num_pages, pnum, retval = -EINVAL;
 
+	lock_kernel();
 	if(addr & ~(PAGE_MASK))
-		return -EINVAL;
+		goto out;
 
 	num_pages = (len / PAGE_SIZE);
+	retval = -EFAULT;
 	if(verify_area(VERIFY_WRITE, array, num_pages))
-		return -EFAULT;
+		goto out;
+	retval = -ENOMEM;
 	if((addr >= PAGE_OFFSET) || ((addr + len) > PAGE_OFFSET))
-		return -ENOMEM; /* I'm sure you're curious about kernel mappings.. */
+		goto out; /* I'm sure you're curious about kernel mappings.. */
 
 	/* Wheee, go through pte's */
 	pnum = 0;
 	for(limit = addr + len; addr < limit; addr += PAGE_SIZE, pnum++) {
 		pgdp = pgd_offset(current->mm, addr);
 		if(pgd_none(*pgdp))
-			return -ENOMEM; /* As per SunOS manpage */
+			goto out; /* As per SunOS manpage */
 		pmdp = pmd_offset(pgdp, addr);
 		if(pmd_none(*pmdp))
-			return -ENOMEM; /* As per SunOS manpage */
+			goto out; /* As per SunOS manpage */
 		ptep = pte_offset(pmdp, addr);
 		if(pte_none(*ptep))
-			return -ENOMEM; /* As per SunOS manpage */
+			goto out; /* As per SunOS manpage */
 		/* Page in core or Swapped page? */
 		__put_user((pte_present(*ptep) ? 1 : 0), &array[pnum]);
 	}
-	return 0; /* Success... I think... */
+	retval = 0; /* Success... I think... */
+out:
+	unlock_kernel();
+	return retval;
 }
 
 /* This just wants the soft limit (ie. rlim_cur element) of the RLIMIT_NOFILE
@@ -339,10 +351,12 @@
 	unsigned long flags;
 	unsigned long old;
 
+	lock_kernel();
 	save_and_cli(flags);
 	old = current->blocked;
 	current->blocked |= (blk_mask & _BLOCKABLE);
 	restore_flags(flags);
+	unlock_kernel();
 	return old;
 }
 
@@ -351,10 +365,12 @@
 	unsigned long flags;
 	unsigned long retval;
 
+	lock_kernel();
 	save_and_cli(flags);
 	retval = current->blocked;
 	current->blocked = newmask & _BLOCKABLE;
 	restore_flags(flags);
+	unlock_kernel();
 	return retval;
 }
 
@@ -410,14 +426,17 @@
 	struct file * file;
 	struct sunos_dirent * lastdirent;
 	struct sunos_dirent_callback buf;
-	int error;
+	int error = -EBADF;
 
+	lock_kernel();
 	if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
-		return -EBADF;
+		goto out;
+	error = -ENOTDIR;
 	if (!file->f_op || !file->f_op->readdir)
-		return -ENOTDIR;
+		goto out;
+	error = -EINVAL;
 	if(cnt < (sizeof(struct sunos_dirent) + 255))
-		return -EINVAL;
+		goto out;
 
 	buf.curr = (struct sunos_dirent *) dirent;
 	buf.previous = NULL;
@@ -425,12 +444,17 @@
 	buf.error = 0;
 	error = file->f_op->readdir(file->f_inode, file, &buf, sunos_filldir);
 	if (error < 0)
-		return error;
+		goto out;
 	lastdirent = buf.previous;
-	if (!lastdirent)
-		return buf.error;
-	put_user(file->f_pos, &lastdirent->d_off);
-	return cnt - buf.count;
+	if (!lastdirent) {
+		error = buf.error;
+	} else {
+		put_user(file->f_pos, &lastdirent->d_off);
+		error = cnt - buf.count;
+	}
+out:
+	unlock_kernel();
+	return error;
 }
 
 /* Old sunos getdirentries, severely broken compatibility stuff here. */
@@ -477,14 +501,17 @@
 	struct file * file;
 	struct sunos_direntry * lastdirent;
 	struct sunos_direntry_callback buf;
-	int error;
+	int error = -EBADF;
 
+	lock_kernel();
 	if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
-		return -EBADF;
+		goto out;
+	error = -ENOTDIR;
 	if (!file->f_op || !file->f_op->readdir)
-		return -ENOTDIR;
+		goto out;
+	error = -EINVAL;
 	if(cnt < (sizeof(struct sunos_direntry) + 255))
-		return -EINVAL;
+		goto out;
 
 	buf.curr = (struct sunos_direntry *) dirent;
 	buf.previous = NULL;
@@ -492,26 +519,36 @@
 	buf.error = 0;
 	error = file->f_op->readdir(file->f_inode, file, &buf, sunos_filldirentry);
 	if (error < 0)
-		return error;
+		goto out;
 	lastdirent = buf.previous;
-	if (!lastdirent)
-		return buf.error;
-	put_user(file->f_pos, basep);
-	return cnt - buf.count;
+	if (!lastdirent) {
+		error = buf.error;
+	} else {
+		put_user(file->f_pos, basep);
+		error = cnt - buf.count;
+	}
+out:
+	unlock_kernel();
+	return error;
 }
 
 asmlinkage int sunos_getdomainname(char *name, int len)
 {
         int nlen = strlen(system_utsname.domainname);
+	int ret = -EFAULT;
 
+	lock_kernel();
         if (nlen < len)
                 len = nlen;
 
 	if(len > __NEW_UTS_LEN)
-		return -EFAULT;
+		goto out;
 	if(copy_to_user(name, system_utsname.domainname, len))
-		return -EFAULT;
-	return 0;
+		goto out;
+	ret = 0;
+out:
+	unlock_kernel();
+	return ret;
 }
 
 struct sunos_utsname {
@@ -525,22 +562,29 @@
 
 asmlinkage int sunos_uname(struct sunos_utsname *name)
 {
+	int ret = -EFAULT;
+
+	lock_kernel();
 	if(!name)
-		return -EFAULT;
+		goto out;
 	if(copy_to_user(&name->sname[0], &system_utsname.sysname[0], sizeof(name->sname) - 1))
-		return -EFAULT;
+		goto out;
 	copy_to_user(&name->nname[0], &system_utsname.nodename[0], sizeof(name->nname) - 1);
 	put_user('\0', &name->nname[8]);
 	copy_to_user(&name->rel[0], &system_utsname.release[0], sizeof(name->rel) - 1);
 	copy_to_user(&name->ver[0], &system_utsname.version[0], sizeof(name->ver) - 1);
 	copy_to_user(&name->mach[0], &system_utsname.machine[0], sizeof(name->mach) - 1);
-	return 0;
+	ret = 0;
+out:
+	unlock_kernel();
+	return ret;
 }
 
 asmlinkage int sunos_nosys(void)
 {
 	struct pt_regs *regs;
 
+	lock_kernel();
 	regs = current->tss.kregs;
 	current->tss.sig_address = regs->pc;
 	current->tss.sig_desc = regs->u_regs[UREG_G1];
@@ -548,6 +592,7 @@
 	printk("Process makes ni_syscall number %d, register dump:\n",
 	       (int) regs->u_regs[UREG_G1]);
 	show_regs(regs);
+	unlock_kernel();
 	return -ENOSYS;
 }
 
@@ -556,33 +601,51 @@
  */
 asmlinkage int sunos_fpathconf(int fd, int name)
 {
+	int ret;
+
+	lock_kernel();
 	switch(name) {
 	case _PCONF_LINK:
-		return LINK_MAX;
+		ret = LINK_MAX;
+		break;
 	case _PCONF_CANON:
-		return MAX_CANON;
+		ret = MAX_CANON;
+		break;
 	case _PCONF_INPUT:
-		return MAX_INPUT;
+		ret = MAX_INPUT;
+		break;
 	case _PCONF_NAME:
-		return NAME_MAX;
+		ret = NAME_MAX;
+		break;
 	case _PCONF_PATH:
-		return PATH_MAX;
+		ret = PATH_MAX;
+		break;
 	case _PCONF_PIPE:
-		return PIPE_BUF;
-	case _PCONF_CHRESTRICT:
-		return 1; /* XXX Investigate XXX */
-	case _PCONF_NOTRUNC:
-		return 0; /* XXX Investigate XXX */
+		ret = PIPE_BUF;
+		break;
+	case _PCONF_CHRESTRICT:		/* XXX Investigate XXX */
+		ret = 1;
+		break;
+	case _PCONF_NOTRUNC:		/* XXX Investigate XXX */
 	case _PCONF_VDISABLE:
-		return 0;
+		ret = 0;
+		break;
 	default:
-		return -EINVAL;
+		ret = -EINVAL;
+		break;
 	}
+	unlock_kernel();
+	return ret;
 }
 
 asmlinkage int sunos_pathconf(char *path, int name)
 {
-	return sunos_fpathconf(0, name); /* XXX cheese XXX */
+	int ret;
+
+	lock_kernel();
+	ret = sunos_fpathconf(0, name); /* XXX cheese XXX */
+	unlock_kernel();
+	return ret;
 }
 
 /* SunOS mount system call emulation */
@@ -591,9 +654,14 @@
 
 asmlinkage int sunos_select(int width, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp)
 {
+	int ret;
+
 	/* SunOS binaries expect that select won't change the tvp contents */
+	lock_kernel();
 	current->personality |= STICKY_TIMEOUTS;
-	return sys_select (width, inp, outp, exp, tvp);
+	ret = sys_select (width, inp, outp, exp, tvp);
+	unlock_kernel();
+	return ret;
 }
 
 asmlinkage void sunos_nop(void)
@@ -757,15 +825,17 @@
 sunos_mount(char *type, char *dir, int flags, void *data)
 {
 	int linux_flags = MS_MGC_MSK; /* new semantics */
+	int ret = -EINVAL;
 	char *dev_fname = 0;
 
+	lock_kernel();
 	/* We don't handle the integer fs type */
 	if ((flags & SMNT_NEWTYPE) == 0)
-		return -EINVAL;
+		goto out;
 
 	/* Do not allow for those flags we don't support */
 	if (flags & (SMNT_GRPID|SMNT_NOSUB|SMNT_MULTI|SMNT_SYS5))
-		return -EINVAL;
+		goto out;
 
 	if(flags & SMNT_REMOUNT)
 		linux_flags |= MS_REMOUNT;
@@ -780,14 +850,20 @@
 	} else if(strcmp(type, "minix") == 0) {
 		dev_fname = (char *) data;
 	} else if(strcmp(type, "nfs") == 0) {
-		return sunos_nfs_mount (dir, flags, data);
+		ret = sunos_nfs_mount (dir, flags, data);
+		goto out;
         } else if(strcmp(type, "ufs") == 0) {
 		printk("Warning: UFS filesystem mounts unsupported.\n");
-		return -ENODEV;
+		ret = -ENODEV;
+		goto out;
 	} else if(strcmp(type, "proc")) {
-		return -ENODEV;
+		ret = -ENODEV;
+		goto out;
 	}
-	return sys_mount(dev_fname, dir, type, linux_flags, NULL);
+	ret = sys_mount(dev_fname, dir, type, linux_flags, NULL);
+out:
+	unlock_kernel();
+	return ret;
 }
 
 extern asmlinkage int sys_setsid(void);
@@ -795,217 +871,102 @@
 
 asmlinkage int sunos_setpgrp(pid_t pid, pid_t pgid)
 {
+	int ret;
+
 	/* So stupid... */
+	lock_kernel();
 	if((!pid || pid == current->pid) &&
 	   !pgid) {
 		sys_setsid();
-		return 0;
+		ret = 0;
 	} else {
-		return sys_setpgid(pid, pgid);
+		ret = sys_setpgid(pid, pgid);
 	}
+	unlock_kernel();
+	return ret;
 }
 
 /* So stupid... */
 extern asmlinkage int sys_wait4(pid_t, unsigned int *, int, struct rusage *);
 asmlinkage int sunos_wait4(pid_t pid, unsigned int *stat_addr, int options, struct rusage *ru)
 {
-	return sys_wait4((pid ? pid : -1), stat_addr, options, ru);
+	int ret;
+
+	lock_kernel();
+	ret = sys_wait4((pid ? pid : -1), stat_addr, options, ru);
+	unlock_kernel();
+	return ret;
 }
 
 extern int kill_pg(int, int, int);
 asmlinkage int sunos_killpg(int pgrp, int sig)
 {
-	return kill_pg(pgrp, sig, 0);
+	int ret;
+
+	lock_kernel();
+	ret = kill_pg(pgrp, sig, 0);
+	unlock_kernel();
+	return ret;
 }
 
 asmlinkage int sunos_audit(void)
 {
+	lock_kernel();
 	printk ("sys_audit\n");
+	unlock_kernel();
 	return -1;
 }
 
 extern asmlinkage unsigned long sunos_gethostid(void)
 {
-	return ((unsigned long)idprom->id_machtype << 24) |
-	       (unsigned long)idprom->id_sernum;
+	unsigned long ret;
+
+	lock_kernel();
+	ret = ((unsigned long)idprom->id_machtype << 24) |
+		(unsigned long)idprom->id_sernum;
+	unlock_kernel();
+	return ret;
 }
 
 extern asmlinkage long sunos_sysconf (int name)
 {
+	long ret;
+
+	lock_kernel();
 	switch (name){
 	case _SC_ARG_MAX:
-		return ARG_MAX;
+		ret = ARG_MAX;
+		break;
 	case _SC_CHILD_MAX:
-		return CHILD_MAX;
+		ret = CHILD_MAX;
+		break;
 	case _SC_CLK_TCK:
-		return HZ;
+		ret = HZ;
+		break;
 	case _SC_NGROUPS_MAX:
-		return NGROUPS_MAX;
+		ret = NGROUPS_MAX;
+		break;
 	case _SC_OPEN_MAX:
-		return OPEN_MAX;
+		ret = OPEN_MAX;
+		break;
 	case _SC_JOB_CONTROL:
-		return 1;	/* yes, we do support job control */
+		ret = 1;	/* yes, we do support job control */
+		break;
 	case _SC_SAVED_IDS:
-		return 1;	/* yes, we do support saved uids  */
+		ret = 1;	/* yes, we do support saved uids  */
+		break;
 	case _SC_VERSION:
 		/* mhm, POSIX_VERSION is in /usr/include/unistd.h
 		 * should it go on /usr/include/linux?
 		 */
-		return  199009L; 
-	}
-	return -1;
-}
-
-#define POLL_ROUND_UP(x,y) (((x)+(y)-1)/(y))
-
-#define POLLIN 1
-#define POLLPRI 2
-#define POLLOUT 4
-#define POLLERR 8
-#define POLLHUP 16
-#define POLLNVAL 32
-#define POLLRDNORM 64
-#define POLLWRNORM POLLOUT
-#define POLLRDBAND 128
-#define POLLWRBAND 256
-
-#define LINUX_POLLIN (POLLRDNORM | POLLRDBAND | POLLIN)
-#define LINUX_POLLOUT (POLLWRBAND | POLLWRNORM | POLLOUT)
-#define LINUX_POLLERR (POLLERR)
-
-static inline void free_wait(select_table * p)
-{
-	struct select_table_entry * entry = p->entry + p->nr;
-
-	while (p->nr > 0) {
-		p->nr--;
-		entry--;
-		remove_wait_queue(entry->wait_address,&entry->wait);
-	}
-}
-
-
-/* Copied directly from fs/select.c */
-static int check(int flag, select_table * wait, struct file * file)
-{
-	struct inode * inode;
-	struct file_operations *fops;
-	int (*select) (struct inode *, struct file *, int, select_table *);
-
-	inode = file->f_inode;
-	if ((fops = file->f_op) && (select = fops->select))
-		return select(inode, file, flag, wait)
-		    || (wait && select(inode, file, flag, NULL));
-	if (S_ISREG(inode->i_mode))
-		return 1;
-	return 0;
-}
-
-struct poll {
-	int fd;
-	short events;
-	short revents;
-};
-
-int sunos_poll(struct poll * ufds, size_t nfds, int timeout)
-{
-        int i,j, count, fdcount, retflag;
-	struct poll * fdpnt;
-	struct poll * fds, *fds1;
-	select_table wait_table, *wait;
-	struct select_table_entry *entry;
-
-	if (nfds > NR_OPEN)
-		return -EINVAL;
-
-	if (!(entry = (struct select_table_entry*)__get_free_page(GFP_KERNEL))
-	|| !(fds = (struct poll *)kmalloc(nfds*sizeof(struct poll), GFP_KERNEL)))
-		return -ENOMEM;
-
-	if(copy_from_user(fds, ufds, nfds*sizeof(struct poll))) {
-		free_page((unsigned long)entry);
-		kfree(fds);
-		return -EFAULT;
-	}
-
-	if (timeout < 0)
-		current->timeout = 0x7fffffff;
-	else {
-		current->timeout = jiffies + POLL_ROUND_UP(timeout, (1000/HZ));
-		if (current->timeout <= jiffies)
-			current->timeout = 0;
-	}
-
-	count = 0;
-	wait_table.nr = 0;
-	wait_table.entry = entry;
-	wait = &wait_table;
-
-	for(fdpnt = fds, j = 0; j < (int)nfds; j++, fdpnt++) {
-		i = fdpnt->fd;
-		fdpnt->revents = 0;
-		if (!current->files->fd[i] || !current->files->fd[i]->f_inode)
-			fdpnt->revents = POLLNVAL;
-	}
-repeat:
-	current->state = TASK_INTERRUPTIBLE;
-	for(fdpnt = fds, j = 0; j < (int)nfds; j++, fdpnt++) {
-		i = fdpnt->fd;
-
-		if(i < 0) continue;
-		if (!current->files->fd[i] || !current->files->fd[i]->f_inode) continue;
-
-		if ((fdpnt->events & LINUX_POLLIN)
-		&& check(SEL_IN, wait, current->files->fd[i])) {
-			retflag = 0;
-			if (fdpnt->events & POLLIN)
-				retflag = POLLIN;
-			if (fdpnt->events & POLLRDNORM)
-				retflag = POLLRDNORM;
-			fdpnt->revents |= retflag; 
-			count++;
-			wait = NULL;
-		}
-
-		if ((fdpnt->events & LINUX_POLLOUT) &&
-		check(SEL_OUT, wait, current->files->fd[i])) {
-			fdpnt->revents |= (LINUX_POLLOUT & fdpnt->events);
-			count++;
-			wait = NULL;
-		}
-
-		if (check(SEL_EX, wait, current->files->fd[i])) {
-			fdpnt->revents |= POLLHUP;
-			count++;
-			wait = NULL;
-		}
-	}
-
-	if ((current->signal & (~current->blocked)))
-		return -EINTR;
-
-	wait = NULL;
-	if (!count && current->timeout > jiffies) {
-		schedule();
-		goto repeat;
-	}
-
-	free_wait(&wait_table);
-	free_page((unsigned long) entry);
-
-	/* OK, now copy the revents fields back to user space. */
-	fds1 = fds;
-	fdcount = 0;
-	for(i=0; i < (int)nfds; i++, ufds++, fds++) {
-		if (fds->revents) {
-			fdcount++;
-		}
-		__put_user(fds->revents, &ufds->revents);
-	}
-	kfree(fds1);
-	current->timeout = 0;
-	current->state = TASK_RUNNING;
-	return fdcount;
+		ret = 199009L; 
+		break;
+	default:
+		ret = -1;
+		break;
+	};
+	unlock_kernel();
+	return ret;
 }
 
 extern asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg);
@@ -1016,7 +977,9 @@
 			    unsigned long arg3, void *ptr)
 {
 	union semun arg4;
+	int ret;
 
+	lock_kernel();
 	switch (op) {
 	case 0:
 		/* Most arguments match on a 1:1 basis but cmd doesn't */
@@ -1038,16 +1001,22 @@
 		}
 		/* sys_semctl(): */
 		arg4.__pad=ptr; /* value to modify semaphore to */
-		return sys_semctl((int)arg1, (int)arg2, (int)arg3, arg4 );
+		ret = sys_semctl((int)arg1, (int)arg2, (int)arg3, arg4 );
+		break;
 	case 1:
 		/* sys_semget(): */
-		return sys_semget((key_t)arg1, (int)arg2, (int)arg3);
+		ret = sys_semget((key_t)arg1, (int)arg2, (int)arg3);
+		break;
 	case 2:
 		/* sys_semop(): */
-		return sys_semop((int)arg1, (struct sembuf *)arg2, (unsigned)arg3);
+		ret = sys_semop((int)arg1, (struct sembuf *)arg2, (unsigned)arg3);
+		break;
 	default:
-		return -EINVAL;
-	}
+		ret = -EINVAL;
+		break;
+	};
+	unlock_kernel();
+	return ret;
 }
     
 extern asmlinkage int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr);
@@ -1061,32 +1030,43 @@
 	unsigned long raddr;
 	int rval;
 
+	lock_kernel();
 	switch(op) {
 	case 0:
 		/* sys_shmat(): attach a shared memory area */
 		rval = sys_shmat((int)arg1,(char *)arg2,(int)arg3,&raddr);
-		if(rval != 0)
-			return rval;
-		return (int) raddr;
+		if(!rval)
+			rval = (int) raddr;
+		break;
 	case 1:
 		/* sys_shmctl(): modify shared memory area attr. */
 		rval = sys_shmctl((int)arg1,(int)arg2,(struct shmid_ds *)arg3);
-		return (rval);
+		break;
 	case 2:
 		/* sys_shmdt(): detach a shared memory area */
-		return sys_shmdt((char *)arg1);
+		rval = sys_shmdt((char *)arg1);
+		break;
 	case 3:
 		/* sys_shmget(): get a shared memory area */
-		return sys_shmget((key_t)arg1,(int)arg2,(int)arg3);
+		rval = sys_shmget((key_t)arg1,(int)arg2,(int)arg3);
+		break;
 	default:
-		return -EINVAL;
-	}
+		rval = -EINVAL;
+		break;
+	};
+	unlock_kernel();
+	return rval;
 }
 
 asmlinkage int sunos_open(const char *filename, int flags, int mode)
 {
+	int ret;
+
+	lock_kernel();
 	current->personality |= PER_BSD;
-	return sys_open (filename, flags, mode);
+	ret = sys_open (filename, flags, mode);
+	unlock_kernel();
+	return ret;
 }
 
 
@@ -1115,37 +1095,72 @@
 
 asmlinkage int sunos_read(unsigned int fd,char *buf,int count)
 {
-	return check_nonblock(sys_read(fd,buf,count),fd);
+	int ret;
+
+	lock_kernel();
+	ret = check_nonblock(sys_read(fd,buf,count),fd);
+	unlock_kernel();
+	return ret;
 }
 
 asmlinkage int sunos_readv(unsigned long fd, const struct iovec * vector, long count)
 {
-	return check_nonblock(sys_readv(fd,vector,count),fd);
+	int ret;
+
+	lock_kernel();
+	ret = check_nonblock(sys_readv(fd,vector,count),fd);
+	lock_kernel();
+	return ret;
 }
 
 asmlinkage int sunos_write(unsigned int fd,char *buf,int count)
 {
-	return check_nonblock(sys_write(fd,buf,count),fd);
+	int ret;
+
+	lock_kernel();
+	ret = check_nonblock(sys_write(fd,buf,count),fd);
+	unlock_kernel();
+	return ret;
 }
 
 asmlinkage int sunos_writev(unsigned long fd, const struct iovec * vector, long count)
 {
-	return check_nonblock(sys_writev(fd,vector,count),fd);
+	int ret;
+
+	lock_kernel();
+	ret = check_nonblock(sys_writev(fd,vector,count),fd);
+	unlock_kernel();
+	return ret;
 }
 
 asmlinkage int sunos_recv(int fd, void * ubuf, int size, unsigned flags)
 {
-	return check_nonblock(sys_recv(fd,ubuf,size,flags),fd);
+	int ret;
+
+	lock_kernel();
+	ret = check_nonblock(sys_recv(fd,ubuf,size,flags),fd);
+	unlock_kernel();
+	return ret;
 }
 
 asmlinkage int sunos_send(int fd, void * buff, int len, unsigned flags)
 {
-	return check_nonblock(sys_send(fd,buff,len,flags),fd);
+	int ret;
+
+	lock_kernel();
+	ret = check_nonblock(sys_send(fd,buff,len,flags),fd);
+	unlock_kernel();
+	return ret;
 }
 
 asmlinkage int sunos_accept(int fd, struct sockaddr *sa, int *addrlen)
 {
-	return check_nonblock(sys_accept(fd,sa,addrlen),fd);	
+	int ret;
+
+	lock_kernel();
+	ret = check_nonblock(sys_accept(fd,sa,addrlen),fd);	
+	unlock_kernel();
+	return ret;
 }
 
 #define SUNOS_SV_INTERRUPT 2
@@ -1157,33 +1172,38 @@
 {
 	struct sigaction new_sa, *p;
 	const  int sigaction_size = sizeof (struct sigaction) - sizeof (void *);
-	int err;
+	int err = -EINVAL;
 
+	lock_kernel();
 	current->personality |= PER_BSD;
 
 	if (signum<1 || signum>32)
-		return -EINVAL;
+		goto out;
 
 	p = signum - 1 + current->sig->action;
 	if (action) {
+		err = -EFAULT;
 		if(copy_from_user(&new_sa, action, sigaction_size))
-			return -EFAULT;
+			goto out;
+		err = -EINVAL;
 		if (signum==SIGKILL || signum==SIGSTOP)
-			return -EINVAL;
+			goto out;
 		memset(&new_sa, 0, sizeof(struct sigaction));
+		err = -EFAULT;
 		if(copy_from_user(&new_sa, action, sigaction_size))
-			return -EFAULT;	
+			goto out;
 		if (new_sa.sa_handler != SIG_DFL && new_sa.sa_handler != SIG_IGN) {
 			err = verify_area(VERIFY_READ, new_sa.sa_handler, 1);
 			if (err)
-				return err;
+				goto out;
 		}
 		new_sa.sa_flags ^= SUNOS_SV_INTERRUPT;
 	}
 
 	if (oldaction) {
+		err = -EFAULT;
 		if (copy_to_user(oldaction, p, sigaction_size))
-			return -EFAULT;	
+			goto out;	
 		if (oldaction->sa_flags & SA_RESTART)
 			oldaction->sa_flags &= ~SA_RESTART;
 		else
@@ -1194,8 +1214,10 @@
 		*p = new_sa;
 		check_pending(signum);
 	}
-
-	return 0;
+	err = 0;
+out:
+	unlock_kernel();
+	return err;
 }
 
 
@@ -1206,34 +1228,32 @@
 				int optlen)
 {
 	int tr_opt = optname;
+	int ret;
 
-	if (level == SOL_IP)
-	{
-		/*
-		 *	Multicast socketopts (ttl, membership)
-		 */
+	lock_kernel();
+	if (level == SOL_IP) {
+		/* Multicast socketopts (ttl, membership) */
 		if (tr_opt >=2 && tr_opt <= 6)
-		{
 			tr_opt += 30;
-		}
 	}
-	return sys_setsockopt(fd, level, tr_opt, optval, optlen);
+	ret = sys_setsockopt(fd, level, tr_opt, optval, optlen);
+	unlock_kernel();
+	return ret;
 }
 
 asmlinkage int sunos_getsockopt(int fd, int level, int optname, char *optval,
 				int *optlen)
 {
 	int tr_opt = optname;
+	int ret;
 
-	if (level == SOL_IP)
-	{
-		/*
-		 *	Multicast socketopts (ttl, membership)
-		 */
+	lock_kernel();
+	if (level == SOL_IP) {
+		/* Multicast socketopts (ttl, membership) */
 		if (tr_opt >=2 && tr_opt <= 6)
-		{
 			tr_opt += 30;
-		}
 	}
-	return sys_getsockopt(fd, level, tr_opt, optval, optlen);
+	ret = sys_getsockopt(fd, level, tr_opt, optval, optlen);
+	unlock_kernel();
+	return ret;
 }
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/kernel/systbls.S linux/arch/sparc/kernel/systbls.S
--- v2.1.22/linux/arch/sparc/kernel/systbls.S	Tue Dec 31 21:41:00 1996
+++ linux/arch/sparc/kernel/systbls.S	Sun Jan 26 12:07:08 1997
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.56 1996/12/29 20:46:03 davem Exp $
+/* $Id: systbls.S,v 1.58 1997/01/26 07:12:31 davem Exp $
  * systbls.S: System call entry point tables for OS compatibility.
  *            The native Linux system call table lives here also.
  *
@@ -11,30 +11,6 @@
 
 #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
 
@@ -78,25 +54,29 @@
 	.long C_LABEL(sys_fcntl), C_LABEL(sys_select), C_LABEL(sys_nis_syscall)
 	.long C_LABEL(sys_fsync), C_LABEL(sys_setpriority), C_LABEL(sys_nis_syscall)
 	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*100*/	.long C_LABEL(sys_getpriority), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_gettimeofday), C_LABEL(sys_getrusage)
+/*100*/	.long C_LABEL(sys_getpriority), C_LABEL(sys_nis_syscall)
+	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
+	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
+	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
+	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
+	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
+	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
+	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
+	.long C_LABEL(sys_gettimeofday), C_LABEL(sys_getrusage)
 	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_readv)
 	.long C_LABEL(sys_writev), C_LABEL(sys_settimeofday), C_LABEL(sys_fchown)
 	.long C_LABEL(sys_fchmod), C_LABEL(sys_nis_syscall), C_LABEL(sys_setreuid)
 	.long C_LABEL(sys_setregid), C_LABEL(sys_rename), C_LABEL(sys_truncate)
 	.long C_LABEL(sys_ftruncate), C_LABEL(sys_flock), C_LABEL(sys_nis_syscall)
 	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
+
 	.long C_LABEL(sys_mkdir), C_LABEL(sys_rmdir), C_LABEL(sys_nis_syscall)
 	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
 	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_getrlimit)
 	.long C_LABEL(sys_setrlimit), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
 	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
 /*150*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
+	.long C_LABEL(sys_poll), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
 	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_statfs), C_LABEL(sys_fstatfs)
 	.long C_LABEL(sys_umount), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
 	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_setdomainname)
@@ -193,7 +173,7 @@
 	.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_poll), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+	.long C_LABEL(sys_poll), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
 	.long C_LABEL(sunos_getdirentries), C_LABEL(sys_statfs), C_LABEL(sys_fstatfs)
 	.long C_LABEL(sys_umount), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
 	.long C_LABEL(sunos_getdomainname), C_LABEL(sys_setdomainname)
@@ -228,257 +208,3 @@
 	.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
 /*250*/	.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
 	.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sys_aplib)
-
-#if 0
-/* Not used yet - {net, open}bsd is a TODO */
-	/* {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*/
-#endif
-
-#if 0
-/* Not needed - iBCS has its own */
-	/* One thing left, Solaris syscall table, TODO */
-	.globl	C_LABEL(solaris_sys_table)
-C_LABEL(solaris_sys_table):
-/*0*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_exit), C_LABEL(sys_fork)
-	.long C_LABEL(sys_read), C_LABEL(sys_write)
-/*5*/	.long C_LABEL(solaris_open), C_LABEL(sys_close), C_LABEL(sys_wait4)
-	.long C_LABEL(sys_creat), C_LABEL(sys_link)
-/*10*/	.long C_LABEL(sys_unlink), C_LABEL(sys_nis_syscall), C_LABEL(sys_chdir)
-	.long C_LABEL(sys_time), C_LABEL(sys_mknod)
-/*15*/	.long C_LABEL(sys_chmod), C_LABEL(sys_chown), C_LABEL(sys_brk)
-	.long C_LABEL(sys_stat), C_LABEL(sys_lseek)
-/*20*/	.long C_LABEL(sunos_getpid), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_setuid), C_LABEL(sunos_getuid)
-/*25*/	.long C_LABEL(sys_stime), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_alarm), C_LABEL(sys_nis_syscall), C_LABEL(sys_pause)
-/*30*/	.long C_LABEL(sys_utime), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_access), C_LABEL(sys_nice)
-/*35*/	.long C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_sync), C_LABEL(sys_kill), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall)
-/*40*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*45*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*50*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*55*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*60*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*65*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*70*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*75*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*80*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*85*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*90*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*95*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*100*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*105*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*110*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*115*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*120*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*125*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*130*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*135*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*140*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*145*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*150*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*155*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*160*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*165*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*170*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*175*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*180*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*185*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*190*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*195*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*200*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*205*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*210*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*215*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*220*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*225*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*230*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*235*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*240*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*245*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*250*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*255*/	.long C_LABEL(sys_nis_syscall)
-#endif
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/kernel/time.c linux/arch/sparc/kernel/time.c
--- v2.1.22/linux/arch/sparc/kernel/time.c	Sun Dec 22 16:37:27 1996
+++ linux/arch/sparc/kernel/time.c	Sun Jan 26 12:07:08 1997
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.22 1996/12/19 08:06:32 davem Exp $
+/* $Id: time.c,v 1.23 1997/01/26 04:28:34 davem Exp $
  * linux/arch/sparc/kernel/time.c
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -238,6 +238,8 @@
 {
 	unsigned int year, mon, day, hour, min, sec;
 	struct mostek48t02 *mregs;
+
+	do_get_fast_time = do_gettimeofday;
 
 #if CONFIG_AP1000
 	init_timers(timer_interrupt);
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/kernel/traps.c linux/arch/sparc/kernel/traps.c
--- v2.1.22/linux/arch/sparc/kernel/traps.c	Tue Dec 31 21:41:00 1996
+++ linux/arch/sparc/kernel/traps.c	Sun Jan 26 12:07:08 1997
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.50 1996/12/29 20:46:05 davem Exp $
+/* $Id: traps.c,v 1.53 1997/01/25 02:43:05 miguel Exp $
  * arch/sparc/kernel/traps.c
  *
  * Copyright 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -11,6 +11,8 @@
 #include <linux/sched.h>  /* for jiffies */
 #include <linux/kernel.h>
 #include <linux/signal.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/delay.h>
 #include <asm/system.h>
@@ -21,7 +23,6 @@
 #include <asm/kdebug.h>
 #include <asm/unistd.h>
 #include <asm/traps.h>
-#include <asm/smp.h>
 
 /* #define TRAP_DEBUG */
 
@@ -93,6 +94,7 @@
 
 void do_hw_interrupt(unsigned long type, unsigned long psr, unsigned long pc)
 {
+	lock_kernel();
 	if(type < 0x80) {
 		/* Sun OS's puke from bad traps, Linux survives! */
 		printk("Unimplemented Sparc TRAP, type = %02lx\n", type);
@@ -101,20 +103,21 @@
 
 	if(type == SP_TRAP_SBPT) {
 		send_sig(SIGTRAP, current, 1);
-		return;
-	}
-
-	if(psr & PSR_PS)
-		die_if_kernel("Kernel bad trap", current->tss.kregs);
+	} else {
+		if(psr & PSR_PS)
+			die_if_kernel("Kernel bad trap", current->tss.kregs);
 
-	current->tss.sig_desc = SUBSIG_BADTRAP(type - 0x80);
-	current->tss.sig_address = pc;
-	send_sig(SIGILL, current, 1);
+		current->tss.sig_desc = SUBSIG_BADTRAP(type - 0x80);
+		current->tss.sig_address = pc;
+		send_sig(SIGILL, current, 1);
+	}
+	unlock_kernel();
 }
 
 void do_illegal_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
 			    unsigned long psr)
 {
+	lock_kernel();
 	if(psr & PSR_PS)
 		die_if_kernel("Kernel illegal instruction", regs);
 #ifdef TRAP_DEBUG
@@ -124,21 +127,25 @@
 	if (sparc_cpu_model == sun4c || sparc_cpu_model == sun4) {
 		extern int do_user_muldiv (struct pt_regs *, unsigned long);
 		if (!do_user_muldiv (regs, pc))
-			return;
+			goto out;
 	}
 	current->tss.sig_address = pc;
 	current->tss.sig_desc = SUBSIG_ILLINST;
 	send_sig(SIGILL, current, 1);
+out:
+	unlock_kernel();
 }
 
 void do_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
 			 unsigned long psr)
 {
+	lock_kernel();
 	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);
+	unlock_kernel();
 }
 
 /* XXX User may want to be allowed to do this. XXX */
@@ -146,6 +153,7 @@
 void do_memaccess_unaligned(struct pt_regs *regs, unsigned long pc, unsigned long npc,
 			    unsigned long psr)
 {
+	lock_kernel();
 	if(regs->psr & PSR_PS) {
 		printk("KERNEL MNA at pc %08lx npc %08lx called by %08lx\n", pc, npc,
 		       regs->u_regs[UREG_RETPC]);
@@ -160,6 +168,7 @@
 	printk ("do_MNA!\n");
 #endif
 	send_sig(SIGBUS, current, 1);
+	unlock_kernel();
 }
 
 extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
@@ -176,6 +185,7 @@
 void do_fpd_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
 		 unsigned long psr)
 {
+	lock_kernel();
 	/* Sanity check... */
 	if(psr & PSR_PS)
 		die_if_kernel("Kernel gets FloatingPenguinUnit disabled trap", regs);
@@ -184,7 +194,7 @@
 	regs->psr |= PSR_EF;
 #ifndef __SMP__
 	if(last_task_used_math == current)
-		return;
+		goto out;
 	if(last_task_used_math) {
 		/* Other processes fpu state, save away */
 		struct task_struct *fptask = last_task_used_math;
@@ -208,6 +218,10 @@
 	}
 	current->flags |= PF_USEDFPU;
 #endif
+#ifndef __SMP__
+out:
+#endif
+	unlock_kernel();
 }
 
 static unsigned long fake_regs[32] __attribute__ ((aligned (8)));
@@ -224,7 +238,7 @@
 #else
 	struct task_struct *fpt = current;
 #endif
-
+	lock_kernel();
 	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
@@ -237,7 +251,7 @@
 #endif
 		fpsave(&fake_regs[0], &fake_fsr, &fake_queue[0], &fake_depth);
 		regs->psr &= ~PSR_EF;
-		return;
+		goto out;
 	}
 	fpsave(&fpt->tss.float_regs[0], &fpt->tss.fsr,
 	       &fpt->tss.fpqueue[0], &fpt->tss.fpqdepth);
@@ -258,7 +272,7 @@
 		if(calls > 2)
 			die_if_kernel("Too many Penguin-FPU traps from kernel mode",
 				      regs);
-		return;
+		goto out;
 	}
 	send_sig(SIGFPE, fpt, 1);
 #ifndef __SMP__
@@ -267,21 +281,26 @@
 	regs->psr &= ~PSR_EF;
 	if(calls > 0)
 		calls=0;
+out:
+	unlock_kernel();
 }
 
 void handle_tag_overflow(struct pt_regs *regs, unsigned long pc, unsigned long npc,
 			 unsigned long psr)
 {
+	lock_kernel();
 	if(psr & PSR_PS)
 		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);
+	unlock_kernel();
 }
 
 void handle_watchpoint(struct pt_regs *regs, unsigned long pc, unsigned long npc,
 		       unsigned long psr)
 {
+	lock_kernel();
 #ifdef TRAP_DEBUG
 	printk("Watchpoint detected at PC %08lx NPC %08lx PSR %08lx\n",
 	       pc, npc, psr);
@@ -289,49 +308,60 @@
 	if(psr & PSR_PS)
 		panic("Tell me what a watchpoint trap is, and I'll then deal "
 		      "with such a beast...");
+	unlock_kernel();
 }
 
 void handle_reg_access(struct pt_regs *regs, unsigned long pc, unsigned long npc,
 		       unsigned long psr)
 {
+	lock_kernel();
 #ifdef TRAP_DEBUG
 	printk("Register Access Exception at PC %08lx NPC %08lx PSR %08lx\n",
 	       pc, npc, psr);
 #endif
 	send_sig(SIGILL, current, 1);
+	unlock_kernel();
 }
 
 void handle_cp_disabled(struct pt_regs *regs, unsigned long pc, unsigned long npc,
 			unsigned long psr)
 {
+	lock_kernel();
 	send_sig(SIGILL, current, 1);
+	unlock_kernel();
 }
 
 void handle_bad_flush(struct pt_regs *regs, unsigned long pc, unsigned long npc,
 		      unsigned long psr)
 {
+	lock_kernel();
 #ifdef TRAP_DEBUG
 	printk("Unimplemented FLUSH Exception at PC %08lx NPC %08lx PSR %08lx\n",
 	       pc, npc, psr);
 #endif
 	printk("INSTRUCTION=%08lx\n", *((unsigned long *) regs->pc));
 	send_sig(SIGILL, current, 1);
+	unlock_kernel();
 }
 
 void handle_cp_exception(struct pt_regs *regs, unsigned long pc, unsigned long npc,
 			 unsigned long psr)
 {
+	lock_kernel();
 #ifdef TRAP_DEBUG
 	printk("Co-Processor Exception at PC %08lx NPC %08lx PSR %08lx\n",
 	       pc, npc, psr);
 #endif
 	send_sig(SIGILL, current, 1);
+	unlock_kernel();
 }
 
 void handle_hw_divzero(struct pt_regs *regs, unsigned long pc, unsigned long npc,
 		       unsigned long psr)
 {
+	lock_kernel();
 	send_sig(SIGILL, current, 1);
+	unlock_kernel();
 }
 
 /* Since we have our mappings set up, on multiprocessors we can spin them
@@ -340,7 +370,6 @@
 
 extern void sparc_cpu_startup(void);
 
-extern int linux_num_cpus;
 extern ctxd_t *srmmu_ctx_table_phys;
 
 int linux_smp_still_initting;
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/kernel/unaligned.c linux/arch/sparc/kernel/unaligned.c
--- v2.1.22/linux/arch/sparc/kernel/unaligned.c	Wed Jan 15 19:45:41 1997
+++ linux/arch/sparc/kernel/unaligned.c	Sun Jan 26 12:07:09 1997
@@ -1,4 +1,4 @@
-/* $Id: unaligned.c,v 1.13 1996/11/26 14:01:57 jj Exp $
+/* $Id: unaligned.c,v 1.15 1997/01/16 14:14:42 davem Exp $
  * unaligned.c: Unaligned load/store trap handling with special
  *              cases for the kernel to do them more quickly.
  *
@@ -14,6 +14,8 @@
 #include <asm/processor.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 /* #define DEBUG_MNA */
 
@@ -206,7 +208,7 @@
 	: : "r" (dest_reg), "r" (size), "r" (saddr), "r" (is_signed)		\
 	: "l1", "l2", "g7", "g1");						\
 })
-
+	
 #define store_common(dst_addr, size, src_val, errh) ({				\
 __asm__ __volatile__ (								\
 	"ld	[%2], %%l1\n"							\
@@ -332,6 +334,7 @@
 	enum direction dir = decode_direction(insn);
 	int size = decode_access_size(insn);
 
+	lock_kernel();
 	if(!ok_for_kernel(insn) || dir == both) {
 		printk("Unsupported unaligned load/store trap for kernel at <%08lx>.\n",
 		       regs->pc);
@@ -344,8 +347,6 @@
 		" mov	%1, %%o1\n\t"
 		: : "r" (regs), "r" (insn)
 		: "o0", "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g4", "g5", "g7");
-
-		return;
 	} else {
 		unsigned long addr = compute_effective_address(regs, insn);
 
@@ -379,6 +380,7 @@
 		}
 		advance(regs);
 	}
+	unlock_kernel();
 }
 
 static inline int ok_for_user(struct pt_regs *regs, unsigned int insn,
@@ -431,6 +433,7 @@
 {
 	enum direction dir;
 
+	lock_kernel();
 	if(!(current->tss.flags & SPARC_FLAG_UNALIGNED) ||
 	   (((insn >> 30) & 3) != 3))
 		goto kill_user;
@@ -477,15 +480,16 @@
 			" mov	%1, %%o1\n\t"
 			: : "r" (regs), "r" (insn)
 			: "o0", "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g4", "g5", "g7");
-
-			return;
+			goto out;
 		}
 		advance(regs);
-		return;
+		goto out;
 	}
 
 kill_user:
 	current->tss.sig_address = regs->pc;
 	current->tss.sig_desc = SUBSIG_PRIVINST;
 	send_sig(SIGBUS, current, 1);
+out:
+	unlock_kernel();
 }
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/kernel/windows.c linux/arch/sparc/kernel/windows.c
--- v2.1.22/linux/arch/sparc/kernel/windows.c	Tue Nov 12 15:56:03 1996
+++ linux/arch/sparc/kernel/windows.c	Sun Jan 26 12:07:09 1997
@@ -8,6 +8,8 @@
 #include <linux/sched.h>
 #include <linux/string.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 
@@ -111,6 +113,7 @@
 	struct thread_struct *tp;
 	int window;
 
+	lock_kernel();
 	flush_user_windows();
 	tp = &current->tss;
 	for(window = 0; window < tp->w_saved; window++) {
@@ -121,4 +124,5 @@
 			do_exit(SIGILL);
 	}
 	tp->w_saved = 0;
+	unlock_kernel();
 }
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/kernel/wof.S linux/arch/sparc/kernel/wof.S
--- v2.1.22/linux/arch/sparc/kernel/wof.S	Tue Dec 31 21:41:00 1996
+++ linux/arch/sparc/kernel/wof.S	Sun Jan 26 12:07:09 1997
@@ -1,4 +1,4 @@
-/* $Id: wof.S,v 1.31 1996/12/28 18:14:22 davem Exp $
+/* $Id: wof.S,v 1.32 1997/01/06 06:52:43 davem Exp $
  * wof.S: Sparc window overflow handler.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -243,8 +243,6 @@
 	mov	%saved_g6, %g6
 	STORE_PT_ALL(sp, t_psr, t_pc, t_npc, g1)
 	mov	%l4, %g6
-
-	ENTER_SYSCALL
 
 	/* Turn on traps and call c-code to deal with it. */
 	wr	%t_psr, PSR_ET, %psr
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/kernel/wuf.S linux/arch/sparc/kernel/wuf.S
--- v2.1.22/linux/arch/sparc/kernel/wuf.S	Tue Dec 31 21:41:00 1996
+++ linux/arch/sparc/kernel/wuf.S	Sun Jan 26 12:07:09 1997
@@ -1,4 +1,4 @@
-/* $Id: wuf.S,v 1.29 1996/12/28 18:14:23 davem Exp $
+/* $Id: wuf.S,v 1.30 1997/01/06 06:52:44 davem Exp $
  * wuf.S: Window underflow trap handler for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller
@@ -180,8 +180,6 @@
 	sll	%g5, %g3, %g5
 	st	%g5, [%curptr + THREAD_UMASK]		! one live user window still
 	st	%g0, [%curptr + THREAD_W_SAVED]		! no windows in the buffer
-
-	ENTER_SYSCALL
 
 	wr	%t_psr, PSR_ET, %psr			! enable traps
 	nop
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/lib/Makefile linux/arch/sparc/lib/Makefile
--- v2.1.22/linux/arch/sparc/lib/Makefile	Wed Dec 18 15:58:46 1996
+++ linux/arch/sparc/lib/Makefile	Sun Jan 26 12:07:09 1997
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.15 1996/11/22 11:57:00 ecd Exp $
+# $Id: Makefile,v 1.21 1997/01/25 06:48:43 davem Exp $
 # Makefile for Sparc library files..
 #
 
@@ -7,7 +7,7 @@
 OBJS  = mul.o rem.o sdiv.o udiv.o umul.o urem.o ashrdi3.o memcpy.o memset.o \
         strlen.o checksum.o blockops.o memscan.o memcmp.o strncmp.o \
 	strncpy_from_user.o divdi3.o udivdi3.o strlen_user.o \
-	copy_user.o clear_user.o
+	copy_user.o clear_user.o locks.o atomic.o bitops.o
 
 lib.a: $(OBJS)
 	$(AR) rcs lib.a $(OBJS)
@@ -45,6 +45,30 @@
 
 memset.o: memset.S
 	$(CC) -D__ASSEMBLY__ -ansi -c -o memset.o memset.S
+
+ifdef SMP
+
+locks.o: locks.S
+	$(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o locks.o locks.S
+
+atomic.o: atomic.S
+	$(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o atomic.o atomic.S
+
+bitops.o: bitops.S
+	$(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o bitops.o bitops.S
+
+else
+
+locks.o: locks.S
+	$(CC) -D__ASSEMBLY__ -ansi -c -o locks.o locks.S
+
+atomic.o: atomic.S
+	$(CC) -D__ASSEMBLY__ -ansi -c -o atomic.o atomic.S
+
+bitops.o: bitops.S
+	$(CC) -D__ASSEMBLY__ -ansi -c -o bitops.o bitops.S
+
+endif
 
 strlen.o: strlen.S
 	$(CC) -ansi -c -o strlen.o strlen.S
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/lib/atomic.S linux/arch/sparc/lib/atomic.S
--- v2.1.22/linux/arch/sparc/lib/atomic.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/lib/atomic.S	Sun Jan 26 12:07:09 1997
@@ -0,0 +1,84 @@
+/* atomic.S: Move this stuff here for better ICACHE hit rates.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu)
+ */
+
+#include <asm/cprefix.h>
+#include <asm/ptrace.h>
+#include <asm/psr.h>
+
+	.text
+	.align	4
+
+	/* XXX At boot time patch this with swap [x], y; retl; if
+	 * XXX processor is found to have that instruction.
+	 */
+
+	.globl	___xchg32
+___xchg32:
+	rd	%psr, %g3
+	andcc	%g3, PSR_PIL, %g0
+	bne	1f
+	 nop
+	wr	%g3, PSR_PIL, %psr
+	nop; nop; nop
+1:
+	andcc	%g3, PSR_PIL, %g0
+	ld	[%g1], %g7
+	bne	1f
+	 st	%g2, [%g1]
+	wr	%g3, 0x0, %psr
+	nop; nop; nop
+1:
+	mov	%g7, %g2
+	jmpl	%o7, %g0		/* Note, not + 0x8, see call in system.h */
+	 mov	%g4, %o7
+
+	.globl	___xchg32_hw
+___xchg32_hw:
+	swap	[%g1], %g2
+	jmpl	%o7, %g0		/* Note, not + 0x8, see call in system.h */
+	 mov	%g4, %o7
+
+	/* Atomic add/sub routines.  Returns the final value whether you
+	 * want it or not for even _better_ cache hit rates.
+	 */
+	.globl	___atomic_add
+___atomic_add:
+	rd	%psr, %g3
+	andcc	%g3, PSR_PIL, %g0
+	bne	1f
+	 nop
+	wr	%g3, PSR_PIL, %psr
+	nop; nop; nop;
+1:
+	ld	[%g1], %g7
+	andcc	%g3, PSR_PIL, %g0
+	add	%g7, %g2, %g2
+	bne	1f
+	 st	%g2, [%g1]
+	wr	%g3, 0x0, %psr
+	nop; nop; nop;
+1:
+	jmpl	%o7, %g0		/* NOTE: not + 8, see callers in atomic.h */
+	 mov	%g4, %o7
+
+	.globl	___atomic_sub
+___atomic_sub:
+	rd	%psr, %g3
+	andcc	%g3, PSR_PIL, %g0
+	bne	1f
+	 nop
+	wr	%g3, PSR_PIL, %psr
+	nop; nop; nop;
+1:
+	ld	[%g1], %g7
+	andcc	%g3, PSR_PIL, %g0
+	sub	%g7, %g2, %g2
+	bne	1f
+	 st	%g2, [%g1]
+	wr	%g3, 0x0, %psr
+	nop; nop; nop;
+1:
+	jmpl	%o7, %g0		/* NOTE: not + 8, see callers in atomic.h */
+	 mov	%g4, %o7
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/lib/bitops.S linux/arch/sparc/lib/bitops.S
--- v2.1.22/linux/arch/sparc/lib/bitops.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/lib/bitops.S	Sun Jan 26 12:07:09 1997
@@ -0,0 +1,126 @@
+/* bitops.S: Low level assembler bit operations.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/cprefix.h>
+#include <asm/ptrace.h>
+#include <asm/psr.h>
+
+	.text
+	.align	4
+
+	/* Take bits in %g2 and set them in word at %g1,
+	 * return whether bits were set in original value
+	 * in %g2.  %g4 holds value to restore into %o7
+	 * in delay slot of jmpl return, %g3 + %g5 + %g7 can be
+	 * used as temporaries and thus is considered clobbered
+	 * by all callers.
+	 */
+	.globl	___set_bit
+___set_bit:
+	rd	%psr, %g3
+	andcc	%g3, PSR_PIL, %g0
+	bne	1f
+	 nop
+	wr	%g3, PSR_PIL, %psr
+	nop; nop; nop
+1:
+	ld	[%g1], %g7
+	or	%g7, %g2, %g5
+	andcc	%g3, PSR_PIL, %g0
+	and	%g7, %g2, %g2
+	bne	1f
+	 st	%g5, [%g1]
+	wr	%g3, 0x0, %psr
+	nop; nop; nop
+1:
+	jmpl	%o7, %g0
+	 mov	%g4, %o7
+
+	/* Same as above, but clears the bits from %g2 instead. */
+	.globl	___clear_bit
+___clear_bit:
+	rd	%psr, %g3
+	andcc	%g3, PSR_PIL, %g0
+	bne	1f
+	 nop
+	wr	%g3, PSR_PIL, %psr
+	nop; nop; nop
+1:
+	ld	[%g1], %g7
+	andn	%g7, %g2, %g5
+	andcc	%g3, PSR_PIL, %g0
+	and	%g7, %g2, %g2
+	bne	1f
+	 st	%g5, [%g1]
+	wr	%g3, 0x0, %psr
+	nop; nop; nop
+1:
+	jmpl	%o7, %g0
+	 mov	%g4, %o7
+
+	/* Same thing again, but this time toggles the bits from %g2. */
+	.globl	___change_bit
+___change_bit:
+	rd	%psr, %g3
+	andcc	%g3, PSR_PIL, %g0
+	bne	1f
+	 nop
+	wr	%g3, PSR_PIL, %psr
+	nop; nop; nop
+1:
+	ld	[%g1], %g7
+	xor	%g7, %g2, %g5
+	andcc	%g3, PSR_PIL, %g0
+	and	%g7, %g2, %g2
+	bne	1f
+	 st	%g5, [%g1]
+	wr	%g3, 0x0, %psr
+	nop; nop; nop
+1:
+	jmpl	%o7, %g0
+	 mov	%g4, %o7
+
+	/* Now the little endian versions. */
+	.globl	___set_le_bit
+___set_le_bit:
+	rd	%psr, %g3
+	andcc	%g3, PSR_PIL, %g0
+	bne	1f
+	 nop
+	wr	%g3, PSR_PIL, %psr
+	nop; nop; nop
+1:
+	ldub	[%g1], %g7
+	or	%g7, %g2, %g5
+	andcc	%g3, PSR_PIL, %g0
+	and	%g7, %g2, %g2
+	bne	1f
+	 stb	%g5, [%g1]
+	wr	%g3, 0x0, %psr
+	nop; nop; nop
+1:
+	jmpl	%o7, %g0
+	 mov	%g4, %o7
+
+	.globl	___clear_le_bit
+___clear_le_bit:
+	rd	%psr, %g3
+	andcc	%g3, PSR_PIL, %g0
+	bne	1f
+	 nop
+	wr	%g3, PSR_PIL, %psr
+	nop; nop; nop
+1:
+	ldub	[%g1], %g7
+	andn	%g7, %g2, %g5
+	andcc	%g3, PSR_PIL, %g0
+	and	%g7, %g2, %g2
+	bne	1f
+	 stb	%g5, [%g1]
+	wr	%g3, 0x0, %psr
+	nop; nop; nop
+1:
+	jmpl	%o7, %g0
+	 mov	%g4, %o7
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/lib/locks.S linux/arch/sparc/lib/locks.S
--- v2.1.22/linux/arch/sparc/lib/locks.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/lib/locks.S	Sun Jan 26 12:07:09 1997
@@ -0,0 +1,114 @@
+/* $Id: locks.S,v 1.3 1997/01/12 11:36:44 davem Exp $
+ * locks.S: SMP low-level lock primitives on Sparc.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/cprefix.h>
+#include <asm/ptrace.h>
+#include <asm/psr.h>
+
+	.text
+	.align	4
+
+	/* This is called when the initial acquisition attempt of a spin
+	 * lock fails.  The calling convention is weird, return address
+	 * is in %o7 as usual but we agree with the caller to only touch
+	 * and use %g2 as a temporary.  We are passed a ptr to the lock
+	 * itself in %g1, %g4 must be restored into %o7 when we return,
+	 * and the caller wants us to return to him at three instructions
+	 * previous to the call instruction which got us here.  See how
+	 * this is used in asm-sparc/smp_lock.h if what I just said
+	 * confuses you to no end.
+	 */
+	.globl	___spinlock_waitfor
+___spinlock_waitfor:
+1:	orcc	%g2, 0x0, %g0
+	bne	1b
+	 ldub	[%g1], %g2
+	ldstub	[%g1], %g2
+	jmpl	%o7 - 12, %g0
+	 mov	%g4, %o7
+
+	/* This is called when the kernel master lock holder changes,
+	 * caller's PC is in %o7, %o7 must be restored to the value
+	 * in %g4 when returning.  The interrupt receiver cpu is to
+	 * change to the new kernel lock holder before returning.
+	 * The current implementation assumes that irq_rcvreg is a
+	 * pointer to a word sized register which can be written with
+	 * the MID value of the cpu to receive undirected interrupts.
+	 * CPUID is in %g5, and mid_xlate is a byte table which translates
+	 * CPUID values into the corresponding MID.
+	 */
+	.globl	___become_idt
+___become_idt:
+#ifdef __SMP__
+	sethi	%hi(C_LABEL(mid_xlate)), %g2
+	or	%g2, %lo(C_LABEL(mid_xlate)), %g2
+	ldub	[%g5 + %g2], %g7
+	sethi	%hi(C_LABEL(irq_rcvreg)), %g2
+	ld	[%g2 + %lo(C_LABEL(irq_rcvreg))], %g2
+	st	%g7, [%g2]
+#endif
+	jmpl	%o7 + 8, %g0
+	 mov	%g4, %o7
+
+___lk_busy_spin:
+	orcc	%g2, 0, %g0
+	bne	___lk_busy_spin
+	 ldub	[%g1 + 0], %g2
+	b	1f
+	 ldstub	[%g1 + 0], %g2	
+
+	.globl	___lock_kernel
+___lock_kernel:
+	addcc	%g2, -1, %g2
+	bcs,a	9f
+	 st	%g2, [%g6 + TASK_LOCK_DEPTH]
+	rd	%psr, %g3
+	or	%g3, PSR_PIL, %g2
+	wr	%g2, 0x0, %psr
+	nop; nop; nop
+	ldstub	[%g1 + 0], %g2
+1:	orcc	%g2, 0, %g0
+	bne,a	___lk_busy_spin
+	 ldub	[%g1 + 0], %g2
+	ldub	[%g1 + 2], %g2
+	cmp	%g2, %g5
+	be	2f
+	 stb	%g5, [%g1 + 1]
+	stb	%g5, [%g1 + 2]
+#ifdef __SMP__
+	set	C_LABEL(mid_xlate), %g2
+	ldub	[%g2 + %g5], %g7
+	sethi	%hi(C_LABEL(irq_rcvreg)), %g2
+	ld	[%g2 + %lo(C_LABEL(irq_rcvreg))], %g2
+	st	%g7, [%g2]
+#endif
+2:	mov	-1, %g2
+	st	%g2, [%g6 + TASK_LOCK_DEPTH]
+	wr	%g3, 0x0, %psr
+	nop; nop; nop
+9:	jmpl	%o7 + 0x8, %g0
+	 mov	%g4, %o7
+
+#undef NO_PROC_ID
+#define NO_PROC_ID	0xff
+
+	.globl	___unlock_kernel
+___unlock_kernel:
+	addcc	%g2, 1, %g2
+	bne,a	1f
+	 st	%g2, [%g6 + TASK_LOCK_DEPTH]
+	rd	%psr, %g3
+	or	%g3, PSR_PIL, %g2
+	wr	%g2, 0x0, %psr
+	nop; nop; nop
+	mov	NO_PROC_ID, %g2
+	stb	%g2, [%g1 + 1]
+	stb	%g0, [%g1 + 0]
+	st	%g0, [%g6 + TASK_LOCK_DEPTH]
+	wr	%g3, 0x0, %psr
+	nop; nop; nop;
+1:	jmpl	%o7 + 0x8, %g0
+	 mov	%g4, %o7
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/lib/memcpy.S linux/arch/sparc/lib/memcpy.S
--- v2.1.22/linux/arch/sparc/lib/memcpy.S	Wed Dec 18 15:58:46 1996
+++ linux/arch/sparc/lib/memcpy.S	Sun Jan 26 12:07:09 1997
@@ -1,188 +1,606 @@
-/* memcpy.S: Sparc optimized memcpy code.
- *
- *  Copyright(C) 1995 Linus Torvalds
- *  Copyright(C) 1996 David S. Miller
- *  Copyright(C) 1996 Eddie C. Dost
- *  Copyright(C) 1996 Jakub Jelinek
- *
- * derived from:
- *	e-mail between David and Eddie.
+/* memcpy.S: Sparc optimized memcpy, bcopy and memmove code
+ * Hand optimized from GNU libc's memcpy, bcopy and memmove
+ * Copyright (C) 1991,1996 Free Software Foundation
+ * Copyright (C) 1995 Linus Torvalds (Linus.Torvalds@helsinki.fi)
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
+ * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
+#ifdef __KERNEL__
+
 #include <asm/cprefix.h>
-#include <asm/ptrace.h>
+
+#define FUNC(x) 											\
+	.globl	C_LABEL(x);										\
+	.type	C_LABEL(x),@function;									\
+	.align	4;											\
+C_LABEL(x):
+
+#undef FASTER_REVERSE
+#undef FASTER_NONALIGNED
+#define FASTER_ALIGNED
+
+/* In kernel these functions don't return a value.
+ * One should use macros in asm/string.h for that purpose.
+ * We return 0, so that bugs are more apparent.
+ */
+#define SETUP_RETL
+#define RETL_INSN	clr	%o0
+
+#else
+
+/* libc */
+
+#include "DEFS.h"
+
+#define FASTER_REVERSE
+#define FASTER_NONALIGNED
+#define FASTER_ALIGNED
+
+#define SETUP_RETL	mov	%o0, %g6
+#define RETL_INSN	mov	%g6, %o0
+
+#endif
 
 /* Both these macros have to start with exactly the same insn */
-#define MOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \
-	ldd	[%src + offset + 0x00], %t0; \
-	ldd	[%src + offset + 0x08], %t2; \
-	ldd	[%src + offset + 0x10], %t4; \
-	ldd	[%src + offset + 0x18], %t6; \
-	st	%t0, [%dst + offset + 0x00]; \
-	st	%t1, [%dst + offset + 0x04]; \
-	st	%t2, [%dst + offset + 0x08]; \
-	st	%t3, [%dst + offset + 0x0c]; \
-	st	%t4, [%dst + offset + 0x10]; \
-	st	%t5, [%dst + offset + 0x14]; \
-	st	%t6, [%dst + offset + 0x18]; \
+#define MOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) 				\
+	ldd	[%src + offset + 0x00], %t0; 								\
+	ldd	[%src + offset + 0x08], %t2; 								\
+	ldd	[%src + offset + 0x10], %t4; 								\
+	ldd	[%src + offset + 0x18], %t6; 								\
+	st	%t0, [%dst + offset + 0x00]; 								\
+	st	%t1, [%dst + offset + 0x04]; 								\
+	st	%t2, [%dst + offset + 0x08]; 								\
+	st	%t3, [%dst + offset + 0x0c]; 								\
+	st	%t4, [%dst + offset + 0x10]; 								\
+	st	%t5, [%dst + offset + 0x14]; 								\
+	st	%t6, [%dst + offset + 0x18]; 								\
 	st	%t7, [%dst + offset + 0x1c];
 
-#define MOVE_BIGALIGNCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \
-	ldd	[%src + offset + 0x00], %t0; \
-	ldd	[%src + offset + 0x08], %t2; \
-	ldd	[%src + offset + 0x10], %t4; \
-	ldd	[%src + offset + 0x18], %t6; \
-	std	%t0, [%dst + offset + 0x00]; \
-	std	%t2, [%dst + offset + 0x08]; \
-	std	%t4, [%dst + offset + 0x10]; \
+#define MOVE_BIGALIGNCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) 				\
+	ldd	[%src + offset + 0x00], %t0; 								\
+	ldd	[%src + offset + 0x08], %t2; 								\
+	ldd	[%src + offset + 0x10], %t4; 								\
+	ldd	[%src + offset + 0x18], %t6; 								\
+	std	%t0, [%dst + offset + 0x00]; 								\
+	std	%t2, [%dst + offset + 0x08]; 								\
+	std	%t4, [%dst + offset + 0x10]; 								\
 	std	%t6, [%dst + offset + 0x18];
 
-#define MOVE_LASTCHUNK(src, dst, offset, t0, t1, t2, t3) \
-	ldd	[%src - offset - 0x10], %t0; \
-	ldd	[%src - offset - 0x08], %t2; \
-	st	%t0, [%dst - offset - 0x10]; \
-	st	%t1, [%dst - offset - 0x0c]; \
-	st	%t2, [%dst - offset - 0x08]; \
+#define MOVE_LASTCHUNK(src, dst, offset, t0, t1, t2, t3) 						\
+	ldd	[%src - offset - 0x10], %t0; 								\
+	ldd	[%src - offset - 0x08], %t2; 								\
+	st	%t0, [%dst - offset - 0x10]; 								\
+	st	%t1, [%dst - offset - 0x0c]; 								\
+	st	%t2, [%dst - offset - 0x08]; 								\
 	st	%t3, [%dst - offset - 0x04];
 
-#define MOVE_HALFCHUNK(src, dst, offset, t0, t1, t2, t3) \
-	lduh	[%src + offset + 0x00], %t0; \
-	lduh	[%src + offset + 0x02], %t1; \
-	lduh	[%src + offset + 0x04], %t2; \
-	lduh	[%src + offset + 0x06], %t3; \
-	sth	%t0, [%dst + offset + 0x00]; \
-	sth	%t1, [%dst + offset + 0x02]; \
-	sth	%t2, [%dst + offset + 0x04]; \
-	sth	%t3, [%dst + offset + 0x06];
-
-#define MOVE_SHORTCHUNK(src, dst, offset, t0, t1) \
-	ldub	[%src - offset - 0x02], %t0; \
-	ldub	[%src - offset - 0x01], %t1; \
-	stb	%t0, [%dst - offset - 0x02]; \
+#define MOVE_LASTALIGNCHUNK(src, dst, offset, t0, t1, t2, t3) 						\
+	ldd	[%src - offset - 0x10], %t0; 								\
+	ldd	[%src - offset - 0x08], %t2; 								\
+	std	%t0, [%dst - offset - 0x10]; 								\
+	std	%t2, [%dst - offset - 0x08];
+
+#define MOVE_SHORTCHUNK(src, dst, offset, t0, t1) 							\
+	ldub	[%src - offset - 0x02], %t0; 								\
+	ldub	[%src - offset - 0x01], %t1; 								\
+	stb	%t0, [%dst - offset - 0x02]; 								\
 	stb	%t1, [%dst - offset - 0x01];
 
+/* Both these macros have to start with exactly the same insn */
+#define RMOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) 				\
+	ldd	[%src - offset - 0x20], %t0; 								\
+	ldd	[%src - offset - 0x18], %t2; 								\
+	ldd	[%src - offset - 0x10], %t4; 								\
+	ldd	[%src - offset - 0x08], %t6; 								\
+	st	%t0, [%dst - offset - 0x20]; 								\
+	st	%t1, [%dst - offset - 0x1c]; 								\
+	st	%t2, [%dst - offset - 0x18]; 								\
+	st	%t3, [%dst - offset - 0x14]; 								\
+	st	%t4, [%dst - offset - 0x10]; 								\
+	st	%t5, [%dst - offset - 0x0c]; 								\
+	st	%t6, [%dst - offset - 0x08]; 								\
+	st	%t7, [%dst - offset - 0x04];
+
+#define RMOVE_BIGALIGNCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) 				\
+	ldd	[%src - offset - 0x20], %t0; 								\
+	ldd	[%src - offset - 0x18], %t2; 								\
+	ldd	[%src - offset - 0x10], %t4; 								\
+	ldd	[%src - offset - 0x08], %t6; 								\
+	std	%t0, [%dst - offset - 0x20]; 								\
+	std	%t2, [%dst - offset - 0x18]; 								\
+	std	%t4, [%dst - offset - 0x10]; 								\
+	std	%t6, [%dst - offset - 0x08];
+
+#define RMOVE_LASTCHUNK(src, dst, offset, t0, t1, t2, t3) 						\
+	ldd	[%src + offset + 0x00], %t0; 								\
+	ldd	[%src + offset + 0x08], %t2; 								\
+	st	%t0, [%dst + offset + 0x00]; 								\
+	st	%t1, [%dst + offset + 0x04]; 								\
+	st	%t2, [%dst + offset + 0x08]; 								\
+	st	%t3, [%dst + offset + 0x0c];
+
+#define RMOVE_SHORTCHUNK(src, dst, offset, t0, t1) 							\
+	ldub	[%src + offset + 0x00], %t0; 								\
+	ldub	[%src + offset + 0x01], %t1; 								\
+	stb	%t0, [%dst + offset + 0x00]; 								\
+	stb	%t1, [%dst + offset + 0x01];
+
+#define SMOVE_CHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, prev, shil, shir, offset2) 		\
+	ldd	[%src + offset + 0x00], %t0; 								\
+	ldd	[%src + offset + 0x08], %t2; 								\
+	srl	%t0, shir, %t5; 									\
+	srl	%t1, shir, %t6; 									\
+	sll	%t0, shil, %t0; 									\
+	or	%t5, %prev, %t5; 									\
+	sll	%t1, shil, %prev; 									\
+	or	%t6, %t0, %t0; 										\
+	srl	%t2, shir, %t1; 									\
+	srl	%t3, shir, %t6; 									\
+	sll	%t2, shil, %t2; 									\
+	or	%t1, %prev, %t1; 									\
+	std	%t4, [%dst + offset + offset2 - 0x04]; 							\
+	std	%t0, [%dst + offset + offset2 + 0x04];							\
+	sll	%t3, shil, %prev; 									\
+	or	%t6, %t2, %t4;
+
+#define SMOVE_ALIGNCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, prev, shil, shir, offset2) 	\
+	ldd	[%src + offset + 0x00], %t0; 								\
+	ldd	[%src + offset + 0x08], %t2; 								\
+	srl	%t0, shir, %t4; 									\
+	srl	%t1, shir, %t5; 									\
+	sll	%t0, shil, %t6; 									\
+	or	%t4, %prev, %t0; 									\
+	sll	%t1, shil, %prev; 									\
+	or	%t5, %t6, %t1; 										\
+	srl	%t2, shir, %t4; 									\
+	srl	%t3, shir, %t5; 									\
+	sll	%t2, shil, %t6; 									\
+	or	%t4, %prev, %t2; 									\
+	sll	%t3, shil, %prev; 									\
+	or	%t5, %t6, %t3;										\
+	std	%t0, [%dst + offset + offset2 + 0x00]; 							\
+	std	%t2, [%dst + offset + offset2 + 0x08];
+
 	.text
 	.align	4
 
-	.globl	C_LABEL(__memcpy), C_LABEL(memcpy), C_LABEL(bcopy)
-	.globl	C_LABEL(amemmove), C_LABEL(memmove)
-C_LABEL(bcopy):
-	mov	%o0, %o3
-	mov	%o1, %o0
-	mov	%o3, %o1
-C_LABEL(amemmove):
-C_LABEL(memmove):
-/* This should be kept as optimized as possible */
-	cmp	%o0, %o1
-	bleu	1f
-	 xor	%o0, %o1, %o4
-
-	add	%o1, %o2, %o3
-	cmp	%o3, %o0
-	bleu	2f
-	 andcc	%o4, 3, %g0
-
-/* But I think from now on, we can hold on. Or tell me, is memmoving
- * overlapping regions such a nice game? */
-
-	mov	%o0, %g1
-	add	%o1, %o2, %o1
-	add	%o0, %o2, %o0
-	sub	%o1, 1, %o1
-	sub	%o0, 1, %o0
+#ifdef FASTER_REVERSE
+
+70:	/* rdword_align */
+
+	andcc		%o1, 1, %g0
+	be		4f
+	 andcc		%o1, 2, %g0
+
+	ldub		[%o1 - 1], %g2
+	sub		%o1, 1, %o1
+	stb		%g2, [%o0 - 1]
+	sub		%o2, 1, %o2
+	be		3f
+	 sub		%o0, 1, %o0
+4:
+	lduh		[%o1 - 2], %g2
+	sub		%o1, 2, %o1
+	sth		%g2, [%o0 - 2]
+	sub		%o2, 2, %o2
+	b		3f
+	 sub		%o0, 2, %o0
+
+#endif /* FASTER_REVERSE */
+
+0:
+	retl
+	 nop		! Only bcopy returns here and it retuns void...
+
+FUNC(bcopy)
+	mov		%o0, %o3
+	mov		%o1, %o0
+	mov		%o3, %o1
+	tst		%o2
+	bcs		0b
+	 /* Do the cmp in the delay slot */
+#ifdef __KERNEL__
+FUNC(amemmove)
+FUNC(__memmove)
+#endif
+FUNC(memmove)
+	cmp		%o0, %o1
+	SETUP_RETL
+	bleu		9f
+	 sub		%o0, %o1, %o4
+
+	add		%o1, %o2, %o3
+	cmp		%o3, %o0
+	bleu		0f
+	 andcc		%o4, 3, %o5
+
+#ifndef FASTER_REVERSE
+
+	add		%o1, %o2, %o1
+	add		%o0, %o2, %o0
+	sub		%o1, 1, %o1
+	sub		%o0, 1, %o0
 	
-reverse_bytes:
-	ldub	[%o1], %o4
-	subcc	%o2, 1, %o2
-	stb	%o4, [%o0]
-	sub	%o1, 1, %o1
-	bne	reverse_bytes
-	 sub	%o0, 1, %o0
+1:	/* reverse_bytes */
+
+	ldub		[%o1], %o4
+	subcc		%o2, 1, %o2
+	stb		%o4, [%o0]
+	sub		%o1, 1, %o1
+	bne		1b
+	 sub		%o0, 1, %o0
+
+	retl
+	 RETL_INSN
+
+#else /* FASTER_REVERSE */
+
+	add		%o1, %o2, %o1
+	add		%o0, %o2, %o0
+	bne		77f
+	 cmp		%o2, 15
+	bleu		91f
+	 andcc		%o1, 3, %g0
+	bne		70b
+3:
+	 andcc		%o1, 4, %g0
+
+	be		2f
+	 mov		%o2, %g1
+
+	ld		[%o1 - 4], %o4
+	sub		%g1, 4, %g1
+	st		%o4, [%o0 - 4]
+	sub		%o1, 4, %o1
+	sub		%o0, 4, %o0
+2:
+	andcc		%g1, 0xffffff80, %g7
+	be		3f
+	 andcc		%o0, 4, %g0
+
+	be		74f + 4
+5:
+	RMOVE_BIGCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5)
+	RMOVE_BIGCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5)
+	RMOVE_BIGCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5)
+	RMOVE_BIGCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5)
+	subcc		%g7, 128, %g7
+	sub		%o1, 128, %o1
+	bne		5b
+	 sub		%o0, 128, %o0
+3:
+	andcc		%g1, 0x70, %g7
+	be		72f
+	 andcc		%g1, 8, %g0
+
+	sethi		%hi(72f), %o5
+	srl		%g7, 1, %o4
+	add		%g7, %o4, %o4
+	sub		%o1, %g7, %o1
+	sub		%o5, %o4, %o5
+	jmpl		%o5 + %lo(72f), %g0
+	 sub		%o0, %g7, %o0
+
+71:	/* rmemcpy_table */
+	RMOVE_LASTCHUNK(o1, o0, 0x60, g2, g3, g4, g5)
+	RMOVE_LASTCHUNK(o1, o0, 0x50, g2, g3, g4, g5)
+	RMOVE_LASTCHUNK(o1, o0, 0x40, g2, g3, g4, g5)
+	RMOVE_LASTCHUNK(o1, o0, 0x30, g2, g3, g4, g5)
+	RMOVE_LASTCHUNK(o1, o0, 0x20, g2, g3, g4, g5)
+	RMOVE_LASTCHUNK(o1, o0, 0x10, g2, g3, g4, g5)
+	RMOVE_LASTCHUNK(o1, o0, 0x00, g2, g3, g4, g5)
+
+72:	/* rmemcpy_table_end */
+
+	be		73f
+	 andcc		%g1, 4, %g0
+
+	ldd		[%o1 - 0x08], %g2
+	sub		%o0, 8, %o0
+	sub		%o1, 8, %o1
+	st		%g2, [%o0]
+	st		%g3, [%o0 + 0x04]
+
+73:	/* rmemcpy_last7 */
+
+	be		1f
+	 andcc		%g1, 2, %g0
+
+	ld		[%o1 - 4], %g2
+	sub		%o1, 4, %o1
+	st		%g2, [%o0 - 4]
+	sub		%o0, 4, %o0
+1:
+	be		1f
+	 andcc		%g1, 1, %g0
+
+	lduh		[%o1 - 2], %g2
+	sub		%o1, 2, %o1
+	sth		%g2, [%o0 - 2]
+	sub		%o0, 2, %o0
+1:
+	be		1f
+	 nop
 
+	ldub		[%o1 - 1], %g2
+	stb		%g2, [%o0 - 1]
+1:
 	retl
-	 mov	%g1, %o0
+ 	 RETL_INSN
+
+74:	/* rldd_std */
+	RMOVE_BIGALIGNCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5)
+	RMOVE_BIGALIGNCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5)
+	RMOVE_BIGALIGNCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5)
+	RMOVE_BIGALIGNCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5)
+	subcc		%g7, 128, %g7
+	sub		%o1, 128, %o1
+	bne		74b
+	 sub		%o0, 128, %o0
+
+	andcc		%g1, 0x70, %g7
+	be		72b
+	 andcc		%g1, 8, %g0
+
+	sethi		%hi(72b), %o5
+	srl		%g7, 1, %o4
+	add		%g7, %o4, %o4
+	sub		%o1, %g7, %o1
+	sub		%o5, %o4, %o5
+	jmpl		%o5 + %lo(72b), %g0
+	 sub		%o0, %g7, %o0
+
+75:	/* rshort_end */
+
+	and		%o2, 0xe, %o3
+2:
+	sethi		%hi(76f), %o5
+	sll		%o3, 3, %o4
+	sub		%o0, %o3, %o0
+	sub		%o5, %o4, %o5
+	sub		%o1, %o3, %o1
+	jmpl		%o5 + %lo(76f), %g0
+	 andcc		%o2, 1, %g0
+
+	RMOVE_SHORTCHUNK(o1, o0, 0x0c, g2, g3)
+	RMOVE_SHORTCHUNK(o1, o0, 0x0a, g2, g3)
+	RMOVE_SHORTCHUNK(o1, o0, 0x08, g2, g3)
+	RMOVE_SHORTCHUNK(o1, o0, 0x06, g2, g3)
+	RMOVE_SHORTCHUNK(o1, o0, 0x04, g2, g3)
+	RMOVE_SHORTCHUNK(o1, o0, 0x02, g2, g3)
+	RMOVE_SHORTCHUNK(o1, o0, 0x00, g2, g3)
+
+76:	/* rshort_table_end */
+
+	be		1f
+	 nop
+	ldub		[%o1 - 1], %g2
+	stb		%g2, [%o0 - 1]
+1:
+	retl
+ 	 RETL_INSN
+
+91:	/* rshort_aligned_end */
 
-/* And here start optimizing again... */
+	bne		75b
+	 andcc		%o2, 8, %g0
 
-dword_align:
-	andcc	%o1, 1, %g0
-	be	4f
-	 andcc	%o1, 2, %g0
-
-	ldub	[%o1], %g2
-	add	%o1, 1, %o1
-	stb	%g2, [%o0]
-	sub	%o2, 1, %o2
-	bne	3f
-	 add	%o0, 1, %o0
-
-	lduh	[%o1], %g2
-	add	%o1, 2, %o1
-	sth	%g2, [%o0]
-	sub	%o2, 2, %o2
-	b	3f
-	 add	%o0, 2, %o0
-4:
-	lduh	[%o1], %g2
-	add	%o1, 2, %o1
-	sth	%g2, [%o0]
-	sub	%o2, 2, %o2
-	b	3f
-	 add	%o0, 2, %o0
-
-C_LABEL(__memcpy):
-C_LABEL(memcpy):	/* %o0=dst %o1=src %o2=len */
-	xor	%o0, %o1, %o4
+	be		1f
+	 andcc		%o2, 4, %g0
+
+	ld		[%o1 - 0x08], %g2
+	ld		[%o1 - 0x04], %g3
+	sub		%o1, 8, %o1
+	st		%g2, [%o0 - 0x08]
+	st		%g3, [%o0 - 0x04]
+	sub		%o0, 8, %o0
 1:
-	andcc	%o4, 3, %o5
+	b		73b
+	 mov		%o2, %g1
+
+77:	/* rnon_aligned */
+	cmp		%o2, 15
+	bleu		75b
+	 andcc		%o0, 3, %g0
+	be		64f
+	 andcc		%o0, 1, %g0
+	be		63f
+	 andcc		%o0, 2, %g0
+	ldub		[%o1 - 1], %g5
+	sub		%o1, 1, %o1
+	stb		%g5, [%o0 - 1]
+	sub		%o0, 1, %o0
+	be		64f
+	 sub		%o2, 1, %o2
+63:
+	ldub		[%o1 - 1], %g5
+	sub		%o1, 2, %o1
+	stb		%g5, [%o0 - 1]
+	sub		%o0, 2, %o0
+	ldub		[%o1], %g5
+	sub		%o2, 2, %o2
+	stb		%g5, [%o0]
+64:	
+	and		%o1, 3, %g2
+	and		%o1, -4, %o1
+	and		%o2, 0xc, %g3
+	add		%o1, 4, %o1
+	cmp		%g3, 4
+	sll		%g2, 3, %g4
+	mov		32, %g2
+	be		4f
+	 sub		%g2, %g4, %g7
+
+	blu		3f
+	 cmp		%g3, 8
+
+	be		2f
+	 srl		%o2, 2, %g3
+
+	ld		[%o1 - 4], %o3
+	add		%o0, -8, %o0
+	ld		[%o1 - 8], %o4
+	add		%o1, -16, %o1
+	b		7f
+	 add		%g3, 1, %g3
 2:
-	bne	cannot_optimize
-	 cmp	%o2, 15
+	ld		[%o1 - 4], %o4
+	add		%o0, -4, %o0
+	ld		[%o1 - 8], %g1
+	add		%o1, -12, %o1
+	b		8f
+	 add		%g3, 2, %g3
+3:
+	ld		[%o1 - 4], %o5
+	add		%o0, -12, %o0
+	ld		[%o1 - 8], %o3
+	add		%o1, -20, %o1
+	b		6f
+	 srl		%o2, 2, %g3
+4:
+	ld		[%o1 - 4], %g1
+	srl		%o2, 2, %g3
+	ld		[%o1 - 8], %o5
+	add		%o1, -24, %o1
+	add		%o0, -16, %o0
+	add		%g3, -1, %g3
 
-	bleu	short_aligned_end
-	 andcc	%o1, 3, %g0
+	ld		[%o1 + 12], %o3
+5:
+	sll		%o5, %g4, %g2
+	srl		%g1, %g7, %g5
+	or		%g2, %g5, %g2
+	st		%g2, [%o0 + 12]
+6:
+	ld		[%o1 + 8], %o4
+	sll		%o3, %g4, %g2
+	srl		%o5, %g7, %g5
+	or		%g2, %g5, %g2
+	st		%g2, [%o0 + 8]
+7:
+	ld		[%o1 + 4], %g1
+	sll		%o4, %g4, %g2
+	srl		%o3, %g7, %g5
+	or		%g2, %g5, %g2
+	st		%g2, [%o0 + 4]
+8:
+	ld		[%o1], %o5
+	sll		%g1, %g4, %g2
+	srl		%o4, %g7, %g5
+	addcc		%g3, -4, %g3
+	or		%g2, %g5, %g2
+	add		%o1, -16, %o1
+	st		%g2, [%o0]
+	add		%o0, -16, %o0
+	bne,a		5b	
+	 ld		[%o1 + 12], %o3
+	sll		%o5, %g4, %g2
+	srl		%g1, %g7, %g5
+	srl		%g4, 3, %g3
+	or		%g2, %g5, %g2
+	add		%o1, %g3, %o1
+	andcc		%o2, 2, %g0
+	st		%g2, [%o0 + 12]
+	be		1f
+	 andcc		%o2, 1, %g0
+	
+	ldub		[%o1 + 15], %g5
+	add		%o1, -2, %o1
+	stb		%g5, [%o0 + 11]
+	add		%o0, -2, %o0
+	ldub		[%o1 + 16], %g5
+	stb		%g5, [%o0 + 12]
+1:
+	be		1f
+	 nop
+	ldub		[%o1 + 15], %g5
+	stb		%g5, [%o0 + 11]
+1:
+	retl
+	 RETL_INSN
+
+#endif /* FASTER_REVERSE */
 
-	bne	dword_align
+78:	/* dword_align */
+
+	andcc		%o1, 1, %g0
+	be		4f
+	 andcc		%o1, 2, %g0
+
+	ldub		[%o1], %g2
+	add		%o1, 1, %o1
+	stb		%g2, [%o0]
+	sub		%o2, 1, %o2
+	bne		3f
+	 add		%o0, 1, %o0
+4:
+	lduh		[%o1], %g2
+	add		%o1, 2, %o1
+	sth		%g2, [%o0]
+	sub		%o2, 2, %o2
+	b		3f
+	 add		%o0, 2, %o0
+
+#ifdef __KERNEL__
+FUNC(__memcpy)
+#endif
+FUNC(memcpy)	/* %o0=dst %o1=src %o2=len */
+
+	sub		%o0, %o1, %o4
+	SETUP_RETL
+9:
+	andcc		%o4, 3, %o5
+0:
+	bne		86f
+	 cmp		%o2, 15
+
+	bleu		90f
+	 andcc		%o1, 3, %g0
+
+	bne		78b
 3:
-	 andcc	%o1, 4, %g0
+	 andcc		%o1, 4, %g0
 
-	be	2f
-	 mov	%o2, %g1
+	be		2f
+	 mov		%o2, %g1
 
-	ld	[%o1], %o4
-	sub	%g1, 4, %g1
-	st	%o4, [%o0]
-	add	%o1, 4, %o1
-	add	%o0, 4, %o0
+	ld		[%o1], %o4
+	sub		%g1, 4, %g1
+	st		%o4, [%o0]
+	add		%o1, 4, %o1
+	add		%o0, 4, %o0
 2:
-	andcc	%g1, 0xffffff80, %g7
-	be	3f
-	 andcc	%o0, 4, %g0
+	andcc		%g1, 0xffffff80, %g7
+	be		3f
+	 andcc		%o0, 4, %g0
 
-	be	ldd_std + 4
+	be		82f + 4
 5:
 	MOVE_BIGCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5)
 	MOVE_BIGCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5)
 	MOVE_BIGCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5)
 	MOVE_BIGCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5)
-	subcc	%g7, 128, %g7
-	add	%o1, 128, %o1
-	bne	5b
-	 add	%o0, 128, %o0
+	subcc		%g7, 128, %g7
+	add		%o1, 128, %o1
+	bne		5b
+	 add		%o0, 128, %o0
 3:
-	andcc	%g1, 0x70, %g7
-	be	memcpy_table_end
-	 andcc	%g1, 8, %g0
-
-	sethi	%hi(memcpy_table_end), %o5
-	srl	%g7, 1, %o4
-	add	%g7, %o4, %o4
-	add	%o1, %g7, %o1
-	sub	%o5, %o4, %o5
-	jmpl	%o5 + %lo(memcpy_table_end), %g0
-	 add	%o0, %g7, %o0
+	andcc		%g1, 0x70, %g7
+	be		80f
+	 andcc		%g1, 8, %g0
+
+	sethi		%hi(80f), %o5
+	srl		%g7, 1, %o4
+	add		%g7, %o4, %o4
+	add		%o1, %g7, %o1
+	sub		%o5, %o4, %o5
+	jmpl		%o5 + %lo(80f), %g0
+	 add		%o0, %g7, %o0
+
+79:	/* memcpy_table */
 
-memcpy_table:
 	MOVE_LASTCHUNK(o1, o0, 0x60, g2, g3, g4, g5)
 	MOVE_LASTCHUNK(o1, o0, 0x50, g2, g3, g4, g5)
 	MOVE_LASTCHUNK(o1, o0, 0x40, g2, g3, g4, g5)
@@ -191,115 +609,509 @@
 	MOVE_LASTCHUNK(o1, o0, 0x10, g2, g3, g4, g5)
 	MOVE_LASTCHUNK(o1, o0, 0x00, g2, g3, g4, g5)
 
-memcpy_table_end:
-	be	memcpy_last7
-	 andcc	%g1, 4, %g0
-
-	ldd	[%o1], %g2
-	add	%o0, 8, %o0
-	add	%o1, 8, %o1
-	st	%g2, [%o0 - 0x08]
-	st	%g3, [%o0 - 0x04]
-memcpy_last7:
-	be	1f
-	 andcc	%g1, 2, %g0
-
-	ld	[%o1], %g2
-	add	%o1, 4, %o1
-	st	%g2, [%o0]
-	add	%o0, 4, %o0
-1:
-	be	1f
-	 andcc	%g1, 1, %g0
-
-	lduh	[%o1], %g2
-	add	%o1, 2, %o1
-	sth	%g2, [%o0]
-	add	%o0, 2, %o0
+80:	/* memcpy_table_end */
+	be		81f
+	 andcc		%g1, 4, %g0
+
+	ldd		[%o1], %g2
+	add		%o0, 8, %o0
+	st		%g2, [%o0 - 0x08]
+	add		%o1, 8, %o1
+	st		%g3, [%o0 - 0x04]
+
+81:	/* memcpy_last7 */
+
+	be		1f
+	 andcc		%g1, 2, %g0
+
+	ld		[%o1], %g2
+	add		%o1, 4, %o1
+	st		%g2, [%o0]
+	add		%o0, 4, %o0
 1:
-	be	1f
+	be		1f
+	 andcc		%g1, 1, %g0
+
+	lduh		[%o1], %g2
+	add		%o1, 2, %o1
+	sth		%g2, [%o0]
+	add		%o0, 2, %o0
+1:
+	be		1f
 	 nop
 
-	ldub	[%o1], %g2
-	stb	%g2, [%o0]
+	ldub		[%o1], %g2
+	stb		%g2, [%o0]
 1:
 	retl
- 	 nop
+ 	 RETL_INSN
 
-ldd_std:
+82:	/* ldd_std */
 	MOVE_BIGALIGNCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5)
 	MOVE_BIGALIGNCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5)
 	MOVE_BIGALIGNCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5)
 	MOVE_BIGALIGNCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5)
-	subcc	%g7, 128, %g7
-	add	%o1, 128, %o1
-	bne	ldd_std
-	 add	%o0, 128, %o0
-
-	andcc	%g1, 0x70, %g7
-	be	memcpy_table_end
-	 andcc	%g1, 8, %g0
-
-	sethi	%hi(memcpy_table_end), %o5
-	srl	%g7, 1, %o4
-	add	%g7, %o4, %o4
-	add	%o1, %g7, %o1
-	sub	%o5, %o4, %o5
-	jmpl	%o5 + %lo(memcpy_table_end), %g0
-	 add	%o0, %g7, %o0
-
-cannot_optimize:
-	bleu	short_end
-	 cmp	%o5, 2
+	subcc		%g7, 128, %g7
+	add		%o1, 128, %o1
+	bne		82b
+	 add		%o0, 128, %o0
+
+#ifndef FASTER_ALIGNED
+
+	andcc		%g1, 0x70, %g7
+	be		80b
+	 andcc		%g1, 8, %g0
+
+	sethi		%hi(80b), %o5
+	srl		%g7, 1, %o4
+	add		%g7, %o4, %o4
+	add		%o1, %g7, %o1
+	sub		%o5, %o4, %o5
+	jmpl		%o5 + %lo(80b), %g0
+	 add		%o0, %g7, %o0
+
+#else /* FASTER_ALIGNED */
+
+	andcc		%g1, 0x70, %g7
+	be		84f
+	 andcc		%g1, 8, %g0
+
+	sethi		%hi(84f), %o5
+	add		%o1, %g7, %o1
+	sub		%o5, %g7, %o5
+	jmpl		%o5 + %lo(84f), %g0
+	 add		%o0, %g7, %o0
+
+83:	/* amemcpy_table */
+
+	MOVE_LASTALIGNCHUNK(o1, o0, 0x60, g2, g3, g4, g5)
+	MOVE_LASTALIGNCHUNK(o1, o0, 0x50, g2, g3, g4, g5)
+	MOVE_LASTALIGNCHUNK(o1, o0, 0x40, g2, g3, g4, g5)
+	MOVE_LASTALIGNCHUNK(o1, o0, 0x30, g2, g3, g4, g5)
+	MOVE_LASTALIGNCHUNK(o1, o0, 0x20, g2, g3, g4, g5)
+	MOVE_LASTALIGNCHUNK(o1, o0, 0x10, g2, g3, g4, g5)
+	MOVE_LASTALIGNCHUNK(o1, o0, 0x00, g2, g3, g4, g5)
+
+84:	/* amemcpy_table_end */
+	be		85f
+	 andcc		%g1, 4, %g0
+
+	ldd		[%o1], %g2
+	add		%o0, 8, %o0
+	std		%g2, [%o0 - 0x08]
+	add		%o1, 8, %o1
+85:	/* amemcpy_last7 */
+	be		1f
+	 andcc		%g1, 2, %g0
+
+	ld		[%o1], %g2
+	add		%o1, 4, %o1
+	st		%g2, [%o0]
+	add		%o0, 4, %o0
+1:
+	be		1f
+	 andcc		%g1, 1, %g0
 
-	bne	byte_chunk
-	 and	%o2, 0xfffffff0, %o3
-	 
-	andcc	%o1, 1, %g0
-	be	1f
+	lduh		[%o1], %g2
+	add		%o1, 2, %o1
+	sth		%g2, [%o0]
+	add		%o0, 2, %o0
+1:
+	be		1f
 	 nop
 
-	ldub	[%o1], %g2
-	add	%o1, 1, %o1
-	sub	%o2, 1, %o2
-	stb	%g2, [%o0]
-	andcc	%o2, 0xfffffff0, %o3
-	be	short_end
-	 add	%o0, 1, %o0
-1:
-	MOVE_HALFCHUNK(o1, o0, 0x00, g2, g3, g4, g5)
-	MOVE_HALFCHUNK(o1, o0, 0x08, g2, g3, g4, g5)
-	subcc	%o3, 0x10, %o3
-	add	%o1, 0x10, %o1
-	bne	1b
-	 add	%o0, 0x10, %o0
-	b	2f
-	 and	%o2, 0xe, %o3
+	ldub		[%o1], %g2
+	stb		%g2, [%o0]
+1:
+	retl
+ 	 RETL_INSN
+
+#endif /* FASTER_ALIGNED */
+
+86:	/* non_aligned */
+	cmp		%o2, 6
+	bleu		88f
+
+#ifdef FASTER_NONALIGNED
+
+	 cmp		%o2, 256
+	bcc		87f
+
+#endif /* FASTER_NONALIGNED */
+
+	 andcc		%o0, 3, %g0
+	be		61f
+	 andcc		%o0, 1, %g0
+	be		60f
+	 andcc		%o0, 2, %g0
+
+	ldub		[%o1], %g5
+	add		%o1, 1, %o1
+	stb		%g5, [%o0]
+	sub		%o2, 1, %o2
+	bne		61f
+	 add		%o0, 1, %o0
+60:
+	ldub		[%o1], %g3
+	add		%o1, 2, %o1
+	stb		%g3, [%o0]
+	sub		%o2, 2, %o2
+	ldub		[%o1 - 1], %g3
+	add		%o0, 2, %o0
+	stb		%g3, [%o0 - 1]
+61:
+	and		%o1, 3, %g2
+	and		%o2, 0xc, %g3
+	and		%o1, -4, %o1
+	cmp		%g3, 4
+	sll		%g2, 3, %g4
+	mov		32, %g2
+	be		4f
+	 sub		%g2, %g4, %g7
 	
-byte_chunk:
-	MOVE_SHORTCHUNK(o1, o0, -0x02, g2, g3)
-	MOVE_SHORTCHUNK(o1, o0, -0x04, g2, g3)
-	MOVE_SHORTCHUNK(o1, o0, -0x06, g2, g3)
-	MOVE_SHORTCHUNK(o1, o0, -0x08, g2, g3)
-	MOVE_SHORTCHUNK(o1, o0, -0x0a, g2, g3)
-	MOVE_SHORTCHUNK(o1, o0, -0x0c, g2, g3)
-	MOVE_SHORTCHUNK(o1, o0, -0x0e, g2, g3)
-	MOVE_SHORTCHUNK(o1, o0, -0x10, g2, g3)
-	subcc	%o3, 0x10, %o3
-	add	%o1, 0x10, %o1
-	bne	byte_chunk
-	 add	%o0, 0x10, %o0
+	blu		3f
+	 cmp		%g3, 0x8
+
+	be		2f
+	 srl		%o2, 2, %g3
+
+	ld		[%o1], %o3
+	add		%o0, -8, %o0
+	ld		[%o1 + 4], %o4
+	b		8f
+	 add		%g3, 1, %g3
+2:
+	ld		[%o1], %o4
+	add		%o0, -12, %o0
+	ld		[%o1 + 4], %o5
+	add		%g3, 2, %g3
+	b		9f
+	 add		%o1, -4, %o1
+3:
+	ld		[%o1], %g1
+	add		%o0, -4, %o0
+	ld		[%o1 + 4], %o3
+	srl		%o2, 2, %g3
+	b		7f
+	 add		%o1, 4, %o1
+4:
+	ld		[%o1], %o5
+	cmp		%o2, 7
+	ld		[%o1 + 4], %g1
+	srl		%o2, 2, %g3
+	bleu		10f
+	 add		%o1, 8, %o1
+
+	ld		[%o1], %o3
+	add		%g3, -1, %g3
+5:
+	sll		%o5, %g4, %g2
+	srl		%g1, %g7, %g5
+	or		%g2, %g5, %g2
+	st		%g2, [%o0]
+7:
+	ld		[%o1 + 4], %o4
+	sll		%g1, %g4, %g2
+	srl		%o3, %g7, %g5
+	or		%g2, %g5, %g2
+	st		%g2, [%o0 + 4]
+8:
+	ld		[%o1 + 8], %o5
+	sll		%o3, %g4, %g2
+	srl		%o4, %g7, %g5
+	or		%g2, %g5, %g2
+	st		%g2, [%o0 + 8]
+9:
+	ld		[%o1 + 12], %g1
+	sll		%o4, %g4, %g2
+	srl		%o5, %g7, %g5
+	addcc		%g3, -4, %g3
+	or		%g2, %g5, %g2
+	add		%o1, 16, %o1
+	st		%g2, [%o0 + 12]
+	add		%o0, 16, %o0
+	bne,a		5b
+	 ld		[%o1], %o3
+10:
+	sll		%o5, %g4, %g2
+	srl		%g1, %g7, %g5
+	srl		%g7, 3, %g3
+	or		%g2, %g5, %g2
+	sub		%o1, %g3, %o1
+	andcc		%o2, 2, %g0
+	st		%g2, [%o0]
+	be		1f
+	 andcc		%o2, 1, %g0
+
+	ldub		[%o1], %g2
+	add		%o1, 2, %o1
+	stb		%g2, [%o0 + 4]
+	add		%o0, 2, %o0
+	ldub		[%o1 - 1], %g2
+	stb		%g2, [%o0 + 3]
+1:
+	be		1f
+	 nop
+	ldub		[%o1], %g2
+	stb		%g2, [%o0 + 4]
+1:
+	retl
+	 RETL_INSN
+
+#ifdef FASTER_NONALIGNED
+
+87:	/* faster_nonaligned */
+
+	andcc		%o1, 3, %g0
+	be		3f
+	 andcc		%o1, 1, %g0
 
-short_end:
-	and	%o2, 0xe, %o3
+	be		4f
+	 andcc		%o1, 2, %g0
+
+	ldub		[%o1], %g2
+	add		%o1, 1, %o1
+	stb		%g2, [%o0]
+	sub		%o2, 1, %o2
+	bne		3f
+	 add		%o0, 1, %o0
+4:
+	lduh		[%o1], %g2
+	add		%o1, 2, %o1
+	srl		%g2, 8, %g3
+	sub		%o2, 2, %o2
+	stb		%g3, [%o0]
+	add		%o0, 2, %o0
+	stb		%g2, [%o0 - 1]
+3:
+	 andcc		%o1, 4, %g0
+
+	bne		2f
+	 cmp		%o5, 1
+
+	ld		[%o1], %o4
+	srl		%o4, 24, %g2
+	stb		%g2, [%o0]
+	srl		%o4, 16, %g3
+	stb		%g3, [%o0 + 1]
+	srl		%o4, 8, %g2
+	stb		%g2, [%o0 + 2]
+	sub		%o2, 4, %o2
+	stb		%o4, [%o0 + 3]
+	add		%o1, 4, %o1
+	add		%o0, 4, %o0
 2:
-	sethi	%hi(short_table_end), %o5
-	sll	%o3, 3, %o4
-	add	%o0, %o3, %o0
-	sub	%o5, %o4, %o5
-	add	%o1, %o3, %o1
-	jmpl	%o5 + %lo(short_table_end), %g0
-	 andcc	%o2, 1, %g0
+	be		33f
+	 cmp		%o5, 2
+	be		32f
+	 sub		%o2, 4, %o2
+31:
+	ld		[%o1], %g2
+	add		%o1, 4, %o1
+	srl		%g2, 24, %g3
+	and		%o0, 7, %g5
+	stb		%g3, [%o0]
+	cmp		%g5, 7
+	sll		%g2, 8, %g1
+	add		%o0, 4, %o0
+	be		41f
+	 and		%o2, 0xffffffc0, %o3
+	ld		[%o0 - 7], %o4
+4:
+	SMOVE_CHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3)
+	SMOVE_CHUNK(o1, o0, 0x10, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3)
+	SMOVE_CHUNK(o1, o0, 0x20, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3)
+	SMOVE_CHUNK(o1, o0, 0x30, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3)
+	subcc		%o3, 64, %o3
+	add		%o1, 64, %o1
+	bne		4b
+	 add		%o0, 64, %o0
+
+	andcc		%o2, 0x30, %o3
+	be,a		1f
+	 srl		%g1, 16, %g2
+4:
+	SMOVE_CHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3)
+	subcc		%o3, 16, %o3
+	add		%o1, 16, %o1
+	bne		4b
+	 add		%o0, 16, %o0
+
+	srl		%g1, 16, %g2
+1:
+	st		%o4, [%o0 - 7]
+	sth		%g2, [%o0 - 3]
+	srl		%g1, 8, %g4
+	b		88f
+	 stb		%g4, [%o0 - 1]
+32:
+	ld		[%o1], %g2
+	add		%o1, 4, %o1
+	srl		%g2, 16, %g3
+	and		%o0, 7, %g5
+	sth		%g3, [%o0]
+	cmp		%g5, 6
+	sll		%g2, 16, %g1
+	add		%o0, 4, %o0
+	be		42f
+	 and		%o2, 0xffffffc0, %o3
+	ld		[%o0 - 6], %o4
+4:
+	SMOVE_CHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2)
+	SMOVE_CHUNK(o1, o0, 0x10, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2)
+	SMOVE_CHUNK(o1, o0, 0x20, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2)
+	SMOVE_CHUNK(o1, o0, 0x30, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2)
+	subcc		%o3, 64, %o3
+	add		%o1, 64, %o1
+	bne		4b
+	 add		%o0, 64, %o0
+
+	andcc		%o2, 0x30, %o3
+	be,a		1f
+	 srl		%g1, 16, %g2
+4:
+	SMOVE_CHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2)
+	subcc		%o3, 16, %o3
+	add		%o1, 16, %o1
+	bne		4b
+	 add		%o0, 16, %o0
+
+	srl		%g1, 16, %g2
+1:
+	st		%o4, [%o0 - 6]
+	b		88f
+	 sth		%g2, [%o0 - 2]
+33:
+	ld		[%o1], %g2
+	sub		%o2, 4, %o2
+	srl		%g2, 24, %g3
+	and		%o0, 7, %g5
+	stb		%g3, [%o0]
+	cmp		%g5, 5
+	srl		%g2, 8, %g4
+	sll		%g2, 24, %g1
+	sth		%g4, [%o0 + 1]
+	add		%o1, 4, %o1
+	be		43f
+	 and		%o2, 0xffffffc0, %o3
+
+	ld		[%o0 - 1], %o4
+	add		%o0, 4, %o0
+4:
+	SMOVE_CHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, -1)
+	SMOVE_CHUNK(o1, o0, 0x10, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, -1)
+	SMOVE_CHUNK(o1, o0, 0x20, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, -1)
+	SMOVE_CHUNK(o1, o0, 0x30, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, -1)
+	subcc		%o3, 64, %o3
+	add		%o1, 64, %o1
+	bne		4b
+	 add		%o0, 64, %o0
+
+	andcc		%o2, 0x30, %o3
+	be,a		1f
+	 srl		%g1, 24, %g2
+4:
+	SMOVE_CHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, -1)
+	subcc		%o3, 16, %o3
+	add		%o1, 16, %o1
+	bne		4b
+	 add		%o0, 16, %o0
+
+	srl		%g1, 24, %g2
+1:
+	st		%o4, [%o0 - 5]
+	b		88f
+	 stb		%g2, [%o0 - 1]
+41:
+	SMOVE_ALIGNCHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3)
+	SMOVE_ALIGNCHUNK(o1, o0, 0x10, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3)
+	SMOVE_ALIGNCHUNK(o1, o0, 0x20, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3)
+	SMOVE_ALIGNCHUNK(o1, o0, 0x30, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3)
+	subcc		%o3, 64, %o3
+	add		%o1, 64, %o1
+	bne		41b
+	 add		%o0, 64, %o0
+	 
+	andcc		%o2, 0x30, %o3
+	be,a		1f
+	 srl		%g1, 16, %g2
+4:
+	SMOVE_ALIGNCHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3)
+	subcc		%o3, 16, %o3
+	add		%o1, 16, %o1
+	bne		4b
+	 add		%o0, 16, %o0
+
+	srl		%g1, 16, %g2
+1:
+	sth		%g2, [%o0 - 3]
+	srl		%g1, 8, %g4
+	b		88f
+	 stb		%g4, [%o0 - 1]
+43:
+	SMOVE_ALIGNCHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, 3)
+	SMOVE_ALIGNCHUNK(o1, o0, 0x10, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, 3)
+	SMOVE_ALIGNCHUNK(o1, o0, 0x20, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, 3)
+	SMOVE_ALIGNCHUNK(o1, o0, 0x30, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, 3)
+	subcc		%o3, 64, %o3
+	add		%o1, 64, %o1
+	bne		43b
+	 add		%o0, 64, %o0
+
+	andcc		%o2, 0x30, %o3
+	be,a		1f
+	 srl		%g1, 24, %g2
+4:
+	SMOVE_ALIGNCHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, 3)
+	subcc		%o3, 16, %o3
+	add		%o1, 16, %o1
+	bne		4b
+	 add		%o0, 16, %o0
+
+	srl		%g1, 24, %g2
+1:
+	stb		%g2, [%o0 + 3]
+	b		88f
+	 add		%o0, 4, %o0
+42:
+	SMOVE_ALIGNCHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2)
+	SMOVE_ALIGNCHUNK(o1, o0, 0x10, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2)
+	SMOVE_ALIGNCHUNK(o1, o0, 0x20, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2)
+	SMOVE_ALIGNCHUNK(o1, o0, 0x30, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2)
+	subcc		%o3, 64, %o3
+	add		%o1, 64, %o1
+	bne		42b
+	 add		%o0, 64, %o0
+	 
+	andcc		%o2, 0x30, %o3
+	be,a		1f
+	 srl		%g1, 16, %g2
+4:
+	SMOVE_ALIGNCHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2)
+	subcc		%o3, 16, %o3
+	add		%o1, 16, %o1
+	bne		4b
+	 add		%o0, 16, %o0
+
+	srl		%g1, 16, %g2
+1:
+	sth		%g2, [%o0 - 2]
+
+	/* Fall through */
+	 
+#endif /* FASTER_NONALIGNED */
+
+88:	/* short_end */
+
+	and		%o2, 0xe, %o3
+20:
+	sethi		%hi(89f), %o5
+	sll		%o3, 3, %o4
+	add		%o0, %o3, %o0
+	sub		%o5, %o4, %o5
+	add		%o1, %o3, %o1
+	jmpl		%o5 + %lo(89f), %g0
+	 andcc		%o2, 1, %g0
 
 	MOVE_SHORTCHUNK(o1, o0, 0x0c, g2, g3)
 	MOVE_SHORTCHUNK(o1, o0, 0x0a, g2, g3)
@@ -308,28 +1120,31 @@
 	MOVE_SHORTCHUNK(o1, o0, 0x04, g2, g3)
 	MOVE_SHORTCHUNK(o1, o0, 0x02, g2, g3)
 	MOVE_SHORTCHUNK(o1, o0, 0x00, g2, g3)
-short_table_end:
-	be	1f
+
+89:	/* short_table_end */
+
+	be		1f
 	 nop
-	ldub	[%o1], %g2
-	stb	%g2, [%o0]
+
+	ldub		[%o1], %g2
+	stb		%g2, [%o0]
 1:
 	retl
- 	 nop
+ 	 RETL_INSN
 
-short_aligned_end:
-	bne	short_end
-	 andcc	%o2, 8, %g0
-
-	be	1f
-	 andcc	%o2, 4, %g0
-
-	ld	[%o1 + 0x00], %g2
-	ld	[%o1 + 0x04], %g3
-	add	%o1, 8, %o1
-	st	%g2, [%o0 + 0x00]
-	st	%g3, [%o0 + 0x04]
-	add	%o0, 8, %o0
+90:	/* short_aligned_end */
+	bne		88b
+	 andcc		%o2, 8, %g0
+
+	be		1f
+	 andcc		%o2, 4, %g0
+
+	ld		[%o1 + 0x00], %g2
+	ld		[%o1 + 0x04], %g3
+	add		%o1, 8, %o1
+	st		%g2, [%o0 + 0x00]
+	st		%g3, [%o0 + 0x04]
+	add		%o0, 8, %o0
 1:
-	b	memcpy_last7
-	 mov	%o2, %g1
+	b		81b
+	 mov		%o2, %g1
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/lib/memset.S linux/arch/sparc/lib/memset.S
--- v2.1.22/linux/arch/sparc/lib/memset.S	Wed Dec 18 15:58:46 1996
+++ linux/arch/sparc/lib/memset.S	Sun Jan 26 12:07:09 1997
@@ -1,15 +1,13 @@
 /* linux/arch/sparc/lib/memset.S: Sparc optimized memset and bzero code
  * Hand optimized from GNU libc's memset
  * Copyright (C) 1991,1996 Free Software Foundation
- * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
  */
 
 #include <asm/cprefix.h>
 #include <asm/ptrace.h>
 
-#define HANDLE_UNALIGNED 1
-
 	/* Store 64 bytes at (BASE + OFFSET) using value SOURCE. */
 #define ZERO_BIG_BLOCK(base, offset, source)    \
 	std	source, [base + offset + 0x00]; \
@@ -44,13 +42,6 @@
 	or	%g3, %g2, %g3
 	b	1f
 	 mov	%o2, %o1
-
-#if HANDLE_UNALIGNED
-/* As this is highly unprobable, we optimize the other case (4 aligned)
- * Define HANDLE_UNALIGNED to 0, if all the alignment work is done by
- * the trap. Then we have to hope nobody will memset something unaligned
- * with large counts, as this would lead to a lot of traps...
- */
 3:
 	cmp	%o2, 3
 	be	2f
@@ -66,19 +57,16 @@
 	add	%o1, %o2, %o1
 	b	4f
 	 sub	%o0, %o2, %o0
-#endif /* HANDLE_UNALIGNED */
 
 C_LABEL(__bzero):
 	mov	%g0, %g3
 1:
+ 	mov	%o0, %g1
 	cmp	%o1, 7
 	bleu	7f
-	 mov	%o0, %g1
+	 andcc	%o0, 3, %o2
 
-#if HANDLE_UNALIGNED
-	andcc	%o0, 3, %o2
 	bne	3b
-#endif /* HANDLE_UNALIGNED */
 4:
 	 andcc	%o0, 4, %g0
 
@@ -113,7 +101,6 @@
 bzero_table:
 	ZERO_LAST_BLOCKS(%o0, 0x48, %g2)
 	ZERO_LAST_BLOCKS(%o0, 0x08, %g2)
-
 6:
 	be	8f
 	 andcc	%o1, 4, %g0
@@ -134,11 +121,17 @@
 	 stb	%g3, [%o0]
 8:
 	retl
-	 mov	%g1,%o0
-
-/* Don't care about alignment here. It is highly 
- * unprobable and at most two traps may happen
- */
+	 mov	%g1, %o0
 7:
-	b	6b
+	be	6b
 	 orcc	%o1, 0, %g0
+
+	be	0f
+8:
+	 add	%o0, 1, %o0
+	subcc	%o1, 1, %o1
+	bne,a	8b
+	 stb	%g3, [%o0 - 1]
+0:
+	retl
+	 mov	%g1, %o0
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/mm/fault.c linux/arch/sparc/mm/fault.c
--- v2.1.22/linux/arch/sparc/mm/fault.c	Sun Dec 22 16:37:27 1996
+++ linux/arch/sparc/mm/fault.c	Sun Jan 26 12:07:09 1997
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.85 1996/12/18 06:43:23 tridge Exp $
+/* $Id: fault.c,v 1.86 1997/01/06 06:52:52 davem Exp $
  * fault.c:  Page fault handlers for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -15,6 +15,8 @@
 #include <linux/smp.h>
 #include <linux/signal.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/system.h>
 #include <asm/segment.h>
@@ -143,7 +145,7 @@
 #if 0
 	static unsigned long last_one;
 #endif
-
+	lock_kernel();
 	down(&mm->mmap_sem);
 	if(text_fault)
 		address = regs->pc;
@@ -198,7 +200,7 @@
 	}
 	handle_mm_fault(vma, address, write);
 	up(&mm->mmap_sem);
-	return;
+	goto out;
 	/*
 	 * Something tried to access memory that isn't in our memory map..
 	 * Fix it, but check if it's kernel or user first..
@@ -215,7 +217,7 @@
 		regs->pc = fixup;
 		regs->npc = regs->pc + 4;
 		regs->u_regs[UREG_G2] = g2;
-		return;
+		goto out;
 	}
 	/* Did we have an exception handler installed? */
 	if(current->tss.ex.count == 1) {
@@ -235,7 +237,7 @@
 			regs->u_regs[UREG_G1] = -EFAULT;
 			regs->u_regs[UREG_G2] = address - current->tss.ex.address;
 			regs->u_regs[UREG_G3] = current->tss.ex.pc;
-			return;
+			goto out;
 		}
 	}
 	if(from_user) {
@@ -246,7 +248,7 @@
 		tsk->tss.sig_address = address;
 		tsk->tss.sig_desc = SUBSIG_NOMAPPING;
 		send_sig(SIGSEGV, tsk, 1);
-		return;
+		goto out;
 	}
 	if((unsigned long) address < PAGE_SIZE) {
 		printk(KERN_ALERT "Unable to handle kernel NULL "
@@ -260,6 +262,8 @@
 	printk(KERN_ALERT "tsk->mm->pgd = %08lx\n",
 	       (unsigned long) tsk->mm->pgd);
 	die_if_kernel("Oops", regs);
+out:
+	unlock_kernel();
 }
 
 asmlinkage void do_sun4c_fault(struct pt_regs *regs, int text_fault, int write,
@@ -372,25 +376,31 @@
 {
 	unsigned long sp;
 
+	lock_kernel();
 	sp = current->tss.rwbuf_stkptrs[0];
 	if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
 		force_user_fault(sp + 0x38, 1);
 	force_user_fault(sp, 1);
+	unlock_kernel();
 }
 
 void window_underflow_fault(unsigned long sp)
 {
+	lock_kernel();
 	if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
 		force_user_fault(sp + 0x38, 0);
 	force_user_fault(sp, 0);
+	unlock_kernel();
 }
 
 void window_ret_fault(struct pt_regs *regs)
 {
 	unsigned long sp;
 
+	lock_kernel();
 	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);
+	unlock_kernel();
 }
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/mm/init.c linux/arch/sparc/mm/init.c
--- v2.1.22/linux/arch/sparc/mm/init.c	Sun Dec 22 16:37:27 1996
+++ linux/arch/sparc/mm/init.c	Sun Jan 26 12:07:09 1997
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.46 1996/12/18 06:43:24 tridge Exp $
+/*  $Id: init.c,v 1.47 1997/01/02 14:14:28 jj Exp $
  *  linux/arch/sparc/mm/init.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -266,28 +266,16 @@
 
 void free_initmem (void)
 {
-	extern int text_init_begin, text_init_end, data_init_begin, data_init_end;
-	unsigned long addr, addrend;
-	int savec, saved;
+	extern char __init_begin, __init_end;
+	unsigned long addr;
 	
-	addr = PAGE_ALIGN((unsigned long)(&text_init_begin));
-	addrend = ((unsigned long)(&text_init_end)) & PAGE_MASK;
-	for (savec = addrend - addr; addr < addrend; addr += PAGE_SIZE) {
+	addr = (unsigned long)(&__init_begin);
+	for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
 		mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
 		mem_map[MAP_NR(addr)].count = 1;
 		free_page(addr);
 	}
-	if (savec < 0) savec = 0;
-	addr = PAGE_ALIGN((unsigned long)(&data_init_begin));
-	addrend = ((unsigned long)(&data_init_end)) & PAGE_MASK;
-	for (saved = addrend - addr; addr < addrend; addr += PAGE_SIZE) {
-		mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
-		mem_map[MAP_NR(addr)].count = 1;
-		free_page(addr);
-	}
-	if (saved < 0) saved = 0;
-	printk ("Freeing unused kernel memory: %dk code, %dk data\n",
-        	savec >> 10, saved >> 10);
+	printk ("Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10);
 }
 
 void si_meminfo(struct sysinfo *val)
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c
--- v2.1.22/linux/arch/sparc/mm/srmmu.c	Thu Jan  2 15:55:15 1997
+++ linux/arch/sparc/mm/srmmu.c	Sun Jan 26 12:07:09 1997
@@ -1,4 +1,4 @@
-/* $Id: srmmu.c,v 1.123 1996/12/31 09:53:00 davem Exp $
+/* $Id: srmmu.c,v 1.128 1997/01/12 12:07:00 davem Exp $
  * srmmu.c:  SRMMU specific routines for memory management.
  *
  * Copyright (C) 1995 David S. Miller  (davem@caip.rutgers.edu)
@@ -46,14 +46,6 @@
 extern unsigned long sparc_iobase_vaddr;
 
 #ifdef __SMP__
-extern void smp_capture(void);
-extern void smp_release(void);
-#else
-#define smp_capture()
-#define smp_release()
-#endif /* !(__SMP__) */
-
-#ifdef __SMP__
 #define FLUSH_BEGIN(mm)
 #define FLUSH_END
 #else
@@ -61,7 +53,7 @@
 #define FLUSH_END	}
 #endif
 
-/* #define USE_CHUNK_ALLOC 1 */
+#define USE_CHUNK_ALLOC 1
 
 static unsigned long (*mmu_getpage)(void);
 static void (*ctxd_set)(ctxd_t *ctxp, pgd_t *pgdp);
@@ -70,6 +62,7 @@
 static void (*flush_page_for_dma)(unsigned long page);
 static void (*flush_cache_page_to_uncache)(unsigned long page);
 static void (*flush_tlb_page_for_cbit)(unsigned long page);
+static void (*flush_chunk)(unsigned long chunk);
 #ifdef __SMP__
 static void (*local_flush_page_for_dma)(unsigned long page);
 static void (*local_flush_cache_page_to_uncache)(unsigned long page);
@@ -328,7 +321,7 @@
 
 #define OTHER_PAGE(p,q)	(((unsigned long)(p) ^ (unsigned long)(q)) & PAGE_MASK)
 
-static inline int garbage_collect(unsigned long **cnks, int n, int cpp)
+static int garbage_collect(unsigned long **cnks, int n, int cpp)
 {
 	struct chunk *root = (struct chunk *)*cnks;
 	struct chunk *p, *q, *curr, *next;
@@ -424,8 +417,7 @@
 	return water;
 }
 
-
-static inline unsigned long *get_small_chunk(void)
+static unsigned long *get_small_chunk(void)
 {
 	unsigned long *rval;
 	unsigned long flags;
@@ -467,6 +459,7 @@
 	lcjiffies = jiffies;
 	restore_flags(flags);
 	memset(rval, 0, 256);
+	flush_chunk((unsigned long)rval);
 	return rval;
 }
 
@@ -486,7 +479,7 @@
 	restore_flags(flags);
 }
 
-static inline unsigned long *get_big_chunk(void)
+static unsigned long *get_big_chunk(void)
 {
 	unsigned long *rval;
 	unsigned long flags;
@@ -516,6 +509,7 @@
 	bcjiffies = jiffies;
 	restore_flags(flags);
 	memset(rval, 0, 1024);
+	flush_chunk((unsigned long)rval);
 	return rval;
 }
 
@@ -980,6 +974,10 @@
 	tsunami_flush_icache();
 }
 
+static void tsunami_flush_chunk(unsigned long chunk)
+{
+}
+
 static void tsunami_flush_tlb_all(void)
 {
 	srmmu_flush_whole_tlb();
@@ -1087,6 +1085,10 @@
 	swift_flush_dcache();
 }
 
+static void swift_flush_chunk(unsigned long chunk)
+{
+}
+
 static void swift_flush_tlb_all(void)
 {
 	srmmu_flush_whole_tlb();
@@ -1160,6 +1162,10 @@
 {
 }
 
+static void viking_mxcc_flush_chunk(unsigned long chunk)
+{
+}
+
 /* All vikings have an icache which snoops the processor bus and is fully
  * coherent with the dcache, so no flush is necessary at all.
  */
@@ -1251,6 +1257,11 @@
 	}
 }
 
+static void viking_nomxcc_flush_chunk(unsigned long chunk)
+{
+	viking_no_mxcc_flush_page(chunk);
+}
+
 /* Viking is IO cache coherent, but really only on MXCC. */
 static void viking_flush_page_for_dma(unsigned long page)
 {
@@ -1544,6 +1555,11 @@
 	} while(line != page);
 }
 
+static void cypress_flush_chunk(unsigned long chunk)
+{
+	cypress_flush_page_to_ram(chunk);
+}
+
 /* Cypress is also IO cache coherent. */
 static void cypress_flush_page_for_dma(unsigned long page)
 {
@@ -1711,7 +1727,6 @@
 static void hypersparc_flush_cache_mm(struct mm_struct *mm)
 {
 	register int ctr asm("g5");
-	unsigned long tmp1;
 
 	FLUSH_BEGIN(mm)
 	ctr = 0;
@@ -1728,66 +1743,135 @@
 	: "0" (ctr), "i" (UWINMASK_OFFSET)
 	: "g4");
 
+	/* Gcc can bite me... */
+#if !defined(__svr4__) && !defined(__ELF__)
+	__asm__ __volatile__("
+	sethi	%hi(_vac_line_size), %g1
+	ld	[%g1 + %lo(_vac_line_size)], %o1
+	sethi	%hi(_vac_cache_size), %g2
+	ld	[%g2 + %lo(_vac_cache_size)], %o0");
+#else
 	__asm__ __volatile__("
-	1:	subcc	%0, %2, %0		! hyper_flush_cache_user
+	sethi	%hi(vac_line_size), %g1
+	ld	[%g1 + %lo(vac_line_size)], %o1
+	sethi	%hi(vac_cache_size), %g2
+	ld	[%g2 + %lo(vac_cache_size)], %o0");
+#endif
+
+	__asm__ __volatile__("
+		add	%%o1, %%o1, %%g1
+		add	%%o1, %%g1, %%g2
+		add	%%o1, %%g2, %%g3
+		add	%%o1, %%g3, %%g4
+		add	%%o1, %%g4, %%g5
+		add	%%o1, %%g5, %%o4
+		add	%%o1, %%o4, %%o5
+	1:	subcc	%%o0, %%o5, %%o0		! hyper_flush_cache_user
+		sta	%%g0, [%%o0 + %%g0] %0
+		sta	%%g0, [%%o0 + %%o1] %0
+		sta	%%g0, [%%o0 + %%g1] %0
+		sta	%%g0, [%%o0 + %%g2] %0
+		sta	%%g0, [%%o0 + %%g3] %0
+		sta	%%g0, [%%o0 + %%g4] %0
+		sta	%%g0, [%%o0 + %%g5] %0
 		bne	1b
-		 sta	%%g0, [%0] %3
-		sta	%%g0, [%%g0] %4		! hyper_flush_whole_icache"
-	: "=&r" (tmp1)
-	: "0" (vac_cache_size), "r" (vac_line_size), "i" (ASI_M_FLUSH_USER),
-	  "i" (ASI_M_FLUSH_IWHOLE));
+		 sta	%%g0, [%%o0 + %%o4] %0
+		sta	%%g0, [%%g0 + %%g0] %1		! hyper_flush_whole_icache"
+	: : "i" (ASI_M_FLUSH_USER), "i" (ASI_M_FLUSH_IWHOLE));
 	FLUSH_END
 }
 
 /* The things we do for performance... */
 static void hypersparc_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end)
 {
-	register int ctr asm("g5");
-	unsigned long tmp1;
-
 	FLUSH_BEGIN(mm)
-	ctr = 0;
 	__asm__ __volatile__("
-	1:	ld	[%%g6 + %2], %%g4	! flush user windows
-		orcc	%%g0, %%g4, %%g0
-		add	%0, 1, %0
-		bne	1b
-		 save	%%sp, -64, %%sp
-	2:	subcc	%0, 1, %0
-		bne	2b
-		 restore %%g0, %%g0, %%g0"
-	: "=&r" (ctr) : "0" (ctr), "i" (UWINMASK_OFFSET) : "g4");
-	tmp1 = vac_cache_size; start &= PAGE_MASK; end = PAGE_ALIGN(end);
-	if((end - start) >= (tmp1 << 2)) {
-		__asm__ __volatile__("
-		1:	subcc	%0, %2, %0	! hyper_flush_cache_user
-			bne	1b
-			 sta	%%g0, [%0] %3
-			sta	%%g0, [%%g0] %4"
-		: "=&r" (tmp1) : "0" (tmp1), "r" (vac_line_size),
-		  "i" (ASI_M_FLUSH_USER), "i" (ASI_M_FLUSH_IWHOLE));
-	} else {
-		tmp1 = srmmu_get_context(); srmmu_set_context(mm->context);
-		__asm__ __volatile__("
-			sub	%0, %3, %0
-		1:	or	%0, 0x400, %%g4
-			lda	[%%g4] %4, %%g4
-			orcc	%%g4, 0x0, %%g0
-			be	3f
-			 sethi	%%hi(0x1000), %%g5
-		2:	subcc	%%g5, %7, %%g5	! hyper_flush_cache_page
-			bne	2b
-			 sta	%%g0, [%0 + %%g5] %5
-		3:	cmp	%0, %2
-			bne	1b
-			 sub	%0, %3, %0
-			sta	%%g0, [%%g0] %6	! hyper_flush_whole_icache"
-		: "=&r" (end)
-		: "0" (end), "r" (start), "r" (PAGE_SIZE), "i" (ASI_M_FLUSH_PROBE),
-		  "i" (ASI_M_FLUSH_PAGE), "i" (ASI_M_FLUSH_IWHOLE), "r" (vac_line_size)
-		: "g4", "g5");
-		(void) srmmu_get_fstatus(); srmmu_set_context(tmp1);
-	}
+	mov	0, %%g5
+1:	ld	[%%g6 + %0], %%g4
+	orcc	%%g0, %%g4, %%g0
+	add	%%g5, 1, %%g5
+	bne	1b
+	 save	%%sp, -64, %%sp
+2:	subcc	%%g5, 1, %%g5
+	bne	2b
+	 restore %%g0, %%g0, %%g0
+	" : : "i" (UWINMASK_OFFSET));
+#if !defined(__svr4__) && !defined(__ELF__)
+	__asm__ __volatile__("
+	sethi	%hi(_vac_line_size), %g1
+	ld	[%g1 + %lo(_vac_line_size)], %o4
+	sethi	%hi(_vac_cache_size), %g2
+	ld	[%g2 + %lo(_vac_cache_size)], %o3");
+#else
+	__asm__ __volatile__("
+	sethi	%hi(vac_line_size), %g1
+	ld	[%g1 + %lo(vac_line_size)], %o4
+	sethi	%hi(vac_cache_size), %g2
+	ld	[%g2 + %lo(vac_cache_size)], %o3");
+#endif
+	/* Close your eyes... */
+	__asm__ __volatile__("
+	add	%%o2, (%0 - 1), %%o2
+	andn	%%o1, (%0 - 1), %%o1
+	add	%%o4, %%o4, %%o5
+	andn	%%o2, (%0 - 1), %%o2
+	add	%%o4, %%o5, %%g1
+	sub	%%o2, %%o1, %%g4
+	add	%%o4, %%g1, %%g2
+	sll	%%o3, 2, %%g5
+	add	%%o4, %%g2, %%g3
+	cmp	%%g4, %%g5
+	add	%%o4, %%g3, %%g4
+	blu	0f
+	 add	%%o4, %%g4, %%g5
+	add	%%o4, %%g5, %%g7
+1:	subcc	%%o3, %%g7, %%o3
+	sta	%%g0, [%%o3 + %%g0] %1
+	sta	%%g0, [%%o3 + %%o4] %1
+	sta	%%g0, [%%o3 + %%o5] %1
+	sta	%%g0, [%%o3 + %%g1] %1
+	sta	%%g0, [%%o3 + %%g2] %1
+	sta	%%g0, [%%o3 + %%g3] %1
+	sta	%%g0, [%%o3 + %%g4] %1
+	bne	1b
+	 sta	%%g0, [%%o3 + %%g5] %1
+	b,a	9f
+0:	ld	[%%o0 + %3], %%o0
+	mov	%2, %%g7
+	lda	[%%g7] %4, %%o3
+	sta	%%o0, [%%g7] %4
+	sethi	%%hi(%0), %%g7
+	sub	%%o2, %%g7, %%o0
+1:	or	%%o0, 0x400, %%g7
+	lda	[%%g7] %5, %%g7
+	orcc	%%g7, 0x0, %%g0
+	be,a	3f
+	 mov	%%o0, %%o2
+	add	%%o4, %%g5, %%g7
+2:	sub	%%o2, %%g7, %%o2
+	sta	%%g0, [%%o2 + %%g0] %6
+	sta	%%g0, [%%o2 + %%o4] %6
+	sta	%%g0, [%%o2 + %%o5] %6
+	sta	%%g0, [%%o2 + %%g1] %6
+	sta	%%g0, [%%o2 + %%g2] %6
+	sta	%%g0, [%%o2 + %%g3] %6
+	andcc	%%o2, 0xffc, %%g0
+	sta	%%g0, [%%o2 + %%g4] %6
+	bne	2b
+	 sta	%%g0, [%%o2 + %%g5] %6
+3:	sethi	%%hi(%0), %%g7
+	cmp	%%o2, %%o1
+	bne	1b
+	 sub	%%o2, %%g7, %%o0
+	mov	%8, %%g5
+	lda	[%%g5] %4, %%g0
+	mov	%2, %%g7
+	sta	%%o3, [%%g7] %4
+9:	sta	%%g0, [%%g0 + %%g0] %7
+"	: : "i" (PAGE_SIZE), "i" (ASI_M_FLUSH_USER), "i" (SRMMU_CTX_REG),
+	    "i" ((const unsigned long)(&(((struct mm_struct *)0)->context))),
+	    "i" (ASI_M_MMUREGS), "i" (ASI_M_FLUSH_PROBE), "i" (ASI_M_FLUSH_PAGE),
+	    "i" (ASI_M_FLUSH_IWHOLE), "i" (SRMMU_FAULT_STATUS));
 	FLUSH_END
 }
 
@@ -1796,65 +1880,127 @@
  */
 static void hypersparc_flush_cache_page(struct vm_area_struct *vma, unsigned long page)
 {
-	struct mm_struct *mm = vma->vm_mm;
-	register int ctr asm("g5");
-	unsigned long tmp1;
-
-	FLUSH_BEGIN(mm)
-	ctr = 0;
 	__asm__ __volatile__("
-	1:	ld	[%%g6 + %2], %%g4	! flush user windows
-		orcc	%%g0, %%g4, %%g0
-		add	%0, 1, %0
-		bne	1b
-		 save	%%sp, -64, %%sp
-	2:	subcc	%0, 1, %0
-		bne	2b
-		 restore %%g0, %%g0, %%g0"
-	: "=&r" (ctr) : "0" (ctr), "i" (UWINMASK_OFFSET) : "g4");
+	ld	[%%o0 + %0], %%g4
+	ld	[%%g4 + %1], %%o0
+"	: : "i" ((const unsigned long)(&(((struct vm_area_struct *)0)->vm_mm))),
+	    "i" ((const unsigned long)(&(((struct mm_struct *)0)->context))));
+#ifndef __SMP__
+	__asm__ __volatile__("
+	cmp	%o0, -1
+	bne	1f
+	 mov	0, %g5
+	retl");
+#else
+	__asm__ __volatile__("mov	0, %g5");	/* else we die a horrible death */
+#endif
 	__asm__ __volatile__("
-		mov	0x200, %%g4
-		lda	[%%g4] %6, %1
-		sta	%0, [%%g4] %6
-		or	%3, 0x400, %0
-		lda	[%0] %9, %0
-		orcc	%0, 0x0, %%g0
-		be	2f
-		 sethi	%%hi(0x1000), %0
-	1:	subcc	%0, %5, %0		! hyper_flush_cache_page
-		bne	1b
-		 sta	%%g0, [%3 + %0] %7
-	2:	andcc	%4, 0x4, %%g0
-		sta	%1, [%%g4] %6
-		bne,a	1f
-		 sta	%%g0, [%%g0] %8
-1:"	: "=&r" (tmp1), "=&r" (ctr)
-	: "0" (mm->context), "r" (page & PAGE_MASK), "r" (vma->vm_flags),
-	  "r" (vac_line_size), "i" (ASI_M_MMUREGS), "i" (ASI_M_FLUSH_PAGE),
-	  "i" (ASI_M_FLUSH_IWHOLE), "i" (ASI_M_FLUSH_PROBE)
-	: "g4");
-	(void) srmmu_get_fstatus();
-	FLUSH_END
+1:	 ld	[%%g6 + %0], %%g4	! flush user windows
+	orcc	%%g0, %%g4, %%g0
+	add	%%g5, 1, %%g5
+	bne	1b
+	 save	%%sp, -64, %%sp
+2:	subcc	%%g5, 1, %%g5
+	bne	2b
+	 restore %%g0, %%g0, %%g0"
+	: : "i" (UWINMASK_OFFSET));
+#if !defined(__svr4__) && !defined(__ELF__)
+	__asm__ __volatile__("
+	sethi	%hi(_vac_line_size), %g1
+	ld	[%g1 + %lo(_vac_line_size)], %o4");
+#else
+	__asm__ __volatile__("
+	sethi	%hi(vac_line_size), %g1
+	ld	[%g1 + %lo(vac_line_size)], %o4");
+#endif
+	__asm__ __volatile__("
+	mov	%0, %%o3
+	andn	%%o1, (%4 - 1), %%o1
+	lda	[%%o3] %1, %%o2
+	sta	%%o0, [%%o3] %1
+	or	%%o1, 0x400, %%o5
+	lda	[%%o5] %3, %%o5
+	orcc	%%o5, 0x0, %%g0
+	be	2f
+	 sethi	%%hi(%4), %%g7
+	add	%%o4, %%o4, %%o5
+	add	%%o1, %%g7, %%o1
+	add	%%o4, %%o5, %%g1
+	add	%%o4, %%g1, %%g2
+	add	%%o4, %%g2, %%g3
+	add	%%o4, %%g3, %%g4
+	add	%%o4, %%g4, %%g5
+	add	%%o4, %%g5, %%g7
+1:	sub	%%o1, %%g7, %%o1		! hyper_flush_cache_page
+	sta	%%g0, [%%o1 + %%g0] %5
+	sta	%%g0, [%%o1 + %%o4] %5
+	sta	%%g0, [%%o1 + %%o5] %5
+	sta	%%g0, [%%o1 + %%g1] %5
+	sta	%%g0, [%%o1 + %%g2] %5
+	sta	%%g0, [%%o1 + %%g3] %5
+	andcc	%%o1, 0xffc, %%g0
+	sta	%%g0, [%%o1 + %%g4] %5
+	bne	1b
+	 sta	%%g0, [%%o1 + %%g5] %5
+	sta	%%g0, [%%g0 + %%g0] %6
+2:	mov	%0, %%g4
+	sta	%%o2, [%%g4] %1
+	mov	%2, %%g7
+	retl
+	 lda	[%%g7] %1, %%g0
+"	: : "i" (SRMMU_CTX_REG), "i" (ASI_M_MMUREGS), "i" (SRMMU_FAULT_STATUS),
+	    "i" (ASI_M_FLUSH_PROBE), "i" (PAGE_SIZE), "i" (ASI_M_FLUSH_PAGE),
+	    "i" (ASI_M_FLUSH_IWHOLE));
 }
 
 /* HyperSparc is copy-back. */
 static void hypersparc_flush_page_to_ram(unsigned long page)
 {
-	page &= PAGE_MASK;
+#if !defined(__svr4__) && !defined(__ELF__)
 	__asm__ __volatile__("
-	lda	[%0] %2, %%g4
-	orcc	%%g4, 0x0, %%g0
+	sethi	%hi(_vac_line_size), %g1
+	ld	[%g1 + %lo(_vac_line_size)], %o4");
+#else
+	__asm__ __volatile__("
+	sethi	%hi(vac_line_size), %g1
+	ld	[%g1 + %lo(vac_line_size)], %o4");
+#endif
+	__asm__ __volatile__("
+	andn	%%o0, (%0 - 1), %%o0
+	add	%%o4, %%o4, %%o5
+	or	%%o0, 0x400, %%g7
+	lda	[%%g7] %2, %%g5
+	add	%%o4, %%o5, %%g1
+	orcc	%%g5, 0x0, %%g0
 	be	2f
-	 sethi	%%hi(%7), %%g5
-1:	subcc	%%g5, %6, %%g5		! hyper_flush_cache_page
+	 add	%%o4, %%g1, %%g2
+	sethi	%%hi(%0), %%g5
+	add	%%o4, %%g2, %%g3
+	add	%%o0, %%g5, %%o0
+	add	%%o4, %%g3, %%g4
+	add	%%o4, %%g4, %%g5
+	add	%%o4, %%g5, %%g7
+1:	sub	%%o0, %%g7, %%o0
+	sta	%%g0, [%%o0 + %%g0] %1
+	sta	%%g0, [%%o0 + %%o4] %1
+	sta	%%g0, [%%o0 + %%o5] %1
+	sta	%%g0, [%%o0 + %%g1] %1
+	sta	%%g0, [%%o0 + %%g2] %1
+	sta	%%g0, [%%o0 + %%g3] %1
+	andcc	%%o0, 0xffc, %%g0
+	sta	%%g0, [%%o0 + %%g4] %1
 	bne	1b
-	 sta	%%g0, [%1 + %%g5] %3
-2:	lda	[%4] %5, %%g0"
+	 sta	%%g0, [%%o0 + %%g5] %1
+2:	mov	%3, %%g1
+	lda	[%%g1] %4, %%g0"
 	: /* no outputs */
-	: "r" (page | 0x400), "r" (page), "i" (ASI_M_FLUSH_PROBE),
-	  "i" (ASI_M_FLUSH_PAGE), "r" (SRMMU_FAULT_STATUS), "i" (ASI_M_MMUREGS),
-	  "r" (vac_line_size), "i" (PAGE_SIZE)
-	: "g4", "g5");
+	: "i" (PAGE_SIZE), "i" (ASI_M_FLUSH_PAGE), "i" (ASI_M_FLUSH_PROBE),
+	  "i" (SRMMU_FAULT_STATUS), "i" (ASI_M_MMUREGS));
+}
+
+static void hypersparc_flush_chunk(unsigned long chunk)
+{
+	hypersparc_flush_page_to_ram(chunk);
 }
 
 /* HyperSparc is IO cache coherent. */
@@ -1891,23 +2037,41 @@
 
 static unsigned long hypersparc_getpage(void)
 {
-	unsigned long page = get_free_page(GFP_KERNEL);
+	register unsigned long page asm("i0");
 
+	page = get_free_page(GFP_KERNEL);
+#if !defined(__svr4__) && !defined(__ELF__)
 	__asm__ __volatile__("
-	lda	[%0] %2, %%g4
-	orcc	%%g4, 0x0, %%g0
-	be	2f
-	 sethi	%%hi(%7), %%g5
-1:	subcc	%%g5, %6, %%g5		! hyper_flush_cache_page
+	sethi	%hi(_vac_line_size), %g1
+	ld	[%g1 + %lo(_vac_line_size)], %o4");
+#else
+	__asm__ __volatile__("
+	sethi	%hi(vac_line_size), %g1
+	ld	[%g1 + %lo(vac_line_size)], %o4");
+#endif
+	__asm__ __volatile__("
+	sethi	%%hi(%0), %%g5
+	add	%%o4, %%o4, %%o5
+	add	%%o4, %%o5, %%g1
+	add	%%o4, %%g1, %%g2
+	add	%%o4, %%g2, %%g3
+	add	%%i0, %%g5, %%o0
+	add	%%o4, %%g3, %%g4
+	add	%%o4, %%g4, %%g5
+	add	%%o4, %%g5, %%g7
+1:	sub	%%o0, %%g7, %%o0
+	sta	%%g0, [%%o0 + %%g0] %1
+	sta	%%g0, [%%o0 + %%o4] %1
+	sta	%%g0, [%%o0 + %%o5] %1
+	sta	%%g0, [%%o0 + %%g1] %1
+	sta	%%g0, [%%o0 + %%g2] %1
+	sta	%%g0, [%%o0 + %%g3] %1
+	andcc	%%o0, 0xffc, %%g0
+	sta	%%g0, [%%o0 + %%g4] %1
 	bne	1b
-	 sta	%%g0, [%1 + %%g5] %3
-2:	lda	[%4] %5, %%g0"
+	 sta	%%g0, [%%o0 + %%g5] %1"
 	: /* no outputs */
-	: "r" (page | 0x400), "r" (page), "i" (ASI_M_FLUSH_PROBE),
-	  "i" (ASI_M_FLUSH_PAGE), "r" (SRMMU_FAULT_STATUS), "i" (ASI_M_MMUREGS),
-	  "r" (vac_line_size), "i" (PAGE_SIZE)
-	: "g4", "g5");
-
+	: "i" (PAGE_SIZE), "i" (ASI_M_FLUSH_PAGE));
 	return page;
 }
 
@@ -1989,21 +2153,7 @@
 {
 	unsigned long page = ((unsigned long) pgdp) & PAGE_MASK;
 
-	__asm__ __volatile__("
-	lda	[%0] %2, %%g4
-	orcc	%%g4, 0x0, %%g0
-	be	2f
-	 sethi	%%hi(%7), %%g5
-1:	subcc	%%g5, %6, %%g5		! hyper_flush_cache_page
-	bne	1b
-	 sta	%%g0, [%1 + %%g5] %3
-2:	lda	[%4] %5, %%g0"
-	: /* no outputs */
-	: "r" (page | 0x400), "r" (page), "i" (ASI_M_FLUSH_PROBE),
-	  "i" (ASI_M_FLUSH_PAGE), "r" (SRMMU_FAULT_STATUS), "i" (ASI_M_MMUREGS),
-	  "r" (vac_line_size), "i" (PAGE_SIZE)
-	: "g4", "g5");
-
+	hypersparc_flush_page_to_ram(page);
 	if(tsk->mm->context != NO_CONTEXT) {
 		flush_cache_mm(tsk->mm);
 		ctxd_set(&srmmu_context_table[tsk->mm->context], pgdp);
@@ -3101,6 +3251,8 @@
 	flush_cache_page_to_uncache = hypersparc_flush_cache_page_to_uncache;
 	flush_tlb_page_for_cbit = hypersparc_flush_tlb_page_for_cbit;
 
+	flush_chunk = hypersparc_flush_chunk; /* local flush _only_ */
+
 	ctxd_set = hypersparc_ctxd_set;
 	switch_to_context = hypersparc_switch_to_context;
 	init_new_context = hypersparc_init_new_context;
@@ -3165,6 +3317,8 @@
 	flush_tlb_page = cypress_flush_tlb_page;
 	flush_tlb_range = cypress_flush_tlb_range;
 
+	flush_chunk = cypress_flush_chunk; /* local flush _only_ */
+
 	flush_page_to_ram = cypress_flush_page_to_ram;
 	flush_sig_insns = cypress_flush_sig_insns;
 	flush_page_for_dma = cypress_flush_page_for_dma;
@@ -3273,6 +3427,8 @@
 	flush_cache_page = swift_flush_cache_page;
 	flush_cache_range = swift_flush_cache_range;
 
+	flush_chunk = swift_flush_chunk; /* local flush _only_ */
+
 	flush_tlb_all = swift_flush_tlb_all;
 	flush_tlb_mm = swift_flush_tlb_mm;
 	flush_tlb_page = swift_flush_tlb_page;
@@ -3319,6 +3475,8 @@
 	flush_cache_page = tsunami_flush_cache_page;
 	flush_cache_range = tsunami_flush_cache_range;
 
+	flush_chunk = tsunami_flush_chunk; /* local flush _only_ */
+
 	flush_tlb_all = tsunami_flush_tlb_all;
 	flush_tlb_mm = tsunami_flush_tlb_mm;
 	flush_tlb_page = tsunami_flush_tlb_page;
@@ -3410,6 +3568,8 @@
 
 		flush_cache_page_to_uncache = viking_no_mxcc_flush_page;
 
+		flush_chunk = viking_nomxcc_flush_chunk; /* local flush _only_ */
+
 		/* We need this to make sure old viking takes no hits
 		 * on it's cache for dma snoops to workaround the
 		 * "load from non-cacheable memory" interrupt bug.
@@ -3422,6 +3582,8 @@
 		viking_mxcc_present = 1;
 		flush_cache_page_to_uncache = viking_mxcc_flush_page;
 
+		flush_chunk = viking_mxcc_flush_chunk; /* local flush _only_ */
+
 		/* MXCC vikings lack the DMA snooping bug. */
 		flush_page_for_dma = viking_flush_page_for_dma;
 	}
@@ -3518,10 +3680,6 @@
 extern unsigned long spwin_srmmu_stackchk, srmmu_fwin_stackchk,
 	tsetup_srmmu_stackchk, srmmu_rett_stackchk;
 
-#ifdef __SMP__
-extern unsigned long rirq_mmu_patchme, srmmu_reti_stackchk;
-#endif
-
 extern unsigned long srmmu_fault;
 
 #define PATCH_BRANCH(insn, dest) do { \
@@ -3538,9 +3696,6 @@
 	PATCH_BRANCH(fwin_mmu_patchme, srmmu_fwin_stackchk);
 	PATCH_BRANCH(tsetup_mmu_patchme, tsetup_srmmu_stackchk);
 	PATCH_BRANCH(rtrap_mmu_patchme, srmmu_rett_stackchk);
-#ifdef __SMP__
-	PATCH_BRANCH(rirq_mmu_patchme, srmmu_reti_stackchk);
-#endif
 	PATCH_BRANCH(sparc_ttable[SP_TRAP_TFLT].inst_three, srmmu_fault);
 	PATCH_BRANCH(sparc_ttable[SP_TRAP_DFLT].inst_three, srmmu_fault);
 	PATCH_BRANCH(sparc_ttable[SP_TRAP_DACC].inst_three, srmmu_fault);
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/vmlinux.lds linux/arch/sparc/vmlinux.lds
--- v2.1.22/linux/arch/sparc/vmlinux.lds	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/vmlinux.lds	Sun Jan 26 12:07:09 1997
@@ -0,0 +1,62 @@
+/* ld script to make SparcLinux kernel */
+OUTPUT_FORMAT("elf32-sparc", "elf32-sparc", "elf32-sparc")
+OUTPUT_ARCH(sparc)
+ENTRY(_start)
+SECTIONS
+{
+  . = 0x10000 + SIZEOF_HEADERS;
+  .text 0xf0004000 :
+  {
+    *(.text)
+    *(.gnu.warning)
+  } =0
+  _etext = .;
+  PROVIDE (etext = .);
+  .rodata    : { *(.rodata)  }
+  .rodata1   : { *(.rodata1) }
+  .data    :
+  {
+    *(.data)
+    CONSTRUCTORS
+  }
+  .data1   : { *(.data1) }
+  _edata  =  .;
+  PROVIDE (edata = .);
+  .fixup   : { *(.fixup) }
+  __start___ex_table = .;
+  __ex_table : { *(__ex_table) }
+  __stop___ex_table = .;
+  __start___ksymtab = .;
+  __ksymtab  : { *(__ksymtab) }
+  __stop___ksymtab = .;
+  . = ALIGN(4096);
+  __init_begin = .;
+  .text.init : { *(.text.init) }
+  .data.init : { *(.data.init) }
+  . = ALIGN(4096);
+  __init_end = .;
+  __bss_start = .;
+  .sbss      : { *(.sbss) *(.scommon) }
+  .bss       :
+  {
+   *(.dynbss)
+   *(.bss)
+   *(COMMON)
+  }
+  _end = . ;
+  PROVIDE (end = .);
+  /* Stabs debugging sections.  */
+  .stab 0 : { *(.stab) }
+  .stabstr 0 : { *(.stabstr) }
+  .stab.excl 0 : { *(.stab.excl) }
+  .stab.exclstr 0 : { *(.stab.exclstr) }
+  .stab.index 0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment 0 : { *(.comment) }
+  .debug          0 : { *(.debug) }
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+  .line           0 : { *(.line) }
+}
diff -u --recursive --new-file v2.1.22/linux/arch/sparc64/Makefile linux/arch/sparc64/Makefile
--- v2.1.22/linux/arch/sparc64/Makefile	Tue Dec 31 21:41:00 1996
+++ linux/arch/sparc64/Makefile	Sun Jan 26 12:07:09 1997
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.2 1996/12/27 17:28:20 davem Exp $
+# $Id: Makefile,v 1.3 1997/01/02 14:14:35 jj Exp $
 # sparc64/Makefile
 #
 # Makefile for the architecture dependent flags and dependencies on the
@@ -25,9 +25,9 @@
 #CFLAGS := $(CFLAGS) -g -pipe
 CFLAGS := $(CFLAGS) -pipe
 
-LINKFLAGS = -N -Ttext 0xFFFFF80000008000
+LINKFLAGS = -T arch/sparc64/vmlinux.lds
 
-HEAD := arch/sparc/kernel/head.o
+HEAD := arch/sparc64/kernel/head.o
 
 SUBDIRS := $(SUBDIRS) arch/sparc64/kernel arch/sparc64/lib arch/sparc64/mm \
 	arch/sparc64/prom
@@ -36,9 +36,6 @@
 
 LIBS := $(TOPDIR)/lib/lib.a $(LIBS) $(TOPDIR)/arch/sparc64/prom/promlib.a \
 	$(TOPDIR)/arch/sparc64/lib/lib.a
-
-INITOBJ = $(TOPDIR)/arch/sparc64/kernel/initobj.o
-FINITOBJ = $(TOPDIR)/arch/sparc64/kernel/finitobj.o
 
 archclean:
 
diff -u --recursive --new-file v2.1.22/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig
--- v2.1.22/linux/arch/sparc64/defconfig	Wed Jan 15 19:45:41 1997
+++ linux/arch/sparc64/defconfig	Sun Jan 26 12:07:09 1997
@@ -165,7 +165,9 @@
 #
 CONFIG_QUOTA=y
 CONFIG_MINIX_FS=y
+CONFIG_EXT_FS=y
 CONFIG_EXT2_FS=y
+CONFIG_XIA_FS=y
 CONFIG_FAT_FS=y
 CONFIG_MSDOS_FS=y
 CONFIG_VFAT_FS=y
diff -u --recursive --new-file v2.1.22/linux/arch/sparc64/kernel/finitobj.S linux/arch/sparc64/kernel/finitobj.S
--- v2.1.22/linux/arch/sparc64/kernel/finitobj.S	Tue Dec 31 21:41:00 1996
+++ linux/arch/sparc64/kernel/finitobj.S	Thu Jan  1 02:00:00 1970
@@ -1,6 +0,0 @@
-	.section	".text.init",#alloc,#execinstr
-	.globl	text_init_end
-text_init_end:
-	.section	".data.init",#alloc,#write
-	.globl	data_init_end
-data_init_end:
diff -u --recursive --new-file v2.1.22/linux/arch/sparc64/kernel/head.S linux/arch/sparc64/kernel/head.S
--- v2.1.22/linux/arch/sparc64/kernel/head.S	Tue Dec 31 21:41:00 1996
+++ linux/arch/sparc64/kernel/head.S	Sun Jan 26 12:07:09 1997
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.4 1996/12/28 18:39:42 davem Exp $
+/* $Id: head.S,v 1.6 1997/01/06 20:32:44 jj Exp $
  * head.S: Initial boot code for the Sparc64 port of Linux.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -7,6 +7,7 @@
 #include <asm/pstate.h>
 #include <asm/spitfire.h>
 #include <asm/pgtable.h>
+#include <asm/errno.h>
 
 	.text
 
@@ -14,7 +15,6 @@
 
 sparc64_boot:
 	rdpr	%ver, %g1			/* Get VERSION register.	*/
-	mov	%o4, %g2			/* Get OpenPROM vector.		*/
 
 	/* We must be careful, 32-bit OpenBOOT will get confused if it
 	 * tries to save away a register window to a 64-bit kernel
@@ -76,10 +76,7 @@
 	stx	%g4, [%g7]
 	set	nwindowsm1, %g6
 	stx	%g5, [%g6]
-	set	romvec, %g7
-	stx	%g2, [%g7]
-	set	prom_sp, %g7
-	stx	%sp, [%g7]
+	mov	%sp, %o1			! second argument to prom_init
 	set	swapper_pg_dir, %g6
 	set	PAGE_OFFSET, %g4		! this stays here for a long time
 	sub	%g6, %g4, %g5
@@ -97,7 +94,7 @@
 	/* XXX Map in PROM 32-bit trampoline code. */
 	
 	call	prom_init
-	 mov	%o4, %o0
+	 mov	%o4, %o0			! OpenPROM cif handler
 
 	/* Off we go.... */
 	call	start_kernel
@@ -106,9 +103,13 @@
 	/* Not reached... */
 
 	.data
-	.align	4
-	.globl	nwindows, nwindowsm1, romvec, prom_sp
+	.align	8
+	.globl	nwindows, nwindowsm1 
 nwindows:	.xword	0
 nwindowsm1:	.xword	0
-romvec:		.xword	0
-prom_sp:	.xword	0
+
+	.section	".fixup",#alloc,#execinstr
+	.globl	__ret_efault
+__ret_efault:
+	ret
+	 restore %g0, -EFAULT, %o0
diff -u --recursive --new-file v2.1.22/linux/arch/sparc64/kernel/initobj.S linux/arch/sparc64/kernel/initobj.S
--- v2.1.22/linux/arch/sparc64/kernel/initobj.S	Tue Dec 31 21:41:00 1996
+++ linux/arch/sparc64/kernel/initobj.S	Thu Jan  1 02:00:00 1970
@@ -1,15 +0,0 @@
-#include <asm/errno.h>
-
-	.section	".text.init",#alloc,#execinstr
-	.globl	text_init_begin
-text_init_begin:
-	.section	".data.init",#alloc,#write
-	.globl	data_init_begin
-data_init_begin:
-
-	.section	".fixup",#alloc,#execinstr
-	.globl	__ret_efault
-__ret_efault:
-	ret
-	 restore %g0, -EFAULT, %o0
-
diff -u --recursive --new-file v2.1.22/linux/arch/sparc64/kernel/signal32.c linux/arch/sparc64/kernel/signal32.c
--- v2.1.22/linux/arch/sparc64/kernel/signal32.c	Tue Dec 31 21:41:00 1996
+++ linux/arch/sparc64/kernel/signal32.c	Sun Jan 26 12:07:09 1997
@@ -1,9 +1,10 @@
-/*  $Id: signal32.c,v 1.1 1996/12/26 10:16:41 davem Exp $
+/*  $Id: signal32.c,v 1.3 1997/01/19 22:32:30 ecd Exp $
  *  arch/sparc64/kernel/signal32.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  *  Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ *  Copyright (C) 1997 Eddie C. Dost   (ecd@skynet.be)
  */
 
 #include <linux/sched.h>
@@ -67,10 +68,11 @@
  */
 
 struct new_signal_frame32 {
-	struct      sparc_stackf_32 ss;
-	__siginfo32_t info;
-	unsigned    int __pad;
-	unsigned    int insns [2];
+	struct sparc_stackf_32	ss;
+	__siginfo32_t		info;
+	__siginfo_fpu32_t	*fpu_save;
+	unsigned int		insns [2];
+	__siginfo_fpu32_t	fpu_state;
 };
 
 /* Align macros */
@@ -119,6 +121,34 @@
 	_sigpause32_common(regs->u_regs[UREG_I0], regs);
 }
 
+
+static inline void
+restore_fpu_state(struct pt_regs *regs, __siginfo_fpu32_t *fpu)
+{
+#ifdef __SMP__
+	if (current->flags & PF_USEDFPU)
+		regs->psr &= ~(TSTATE_PEF);
+#else
+	if (current == last_task_used_math) {
+		last_task_used_math = 0;
+		regs->psr &= ~(TSTATE_PEF);
+	}
+#endif
+	current->used_math = 1;
+	current->flags &= ~PF_USEDFPU;
+
+	copy_32bit_to_kernel_fpuregs(&current->tss.float_regs[0],
+				     &sf->info.si_float_regs[0],
+				     (sizeof(unsigned int) * 64));
+	__get_user(current->tss.fsr, &fpu->si_fsr);
+	__get_user(current->tss.fpqdepth, &fpu->si_fpqdepth);
+	if (current->tss.fpqdepth != 0)
+		copy_from_user(&current->tss.fpqueue[0],
+			       &fpu->si_fpqueue[0],
+			       ((sizeof(unsigned long) +
+			       (sizeof(unsigned long *)))*16));
+}
+
 void do_new_sigreturn32(struct pt_regs *regs)
 {
 	struct new_signal_frame32 *sf;
@@ -138,33 +168,19 @@
 		do_exit (SIGSEGV);
 		return;
 	}
-	
+
 	/* 2. Restore the state */
-	copy_32bit_to_kernel_ptregs (regs, &sf->info.si_regs, sizeof (struct pt_regs));
+	copy_32bit_to_kernel_ptregs (regs, &sf->info.si_regs,
+				     sizeof (struct pt_regs));
 
-	/* User can only change condition codes and FPU enabling in the %tstate. */
+	/* User can only change condition codes and FPU enabling in %tstate. */
 	regs->tstate &= ~(TSTATE_ICC | TSTATE_PEF);
 	regs->tstate |= psr_to_tstate_icc(sf->info.si_regs.psr);
 	regs->tstate |= (sf->info.si_regs.psr & PSR_EF);
 
-	if (regs->tstate & TSTATE_PEF) {
-		regs->psr &= ~(TSTATE_PEF);
-#ifndef __SMP__
-		if(current == last_task_used_math)
-			last_task_used_math = 0;
-#endif
-		current->used_math = 1;
-		current->flags &= ~(PF_USEDFPU);
+	if (sf->fpu_save)
+		restore_fpu_state(regs, sf->fpu_state);
 
-		/* Copy signal FPU state into thread struct FPU state. */
-		copy_32bit_to_kernel_fpuregs(&current->tss.float_regs[0],
-					     &sf->info.si_float_regs[0],
-					     (sizeof(unsigned int) * 64));
-		current->tss.fsr = sf->info.si_fsr;
-		if((current->tss.fpqdepth = sf->info.si_fpqdepth) != 0)
-		    memcpy(&current->tss.fpqueue[0], &sf->info.si_fpqueue[0],
-		           ((sizeof(unsigned int) + (sizeof(unsigned int *))) * 16));
-	}
 	current->blocked = sf->info.si_mask & _BLOCKABLE;
 }
 
@@ -284,77 +300,80 @@
 	regs->npc = (regs->pc + 4);
 }
 
-/* To align the structure properly. */
+
+static inline void
+save_fpu_state(struct pt_regs *regs, __siginfo_fpu32_t *fpu)
+{
+#ifdef __SMP__
+	if (current->flags & PF_USEDFPU) {
+		put_psr(get_psr() | PSR_EF);
+		fpsave(&current->tss.float_regs[0], &current->tss.fsr,
+		       &current->tss.fpqueue[0], &current->tss.fpqdepth);
+		regs->psr &= ~(PSR_EF);
+		current->flags &= ~(PF_USEDFPU);
+	}
+#else
+	if (current == last_task_used_math) {
+		put_psr(get_psr() | PSR_EF);
+		fpsave(&current->tss.float_regs[0], &current->tss.fsr,
+		       &current->tss.fpqueue[0], &current->tss.fpqdepth);
+		last_task_used_math = 0;
+		regs->psr &= ~(PSR_EF);
+	}
+#endif
+	copy_to_user(&fpu->si_float_regs[0], &current->tss.float_regs[0],
+		     (sizeof(unsigned long) * 64));
+	__put_user(current->tss.fsr, &fpu->si_fsr);
+	__put_user(current->tss.fpqdepth, &fpu->si_fpqdepth);
+	if (current->tss.fpqdepth != 0)
+		copy_to_user(&fpu->si_fpqueue[0], &current->tss.fpqueue[0],
+			     ((sizeof(unsigned long) +
+			     (sizeof(unsigned long *)))*16));
+	current->used_math = 0;
+}
 
 static inline void
 new_setup_frame32(struct sigaction *sa, struct pt_regs *regs,
 		  int signo, unsigned long oldmask)
 {
 	struct new_signal_frame32 *sf;
+	int sigframe_size;
 
 	/* 1. Make sure everything is clean */
 	synchronize_user_stack();
-	sf = (struct new_signal_frame *) regs->u_regs[UREG_FP];
-	sf = (struct new_signal_frame *) (((unsigned long) sf)-NF_ALIGNEDSZ);
+	sigframe_size = NF_ALIGNEDSZ;
+	if (!current->used_math)
+		sigframe_size -= sizeof(__siginfo_fpu32_t);
+
+	sf = (struct new_signal_frame *)(regs->u_regs[UREG_FP] - sigframe_size);
 	
-	if (invalid_frame_pointer (sf, sizeof(struct new_signal_frame))){
+	if (invalid_frame_pointer (sf, sigframe_size)){
 		do_exit(SIGILL);
 		return;
 	}
 
 	if (current->tss.w_saved != 0){
-		printk ("%s[%d]: Invalid user stack frame for signal delivery.\n",
-			current->comm, current->pid);
+		printk ("%s[%d]: Invalid user stack frame for "
+			"signal delivery.\n", current->comm, current->pid);
 		do_exit (SIGILL);
 		return;
 	}
 
 	/* 2. Save the current process state */
 	memcpy (&sf->info.si_regs, regs, sizeof (struct pt_regs));
-#ifdef __SMP__
-	if(current->flags & PF_USEDFPU) {
-		put_psr(get_psr() | PSR_EF);
-		fpsave (&sf->info.si_float_regs [0], &sf->info.si_fsr,
-			&sf->info.si_fpqueue[0], &sf->info.si_fpqdepth);
-
-		/* Save a copy into thread struct as well. */
-		memcpy(&current->tss.float_regs[0], &sf->info.si_float_regs[0],
-		       (sizeof(unsigned long) * 64));
-		current->tss.fsr = sf->info.si_fsr;
-		if((current->tss.fpqdepth = sf->info.si_fpqdepth) != 0)
-		    memcpy(&current->tss.fpqueue[0], &sf->info.si_fpqueue[0],
-			   ((sizeof(unsigned long) + (sizeof(unsigned long *))) * 16));
 
-		regs->psr &= ~(PSR_EF);
-		current->flags &= ~(PF_USEDFPU);
-	}
-#else
-	if(current == last_task_used_math) {
-		put_psr(get_psr() | PSR_EF);
-		fpsave (&sf->info.si_float_regs [0], &sf->info.si_fsr,
-			&sf->info.si_fpqueue[0], &sf->info.si_fpqdepth);
-
-		/* Save a copy into thread struct as well. */
-		memcpy(&current->tss.float_regs[0], &sf->info.si_float_regs[0],
-		       (sizeof(unsigned long) * 64));
-		current->tss.fsr = sf->info.si_fsr;
-		if((current->tss.fpqdepth = sf->info.si_fpqdepth) != 0)
-		    memcpy(&current->tss.fpqueue[0], &sf->info.si_fpqueue[0],
-			   ((sizeof(unsigned long) + (sizeof(unsigned long *))) * 16));
-
-		last_task_used_math = NULL;
-		regs->psr &= ~(PSR_EF);
+	if (current->used_math) {
+		save_fpu_state(regs, &sf->fpu_state);
+		sf->fpu_save = &sf->fpu_state;
+	} else {
+		sf->fpu_save = NULL;
 	}
-#endif
-
-	/* This new thread of control has not used the FPU. */
-	current->used_math = 0;
 
 	sf->info.si_mask = oldmask;
-	memcpy (sf, (char *) regs->u_regs [UREG_FP], sizeof (struct reg_window));
+	memcpy (sf, (char *)regs->u_regs [UREG_FP], sizeof(struct reg_window));
 	
 	/* 3. return to kernel instructions */
-	sf->insns [0] = 0x821020d8; /* mov __NR_sigreturn,%g1 */
+	sf->insns [0] = 0x821020d8; /* mov __NR_sigreturn, %g1 */
 	sf->insns [1] = 0x91d02010; /* t 0x10 */
 
 	/* 4. signal handler back-trampoline and parameters */
@@ -503,7 +522,7 @@
 	gr = &mc->greg;
 	
 	/* We only have < 32 signals, fill the first slot only */
-	__put_user(current->sig->action->sa_mask, &uc->sigmask.sigbits [0]);
+	__put_user(current->blocked, &uc->sigmask.sigbits [0]);
 
 	/* Store registers */
 	__put_user(regs->pc, &uc->mcontext.greg [SVR4_PC]);
diff -u --recursive --new-file v2.1.22/linux/arch/sparc64/kernel/ttable.S linux/arch/sparc64/kernel/ttable.S
--- v2.1.22/linux/arch/sparc64/kernel/ttable.S	Tue Dec 31 21:41:01 1996
+++ linux/arch/sparc64/kernel/ttable.S	Sun Jan 26 12:07:09 1997
@@ -1,4 +1,4 @@
-/* $Id: ttable.S,v 1.3 1996/12/28 18:39:43 davem Exp $
+/* $Id: ttable.S,v 1.4 1997/01/16 13:43:24 jj Exp $
  * ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -216,6 +216,11 @@
 tl1_f5o:	FILL_5_OTHER_TL1
 tl1_f6o:	FILL_6_OTHER_TL1
 tl1_f7o:	FILL_7_OTHER_TL1
+
+#if 0
+/* Unless we are going to have software trap insns in the kernel code, we
+ * don't need this. For now we just save 8KB.
+ */
 tl1_sunos:	BTRAPTL1(0x100)
 tl1_bkpt:	BREAKPOINT_TRAP
 tl1_resv102:	BTRAPTL1(0x102)
@@ -252,3 +257,4 @@
 tl1_resv177:	BTRAPTL1(0x177) BTRAPTL1(0x178) BTRAPTL1(0x179) BTRAPTL1(0x17a)
 tl1_resv17b:	BTRAPTL1(0x17b) BTRAPTL1(0x17c)	BTRAPTL1(0x17d) BTRAPTL1(0x17e)
 tl1_resv17f:	BTRAPTL1(0x17f)
+#endif
diff -u --recursive --new-file v2.1.22/linux/arch/sparc64/mm/init.c linux/arch/sparc64/mm/init.c
--- v2.1.22/linux/arch/sparc64/mm/init.c	Tue Dec 31 21:41:01 1996
+++ linux/arch/sparc64/mm/init.c	Sun Jan 26 12:07:10 1997
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.1 1996/12/26 10:24:23 davem Exp $
+/*  $Id: init.c,v 1.2 1997/01/02 14:14:42 jj Exp $
  *  arch/sparc64/mm/init.c
  *
  *  Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -173,28 +173,16 @@
 
 void free_initmem (void)
 {
-	extern int text_init_begin, text_init_end, data_init_begin, data_init_end;
-	unsigned long addr, addrend;
-	int savec, saved;
+	extern char __init_begin, __init_end;
+	unsigned long addr;
 	
-	addr = PAGE_ALIGN((unsigned long)(&text_init_begin));
-	addrend = ((unsigned long)(&text_init_end)) & PAGE_MASK;
-	for (savec = addrend - addr; addr < addrend; addr += PAGE_SIZE) {
+	addr = (unsigned long)(&__init_begin);
+	for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
 		mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
 		mem_map[MAP_NR(addr)].count = 1;
 		free_page(addr);
 	}
-	if (savec < 0) savec = 0;
-	addr = PAGE_ALIGN((unsigned long)(&data_init_begin));
-	addrend = ((unsigned long)(&data_init_end)) & PAGE_MASK;
-	for (saved = addrend - addr; addr < addrend; addr += PAGE_SIZE) {
-		mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
-		mem_map[MAP_NR(addr)].count = 1;
-		free_page(addr);
-	}
-	if (saved < 0) saved = 0;
-	printk ("Freeing unused kernel memory: %dk code, %dk data\n",
-        	savec >> 10, saved >> 10);
+	printk ("Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10);
 }
 
 void si_meminfo(struct sysinfo *val)
diff -u --recursive --new-file v2.1.22/linux/arch/sparc64/prom/k1275d.c linux/arch/sparc64/prom/k1275d.c
--- v2.1.22/linux/arch/sparc64/prom/k1275d.c	Tue Dec 31 21:41:01 1996
+++ linux/arch/sparc64/prom/k1275d.c	Sun Jan 26 12:07:10 1997
@@ -1,4 +1,4 @@
-/* $Id: k1275d.c,v 1.1 1996/12/27 08:49:12 jj Exp $
+/* $Id: k1275d.c,v 1.2 1997/01/02 14:14:44 jj Exp $
  * k1275d.c: Sun IEEE 1275 PROM kernel daemon
  *
  * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -13,6 +13,12 @@
 
 #define p1275sect __attribute__ ((__section__ (".p1275")))
 
+static void (*prom_cif_handler)(long *) p1275sect;
+static long prom_cif_stack;
+static void (*prom_do_it)(void);
+static long prom_args [23] p1275sect;
+static char prom_buffer [4096] p1275sect;
+
 static void prom_doit (void) p1275sect;
 
 static void prom_doit (void)
@@ -33,12 +39,6 @@
 	restore;
 	" : : "r" (prom_cif_stack), "r" (prom_cif_handler));
 }
-
-static void (*prom_cif_handler)(long *) p1275sect;
-static void prom_cif_stack;
-static void (*prom_do_it)(void);
-static long prom_args [23] p1275sect;
-static char prom_buffer [4096] p1275sect;
 
 long prom_handle_command(char *service, long fmt, ...)
 {
diff -u --recursive --new-file v2.1.22/linux/arch/sparc64/vmlinux.lds linux/arch/sparc64/vmlinux.lds
--- v2.1.22/linux/arch/sparc64/vmlinux.lds	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc64/vmlinux.lds	Sun Jan 26 12:07:10 1997
@@ -0,0 +1,68 @@
+/* ld script to make UltraLinux kernel */
+OUTPUT_FORMAT("elf64-sparc", "elf64-sparc", "elf64-sparc")
+OUTPUT_ARCH(sparc:v9)
+ENTRY(_start)
+SECTIONS
+{
+  . = 0x100200 + SIZEOF_HEADERS;
+  .text 0xfffff80000008000 :
+  {
+    *(.text)
+    *(.gnu.warning)
+  } =0
+  _etext = .;
+  PROVIDE (etext = .);
+  .rodata    : { *(.rodata)  }
+  .rodata1   : { *(.rodata1) }
+  .data    :
+  {
+    *(.data)
+    CONSTRUCTORS
+  }
+  .data1   : { *(.data1) }
+  _edata  =  .;
+  PROVIDE (edata = .);
+  .fixup   : { *(.fixup) }
+  __start___ex_table = .;
+  __ex_table : { *(__ex_table) }
+  __stop___ex_table = .;
+  __start___ksymtab = .;
+  __ksymtab  : { *(__ksymtab) }
+  __stop___ksymtab = .;
+  . = ALIGN(8192);
+  __init_begin = .;
+  .text.init : { *(.text.init) }
+  .data.init : { *(.data.init) }
+  . = ALIGN(8192);
+  __init_end = .;
+  __bss_start = .;
+  .sbss      : { *(.sbss) *(.scommon) }
+  .bss       :
+  {
+   *(.dynbss)
+   *(.bss)
+   *(COMMON)
+  }
+  _end = . ;
+  PROVIDE (end = .);
+  __p1275_loc = .;
+  .p1275 0x0000000000008000 :
+  {
+	*(.p1275)
+  }
+  __p1275_end = .;
+  /* Stabs debugging sections.  */
+  .stab 0 : { *(.stab) }
+  .stabstr 0 : { *(.stabstr) }
+  .stab.excl 0 : { *(.stab.excl) }
+  .stab.exclstr 0 : { *(.stab.exclstr) }
+  .stab.index 0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment 0 : { *(.comment) }
+  .debug          0 : { *(.debug) }
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+  .line           0 : { *(.line) }
+}
diff -u --recursive --new-file v2.1.22/linux/drivers/ap1000/Makefile linux/drivers/ap1000/Makefile
--- v2.1.22/linux/drivers/ap1000/Makefile	Thu Jan  1 02:00:00 1970
+++ linux/drivers/ap1000/Makefile	Sun Jan 26 12:07:10 1997
@@ -0,0 +1,29 @@
+# File: drivers/ap1000/Makefile
+#
+# Makefile for the AP1000 drivers
+#
+
+L_TARGET := ap1000.a
+L_OBJS   := bif.o apfddi.o mac.o plc.o ringbuf.o
+
+ifeq ($(CONFIG_APBLOCK),y)
+L_OBJS += ap.o
+else
+  ifeq ($(CONFIG_APBLOCK),m)
+  M_OBJS += ap.o
+  endif
+endif
+
+ifeq ($(CONFIG_DDV),y)
+L_OBJS += ddv.o ddv_util.o
+else
+  ifeq ($(CONFIG_DDV),m)
+  M_OBJS += ddv.o ddv_util.o
+  endif
+endif
+
+include $(TOPDIR)/Rules.make
+
+clean:
+	rm -f core *.o *.a *.s
+
diff -u --recursive --new-file v2.1.22/linux/drivers/ap1000/am79c830.h linux/drivers/ap1000/am79c830.h
--- v2.1.22/linux/drivers/ap1000/am79c830.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/ap1000/am79c830.h	Sun Jan 26 12:07:10 1997
@@ -0,0 +1,276 @@
+  /*
+   * Copyright 1996 The Australian National University.
+   * Copyright 1996 Fujitsu Laboratories Limited
+   * 
+   * This software may be distributed under the terms of the Gnu
+   * Public License version 2 or later
+  */
+/*
+ * Definitions for the AM79C830 FORMAC (Fiber Optic Ring MAC) chip.
+ */
+
+typedef int	formac_reg;
+
+struct formac {
+    formac_reg	cmdreg1;	/* command register 1 */
+    formac_reg	cmdreg2;	/* command register 2 */
+#define st1u	cmdreg1		/* status reg 1, upper */
+#define st1l	cmdreg2		/* status reg 1, lower */
+    formac_reg	st2u;		/* status reg 2, upper */
+    formac_reg	st2l;		/* status reg 2, lower */
+    formac_reg	imsk1u;		/* interrupt mask 1, upper */
+    formac_reg	imsk1l;		/* interrupt mask 1, lower */
+    formac_reg	imsk2u;		/* interrupt mask 2, upper */
+    formac_reg	imsk2l;		/* interrupt mask 2, lower */
+    formac_reg	said;		/* short address, individual */
+    formac_reg	laim;		/* long adrs, indiv, MS word */
+    formac_reg	laic;		/* long adrs, indiv, middle word */
+    formac_reg	lail;		/* long adrs, indiv, LS word */
+    formac_reg	sagp;		/* short address, group */
+    formac_reg	lagm;		/* short adrs, group, MS word */
+    formac_reg	lagc;		/* short adrs, group, middle word */
+    formac_reg	lagl;		/* short adrs, group, LS word */
+    formac_reg	mdreg1;		/* mode reg 1 */
+    formac_reg	stmchn;		/* state machine reg */
+    formac_reg	mir1;		/* MAC information reg, upper */
+    formac_reg	mir0;		/* MAC information reg, lower */
+    formac_reg	tmax;		/* TMax value (2's-comp) */
+    formac_reg	tvx;		/* TVX value (2's-comp) */
+    formac_reg	trt;		/* TRT timer value */
+    formac_reg	tht;		/* THT timer value */
+    formac_reg	tneg;		/* current TNeg (2's-comp) */
+    formac_reg	tmrs;		/* extra bits of tneg, trt, tht; late count */
+    formac_reg	treq0;		/* our TReq (2's-comp), lower */
+    formac_reg	treq1;		/* our TReq (2's-comp), upper */
+    formac_reg	pri0;		/* priority reg for async queue 0 */
+    formac_reg	pri1;		/* priority reg for async queue 1 */
+    formac_reg	pri2;		/* priority reg for async queue 2 */
+    formac_reg	tsync;		/* TSync value (2's-comp) */
+    formac_reg	mdreg2;		/* mode reg 2 */
+    formac_reg	frmthr;		/* frame threshold reg */
+    formac_reg	eacb;		/* end address of claim/beacon area */
+    formac_reg	earv;		/* end address of receive area */
+    formac_reg	eas;		/* end address of sync queue */
+    formac_reg	eaa0;		/* end address of async queue 0 */
+    formac_reg	eaa1;		/* end address of async queue 1 */
+    formac_reg	eaa2;		/* end address of async queue 2 */
+    formac_reg	sacl;		/* start address of claim frame */
+    formac_reg	sabc;		/* start address of beacon frame */
+    formac_reg	wpxsf;		/* write pointer, special frames */
+    formac_reg	rpxsf;		/* read pointer, special frames */
+    formac_reg	dummy1;		/* not used */
+    formac_reg	rpr;		/* read pointer, receive */
+    formac_reg	wpr;		/* write pointer, receive */
+    formac_reg	swpr;		/* shadow write pointer, receive */
+    formac_reg	wpxs;		/* write pointer, sync queue */
+    formac_reg	wpxa0;		/* write pointer, async queue 0 */
+    formac_reg	wpxa1;		/* write pointer, async queue 1 */
+    formac_reg	wpxa2;		/* write pointer, async queue 2 */
+    formac_reg	swpxs;		/* shadow write pointer, sync queue */
+    formac_reg	swpxa0;		/* shadow write pointer, async queue 0 */
+    formac_reg	swpxa1;		/* shadow write pointer, async queue 1 */
+    formac_reg	swpxa2;		/* shadow write pointer, async queue 2 */
+    formac_reg	rpxs;		/* read pointer, sync queue */
+    formac_reg	rpxa0;		/* read pointer, async queue 0 */
+    formac_reg	rpxa1;		/* read pointer, async queue 1 */
+    formac_reg	rpxa2;		/* read pointer, async queue 2 */
+    formac_reg	marr;		/* memory address for random reads */
+    formac_reg	marw;		/* memory address for random writes */
+    formac_reg	mdru;		/* memory data register, upper */
+    formac_reg	mdrl;		/* memory data register, lower */
+    formac_reg	tmsync;		/* TSync timer value */
+    formac_reg	fcntr;		/* frame counter */
+    formac_reg	lcntr;		/* lost counter */
+    formac_reg	ecntr;		/* error counter */
+};
+
+/* Values for cmdreg1 */
+#define C1_SOFTWARE_RESET	1
+#define C1_IRMEMWI		2
+#define C1_IRMEMWO		3
+#define C1_IDLE_LISTEN		4
+#define C1_CLAIM_LISTEN		5
+#define C1_BEACON_LISTEN	6
+#define C1_LOAD_TVX		7
+#define C1_SEND_NR_TOKEN	0x0c
+#define C1_SEND_R_TOKEN		0x0d
+#define C1_ENTER_SI_MODE	0x0e
+#define C1_EXIT_SI_MODE		0x0f
+#define C1_CLR_SYNCQ_LOCK	0x11
+#define C1_CLR_ASYNCQ0_LOCK	0x12
+#define C1_CLR_ASYNCQ1_LOCK	0x14
+#define C1_CLR_ASYNCQ2_LOCK	0x18
+#define C1_CLR_RECVQ_LOCK	0x20
+#define C1_CLR_ALL_LOCKS	0x3f
+
+/* Values for cmdreg2 */
+#define C2_XMIT_SYNCQ		1
+#define C2_XMIT_ASYNCQ0		2
+#define C2_XMIT_ASYNCQ1		4
+#define C2_XMIT_ASYNCQ2		8
+#define C2_ABORT_XMIT		0x10
+#define C2_RESET_XMITQS		0x20
+#define C2_SET_TAG		0x30
+#define C2_EN_RECV_FRAME	0x40
+
+/* Bits in (st1u << 16) + st1l (and (imsk1u << 16) + imsk1l) */
+#define S1_XMIT_ABORT		0x80000000
+#define S1_XABORT_ASYNC2	0x40000000
+#define S1_XABORT_ASYNC1	0x20000000
+#define S1_XABORT_ASYNC0	0x10000000
+#define S1_XABORT_SYNC		0x08000000
+#define S1_XBUF_FULL_SYNC	0x04000000
+#define S1_XBUF_FULL_ASYNC	0x02000000
+#define S1_XDONE_SYNC		0x01000000
+#define S1_END_CHAIN_ASYNC2	0x00800000
+#define S1_END_CHAIN_ASYNC1	0x00400000
+#define S1_END_CHAIN_ASYNC0	0x00200000
+#define S1_END_CHAIN_SYNC	0x00100000
+#define S1_END_FRAME_ASYNC2	0x00080000
+#define S1_END_FRAME_ASYNC1	0x00040000
+#define S1_END_FRAME_ASYNC0	0x00020000
+#define S1_END_FRAME_SYNC	0x00010000
+#define S1_BUF_UNDERRUN_ASYNC2	0x00008000
+#define S1_BUF_UNDERRUN_ASYNC1	0x00004000
+#define S1_BUF_UNDERRUN_ASYNC0	0x00002000
+#define S1_BUF_UNDERRUN_SYNC	0x00001000
+#define S1_PAR_ERROR_ASYNC2	0x00000800
+#define S1_PAR_ERROR_ASYNC1	0x00000400
+#define S1_PAR_ERROR_ASYNC0	0x00000200
+#define S1_PAR_ERROR_SYNC	0x00000100
+#define S1_XINSTR_FULL_ASYNC2	0x00000080
+#define S1_XINSTR_FULL_ASYNC1	0x00000040
+#define S1_XINSTR_FULL_ASYNC0	0x00000020
+#define S1_XINSTR_FULL_SYNC	0x00000010
+#define S1_QUEUE_LOCK_ASYNC2	0x00000008
+#define S1_QUEUE_LOCK_ASYNC1	0x00000004
+#define S1_QUEUE_LOCK_ASYNC0	0x00000002
+#define S1_QUEUE_LOCK_SYNC	0x00000001
+
+/* Bits in (st2u << 16) + st2l (and (imsk2u << 16) + imsk2l) */
+#define S2_RECV_COMPLETE	0x80000000
+#define S2_RECV_BUF_EMPTY	0x40000000
+#define S2_RECV_ABORT		0x20000000
+#define S2_RECV_BUF_FULL	0x10000000
+#define S2_RECV_FIFO_OVF	0x08000000
+#define S2_RECV_FRAME		0x04000000
+#define S2_RECV_FRCT_OVF	0x02000000
+#define S2_NP_SIMULT_LOAD	0x01000000
+#define S2_ERR_SPECIAL_FR	0x00800000
+#define S2_CLAIM_STATE		0x00400000
+#define S2_MY_CLAIM		0x00200000
+#define S2_HIGHER_CLAIM		0x00100000
+#define S2_LOWER_CLAIM		0x00080000
+#define S2_BEACON_STATE		0x00040000
+#define S2_MY_BEACON		0x00020000
+#define S2_OTHER_BEACON		0x00010000
+#define S2_RING_OP		0x00008000
+#define S2_MULTIPLE_DA		0x00004000
+#define S2_TOKEN_ERR		0x00002000
+#define S2_TOKEN_ISSUED		0x00001000
+#define S2_TVX_EXP		0x00000800
+#define S2_TRT_EXP		0x00000400
+#define S2_MISSED_FRAME		0x00000200
+#define S2_ADDRESS_DET		0x00000100
+#define S2_PHY_INVALID		0x00000080
+#define S2_LOST_CTR_OVF		0x00000040
+#define S2_ERR_CTR_OVF		0x00000020
+#define S2_FRAME_CTR_OVF	0x00000010
+#define S2_SHORT_IFG		0x00000008
+#define S2_DUPL_CLAIM		0x00000004
+#define S2_TRT_EXP_RECOV	0x00000002
+
+/* Bits in mdreg1 */
+#define M1_SINGLE_FRAME		0x8000
+#define M1_MODE			0x7000
+#define M1_MODE_INITIALIZE	0x0000
+#define M1_MODE_MEMORY		0x1000
+#define M1_MODE_ONLINE_SP	0x2000
+#define M1_MODE_ONLINE		0x3000
+#define M1_MODE_INT_LOOP	0x4000
+#define M1_MODE_EXT_LOOP	0x7000
+#define M1_SHORT_ADRS		0x0800
+#define M1_ADDET		0x0700
+#define M1_ADDET_NORM		0x0000
+#define M1_ADDET_METOO		0x0100
+#define M1_ADDET_NSA_NOTME	0x0200
+#define M1_ADDET_NSA		0x0300
+#define M1_ADDET_DISABLE_RECV	0x0400
+#define M1_ADDET_LIM_PROMISC	0x0600
+#define M1_ADDET_PROMISC	0x0700
+#define M1_SELECT_RA		0x0080
+#define M1_DISABLE_CARRY	0x0040
+#define M1_EXT_GRP		0x0030
+#define M1_EXT_GRP_MYGRP	0x0000
+#define M1_EXT_GRP_SOFT		0x0010
+#define M1_EXT_GRP_UPPER24	0x0020
+#define M1_EXT_GRP_UPPER16	0x0030
+#define M1_LOCK_XMIT_QS		0x0008
+#define M1_FULL_DUPLEX		0x0004
+#define M1_XMTINH_PIN		0x0002
+
+/* Bits in mdreg2 */
+#define M2_TAGMODE		0x8000
+#define M2_STRIP_FCS		0x4000
+#define M2_CHECK_PARITY		0x2000
+#define M2_EVEN_PARITY		0x1000
+#define M2_LSB_FIRST		0x0800
+#define M2_RCV_BYTE_BDRY_MASK	0x0600
+#define M2_RCV_BYTE_BDRY	0x0200
+#define M2_ENABLE_HSREQ		0x0100
+#define M2_ENABLE_NPDMA		0x0080
+#define M2_SYNC_NPDMA		0x0040
+#define M2_SYMBOL_CTRL		0x0020
+#define M2_RECV_BAD_FRAMES	0x0010
+#define M2_AFULL_MASK		0x000f
+#define M2_AFULL		0x0001
+
+/* Bits in stmchn */
+#define SM_REV_MASK		0xe000
+#define SM_REV			0x2000
+#define SM_SEND_IMM_MODE	0x1000
+#define SM_TOKEN_MODE		0x0c00
+#define SM_TOKEN_MODE_NR	0x0000
+#define SM_TOKEN_MODE_ENTER_R	0x0400
+#define SM_TOKEN_MODE_ENTER_NR	0x0800
+#define SM_TOKEN_MODE_R		0x0c00
+#define SM_RCV_STATE		0x0380
+#define SM_XMIT_STATE		0x0070
+#define SM_MDR_PENDING		0x0008
+#define SM_MDR_TAG		0x0004
+
+/* Bits in transmit descriptor */
+#define TD_MORE			0x80000000
+#define TD_MAGIC		0x40000000
+#define TD_BYTE_BDRY_MASK	0x18000000
+#define TD_BYTE_BDRY_1		0x08000000
+#define TD_XMIT_DONE		0x04000000
+#define TD_NO_FCS		0x02000000
+#define TD_XMIT_ABORT		0x01000000
+#define TD_BYTE_BDRY_LG		27
+
+/* Bits in pointer in buffer memory (nontag mode) */
+#define PT_MAGIC		0xa0000000
+
+/* Bits in receive status word */
+#define RS_VALID		0x80000000
+#define RS_ABORTED		0x40000000
+#define RS_SRC_ROUTE		0x10000000
+#define RS_E_INDIC		0x08000000
+#define RS_A_INDIC		0x04000000
+#define RS_C_INDIC		0x02000000
+#define RS_ERROR		0x01000000
+#define RS_ADDR_MATCH		0x00800000
+#define RS_FRAME_TYPE		0x00700000
+#define RS_FT_SMT		0x00000000
+#define RS_FT_LLC		0x00100000
+#define RS_FT_IMPL		0x00200000
+#define RS_FT_MAC		0x00400000
+#define RS_FT_LLC_SYNC		0x00500000
+#define RS_FT_IMPL_SYNC		0x00600000
+#define RS_BYTE_BDRY_MASK	0x00030000
+#define RS_BYTE_BDRY		0x00010000
+#define RS_BYTE_BDRY_LG		16
+
+#define RS_LENGTH		0x0000ffff
+
diff -u --recursive --new-file v2.1.22/linux/drivers/ap1000/am79c864.h linux/drivers/ap1000/am79c864.h
--- v2.1.22/linux/drivers/ap1000/am79c864.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/ap1000/am79c864.h	Sun Jan 26 12:07:10 1997
@@ -0,0 +1,162 @@
+  /*
+   * Copyright 1996 The Australian National University.
+   * Copyright 1996 Fujitsu Laboratories Limited
+   * 
+   * This software may be distributed under the terms of the Gnu
+   * Public License version 2 or later
+  */
+/*
+ * Definitions for Am79c864 PLC (Physical Layer Controller)
+ */
+
+typedef int	plc_reg;
+
+struct plc {
+    plc_reg	ctrl_a;
+    plc_reg	ctrl_b;
+    plc_reg	intr_mask;
+    plc_reg	xmit_vector;
+    plc_reg	vec_length;
+    plc_reg	le_threshold;
+    plc_reg	c_min;
+    plc_reg	tl_min;
+    plc_reg	tb_min;
+    plc_reg	t_out;
+    plc_reg	dummy1;
+    plc_reg	lc_length;
+    plc_reg	t_scrub;
+    plc_reg	ns_max;
+    plc_reg	tpc_load;
+    plc_reg	tne_load;
+    plc_reg	status_a;
+    plc_reg	status_b;
+    plc_reg	tpc;
+    plc_reg	tne;
+    plc_reg	clk_div;
+    plc_reg	bist_sig;
+    plc_reg	rcv_vector;
+    plc_reg	intr_event;
+    plc_reg	viol_sym_ct;
+    plc_reg	min_idle_ct;
+    plc_reg	link_err_ct;
+};
+
+/* Bits in ctrl_a */
+#define CA_NOISE_TIMER		0x4000
+#define CA_TNE_16BIT		0x2000
+#define CA_TPC_16BIT		0x1000
+#define CA_REQ_SCRUB		0x0800
+#define CA_VSYM_INTR_MODE	0x0200
+#define CA_MINI_INTR_MODE	0x0100
+#define CA_LOOPBACK		0x0080
+#define CA_FOT_OFF		0x0040
+#define CA_EB_LOOP		0x0020
+#define CA_LM_LOOP		0x0010
+#define CA_BYPASS		0x0008
+#define CA_REM_LOOP		0x0004
+#define CA_RF_DISABLE		0x0002
+#define CA_RUN_BIST		0x0001
+
+/* Bits in ctrl_b */
+#define CB_CONFIG_CTRL		0x8000
+#define CB_MATCH_LS		0x7800
+#define CB_MATCH_LS_ANY		0x0000
+#define CB_MATCH_LS_QLS		0x4000
+#define CB_MATCH_LS_MLS		0x2000
+#define CB_MATCH_LS_HLS		0x1000
+#define CB_MATCH_LS_ILS		0x0800
+#define CB_MAINT_LS		0x0700
+#define CB_MAINT_LS_QLS		0x0000
+#define CB_MAINT_LS_ILS		0x0100
+#define CB_MAINT_LS_HLS		0x0200
+#define CB_MAINT_LS_MLS		0x0300
+#define CB_MAINT_LS_PDR		0x0600
+#define CB_CLASS_S		0x0080
+#define CB_PC_LCT		0x0060
+#define CB_PC_LCT_NONE		0x0000
+#define CB_PC_LCT_PDR		0x0020
+#define CB_PC_LCT_IDLE		0x0040
+#define CB_PC_LCT_LOOP		0x0060
+#define CB_PC_JOIN		0x0010
+#define CB_LONG_LCT		0x0008
+#define CB_PC_MAINT		0x0004
+#define CB_PCM_CTRL		0x0003
+#define CB_PC_START		0x0001
+#define CB_PC_TRACE		0x0002
+#define CB_PC_STOP		0x0003
+
+/* Bits in status_a */
+#define SA_SIG_DETECT		0x0400
+#define SA_PREV_LS		0x0300
+#define SA_PREV_LS_QLS		0x0000
+#define SA_PREV_LS_MLS		0x0100
+#define SA_PREV_LS_HLS		0x0200
+#define SA_PREV_LS_ILS		0x0300
+#define SA_LINE_ST		0x00e0
+#define SA_LINE_ST_NLS		0x0000
+#define SA_LINE_ST_ALS		0x0020
+#define SA_LINE_ST_ILS4		0x0060
+#define SA_LINE_ST_QLS		0x0080
+#define SA_LINE_ST_MLS		0x00a0
+#define SA_LINE_ST_HLS		0x00c0
+#define SA_LINE_ST_ILS		0x00e0
+#define SA_LSM_STATE		0x0010
+#define SA_UNKN_LINE_ST		0x0008
+#define SA_SYM_PAIR_CTR		0x0007
+
+/* Bits in status_b */
+#define SB_RF_STATE		0xc000
+#define SB_RF_STATE_REPEAT	0x0000
+#define SB_RF_STATE_IDLE	0x4000
+#define SB_RF_STATE_HALT1	0x8000
+#define SB_RF_STATE_HALT2	0xc000
+#define SB_PCI_STATE		0x3000
+#define SB_PCI_STATE_REMOVED	0x0000
+#define SB_PCI_STATE_INS_SCR	0x1000
+#define SB_PCI_STATE_REM_SCR	0x2000
+#define SB_PCI_STATE_INSERTED	0x3000
+#define SB_PCI_SCRUB		0x0800
+#define SB_PCM_STATE		0x0780
+#define SB_PCM_STATE_OFF	0x0000
+#define SB_PCM_STATE_BREAK	0x0080
+#define SB_PCM_STATE_TRACE	0x0100
+#define SB_PCM_STATE_CONNECT	0x0180
+#define SB_PCM_STATE_NEXT	0x0200
+#define SB_PCM_STATE_SIGNAL	0x0280
+#define SB_PCM_STATE_JOIN	0x0300
+#define SB_PCM_STATE_VERIFY	0x0380
+#define SB_PCM_STATE_ACTIVE	0x0400
+#define SB_PCM_STATE_MAIN	0x0480
+#define SB_PCM_SIGNALING	0x0040
+#define SB_LSF			0x0020
+#define SB_RCF			0x0010
+#define SB_TCF			0x0008
+#define SB_BREAK_REASON		0x0007
+#define SB_BREAK_REASON_NONE	0x0000
+#define SB_BREAK_REASON_START	0x0001
+#define SB_BREAK_REASON_T_OUT	0x0002
+#define SB_BREAK_REASON_NS_MAX	0x0003
+#define SB_BREAK_REASON_QLS	0x0004
+#define SB_BREAK_REASON_ILS	0x0005
+#define SB_BREAK_REASON_HLS	0x0006
+
+/* Bits in intr_event and intr_mask */
+#define IE_NP_ERROR		0x8000
+#define IE_SIGNAL_OFF		0x4000
+#define IE_LE_CTR		0x2000
+#define IE_MINI_CTR		0x1000
+#define IE_VSYM_CTR		0x0800
+#define IE_PHY_INVALID		0x0400
+#define IE_EBUF_ERR		0x0200
+#define IE_TNE_EXP		0x0100
+#define IE_TPC_EXP		0x0080
+#define IE_PCM_ENABLED		0x0040
+#define IE_PCM_BREAK		0x0020
+#define IE_SELF_TEST		0x0010
+#define IE_TRACE_PROP		0x0008
+#define IE_PCM_CODE		0x0004
+#define IE_LS_MATCH		0x0002
+#define IE_PARITY_ERR		0x0001
+
+/* Correct value for BIST signature */
+#define BIST_CORRECT		0x6ecd
diff -u --recursive --new-file v2.1.22/linux/drivers/ap1000/ap.c linux/drivers/ap1000/ap.c
--- v2.1.22/linux/drivers/ap1000/ap.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/ap1000/ap.c	Sun Jan 26 12:07:10 1997
@@ -0,0 +1,318 @@
+  /*
+   * Copyright 1996 The Australian National University.
+   * Copyright 1996 Fujitsu Laboratories Limited
+   * 
+   * This software may be distributed under the terms of the Gnu
+   * Public License version 2 or later
+  */
+/* 
+ * ap.c - Single AP1000 block driver.
+ *
+ * (C) dwalsh, Pious project, DCS, ANU 1996
+ *
+ * This block driver is designed to simply to perform
+ * io operations to the hosts file system. 
+ *
+ * Heavily modified by tridge
+ *
+ */
+
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/ext2_fs.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/module.h>
+#include <asm/uaccess.h>
+#include <asm/ap1000/apservice.h>
+
+#define AP_DEBUG 0
+
+#define MAJOR_NR APBLOCK_MAJOR
+#define AP_DRIVER 1
+#include <linux/blk.h>
+
+#define NUM_APDEVS 8
+#define MAX_REQUESTS 1
+
+static struct wait_queue * busy_wait = NULL;
+
+static int ap_blocksizes[NUM_APDEVS];
+static int ap_length[NUM_APDEVS];
+static int ap_fds[NUM_APDEVS];
+
+#define SECTOR_BLOCK_SHIFT 9
+#define AP_BLOCK_SHIFT 12 /* 4k blocks */
+#define AP_BLOCK_SIZE (1<<AP_BLOCK_SHIFT)
+
+static volatile int request_count = 0;
+
+#ifdef MODULE
+static void ap_release(struct inode * inode, struct file * filp)
+{
+	MOD_DEC_USE_COUNT;
+}
+#endif
+
+static void ap_request(void)
+{
+  struct cap_request creq;
+  unsigned int minor;
+  int offset, len;
+  struct request *req;
+
+  if (request_count >= MAX_REQUESTS) return;
+
+repeat:  
+
+  if (!CURRENT) {
+    return;
+  }
+
+  if (MAJOR(CURRENT->rq_dev) != MAJOR_NR) {
+    panic(DEVICE_NAME ": request list destroyed");
+  }
+  if (CURRENT->bh) {
+    if (!buffer_locked(CURRENT->bh)) {
+      panic(DEVICE_NAME ": block not locked");
+    }
+  }
+
+  req = CURRENT;
+
+  minor = MINOR(req->rq_dev);
+
+  if (minor >= NUM_APDEVS) {
+    printk("apblock: request for invalid minor %d\n",minor);
+    end_request(0);
+    goto repeat;
+  }
+
+  offset = req->sector;
+  len = req->current_nr_sectors;
+
+  if ((offset + len) > ap_length[minor]) {
+    printk("apblock: request for invalid sectors %d -> %d\n",
+	   offset,offset+len);
+    end_request(0);
+    goto repeat;
+  }
+
+  if (ap_fds[minor] == -1) {
+    printk("apblock: minor %d not open\n",minor);
+    end_request(0);
+    goto repeat;
+  }
+
+  /* convert to our units */
+  offset <<= SECTOR_BLOCK_SHIFT;
+  len <<= SECTOR_BLOCK_SHIFT;
+  
+  /* setup a request for the host */
+  creq.cid = mpp_cid();
+  creq.size = sizeof(creq);
+  creq.header = 0;
+  creq.data[0] = (int)(req);
+  creq.data[1] = ap_fds[minor];
+  creq.data[2] = offset;
+  creq.data[3] = len;
+
+  switch (req->cmd) {
+  case READ:
+#if AP_DEBUG
+    printk("apblock: read req=0x%x len=%d offset=%d\n",
+	   req,len,offset);
+#endif
+    creq.type = REQ_BREAD;
+    if (bif_queue(&creq,0,0)) {
+      return;
+    }
+    break;
+
+  case WRITE:
+#if AP_DEBUG
+    printk("apblock: write req=0x%x len=%d offset=%d\n",
+	   req,len,offset);
+#endif
+    creq.type = REQ_BWRITE;
+    creq.size += len;
+    if (bif_queue_nocopy(&creq,req->buffer,creq.size - sizeof(creq))) {
+      return;
+    }
+    break;
+
+  default:
+    printk("apblock: unknown ap op %d\n",req->cmd);
+    end_request(0);
+    return;
+  }
+
+  if (++request_count < MAX_REQUESTS)
+    goto repeat;
+}
+
+/* this is called by ap1000/bif.c when a read/write has completed */
+void ap_complete(struct cap_request *creq)
+{  
+#if AP_DEBUG
+  struct request *req = (struct request *)(creq->data[0]);
+
+  printk("request 0x%x complete\n",req);
+#endif
+  end_request(1);
+  request_count--;
+  ap_request();
+}
+
+
+/* this is called by ap1000/bif.c to find a buffer to put a BREAD into 
+ using DMA */
+char *ap_buffer(struct cap_request *creq)
+{  
+  struct request *req = (struct request *)(creq->data[0]);
+
+  return(req->buffer);
+}
+
+
+static int ap_open(struct inode * inode, struct file * filp)
+{
+  struct cap_request creq;
+  int minor;
+  minor =  DEVICE_NR(inode->i_rdev);
+  
+#if AP_DEBUG
+  printk("ap_open: minor=%x\n", minor);
+#endif
+
+  if (minor >= NUM_APDEVS)
+    return -ENODEV;
+
+  /* if its already open then don't do anything */
+  if (ap_fds[minor] != -1)
+    return 0;
+
+  /* send the open request to the front end */
+  creq.cid = mpp_cid();
+  creq.type = REQ_BOPEN;
+  creq.header = 0;
+  creq.size = sizeof(creq);
+  creq.data[0] = minor;
+
+  bif_queue(&creq,0,0);
+
+  /* wait for the reply */
+  while (ap_fds[minor] == -1)
+    sleep_on(&busy_wait);
+
+  return 0;
+}
+
+
+static int ap_ioctl(struct inode *inode, struct file *file, 
+		    unsigned int cmd, unsigned long arg)
+{
+	if (!inode || !inode->i_rdev) 	
+		return -EINVAL;
+
+	switch (cmd) {
+	case BLKGETSIZE:   /* Return device size */
+		if (put_user(ap_length[MINOR(inode->i_rdev)],(long *) arg))
+			return -EFAULT;
+		return 0;
+    
+	default:
+		break;
+	};
+	
+	return 0;
+}
+
+
+/* this is called by ap1000/bif.c when a open reply comes in */
+void ap_open_reply(struct cap_request *creq)
+{
+  int minor = creq->data[0];
+
+  ap_fds[minor] = creq->data[1];
+  ap_length[minor] = creq->data[2] >> SECTOR_BLOCK_SHIFT;
+
+#if AP_DEBUG
+  printk("ap opened minor %d length=%d fd=%d\n",
+	 minor,ap_length[minor],ap_fds[minor]);
+#endif
+
+  wake_up(&busy_wait);  
+} 
+
+static struct file_operations ap_fops = {
+        NULL,                   /* lseek - default */
+        block_read,             /* read - general block-dev read */
+        block_write,            /* write - general block-dev write */
+        NULL,                   /* readdir - bad */
+        NULL,                   /* poll */
+        ap_ioctl,               /* ioctl */
+        NULL,                   /* mmap */
+        ap_open,                /* open */
+#ifndef MODULE
+	NULL,		/* no special release code... */
+#else
+	ap_release,	/* module needs to decrement use count */
+#endif
+        block_fsync,            /* fsync */
+};
+
+
+int ap_init(void)
+{
+  int i;
+  static int done = 0;
+
+  if (done) return(1);
+
+  if (register_blkdev(MAJOR_NR,"apblock",&ap_fops)) {
+    printk("ap: unable to get major %d for ap block dev\n",MAJOR_NR);
+    return -1;
+  }
+  printk("ap_init: register dev %d\n", MAJOR_NR);
+  blk_dev[MAJOR_NR].request_fn = &ap_request;
+
+  for (i=0;i<NUM_APDEVS;i++) {
+    ap_blocksizes[i] = AP_BLOCK_SIZE;
+    ap_length[i] = 0;
+    ap_fds[i] = -1;
+  }
+
+  blksize_size[MAJOR_NR] = ap_blocksizes;
+
+  read_ahead[MAJOR_NR] = 32; /* 16k read ahead */
+
+  return(0);
+}
+
+/* loadable module support */
+
+#ifdef MODULE
+
+int init_module(void)
+{
+	int error = ap_init();
+	if (!error)
+		printk(KERN_INFO "APBLOCK: Loaded as module.\n");
+	return error;
+}
+
+/* Before freeing the module, invalidate all of the protected buffers! */
+void cleanup_module(void)
+{
+	int i;
+
+	for (i = 0 ; i < NUM_APDEVS; i++)
+		invalidate_buffers(MKDEV(MAJOR_NR, i));
+
+	unregister_blkdev( MAJOR_NR, "apblock" );
+	blk_dev[MAJOR_NR].request_fn = 0;
+}
+
+#endif  /* MODULE */
diff -u --recursive --new-file v2.1.22/linux/drivers/ap1000/apfddi-reg.h linux/drivers/ap1000/apfddi-reg.h
--- v2.1.22/linux/drivers/ap1000/apfddi-reg.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/ap1000/apfddi-reg.h	Sun Jan 26 12:07:10 1997
@@ -0,0 +1,14 @@
+  /*
+   * Copyright 1996 The Australian National University.
+   * Copyright 1996 Fujitsu Laboratories Limited
+   * 
+   * This software may be distributed under the terms of the Gnu
+   * Public License version 2 or later
+  */
+/* FDDI register pointers */
+extern volatile struct formac *mac;
+extern volatile struct plc *plc;
+extern volatile int *csr0;
+extern volatile int *csr1;
+extern volatile int *buffer_mem;
+extern volatile int *fifo;
diff -u --recursive --new-file v2.1.22/linux/drivers/ap1000/apfddi.c linux/drivers/ap1000/apfddi.c
--- v2.1.22/linux/drivers/ap1000/apfddi.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/ap1000/apfddi.c	Sun Jan 26 12:07:10 1997
@@ -0,0 +1,702 @@
+  /*
+   * Copyright 1996 The Australian National University.
+   * Copyright 1996 Fujitsu Laboratories Limited
+   * 
+   * This software may be distributed under the terms of the Gnu
+   * Public License version 2 or later
+  */
+/*
+ * $Id: apfddi.c,v 1.6 1996/12/18 01:45:51 tridge Exp $
+ *
+ * Network interface definitions for AP1000 fddi device.
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/fs.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/socket.h>
+#include <linux/errno.h>
+#include <linux/fcntl.h>
+#include <linux/in.h>
+#include <linux/if_ether.h>	/* For the statistics structure. */
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/io.h>
+
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+
+#include <asm/ap1000/apservice.h>
+#include <asm/ap1000/apreg.h>
+#include <asm/irq.h>
+
+#include <net/arp.h>
+
+#include "apfddi.h"
+#include "smt-types.h"
+#include "mac.h"
+#include "plc.h"
+#include "am79c830.h"
+#include "apfddi-reg.h"
+
+volatile struct formac *mac;
+volatile struct plc *plc;
+volatile int *csr0;
+volatile int *csr1;
+volatile int *buffer_mem;
+volatile int *fifo;
+
+#define APFDDI_DEBUG 0
+
+#define APFDDI_IRQ    7
+
+#define T(x)	(-SECS_TO_FDDI_TIME(x))
+
+struct plc_info plc_info = {
+    pt_s,			/* port_type */
+    T(1.6e-3),			/* c_min */
+    T(50e-6),			/* tl_min */
+    T(5e-3),			/* tb_min */
+    T(100e-3),			/* t_out */
+    T(50e-3),			/* lc_short */
+    T(500e-3),			/* lc_medium */
+    T(5.0),			/* lc_long */
+    T(50.0),			/* lc_extended */
+    T(3.5e-3),			/* t_scrub */
+    T(1.3e-3),			/* ns_max */
+};
+
+struct mac_info mac_info = {
+    T(165e-3),			/* tmax */
+    T(3.5e-3),			/* tvx */
+    T(20e-3),			/* treq */
+    { 0x42, 0x59 },		/* s_address */
+    { 0x42, 0x59, 0x10, 0x76, 0x88, 0x82 },	/* l_address */
+    { 0 },			/* s_group_adrs */
+    { 0 },			/* l_group_adrs */
+    0,				/* rcv_own_frames */
+    1,				/* only_good_frames */
+};
+
+u_char fddi_bitrev[256] = {
+    0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+    0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+    0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+    0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+    0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+    0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+    0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+    0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+    0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+    0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+    0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+    0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+    0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+    0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+    0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+    0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+    0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+    0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+    0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+    0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+    0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+    0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+    0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+    0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+    0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+    0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+    0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+    0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+    0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+    0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+    0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+    0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
+};
+
+/* XXX our hardware address, canonical bit order */
+static u_char apfddi_saddr[6] = { 0x42, 0x9a, 0x08, 0x6e, 0x11, 0x41 };
+
+struct device *apfddi_device = NULL;
+struct enet_statistics *apfddi_stats = NULL;
+
+volatile struct apfddi_queue *apfddi_queue_top = NULL;
+
+void map_regs(void)
+{
+    unsigned long reg_base_addr = 0xfbf00000;
+
+    mac = (volatile struct formac *) (reg_base_addr + FORMAC);
+    plc = (volatile struct plc *) (reg_base_addr + PLC);
+    csr0 = (volatile int *) (reg_base_addr + CSR0);
+    csr1 = (volatile int *) (reg_base_addr + CSR1);
+    buffer_mem = (volatile int *) (reg_base_addr + BUFFER_MEM);
+    fifo = (volatile int *) (reg_base_addr + FIFO);
+}
+
+int ring_op;
+
+void apfddi_startup(void)
+{
+    int reason;
+
+#if APFDDI_DEBUG
+    printk("In apfddi_startup\n");
+#endif
+
+    *csr0 = CS0_LED0;
+    ring_op = 0;
+    if (*csr1 & 0xf078) {
+	*csr1 = CS1_RESET_MAC | CS1_RESET_FIFO;
+	*csr1 = 0;
+	reason = 1;
+	printk("resetting after power-on\n");
+    } else {
+	*csr1 = CS1_RESET_FIFO;
+	*csr1 = 0;
+	reason = plc_inited(&plc_info);
+	if (reason)
+	    printk("resetting: plc reason %d\n", reason);
+    }
+    if (reason) {
+#if APFDDI_DEBUG
+	printk("Calling plc_init\n");
+#endif
+	plc_init(&plc_info);
+#if APFDDI_DEBUG
+	printk("Calling mac_init\n");
+#endif
+	mac_init(&mac_info);
+	*csr0 |= CS0_LED1;
+	pc_start(loop_none);
+
+    } else {
+	*csr0 |= CS0_LED2 | CS0_LED1;
+	reason = mac_inited(&mac_info);
+	if (reason) {
+	    printk("resetting mac: reason %d\n", reason);
+	    mac_init(&mac_info);
+	    mac_reset(loop_none);
+	    mac_claim();
+	} else {
+	    ring_op = 1;
+	    *csr0 &= ~(CS0_LED0 | CS0_LED1 | CS0_LED2);
+	}
+    }
+}
+
+void apfddi_off(void)
+{
+    *csr0 &= ~CS0_LED1;
+    pc_stop();
+}
+
+void apfddi_sleep(void)
+{
+    mac_sleep();
+    plc_sleep();
+}
+
+void apfddi_poll(void)
+{
+    if (*csr0 & CS0_PHY_IRQ)
+	plc_poll();
+    if (*csr0 & CS0_MAC_IRQ)
+	mac_poll();
+}
+
+void set_cf_join(int on)
+{
+    if (on) {
+#if APFDDI_DEBUG
+	printk("apfddi: joined the ring!\n");
+#endif
+	mac_reset(loop_none);
+	*csr0 |= CS0_LED2;
+	mac_claim();
+    } else {
+	mac_disable();
+	ring_op = 0;
+	*csr0 = (*csr0 & ~CS0_LED2) | CS0_LED1 | CS0_LED0;
+    }
+}
+
+void set_ring_op(int up)
+{
+    ring_op = up;
+    if (up) {
+#if APFDDI_DEBUG
+	printk("apfddi: ring operational!\n");
+#endif
+	*csr0 &= ~(CS0_LED2 | CS0_LED1 | CS0_LED0);
+    } else
+	*csr0 |= CS0_LED2 | CS0_LED1 | CS0_LED0;
+}
+
+void rmt_event(int st)
+{
+    if (st & (S2_BEACON_STATE|S2_MULTIPLE_DA|S2_TOKEN_ERR
+	      |S2_DUPL_CLAIM|S2_TRT_EXP_RECOV)) {
+	printk("st2 = %x\n", st);
+    }
+}
+
+
+int apfddi_init(struct device *dev);
+static void apfddi_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static int apfddi_xmit(struct sk_buff *skb, struct device *dev);
+int apfddi_rx(struct mac_buf *mbuf);
+static struct enet_statistics *apfddi_get_stats(struct device *dev);
+#if APFDDI_DEBUG
+void dump_packet(char *action, char *buf, int len, int seq);
+#endif
+
+/*
+ * Create FDDI header for an arbitrary protocol layer
+ *
+ * saddr=NULL means use device source address (always will anyway)
+ * daddr=NULL means leave destination address (eg unresolved arp)
+ */
+static int apfddi_hard_header(struct sk_buff *skb, struct device *dev,
+			      unsigned short type, void *daddr,
+			      void *saddr, unsigned len)
+{
+    struct fddi_header *fh;
+    struct llc_header *lh;
+    u_char *base_header;
+    u_char *fd_daddr = (u_char *)daddr;
+    int i;
+
+#if APFDDI_DEBUG
+    printk("In apfddi_hard_header\n");
+#endif
+
+    if (skb == NULL) {
+	printk("Null skb in apfddi_hard_header... returning...\n");
+	return 0;
+    }
+
+    switch(type) {
+    case ETH_P_IP:
+#if APFDDI_DEBUG
+	printk("apfddi_hard_header: Processing IP packet\n");
+#endif
+	break;
+    case ETH_P_ARP:
+#if APFDDI_DEBUG
+	printk("apfddi_hard_header: Processing ARP packet\n");
+#endif
+	break;
+    case ETH_P_RARP:
+#if APFDDI_DEBUG
+	printk("apfddi_hard_header: Processing RARP packet\n");
+#endif
+	break;
+    default:
+	printk("apfddi_hard_header: I don't understand protocol %d (0x%x)\n",
+	       type, type);
+	apfddi_stats->tx_errors++;
+	return 0;
+    }
+
+    base_header = (u_char *)skb_push(skb, FDDI_HARDHDR_LEN-4);
+    if (base_header == NULL) {
+	printk("apfddi_hard_header: Memory squeeze, dropping packet.\n");
+	apfddi_stats->tx_dropped++;
+	return 0;
+    }
+    fh = (struct fddi_header *)(base_header + 3);
+    lh = (struct llc_header *)((char *)fh + FDDI_HDRLEN);
+
+    lh->llc_dsap = lh->llc_ssap = LLC_SNAP_LSAP;
+    lh->snap_control = LLC_UI;
+    lh->snap_org_code[0] = 0;
+    lh->snap_org_code[1] = 0;
+    lh->snap_org_code[2] = 0;
+    lh->snap_ether_type = htons(type);
+
+#if APFDDI_DEBUG
+    printk("snap_ether_type is %d (0x%x)\n", lh->snap_ether_type,
+	   lh->snap_ether_type);
+#endif
+    
+    fh->fddi_fc = FDDI_FC_LLC;
+    
+    /*
+     * Fill in the source address.
+     */
+    for (i = 0; i < 6; i++)
+	fh->fddi_shost[i] = fddi_bitrev[apfddi_saddr[i]];
+    
+    /*
+     * Fill in the destination address.
+     */
+    if (daddr) {
+#if APFDDI_DEBUG
+	printk("daddr is: ");
+#endif
+	for (i = 0; i < 6; i++) {
+	    fh->fddi_dhost[i] = fddi_bitrev[fd_daddr[i]];
+#if APFDDI_DEBUG
+	    printk("%x(%x):",fh->fddi_dhost[i], fd_daddr[i]);
+#endif
+	}
+#if APFDDI_DEBUG
+	printk("\n");
+#endif
+	return(FDDI_HARDHDR_LEN-4);
+    }
+    else {
+#if APFDDI_DEBUG
+	printk("apfddi_hard_header, daddr was NULL\n");
+#endif
+	return -(FDDI_HARDHDR_LEN-4);
+    }
+}
+
+/*
+ * Rebuild the FDDI header. This is called after an ARP (or in future
+ * other address resolution) has completed on this sk_buff. We now let
+ * ARP fill in the other fields.  
+ */
+static int apfddi_rebuild_header(void *buff, struct device *dev,
+				 unsigned long raddr, struct sk_buff *skb)
+{
+    int i, status;
+    struct fddi_header *fh = (struct fddi_header *)(buff+3);
+
+#if APFDDI_DEBUG
+    printk("In apfddi_rebuild_header, dev is %x apfddi_device is %x\n", dev,
+	   apfddi_device);
+    printk("rebuild header for fc 0x%x\n", fh->fddi_fc);
+    printk("dest address is:\n");
+    for (i = 0; i < 6; i++) printk("%x:", fh->fddi_dhost[i]);
+#endif
+    status = arp_find(raddr, skb) ? 1 : 0;
+    
+    if (!status) {
+#if APFDDI_DEBUG
+	printk("dest address is now:\n");
+	for (i = 0; i < 6; i++) printk("%x:", fh->fddi_dhost[i]);
+	printk("status is %d\n", status);
+#endif
+	/*
+	 * Bit reverse the dest_address.
+	 */
+	for (i = 0; i < 6; i++)
+	    fh->fddi_dhost[i] = fddi_bitrev[fh->fddi_dhost[i]];
+    }
+#if APFDDI_DEBUG    
+    printk("\n");
+#endif
+    return(status);
+}
+
+static int apfddi_set_mac_address(struct device *dev, void *addr)
+{
+#if APFDDI_DEBUG
+    printk("In apfddi_set_mac_address\n");
+#endif
+    return (0);
+}
+
+static void apfddi_set_multicast_list(struct device *dev)
+{
+#if APFDDI_DEBUG
+    printk("In apfddi_set_multicast_list\n");
+#endif
+}
+
+static int apfddi_do_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
+{
+#if APFDDI_DEBUG
+    printk("In apfddi_do_ioctl\n");
+#endif
+    return (0);
+}
+
+static int apfddi_set_config(struct device *dev, struct ifmap *map)
+{
+#if APFDDI_DEBUG
+    printk("In apfddi_set_config\n");
+#endif
+    return (0);
+}
+
+/*
+ * Opening the fddi device through ifconfig.
+ */
+int apfddi_open(struct device *dev)
+{
+    static int already_run = 0;
+    unsigned flags;
+    int res;
+
+    if (already_run) {
+	apfddi_startup();
+	*csr0 |= CS0_INT_ENABLE;
+	return 0;
+    }
+    already_run = 1;
+
+    map_regs();
+    apfddi_startup();
+
+    save_flags(flags); cli();
+    if ((res = request_irq(APFDDI_IRQ, apfddi_interrupt, SA_INTERRUPT, 
+			   "apfddi", dev))) {
+	printk("Failed to install apfddi handler error=%d\n", res);
+	restore_flags(flags);
+	return(0);
+    }
+    enable_irq(APFDDI_IRQ);
+    restore_flags(flags);
+
+#if APFDDI_DEBUG
+    printk("Installed apfddi interrupt handler\n");
+#endif
+    *csr0 |= CS0_INT_ENABLE;
+#if APFDDI_DEBUG
+    printk("Enabled fddi interrupts\n");
+#endif
+    
+    return 0;
+}
+
+/*
+ * Stop the fddi device through ifconfig.
+ */
+int apfddi_stop(struct device *dev)
+{
+    *csr0 &= ~CS0_INT_ENABLE;
+    apfddi_sleep();
+    return 0;
+}
+
+
+/*
+ * Initialise fddi network interface.
+ */
+int apfddi_init(struct device *dev)
+{
+    int i;
+    printk("apfddi_init(): Initialising fddi interface\n");
+
+    apfddi_device = dev;
+
+    dev->open = apfddi_open;
+    dev->stop = apfddi_stop;
+    dev->hard_start_xmit = apfddi_xmit;
+    dev->get_stats = apfddi_get_stats;
+    dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_ATOMIC); 
+    if (dev->priv == NULL)
+	return -ENOMEM;
+    memset(dev->priv, 0, sizeof(struct enet_statistics)); 
+    apfddi_stats = (struct enet_statistics *)apfddi_device->priv;
+
+    /* Initialise the fddi device structure */
+    for (i = 0; i < DEV_NUMBUFFS; i++)
+	skb_queue_head_init(&dev->buffs[i]);
+    
+    dev->hard_header = apfddi_hard_header;
+    dev->rebuild_header	= apfddi_rebuild_header;
+    dev->set_mac_address = apfddi_set_mac_address;
+    dev->header_cache_update = NULL;
+    dev->do_ioctl = apfddi_do_ioctl;    
+    dev->set_config = apfddi_set_config;
+    dev->set_multicast_list = apfddi_set_multicast_list;
+    dev->type = ARPHRD_ETHER;
+    dev->hard_header_len = FDDI_HARDHDR_LEN;
+    dev->mtu = FDDIMTU;
+    dev->addr_len = 6;
+    memcpy(dev->dev_addr, apfddi_saddr, sizeof(apfddi_saddr));
+    dev->tx_queue_len = 100;    /* XXX What should this be? */
+    dev->irq = APFDDI_IRQ;
+
+    memset(dev->broadcast, 0xFF, ETH_ALEN);
+    
+    dev->family = AF_INET;
+    dev->pa_addr = in_aton("150.203.142.28");  /* hibana-f */
+    dev->pa_mask = in_aton("255.255.255.0");
+    dev->pa_brdaddr = dev->pa_addr | ~dev->pa_mask;
+    dev->pa_alen = 4;
+
+    return(0);
+}
+
+static void apfddi_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+#if APFDDI_DEBUG
+    static int times = 0;
+#endif
+    unsigned flags;
+    save_flags(flags); cli();
+    
+#if APFDDI_DEBUG
+    printk("In apfddi_interrupt irq %d dev_id %p times %d\n",
+	   irq, dev_id, ++times);
+#endif
+    
+    apfddi_poll();
+    restore_flags(flags);
+}
+
+#if APFDDI_DEBUG
+static char *flagbits[8] = {
+    "fin", "syn", "rst", "push", "ack", "urg", "6", "7"
+};
+
+void dump_packet(action, buf, len, seq)
+    char *action, *buf;
+    int len, seq;
+{
+    int i, flags;
+    char *sep;
+
+    printk("%s packet %d of %d bytes at %d:\n", action, seq,
+	   len, jiffies);
+    printk("  from %x to %x pktid=%d ttl=%d pcol=%d len=%d\n",
+	   *(long *)(buf+12), *(long *)(buf+16), *(u_short *)(buf+4),
+	   *(unsigned char *)(buf+8), buf[9], *(u_short *)(buf+2));
+    if( buf[9] == 6 || buf[9] == 17 ){
+	/* TCP or UDP */
+	printk("  sport=%d dport=%d",
+	       *(u_short *)(buf+20), *(u_short *)(buf+22));
+	if( buf[9] == 6 ){
+	    printk(" seq=%d ack=%d win=%d flags=<",
+		   *(long *)(buf+24), *(long *)(buf+28),
+		   *(unsigned short *)(buf+34));
+	    flags = buf[33];
+	    sep = "";
+	    for (i = 7; i >= 0; --i) {
+		if (flags & (1 << i)) {
+		    printk("%s%s", sep, flagbits[i]);
+		    sep = "+";
+		}
+	    }
+	    printk(">");
+	}
+	printk("\n");
+    }
+}
+#endif
+
+#if APFDDI_DEBUG
+static void apfddi_print_frame(struct sk_buff *skb)
+{
+    int i;
+    struct llc_header *lh;
+    static int seq = 0;
+
+#if 0
+    printk("skb->len is %d\n", skb->len);
+    printk("fc is 0x%x\n", *(u_char *)(skb->data+3));
+    printk("dest address is:\n");
+    for (i = 0; i < 6; i++) {
+	printk("%x:", fddi_bitrev[*(u_char *)(skb->data+4+i)]);
+    }
+    printk("\n");
+    printk("source address is:\n");
+    for (i = 0; i < 6; i++) {
+	printk("%x:", fddi_bitrev[*(u_char *)(skb->data+10+i)]);
+    }
+    printk("\n");
+#endif
+    lh = (struct llc_header *)(skb->data+16);
+#if 0
+    printk("llc_dsp %d llc_ssap %d snap_control %d org_code [0]=%d [1]=%d [2]=%d ether_type=%d\n",
+	   lh->llc_dsap, lh->llc_ssap, lh->snap_control,
+	   lh->snap_org_code[0], lh->snap_org_code[1], lh->snap_org_code[2],
+	   lh->snap_ether_type);
+#endif
+    if (lh->snap_ether_type == ETH_P_IP)
+	dump_packet("apfddi_xmit:", skb->data+24, skb->len-24, seq++);
+}
+#endif
+
+/*
+ * Transmitting packet over FDDI.
+ */
+static int apfddi_xmit(struct sk_buff *skb, struct device *dev)
+{
+    unsigned long flags;
+    
+#if APFDDI_DEBUG
+    printk("In apfddi_xmit\n");
+#endif
+
+    /*
+     * Check there is some work to do.
+     */
+    if (skb == NULL || dev == NULL) 
+	return(0);
+
+#if APFDDI_DEBUG
+    printk("skb address is for apfddi 0x%x\n", skb);
+#endif
+
+    /*
+     * Check lock variable.
+     */
+    save_flags(flags); cli();
+    if (dev->tbusy != 0) {
+	restore_flags(flags);
+	printk("apfddi_xmit: device busy\n");
+	apfddi_stats->tx_errors++;
+	return 1;
+    }
+    restore_flags(flags);
+    dev->tbusy = 1;
+
+    dev->trans_start = jiffies;
+
+    skb->mac.raw = skb->data;
+
+    /*
+     * Append packet onto send queue.
+     */
+    if (mac_queue_append(skb)) {
+	/*
+	 * No memory.
+	 */
+	return 1;
+    }
+
+    /*
+     * Process packet queue.
+     */
+    mac_process();
+
+    apfddi_stats->tx_packets++;
+    dev->tbusy = 0;
+    return 0;
+}
+
+#if APFDDI_DEBUG
+void print_mbuf(struct mac_buf *mbuf)
+{
+    printk("mac %p length=%d ptr=%p wraplen=%d wrapptr=%x fr_start=%d fr_end=%d\n",
+	   mbuf, mbuf->length, mbuf->ptr, mbuf->wraplen, mbuf->wrapptr,
+	   mbuf->fr_start, mbuf->fr_end);
+}
+#endif
+
+/*
+ * Return statistics of fddi driver.
+ */
+static struct enet_statistics *apfddi_get_stats(struct device *dev)
+{
+    return((struct enet_statistics *)dev->priv);
+}
+
+    
+
+
diff -u --recursive --new-file v2.1.22/linux/drivers/ap1000/apfddi.h linux/drivers/ap1000/apfddi.h
--- v2.1.22/linux/drivers/ap1000/apfddi.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/ap1000/apfddi.h	Sun Jan 26 12:07:10 1997
@@ -0,0 +1,142 @@
+  /*
+   * Copyright 1996 The Australian National University.
+   * Copyright 1996 Fujitsu Laboratories Limited
+   * 
+   * This software may be distributed under the terms of the Gnu
+   * Public License version 2 or later
+  */
+#define BUFFER_MEM	0x40000
+#define CSR0		0x60000
+#define CSR1		0x60004
+#define PLC		0x60080
+#define FORMAC		0x60200
+#define FIFO		0x68000
+
+/* Size of buffer memory */
+#define BUFFER_SIZE	32768		/* words; 128kB */
+
+/* Bits in CSR0 */
+#define CS0_INT_REQ	0x8000		/* board interrupt request asserted */
+#define CS0_MAC_IRQ	0x4000		/* FORMAC is requesting interrupt */
+#define CS0_PHY_IRQ	0x2000		/* PLC is requesting interrupt */
+#define CS0_LED2	0x1000		/* turn on led 2 */
+#define CS0_DO_IRQ	0x0200		/* request interrupt */
+#define CS0_INT_ENABLE	0x0100		/* enable interrupt requests */
+#define CS0_DMA_ENABLE	0x0080		/* enable DMA requests */
+#define CS0_DMA_RECV	0x0040		/* DMA requests are in receive dirn. */
+#define CS0_LED1	0x0010		/* turn on led 1 */
+#define CS0_LED0	0x0008		/* turn on led 0 (red) */
+#define CS0_HREQ	0x0007		/* host request to FORMAC */
+#define CS0_HREQ_WSPEC	0x0002		/* write special frames */
+#define CS0_HREQ_RECV	0x0003		/* read receive queue */
+#define CS0_HREQ_WS	0x0004		/* write synchronous queue */
+#define CS0_HREQ_WA0	0x0005		/* write async queue 0 */
+#define CS0_HREQ_WA1	0x0006		/* write async queue 1 */
+#define CS0_HREQ_WA2	0x0007		/* write async queue 2 */
+
+/* Bits in CSR1 */
+#define CS1_THIS_QAF	0x0800		/* this queue almost full */
+#define CS1_FIFO_TAG	0x0400		/* tag of word at head of fifo */
+#define CS1_BUF_RD_TAG	0x0200		/* tag of last word read from buffer */
+#define CS1_BUF_WR_TAG	0x0100		/* tag to write to buffer */
+#define CS1_TAGMODE	0x0080		/* enable tag mode */
+#define CS1_RESET_MAC	0x0040		/* reset FORMAC and PLC */
+#define CS1_RESET_FIFO	0x0020		/* reset FIFO */
+#define CS1_CLEAR_QAF	0x0010		/* clear queue-almost-full bits */
+#define CS1_FIFO_LEVEL	0x0007		/* # words in FIFO (0 - 4) */
+
+/*
+ * FDDI Frame Control values.
+ */
+#define FDDI_SMT		0x41
+#define FDDI_SMT_NSA		0x4f
+#define FDDI_FC_LLC		0x50
+#define FDDI_FC_LLC_MASK	0xf0
+
+/*
+ * Unnumbered LLC format commands
+ */
+#define LLC_UI		0x3
+#define LLC_UI_P	0x13
+#define LLC_DISC	0x43
+#define	LLC_DISC_P	0x53
+#define LLC_UA		0x63
+#define LLC_UA_P	0x73
+#define LLC_TEST	0xe3
+#define LLC_TEST_P	0xf3
+#define LLC_FRMR	0x87
+#define	LLC_FRMR_P	0x97
+#define LLC_DM		0x0f
+#define	LLC_DM_P	0x1f
+#define LLC_XID		0xaf
+#define LLC_XID_P	0xbf
+#define LLC_SABME	0x6f
+#define LLC_SABME_P	0x7f
+
+/*
+ * Supervisory LLC commands
+ */
+#define	LLC_RR		0x01
+#define	LLC_RNR		0x05
+#define	LLC_REJ		0x09
+
+/*
+ * Info format - dummy only
+ */
+#define	LLC_INFO	0x00
+
+/*
+ * ISO PDTR 10178 contains among others
+ */
+#define LLC_X25_LSAP	0x7e
+#define LLC_SNAP_LSAP	0xaa
+#define LLC_ISO_LSAP	0xfe
+
+/*
+ * Structure of the FDDI MAC header.
+ */
+struct fddi_header {
+    u_char	fddi_fc;	/* frame control field */
+    u_char	fddi_dhost[6];	/* destination address */
+    u_char	fddi_shost[6];	/* source address */
+};
+
+/*
+ * Structure of LLC/SNAP header.
+ */
+struct llc_header {
+  u_char llc_dsap;
+  u_char llc_ssap;
+  u_char snap_control;
+  u_char snap_org_code[3];
+  u_short snap_ether_type;
+};
+  
+#define FDDI_HDRLEN	13	/* sizeof(struct fddi_header) */
+#define LLC_SNAPLEN	8	/* bytes for LLC/SNAP header */
+#define FDDI_HARDHDR_LEN 28     /* Hard header size */
+
+#define FDDIMTU		4352
+
+
+/* Types of loopback we can do. */
+typedef enum {
+    loop_none,
+    loop_formac,
+    loop_plc_lm,
+    loop_plc_eb,
+    loop_pdx
+} LoopbackType;
+
+/* Offset from fifo for writing word with tag. */
+#define FIFO_TAG	0x80
+
+#define MAX_FRAME_LEN	4500
+
+void set_ring_op(int up);
+void rmt_event(int st);
+void set_cf_join(int on);
+
+extern struct device *apfddi_device;
+extern struct enet_statistics *apfddi_stats;
+
diff -u --recursive --new-file v2.1.22/linux/drivers/ap1000/bif.c linux/drivers/ap1000/bif.c
--- v2.1.22/linux/drivers/ap1000/bif.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/ap1000/bif.c	Sun Jan 26 12:07:10 1997
@@ -0,0 +1,289 @@
+  /*
+   * Copyright 1996 The Australian National University.
+   * Copyright 1996 Fujitsu Laboratories Limited
+   * 
+   * This software may be distributed under the terms of the Gnu
+   * Public License version 2 or later
+  */
+/*
+ * $Id: bif.c,v 1.13 1996/12/18 01:45:52 tridge Exp $
+ *
+ * Network interface definitions for bif device.
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/fs.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/socket.h>
+#include <linux/errno.h>
+#include <linux/fcntl.h>
+#include <linux/in.h>
+#include <linux/if_ether.h>	/* For the statistics structure. */
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>	/* For ARPHRD_BIF */
+
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/io.h>
+
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+
+#include <asm/ap1000/apservice.h>
+#include <asm/ap1000/apreg.h>
+
+#define BIF_DEBUG 0
+#if BIF_DEBUG
+static int seq = 0;
+#endif
+
+#define BIF_MTU 10240
+
+static struct device *bif_device = 0;
+static struct enet_statistics *bif_stats = 0;
+
+int bif_init(struct device *dev);
+int bif_open(struct device *dev);
+static int bif_xmit(struct sk_buff *skb, struct device *dev);
+int bif_rx(struct sk_buff *skb);
+int bif_stop(struct device *dev);
+static struct enet_statistics *bif_get_stats(struct device *dev);
+
+static int bif_hard_header(struct sk_buff *skb, struct device *dev,
+			   unsigned short type, void *daddr,
+			   void *saddr, unsigned len)
+{
+#if BIF_DEBUG
+  printk("bif_hard_header()\n");
+#endif
+  
+  skb_push(skb,dev->hard_header_len);
+
+  if (daddr) skb->arp = 1;
+
+  /* tell IP how much space we took */
+  return (dev->hard_header_len);
+}
+
+static int bif_rebuild_header(void *buff, struct device *dev,
+			      unsigned long raddr, struct sk_buff *skb)
+{
+  /* this would normally be used to fill in hardware addresses after
+     an ARP */
+#if BIF_DEBUG
+  printk("bif_rebuild_header()\n");
+#endif
+  if (skb) skb->arp = 1;
+  return(0);
+}
+
+static int bif_set_mac_address(struct device *dev, void *addr)
+{
+  printk("BIF: set_mac_address called\n");
+  return (0);
+}
+
+static void bif_set_multicast_list(struct device *dev)
+{
+  return;
+}
+
+static int bif_do_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
+{
+  printk("BIF: Called do_ioctl\n");
+  return (0);
+}
+
+static int bif_set_config(struct device *dev, struct ifmap *map)
+{
+  printk("BIF: Called bif_set_config\n");
+  return (0);
+}
+
+/*
+ * Initialise bif network interface.
+ */
+int bif_init(struct device *dev)
+{
+    int i;
+
+    printk("bif_init(): Initialising bif interface\n");
+    bif_device = dev;
+
+    dev->mtu = BIF_MTU;
+    dev->tbusy = 0;
+    dev->hard_start_xmit = bif_xmit;
+    dev->hard_header = bif_hard_header;
+    dev->hard_header_len = sizeof(struct cap_request);
+    dev->addr_len = 0;
+    dev->tx_queue_len = 50000;    /* no limit (almost!) */
+    dev->type = ARPHRD_BIF;
+    dev->rebuild_header	= bif_rebuild_header;
+    dev->open = bif_open;
+    dev->flags = IFF_NOARP;   /* Don't use ARP on this device */
+    dev->family = AF_INET;
+    dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL);
+    if (dev->priv == NULL)
+	return -ENOMEM;
+    memset(dev->priv, 0, sizeof(struct enet_statistics));
+    bif_stats = (struct enet_statistics *)bif_device->priv;
+
+
+    dev->stop = bif_stop;
+    dev->get_stats = bif_get_stats;
+
+    /* Initialise the bif device structure */
+    for (i = 0; i < DEV_NUMBUFFS; i++)
+	skb_queue_head_init(&dev->buffs[i]);
+    
+    dev->set_mac_address = bif_set_mac_address;
+    dev->header_cache_update = NULL;
+    dev->do_ioctl = bif_do_ioctl;    
+    dev->set_config = bif_set_config;
+    dev->set_multicast_list = bif_set_multicast_list;
+
+    memset(dev->broadcast, 0xFF, ETH_ALEN);
+    
+    dev->pa_addr = 0;
+    dev->pa_brdaddr = 0;
+    dev->pa_mask = 0;
+    dev->pa_alen = 4;
+
+    return(0);
+}
+
+int bif_open(struct device *dev)
+{
+    printk("In bif_open\n");
+    dev->tbusy = 0;
+    dev->start = 1;
+    return 0;
+}
+
+#if BIF_DEBUG
+static void dump_packet(char *action, char *buf, int len, int seq)
+{
+    int flags;
+    char *sep;
+
+    printk("%s packet %d of %d bytes at %d:\n", action, seq,
+	   len, (int)jiffies);
+    printk("  from %x to %x pktid=%d ttl=%d pcol=%d len=%d\n",
+	   *(long *)(buf+12), *(long *)(buf+16), *(u_short *)(buf+4),
+	   *(unsigned char *)(buf+8), buf[9], *(u_short *)(buf+2));
+    if( buf[9] == 6 || buf[9] == 17 ){
+	/* TCP or UDP */
+	printk("  sport=%d dport=%d",
+	       *(u_short *)(buf+20), *(u_short *)(buf+22));
+	if( buf[9] == 6 ){
+	    printk(" seq=%d ack=%d win=%d flags=<",
+		   *(long *)(buf+24), *(long *)(buf+28),
+		   *(unsigned short *)(buf+34));
+	    flags = buf[33];
+	    sep = "";
+	    printk(">");
+	}
+	printk("\n");
+    }
+    else {
+	printk("  protocol = %d\n", buf[9]);
+    }
+}
+#endif
+
+
+static int bif_xmit(struct sk_buff *skb, struct device *dev)
+{
+	extern int bif_send_ip(int cid,struct sk_buff *skb);
+	extern int tnet_send_ip(int cid,struct sk_buff *skb);
+	extern int msc_blocked, tnet_ip_enabled;
+	u_long destip;
+	int cid;
+
+	if (skb == NULL || dev == NULL) 
+		return(0);
+  
+	destip = *(u_long *)(skb->data+sizeof(struct cap_request)+16);
+	cid = ap_ip_to_cid(destip);
+
+	skb->dev = dev;
+	skb->mac.raw = skb->data;
+
+	if (cid != -1 && tnet_ip_enabled && !msc_blocked) {
+		tnet_send_ip(cid,skb);
+	} else {
+		bif_send_ip(cid, skb);
+	}
+  
+	dev->tbusy = 0;
+  
+	bif_stats->tx_packets++;
+
+	mark_bh(NET_BH);
+  
+	return 0;
+}
+
+
+/*
+ * Receive a packet from the BIF - called from interrupt handler.
+ */
+int bif_rx(struct sk_buff *skb)
+{
+#if BIF_DEBUG
+	dump_packet("bif_rx:", skb->data, skb->len, seq++);
+#endif
+
+	if (bif_device == NULL) {
+		printk("bif: bif_device is NULL in bif_rx\n");
+		dev_kfree_skb(skb, FREE_WRITE);
+		return 0;
+	}
+	skb->dev = bif_device;
+	skb->protocol = ETH_P_IP;
+	
+#if 1
+	/* try disabling checksums on receive */
+	if (ap_ip_to_cid(*(u_long *)(((char *)skb->data)+12)) != -1)
+		skb->ip_summed = CHECKSUM_UNNECESSARY;
+#endif
+	
+	/*
+	 * Inform the network layer of the new packet.
+	 */
+	skb->mac.raw = skb->data;
+	netif_rx(skb);
+	
+	if (bif_stats == NULL) {
+		printk("bif: bif_stats is NULL is bif_rx\n");
+		return 0;
+	}
+	bif_stats->rx_packets++;
+	
+	return 0;
+}
+
+int bif_stop(struct device *dev)
+{
+	printk("in bif_close\n");
+
+	dev->tbusy = 1;
+	dev->start = 0;
+
+	return 0;
+}
+
+/*
+ * Return statistics of bif driver.
+ */
+static struct enet_statistics *bif_get_stats(struct device *dev)
+{
+    return((struct enet_statistics *)dev->priv);
+}
+    
diff -u --recursive --new-file v2.1.22/linux/drivers/ap1000/ddv.c linux/drivers/ap1000/ddv.c
--- v2.1.22/linux/drivers/ap1000/ddv.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/ap1000/ddv.c	Sun Jan 26 12:07:10 1997
@@ -0,0 +1,1008 @@
+  /*
+   * Copyright 1996 The Australian National University.
+   * Copyright 1996 Fujitsu Laboratories Limited
+   * 
+   * This software may be distributed under the terms of the Gnu
+   * Public License version 2 or later
+  */
+/* 
+ * ddv.c - Single AP1000 block driver.
+ *
+ * This block driver performs io operations to the ddv option
+ * board. (Hopefully:)
+ *
+ */
+
+#include <linux/errno.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/ext2_fs.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#define __KERNEL_SYSCALLS__
+#include <linux/unistd.h>
+#include <linux/sched.h>
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+#include <linux/module.h>
+#include <asm/ap1000/apreg.h>
+#include <asm/ap1000/DdvReqTable.h>
+
+#define MAJOR_NR DDV_MAJOR
+
+#include <linux/blk.h>
+#include <linux/genhd.h>
+#include <linux/hdreg.h> 
+
+#define DDV_DEBUG 0
+#define AIR_DISK 1
+
+#define SECTOR_SIZE 512
+
+/* we can have lots of partitions */
+#define PARTN_BITS 6
+#define NUM_DDVDEVS (1<<PARTN_BITS)
+
+#define PARDISK_BASE (1<<5) /* partitions above this number are 
+			       striped	across all the cells */
+#define STRIPE_SHIFT   6
+#define STRIPE_SECTORS (1<<STRIPE_SHIFT) /* number of sectors per stripe */
+
+#define MAX_BNUM 16
+#define MAX_REQUEST (TABLE_SIZE - 2)
+#define REQUEST_LOW 16
+#define REQUEST_HIGH 4
+
+
+/* we fake up a block size larger than the physical block size to try
+   to make things a bit more efficient */
+#define SECTOR_BLOCK_SHIFT 9
+
+/* try to read ahead a bit */
+#define DDV_READ_AHEAD 64
+
+static int have_ddv_board = 1;
+static unsigned num_options = 0;
+static unsigned this_option = 0;
+
+extern int ddv_get_mlist(unsigned mptr[],int bnum);
+extern int ddv_set_request(struct request *req,
+			   int request_type,int bnum,int mlist,int len,int offset);
+extern void ddv_load_kernel(char *opcodep);
+extern int ddv_restart_cpu(void);
+extern int ddv_mlist_available(void);
+static int ddv_revalidate(kdev_t dev, struct gendisk *gdev);
+static void ddv_geninit(struct gendisk *ignored);
+static void ddv_release(struct inode * inode, struct file * filp);
+static void ddv_request1(void);
+
+
+static char *ddv_opcodep = NULL;
+static struct request *next_request = NULL;
+
+static struct wait_queue * busy_wait = NULL;
+
+static int ddv_blocksizes[NUM_DDVDEVS]; /* in bytes */
+int ddv_sect_length[NUM_DDVDEVS]; /* in sectors */
+int ddv_blk_length[NUM_DDVDEVS]; /* in blocks */
+
+/* these are used by the ddv_daemon, which services remote disk requests */
+static struct remote_request *rem_queue = NULL;
+static struct remote_request *rem_queue_end;
+static struct wait_queue *ddv_daemon_wait = NULL;
+
+static int opiu_kernel_loaded = 0;
+
+static struct {
+	unsigned reads, writes, blocks, rq_started, rq_finished, errors;
+	unsigned sectors_read, sectors_written;
+} ddv_stats;
+
+static struct hd_struct partition_tables[NUM_DDVDEVS];
+
+static struct gendisk ddv_gendisk = {
+	MAJOR_NR,	/* Major number */
+	DEVICE_NAME,		/* Major name */
+	PARTN_BITS,		/* Bits to shift to get real from partition */
+	1 << PARTN_BITS,	/* Number of partitions per real */
+	1,	        /* maximum number of real */
+#ifdef MODULE
+	NULL,		/* called from init_module */
+#else
+        ddv_geninit,     /* init function */
+#endif
+	partition_tables,/* hd struct */
+	ddv_blk_length,	/* block sizes */
+	1,		/* number */
+	(void *) NULL,	/* internal */
+	NULL		/* next */
+};
+
+
+struct ddv_geometry {
+	unsigned char heads;
+	unsigned char sectors;
+	unsigned short cylinders;
+	unsigned long start;
+}; 
+
+static struct ddv_geometry ddv_geometry;
+
+
+struct remote_request {
+	union {
+		struct remote_request *next;
+		void (*fn)(void);
+	} u;
+	unsigned bnum; /* how many blocks does this contain */
+	struct request *reqp; /* pointer to the request on the original cell */
+	unsigned cell; /* what cell is the request from */
+	struct request req; /* details of the request */
+};
+
+
+static void ddv_set_optadr(void)
+{
+	unsigned addr = 0x11000000;
+	OPT_IO(OBASE) = addr;
+	MSC_IO(MSC_OPTADR) = 
+		((addr & 0xff000000)>>16) |
+			((OPTION_BASE & 0xf0000000)>>24) | 
+				((OPTION_BASE + 0x10000000)>>28); 
+	OPT_IO(PRST) = 0;
+}
+
+extern struct RequestTable *RTable;
+extern struct OPrintBufArray *PrintBufs;
+extern struct OAlignBufArray *AlignBufs;
+extern struct DiskInfo *DiskInfo;
+
+static void ddv_release(struct inode * inode, struct file * filp)
+{
+#if DEBUG
+	printk("ddv_release started\n");
+#endif
+	sync_dev(inode->i_rdev);
+#if DEBUG
+	printk("ddv_release done\n");
+#endif
+}
+
+
+static unsigned in_request = 0;
+static unsigned req_queued = 0;
+
+static void ddv_end_request(int uptodate,struct request *req) 
+{
+	struct buffer_head * bh;
+
+	ddv_stats.rq_finished++;
+
+/*	printk("ddv_end_request(%d,%p)\n",uptodate,req); */
+
+	req->errors = 0;
+	if (!uptodate) {
+		printk("end_request: I/O error, dev %s, sector %lu\n",
+		       kdevname(req->rq_dev), req->sector);
+		req->nr_sectors--;
+		req->nr_sectors &= ~SECTOR_MASK;
+		req->sector += (BLOCK_SIZE / SECTOR_SIZE);
+		req->sector &= ~SECTOR_MASK;		
+		ddv_stats.errors++;
+	}
+	
+	if ((bh = req->bh) != NULL) {
+		req->bh = bh->b_reqnext;
+		bh->b_reqnext = NULL;
+		mark_buffer_uptodate(bh, uptodate);
+		unlock_buffer(bh);
+		if ((bh = req->bh) != NULL) {
+			req->current_nr_sectors = bh->b_size >> 9;
+			if (req->nr_sectors < req->current_nr_sectors) {
+				req->nr_sectors = req->current_nr_sectors;
+				printk("end_request: buffer-list destroyed\n");
+			}
+			req->buffer = bh->b_data;
+			printk("WARNING: ddv: more sectors!\n");
+			ddv_stats.errors++;
+			return;
+		}
+	}
+	if (req->sem != NULL)
+		up(req->sem);
+	req->rq_status = RQ_INACTIVE;	
+	wake_up(&wait_for_request);
+}
+
+
+/* check that a request is all OK to process */
+static int request_ok(struct request *req)
+{
+	int minor;
+	if (!req) return 0;
+
+	if (MAJOR(req->rq_dev) != MAJOR_NR)
+		panic(DEVICE_NAME ": bad major number\n");
+	if (!buffer_locked(req->bh))
+		panic(DEVICE_NAME ": block not locked");
+	
+	minor = MINOR(req->rq_dev);
+	if (minor >= NUM_DDVDEVS) {
+		printk("ddv_request: Invalid minor (%d)\n", minor);
+		return 0;
+	}
+
+	if ((req->sector + req->current_nr_sectors) > ddv_sect_length[minor]) {
+		printk("ddv: out of range minor=%d offset=%d len=%d sect_length=%d\n",
+		       minor,(int)req->sector,(int)req->current_nr_sectors,
+		       ddv_sect_length[minor]);
+		return 0;
+	}
+
+	if (req->cmd != READ && req->cmd != WRITE) {
+		printk("unknown request type %d\n",req->cmd);
+		return 0;
+	}			
+
+	/* it seems to be OK */
+	return 1;
+}
+
+
+static void complete_request(struct request *req,int bnum)
+{
+	while (bnum--) {
+		ddv_end_request(1,req);
+		req = req->next;
+	}
+}
+
+
+static int completion_pointer = 0;
+
+static void check_completion(void)
+{
+	int i,bnum;
+	struct request *req;
+
+	if (!RTable) return;
+
+	for (;
+	     (i=completion_pointer) != RTable->ddv_pointer &&
+	     RTable->async_info[i].status == DDV_REQ_FREE;
+	     completion_pointer = INC_T(completion_pointer))	     
+	{
+		req = (struct request *)RTable->async_info[i].argv[7];
+		bnum = RTable->async_info[i].bnum;
+		if (!req || !bnum) {
+			printk("%s(%d)\n",__FILE__,__LINE__);
+			ddv_stats.errors++;
+			continue;
+		}
+			
+		RTable->async_info[i].status = 0;
+		RTable->async_info[i].argv[7] = 0;
+
+		complete_request(req,bnum);
+		in_request--;		
+	}
+}
+
+
+static struct request *get_request_queue(struct request *oldq)
+{
+	struct request *req,*req2;
+
+	/* skip any non-active or bad requests */
+ skip1:
+	if (!(req = CURRENT)) 
+		return oldq;
+
+	if (req->rq_status != RQ_ACTIVE) {
+		CURRENT = req->next;
+		goto skip1;
+	}
+
+	if (!request_ok(req)) {
+		ddv_end_request(0,req);
+		CURRENT = req->next;
+		goto skip1;
+	}
+
+	/* now grab as many as we can */
+	req_queued++;
+
+	for (req2 = req;
+	     req2->next && 
+	     req2->next->rq_status == RQ_ACTIVE &&
+	     request_ok(req2->next);
+	     req2 = req2->next) 
+		req_queued++;
+
+	/* leave CURRENT pointing at the bad ones */
+	CURRENT = req2->next;
+
+	/* chop our list at that point */
+	req2->next = NULL;
+
+	if (!oldq)
+		return req;
+
+	for (req2=oldq;req2->next;req2=req2->next) ;
+
+	req2->next = req;
+
+	return oldq;	
+}
+
+
+static void ddv_rem_complete(struct remote_request *rem)
+{
+	unsigned flags;
+	int bnum = rem->bnum;
+	struct request *req = rem->reqp;
+
+	complete_request(req,bnum);
+	in_request--;
+
+	save_flags(flags); cli();
+	ddv_request1();
+	restore_flags(flags);
+}
+
+
+/*
+ * The background ddv daemon. This receives remote disk requests
+ * and processes them via the normal block operations
+ */
+static int ddv_daemon(void *unused)
+{
+	current->session = 1;
+	current->pgrp = 1;
+	sprintf(current->comm, "ddv_daemon");
+	current->blocked = ~0UL; /* block all signals */
+  
+	/* Give it a realtime priority. */
+	current->policy = SCHED_FIFO;
+	current->priority = 32;  /* Fixme --- we need to standardise our
+				    namings for POSIX.4 realtime scheduling
+				    priorities.  */
+  
+	printk("Started ddv_daemon\n");
+  
+	while (1) {
+		struct remote_request *rem;
+		unsigned flags;
+		struct buffer_head *bhlist[MAX_BNUM*4];
+		int i,j,minor,len,shift,offset;
+
+		save_flags(flags); cli();
+
+		while (!rem_queue) {
+			current->signal = 0;
+			interruptible_sleep_on(&ddv_daemon_wait);
+		}
+
+		rem = rem_queue;
+		rem_queue = rem->u.next;
+		restore_flags(flags);
+			
+
+		minor = MINOR(rem->req.rq_dev);
+		len = rem->req.current_nr_sectors;
+		offset = rem->req.sector;
+
+		/* work out the conversion to the local block size from
+		   sectors */
+		for (shift=0;
+		     (SECTOR_SIZE<<shift) != ddv_blocksizes[minor];
+		     shift++) ;
+
+		/* do the request */
+		for (i=0; len; i++) {
+			bhlist[i] = getblk(rem->req.rq_dev, 
+					   offset >> shift,
+					   ddv_blocksizes[minor]);
+			if (!buffer_uptodate(bhlist[i]))
+				ll_rw_block(READ,1,&bhlist[i]);
+			offset += 1<<shift;
+			len -= 1<<shift;
+		}
+			    
+		for (j=0;j<i;j++)
+			if (!buffer_uptodate(bhlist[j]))
+				wait_on_buffer(bhlist[j]);
+		
+		
+		/* put() the data */
+		
+
+		/* release the buffers */
+		for (j=0;j<i;j++)
+			brelse(bhlist[j]);
+
+		/* tell the originator that its done */
+		rem->u.fn = ddv_rem_complete;
+		tnet_rpc(rem->cell,rem,sizeof(int)*3,1);
+	}
+}
+
+
+/* receive a remote disk request */
+static void ddv_rem_queue(char *data,unsigned size)
+{
+	unsigned flags;
+	struct remote_request *rem = (struct remote_request *)
+		kmalloc(size,GFP_ATOMIC);
+
+	if (!rem) {
+		/* oh bugger! */
+		ddv_stats.errors++;
+		return;
+	}
+
+	memcpy(rem,data,size);
+	rem->u.next = NULL;
+
+	save_flags(flags); cli();
+
+	/* add it to our remote request queue */
+	if (!rem_queue)
+		rem_queue = rem;
+	else
+		rem_queue_end->u.next = rem;
+	rem_queue_end = rem;
+
+	restore_flags(flags);
+
+	wake_up(&ddv_daemon_wait);  
+}
+
+
+/* which disk should this request go to */
+static inline unsigned pardisk_num(struct request *req)
+{
+	int minor = MINOR(req->rq_dev);
+	unsigned stripe;
+	unsigned cell;
+
+	if (minor < PARDISK_BASE)
+		return this_option;
+
+	stripe = req->sector >> STRIPE_SHIFT;
+	cell = stripe % num_options;
+
+	return cell;
+}
+
+
+/* check if a 2nd request can be tacked onto the first */
+static inline int contiguous(struct request *req1,struct request *req2)
+{
+	if (req2->cmd != req1->cmd ||
+	    req2->rq_dev != req1->rq_dev ||
+	    req2->sector != req1->sector + req1->current_nr_sectors ||
+	    req2->current_nr_sectors != req1->current_nr_sectors)
+		return 0;
+	if (pardisk_num(req1) != pardisk_num(req2))
+		return 0;
+	return 1;
+}
+
+static void ddv_request1(void)
+{
+	struct request *req,*req1,*req2;
+	unsigned offset,len,req_num,mlist,bnum,available=0;
+	static unsigned mptrs[MAX_BNUM];
+	unsigned cell;
+
+	if (in_request > REQUEST_HIGH)
+		return;
+
+	next_request = get_request_queue(next_request);
+
+	while ((req = next_request)) {
+		int minor;
+
+		if (in_request >= MAX_REQUEST)
+			return;
+
+		if (in_request>1 && req_queued<REQUEST_LOW)
+			return;
+	
+		/* make sure we have room for a request */
+		available = ddv_mlist_available();
+		if (available < 1) return;
+		if (available > MAX_BNUM)
+			available = MAX_BNUM;
+
+		offset = req->sector;
+		len = req->current_nr_sectors;
+		minor = MINOR(req->rq_dev);
+		  
+		mptrs[0] = (int)req->buffer;
+
+		for (bnum=1,req1=req,req2=req->next;
+		     req2 && bnum<available && contiguous(req1,req2);
+		     req1=req2,req2=req2->next) {
+			mptrs[bnum++] = (int)req2->buffer;
+		}
+
+		next_request = req2;
+
+
+		req_queued -= bnum;
+		ddv_stats.blocks += bnum;
+		ddv_stats.rq_started += bnum;
+
+		if (req->cmd == READ) {
+			ddv_stats.reads++;
+			ddv_stats.sectors_read += len*bnum;
+		} else {
+			ddv_stats.writes++;
+			ddv_stats.sectors_written += len*bnum;
+		}
+
+		if (minor >= PARDISK_BASE) {
+			/* translate the request to the normal partition */
+			unsigned stripe;
+			minor -= PARDISK_BASE;
+
+			stripe = offset >> STRIPE_SHIFT;
+			stripe /= num_options;
+			offset = (stripe << STRIPE_SHIFT) + 
+				(offset & ((1<<STRIPE_SHIFT)-1));
+#if AIR_DISK 
+			/* like an air-guitar :-) */
+			complete_request(req,bnum);
+			continue;
+#endif
+		}
+
+		if ((cell=pardisk_num(req)) != this_option) {
+			/* its a remote request */
+			struct remote_request *rem;
+			unsigned *remlist;
+			unsigned size = sizeof(*rem) + sizeof(int)*bnum;
+
+			rem = (struct remote_request *)kmalloc(size,GFP_ATOMIC);
+			if (!rem) {
+				/* hopefully we can get it on the next go */
+				return;
+			}
+			remlist = (unsigned *)(rem+1);
+			
+			rem->u.fn = ddv_rem_queue;
+			rem->cell = this_option;
+			rem->bnum = bnum;
+			rem->req = *req;
+			rem->reqp = req;
+			rem->req.rq_dev = MKDEV(MAJOR_NR,minor);
+			rem->req.sector = offset;
+			memcpy(remlist,mptrs,sizeof(mptrs[0])*bnum);
+			
+			if (tnet_rpc(cell,rem,size,1) != 0) {
+				kfree_s(rem,size);
+				return;
+			}
+		} else {
+			/* its a local request */
+			if ((mlist = ddv_get_mlist(mptrs,bnum)) == -1) {
+				ddv_stats.errors++;
+				panic("ddv: mlist corrupted");
+			}
+
+			req_num = RTable->cell_pointer;
+			RTable->async_info[req_num].status = 
+				req->cmd==READ?DDV_RAWREAD_REQ:DDV_RAWWRITE_REQ;
+			RTable->async_info[req_num].bnum = bnum;
+			RTable->async_info[req_num].argv[0] = mlist;
+			RTable->async_info[req_num].argv[1] = len;
+			RTable->async_info[req_num].argv[2] = offset + 
+				partition_tables[minor].start_sect;
+			RTable->async_info[req_num].argv[3] = bnum;
+			RTable->async_info[req_num].argv[7] = (unsigned)req;
+			RTable->cell_pointer = INC_T(RTable->cell_pointer);
+			
+		}
+
+		in_request++;	
+	}
+}
+
+
+static void ddv_request(void)
+{
+	cli();
+	ddv_request1();
+	sti();
+}
+
+
+static void check_printbufs(void)
+{  
+	int i;
+
+	if (!PrintBufs) return;
+
+	while (PrintBufs->option_counter != PrintBufs->cell_counter) {
+		i = PrintBufs->cell_counter;
+		printk("opiu (%d): ",i); 
+		if (((unsigned)PrintBufs->bufs[i].fmt) > 0x100000)
+			printk("Error: bad format in printk at %p\n", 
+			       PrintBufs->bufs[i].fmt);
+		else
+			printk(PrintBufs->bufs[i].fmt + OPIBUS_BASE,
+			       PrintBufs->bufs[i].args[0],
+			       PrintBufs->bufs[i].args[1],
+			       PrintBufs->bufs[i].args[2],
+			       PrintBufs->bufs[i].args[3],
+			       PrintBufs->bufs[i].args[4],
+			       PrintBufs->bufs[i].args[5]);
+		if (++PrintBufs->cell_counter == PRINT_BUFS)
+			PrintBufs->cell_counter = 0;
+	}
+}
+
+static void ddv_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned long flags;
+	save_flags(flags); cli();
+	OPT_IO(IRC1) = 0x80000000;
+
+	check_printbufs();
+	check_completion();
+
+	ddv_request1();
+	restore_flags(flags);
+}
+
+static int ddv_open(struct inode * inode, struct file * filp)
+{
+	int minor = MINOR(inode->i_rdev);
+
+	if (!have_ddv_board || minor >= NUM_DDVDEVS)
+		return -ENODEV;
+
+	if (minor >= PARDISK_BASE) {
+		ddv_sect_length[minor] = ddv_sect_length[minor - PARDISK_BASE];
+		ddv_blk_length[minor] = ddv_blk_length[minor - PARDISK_BASE];
+	}
+
+	return 0;
+}
+
+
+static void ddv_open_reply(struct cap_request *creq)
+{
+	int size = creq->size - sizeof(*creq);
+	ddv_opcodep = (char *)kmalloc(size,GFP_ATOMIC);
+	read_bif(ddv_opcodep, size);
+#if DEBUG
+	printk("received opiu kernel of size %d\n",size);
+#endif
+	if (size == 0)
+		have_ddv_board = 0;
+	wake_up(&busy_wait);	
+}
+
+
+static void ddv_load_opiu(void)
+{
+	int i;
+	struct cap_request creq;
+
+	/* if the opiu kernel is already loaded then we don't do anything */
+	if (!have_ddv_board || opiu_kernel_loaded)
+		return;
+  
+	bif_register_request(REQ_DDVOPEN,ddv_open_reply);
+
+	/* send the open request to the front end */
+	creq.cid = mpp_cid();
+	creq.type = REQ_DDVOPEN;
+	creq.header = 0;
+	creq.size = sizeof(creq);
+	
+	bif_queue(&creq,0,0);
+	
+	ddv_set_optadr();	
+
+	while (!ddv_opcodep)
+		sleep_on(&busy_wait);
+
+	if (!have_ddv_board)
+		return;
+
+	ddv_load_kernel(ddv_opcodep);
+	
+	kfree(ddv_opcodep);
+	ddv_opcodep = NULL;
+	
+	if (ddv_restart_cpu()) 
+		return;
+
+	ddv_sect_length[0] = DiskInfo->blocks;
+	ddv_blk_length[0] = DiskInfo->blocks >> 1;
+	ddv_blocksizes[0] = BLOCK_SIZE;
+
+	ddv_geometry.cylinders = ddv_sect_length[0] / 
+		(ddv_geometry.heads*ddv_geometry.sectors);
+
+	ddv_gendisk.part[0].start_sect = 0;
+	ddv_gendisk.part[0].nr_sects = ddv_sect_length[0];
+
+	resetup_one_dev(&ddv_gendisk, 0);
+	
+	for (i=0;i<PARDISK_BASE;i++) {
+		ddv_sect_length[i] = ddv_gendisk.part[i].nr_sects;
+		ddv_blk_length[i] = ddv_gendisk.part[i].nr_sects >> 1;
+	}
+
+	/* setup the parallel partitions by multiplying the normal
+	   partition by the number of options */
+	for (;i<NUM_DDVDEVS;i++) {
+		ddv_sect_length[i] = ddv_sect_length[i-PARDISK_BASE]*num_options;
+		ddv_blk_length[i] = ddv_blk_length[i-PARDISK_BASE]*num_options;
+		ddv_gendisk.part[i].start_sect = ddv_gendisk.part[i-PARDISK_BASE].start_sect;
+		ddv_gendisk.part[i].nr_sects = ddv_sect_length[i];
+	}
+
+
+	opiu_kernel_loaded = 1;       
+}
+
+
+/*
+ * This routine is called to flush all partitions and partition tables
+ * for a changed disk, and then re-read the new partition table.
+ */
+static int ddv_revalidate(kdev_t dev, struct gendisk *gdev)
+{
+	int target;
+	int max_p;
+	int start;
+	int i;
+
+	target = DEVICE_NR(dev);
+
+	max_p = gdev->max_p;
+	start = target << gdev->minor_shift;
+
+	printk("ddv_revalidate dev=%d target=%d max_p=%d start=%d\n",
+	       dev,target,max_p,start);
+
+	for (i=max_p - 1; i >=0 ; i--) {
+		int minor = start + i;
+		kdev_t devi = MKDEV(gdev->major, minor);
+		sync_dev(devi);
+		invalidate_inodes(devi);
+		invalidate_buffers(devi);
+		gdev->part[minor].start_sect = 0;
+		gdev->part[minor].nr_sects = 0;
+	};
+
+	ddv_sect_length[start] = DiskInfo->blocks;
+	ddv_blk_length[start] = DiskInfo->blocks >> 1;
+
+	gdev->part[start].nr_sects = ddv_sect_length[start];
+	resetup_one_dev(gdev, target);
+
+	printk("sect_length[%d]=%d blk_length[%d]=%d\n",
+	       start,ddv_sect_length[start],
+	       start,ddv_blk_length[start]);
+
+	for (i=0;i<max_p;i++) {
+		ddv_sect_length[start+i] = gdev->part[start+i].nr_sects;
+		ddv_blk_length[start+i] = gdev->part[start+i].nr_sects >> 1;
+		if (gdev->part[start+i].nr_sects)
+			printk("partition[%d] start=%d length=%d\n",i,
+			       (int)gdev->part[start+i].start_sect,
+			       (int)gdev->part[start+i].nr_sects);
+	}
+
+	return 0;
+}
+
+
+
+
+static int ddv_ioctl(struct inode *inode, struct file *file, 
+		    unsigned int cmd, unsigned long arg)
+{
+	int err;
+	struct ddv_geometry *loc = (struct ddv_geometry *) arg;
+	int dev;
+	int minor = MINOR(inode->i_rdev);
+  
+	if ((!inode) || !(inode->i_rdev))
+		return -EINVAL;
+	dev = DEVICE_NR(inode->i_rdev);
+#if DEBUG
+	printk("ddv_ioctl: cmd=%x dev=%x minor=%d\n", cmd, dev, minor);
+#endif
+	switch (cmd) {
+	case HDIO_GETGEO:
+		printk("\tHDIO_GETGEO\n");
+		if (!loc)  return -EINVAL;
+		if (put_user(ddv_geometry.heads, (char *) &loc->heads)) return -EFAULT;
+		if (put_user(ddv_geometry.sectors, (char *) &loc->sectors)) return -EFAULT;
+		if (put_user(ddv_geometry.cylinders, (short *) &loc->cylinders)) return -EFAULT;
+		if (put_user(ddv_geometry.start, (long *) &loc->start)) return -EFAULT;
+		return 0;
+  
+	case HDIO_GET_MULTCOUNT :
+		printk("\tHDIO_GET_MULTCOUNT\n");
+		return -EINVAL;
+
+	case HDIO_GET_IDENTITY :
+		printk("\tHDIO_GET_IDENTITY\n");
+		return -EINVAL;
+
+	case HDIO_GET_NOWERR :
+		printk("\tHDIO_GET_NOWERR\n");
+		return -EINVAL;
+
+	case HDIO_SET_NOWERR :
+		printk("\tHDIO_SET_NOWERR\n");
+		return -EINVAL;
+
+	case BLKRRPART:
+		printk("\tBLKRRPART\n");
+		return ddv_revalidate(inode->i_rdev,&ddv_gendisk);
+
+	case BLKGETSIZE:   /* Return device size */
+		if (put_user(ddv_sect_length[minor],(long *) arg)) return -EFAULT;
+#if DEBUG
+		printk("BLKGETSIZE gave %d\n",ddv_sect_length[minor]);
+#endif
+		return 0;
+    
+	default:
+		printk("ddv_ioctl: Invalid cmd=%d(0x%x)\n", cmd, cmd);
+		return -EINVAL;
+	};
+}
+
+static struct file_operations ddv_fops = {
+        NULL,                   /* lseek - default */
+        block_read,         /* read */
+        block_write,        /* write */
+        NULL,                   /* readdir - bad */
+        NULL,                   /* poll */
+        ddv_ioctl,               /* ioctl */
+        NULL,                   /* mmap */
+        ddv_open,                /* open */
+	ddv_release,
+        block_fsync          /* fsync */
+};
+
+
+static void ddv_status(void)
+{
+	if (!have_ddv_board) {
+		printk("no ddv board\n");
+		return;
+	}
+
+	printk("
+in_request %u   req_queued %u
+MTable:    start=%u end=%u
+Requests:  started=%u finished=%u
+Requests:  completion_pointer=%u ddv_pointer=%u cell_pointer=%u
+PrintBufs: option_counter=%u cell_counter=%u
+ddv_stats: reads=%u writes=%u blocks=%u
+ddv_stats: sectors_read=%u sectors_written=%u
+CURRENT=%p next_request=%p errors=%u
+",
+	       in_request,req_queued,
+	       RTable->start_mtable,RTable->end_mtable,
+	       ddv_stats.rq_started,ddv_stats.rq_finished,
+	       completion_pointer,RTable->ddv_pointer,RTable->cell_pointer,
+	       PrintBufs->option_counter,PrintBufs->cell_counter,
+	       ddv_stats.reads,ddv_stats.writes,ddv_stats.blocks,
+	       ddv_stats.sectors_read,ddv_stats.sectors_written,
+	       CURRENT,next_request,
+	       ddv_stats.errors);	
+}
+
+
+int ddv_init(void)
+{
+	int cid;
+	
+	cid = mpp_cid();
+	
+	if (register_blkdev(MAJOR_NR,DEVICE_NAME,&ddv_fops)) {
+		printk("ap: unable to get major %d for ap block dev\n",
+		       MAJOR_NR);
+		return -1;
+	}
+
+	printk("ddv_init: register dev %d\n", MAJOR_NR);
+	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+	read_ahead[MAJOR_NR] = DDV_READ_AHEAD;
+	
+	bif_add_debug_key('d',ddv_status,"DDV status");
+	ddv_gendisk.next = gendisk_head;
+	gendisk_head = &ddv_gendisk;
+
+	num_options = mpp_num_cells();
+	this_option = mpp_cid();
+
+	kernel_thread(ddv_daemon, NULL, 0);
+
+	return(0);
+}
+
+
+static void ddv_geninit(struct gendisk *ignored)
+{
+	int i;
+	static int done = 0;
+
+	if (done)
+		printk("ddv_geninit already done!\n");
+
+	done = 1;
+
+	printk("ddv_geninit\n");
+
+	/* request interrupt line 2 */
+	if (request_irq(APOPT0_IRQ,ddv_interrupt,SA_INTERRUPT,"apddv",NULL)) {
+		printk("Failed to install ddv interrupt handler\n");
+	}
+	
+	for (i=0;i<NUM_DDVDEVS;i++) {
+		ddv_blocksizes[i] = BLOCK_SIZE;
+		ddv_sect_length[i] = 0;
+		ddv_blk_length[i] = 0;
+	}
+
+	ddv_geometry.heads = 32;
+	ddv_geometry.sectors = 32;
+	ddv_geometry.cylinders = 1;
+	ddv_geometry.start = 0;
+	
+	blksize_size[MAJOR_NR] = ddv_blocksizes;
+
+	ddv_load_opiu();
+}
+
+
+/* loadable module support */
+
+#ifdef MODULE
+
+int init_module(void)
+{
+	int error = ddv_init();
+	ddv_geninit(&(struct gendisk) { 0,0,0,0,0,0,0,0,0,0,0 });
+	if (!error)
+		printk(KERN_INFO "DDV: Loaded as module.\n");
+	return error;
+}
+
+/* Before freeing the module, invalidate all of the protected buffers! */
+void cleanup_module(void)
+{
+	int i;
+
+	for (i = 0 ; i < NUM_DDVDEVS; i++)
+		invalidate_buffers(MKDEV(MAJOR_NR, i));
+
+	/* reset the opiu */
+	OPT_IO(OPIU_OP) = OPIU_RESET; 
+	OPT_IO(PRST) = PRST_IRST; 
+
+	unregister_blkdev( MAJOR_NR, DEVICE_NAME );
+	free_irq(APOPT0_IRQ, NULL);
+	blk_dev[MAJOR_NR].request_fn = 0;
+}
+
+#endif  /* MODULE */
+
+
diff -u --recursive --new-file v2.1.22/linux/drivers/ap1000/ddv_util.c linux/drivers/ap1000/ddv_util.c
--- v2.1.22/linux/drivers/ap1000/ddv_util.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/ap1000/ddv_util.c	Sun Jan 26 12:07:10 1997
@@ -0,0 +1,116 @@
+  /*
+   * Copyright 1996 The Australian National University.
+   * Copyright 1996 Fujitsu Laboratories Limited
+   * 
+   * This software may be distributed under the terms of the Gnu
+   * Public License version 2 or later
+  */
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/blk.h>
+#include <linux/genhd.h>
+#include <asm/pgtable.h>
+#include <asm/ap1000/apreg.h>
+#include <asm/ap1000/DdvReqTable.h>
+
+
+#define GENDISK_STRUCT ddv_gendisk
+
+struct RequestTable *RTable=NULL;
+struct OPrintBufArray *PrintBufs=NULL;
+struct OAlignBufArray *AlignBufs=NULL;
+struct DiskInfo *DiskInfo=NULL;
+
+extern int ddv_length[];
+
+int ddv_mlist_available(void)
+{
+	int start = RTable->start_mtable;
+	int end = RTable->end_mtable;
+	
+	if (start >= end)
+		return (MTABLE_SIZE - start);
+	return (end+1) - start;
+}
+
+
+int ddv_get_mlist(unsigned mptr[],int bnum)
+{
+	int available = ddv_mlist_available();
+	int i;
+	int start = RTable->start_mtable;
+	
+	if (available < bnum) {
+		return -1;
+	}
+	
+	for (i = 0; i < bnum; i++) {    
+		unsigned phys = (unsigned)mmu_v2p((unsigned)mptr[i]);
+		if (phys == -1)
+			panic("bad address %x in ddv_get_mlist\n",mptr[i]);
+		RTable->mtable[RTable->start_mtable] = phys;
+		RTable->start_mtable = INC_ML(RTable->start_mtable);
+	}
+	
+	return start;
+}
+
+
+
+void ddv_load_kernel(char *opcodep)
+{
+	int tsize;
+	char *p;
+	struct exec *mhead;  
+  
+	mhead = (struct exec *)opcodep;
+	p = opcodep + sizeof(*mhead);
+	
+	tsize = (mhead->a_text + (PAGE_SIZE-1)) & ~(PAGE_SIZE-1);
+	memcpy((char *)OPIBUS_BASE+mhead->a_entry,p,mhead->a_text);
+	memcpy((char *)OPIBUS_BASE+mhead->a_entry+tsize,
+	       p+mhead->a_text,mhead->a_data);
+	memset((char *)OPIBUS_BASE+mhead->a_entry+tsize+mhead->a_data,0,
+	       mhead->a_bss+PAGE_SIZE);
+	
+#ifdef DDV_DEBUG  
+	printk("CELL(%d) loaded opiu kernel of size %ld %ld %ld (%ld)\n",
+	       ap_getcid(),
+	       mhead->a_text,mhead->a_data,mhead->a_bss,mhead->a_entry);
+#endif
+}
+
+
+int ddv_restart_cpu(void)
+{ 
+	unsigned long timeout;
+
+	OPT_IO(OPIU_OP) = OPIU_RESET; 
+	OPT_IO(PRST) = PRST_IRST; 
+	if (OPT_IO(PRST) != PRST_IRST) { 
+		printk("_iu_load reset release error.\n"); 
+		return(-1);
+	}
+	for (timeout=jiffies + 10; 
+	     (jiffies < timeout) || (OPT_IO(PBUF0) == 0);
+	     ) /* wait */ ;
+	if (OPT_IO(PBUF0) == 0) {
+		printk("WARNING: option kernel didn't startup\n");
+		return(-1);
+	} else {
+		printk("option kernel IU running\n");
+		DiskInfo = (struct DiskInfo *)(OPT_IO(PBUF0) + OPIBUS_BASE);
+		RTable = (struct RequestTable *)(DiskInfo->ptrs[0]+OPIBUS_BASE);
+		PrintBufs = (struct OPrintBufArray *)(DiskInfo->ptrs[1]+OPIBUS_BASE);
+		AlignBufs = (struct OAlignBufArray *)(DiskInfo->ptrs[2]+OPIBUS_BASE);
+		
+		printk("Disk capacity: %d blocks of size %d\n",
+		       (int)DiskInfo->blocks,(int)DiskInfo->blk_size);
+		
+		OPT_IO(PBUF0) = 0;
+	}
+	return(0);
+}
+
+
+
diff -u --recursive --new-file v2.1.22/linux/drivers/ap1000/mac.c linux/drivers/ap1000/mac.c
--- v2.1.22/linux/drivers/ap1000/mac.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/ap1000/mac.c	Sun Jan 26 12:07:10 1997
@@ -0,0 +1,1177 @@
+  /*
+   * Copyright 1996 The Australian National University.
+   * Copyright 1996 Fujitsu Laboratories Limited
+   * 
+   * This software may be distributed under the terms of the Gnu
+   * Public License version 2 or later
+  */
+/*
+ * Routines for controlling the FORMAC+
+ */
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/interrupt.h>
+#include <linux/if_ether.h>	/* For the statistics structure. */
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/inet.h>
+#include <net/sock.h>
+
+#include <asm/ap1000/apreg.h>
+#include <asm/ap1000/apservice.h>
+#include <asm/pgtable.h>
+
+#include "apfddi.h"
+#include "smt-types.h"
+#include "am79c830.h"
+#include "mac.h"
+#include "plc.h"
+#include "apfddi-reg.h"
+
+#define MAC_DEBUG 0
+
+/* Values for dma_state */
+#define IDLE            0
+#define XMITTING	1
+#define RECVING		2
+
+/*
+ * Messages greater than this value are transferred to the FDDI send buffer
+ * using DMA.
+ */
+#define DMA_XMIT_THRESHOLD 64
+#define DMA_RECV_THRESHOLD 64
+
+/*
+ * If the FDDI receive buffer is occupied by less than this value, then
+ * sending has priority.
+ */
+#define RECV_THRESHOLD (20*1024)
+
+#define DMA_RESET_MASKS ((AP_CLR_INTR_MASK<<DMA_INTR_NORMAL_SH) | \
+			 (AP_CLR_INTR_MASK<<DMA_INTR_ERROR_SH))
+
+#define DMA_INTR_REQS ((AP_INTR_REQ<<DMA_INTR_NORMAL_SH) | \
+		       (AP_INTR_REQ<<DMA_INTR_ERROR_SH))
+
+static void mac_print_state(void);
+
+typedef unsigned int	mac_status_t;
+
+static volatile struct mac_queue *mac_queue_top = NULL;
+static volatile struct mac_queue *mac_queue_bottom = NULL;
+
+struct formac_state {
+    LoopbackType loopback;
+    int	ring_op;
+    int	recv_ptr;
+    int	recv_empty;
+    int	recv_ovf;
+    int	xmit_ptr;
+    int	xmit_free;
+    int	xmit_start;
+    int	xmit_chains;
+    int	xmit_more_ptr;
+    int	frames_xmitted;
+    int	xmit_chain_start[3];
+    int frames_recvd;
+    int recv_aborted;
+    int	xmit_aborted;
+    int	wrong_bb;
+    int recv_error;
+    volatile struct mac_queue *cur_macq; /* Current queue el for send DMA   */
+    volatile struct mac_buf cur_mbuf;    /* Current mac_buf for send DMA    */
+    struct sk_buff *cur_skb;             /* skb for received packets by DMA */
+    int dma_state;
+};
+
+#define SPFRAMES_SIZE	64		/* # words for special frames area */
+#define RECV_BUF_START	SPFRAMES_SIZE
+#define RECV_BUF_END	(BUFFER_SIZE / 2 + 2048)
+#define RECV_BUF_SIZE	(RECV_BUF_END - RECV_BUF_START)
+#define XMIT_BUF_START	RECV_BUF_END
+#define XMIT_BUF_END	BUFFER_SIZE
+
+#define S2_RMT_EVENTS	(S2_CLAIM_STATE | S2_MY_CLAIM | S2_HIGHER_CLAIM | \
+			 S2_LOWER_CLAIM | S2_BEACON_STATE | S2_MY_BEACON | \
+			 S2_OTHER_BEACON | S2_RING_OP | S2_MULTIPLE_DA | \
+			 S2_TOKEN_ERR | S2_DUPL_CLAIM | S2_TRT_EXP_RECOV)
+
+struct mac_info *this_mac_info;
+struct formac_state this_mac_state;
+
+int
+mac_init(struct mac_info *mip)
+{
+    struct formac_state *msp = &this_mac_state;
+
+    bif_add_debug_key('f',mac_print_state,"show FDDI mac state");
+
+    this_mac_info = mip;
+
+    mac->cmdreg1 = C1_SOFTWARE_RESET;
+    mac->said = (mip->s_address[0] << 8) + mip->s_address[1];
+    mac->laim = (mip->l_address[0] << 8) + mip->l_address[1];
+    mac->laic = (mip->l_address[2] << 8) + mip->l_address[3];
+    mac->lail = (mip->l_address[4] << 8) + mip->l_address[5];
+    mac->sagp = (mip->s_group_adrs[0] << 8) + mip->s_group_adrs[1];
+    mac->lagm = (mip->l_group_adrs[0] << 8) + mip->l_group_adrs[1];
+    mac->lagc = (mip->l_group_adrs[2] << 8) + mip->l_group_adrs[3];
+    mac->lagl = (mip->l_group_adrs[4] << 8) + mip->l_group_adrs[5];
+    mac->tmax = mip->tmax >> 5;
+    mac->tvx = (mip->tvx - 254) / 255;	/* it's -ve, round downwards */
+    mac->treq0 = mip->treq;
+    mac->treq1 = mip->treq >> 16;
+    mac->pri0 = ~0;
+    mac->pri1 = ~0;
+    mac->pri2 = ~0;
+    mac->mdreg2 = /*M2_STRIP_FCS +*/ M2_CHECK_PARITY + M2_EVEN_PARITY
+	+ 3 * M2_RCV_BYTE_BDRY + M2_ENABLE_HSREQ
+	+ M2_ENABLE_NPDMA + M2_SYNC_NPDMA + M2_RECV_BAD_FRAMES;
+    mac->eacb = RECV_BUF_START - 1;
+    mac->earv = XMIT_BUF_START - 1;
+    mac->eas = mac->earv;
+    mac->eaa0 = BUFFER_SIZE - 1;
+    mac->eaa1 = mac->eaa0;
+    mac->eaa2 = mac->eaa1;
+    mac->wpxsf = 0;
+    mac->rpr = RECV_BUF_START;
+    mac->wpr = RECV_BUF_START + 1;
+    mac->swpr = RECV_BUF_START;
+    mac->wpxs = mac->eas;
+    mac->swpxs = mac->eas;
+    mac->rpxs = mac->eas;
+    mac->wpxa0 = XMIT_BUF_START;
+    mac->rpxa0 = XMIT_BUF_START;
+
+    memset(msp, 0, sizeof(*msp));
+    msp->recv_ptr = RECV_BUF_START;
+    msp->recv_empty = 1;
+    msp->xmit_ptr = XMIT_BUF_START;
+    msp->xmit_free = XMIT_BUF_START + 1;
+    msp->xmit_start = XMIT_BUF_START;
+    msp->xmit_chains = 0;
+    msp->frames_xmitted = 0;
+    msp->frames_recvd = 0;
+    msp->recv_aborted = 0;
+
+    mac->mdreg1 = M1_MODE_MEMORY;
+
+    mac_make_spframes();
+
+    return 0;
+}
+
+int
+mac_inited(struct mac_info *mip)
+{
+    struct formac_state *msp = &this_mac_state;
+    mac_status_t st1, st2;
+
+    if (mac->said != (mip->s_address[0] << 8) + mip->s_address[1]
+	|| mac->laim != (mip->l_address[0] << 8) + mip->l_address[1]
+	|| mac->laic != (mip->l_address[2] << 8) + mip->l_address[3]
+	|| mac->lail != (mip->l_address[4] << 8) + mip->l_address[5]
+	|| mac->sagp != (mip->s_group_adrs[0] << 8) + mip->s_group_adrs[1]
+	|| mac->lagm != (mip->l_group_adrs[0] << 8) + mip->l_group_adrs[1]
+	|| mac->lagc != (mip->l_group_adrs[2] << 8) + mip->l_group_adrs[3]
+	|| mac->lagl != (mip->l_group_adrs[4] << 8) + mip->l_group_adrs[5])
+	return 1;
+    if ((mac->mdreg1 & ~M1_ADDET) != (M1_MODE_ONLINE | M1_SELECT_RA
+				      | M1_FULL_DUPLEX))
+	return 3;
+    if (mac->treq0 != (mip->treq & 0xffff)
+	|| mac->treq1 != ((unsigned)mip->treq >> 16))
+	return 4;
+
+    st1 = (mac->st1u << 16) + mac->st1l;
+    st2 = (mac->st2u << 16) + mac->st2l;
+    if ((st2 & S2_RING_OP) == 0)
+	return 5;
+
+    /* It's probably OK, reset some things to be safe. */
+    this_mac_info = mip;
+    *csr0 &= ~CS0_HREQ;
+    mac->tmax = mip->tmax >> 5;
+    mac->tvx = (mip->tvx - 254) / 255;	/* it's -ve, round downwards */
+    mac->pri0 = ~0;
+    mac->pri1 = ~0;
+    mac->pri2 = ~0;
+    mac->mdreg2 = /*M2_STRIP_FCS +*/ M2_CHECK_PARITY + M2_EVEN_PARITY
+	+ 3 * M2_RCV_BYTE_BDRY + M2_ENABLE_HSREQ
+	+ M2_ENABLE_NPDMA + M2_SYNC_NPDMA + M2_RECV_BAD_FRAMES;
+
+    /* clear out the receive queue */
+    mac->mdreg1 = (mac->mdreg1 & ~M1_ADDET) | M1_ADDET_DISABLE_RECV;
+    mac->rpr = RECV_BUF_START;
+    mac->wpr = RECV_BUF_START + 1;
+    mac->swpr = RECV_BUF_START;
+
+    memset(msp, 0, sizeof(*msp));
+    msp->recv_ptr = RECV_BUF_START;
+    msp->recv_empty = 1;
+
+    /* XXX reset transmit pointers */
+    mac->cmdreg2 = C2_ABORT_XMIT;
+    mac->cmdreg2 = C2_RESET_XMITQS;
+    mac->wpxa0 = XMIT_BUF_START;
+    mac->rpxa0 = XMIT_BUF_START;
+    msp->xmit_ptr = XMIT_BUF_START;
+    msp->xmit_free = XMIT_BUF_START + 1;
+    msp->xmit_start = XMIT_BUF_START;
+    msp->xmit_chains = 0;
+
+    mac_make_spframes();
+    mac->cmdreg1 = C1_CLR_ALL_LOCKS;
+
+    msp->frames_xmitted = 0;
+    msp->frames_recvd = 0;
+    msp->recv_aborted = 0;
+    msp->ring_op = 1;
+
+    mac->mdreg1 = (mac->mdreg1 & ~M1_ADDET) | M1_ADDET_NSA;
+    mac->imsk1u = ~(S1_XMIT_ABORT | S1_END_FRAME_ASYNC0) >> 16;
+    mac->imsk1l = ~(S1_PAR_ERROR_ASYNC0 | S1_QUEUE_LOCK_ASYNC0);
+    mac->imsk2u = ~(S2_RECV_COMPLETE | S2_RECV_BUF_FULL | S2_RECV_FIFO_OVF
+		    | S2_ERR_SPECIAL_FR | S2_RMT_EVENTS
+		    | S2_NP_SIMULT_LOAD) >> 16;
+    mac->imsk2l = ~(S2_RMT_EVENTS | S2_MISSED_FRAME);
+
+    return 0;
+}
+
+void mac_make_spframes(void)
+{
+    volatile int *bp;
+    struct mac_info *mip = this_mac_info;
+    int sa;
+    struct formac_state *msp = &this_mac_state;
+
+    /* initialize memory to avoid parity errors */
+    *csr0 &= ~CS0_HREQ;
+    *csr1 &= ~CS1_BUF_WR_TAG;
+    for (bp = &buffer_mem[BUFFER_SIZE]; bp > &buffer_mem[XMIT_BUF_START];)
+	*--bp = 0xdeadbeef;
+    for (; bp > buffer_mem;)
+	*--bp = 0xfeedf00d;
+    buffer_mem[msp->recv_ptr] = 0;
+
+    bp = buffer_mem;
+    *bp++ = 0;			/* auto-void frame pointer (not used) */
+
+    /* make claim frame */
+    sa = bp - buffer_mem;
+    *bp++ = 0xd8000011;		/* claim frame descr. + length */
+    *bp++ = 0xc3;		/* FC value for claim frame, long addr */
+    *bp++ = (mip->l_address[0] << 24) + (mip->l_address[1] << 16)
+	+ (mip->l_address[2] << 8) + mip->l_address[3];
+    *bp++ = (mip->l_address[4] << 24) + (mip->l_address[5] << 16)
+	+ (mip->l_address[0] << 8) + mip->l_address[1];
+    *bp++ = (mip->l_address[2] << 24) + (mip->l_address[3] << 16)
+	+ (mip->l_address[4] << 8) + mip->l_address[5];
+    *bp++ = mip->treq;
+    mac->sacl = bp - buffer_mem; /* points to pointer to claim frame */
+    *bp++ = 0xa0000000 + sa;	/* pointer to start of claim frame */
+
+    /* make beacon frame */
+    sa = bp - buffer_mem;
+    *bp++ = 0xd8000011;		/* beacon frame descr. + length */
+    *bp++ = 0xc2;		/* FC value for beacon frame, long addr */
+    *bp++ = 0;			/* DA = 0 */
+    *bp++ = (mip->l_address[0] << 8) + mip->l_address[1];
+    *bp++ = (mip->l_address[2] << 24) + (mip->l_address[3] << 16)
+	+ (mip->l_address[4] << 8) + mip->l_address[5];
+    *bp++ = 0;			/* beacon reason = failed claim */
+    mac->sabc = bp - buffer_mem;
+    *bp++ = 0xa0000000 + sa;	/* pointer to start of beacon frame */
+}
+
+void mac_reset(LoopbackType loopback)
+{
+    int mode;
+    struct formac_state *msp = &this_mac_state;
+
+    msp->loopback = loopback;
+    switch (loopback) {
+    case loop_none:
+	mode = M1_MODE_ONLINE;
+	break;
+    case loop_formac:
+	mode = M1_MODE_INT_LOOP;
+	break;
+    default:
+	mode = M1_MODE_EXT_LOOP;
+	break;
+    }
+    mac->mdreg1 = mode | M1_ADDET_NSA | M1_SELECT_RA | M1_FULL_DUPLEX;
+    mac->cmdreg1 = C1_IDLE_LISTEN;
+    mac->cmdreg1 = C1_CLR_ALL_LOCKS;
+    mac->imsk1u = ~(S1_XMIT_ABORT | S1_END_FRAME_ASYNC0) >> 16;
+    mac->imsk1l = ~(S1_PAR_ERROR_ASYNC0 | S1_QUEUE_LOCK_ASYNC0);
+    mac->imsk2u = ~(S2_RECV_COMPLETE | S2_RECV_BUF_FULL | S2_RECV_FIFO_OVF
+		    | S2_ERR_SPECIAL_FR | S2_RMT_EVENTS
+		    | S2_NP_SIMULT_LOAD) >> 16;
+    mac->imsk2l = ~(S2_RMT_EVENTS | S2_MISSED_FRAME);
+}
+
+void mac_claim(void)
+{
+    mac->cmdreg1 = C1_CLAIM_LISTEN;
+}
+
+void mac_disable(void)
+{
+    mac->mdreg1 = M1_MODE_MEMORY;
+    mac->imsk1u = ~0;
+    mac->imsk1l = ~0;
+    mac->imsk2u = ~0;
+    mac->imsk2l = ~0;
+    mac->wpr = mac->swpr + 1;
+    if (mac->wpr > mac->earv)
+	mac->wpr = mac->eacb + 1;
+    buffer_mem[mac->swpr] = 0;
+}
+
+void mac_stats(void)
+{
+    struct formac_state *msp = &this_mac_state;
+
+    if (msp->recv_ovf)
+	printk("%d receive buffer overflows\n", msp->recv_ovf);
+    if (msp->wrong_bb)
+	printk("%d frames on wrong byte bdry\n", msp->wrong_bb);
+    printk("%d frames transmitted, %d aborted\n", msp->frames_xmitted,
+	   msp->xmit_aborted);
+    printk("%d frames received, %d aborted\n", msp->frames_recvd,
+	   msp->recv_aborted);
+    printk("%d frames received with errors\n", msp->recv_error);
+}
+
+void mac_sleep(void)
+{
+    /* disable the receiver */
+    mac->mdreg1 = (mac->mdreg1 & ~M1_ADDET) | M1_ADDET_DISABLE_RECV;
+}
+
+void mac_poll(void)
+{
+    mac_status_t st1, st2;
+    struct formac_state *msp = &this_mac_state;
+    int up, f, d, l, r, e, i;
+
+    st1 = (mac->st1u << 16) + mac->st1l;
+    st2 = (mac->st2u << 16) + mac->st2l;
+
+    if (st2 & S2_NP_SIMULT_LOAD)
+	panic("NP/formac simultaneous load!!!");
+
+    up = (st2 & S2_RING_OP) != 0;
+    if (up != msp->ring_op) {
+	/* ring has come up or down */
+	msp->ring_op = up;
+	printk("mac: ring %s\n", up? "up": "down");
+	set_ring_op(up);
+    }
+
+    if (up) {
+	if (st1 & S1_XMIT_ABORT) {
+	    ++msp->xmit_aborted;
+	    if (st1 & S1_QUEUE_LOCK_ASYNC0) {
+		printk("mac: xmit queue locked, resetting xmit buffer\n");
+		mac->cmdreg2 = C2_RESET_XMITQS;	/* XXX bit gross */
+		mac->rpxa0 = XMIT_BUF_START;
+		buffer_mem[XMIT_BUF_START] = 0;
+		msp->xmit_ptr = XMIT_BUF_START;
+		msp->xmit_start = XMIT_BUF_START;
+		msp->xmit_chains = 0;
+		mac->cmdreg1 = C1_CLR_ASYNCQ0_LOCK;
+		st1 &= ~(S1_END_CHAIN_ASYNC0 | S1_END_FRAME_ASYNC0
+			 | S1_XINSTR_FULL_ASYNC0);
+	    } else
+		st1 |= S1_END_FRAME_ASYNC0;
+	} else if (st1 & S1_QUEUE_LOCK_ASYNC0) {
+	    printk("mac: xmit queue locked, why?\n");
+	    mac->cmdreg1 = C1_CLR_ASYNCQ0_LOCK;
+	}
+
+	if (st1 & S1_END_FRAME_ASYNC0) {
+	    /* advance xmit_start */
+	    e = msp->xmit_start;
+	    while (e != msp->xmit_ptr) {
+		/* find the end of the current frame */
+		f = buffer_mem[e]; /* read pointer */
+		if (f == 0)
+		    break;	/* huh?? */
+		f &= 0xffff;
+		d = buffer_mem[f]; /* read descriptor */
+		l = ((d & 0xffff) + ((d >> TD_BYTE_BDRY_LG) & 3) + 3) >> 2;
+		e = f + 1 + l;	/* index of ptr at end of frame */
+		r = mac->rpxa0;
+		if ((r <= msp->xmit_ptr && r < e && e <= msp->xmit_ptr)
+		    || (r > msp->xmit_ptr && (r < e || e <= msp->xmit_ptr)))
+		    break;	/* up to current frame */
+		/* printk("frame @ %x done\n", msp->xmit_start); */
+		msp->xmit_start = e;
+		if ((st1 & S1_XMIT_ABORT) == 0)
+		    ++msp->frames_xmitted;
+		if ((msp->xmit_chains == 1 && e == msp->xmit_ptr) ||
+		    (msp->xmit_chains > 1 && e == msp->xmit_chain_start[1])) {
+		    /* we've finished chain 0 */
+		    --msp->xmit_chains;
+		    for (i = 0; i < msp->xmit_chains; ++i)
+			msp->xmit_chain_start[i] = msp->xmit_chain_start[i+1];
+		    if (msp->xmit_chains >= 2) {
+			mac->cmdreg2 = C2_XMIT_ASYNCQ0;
+			/* printk("mac_poll: xmit chain\n"); */
+		    }
+		    if (msp->xmit_chains == 0)
+			*csr0 &= ~CS0_LED1;
+		}
+	    }
+	    /*
+	     * Now that we have a bit more space in the transmit buffer,
+	     * see if we want to put another frame in.
+	     */
+#if MAC_DEBUG
+	    printk("Removed space in transmit buffer.\n");
+#endif
+	    mac_process();
+	}
+    }
+
+    if (st2 & S2_RMT_EVENTS) {
+	rmt_event(st2);
+    }
+
+    if (st2 & S2_RECV_COMPLETE) {
+	/*
+	 * A frame has just finished arriving in the receive buffer.
+	 */
+	*csr0 |= CS0_LED2;
+	msp->recv_empty = 0;
+#if MAC_DEBUG
+	printk("Frame has just trickled in...\n");
+#endif
+	mac_process();
+    }
+
+    if (st2 & S2_RECV_BUF_FULL) {
+	/*
+	 * receive buffer overflow: reset and unlock the receive buffer.
+	 */
+/*	printk("mac: receive buffer full\n"); */
+	mac->rpr = RECV_BUF_START;
+	mac->wpr = RECV_BUF_START + 1;
+	mac->swpr = RECV_BUF_START;
+	msp->recv_ptr = RECV_BUF_START;
+	msp->recv_empty = 1;
+	buffer_mem[RECV_BUF_START] = 0;
+	mac->cmdreg1 = C1_CLR_RECVQ_LOCK;
+	++msp->recv_ovf;
+
+#if 0
+    } else if (st2 & S2_RECV_FIFO_OVF) {
+	printk("mac: receive FIFO overflow\n");
+	/* any further action required here? */
+
+    } else if (st2 & S2_MISSED_FRAME) {
+	printk("mac: missed frame\n");
+#endif
+    }
+
+    if (st2 & S2_ERR_SPECIAL_FR) {
+	printk("mac: bug: error in special frame\n");
+	mac_disable();
+    }
+}
+
+void
+mac_xmit_alloc(sp, bb)
+    struct mac_buf *sp;
+    int bb;
+{
+    int nwords;
+
+    nwords = (sp->length + bb + 3) >> 2;
+    sp->fr_start = mac_xalloc(nwords + 2);
+    sp->fr_end = sp->fr_start + nwords + 1;
+    sp->ptr = (char *) &buffer_mem[sp->fr_start + 1] + bb;
+    buffer_mem[sp->fr_start] = TD_MAGIC + (bb << TD_BYTE_BDRY_LG) + sp->length;
+}
+
+void
+mac_queue_frame(sp)
+    struct mac_buf *sp;
+{
+    struct formac_state *msp = &this_mac_state;
+
+    buffer_mem[sp->fr_end] = 0;	/* null pointer at end of frame */
+    buffer_mem[msp->xmit_ptr] = PT_MAGIC + sp->fr_start;
+    if (msp->xmit_chains <= 2) {
+	msp->xmit_chain_start[msp->xmit_chains] = msp->xmit_ptr;
+	if (msp->xmit_chains < 2)
+	    mac->cmdreg2 = C2_XMIT_ASYNCQ0;
+	++msp->xmit_chains;
+    } else {
+	buffer_mem[msp->xmit_more_ptr] |= TD_MORE;
+    }
+    msp->xmit_ptr = sp->fr_end;
+    msp->xmit_more_ptr = sp->fr_start;
+    *csr0 |= CS0_LED1;
+}
+
+int
+mac_xalloc(int nwords)
+{
+    int fr_start;
+    struct formac_state *msp = &this_mac_state;
+
+    /*
+     * Find some room in the transmit buffer.
+     */
+    fr_start = msp->xmit_free;
+    if (fr_start > msp->xmit_start) {
+	if (fr_start + nwords > XMIT_BUF_END) {
+	    /* no space at end - see if we can start again from the front */
+	    fr_start = XMIT_BUF_START;
+	    if (fr_start + nwords > msp->xmit_start)
+		panic("no space in xmit buffer (1)");
+	}
+    } else {
+	if (fr_start + nwords > msp->xmit_start)
+	    panic("no space in xmit buffer (2)");
+    }
+
+    msp->xmit_free = fr_start + nwords;
+
+    return fr_start;
+}
+
+int
+mac_recv_frame(sp)
+    struct mac_buf *sp;
+{
+    struct formac_state *msp = &this_mac_state;
+    int status, bb, orig_recv_ptr;
+
+    orig_recv_ptr = msp->recv_ptr;
+    for (;;) {
+	status = buffer_mem[msp->recv_ptr];
+	if ((status & RS_VALID) == 0) {
+	    if (status != 0) {
+		printk("recv buf out of sync: recv_ptr=%x status=%x\n",
+		       msp->recv_ptr, status);
+		printk(" rpr=%x swpr=%x, buf[rpr]=%x\n", mac->rpr, mac->swpr,
+		       buffer_mem[mac->rpr]);
+		msp->recv_ptr = mac->swpr;
+	    }
+	    *csr0 &= ~CS0_LED2;
+	    msp->recv_empty = 1;
+	    if (mac->rpr == orig_recv_ptr)
+		mac->rpr = msp->recv_ptr;
+	    return 0;
+	}
+	if (status & RS_ABORTED)
+	    ++msp->recv_aborted;
+	else {
+	    bb = (status >> RS_BYTE_BDRY_LG) & 3;
+	    if (bb != 3) {
+		++msp->wrong_bb;
+		bb = 3;
+	    }
+	    if ((status & RS_ERROR) == 0)
+		break;
+	    ++msp->recv_error;
+	    msp->recv_ptr += NWORDS((status & RS_LENGTH) + bb);
+	}
+	if (++msp->recv_ptr >= RECV_BUF_END)
+	    msp->recv_ptr -= RECV_BUF_SIZE;
+    }
+    ++msp->frames_recvd;
+    if (mac->rpr == orig_recv_ptr)
+	mac->rpr = msp->recv_ptr;
+
+    sp->fr_start = msp->recv_ptr;
+    sp->length = (status & RS_LENGTH) + bb;	/* + 4 (status) - 4 (FCS) */
+    sp->ptr = (void *) &buffer_mem[sp->fr_start];
+    if ((msp->recv_ptr += NWORDS(sp->length) + 1) >= RECV_BUF_END)
+	msp->recv_ptr -= RECV_BUF_SIZE;
+    sp->fr_end = msp->recv_ptr;
+    sp->wraplen = (RECV_BUF_END - sp->fr_start) * 4;
+    sp->wrapptr = (void *) &buffer_mem[RECV_BUF_START];
+
+    return 1;
+}
+
+void
+mac_discard_frame(sp)
+    struct mac_buf *sp;
+{
+    mac->rpr = sp->fr_end;
+}
+
+/*
+ * Return the number of bytes free in the async 0 transmit queue.
+ */
+int
+mac_xmit_space(void)
+{
+    struct formac_state *msp = &this_mac_state;
+    int nw;
+
+    if (msp->xmit_free > msp->xmit_start) {
+	nw = XMIT_BUF_END - msp->xmit_free;
+	if (nw < msp->xmit_start - XMIT_BUF_START)
+	    nw = msp->xmit_start - XMIT_BUF_START;
+    } else
+	nw = msp->xmit_start - msp->xmit_free;
+    return nw <= 2? 0: (nw - 2) << 2;
+}
+
+/*
+ * Return the number of bytes of frames available in the receive queue.
+ */
+int
+mac_recv_level(void)
+{
+    int nw;
+
+    nw = mac->swpr - mac->rpr;
+    if (nw < 0)
+	nw += mac->earv - mac->eacb;
+    return nw << 2;
+}
+
+/*
+ * Return 1 iff all transmission has been completed, 0 otherwise.
+ */
+int mac_xmit_done(void)
+{
+    struct formac_state *msp = &this_mac_state;
+
+    return msp->xmit_chains == 0;
+}
+
+/*
+ * Append skbuff packet to queue.
+ */
+int mac_queue_append (struct sk_buff *skb)
+{
+    struct mac_queue *el;
+    unsigned flags;
+    save_flags(flags); cli();
+
+#if MAC_DEBUG
+    printk("Appending queue element skb 0x%x\n", skb);
+#endif
+
+    if ((el = (struct mac_queue *)kmalloc(sizeof(*el), GFP_ATOMIC)) == NULL) {
+	restore_flags(flags);
+	return 1;
+    }
+    el->next = NULL;
+    el->skb = skb;
+    
+    if (mac_queue_top == NULL) {
+	mac_queue_top = mac_queue_bottom = el;
+    }
+    else {
+	mac_queue_bottom->next = el;
+	mac_queue_bottom = el;
+    }
+    restore_flags(flags);
+    return 0;
+}
+
+/*
+ * If the packet originated from the same FDDI subnet as we are on,
+ * there is no need to perform checksumming as FDDI will does this
+ * us.  
+ */
+#define CHECK_IF_CHECKSUM_REQUIRED(skb) \
+    if ((skb)->protocol == ETH_P_IP) { \
+	extern struct cap_init cap_init; \
+	int *from_ip = (int *)((skb)->data+12); \
+	int *to_ip = (int *)((skb)->data+16); \
+	if ((*from_ip & cap_init.netmask) == (*to_ip & cap_init.netmask)) \
+	    (skb)->ip_summed = CHECKSUM_UNNECESSARY; \
+    }
+
+/*
+ * Try to send and/or recv frames.
+ */
+void mac_process(void)
+{
+    volatile struct dma_chan *dma = (volatile struct dma_chan *) DMA3;
+    struct formac_state *msp = &this_mac_state;
+    struct mac_queue *el;
+    int nw=0, mrl = 0, fstart, send_buffer_full = 0;
+    unsigned flags;
+
+    save_flags(flags); cli();
+
+#if MAC_DEBUG
+    printk("In mac_process()\n");
+#endif
+
+    /*
+     * Check if the DMA is being used.
+     */
+    if (msp->dma_state != IDLE) {
+	restore_flags(flags);
+	return;
+    }
+
+    while (mac_queue_top != NULL  || /* Something to transmit */
+	   (mrl = mac_recv_level()) > 0) {  /* Frames in receive buffer */
+	send_buffer_full = 0;
+#if MAC_DEBUG
+	printk("mac_process(): something to do... mqt %x mrl is %d\n", 
+	       mac_queue_top, mrl);
+#endif
+	if (mac_queue_top != NULL && mrl < RECV_THRESHOLD) {
+	    el = (struct mac_queue *)mac_queue_top;
+
+	    /*
+	     * Check there is enough space in the FDDI send buffer.
+	     */
+	    if (mac_xmit_space() < el->skb->len) {
+#if MAC_DEBUG
+		printk("process_queue(): FDDI send buffer is full\n");
+#endif
+		send_buffer_full = 1;
+	    }
+	    else {
+#if MAC_DEBUG
+		printk("mac_process(): sending a frame\n");
+#endif
+		/*
+		 * Update mac_queue_top.
+		 */
+		mac_queue_top = mac_queue_top->next;
+
+		/*
+		 * Allocate space in the FDDI send buffer.
+		 */
+		msp->cur_mbuf.length = el->skb->len-3;
+		mac_xmit_alloc((struct mac_buf *)&msp->cur_mbuf, 3);
+
+		/*
+		 * If message size is greater than DMA_XMIT_THRESHOLD, send
+		 * using DMA, otherwise use memcpy().
+		 */
+		if (el->skb->len > DMA_XMIT_THRESHOLD) {
+		    /*
+		     * Start the DMA.
+		     */
+#if MAC_DEBUG
+		    printk("mac_process(): Starting send DMA...\n");
+#endif
+		    nw = msp->cur_mbuf.fr_end - msp->cur_mbuf.fr_start + 1;
+		    mac->wpxa0 = msp->cur_mbuf.fr_start + 1;
+		    
+		    *csr0 |= CS0_HREQ_WA0;
+		    
+		    msp->cur_macq = el;
+		    msp->dma_state = XMITTING;
+		    dma->st = DMA_DMST_RST;
+		    dma->st = DMA_RESET_MASKS;
+		    dma->hskip = 1;		/* skip = 0, count = 1 */
+		    dma->vskip = 1;		/* skip = 0, count = 1 */
+		    dma->maddr = (u_char *)
+			mmu_v2p((unsigned long)el->skb->data);
+		    dma->cmd = DMA_DCMD_ST + DMA_DCMD_TYP_AUTO + 
+			DMA_DCMD_TD_MD + nw;
+		    *csr0 &= ~CS0_DMA_RECV;
+		    *csr0 |= CS0_DMA_ENABLE;
+
+		    /*
+		     * Don't process any more packets since the DMA is 
+		     * being used.
+		     */
+		    break;
+		}
+		else {   /* el->skb->len <= DMA_XMIT_THRESHOLD */
+		    /*
+		     * Copy the data directly into the FDDI buffer.
+		     */
+#if MAC_DEBUG
+		    printk("mac_proces(): Copying send data...\n");
+#endif
+		    memcpy(msp->cur_mbuf.ptr - 3, el->skb->data, 
+			   ROUND4(el->skb->len));
+		    mac_queue_frame((struct mac_buf *)&msp->cur_mbuf);
+		    dev_kfree_skb(el->skb, FREE_WRITE);
+		    kfree_s(el, sizeof(*el));
+		    continue;
+		}
+	    }
+
+	    /*
+	     * We have reached here if there is not enough space in the
+	     * send buffer.  Try to receive some packets instead.
+	     */
+	}
+
+	if (mac_recv_frame((struct mac_buf *)&msp->cur_mbuf)) {
+	    volatile int fc, llc_header_word2;
+	    int pkt_len = 0;
+
+#if MAC_DEBUG
+	    printk("mac_process(): Receiving frames...\n");
+#endif
+	    /* 
+	     * Get the fc, note only word accesses are allowed from the
+	     * FDDI buffers.
+	     */
+	    if (msp->cur_mbuf.wraplen > 4) {
+		fc = *(int *)(msp->cur_mbuf.ptr+4);
+	    }
+	    else {
+		/*
+		 * fc_word must be at the start of the FDDI buffer.
+		 */
+#if MAC_DEBUG
+		printk("Grabbed fc_word from wrapptr, wraplen %d\n", 
+		       msp->cur_mbuf.wraplen);
+#endif
+		fc = *(int *)msp->cur_mbuf.wrapptr;
+	    }
+	    fc &= 0xff;
+	    
+#if MAC_DEBUG
+	    printk("fc is 0x%x\n", fc);
+#endif
+	    if (fc < 0x50 || fc > 0x57) {
+		mac_discard_frame((struct mac_buf *)&msp->cur_mbuf);
+		continue;
+	    }
+
+	    /*
+	     * Determine the size of the packet data and allocate a socket
+	     * buffer.
+	     */
+	    pkt_len = msp->cur_mbuf.length - FDDI_HARDHDR_LEN;
+#if MAC_DEBUG
+	    printk("Packet of length %d\n", pkt_len);
+#endif
+	    msp->cur_skb = dev_alloc_skb(ROUND4(pkt_len));
+	    
+	    if (msp->cur_skb == NULL) {
+		printk("mac_process(): Memory squeeze, dropping packet.\n");
+		apfddi_stats->rx_dropped++;
+		restore_flags(flags);
+		return;
+	    }
+	    msp->cur_skb->dev = apfddi_device;
+
+	    /*
+	     * Hardware header isn't copied to skbuff.
+	     */
+	    msp->cur_skb->mac.raw = msp->cur_skb->data;
+	    apfddi_stats->rx_packets++;
+
+	    /*
+	     * Determine protocol from llc header.
+	     */
+	    if (msp->cur_mbuf.wraplen < FDDI_HARDHDR_LEN) {
+		llc_header_word2 = *(int *)(msp->cur_mbuf.wrapptr + 
+					    (FDDI_HARDHDR_LEN - 
+					     msp->cur_mbuf.wraplen - 4));
+	    }
+	    else {
+		llc_header_word2 = *(int *)(msp->cur_mbuf.ptr + 
+					    FDDI_HARDHDR_LEN - 4);
+	    }
+	    msp->cur_skb->protocol = llc_header_word2 & 0xFFFF;
+#if MAC_DEBUG
+	    printk("Got protocol 0x%x\n", msp->cur_skb->protocol);
+#endif
+	    
+	    /*
+	     * Copy data into socket buffer, which may be wrapped around the 
+	     * FDDI buffer.  Use memcpy if the size of the data is less
+	     * than DMA_RECV_THRESHOLD.  Note if DMA is used, then wrap-
+	     * arounds are handled automatically.
+	     */
+	    if (pkt_len < DMA_RECV_THRESHOLD) {
+		if (msp->cur_mbuf.length < msp->cur_mbuf.wraplen) {
+		    memcpy(skb_put(msp->cur_skb, ROUND4(pkt_len)), 
+			   msp->cur_mbuf.ptr + FDDI_HARDHDR_LEN, 
+			   ROUND4(pkt_len));
+		} 
+		else if (msp->cur_mbuf.wraplen < FDDI_HARDHDR_LEN) {
+#if MAC_DEBUG
+		    printk("Wrap case 2\n");
+#endif
+		    memcpy(skb_put(msp->cur_skb, ROUND4(pkt_len)), 
+			   msp->cur_mbuf.wrapptr + 
+			   (FDDI_HARDHDR_LEN - msp->cur_mbuf.wraplen),
+			   ROUND4(pkt_len));
+		} 
+		else {
+#if MAC_DEBUG
+		    printk("wrap case 3\n");
+#endif
+		    memcpy(skb_put(msp->cur_skb, 
+				   ROUND4(msp->cur_mbuf.wraplen-
+					  FDDI_HARDHDR_LEN)),
+			   msp->cur_mbuf.ptr + FDDI_HARDHDR_LEN, 
+			   ROUND4(msp->cur_mbuf.wraplen - FDDI_HARDHDR_LEN));
+		    memcpy(skb_put(msp->cur_skb, 
+				   ROUND4(msp->cur_mbuf.length - 
+					  msp->cur_mbuf.wraplen)),
+			   msp->cur_mbuf.wrapptr, 
+			   ROUND4(msp->cur_mbuf.length - 
+				  msp->cur_mbuf.wraplen));
+		}
+
+#if MAC_DEBUG
+		if (msp->cur_skb->protocol == ETH_P_IP) {
+		    dump_packet("apfddi_rx:", msp->cur_skb->data, pkt_len, 0);
+		}
+		else if (msp->cur_skb->protocol == ETH_P_ARP) {
+		    struct arphdr *arp = (struct arphdr *)msp->cur_skb->data;
+		    printk("arp->ar_op is 0x%x ar_hrd %d ar_pro 0x%x ar_hln %d ar_ln %d\n", 
+			   arp->ar_op, arp->ar_hrd, arp->ar_pro, arp->ar_hln, 
+			   arp->ar_pln);
+		    printk("sender hardware address: %x:%x:%x:%x:%x:%x\n",
+			   *((u_char *)msp->cur_skb->data+8),
+			   *((u_char *)msp->cur_skb->data+9),
+			   *((u_char *)msp->cur_skb->data+10),
+			   *((u_char *)msp->cur_skb->data+11),
+			   *((u_char *)msp->cur_skb->data+12),
+			   *((u_char *)msp->cur_skb->data+13));
+		    printk("sender IP number %d.%d.%d.%d\n", 
+			   *((u_char *)msp->cur_skb->data+14),
+			   *((u_char *)msp->cur_skb->data+15),
+			   *((u_char *)msp->cur_skb->data+16),
+			   *((u_char *)msp->cur_skb->data+17));
+		    printk("receiver hardware address: %x:%x:%x:%x:%x:%x\n",
+			   *((u_char *)msp->cur_skb->data+18),
+			   *((u_char *)msp->cur_skb->data+19),
+			   *((u_char *)msp->cur_skb->data+20),
+			   *((u_char *)msp->cur_skb->data+21),
+			   *((u_char *)msp->cur_skb->data+22),
+			   *((u_char *)msp->cur_skb->data+23));
+		    printk("receiver IP number %d.%d.%d.%d\n", 
+			   *((u_char *)msp->cur_skb->data+24),
+			   *((u_char *)msp->cur_skb->data+25),
+			   *((u_char *)msp->cur_skb->data+26),
+			   *((u_char *)msp->cur_skb->data+27));
+		}
+#endif
+		CHECK_IF_CHECKSUM_REQUIRED(msp->cur_skb);
+
+		/*
+		 * Inform the network layer of the new packet.
+		 */
+#if MAC_DEBUG
+		printk("Calling netif_rx()\n");
+#endif
+		netif_rx(msp->cur_skb);
+
+		/*
+		 * Remove frame from FDDI buffer.
+		 */
+		mac_discard_frame((struct mac_buf *)&msp->cur_mbuf);
+		continue;
+	    }
+	    else {
+		/*
+		 * Set up dma and break.
+		 */
+#if MAC_DEBUG
+		printk("mac_process(): Starting receive DMA...\n");
+#endif
+		nw = NWORDS(pkt_len);
+		msp->dma_state = RECVING;
+		*csr0 &= ~(CS0_HREQ | CS0_DMA_ENABLE);
+/*		*csr1 |= CS1_RESET_FIFO;
+		*csr1 &= ~CS1_RESET_FIFO; */
+		if ((*csr1 & CS1_FIFO_LEVEL) != 0) {
+		    int x;
+		    printk("fifo not empty! (csr1 = 0x%x) emptying...", *csr1);
+		    do {
+			x = *fifo;
+		    } while ((*csr1 & CS1_FIFO_LEVEL) != 0);
+		    printk("done\n");
+		}
+		fstart = msp->cur_mbuf.fr_start + NWORDS(FDDI_HARDHDR_LEN);
+		if (fstart >= RECV_BUF_END)
+		    fstart -= RECV_BUF_SIZE;
+		mac->rpr = fstart;
+#if MAC_DEBUG
+		printk("rpr=0x%x, nw=0x%x, stat=0x%x\n",
+		       mac->rpr, nw, buffer_mem[msp->cur_mbuf.fr_start]);
+#endif
+		dma->st = DMA_DMST_RST;
+		dma->st = DMA_RESET_MASKS;
+		dma->hskip = 1;         /* skip = 0, count = 1 */
+		dma->vskip = 1;         /* skip = 0, count = 1 */
+		dma->maddr = (u_char *)
+		    mmu_v2p((unsigned long)
+			    skb_put(msp->cur_skb, ROUND4(pkt_len)));
+		dma->cmd = DMA_DCMD_ST + DMA_DCMD_TYP_AUTO + DMA_DCMD_TD_DM
+		    + nw - 4;
+		*csr0 |= CS0_HREQ_RECV | CS0_DMA_RECV;
+		*csr0 |= CS0_DMA_ENABLE;
+#if MAC_DEBUG
+		printk("mac_process(): DMA is away!\n");
+#endif
+		break;
+	    }
+	}
+	else {
+#if MAC_DEBUG
+	    printk("mac_recv_frame failed\n");
+#endif
+	    if (msp->recv_empty && send_buffer_full)
+		break;
+	}
+    }
+    /*
+     * Update mac_queue_bottom.
+     */
+    if (mac_queue_top == NULL)
+	mac_queue_bottom = NULL;
+
+#if MAC_DEBUG
+    printk("End of mac_process()\n");
+#endif
+    restore_flags(flags);
+}
+    
+
+#define DMA_IN(reg) (*(volatile unsigned *)(reg))
+#define DMA_OUT(reg,v) (*(volatile unsigned *)(reg) = (v))
+
+/*
+ * DMA completion handler.
+ */
+void mac_dma_complete(void)
+{
+    volatile struct dma_chan *dma;
+    struct formac_state *msp = &this_mac_state;
+    unsigned a;
+
+    a = DMA_IN(DMA3_DMST);
+    if (!(a & DMA_INTR_REQS)) {
+	if (msp->dma_state != IDLE && (a & DMA_DMST_AC) == 0) {
+	    printk("dma completed but no interrupt!\n");
+	    msp->dma_state = IDLE;
+	}
+	return;
+    }
+
+    DMA_OUT(DMA3_DMST,AP_CLR_INTR_REQ<<DMA_INTR_NORMAL_SH);
+    DMA_OUT(DMA3_DMST,AP_CLR_INTR_REQ<<DMA_INTR_ERROR_SH);
+
+    dma = (volatile struct dma_chan *) DMA3;
+
+#if MAC_DEBUG
+    printk("In mac_dma_complete\n");
+#endif
+
+    if (msp->dma_state == XMITTING && ((dma->st & DMA_DMST_AC) == 0)) {
+	/*
+	 * Transmit DMA finished.
+	 */
+	int i = 20;
+#if MAC_DEBUG
+	printk("In mac_dma_complete for transmit complete\n");
+#endif
+	while (*csr1 & CS1_FIFO_LEVEL) {
+	    if (--i <= 0) {
+		printk("csr0=0x%x csr1=0x%x: fifo not emptying\n", *csr0,
+		       *csr1);
+		return;
+	    }
+	}
+	*csr0 &= ~(CS0_HREQ | CS0_DMA_ENABLE);
+	msp->dma_state = IDLE;
+#if MAC_DEBUG
+	printk("mac_dma_complete(): Calling mac_queue_frame\n");
+#endif
+	mac_queue_frame((struct mac_buf *)&msp->cur_mbuf);
+	dev_kfree_skb(msp->cur_macq->skb, FREE_WRITE);
+	kfree_s((struct mac_buf *)msp->cur_macq, sizeof(*(msp->cur_macq)));
+	msp->cur_macq = NULL;
+#if MAC_DEBUG
+	printk("mac_dma_complete(): Calling mac_process()\n");
+#endif
+	mac_process();
+#if MAC_DEBUG
+	printk("End of mac_dma_complete transmitting\n");
+#endif
+    }
+    else if (msp->dma_state == RECVING && ((dma->st & DMA_DMST_AC) == 0)) {
+	/*
+	 * Receive DMA finished.  Copy the last four words from the
+	 * fifo into the buffer, after turning off the host requests.
+	 * We do this to avoid reading past the end of frame.
+	 */
+	int *ip, i;
+
+#if MAC_DEBUG
+	printk("In mac_dma_complete for receive complete\n");
+#endif
+	msp->dma_state = IDLE;
+	ip = (int *)mmu_p2v((unsigned long)dma->cmaddr);
+
+#if MAC_DEBUG
+	printk("ip is 0x%x, skb->data is 0x%x\n", ip, msp->cur_skb->data);
+#endif
+
+	*csr0 &= ~(CS0_DMA_ENABLE | CS0_HREQ);
+
+	for (i = 0; (*csr1 & CS1_FIFO_LEVEL); ++i)
+	    ip[i] = *fifo;
+	if (i != 4)
+	    printk("mac_dma_complete(): not four words remaining in fifo?\n");
+#if MAC_DEBUG
+	printk("Copied last four words out of fifo\n");
+#endif
+	
+	/*
+	 * Remove the frame from the FDDI receive buffer.
+	 */
+	mac_discard_frame((struct mac_buf *)&msp->cur_mbuf);
+
+	CHECK_IF_CHECKSUM_REQUIRED(msp->cur_skb);
+
+	/*
+	 * Now inject the packet into the network system.
+	 */
+	netif_rx(msp->cur_skb);
+
+#if MAC_DEBUG
+	dump_packet("mac_dma_complete:", msp->cur_skb->data, 0, 0);
+#endif
+
+	/*
+	 * Check if any more frames can be processed.
+	 */
+	mac_process();
+
+#if MAC_DEBUG
+	printk("End of mac_dma_complete receiving\n");
+#endif
+    }
+#if MAC_DEBUG
+    printk("End of mac_dma_complete()\n");
+#endif
+}
+    
+static void mac_print_state(void)
+{
+    struct formac_state *msp = &this_mac_state;
+
+    printk("DMA3_DMST is 0x%x dma_state is %d\n", DMA_IN(DMA3_DMST),
+	   msp->dma_state);
+    printk("csr0 = 0x%x, csr1 = 0x%x\n", *csr0, *csr1);
+}
+
+
diff -u --recursive --new-file v2.1.22/linux/drivers/ap1000/mac.h linux/drivers/ap1000/mac.h
--- v2.1.22/linux/drivers/ap1000/mac.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/ap1000/mac.h	Sun Jan 26 12:07:10 1997
@@ -0,0 +1,82 @@
+  /*
+   * Copyright 1996 The Australian National University.
+   * Copyright 1996 Fujitsu Laboratories Limited
+   * 
+   * This software may be distributed under the terms of the Gnu
+   * Public License version 2 or later
+  */
+/*
+ * Definitions of MAC state structures etc.
+ */
+
+struct mac_info {
+    TimerTwosComplement	tmax;
+    TimerTwosComplement tvx;
+    TimerTwosComplement treq;
+    ShortAddressType	s_address;
+    LongAddressType	l_address;
+    ShortAddressType	s_group_adrs;
+    LongAddressType	l_group_adrs;
+    int			rcv_own_frames;
+    int			only_good_frames;
+};
+
+
+struct mac_buf {
+    struct mac_buf *next;
+    int ack;
+    int length;
+    void *ptr;
+    int wraplen;
+    void *wrapptr;
+    int fr_start;
+    int fr_end;
+};
+
+int mac_xmit_space(void);
+void mac_xmit_alloc(struct mac_buf *, int);
+void mac_queue_frame(struct mac_buf *);
+int mac_recv_frame(struct mac_buf *);
+void mac_discard_frame(struct mac_buf *);
+int mac_init(struct mac_info *mip);
+int mac_inited(struct mac_info *mip);
+void mac_reset(LoopbackType loopback);
+void mac_claim(void);
+void mac_sleep(void);
+void mac_poll(void);
+void mac_disable(void);
+void mac_make_spframes(void);
+int mac_xalloc(int nwords);
+int mac_xmit_dma(struct sk_buff *skb);
+void mac_dma_complete(void);
+void mac_process(void);
+int mac_queue_append(struct sk_buff *skb);
+
+struct dma_chan {
+    int cmd;			/* cmd << 16 + size */
+    int st;			/* status << 16 + current size */
+    int hskip;			/* hskip << 16 + hcnt */
+    int vskip;			/* vskip << 16 + vcnt */
+    unsigned char *maddr;	/* memory address */
+    unsigned char *cmaddr;	/* current memory address */
+    int ccount;			/* h_count << 16 + v_count */
+    int *tblp;			/* table pointer */
+    int *ctblp;			/* current table pointer */
+    unsigned char *hdptr;	/* header pointer */
+};
+
+#define ROUND4(x)	(((x) + 3) & -4)
+#define ROUND8(x)	(((x) + 7) & -8)
+#define ROUND16(x)	(((x) + 15) & -16)
+#define ROUNDLINE(x)	ROUND16(x)
+
+#define NWORDS(x)	(((x) + 3) >> 2)
+#define NLINES(x)	(((x) + 15) >> 4)
+
+/*
+ * Queue element used to queue transmit requests on the FDDI.
+ */
+struct mac_queue {
+    volatile struct mac_queue *next;
+    struct sk_buff *skb;
+};
diff -u --recursive --new-file v2.1.22/linux/drivers/ap1000/plc.c linux/drivers/ap1000/plc.c
--- v2.1.22/linux/drivers/ap1000/plc.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/ap1000/plc.c	Sun Jan 26 12:07:10 1997
@@ -0,0 +1,393 @@
+  /*
+   * Copyright 1996 The Australian National University.
+   * Copyright 1996 Fujitsu Laboratories Limited
+   * 
+   * This software may be distributed under the terms of the Gnu
+   * Public License version 2 or later
+  */
+/*
+ * Routines for controlling the Am79c864 physical layer controller.
+ *
+ * This chip implements some parts of the FDDI SMT standard
+ * (PCM: physical connection management, LEM: link error monitor, etc.)
+ * as well as the FDDI PHY standard.
+ */
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include "apfddi.h"
+#include "smt-types.h"
+#include "am79c864.h"
+#include "plc.h"
+#include "apfddi-reg.h"
+
+typedef enum {
+    off,
+    signalling,
+    doing_lct,
+    joining,
+    active
+} PlcPhase;
+    
+struct plc_state {
+    LoopbackType	loopback;
+    char		t_val[16];
+    char		r_val[16];
+    int			n;
+    PortType		peer_type;
+    PlcPhase		phase;
+};
+
+struct plc_info *this_plc_info;
+struct plc_state this_plc_state;
+
+void plc_init(struct plc_info *pip)
+{
+    int class, x;
+    struct plc_state *psp = &this_plc_state;
+
+    this_plc_info = pip;
+
+    /* first turn it off, clear registers */
+    class = pip->port_type == pt_s? CB_CLASS_S: 0;
+    plc->ctrl_b = CB_PC_STOP + class;
+    plc->intr_mask = IE_NP_ERROR;
+    x = plc->intr_event;	/* these register clear when read */
+    x = plc->viol_sym_ct;
+    x = plc->min_idle_ct;
+    x = plc->link_err_ct;
+
+    /* initialize registers */
+    plc->ctrl_a = 0;
+    plc->ctrl_b = class;
+    plc->c_min = pip->c_min >> 8;
+    plc->tl_min = pip->tl_min >> 8;
+    plc->tb_min = pip->tb_min >> 8;
+    plc->t_out = pip->t_out >> 8;
+    plc->t_scrub = pip->t_scrub >> 8;
+    plc->ns_max = pip->ns_max >> 2;
+
+    psp->phase = off;
+}
+
+int
+plc_inited(struct plc_info *pip)
+{
+    int class, x;
+    struct plc_state *psp = &this_plc_state;
+
+    class = pip->port_type == pt_s? CB_CLASS_S: 0;
+    if ((plc->ctrl_a & (CA_LOOPBACK|CA_FOT_OFF|CA_EB_LOOP|CA_LM_LOOP)) != 0)
+	return 1;
+    if ((plc->ctrl_b & (CB_CONFIG_CTRL|CB_CLASS_S|CB_PC_MAINT)) != class)
+	return 2;
+    if (plc->status_a & SA_SIG_DETECT)
+	return 3;
+    if ((plc->status_b & (SB_PCI_STATE|SB_PCM_STATE))
+	 != (SB_PCI_STATE_INSERTED|SB_PCM_STATE_ACTIVE))
+	return 4;
+
+    /* all seems OK, reset the timers and counters just to be sure */
+    plc->intr_mask = IE_NP_ERROR;
+    x = plc->intr_event;	/* these register clear when read */
+    x = plc->viol_sym_ct;
+    x = plc->min_idle_ct;
+    x = plc->link_err_ct;
+
+    plc->c_min = pip->c_min >> 8;
+    plc->tl_min = pip->tl_min >> 8;
+    plc->tb_min = pip->tb_min >> 8;
+    plc->t_out = pip->t_out >> 8;
+    plc->t_scrub = pip->t_scrub >> 8;
+    plc->ns_max = pip->ns_max >> 2;
+
+    psp->phase = active;
+    /* XXX should initialize other fields of this_plc_state */
+
+    return 0;
+}
+
+void plc_sleep(void)
+{
+}
+
+void pc_start(LoopbackType loopback)
+{
+    int x;
+    struct plc_info *pip = this_plc_info;
+    struct plc_state *psp = &this_plc_state;
+
+    /* make sure it's off */
+    plc->ctrl_b &= ~CB_PCM_CTRL;
+    plc->ctrl_b |= CB_PC_STOP;
+
+    /* set up loopback required */
+    psp->loopback = loopback;
+    x = 0;
+    switch (loopback) {
+    case loop_plc_lm:
+	x = CA_LM_LOOP;
+	break;
+    case loop_plc_eb:
+	x = CA_EB_LOOP;
+	break;
+    case loop_pdx:
+	x = CA_LOOPBACK;
+	break;
+    default:
+	x = 0;
+    }
+    plc->ctrl_a = x;
+
+    /* set up bits to be exchanged */
+    psp->t_val[0] = 0;
+    psp->t_val[1] = ((int) pip->port_type >> 1) & 1;
+    psp->t_val[2] = (int) pip->port_type & 1;
+    psp->t_val[4] = 0;		/* XXX assume we want short LCT */
+    psp->t_val[5] = 0;
+    psp->t_val[6] = 0;		/* XXX too lazy to fire up my MAC for LCT */
+    psp->t_val[8] = 0;		/* XXX don't wanna local loop */
+    psp->t_val[9] = 1;		/* gotta MAC on port output */
+
+    pc_restart();
+}
+
+void pc_restart(void)
+{
+    struct plc_state *psp = &this_plc_state;
+
+    if (psp->phase != off)
+	printk("restarting pcm\n");
+    if (psp->phase == active)
+	set_cf_join(0);		/* we're down :-( */
+
+    psp->n = 0;
+    plc->vec_length = 3 - 1;
+    plc->xmit_vector = psp->t_val[0] + (psp->t_val[1] << 1)
+	+ (psp->t_val[2] << 2);
+
+    plc->intr_mask = IE_NP_ERROR | IE_PCM_BREAK | IE_PCM_CODE;
+    plc->ctrl_b &= ~CB_PCM_CTRL;
+    plc->ctrl_b |= CB_PC_START;	/* light blue paper and stand clear */
+
+    psp->phase = signalling;
+}
+
+void pc_stop(void)
+{
+    struct plc_state *psp = &this_plc_state;
+
+    if (psp->phase == active)
+	set_cf_join(0);
+    plc->ctrl_b &= ~CB_PCM_CTRL;
+    plc->ctrl_b |= CB_PC_STOP;
+    plc->intr_mask = IE_NP_ERROR;
+    psp->phase = off;
+}
+
+void plc_poll(void)
+{
+    struct plc_state *psp = &this_plc_state;
+    int events, i;
+
+    if ((*csr0 & CS0_PHY_IRQ) == 0)
+	return;
+    events = plc->intr_event & plc->intr_mask;
+    if (events & IE_NP_ERROR) {
+	printk("plc: NP error!\n");
+    }
+    if (events & IE_PCM_BREAK) {
+	i = plc->status_b & SB_BREAK_REASON;
+	if (i > SB_BREAK_REASON_START) {
+	    if (psp->phase == signalling || psp->phase == doing_lct)
+		pcm_dump_rtcodes();
+	    printk("pcm: break reason %d\n", i);
+	    if (psp->phase != off)
+		pc_restart();
+	    /* XXX need to check for trace? */
+	}
+    }
+    if (events & IE_PCM_CODE) {
+	if (psp->phase == signalling)
+	    pcm_pseudo_code();
+	else if (psp->phase == doing_lct)
+	    pcm_lct_done();
+	else
+	    printk("XXX pcm_code interrupt in phase %d?\n", psp->phase);
+    }
+    if (events & IE_PCM_ENABLED) {
+	if (psp->phase == joining)
+	    pcm_enabled();
+	else
+	    printk("XXX pcm_enabled interrupt in phase %d?\n", psp->phase);
+    }
+    if (events & IE_TRACE_PROP) {
+	if (psp->phase == active)
+	    pcm_trace_prop();
+	else
+	    printk("XXX trace_prop interrupt in phase %d\n", psp->phase);
+    }
+}
+
+void pcm_pseudo_code(void)
+{
+    struct plc_info *pip = this_plc_info;
+    struct plc_state *psp = &this_plc_state;
+    int i, nb, lct, hislct;
+
+    /* unpack the bits from the peer */
+    nb = plc->vec_length + 1;
+    i = plc->rcv_vector;
+    do {
+	psp->r_val[psp->n++] = i & 1;
+	i >>= 1;
+    } while (--nb > 0);
+
+    /* send some more, do LCT, whatever */
+    switch (psp->n) {
+    case 3:
+	/*
+	 * Got escape flag, port type; send compatibility,
+	 * LCT duration, MAC for LCT flag.
+	 */
+	if (psp->r_val[0]) {
+	    /* help! what do I do now? */
+	    pcm_dump_rtcodes();
+	    pc_restart();
+	    break;
+	}
+	psp->peer_type = (PortType) ((psp->r_val[1] << 1) + psp->r_val[2]);
+	/* XXX we're type S, we talk to anybody */
+	psp->t_val[3] = 1;
+
+	plc->vec_length = 4 - 1;
+	plc->xmit_vector = psp->t_val[3] + (psp->t_val[4] << 1)
+	    + (psp->t_val[5] << 2) + (psp->t_val[6] << 3);
+	break;
+
+    case 7:
+	/*
+	 * Got compatibility, LCT duration, MAC for LCT flag;
+	 * time to do the LCT.
+	 */
+	lct = (psp->t_val[4] << 1) + psp->t_val[5];
+	hislct = (psp->r_val[4] << 1) + psp->r_val[5];
+	if (hislct > lct)
+	    lct = hislct;
+
+	/* set LCT duration */
+	switch (lct) {
+	case 0:
+	    plc->lc_length = pip->lc_short >> 8;
+	    plc->ctrl_b &= ~CB_LONG_LCT;
+	    break;
+	case 1:
+	    plc->lc_length = pip->lc_medium >> 8;
+	    plc->ctrl_b &= ~CB_LONG_LCT;
+	    break;
+	case 2:
+	    plc->ctrl_b |= CB_LONG_LCT;
+	    /* XXX set up a timeout for pip->lc_long */
+	    break;
+	case 3:
+	    plc->ctrl_b |= CB_LONG_LCT;
+	    /* XXX set up a timeout for pip->lc_extended */
+	    break;
+	}
+
+	/* start the LCT */
+	i = plc->link_err_ct;	/* clear the register */
+	plc->ctrl_b &= ~CB_PC_LCT;
+	/* XXX assume we're not using the MAC for LCT;
+	   if he's got a MAC, loop his stuff back, otherwise send idle. */
+	if (psp->r_val[6])
+	    plc->ctrl_b |= CB_PC_LCT_LOOP;
+	else
+	    plc->ctrl_b |= CB_PC_LCT_IDLE;
+	psp->phase = doing_lct;
+	break;
+
+    case 8:
+	/*
+	 * Got LCT result, send MAC for local loop and MAC on port
+	 * output flags.
+	 */
+	if (psp->t_val[7] || psp->r_val[7]) {
+	    printk("LCT failed, restarting.\n");
+	    /* LCT failed - do at least a medium length test next time. */
+	    if (psp->t_val[4] == 0 && psp->t_val[5] == 0)
+		psp->t_val[5] = 1;
+	    pcm_dump_rtcodes();
+	    pc_restart();
+	    break;
+	}
+	plc->vec_length = 2 - 1;
+	plc->xmit_vector = psp->t_val[8] + (psp->t_val[9] << 1);
+	break;
+
+    case 10:
+	/*
+	 * Got MAC for local loop and MAC on port output flags.
+	 * Let's join.
+	 */
+	plc->intr_mask = IE_NP_ERROR | IE_PCM_BREAK | IE_PCM_ENABLED;
+	plc->ctrl_b |= CB_PC_JOIN;
+	psp->phase = joining;
+	/* printk("pcm: joining\n"); */
+	break;
+
+    default:
+	printk("pcm_pseudo_code bug: n = %d\n", psp->n);
+    }
+}
+
+void pcm_lct_done(void)
+{
+    struct plc_state *psp = &this_plc_state;
+    int i;
+
+    i = plc->link_err_ct;
+    psp->t_val[7] = i > 0;
+    printk("pcm: lct %s (%d errors)\n", psp->t_val[7]? "failed": "passed", i);
+    plc->ctrl_b &= ~(CB_PC_LCT | CB_LONG_LCT);
+    plc->vec_length = 1 - 1;
+    plc->xmit_vector = psp->t_val[7];
+    psp->phase = signalling;
+}
+
+void pcm_dump_rtcodes(void)
+{
+    struct plc_state *psp = &this_plc_state;
+    int i;
+
+    if (psp->n > 0) {
+	printk("pcm signalling interrupted after %d bits:\nt_val:", psp->n);
+	for (i = 0; i < psp->n; ++i)
+	    printk(" %d", psp->t_val[i]);
+	printk("\nr_val:");
+	for (i = 0; i < psp->n; ++i)
+	    printk(" %d", psp->r_val[i]);
+	printk("\n");
+    }
+}
+
+void pcm_enabled(void)
+{
+    struct plc_state *psp = &this_plc_state;
+    int i;
+
+    printk("pcm: enabled\n");
+    psp->phase = active;
+    i = plc->link_err_ct;	/* clear the register */
+    /* XXX should set up LEM here */
+    /* XXX do we want to count violation symbols, minimum idle gaps,
+       or elasticity buffer errors? */
+    plc->intr_mask = IE_NP_ERROR | IE_PCM_BREAK | IE_TRACE_PROP;
+    set_cf_join(1);		/* we're up :-) */
+}
+
+void pcm_trace_prop(void)
+{
+    /* XXX help! what do I do now? */
+    pc_stop();
+}
diff -u --recursive --new-file v2.1.22/linux/drivers/ap1000/plc.h linux/drivers/ap1000/plc.h
--- v2.1.22/linux/drivers/ap1000/plc.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/ap1000/plc.h	Sun Jan 26 12:07:10 1997
@@ -0,0 +1,53 @@
+  /*
+   * Copyright 1996 The Australian National University.
+   * Copyright 1996 Fujitsu Laboratories Limited
+   * 
+   * This software may be distributed under the terms of the Gnu
+   * Public License version 2 or later
+  */
+/*
+ * Definitions for PLC state structures etc.
+ */
+
+struct plc_info {
+    PortType		port_type;
+    TimerTwosComplement	c_min;
+    TimerTwosComplement	tl_min;
+    TimerTwosComplement	tb_min;
+    TimerTwosComplement	t_out;
+    TimerTwosComplement	lc_short;
+    TimerTwosComplement	lc_medium;
+    TimerTwosComplement	lc_long;
+    TimerTwosComplement	lc_extended;
+    TimerTwosComplement	t_scrub;
+    TimerTwosComplement	ns_max;
+    Counter		link_errors;
+    Counter		viol_syms;
+    Counter		mini_occur;
+    int			min_idle_gap;
+    double		link_error_rate;
+};
+
+void plc_init(struct plc_info *pip);
+int plc_inited(struct plc_info *pip);
+void pc_start(LoopbackType loopback);
+void plc_sleep(void);
+void plc_poll(void);
+void pc_stop(void);
+void pc_restart(void);
+void pcm_dump_rtcodes(void);
+void pcm_pseudo_code(void);
+void pcm_lct_done(void);
+void pcm_enabled(void);
+void pcm_trace_prop(void);
+
+
+
+
+
+
+
+
+
+
+
diff -u --recursive --new-file v2.1.22/linux/drivers/ap1000/ringbuf.c linux/drivers/ap1000/ringbuf.c
--- v2.1.22/linux/drivers/ap1000/ringbuf.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/ap1000/ringbuf.c	Sun Jan 26 12:07:10 1997
@@ -0,0 +1,327 @@
+  /*
+   * Copyright 1996 The Australian National University.
+   * Copyright 1996 Fujitsu Laboratories Limited
+   * 
+   * This software may be distributed under the terms of the Gnu
+   * Public License version 2 or later
+  */
+/*
+ *  linux/drivers/ap1000/ringbuf.c
+ *
+ * This provides the /proc/XX/ringbuf interface to the Tnet ring buffer
+ */
+#define _APLIB_
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+
+#include <asm/page.h>
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/segment.h>
+#include <asm/uaccess.h>
+
+#include <asm/ap1000/pgtapmmu.h>
+#include <asm/ap1000/apreg.h>
+#include <asm/ap1000/apservice.h>
+
+
+/* we have a small number of reserved ring buffers to ensure that at
+   least one parallel program can always run */
+#define RBUF_RESERVED 4
+#define RBUF_RESERVED_ORDER 5
+static struct {
+	char *rb_ptr;
+	char *shared_ptr;
+	int used;
+} reserved_ringbuf[RBUF_RESERVED];
+
+
+void ap_ringbuf_init(void)
+{
+	int i,j;
+	char *rb_ptr, *shared_ptr;
+	int rb_size = PAGE_SIZE * (1<<RBUF_RESERVED_ORDER);
+
+	/* preallocate some ringbuffers */
+	for (i=0;i<RBUF_RESERVED;i++) {
+		if (!(rb_ptr = (char *)__get_free_pages(GFP_ATOMIC,RBUF_RESERVED_ORDER,0))) {
+			printk("failed to preallocate ringbuf %d\n",i);
+			return;
+		}
+		for (j = MAP_NR(rb_ptr); j <= MAP_NR(rb_ptr+rb_size-1); j++) {
+			set_bit(PG_reserved,&mem_map[j].flags);
+		}
+
+		if (!(shared_ptr = (char *)__get_free_page(GFP_ATOMIC))) {
+			printk("failed to preallocate shared ptr %d\n",i);
+                        return;
+		}
+		set_bit(PG_reserved,&mem_map[MAP_NR(shared_ptr)].flags);
+
+		reserved_ringbuf[i].used = 0;
+		reserved_ringbuf[i].rb_ptr = rb_ptr;
+		reserved_ringbuf[i].shared_ptr = shared_ptr;
+	}
+}
+
+
+
+void exit_ringbuf(struct task_struct *tsk)
+{
+	int i;
+	
+	if (!tsk->ringbuf) return;
+	
+	if (tsk->ringbuf->ringbuf) {
+		char *rb_ptr = tsk->ringbuf->ringbuf;
+		char *shared_ptr = tsk->ringbuf->shared;
+		int order = tsk->ringbuf->order;
+		int rb_size = PAGE_SIZE * (1<<order);
+
+		for (i=0;i<RBUF_RESERVED;i++)
+			if (rb_ptr == reserved_ringbuf[i].rb_ptr) break;
+		
+		if (i < RBUF_RESERVED) {
+			reserved_ringbuf[i].used = 0;
+		} else {
+			for (i = MAP_NR(rb_ptr); i <= MAP_NR(rb_ptr+rb_size-1); i++) {
+				clear_bit(PG_reserved, &mem_map[i].flags);
+			}
+			free_pages((unsigned)rb_ptr,order);
+
+			i = MAP_NR(shared_ptr);
+			clear_bit(PG_reserved,&mem_map[i]);
+			free_page((unsigned)shared_ptr);
+		}
+	}
+
+	kfree_s(tsk->ringbuf,sizeof(*(tsk->ringbuf)));
+	tsk->ringbuf = NULL;
+}
+
+
+/*
+ * map the ring buffer into users memory
+ */
+static int cap_map(int rb_size)
+{
+	struct task_struct *tsk=current;
+	int i;
+	char *rb_ptr=NULL;
+	char *shared_ptr=NULL;
+	int order = 0;
+	int error,old_uid;
+
+	error = verify_area(VERIFY_WRITE,(char *)RBUF_VBASE,rb_size);
+	if (error) return error;
+	
+	if (!MPP_IS_PAR_TASK(tsk->taskid)) {
+		printk("ringbuf_mmap called from non-parallel task\n");
+		return -EINVAL;
+	}
+
+	
+	if (tsk->ringbuf) return -EINVAL;
+
+	rb_size -= RBUF_RING_BUFFER_OFFSET;
+	rb_size >>= 1;
+
+	switch (rb_size/1024) {
+	case 128:
+		order = 5;
+		break;
+	case 512:
+		order = 7;
+		break;
+	case 2048:
+		order = 9;
+		break;
+	case 8192:
+		order = 11;
+		break;
+	default:
+		printk("ringbuf_mmap with invalid size %d\n",rb_size);
+		return -EINVAL;
+	}
+	  
+	if (order == RBUF_RESERVED_ORDER) {
+		for (i=0;i<RBUF_RESERVED;i++) 
+			if (!reserved_ringbuf[i].used) {
+				rb_ptr = reserved_ringbuf[i].rb_ptr;
+				shared_ptr = reserved_ringbuf[i].shared_ptr;
+				reserved_ringbuf[i].used = 1;
+				break;
+			}
+	}
+	  
+	if (!rb_ptr) {
+		rb_ptr = (char *)__get_free_pages(GFP_USER,order,0);
+		if (!rb_ptr) return -ENOMEM;
+
+		for (i = MAP_NR(rb_ptr); i <= MAP_NR(rb_ptr+rb_size-1); i++) {
+			set_bit(PG_reserved,&mem_map[i].flags);
+		}
+		  
+		shared_ptr = (char *)__get_free_page(GFP_USER);
+		if (!shared_ptr)
+			return -ENOMEM;
+		set_bit(PG_reserved,&mem_map[MAP_NR(shared_ptr)].flags);
+	}
+
+	if (!rb_ptr)
+		return -ENOMEM;
+  
+	memset(rb_ptr,0,rb_size);
+	memset(shared_ptr,0,PAGE_SIZE);
+
+	if (remap_page_range(RBUF_VBASE + RBUF_RING_BUFFER_OFFSET, 
+			     mmu_v2p((unsigned)rb_ptr),
+			     rb_size,APMMU_PAGE_SHARED))
+		return -EAGAIN;
+
+	if (remap_page_range(RBUF_VBASE + RBUF_RING_BUFFER_OFFSET + rb_size, 
+			     mmu_v2p((unsigned)rb_ptr),
+			     rb_size,APMMU_PAGE_SHARED))
+		return -EAGAIN;
+  
+	/* the shared area */
+	if (remap_page_range(RBUF_VBASE + RBUF_SHARED_PAGE_OFF,
+			     mmu_v2p((unsigned)shared_ptr),
+			     PAGE_SIZE,APMMU_PAGE_SHARED))
+		return -EAGAIN;
+
+#if 0
+	/* lock the ringbuffer in memory */
+	old_uid = current->euid;
+	current->euid = 0;
+	error = sys_mlock(RBUF_VBASE,2*rb_size+RBUF_RING_BUFFER_OFFSET);
+	current->euid = old_uid;
+	if (error) {
+		printk("ringbuffer mlock failed\n");
+		return error;
+	}
+#endif
+
+	/* the queue pages */
+#define MAP_QUEUE(offset,phys) \
+	io_remap_page_range(RBUF_VBASE + offset, \
+			    phys<<PAGE_SHIFT,PAGE_SIZE,APMMU_PAGE_SHARED,0xa)
+	
+	MAP_QUEUE(RBUF_PUT_QUEUE,  0x00000);
+	MAP_QUEUE(RBUF_GET_QUEUE,  0x00001);
+	MAP_QUEUE(RBUF_SEND_QUEUE, 0x00040);
+	
+	MAP_QUEUE(RBUF_XY_QUEUE,   0x00640);
+	MAP_QUEUE(RBUF_X_QUEUE,    0x00240);
+	MAP_QUEUE(RBUF_Y_QUEUE,    0x00440);
+	MAP_QUEUE(RBUF_XYG_QUEUE,  0x00600);
+	MAP_QUEUE(RBUF_XG_QUEUE,   0x00200);
+	MAP_QUEUE(RBUF_YG_QUEUE,   0x00400);  
+	MAP_QUEUE(RBUF_CSI_QUEUE,  0x02004);  
+	MAP_QUEUE(RBUF_FOP_QUEUE,  0x02005);  
+
+#undef MAP_QUEUE
+
+	if (!tsk->ringbuf) {
+		tsk->ringbuf = (void *)kmalloc(sizeof(*(tsk->ringbuf)),GFP_ATOMIC);
+		if (!tsk->ringbuf)
+			return -ENOMEM;    
+	}
+  
+	memset(tsk->ringbuf,0,sizeof(*tsk->ringbuf));
+	tsk->ringbuf->ringbuf = rb_ptr;
+	tsk->ringbuf->shared = shared_ptr;
+	tsk->ringbuf->order = order;
+	tsk->ringbuf->write_ptr = mmu_v2p((unsigned)rb_ptr)<<1;
+	tsk->ringbuf->vaddr = RBUF_VBASE;
+  
+	memset(tsk->ringbuf->vaddr+RBUF_SHARED_PAGE_OFF,0,PAGE_SIZE);
+	{
+		struct _kernel_cap_shared *_kernel = 
+			(struct _kernel_cap_shared *)tsk->ringbuf->vaddr;
+		_kernel->rbuf_read_ptr = (rb_size>>5) - 1;
+	}
+  
+	return 0;
+}
+
+
+static int 
+ringbuf_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	int numcells, *phys_cells;      
+	extern struct cap_init cap_init;
+
+	switch (cmd) {
+	case CAP_GETINIT:
+		if (copy_to_user((char *)arg,(char *)&cap_init,sizeof(cap_init)))
+			return -EFAULT;
+		break;
+
+	case CAP_SYNC:
+		if (verify_area(VERIFY_READ, (void *) arg, sizeof(int)*2))
+			return -EFAULT;
+		if (get_user(numcells,(int *)arg)) return -EFAULT;
+		if (get_user((unsigned)phys_cells,
+			     ((int *)arg)+1)) return -EFAULT;
+		if (verify_area(VERIFY_READ,phys_cells,sizeof(int)*numcells))
+			return -EFAULT;
+		return ap_sync(numcells,phys_cells);
+		break;
+
+	case CAP_SETGANG:
+		{
+			int v;
+			if (get_user(v,(int *)arg)) return -EFAULT;
+			mpp_set_gang_factor(v);
+			break;
+		}
+
+	case CAP_MAP:
+		return cap_map(arg);
+		
+	default:
+		printk("unknown ringbuf ioctl %d\n",cmd);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+
+static struct file_operations proc_ringbuf_operations = {
+	NULL,
+	NULL,
+	NULL,
+	NULL,		/* readdir */
+	NULL,		/* poll */
+	ringbuf_ioctl,	/* ioctl */
+	NULL,           /* mmap */
+	NULL,		/* no special open code */
+	NULL,		/* no special release code */
+	NULL		/* can't fsync */
+};
+
+struct inode_operations proc_ringbuf_inode_operations = {
+	&proc_ringbuf_operations,	/* default base directory file-ops */
+	NULL,			/* create */
+	NULL,			/* lookup */
+	NULL,			/* link */
+	NULL,			/* unlink */
+	NULL,			/* symlink */
+	NULL,			/* mkdir */
+	NULL,			/* rmdir */
+	NULL,			/* mknod */
+	NULL,			/* rename */
+	NULL,			/* readlink */
+	NULL,			/* follow_link */
+	NULL,			/* readpage */
+	NULL,			/* writepage */
+	NULL,			/* bmap */
+	NULL,			/* truncate */
+	NULL			/* permission */
+};
diff -u --recursive --new-file v2.1.22/linux/drivers/ap1000/smt-types.h linux/drivers/ap1000/smt-types.h
--- v2.1.22/linux/drivers/ap1000/smt-types.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/ap1000/smt-types.h	Sun Jan 26 12:07:10 1997
@@ -0,0 +1,167 @@
+  /*
+   * Copyright 1996 The Australian National University.
+   * Copyright 1996 Fujitsu Laboratories Limited
+   * 
+   * This software may be distributed under the terms of the Gnu
+   * Public License version 2 or later
+  */
+/*
+ * Definitions for FDDI Station Management.
+ */
+
+/*
+ * FDDI-COMMON types.
+ */
+
+typedef unsigned int Counter;	/* 32-bit event counter */
+
+typedef enum {
+    cp_isolated,
+    cp_local,
+    cp_secondary,
+    cp_primary,
+    cp_concatenated,
+    cp_thru
+} CurrentPath;
+
+typedef char Flag;
+
+typedef unsigned char LongAddressType[6];
+
+typedef enum {
+    pt_a,
+    pt_b,
+    pt_s,
+    pt_m,
+    pt_none
+} PortType;
+
+typedef unsigned short ResourceId;
+
+typedef int Time;		/* time in 80ns units */
+#define FDDI_TIME_UNIT	80e-9	/* 80 nanoseconds */
+#define SECS_TO_FDDI_TIME(s)	((int)((s)/FDDI_TIME_UNIT+0.99))
+
+typedef int TimerTwosComplement;
+
+/*
+ * FDDI-SMT types.
+ */
+typedef enum {
+    ec_Out,
+    ec_In,
+    ec_Trace,
+    ec_Leave,
+    ec_Path_Test,
+    ec_Insert,
+    ec_Check,
+    ec_Deinsert
+} ECMState;
+
+/*
+ * FDDI-MAC types.
+ */
+typedef enum {
+    dat_none,
+    dat_pass,
+    dat_fail
+} DupAddressTest;
+
+typedef unsigned short DupCondition;
+#define DC_MYDUP	1
+#define DC_UNADUP	2
+
+typedef unsigned short FS_Functions;
+#define FSF_FS_REPEATING	1
+#define FSF_FS_SETTING		2
+#define FSF_FS_CLEARING		4
+
+typedef unsigned char NACondition;
+#define NAC_UNACHANGE	1
+#define NAC_DNACHANGE	2
+
+typedef enum {
+    rmt_Isolated,
+    rmt_Non_Op,
+    rmt_Ring_Op,
+    rmt_Detect,
+    rmt_Non_Op_Dup,
+    rmt_Ring_Op_Dup,
+    rmt_Directed,
+    rmt_Trace
+} RMTState;
+
+typedef unsigned char ShortAddressType[2];
+
+/*
+ * FDDI-PATH types.
+ */
+typedef unsigned short TraceStatus;
+#define TS_TRACEINITIATED	1
+#define TS_TRACEPROPAGATED	2
+#define TS_TRACETERMINATED	4
+#define TS_TRACETIMEOUT		8
+
+/*
+ * FDDI-PORT types.
+ */
+typedef enum {
+    PC_Maint,
+    PC_Enable,
+    PC_Disable,
+    PC_Start,
+    PC_Stop
+} ActionType;
+
+typedef unsigned char ConnectionPolicies;
+#define PC_MAC_LCT	1
+#define PC_MAC_LOOP	2
+
+typedef enum {
+    cs_disabled,
+    cs_connecting,
+    cs_standby,
+    cs_active
+} ConnectState;
+
+typedef enum {
+    ls_qls,
+    ls_ils,
+    ls_mls,
+    ls_hls,
+    ls_pdr,
+    ls_lsu,
+    ls_nls
+} LineState;
+
+typedef enum {
+    pc_Off,
+    pc_Break,
+    pc_Trace,
+    pc_Connect,
+    pc_Next,
+    pc_Signal,
+    pc_Join,
+    pc_Verify,
+    pc_Active,
+    pc_Maint
+} PCMState;
+
+typedef enum {
+    pcw_none,
+    pcw_mm,
+    pcw_otherincompatible,
+    pcw_pathnotavailable
+} PC_Withhold;
+
+typedef enum {
+    pmd_multimode,
+    pmd_single_mode1,
+    pmd_single_mode2,
+    pmd_sonet,
+    pmd_low_cost_fiber,
+    pmd_twisted_pair,
+    pmd_unknown,
+    pmd_unspecified
+} PMDClass;
+
diff -u --recursive --new-file v2.1.22/linux/drivers/block/acsi_slm.c linux/drivers/block/acsi_slm.c
--- v2.1.22/linux/drivers/block/acsi_slm.c	Sun Dec 22 16:37:30 1996
+++ linux/drivers/block/acsi_slm.c	Sun Jan 26 12:07:10 1997
@@ -279,7 +279,7 @@
 	slm_read,		/* read - status reading */
 	slm_write,		/* write - printing data write */
 	NULL,			/* readdir - bad */
-	NULL,			/* select */
+	NULL,			/* poll */
 	slm_ioctl,		/* ioctl */
 	NULL,			/* mmap */
 	slm_open,		/* open */
diff -u --recursive --new-file v2.1.22/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v2.1.22/linux/drivers/block/floppy.c	Thu Jan 23 21:06:46 1997
+++ linux/drivers/block/floppy.c	Sun Jan 26 12:07:10 1997
@@ -3704,7 +3704,7 @@
 	floppy_read,		/* read - general block-dev read */
 	floppy_write,		/* write - general block-dev write */
 	NULL,		       	/* readdir - bad */
-	NULL,			/* select */
+	NULL,			/* poll */
 	fd_ioctl,		/* ioctl */
 	NULL,			/* mmap */
 	floppy_open,		/* open */
@@ -4128,6 +4128,7 @@
 extern char *get_options(char *str, int *ints);
 
 char *floppy=NULL;
+MODULE_PARM(floppy, "s");
 
 static void parse_floppy_cfg_string(char *cfg)
 {
diff -u --recursive --new-file v2.1.22/linux/drivers/block/hd.c linux/drivers/block/hd.c
--- v2.1.22/linux/drivers/block/hd.c	Thu Dec 12 19:36:58 1996
+++ linux/drivers/block/hd.c	Sun Jan 26 12:07:10 1997
@@ -784,7 +784,7 @@
 	block_read,		/* read - general block-dev read */
 	block_write,		/* write - general block-dev write */
 	NULL,			/* readdir - bad */
-	NULL,			/* select */
+	NULL,			/* poll */
 	hd_ioctl,		/* ioctl */
 	NULL,			/* mmap */
 	hd_open,		/* open */
diff -u --recursive --new-file v2.1.22/linux/drivers/block/ide-floppy.c linux/drivers/block/ide-floppy.c
--- v2.1.22/linux/drivers/block/ide-floppy.c	Thu Dec 12 19:36:59 1996
+++ linux/drivers/block/ide-floppy.c	Sat Jan 25 20:51:17 1997
@@ -1,7 +1,7 @@
 /*
- * linux/drivers/block/ide-floppy.c	Version 0.3 - ALPHA	Dec   2, 1996
+ * linux/drivers/block/ide-floppy.c	Version 0.4 - ALPHA	Jan  26, 1997
  *
- * Copyright (C) 1996 Gadi Oxman <gadio@netvision.net.il>
+ * Copyright (C) 1996, 1997 Gadi Oxman <gadio@netvision.net.il>
  */
 
 /*
@@ -16,6 +16,7 @@
  * Ver 0.1   Oct 17 96   Initial test version, mostly based on ide-tape.c.
  * Ver 0.2   Oct 31 96   Minor changes.
  * Ver 0.3   Dec  2 96   Fixed error recovery bug.
+ * Ver 0.4   Jan 26 97   Add support for the HDIO_GETGEO ioctl.
  */
 
 #include <linux/config.h>
@@ -1048,6 +1049,9 @@
 			drive->name, capacity / 1024, page->cyls, page->heads, page->sectors,
 			page->transfer_rate / 8, page->sector_size, page->rpm);
 		floppy->flexible_disk_page = *page;
+		drive->bios_cyl = page->cyls;
+		drive->bios_head = page->heads;
+		drive->bios_sect = page->sectors;
 		if (capacity != floppy->blocks * floppy->block_size)
 			printk (KERN_NOTICE "%s: The drive reports both %d and %d bytes as its capacity\n",
 				drive->name, capacity, floppy->blocks * floppy->block_size);
diff -u --recursive --new-file v2.1.22/linux/drivers/block/ide-probe.c linux/drivers/block/ide-probe.c
--- v2.1.22/linux/drivers/block/ide-probe.c	Thu Dec 12 19:36:59 1996
+++ linux/drivers/block/ide-probe.c	Sat Jan 25 20:51:17 1997
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/block/ide-probe.c	Version 1.0  Oct  31, 1996
+ *  linux/drivers/block/ide-probe.c	Version 1.01  Jan  26, 1997
  *
  *  Copyright (C) 1994-1996  Linus Torvalds & authors (see below)
  */
@@ -36,7 +36,8 @@
  *  code is still sprinkled about.  Think of it as a major evolution, with
  *  inspiration from lots of linux users, esp.  hamish@zot.apana.org.au
  *
- * Version 1.0		move drive probing code from ide.c to ide-probe.c
+ * Version 1.00		move drive probing code from ide.c to ide-probe.c
+ * Version 1.01		fix compilation problem for m68k
  */
 
 #undef REALLY_SLOW_IO		/* most systems can safely undef this */
@@ -494,9 +495,7 @@
 static int init_irq (ide_hwif_t *hwif)
 {
 	unsigned long flags;
-#if MAX_HWIFS > 1
 	unsigned int index;
-#endif /* MAX_HWIFS > 1 */
 	ide_hwgroup_t *hwgroup;
 	ide_hwif_t *match = NULL;
 
diff -u --recursive --new-file v2.1.22/linux/drivers/block/ide-tape.c linux/drivers/block/ide-tape.c
--- v2.1.22/linux/drivers/block/ide-tape.c	Thu Dec 12 19:36:59 1996
+++ linux/drivers/block/ide-tape.c	Sun Jan 26 12:07:10 1997
@@ -3644,7 +3644,7 @@
 	idetape_chrdev_read,	/* read  */
 	idetape_chrdev_write,	/* write */
 	NULL,			/* readdir - bad */
-	NULL,			/* select */
+	NULL,			/* poll */
 	idetape_chrdev_ioctl,	/* ioctl */
 	NULL,			/* mmap */
 	idetape_chrdev_open,	/* open */
diff -u --recursive --new-file v2.1.22/linux/drivers/block/ide.c linux/drivers/block/ide.c
--- v2.1.22/linux/drivers/block/ide.c	Mon Dec 30 15:39:04 1996
+++ linux/drivers/block/ide.c	Sun Jan 26 12:07:10 1997
@@ -1,7 +1,7 @@
 /*
- *  linux/drivers/block/ide.c	Version 6.00  Dec   4, 1996
+ *  linux/drivers/block/ide.c	Version 6.01  Jan  26, 1997
  *
- *  Copyright (C) 1994-1996  Linus Torvalds & authors (see below)
+ *  Copyright (C) 1994-1997  Linus Torvalds & authors (see below)
  */
 #define _IDE_C		/* needed by <linux/blk.h> */
 
@@ -276,6 +276,8 @@
  *			fix bug in ide_error()
  *			fix bug in the first ide_get_lock() call for Atari
  *			don't flush leftover data for ATAPI devices
+ * Version 6.01		clear hwgroup->active while the hwgroup sleeps
+ *			support HDIO_GETGEO for floppies
  *
  *  Some additional driver compile-time options are in ide.h
  *
@@ -1240,10 +1242,9 @@
 			sleep = jiffies + WAIT_MIN_SLEEP;
 		hwgroup->timer.expires = sleep;
 		add_timer(&hwgroup->timer);
-	} else {	/* Ugly, but how can we sleep for the lock otherwise? perhaps from tq_scheduler? */
+	} else	/* Ugly, but how can we sleep for the lock otherwise? perhaps from tq_scheduler? */
 		ide_release_lock(&ide_lock);
-		hwgroup->active = 0;
-	}
+	hwgroup->active = 0;
 }
 
 /*
@@ -1876,7 +1877,7 @@
 		case HDIO_GETGEO:
 		{
 			struct hd_geometry *loc = (struct hd_geometry *) arg;
-			if (!loc || drive->media != ide_disk) return -EINVAL;
+			if (!loc || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL;
 			if (put_user(drive->bios_head, (byte *) &loc->heads)) return -EFAULT;
 			if (put_user(drive->bios_sect, (byte *) &loc->sectors)) return -EFAULT;
 			if (put_user(drive->bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT;
@@ -2817,7 +2818,7 @@
 	block_read,		/* read - general block-dev read */
 	block_write,		/* write - general block-dev write */
 	NULL,			/* readdir - bad */
-	NULL,			/* select */
+	NULL,			/* poll */
 	ide_ioctl,		/* ioctl */
 	NULL,			/* mmap */
 	ide_open,		/* open */
diff -u --recursive --new-file v2.1.22/linux/drivers/block/loop.c linux/drivers/block/loop.c
--- v2.1.22/linux/drivers/block/loop.c	Thu Jan  2 15:55:15 1997
+++ linux/drivers/block/loop.c	Sun Jan 26 12:07:10 1997
@@ -513,7 +513,7 @@
 	block_read,		/* read - general block-dev read */
 	block_write,		/* write - general block-dev write */
 	NULL,			/* readdir - bad */
-	NULL,			/* select */
+	NULL,			/* poll */
 	lo_ioctl,		/* ioctl */
 	NULL,			/* mmap */
 	lo_open,		/* open */
diff -u --recursive --new-file v2.1.22/linux/drivers/block/ps2esdi.c linux/drivers/block/ps2esdi.c
--- v2.1.22/linux/drivers/block/ps2esdi.c	Thu Jan 23 21:06:46 1997
+++ linux/drivers/block/ps2esdi.c	Sun Jan 26 12:07:11 1997
@@ -152,7 +152,7 @@
 	block_read,		/* read - general block-dev read */
 	block_write,		/* write - general block-dev write */
 	NULL,			/* readdir - bad */
-	NULL,			/* select */
+	NULL,			/* poll */
 	ps2esdi_ioctl,		/* ioctl */
 	NULL,			/* mmap */
 	ps2esdi_open,		/* open */
diff -u --recursive --new-file v2.1.22/linux/drivers/block/rd.c linux/drivers/block/rd.c
--- v2.1.22/linux/drivers/block/rd.c	Wed Jan 15 19:45:41 1997
+++ linux/drivers/block/rd.c	Sun Jan 26 12:07:11 1997
@@ -212,7 +212,7 @@
 	initrd_read,	/* read */
 	NULL,		/* write */
 	NULL,		/* readdir */
-	NULL,		/* select */
+	NULL,		/* poll */
 	NULL, 		/* ioctl */
 	NULL,		/* mmap */
 	NULL,		/* open */
@@ -254,7 +254,7 @@
 	block_read,	/* read - block dev read */
 	block_write,	/* write - block dev write */
 	NULL,		/* readdir - not here! */
-	NULL,		/* select */
+	NULL,		/* poll */
 	rd_ioctl, 	/* ioctl */
 	NULL,		/* mmap */
 	rd_open,	/* open */
diff -u --recursive --new-file v2.1.22/linux/drivers/block/xd.c linux/drivers/block/xd.c
--- v2.1.22/linux/drivers/block/xd.c	Thu Jan 23 21:06:46 1997
+++ linux/drivers/block/xd.c	Sun Jan 26 12:07:11 1997
@@ -112,7 +112,7 @@
 	block_read,		/* read - general block-dev read */
 	block_write,		/* write - general block-dev write */
 	NULL,			/* readdir - bad */
-	NULL,			/* select */
+	NULL,			/* poll */
 	xd_ioctl,		/* ioctl */
 	NULL,			/* mmap */
 	xd_open,		/* open */
diff -u --recursive --new-file v2.1.22/linux/drivers/block/z2ram.c linux/drivers/block/z2ram.c
--- v2.1.22/linux/drivers/block/z2ram.c	Sun Dec 22 16:37:30 1996
+++ linux/drivers/block/z2ram.c	Sun Jan 26 12:07:11 1997
@@ -274,7 +274,7 @@
         block_read,             /* read - general block-dev read */
         block_write,            /* write - general block-dev write */
         NULL,                   /* readdir - bad */
-        NULL,                   /* select */
+        NULL,                   /* poll */
         NULL,                   /* ioctl */
         NULL,                   /* mmap */
         z2_open,                /* open */
diff -u --recursive --new-file v2.1.22/linux/drivers/cdrom/aztcd.c linux/drivers/cdrom/aztcd.c
--- v2.1.22/linux/drivers/cdrom/aztcd.c	Mon Dec 30 15:39:04 1996
+++ linux/drivers/cdrom/aztcd.c	Sun Jan 26 12:07:11 1997
@@ -1,5 +1,5 @@
 #define AZT_VERSION "2.50"
-/*      $Id: aztcd.c,v 2.50 1996/05/17 16:19:03 root Exp root $
+/*      $Id: aztcd.c,v 1.16 1997/01/26 07:12:53 davem Exp $
 	linux/drivers/block/aztcd.c - Aztech CD268 CDROM driver
 
 	Copyright (C) 1994,95,96 Werner Zimmermann(zimmerma@rz.fht-esslingen.de)
@@ -341,7 +341,7 @@
 	block_read,             /* read - general block-dev read */
 	block_write,            /* write - general block-dev write */
 	NULL,                   /* readdir - bad */
-	NULL,                   /* select */
+	NULL,                   /* poll */
 	aztcd_ioctl,            /* ioctl */
 	NULL,                   /* mmap */
 	aztcd_open,             /* open */
diff -u --recursive --new-file v2.1.22/linux/drivers/cdrom/bpcd.c linux/drivers/cdrom/bpcd.c
--- v2.1.22/linux/drivers/cdrom/bpcd.c	Sun Dec 22 16:37:31 1996
+++ linux/drivers/cdrom/bpcd.c	Sun Jan 26 12:07:11 1997
@@ -184,7 +184,7 @@
 	block_read,		/* read - general block-dev read */
 	block_write,		/* write - general block-dev write */
 	NULL,			/* readdir - bad */
-	NULL,			/* select */
+	NULL,			/* poll */
 	bp_ioctl,		/* ioctl */
 	NULL,			/* mmap */
 	bp_open,		/* open */
diff -u --recursive --new-file v2.1.22/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c
--- v2.1.22/linux/drivers/cdrom/cdrom.c	Thu Dec 12 17:02:40 1996
+++ linux/drivers/cdrom/cdrom.c	Sun Jan 26 12:07:11 1997
@@ -38,7 +38,7 @@
         block_read,                     /* read - general block-dev read */
         block_write,                    /* write - general block-dev write */
         NULL,                           /* readdir */
-        NULL,                           /* select */
+        NULL,                           /* poll */
         cdrom_ioctl,                    /* ioctl */
         NULL,                           /* mmap */
         cdrom_open,                     /* open */
diff -u --recursive --new-file v2.1.22/linux/drivers/cdrom/cdu31a.c linux/drivers/cdrom/cdu31a.c
--- v2.1.22/linux/drivers/cdrom/cdu31a.c	Mon Dec 30 15:39:04 1996
+++ linux/drivers/cdrom/cdu31a.c	Sun Jan 26 12:07:11 1997
@@ -2885,7 +2885,7 @@
    block_read,             /* read - general block-dev read */
    block_write,            /* write - general block-dev write */
    NULL,                   /* readdir - bad */
-   NULL,                   /* select */
+   NULL,                   /* poll */
    scd_ioctl,              /* ioctl */
    NULL,                   /* mmap */
    scd_open,               /* open */
diff -u --recursive --new-file v2.1.22/linux/drivers/cdrom/gscd.c linux/drivers/cdrom/gscd.c
--- v2.1.22/linux/drivers/cdrom/gscd.c	Mon Dec 30 15:39:05 1996
+++ linux/drivers/cdrom/gscd.c	Sun Jan 26 12:07:11 1997
@@ -155,7 +155,7 @@
 	block_read,		/* read - general block-dev read */
 	block_write,		/* write - general block-dev write */
 	NULL,			/* readdir - bad */
-	NULL,			/* select */
+	NULL,			/* poll */
 	gscd_ioctl,		/* ioctl */
 	NULL,			/* mmap */
 	gscd_open,		/* open */
diff -u --recursive --new-file v2.1.22/linux/drivers/cdrom/mcd.c linux/drivers/cdrom/mcd.c
--- v2.1.22/linux/drivers/cdrom/mcd.c	Fri Nov 15 23:49:07 1996
+++ linux/drivers/cdrom/mcd.c	Sun Jan 26 12:07:11 1997
@@ -1158,7 +1158,7 @@
 	block_read,		/* read - general block-dev read */
 	block_write,		/* write - general block-dev write */
 	NULL,			/* readdir - bad */
-	NULL,			/* select */
+	NULL,			/* poll */
 	mcd_ioctl,		/* ioctl */
 	NULL,			/* mmap */
 	mcd_open,		/* open */
diff -u --recursive --new-file v2.1.22/linux/drivers/cdrom/mcdx.c linux/drivers/cdrom/mcdx.c
--- v2.1.22/linux/drivers/cdrom/mcdx.c	Mon Dec 30 15:39:05 1996
+++ linux/drivers/cdrom/mcdx.c	Sun Jan 26 12:07:11 1997
@@ -49,7 +49,7 @@
 
 #if RCS
 static const char *mcdx_c_version
-		= "$Id: mcdx.c,v 1.12 1996/06/05 01:38:38 heiko Exp $";
+		= "$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $";
 #endif
 
 #include <linux/version.h>
@@ -280,7 +280,7 @@
 	block_read,		/* read - general block-dev read */
 	block_write,	/* write - general block-dev write */
 	NULL,			/* no readdir */
-	NULL,			/* no select */
+	NULL,			/* no poll */
 	mcdx_ioctl,		/* ioctl() */
 	NULL,			/* no mmap */
 	mcdx_open,		/* open() */
@@ -1170,7 +1170,7 @@
 	xwarn("Version 2.14(hs) \n");
 #endif
 
-	xwarn("$Id: mcdx.c,v 1.12 1996/06/05 01:38:38 heiko Exp $\n");
+	xwarn("$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $\n");
 
 	/* zero the pointer array */
 	for (drive = 0; drive < MCDX_NDRIVES; drive++)
diff -u --recursive --new-file v2.1.22/linux/drivers/cdrom/optcd.c linux/drivers/cdrom/optcd.c
--- v2.1.22/linux/drivers/cdrom/optcd.c	Mon Dec 30 15:39:05 1996
+++ linux/drivers/cdrom/optcd.c	Sun Jan 26 12:07:11 1997
@@ -1,5 +1,5 @@
 /*	linux/drivers/cdrom/optcd.c - Optics Storage 8000 AT CDROM driver
-	$Id: optcd.c,v 1.29 1996/02/22 22:38:30 root Exp $
+	$Id: optcd.c,v 1.11 1997/01/26 07:13:00 davem Exp $
 
 	Copyright (C) 1995 Leo Spiekman (spiekman@dutette.et.tudelft.nl)
 
@@ -2002,7 +2002,7 @@
 	block_read,		/* read - general block-dev read */
 	block_write,		/* write - general block-dev write */
 	NULL,			/* readdir - bad */
-	NULL,			/* select */
+	NULL,			/* poll */
 	opt_ioctl,		/* ioctl */
 	NULL,			/* mmap */
 	opt_open,		/* open */
diff -u --recursive --new-file v2.1.22/linux/drivers/cdrom/sbpcd.c linux/drivers/cdrom/sbpcd.c
--- v2.1.22/linux/drivers/cdrom/sbpcd.c	Mon Dec 30 15:39:06 1996
+++ linux/drivers/cdrom/sbpcd.c	Sun Jan 26 12:07:11 1997
@@ -5247,7 +5247,7 @@
 	block_read,             /* read - general block-dev read */
 	block_write,            /* write - general block-dev write */
 	NULL,                   /* readdir - bad */
-	NULL,                   /* select */
+	NULL,                   /* poll */
 	sbpcd_ioctl,            /* ioctl */
 	NULL,                   /* mmap */
 	sbpcd_open,             /* open */
diff -u --recursive --new-file v2.1.22/linux/drivers/cdrom/sjcd.c linux/drivers/cdrom/sjcd.c
--- v2.1.22/linux/drivers/cdrom/sjcd.c	Mon Dec 30 15:39:06 1996
+++ linux/drivers/cdrom/sjcd.c	Sun Jan 26 12:07:12 1997
@@ -1420,7 +1420,7 @@
   block_read,         /* read - general block-dev read */
   block_write,        /* write - general block-dev write */
   NULL,               /* readdir - bad */
-  NULL,               /* select */
+  NULL,               /* poll */
   sjcd_ioctl,         /* ioctl */
   NULL,               /* mmap */
   sjcd_open,          /* open */
diff -u --recursive --new-file v2.1.22/linux/drivers/cdrom/sonycd535.c linux/drivers/cdrom/sonycd535.c
--- v2.1.22/linux/drivers/cdrom/sonycd535.c	Mon Dec 30 15:39:06 1996
+++ linux/drivers/cdrom/sonycd535.c	Sun Jan 26 12:07:12 1997
@@ -1469,7 +1469,7 @@
 	block_read,					/* read - general block-dev read */
 	block_write,				/* write - general block-dev write */
 	NULL,						/* readdir - bad */
-	NULL,						/* select */
+	NULL,						/* poll */
 	cdu_ioctl,					/* ioctl */
 	NULL,						/* mmap */
 	cdu_open,					/* open */
diff -u --recursive --new-file v2.1.22/linux/drivers/char/amigamouse.c linux/drivers/char/amigamouse.c
--- v2.1.22/linux/drivers/char/amigamouse.c	Sun Dec 22 16:37:31 1996
+++ linux/drivers/char/amigamouse.c	Sat Jan 25 23:46:13 1997
@@ -11,13 +11,13 @@
  *
  * Heavily modified by David Giller
  *   changed from queue- to counter- driven
- *   hacked out a (probably incorrect) mouse_select
+ *   hacked out a (probably incorrect) mouse_poll
  *
  * Modified again by Nathan Laredo to interface with
  *   0.96c-pl1 IRQ handling changes (13JUL92)
- *   didn't bother touching select code.
+ *   didn't bother touching poll code.
  *
- * Modified the select() code blindly to conform to the VFS
+ * Modified the poll() code blindly to conform to the VFS
  *   requirements. 92.07.14 - Linus. Somebody should test it out.
  *
  * Modified by Johan Myreen to make room for other mice (9AUG92)
@@ -42,6 +42,7 @@
 #include <linux/errno.h>
 #include <linux/miscdevice.h>
 #include <linux/random.h>
+#include <linux/poll.h>
 
 #include <asm/setup.h>
 #include <asm/system.h>
@@ -277,16 +278,14 @@
 }
 
 /*
- * select for mouse input
+ * poll for mouse input
  */
 
-static int mouse_select(struct inode *inode, struct file *file, int sel_type, select_table * wait)
+static unsigned int mouse_poll(struct file *file, poll_table * wait)
 {
-	if (sel_type == SEL_IN) {
-	    	if (mouse.ready)
-			return 1;
-		select_wait(&mouse.wait, wait);
-    	}
+	poll_wait(&mouse.wait, wait);
+	if (mouse.ready)
+		return POLLIN | POLLRDNORM;
 	return 0;
 }
 
@@ -295,7 +294,7 @@
 	read_mouse,
 	write_mouse,
 	NULL, 		/* mouse_readdir */
-	mouse_select, 	/* mouse_select */
+	mouse_poll, 	/* mouse_poll */
 	NULL, 		/* mouse_ioctl */
 	NULL,		/* mouse_mmap */
 	open_mouse,
diff -u --recursive --new-file v2.1.22/linux/drivers/char/apm_bios.c linux/drivers/char/apm_bios.c
--- v2.1.22/linux/drivers/char/apm_bios.c	Mon Dec 30 15:39:06 1996
+++ linux/drivers/char/apm_bios.c	Sat Jan 25 23:46:13 1997
@@ -302,8 +302,7 @@
 static int	do_open(struct inode *, struct file *);
 static void	do_release(struct inode *, struct file *);
 static long	do_read(struct inode *, struct file *, char *, unsigned long);
-static int	do_select(struct inode *, struct file *, int,
-			  select_table *);
+static unsigned int do_poll(struct file *, poll_table *);
 static int	do_ioctl(struct inode *, struct file *, u_int, u_long);
 
 #ifdef CONFIG_PROC_FS
@@ -360,7 +359,7 @@
 	do_read,
 	NULL,		/* write */
 	NULL,		/* readdir */
-	do_select,
+	do_poll,
 	do_ioctl,
 	NULL,		/* mmap */
 	do_open,
@@ -865,19 +864,16 @@
 	return 0;
 }
 
-static int do_select(struct inode *inode, struct file *fp, int sel_type,
-		     select_table * wait)
+static unsigned int do_poll(struct file *fp, poll_table * wait)
 {
-	struct apm_bios_struct *	as;
+	struct apm_bios_struct * as;
 
 	as = fp->private_data;
 	if (check_apm_bios_struct(as, "select"))
 		return 0;
-	if (sel_type != SEL_IN)
-		return 0;
+	poll_wait(&process_list, wait);
 	if (!queue_empty(as))
-		return 1;
-	select_wait(&process_list, wait);
+		return POLLIN | POLLRDNORM;
 	return 0;
 }
 
diff -u --recursive --new-file v2.1.22/linux/drivers/char/atarimouse.c linux/drivers/char/atarimouse.c
--- v2.1.22/linux/drivers/char/atarimouse.c	Sun Dec 22 16:37:31 1996
+++ linux/drivers/char/atarimouse.c	Sun Jan 26 12:07:12 1997
@@ -19,6 +19,7 @@
 #include <linux/miscdevice.h>
 #include <linux/mm.h>
 #include <linux/random.h>
+#include <linux/poll.h>
 
 #include <asm/setup.h>
 #include <asm/atarikb.h>
@@ -130,13 +131,11 @@
     return r;
 }
 
-static int mouse_select(struct inode *inode, struct file *file, int sel_type, select_table *wait)
+static unsigned int mouse_poll(struct file *file, poll_table *wait)
 {
-	if (sel_type == SEL_IN) {
-	    	if (mouse.ready)
-			return 1;
-		select_wait(&mouse.wait, wait);
-	}
+	poll_wait(&mouse.wait, wait);
+	if (mouse.ready)
+		return POLLIN | POLLRDNORM;
 	return 0;
 }
 
@@ -145,7 +144,7 @@
     read_mouse,
     write_mouse,
     NULL,		/* mouse_readdir */
-    mouse_select,
+    mouse_poll,
     NULL,		/* mouse_ioctl */
     NULL,		/* mouse_mmap */
     open_mouse,
diff -u --recursive --new-file v2.1.22/linux/drivers/char/atixlmouse.c linux/drivers/char/atixlmouse.c
--- v2.1.22/linux/drivers/char/atixlmouse.c	Tue Oct 29 19:58:05 1996
+++ linux/drivers/char/atixlmouse.c	Sun Jan 26 12:07:12 1997
@@ -18,6 +18,7 @@
 #include <linux/errno.h>
 #include <linux/miscdevice.h>
 #include <linux/random.h>
+#include <linux/poll.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -172,13 +173,11 @@
 	return i; /* i data bytes returned */
 }
 
-static int mouse_select(struct inode *inode, struct file *file, int sel_type, select_table * wait)
+static unsigned int mouse_poll(struct file *file, poll_table * wait)
 {
-	if (sel_type != SEL_IN)
-		return 0;
+	poll_wait(&mouse.wait, wait);
 	if (mouse.ready)
-		return 1;
-	select_wait(&mouse.wait,wait);
+		return POLLIN | POLLRDNORM;
 	return 0;
 }
 
@@ -187,7 +186,7 @@
 	read_mouse,
 	write_mouse,
 	NULL, 		/* mouse_readdir */
-	mouse_select, 	/* mouse_select */
+	mouse_poll, 	/* mouse_poll */
 	NULL, 		/* mouse_ioctl */
 	NULL,		/* mouse_mmap */
 	open_mouse,
diff -u --recursive --new-file v2.1.22/linux/drivers/char/busmouse.c linux/drivers/char/busmouse.c
--- v2.1.22/linux/drivers/char/busmouse.c	Tue Oct 29 19:58:05 1996
+++ linux/drivers/char/busmouse.c	Sun Jan 26 12:07:14 1997
@@ -41,6 +41,7 @@
 #include <linux/signal.h>
 #include <linux/errno.h>
 #include <linux/mm.h>
+#include <linux/poll.h>
 #include <linux/miscdevice.h>
 #include <linux/random.h>
 #include <linux/delay.h>
@@ -216,15 +217,13 @@
 }
 
 /*
- * select for mouse input
+ * poll for mouse input
  */
-static int mouse_select(struct inode *inode, struct file *file, int sel_type, select_table * wait)
+static unsigned int mouse_poll(struct file *file, poll_table * wait)
 {
-	if (sel_type == SEL_IN) {
-	    	if (mouse.ready)
-			return 1;
-		select_wait(&mouse.wait, wait);
-    	}
+	poll_wait(&mouse.wait, wait);
+	if (mouse.ready)
+		return POLLIN | POLLRDNORM;
 	return 0;
 }
 
@@ -233,7 +232,7 @@
 	read_mouse,
 	write_mouse,
 	NULL, 		/* mouse_readdir */
-	mouse_select, 	/* mouse_select */
+	mouse_poll, 	/* mouse_poll */
 	NULL, 		/* mouse_ioctl */
 	NULL,		/* mouse_mmap */
 	open_mouse,
diff -u --recursive --new-file v2.1.22/linux/drivers/char/console.c linux/drivers/char/console.c
--- v2.1.22/linux/drivers/char/console.c	Sun Nov 10 20:12:10 1996
+++ linux/drivers/char/console.c	Sun Jan 26 12:07:16 1997
@@ -118,6 +118,10 @@
 #define MIN(a,b)	((a) < (b) ? (a) : (b))
 #endif
 
+#ifdef __sparc__
+int serial_console;
+#endif
+
 struct tty_driver console_driver;
 static int console_refcount;
 static struct tty_struct *console_table[MAX_NR_CONSOLES];
@@ -151,8 +155,10 @@
 extern void reset_palette(int currcons);
 extern void set_palette(void);
 extern unsigned long con_type_init(unsigned long, const char **);
+extern void con_type_init_finish(void);
 extern int set_get_cmap(unsigned char *, int);
 extern int set_get_font(unsigned char *, int, int);
+extern void rs_cons_hook(int chip, int out, int channel);
 
 /* Description of the hardware situation */
 unsigned char	video_type;		/* Type of display being used	*/
@@ -640,40 +646,30 @@
 	} else {
 		unsigned short * d = (unsigned short *) (origin+video_size_row*t);
 		unsigned short * s = (unsigned short *) (origin+video_size_row*(t+1));
-		unsigned int count = (b-t-1) * video_num_columns;
 
-		while (count) {
-			count--;
-			scr_writew(scr_readw(s++), d++);
-		}
-		count = video_num_columns;
-		while (count) {
-			count--;
-			scr_writew(video_erase_char, d++);
-		}
+		memcpyw(d, s, (b-t-1) * video_size_row);
+		memsetw(d + (b-t-1) * video_num_columns, video_erase_char, video_size_row);
 	}
 }
 
 void
 scrdown(int currcons, unsigned int t, unsigned int b)
 {
-	unsigned short *d, *s;
+	unsigned short *s;
 	unsigned int count;
 
 	if (b > video_num_lines || t >= b)
 		return;
-	d = (unsigned short *) (origin+video_size_row*b);
-	s = (unsigned short *) (origin+video_size_row*(b-1));
-	count = (b-t-1)*video_num_columns;
-	while (count) {
-		count--;
-		scr_writew(scr_readw(--s), --d);
-	}
-	count = video_num_columns;
-	while (count) {
-		count--;
-		scr_writew(video_erase_char, --d);
+	s = (unsigned short *) (origin+video_size_row*(b-2));
+	if (b >= t + 1) {
+		count = b - t - 1;
+		while (count) {
+			count--;
+			memcpyw(s + video_num_columns, s, video_size_row);
+			s -= video_num_columns;
+		}
 	}
+	memsetw(s + video_num_columns, video_erase_char, video_size_row);
 	has_scrolled = 1;
 }
 
@@ -746,10 +742,7 @@
 		default:
 			return;
 	}
-	while (count) {
-		count--;
-		scr_writew(video_erase_char, start++);
-	}
+	memsetw(start, video_erase_char, 2*count);
 	need_wrap = 0;
 }
 
@@ -774,28 +767,17 @@
 		default:
 			return;
 	}
-	while (count) {
-		count--;
-		scr_writew(video_erase_char, start++);
-	}
+	memsetw(start, video_erase_char, 2 * count);
 	need_wrap = 0;
 }
 
 static void csi_X(int currcons, int vpar) /* erase the following vpar positions */
 {					  /* not vt100? */
-	unsigned long count;
-	unsigned short * start;
-
 	if (!vpar)
 		vpar++;
 
-	start = (unsigned short *) pos;
-	count = (vpar > video_num_columns-x) ? (video_num_columns-x) : vpar;
-
-	while (count) {
-		count--;
-		scr_writew(video_erase_char, start++);
-	}
+	memsetw((unsigned short *) pos, video_erase_char,
+		(vpar > video_num_columns-x) ? 2 * (video_num_columns-x) : 2 * vpar);
 	need_wrap = 0;
 }
 
@@ -1348,8 +1330,10 @@
 	console_num = MINOR(tty->device) - (tty->driver.minor_start);
 	if (!vc_cons_allocated(console_num))
 		return;
+#if !CONFIG_AP1000
 	set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
 	set_leds();
+#endif
 }
 
 /*
@@ -1363,8 +1347,10 @@
 	console_num = MINOR(tty->device) - (tty->driver.minor_start);
 	if (!vc_cons_allocated(console_num))
 		return;
+#if !CONFIG_AP1000
 	clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
 	set_leds();
+#endif
 }
 
 static void con_flush_chars(struct tty_struct *tty)
@@ -1384,6 +1370,11 @@
 	unsigned int currcons;
 	struct vt_struct *vt = (struct vt_struct *)tty->driver_data;
 
+#if CONFIG_AP1000
+        ap_write(1,buf,count);
+        return(count);
+#endif
+
 	currcons = vt->vc_num;
 	if (!vc_cons_allocated(currcons)) {
 	    /* could this happen? */
@@ -1846,10 +1837,10 @@
 		     const unsigned char *buf, int count)
 {
 	int	retval;
-	
+
 	retval = do_con_write(tty, from_user, buf, count);
 	con_flush_chars(tty);
-	
+
 	return retval;
 }
 
@@ -1891,6 +1882,10 @@
 	unsigned char c;
 	static int printing = 0;
 
+#if CONFIG_AP1000
+        prom_printf(b);
+        return;
+#endif
 	if (!printable || printing)
 		return;	 /* console not yet initialized */
 	printing = 1;
@@ -2026,6 +2021,19 @@
 	int orig_x = ORIG_X;
 	int orig_y = ORIG_Y;
 
+#ifdef __sparc__
+	if (serial_console) {
+		fg_console = 0;
+
+#if CONFIG_SUN_SERIAL
+		rs_cons_hook(0, 0, serial_console);
+		rs_cons_hook(0, 1, serial_console);
+#endif
+
+		return kmem_start;
+	}
+#endif
+
 	memset(&console_driver, 0, sizeof(struct tty_driver));
 	console_driver.magic = TTY_DRIVER_MAGIC;
 	console_driver.name = "tty";
@@ -2056,6 +2064,9 @@
 	if (tty_register_driver(&console_driver))
 		panic("Couldn't register console driver\n");
 
+#if CONFIG_AP1000
+        return(kmem_start);
+#endif
 	con_setsize(ORIG_VIDEO_LINES, ORIG_VIDEO_COLS);
 
 	timer_table[BLANK_TIMER].fn = blank_screen;
@@ -2110,7 +2121,8 @@
 
 	printable = 1;
 	if ( video_type == VIDEO_TYPE_VGAC || video_type == VIDEO_TYPE_EGAC
-	    || video_type == VIDEO_TYPE_EGAM || video_type == VIDEO_TYPE_TGAC )
+	    || video_type == VIDEO_TYPE_EGAM || video_type == VIDEO_TYPE_TGAC 
+	     || video_type == VIDEO_TYPE_SUN )
 	{
 		default_font_height = video_font_height = ORIG_VIDEO_POINTS;
 		/* This may be suboptimal but is a safe bet - go with it */
@@ -2129,6 +2141,8 @@
 		display_desc, video_num_columns, video_num_lines,
 		MIN_NR_CONSOLES, (MIN_NR_CONSOLES == 1) ? "" : "s",
 	        MAX_NR_CONSOLES);
+
+	con_type_init_finish();
 
 	/*
 	 * can't register TGA yet, because PCI bus probe has *not* taken
diff -u --recursive --new-file v2.1.22/linux/drivers/char/fbmem.c linux/drivers/char/fbmem.c
--- v2.1.22/linux/drivers/char/fbmem.c	Sun Dec 22 16:37:31 1996
+++ linux/drivers/char/fbmem.c	Sun Jan 26 12:07:16 1997
@@ -263,7 +263,7 @@
 	fb_read,	/* read		*/
 	fb_write,	/* write	*/
 	NULL,		/* readdir 	*/
-	NULL,		/* select 	*/
+	NULL,		/* poll 	*/
 	fb_ioctl,	/* ioctl 	*/
 	fb_mmap,	/* mmap		*/
 	fb_open,	/* open 	*/
diff -u --recursive --new-file v2.1.22/linux/drivers/char/ftape/kernel-interface.c linux/drivers/char/ftape/kernel-interface.c
--- v2.1.22/linux/drivers/char/ftape/kernel-interface.c	Mon Dec 30 15:39:07 1996
+++ linux/drivers/char/ftape/kernel-interface.c	Sun Jan 26 12:07:16 1997
@@ -72,7 +72,7 @@
 	ftape_read,		/* read */
 	ftape_write,		/* write */
 	NULL,			/* readdir */
-	NULL,			/* select */
+	NULL,			/* poll */
 	ftape_ioctl,		/* ioctl */
 	NULL,			/* mmap */
 	ftape_open,		/* open */
@@ -129,16 +129,16 @@
 	printk(KERN_INFO "ftape-2.08 960314\n"
 	       KERN_INFO " (c) 1993-1995 Bas Laarhoven (bas@vimec.nl)\n"
 	       KERN_INFO " (c) 1995-1996 Kai Harrekilde-Petersen (khp@dolphinics.no)\n"
-	KERN_INFO " QIC-117 driver for QIC-40/80/3010/3020 tape drives\n"
-	       KERN_INFO " Compiled for kernel version %s"
+	       KERN_INFO " QIC-117 driver for QIC-40/80/3010/3020 tape drives\n"
+	       KERN_INFO " Compiled for kernel version " UTS_RELEASE
 #ifdef MODVERSIONS
 	       " with versioned symbols"
 #endif
-	       "\n", kernel_version);
+	       "\n");
 #else /* !MODULE */
 	/* print a short no-nonsense boot message */
 	printk("ftape-2.08 960314 for Linux 1.3.70\n");
-#endif				/* MODULE */
+#endif /* MODULE */
 	TRACE(3, "installing QIC-117 ftape driver...");
 	if (register_chrdev(QIC117_TAPE_MAJOR, "ft", &ftape_cdev)) {
 		TRACE(1, "register_chrdev failed");
diff -u --recursive --new-file v2.1.22/linux/drivers/char/lp.c linux/drivers/char/lp.c
--- v2.1.22/linux/drivers/char/lp.c	Tue Oct 29 19:58:05 1996
+++ linux/drivers/char/lp.c	Sun Jan 26 12:07:16 1997
@@ -527,7 +527,7 @@
 	NULL,		/* lp_read */
 	lp_write,
 	NULL,		/* lp_readdir */
-	NULL,		/* lp_select */
+	NULL,		/* lp_poll */
 	lp_ioctl,
 	NULL,		/* lp_mmap */
 	lp_open,
diff -u --recursive --new-file v2.1.22/linux/drivers/char/lp_m68k.c linux/drivers/char/lp_m68k.c
--- v2.1.22/linux/drivers/char/lp_m68k.c	Sun Dec 22 16:37:31 1996
+++ linux/drivers/char/lp_m68k.c	Sun Jan 26 12:07:16 1997
@@ -450,7 +450,7 @@
 	NULL,		/* lp_read */
 	lp_write,
 	NULL,		/* lp_readdir */
-	NULL,		/* lp_select */
+	NULL,		/* lp_poll */
 	lp_ioctl,
 	NULL,		/* lp_mmap */
 	lp_open,
diff -u --recursive --new-file v2.1.22/linux/drivers/char/mem.c linux/drivers/char/mem.c
--- v2.1.22/linux/drivers/char/mem.c	Thu Jan 23 21:06:47 1997
+++ linux/drivers/char/mem.c	Sat Jan 25 23:46:13 1997
@@ -372,7 +372,7 @@
 	read_mem,
 	write_mem,
 	NULL,		/* mem_readdir */
-	NULL,		/* mem_select */
+	NULL,		/* mem_poll */
 	NULL,		/* mem_ioctl */
 	mmap_mem,
 	NULL,		/* no special open code */
@@ -385,7 +385,7 @@
 	read_kmem,
 	write_kmem,
 	NULL,		/* kmem_readdir */
-	NULL,		/* kmem_select */
+	NULL,		/* kmem_poll */
 	NULL,		/* kmem_ioctl */
 	mmap_kmem,
 	NULL,		/* no special open code */
@@ -398,7 +398,7 @@
 	read_null,
 	write_null,
 	NULL,		/* null_readdir */
-	NULL,		/* null_select */
+	NULL,		/* null_poll */
 	NULL,		/* null_ioctl */
 	NULL,		/* null_mmap */
 	NULL,		/* no special open code */
@@ -411,7 +411,7 @@
 	read_port,
 	write_port,
 	NULL,		/* port_readdir */
-	NULL,		/* port_select */
+	NULL,		/* port_poll */
 	NULL,		/* port_ioctl */
 	NULL,		/* port_mmap */
 	NULL,		/* no special open code */
@@ -424,7 +424,7 @@
 	read_zero,
 	write_zero,
 	NULL,		/* zero_readdir */
-	NULL,		/* zero_select */
+	NULL,		/* zero_poll */
 	NULL,		/* zero_ioctl */
 	mmap_zero,
 	NULL,		/* no special open code */
@@ -436,7 +436,7 @@
 	read_full,
 	write_full,
 	NULL,		/* full_readdir */
-	NULL,		/* full_select */
+	NULL,		/* full_poll */
 	NULL,		/* full_ioctl */	
 	NULL,		/* full_mmap */
 	NULL,		/* no special open code */
@@ -483,7 +483,7 @@
 	NULL,		/* read */
 	NULL,		/* write */
 	NULL,		/* readdir */
-	NULL,		/* select */
+	NULL,		/* poll */
 	NULL,		/* ioctl */
 	NULL,		/* mmap */
 	memory_open,	/* just a selector for the real open */
diff -u --recursive --new-file v2.1.22/linux/drivers/char/misc.c linux/drivers/char/misc.c
--- v2.1.22/linux/drivers/char/misc.c	Thu Jan 23 21:06:47 1997
+++ linux/drivers/char/misc.c	Sun Jan 26 12:07:16 1997
@@ -119,7 +119,7 @@
 	NULL,		/* read */
 	NULL,		/* write */
 	NULL,		/* readdir */
-	NULL,		/* select */
+	NULL,		/* poll */
 	NULL,		/* ioctl */
 	NULL,		/* mmap */
         misc_open,
diff -u --recursive --new-file v2.1.22/linux/drivers/char/msbusmouse.c linux/drivers/char/msbusmouse.c
--- v2.1.22/linux/drivers/char/msbusmouse.c	Tue Oct 29 19:58:06 1996
+++ linux/drivers/char/msbusmouse.c	Sun Jan 26 12:07:16 1997
@@ -40,6 +40,7 @@
 #include <linux/errno.h>
 #include <linux/miscdevice.h>
 #include <linux/random.h>
+#include <linux/poll.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -155,13 +156,11 @@
 	return i;	
 }
 
-static int mouse_select(struct inode *inode, struct file *file, int sel_type, select_table * wait)
+static unsigned int mouse_poll(struct file *file, poll_table * wait)
 {
-	if (sel_type != SEL_IN)
-		return 0;
+	poll_wait(&mouse.wait, wait);
 	if (mouse.ready) 
-		return 1;
-	select_wait(&mouse.wait,wait);
+		return POLLIN | POLLRDNORM;
 	return 0;
 }
 
@@ -170,7 +169,7 @@
 	read_mouse,
 	write_mouse,
 	NULL, 		/* mouse_readdir */
-	mouse_select, 	/* mouse_select */
+	mouse_poll, 	/* mouse_poll */
 	NULL, 		/* mouse_ioctl */
 	NULL,		/* mouse_mmap */
 	open_mouse,
diff -u --recursive --new-file v2.1.22/linux/drivers/char/n_tty.c linux/drivers/char/n_tty.c
--- v2.1.22/linux/drivers/char/n_tty.c	Thu Dec 12 19:37:01 1996
+++ linux/drivers/char/n_tty.c	Sat Jan 25 23:46:13 1997
@@ -33,6 +33,7 @@
 #include <linux/mm.h>
 #include <linux/string.h>
 #include <linux/malloc.h>
+#include <linux/poll.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -982,37 +983,29 @@
 	return (b - buf) ? b - buf : retval;
 }
 
-static int normal_select(struct tty_struct * tty, struct inode * inode,
-			 struct file * file, int sel_type, select_table *wait)
+static unsigned int normal_poll(struct tty_struct * tty, struct file * file, poll_table *wait)
 {
-	switch (sel_type) {
-		case SEL_IN:
-			if (input_available_p(tty, TIME_CHAR(tty) ? 0 :
-					      MIN_CHAR(tty)))
-				return 1;
-			/* fall through */
-		case SEL_EX:
-			if (tty->packet && tty->link->ctrl_status)
-				return 1;
-			if (tty->flags & (1 << TTY_OTHER_CLOSED))
-				return 1;
-			if (tty_hung_up_p(file))
-				return 1;
-			if (!waitqueue_active(&tty->read_wait)) {
-				if (MIN_CHAR(tty) && !TIME_CHAR(tty))
-					tty->minimum_to_wake = MIN_CHAR(tty);
-				else
-					tty->minimum_to_wake = 1;
-			}
-			select_wait(&tty->read_wait, wait);
-			return 0;
-		case SEL_OUT:
-			if (tty->driver.chars_in_buffer(tty) < WAKEUP_CHARS)
-				return 1;
-			select_wait(&tty->write_wait, wait);
-			return 0;
+	unsigned int mask = 0;
+
+	poll_wait(&tty->read_wait, wait);
+	poll_wait(&tty->write_wait, wait);
+	if (input_available_p(tty, TIME_CHAR(tty) ? 0 : MIN_CHAR(tty)))
+		mask |= POLLIN | POLLRDNORM;
+	if (tty->packet && tty->link->ctrl_status)
+		mask |= POLLPRI | POLLIN | POLLRDNORM;
+	if (tty->flags & (1 << TTY_OTHER_CLOSED))
+		mask |= POLLHUP;
+	if (tty_hung_up_p(file))
+		mask |= POLLHUP;
+	if (!(mask & (POLLHUP | POLLIN | POLLRDNORM))) {
+		if (MIN_CHAR(tty) && !TIME_CHAR(tty))
+			tty->minimum_to_wake = MIN_CHAR(tty);
+		else
+			tty->minimum_to_wake = 1;
 	}
-	return 0;
+	if (tty->driver.chars_in_buffer(tty) < WAKEUP_CHARS)
+		mask |= POLLOUT | POLLWRNORM;
+	return mask;
 }
 
 struct tty_ldisc tty_ldisc_N_TTY = {
@@ -1027,7 +1020,7 @@
 	write_chan,		/* write */
 	n_tty_ioctl,		/* ioctl */
 	n_tty_set_termios,	/* set_termios */
-	normal_select,		/* select */
+	normal_poll,		/* poll */
 	n_tty_receive_buf,	/* receive_buf */
 	n_tty_receive_room,	/* receive_room */
 	0			/* write_wakeup */
diff -u --recursive --new-file v2.1.22/linux/drivers/char/psaux.c linux/drivers/char/psaux.c
--- v2.1.22/linux/drivers/char/psaux.c	Thu Dec 12 19:37:01 1996
+++ linux/drivers/char/psaux.c	Sat Jan 25 23:46:13 1997
@@ -45,6 +45,7 @@
 #include <linux/malloc.h>
 #include <linux/miscdevice.h>
 #include <linux/random.h>
+#include <linux/poll.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -494,13 +495,11 @@
 }
 
 
-static int aux_select(struct inode *inode, struct file *file, int sel_type, select_table * wait)
+static unsigned int aux_poll(struct file *file, poll_table * wait)
 {
-	if (sel_type != SEL_IN)
-		return 0;
+	poll_wait(&queue->proc_list, wait);
 	if (aux_ready)
-		return 1;
-	select_wait(&queue->proc_list, wait);
+		return POLLIN | POLLRDNORM;
 	return 0;
 }
 
@@ -510,7 +509,7 @@
 	read_aux,
 	write_aux,
 	NULL, 		/* readdir */
-	aux_select,
+	aux_poll,
 	NULL, 		/* ioctl */
 	NULL,		/* mmap */
 	open_aux,
diff -u --recursive --new-file v2.1.22/linux/drivers/char/random.c linux/drivers/char/random.c
--- v2.1.22/linux/drivers/char/random.c	Tue Oct 29 19:58:06 1996
+++ linux/drivers/char/random.c	Sat Jan 25 23:46:13 1997
@@ -233,6 +233,7 @@
 #include <linux/fcntl.h>
 #include <linux/malloc.h>
 #include <linux/random.h>
+#include <linux/poll.h>
 
 #include <asm/uaccess.h>
 #include <asm/irq.h>
@@ -332,8 +333,7 @@
 		       char * buf, unsigned long nbytes);
 static long random_read_unlimited(struct inode * inode, struct file * file,
 				 char * buf, unsigned long nbytes);
-static int random_select(struct inode *inode, struct file *file,
-			 int sel_type, select_table * wait);
+static unsigned int random_poll(struct file *file, poll_table * wait);
 static long random_write(struct inode * inode, struct file * file,
 			const char * buffer, unsigned long count);
 static int random_ioctl(struct inode * inode, struct file * file,
@@ -1086,23 +1086,18 @@
 	return extract_entropy(&random_state, buf, nbytes, 1);
 }
 
-static int
-random_select(struct inode *inode, struct file *file,
-		      int sel_type, select_table * wait)
+static unsigned int
+random_poll(struct file *file, poll_table * wait)
 {
-	switch (sel_type) {
-	case SEL_IN:
-		if (random_state.entropy_count >= 8)
-			return 1;
-		select_wait(&random_wait, wait);
-		break;
-	case SEL_OUT:
-		if (random_state.entropy_count < WAIT_OUTPUT_BITS)
-			return 1;
-		select_wait(&random_wait, wait);
-		break;
-	}
-	return 0;
+	unsigned int mask;
+
+	poll_wait(&random_wait, wait);
+	mask = 0;
+	if (random_state.entropy_count >= 8)
+		mask |= POLLIN | POLLRDNORM;
+	if (random_state.entropy_count < WAIT_OUTPUT_BITS)
+		mask |= POLLOUT | POLLWRNORM;
+	return mask;
 }
 
 static long
@@ -1270,7 +1265,7 @@
 	random_read,
 	random_write,
 	NULL,		/* random_readdir */
-	random_select,	/* random_select */
+	random_poll,	/* random_poll */
 	random_ioctl,
 	NULL,		/* random_mmap */
 	NULL,		/* no special open code */
@@ -1282,7 +1277,7 @@
 	random_read_unlimited,
 	random_write,
 	NULL,		/* urandom_readdir */
-	NULL,		/* urandom_select */
+	NULL,		/* urandom_poll */
 	random_ioctl,
 	NULL,		/* urandom_mmap */
 	NULL,		/* no special open code */
diff -u --recursive --new-file v2.1.22/linux/drivers/char/rtc.c linux/drivers/char/rtc.c
--- v2.1.22/linux/drivers/char/rtc.c	Sun Dec 22 16:37:31 1996
+++ linux/drivers/char/rtc.c	Sat Jan 25 23:46:13 1997
@@ -75,8 +75,7 @@
 static int rtc_ioctl(struct inode *inode, struct file *file,
 			unsigned int cmd, unsigned long arg);
 
-static int rtc_select(struct inode *inode, struct file *file,
-			int sel_type, select_table *wait);
+static unsigned int rtc_poll(struct file *file, poll_table *wait);
 
 void get_rtc_time (struct rtc_time *rtc_tm);
 void get_rtc_alm_time (struct rtc_time *alm_tm);
@@ -492,14 +491,11 @@
 	rtc_status &= ~RTC_IS_OPEN;
 }
 
-static int rtc_select(struct inode *inode, struct file *file,
-			int sel_type, select_table *wait)
+static unsigned int rtc_poll(struct file *file, poll_table *wait)
 {
-	if (sel_type == SEL_IN) {
-		if (rtc_irq_data != 0)
-			return 1;
-		select_wait(&rtc_wait, wait);
-	}
+	poll_wait(&rtc_wait, wait);
+	if (rtc_irq_data != 0)
+		return POLLIN | POLLRDNORM;
 	return 0;
 }
 
@@ -512,7 +508,7 @@
 	rtc_read,
 	NULL,		/* No write */
 	NULL,		/* No readdir */
-	rtc_select,
+	rtc_poll,
 	rtc_ioctl,
 	NULL,		/* No mmap */
 	rtc_open,
diff -u --recursive --new-file v2.1.22/linux/drivers/char/selection.h linux/drivers/char/selection.h
--- v2.1.22/linux/drivers/char/selection.h	Mon Sep 30 11:20:42 1996
+++ linux/drivers/char/selection.h	Sun Jan 26 12:22:42 1997
@@ -62,7 +62,7 @@
 
 #include <linux/config.h>
 
-#ifdef CONFIG_TGA_CONSOLE
+#if defined(CONFIG_TGA_CONSOLE)
 
 extern int tga_blitc(unsigned int, unsigned long);
 extern unsigned long video_mem_term;
@@ -73,10 +73,6 @@
  * TGA is *not* a character/attribute cell device; font bitmaps must be rendered
  * to the screen pixels.
  *
- * The "unsigned short * addr" is *ALWAYS* a kernel virtual address, either
- * of the VC's backing store, or the "shadow screen" memory where the screen
- * contents are kept, as the TGA frame buffer is *not* char/attr cells.
- *
  * We must test for an Alpha kernel virtual address that falls within
  *  the "shadow screen" memory. This condition indicates we really want 
  *  to write to the screen, so, we do... :-)
@@ -86,10 +82,10 @@
  */
 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) {
@@ -101,7 +97,37 @@
 {
 	return *addr;
 }
-#else /* CONFIG_TGA_CONSOLE */
+
+#elif defined(CONFIG_SUN_CONSOLE)
+#include "vt_kern.h"
+#include <linux/kd.h>
+extern int sun_blitc(unsigned int, unsigned long);
+extern void memsetw(void * s, unsigned short c, unsigned int count);
+extern void memcpyw(unsigned short *to, unsigned short *from, unsigned int count);
+extern unsigned long video_mem_term;
+
+/* Basically the same as the TGA stuff. */
+static inline void scr_writew(unsigned short val, unsigned short * addr)
+{
+        /*
+         * always deposit the char/attr, then see if it was to "screen" mem.
+	 * if so, then render the char/attr onto the real screen.
+         */
+	if (*addr != val) {
+        	*addr = val;
+		if ((unsigned long)addr < video_mem_term &&
+		    (unsigned long)addr >= video_mem_base &&
+		    vt_cons [fg_console]->vc_mode == KD_TEXT)
+			sun_blitc(val, (unsigned long) addr);
+	}
+}
+
+static inline unsigned short scr_readw(unsigned short * addr)
+{
+	return *addr;
+}
+
+#else /* CONFIG_TGA_CONSOLE  || CONFIG_SUN_CONSOLE */
 
 /*
  * normal VGA console access
@@ -147,6 +173,7 @@
 
 #endif /* CONFIG_TGA_CONSOLE */
 
+#ifndef CONFIG_SUN_CONSOLE
 static inline void memsetw(void * s, unsigned short c, unsigned int count)
 {
 	unsigned short * addr = (unsigned short *) s;
@@ -167,3 +194,4 @@
 		scr_writew(scr_readw(from++), to++);
 	}
 }
+#endif /* CONFIG_SUN_CONSOLE */
diff -u --recursive --new-file v2.1.22/linux/drivers/char/tga.c linux/drivers/char/tga.c
--- v2.1.22/linux/drivers/char/tga.c	Tue Oct 29 19:58:08 1996
+++ linux/drivers/char/tga.c	Sun Jan 26 12:07:16 1997
@@ -323,6 +323,11 @@
 	return kmem_start;
 }
 
+void
+con_type_init_finish(void)
+{
+}
+
 /*
  * NOTE: get_scrmem() and set_scrmem() are here only because
  * the VGA version of set_scrmem() has some direct VGA references.
diff -u --recursive --new-file v2.1.22/linux/drivers/char/tpqic02.c linux/drivers/char/tpqic02.c
--- v2.1.22/linux/drivers/char/tpqic02.c	Thu Jan 23 21:06:47 1997
+++ linux/drivers/char/tpqic02.c	Sun Jan 26 12:07:17 1997
@@ -1,4 +1,4 @@
-/* $Id: tpqic02.c,v 0.7.1.5 1996/12/14 22:58:52 root Exp root $
+/* $Id: tpqic02.c,v 1.10 1997/01/26 07:13:20 davem Exp $
  *
  * Driver for tape drive support for Linux-i386
  *
@@ -133,8 +133,8 @@
 
 static volatile struct tpstatus tperror;	/* last drive status */
 
-static char rcs_revision[] = "$Revision: 0.7.1.5 $";
-static char rcs_date[] = "$Date: 1996/12/14 22:58:52 $";
+static char rcs_revision[] = "$Revision: 1.10 $";
+static char rcs_date[] = "$Date: 1997/01/26 07:13:20 $";
 
 /* Flag bits for status and outstanding requests.
  * (Could all be put in one bit-field-struct.)
@@ -2747,7 +2747,7 @@
 	qic02_tape_read,		/* read */
 	qic02_tape_write,		/* write */
 	NULL,				/* readdir not allowed */
-	NULL,				/* select ??? */
+	NULL,				/* poll ??? */
 	qic02_tape_ioctl,		/* ioctl */
 	NULL,				/* mmap not allowed */
 	qic02_tape_open,		/* open */
diff -u --recursive --new-file v2.1.22/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- v2.1.22/linux/drivers/char/tty_io.c	Thu Jan  2 15:55:16 1997
+++ linux/drivers/char/tty_io.c	Sun Jan 26 12:07:17 1997
@@ -62,6 +62,7 @@
 #include <linux/mm.h>
 #include <linux/string.h>
 #include <linux/malloc.h>
+#include <linux/poll.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -110,7 +111,7 @@
 
 static long tty_read(struct inode *, struct file *, char *, unsigned long);
 static long tty_write(struct inode *, struct file *, const char *, unsigned long);
-static int tty_select(struct inode *, struct file *, int, select_table *);
+static unsigned int tty_poll(struct file *, poll_table *);
 static int tty_open(struct inode *, struct file *);
 static void tty_release(struct inode *, struct file *);
 static int tty_ioctl(struct inode * inode, struct file * file,
@@ -322,10 +323,9 @@
 	return -EIO;
 }
 
-static int hung_up_tty_select(struct inode * inode, struct file * filp,
-	int sel_type, select_table * wait)
+static unsigned int hung_up_tty_poll(struct file * filp, poll_table * wait)
 {
-	return 1;
+	return POLLIN | POLLOUT | POLLERR | POLLHUP | POLLRDNORM | POLLWRNORM;
 }
 
 static int hung_up_tty_ioctl(struct inode * inode, struct file * file,
@@ -345,7 +345,7 @@
 	tty_read,
 	tty_write,
 	NULL,		/* tty_readdir */
-	tty_select,
+	tty_poll,
 	tty_ioctl,
 	NULL,		/* tty_mmap */
 	tty_open,
@@ -359,7 +359,7 @@
 	hung_up_tty_read,
 	hung_up_tty_write,
 	NULL,		/* hung_up_tty_readdir */
-	hung_up_tty_select,
+	hung_up_tty_poll,
 	hung_up_tty_ioctl,
 	NULL,		/* hung_up_tty_mmap */
 	NULL,		/* hung_up_tty_open */
@@ -607,6 +607,25 @@
 	if (vt_cons[new_console]->vc_mode == KD_TEXT)
 		set_palette() ;
 	
+#ifdef CONFIG_SUN_CONSOLE
+	if (old_vc_mode != vt_cons[new_console]->vc_mode)
+	{
+		extern void set_cursor(int currcons);
+		extern void hide_cursor(void);
+
+	 	if (old_vc_mode == KD_GRAPHICS)
+		{
+			extern void sun_clear_margin(void);
+			extern void render_screen(void);
+			
+			sun_clear_margin();
+			render_screen();
+			set_cursor(fg_console);
+		}
+		else
+			hide_cursor();
+	}
+#endif		
 	/*
 	 * Wake anyone waiting for their VT to activate
 	 */
@@ -1287,16 +1306,16 @@
 	release_dev(filp);
 }
 
-static int tty_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait)
+static unsigned int tty_poll(struct file * filp, poll_table * wait)
 {
 	struct tty_struct * tty;
 
 	tty = (struct tty_struct *)filp->private_data;
-	if (tty_paranoia_check(tty, inode->i_rdev, "tty_select"))
+	if (tty_paranoia_check(tty, filp->f_inode->i_rdev, "tty_poll"))
 		return 0;
 
-	if (tty->ldisc.select)
-		return (tty->ldisc.select)(tty, inode, filp, sel_type, wait);
+	if (tty->ldisc.poll)
+		return (tty->ldisc.poll)(tty, filp, wait);
 	return 0;
 }
 
@@ -1922,7 +1941,9 @@
 	if (tty_register_driver(&dev_console_driver))
 		panic("Couldn't register /dev/console driver\n");
 	
+#if !CONFIG_NO_KEYBOARD
 	kbd_init();
+#endif
 #ifdef CONFIG_ESPSERIAL  /* init ESP before rs, so rs doesn't see the port */
 	espserial_init();
 #endif
diff -u --recursive --new-file v2.1.22/linux/drivers/char/vc_screen.c linux/drivers/char/vc_screen.c
--- v2.1.22/linux/drivers/char/vc_screen.c	Wed Dec 18 15:58:47 1996
+++ linux/drivers/char/vc_screen.c	Sun Jan 26 12:07:17 1997
@@ -98,7 +98,7 @@
 	unsigned int currcons = MINOR(inode->i_rdev);
 	int viewed, attr, size, read;
 	char *buf0;
-	unsigned short *org;
+	unsigned short *org = NULL;
 
 	attr = (currcons & 128);
 	currcons = (currcons & 127);
@@ -159,7 +159,7 @@
 	unsigned int currcons = MINOR(inode->i_rdev);
 	int viewed, attr, size, written;
 	const char *buf0;
-	unsigned short *org;
+	unsigned short *org = NULL;
 
 	attr = (currcons & 128);
 	currcons = (currcons & 127);
@@ -243,7 +243,7 @@
 	vcs_read,	/* read */
 	vcs_write,	/* write */
 	NULL,		/* readdir */
-	NULL,		/* select */
+	NULL,		/* poll */
 	NULL,		/* ioctl */
 	NULL,		/* mmap */
 	vcs_open,	/* open */
diff -u --recursive --new-file v2.1.22/linux/drivers/char/vga.c linux/drivers/char/vga.c
--- v2.1.22/linux/drivers/char/vga.c	Sun Dec 22 16:37:31 1996
+++ linux/drivers/char/vga.c	Sun Jan 26 12:07:17 1997
@@ -248,6 +248,11 @@
 }
 
 void
+con_type_init_finish(void)
+{
+}
+
+void
 get_scrmem(int currcons)
 {
 	memcpyw((unsigned short *)vc_scrbuf[currcons],
diff -u --recursive --new-file v2.1.22/linux/drivers/char/vt.c linux/drivers/char/vt.c
--- v2.1.22/linux/drivers/char/vt.c	Tue Oct 29 19:58:10 1996
+++ linux/drivers/char/vt.c	Sun Jan 26 12:07:17 1997
@@ -1111,10 +1111,10 @@
 		    get_user(list, &ud->entries);
 		    i = verify_area(VERIFY_READ, (void *) list,
 				    ct*sizeof(struct unipair));
+		    if(!i)
+			    return con_set_unimap(ct, list);
 		}
-		if (i)
-		  return i;
-		return con_set_unimap(ct, list);
+		return i;
 	      }
 
 	case GIO_UNIMAP:
@@ -1130,10 +1130,10 @@
 		    if (ct)
 		      i = verify_area(VERIFY_WRITE, (void *) list,
 				      ct*sizeof(struct unipair));
+		    if(!i)
+			    return con_get_unimap(ct, &(ud->entry_ct), list);
 		}
-		if (i)
-		  return i;
-		return con_get_unimap(ct, &(ud->entry_ct), list);
+		return i;
 	      }
 	case VT_LOCKSWITCH:
 		if (!suser())
diff -u --recursive --new-file v2.1.22/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v2.1.22/linux/drivers/net/Makefile	Thu Jan  2 15:55:16 1997
+++ linux/drivers/net/Makefile	Sun Jan 26 12:07:17 1997
@@ -255,14 +255,6 @@
   endif
 endif
 
-ifeq ($(CONFIG_DE620),y)
-L_OBJS += de620.o
-else
-  ifeq ($(CONFIG_DE620),m)
-  M_OBJS += de620.o
-  endif
-endif
-
 ifeq ($(CONFIG_AT1500),y)
 L_OBJS += lance.o
 endif
@@ -280,6 +272,10 @@
 
 ifeq ($(CONFIG_SUNLANCE),y)
 L_OBJS += sunlance.o
+else
+  ifeq ($(CONFIG_SUNLANCE),m)
+  M_OBJS += sunlance.o
+  endif
 endif
 
 ifeq ($(CONFIG_HAPPYMEAL),y)
diff -u --recursive --new-file v2.1.22/linux/drivers/net/README.multicast linux/drivers/net/README.multicast
--- v2.1.22/linux/drivers/net/README.multicast	Thu Dec 12 19:37:04 1996
+++ linux/drivers/net/README.multicast	Sun Jan 26 12:07:17 1997
@@ -44,7 +44,7 @@
 seeq		NO		NO		NO		N/A
 sk_g16		NO		NO		YES		N/A
 smc-ultra	YES		YES		YES		Hardware
-sunlance	YES		YES		YES		Software(#)
+sunlance	YES		YES		YES		Hardware
 tulip		YES		YES		YES		Hardware
 wavelan		YES		PROMISC		YES		Hardware
 wd		YES		YES		YES		Hardware
diff -u --recursive --new-file v2.1.22/linux/drivers/net/Space.c linux/drivers/net/Space.c
--- v2.1.22/linux/drivers/net/Space.c	Thu Jan  2 15:55:16 1997
+++ linux/drivers/net/Space.c	Sun Jan 26 12:07:17 1997
@@ -277,24 +277,31 @@
 #ifndef ETH0_IRQ
 # define ETH0_IRQ 0
 #endif
+
+#ifndef __sparc__
+#define ETH_NOPROBE_ADDR 0xffe0
+#else
+#define ETH_NOPROBE_ADDR 0
+#endif
+
 /* "eth0" defaults to autoprobe (== 0), other use a base of 0xffe0 (== -0x20),
    which means "don't probe".  These entries exist to only to provide empty
    slots which may be enabled at boot-time. */
 
 static struct device eth7_dev = {
-    "eth7", 0,0,0,0,0xffe0 /* I/O base*/, 0,0,0,0, NEXT_DEV, ethif_probe };
+    "eth7", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, NEXT_DEV, ethif_probe };
 static struct device eth6_dev = {
-    "eth6", 0,0,0,0,0xffe0 /* I/O base*/, 0,0,0,0, &eth7_dev, ethif_probe };
+    "eth6", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, &eth7_dev, ethif_probe };
 static struct device eth5_dev = {
-    "eth5", 0,0,0,0,0xffe0 /* I/O base*/, 0,0,0,0, &eth6_dev, ethif_probe };
+    "eth5", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, &eth6_dev, ethif_probe };
 static struct device eth4_dev = {
-    "eth4", 0,0,0,0,0xffe0 /* I/O base*/, 0,0,0,0, &eth5_dev, ethif_probe };
+    "eth4", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, &eth5_dev, ethif_probe };
 static struct device eth3_dev = {
-    "eth3", 0,0,0,0,0xffe0 /* I/O base*/, 0,0,0,0, &eth4_dev, ethif_probe };
+    "eth3", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, &eth4_dev, ethif_probe };
 static struct device eth2_dev = {
-    "eth2", 0,0,0,0,0xffe0 /* I/O base*/, 0,0,0,0, &eth3_dev, ethif_probe };
+    "eth2", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, &eth3_dev, ethif_probe };
 static struct device eth1_dev = {
-    "eth1", 0,0,0,0,0xffe0 /* I/O base*/, 0,0,0,0, &eth2_dev, ethif_probe };
+    "eth1", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, &eth2_dev, ethif_probe };
 
 static struct device eth0_dev = {
     "eth0", 0, 0, 0, 0, ETH0_ADDR, ETH0_IRQ, 0, 0, 0, &eth1_dev, ethif_probe };
@@ -446,19 +453,20 @@
 
 #endif
 
-#ifdef CONFIG_AP1000
+#ifdef CONFIG_APFDDI
     extern int apfddi_init(struct device *dev);
     static struct device fddi_dev = {
 	"fddi", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NEXT_DEV, apfddi_init };
 #   undef       NEXT_DEV
 #   define      NEXT_DEV        (&fddi_dev)
+#endif
 
+#ifdef CONFIG_APBIF
     extern int bif_init(struct device *dev);
     static struct device bif_dev = {
         "bif", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NEXT_DEV, bif_init };
 #   undef       NEXT_DEV
 #   define      NEXT_DEV        (&bif_dev)
-
 #endif
 	
 extern int loopback_init(struct device *dev);
diff -u --recursive --new-file v2.1.22/linux/drivers/net/ppp.c linux/drivers/net/ppp.c
--- v2.1.22/linux/drivers/net/ppp.c	Thu Jan 23 21:06:48 1997
+++ linux/drivers/net/ppp.c	Sun Jan 26 12:07:17 1997
@@ -51,7 +51,7 @@
 #define PPP_MAX_DEV	256
 #endif
 
-/* $Id: ppp.c,v 1.5 1995/06/12 11:36:53 paulus Exp $
+/* $Id: ppp.c,v 1.27 1997/01/26 07:13:29 davem Exp $
  * Added dynamic allocation of channels to eliminate
  *   compiled-in limits on the number of channels.
  *
@@ -65,6 +65,7 @@
 #include <linux/sched.h>
 #include <linux/types.h>
 #include <linux/fcntl.h>
+#include <linux/poll.h>
 #include <linux/interrupt.h>
 #include <linux/ptrace.h>
 #include <linux/ioport.h>
@@ -195,8 +196,7 @@
 			  unsigned int);
 static int ppp_tty_ioctl (struct tty_struct *, struct file *, unsigned int,
                           unsigned long);
-static int ppp_tty_select (struct tty_struct *tty, struct inode *inode,
-		      struct file *filp, int sel_type, select_table * wait);
+static unsigned int ppp_tty_poll (struct tty_struct *tty, struct file *filp, poll_table * wait);
 static int ppp_tty_open (struct tty_struct *);
 static void ppp_tty_close (struct tty_struct *);
 static int ppp_tty_room (struct tty_struct *tty);
@@ -365,7 +365,7 @@
 	ppp_ldisc.read		= ppp_tty_read;
 	ppp_ldisc.write		= ppp_tty_write;
 	ppp_ldisc.ioctl		= ppp_tty_ioctl;
-	ppp_ldisc.select	= ppp_tty_select;
+	ppp_ldisc.poll		= ppp_tty_poll;
 	ppp_ldisc.receive_room	= ppp_tty_room;
 	ppp_ldisc.receive_buf	= ppp_tty_receive;
 	ppp_ldisc.write_wakeup	= ppp_tty_wakeup;
@@ -680,7 +680,7 @@
 
 	ppp_ccp_closed (ppp);
 
-        /* Ensure that the pppd process is not hanging on select() */
+        /* Ensure that the pppd process is not hanging on poll() */
         wake_up_interruptible (&ppp->read_wait);
         wake_up_interruptible (&ppp->write_wait);
 
@@ -2165,13 +2165,12 @@
 			nb = CCP_MAX_OPTION_LENGTH;
 
 		error = verify_area (VERIFY_READ, ptr, nb);
+		if(!error)
+			copy_from_user (ccp_option, ptr, nb);
 	}
-
 	if (error != 0)
 		return error;
 
-	copy_from_user (ccp_option, ptr, nb);
-
 	if (ccp_option[1] < 2)	/* preliminary check on the length byte */
 		return (-EINVAL);
 
@@ -2581,65 +2580,35 @@
 /*
  * TTY callback.
  *
- * Process the select() statement for the PPP device.
+ * Process the poll() statement for the PPP device.
  */
 
-static int
-ppp_tty_select (struct tty_struct *tty, struct inode *inode,
-		struct file *filp, int sel_type, select_table * wait)
+static unsigned int
+ppp_tty_poll (struct tty_struct *tty, struct file *filp, poll_table * wait)
 {
 	struct ppp *ppp = tty2ppp (tty);
-	int result = 1;
-/*
- * Verify the status of the PPP device.
- */
-	if (!ppp)
-		return -EBADF;
+	unsigned int mask = 0;
 
-	if (ppp->magic != PPP_MAGIC)
-		return -EBADF;
+	if(ppp && ppp->magic == PPP_MAGIC) {
+		CHECK_PPP (0);
 
-	CHECK_PPP (0);
-/*
- * Branch on the type of select mode. A read request must lock the user
- * buffer area.
- */
-	switch (sel_type) {
-	case SEL_IN:
-		if (set_bit (0, &ppp->ubuf->locked) == 0) {
-			/* Test for the presence of data in the queue */
-			if (ppp->ubuf->head != ppp->ubuf->tail) {
-				clear_bit (0, &ppp->ubuf->locked);
-				break;
-			}
-			clear_bit (0, &ppp->ubuf->locked);
-		}		/* fall through */
-/*
- * Exceptions or read errors.
- */
-	case SEL_EX:
-		/* Is this a pty link and the remote disconnected? */
-		if (tty->flags & (1 << TTY_OTHER_CLOSED))
-			break;
-
-		/* Is this a local link and the modem disconnected? */
-		if (tty_hung_up_p (filp))
-			break;
+		poll_wait(&ppp->read_wait, wait);
+		poll_wait(&ppp->write_wait, wait);
 
-		select_wait (&ppp->read_wait, wait);
-		result = 0;
-		break;
-/*
- * Write mode. A write is allowed if there is no current transmission.
- */
-	case SEL_OUT:
-		if (ppp->tbuf->locked != 0) {
-			select_wait (&ppp->write_wait, wait);
-			result = 0;
-		}
-		break;
+		/* Must lock the user buffer area while checking. */
+		if(set_bit(0, &ppp->ubuf->locked) == 0) {
+			if(ppp->ubuf->head != ppp->ubuf->tail)
+				mask |= POLLIN | POLLRDNORM;
+			clear_bit(0, &ppp->ubuf->locked);
+		}
+		if(tty->flags & (1 << TTY_OTHER_CLOSED))
+			mask |= POLLHUP;
+		if(tty_hung_up_p(filp))
+			mask |= POLLHUP;
+		if(ppp->tbuf->locked == 0)
+			mask |= POLLOUT | POLLWRNORM;
 	}
-	return result;
+	return mask;
 }
 
 /*************************************************************
diff -u --recursive --new-file v2.1.22/linux/drivers/net/slip.c linux/drivers/net/slip.c
--- v2.1.22/linux/drivers/net/slip.c	Thu Jan  2 15:55:19 1997
+++ linux/drivers/net/slip.c	Sun Jan 26 12:07:17 1997
@@ -111,7 +111,7 @@
 static inline struct slip *
 sl_alloc(void)
 {
-	slip_ctrl_t *slp;
+	slip_ctrl_t *slp = NULL;
 	int i;
 
 	if (slip_ctrls == NULL) return NULL;	/* Master array missing ! */
@@ -1123,7 +1123,7 @@
 	sl_ldisc.write  = NULL;
 	sl_ldisc.ioctl  = (int (*)(struct tty_struct *, struct file *,
 				   unsigned int, unsigned long)) slip_ioctl;
-	sl_ldisc.select = NULL;
+	sl_ldisc.poll   = NULL;
 	sl_ldisc.receive_buf = slip_receive_buf;
 	sl_ldisc.receive_room = slip_receive_room;
 	sl_ldisc.write_wakeup = slip_write_wakeup;
diff -u --recursive --new-file v2.1.22/linux/drivers/net/strip.c linux/drivers/net/strip.c
--- v2.1.22/linux/drivers/net/strip.c	Thu Jan 23 21:06:49 1997
+++ linux/drivers/net/strip.c	Sun Jan 26 12:07:17 1997
@@ -2752,7 +2752,7 @@
     strip_ldisc.read         = NULL;
     strip_ldisc.write        = NULL;
     strip_ldisc.ioctl        = strip_ioctl;
-    strip_ldisc.select       = NULL;
+    strip_ldisc.poll         = NULL;
     strip_ldisc.receive_buf  = strip_receive_buf;
     strip_ldisc.receive_room = strip_receive_room;
     strip_ldisc.write_wakeup = strip_write_some_more;
diff -u --recursive --new-file v2.1.22/linux/drivers/net/sunhme.h linux/drivers/net/sunhme.h
--- v2.1.22/linux/drivers/net/sunhme.h	Wed Dec 18 15:58:47 1996
+++ linux/drivers/net/sunhme.h	Sun Jan 26 12:07:17 1997
@@ -346,7 +346,7 @@
 #define LPA_10FULL              0x0040  /* Can do 10mbps full-duplex   */
 #define LPA_100HALF             0x0080  /* Can do 100mbps half-duplex  */
 #define LPA_100FULL             0x0100  /* Can do 100mbps full-duplex  */
-#define LPA_100BASE4            0x0100  /* Can do 100mbps 4k packets   */
+#define LPA_100BASE4            0x0200  /* Can do 100mbps 4k packets   */
 #define LPA_RESV                0x1c00  /* Unused...                   */
 #define LPA_RFAULT              0x2000  /* Link partner faulted        */
 #define LPA_LPACK               0x4000  /* Link partner acked us       */
diff -u --recursive --new-file v2.1.22/linux/drivers/net/sunlance.c linux/drivers/net/sunlance.c
--- v2.1.22/linux/drivers/net/sunlance.c	Tue Dec 31 21:41:07 1996
+++ linux/drivers/net/sunlance.c	Sun Jan 26 12:07:17 1997
@@ -1,60 +1,70 @@
-/* lance.c: Linux/Sparc/Lance driver */
-/*
-	 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 de Raadt (deraadt@openbsd.org)
-	 NCR92C990 Lan Controller manual
-
-1.4:
-	 Added support to run with a ledma on the Sun4m
-1.5:
-         Added multiple card detection.
-
-	 4/17/96: Burst sizes and tpe selection on sun4m by Eddie C. Dost
-	          (ecd@skynet.be)
-
-	 5/15/96: auto carrier detection on sun4m by Eddie C. Dost
-	          (ecd@skynet.be)
-
-         5/17/96: lebuffer on scsi/ether cards now work David S. Miller
-		  (davem@caip.rutgers.edu)
-
-	 5/29/96: override option 'tpe-link-test?', if it is 'false', as
-		  this disables auto carrier detection on sun4m. Eddie C. Dost
-	          (ecd@skynet.be)
-1.7:
-	 6/26/96: Bug fix for multiple ledmas, miguel.
-1.8:
-         Stole multicast code from depca.c, fixed lance_tx.
-1.9:
-         Fixed the multicast code (Pedro Roque)
-
-	 8/28/96: Send fake packet in lance_open() if auto_select is true,
-		  so we can detect the carrier loss condition in time.
-		  Eddie C. Dost (ecd@skynet.be)
-
-	 9/15/96: Align rx_buf so that eth_copy_and_sum() won't cause an
-		  MNA trap during chksum_partial_copy(). (ecd@skynet.be)
-
-	11/17/96: Handle LE_C0_MERR in lance_interrupt(). (ecd@skynet.be)
-
-	12/22/96: Don't loop forever in lance_rx() on incomplete packets.
-		  This was the sun4c killer. Shit, stupid bug.
-		  (ecd@skynet.be)
-*/
+/* $Id: sunlance.c,v 1.52 1997/01/25 23:29:56 ecd Exp $
+ * lance.c: Linux/Sparc/Lance driver
+ *
+ *	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 de Raadt (deraadt@openbsd.org)
+ *	NCR92C990 Lan Controller manual
+ *
+ * 1.4:
+ *	Added support to run with a ledma on the Sun4m
+ *
+ * 1.5:
+ *	Added multiple card detection.
+ *
+ *	 4/17/96: Burst sizes and tpe selection on sun4m by Eddie C. Dost
+ *		  (ecd@skynet.be)
+ *
+ *	 5/15/96: auto carrier detection on sun4m by Eddie C. Dost
+ *		  (ecd@skynet.be)
+ *
+ *	 5/17/96: lebuffer on scsi/ether cards now work David S. Miller
+ *		  (davem@caip.rutgers.edu)
+ *
+ *	 5/29/96: override option 'tpe-link-test?', if it is 'false', as
+ *		  this disables auto carrier detection on sun4m. Eddie C. Dost
+ *		  (ecd@skynet.be)
+ *
+ * 1.7:
+ *	 6/26/96: Bug fix for multiple ledmas, miguel.
+ *
+ * 1.8:
+ *		  Stole multicast code from depca.c, fixed lance_tx.
+ *
+ * 1.9:
+ *	 8/21/96: Fixed the multicast code (Pedro Roque)
+ *
+ *	 8/28/96: Send fake packet in lance_open() if auto_select is true,
+ *		  so we can detect the carrier loss condition in time.
+ *		  Eddie C. Dost (ecd@skynet.be)
+ *
+ *	 9/15/96: Align rx_buf so that eth_copy_and_sum() won't cause an
+ *		  MNA trap during chksum_partial_copy(). (ecd@skynet.be)
+ *
+ *	11/17/96: Handle LE_C0_MERR in lance_interrupt(). (ecd@skynet.be)
+ *
+ *	12/22/96: Don't loop forever in lance_rx() on incomplete packets.
+ *		  This was the sun4c killer. Shit, stupid bug.
+ *		  (ecd@skynet.be)
+ *
+ * 1.10:
+ *	 1/26/97: Modularize driver. (ecd@skynet.be)
+ */
 
 #undef DEBUG_DRIVER
 
 static char *version =
-	"sunlance.c:v1.9 21/Aug/96 Miguel de Icaza (miguel@nuclecu.unam.mx)\n";
+	"sunlance.c:v1.10 26/Jan/97 Miguel de Icaza (miguel@nuclecu.unam.mx)\n";
 
 static char *lancestr = "LANCE";
 static char *lancedma = "LANCE DMA";
 
+#include <linux/module.h>
+
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/types.h>
@@ -211,12 +221,18 @@
 	int rx_old, tx_old;
     
 	struct enet_statistics stats;
-	struct Linux_SBus_DMA *ledma; /* if set this points to ledma and arch=4m */
+	struct Linux_SBus_DMA *ledma; /* If set this points to ledma    */
+				      /* and arch = sun4m		*/
+
+	int tpe;		      /* cable-selection is TPE		*/
+	int auto_select;	      /* cable-selection by carrier	*/
+	int burst_sizes;	      /* ledma SBus burst sizes		*/
 
-	int tpe;		      /* cable-selection is TPE */
-	int auto_select;	      /* cable-selection by carrier */
-	int burst_sizes;	      /* ledma SBus burst sizes */
-	unsigned short busmaster_regval, pio_buffer;
+	unsigned short busmaster_regval;
+	unsigned short pio_buffer;
+
+	struct device		 *dev;		  /* Backpointer	*/
+	struct lance_private	 *next_module;
 };
 
 #define TX_BUFFS_AVAIL ((lp->tx_old<=lp->tx_new)?\
@@ -241,6 +257,10 @@
 
 #define LANCE_ADDR(x) ((int)(x) & ~0xff000000)
 
+#ifdef MODULE
+static struct lance_private *root_lance_dev = NULL;
+#endif
+
 /* Load the CSR registers */
 static void load_csrs (struct lance_private *lp)
 {
@@ -686,6 +706,9 @@
 		flush = ll->rdp;
 	}
 
+	if (!status)
+		MOD_INC_USE_COUNT;
+
 	return status;
 }
 
@@ -702,7 +725,7 @@
 	ll->rdp = LE_C0_STOP;
 
 	free_irq (dev->irq, (void *) dev);
-    
+	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
@@ -916,11 +939,13 @@
 	volatile struct lance_regs *ll;
 
 	if (dev == NULL) {
-		dev = init_etherdev (0, sizeof (struct lance_private));
+		dev = init_etherdev (0, sizeof (struct lance_private) + 8);
 	} else {
-		dev->priv = kmalloc (sizeof (struct lance_private), GFP_KERNEL);
+		dev->priv = kmalloc (sizeof (struct lance_private) + 8,
+				     GFP_KERNEL);
 		if (dev->priv == NULL)
 			return -ENOMEM;
+		memset(dev->priv, 0, sizeof (struct lance_private) + 8);
 	}
 	if (sparc_lance_debug && version_printed++ == 0)
 		printk (version);
@@ -948,7 +973,6 @@
 	/* 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));
 
 	if (lebuffer){
 		prom_apply_sbus_ranges (lebuffer->my_bus,
@@ -1045,6 +1069,7 @@
 		return ENODEV;
 	}
 
+	lp->dev = dev;
 	dev->open = &lance_open;
 	dev->stop = &lance_close;
 	dev->hard_start_xmit = &lance_start_xmit;
@@ -1055,6 +1080,11 @@
 	dev->dma = 0;
 	ether_setup (dev);
 
+#ifdef MODULE
+	dev->ifindex = dev_new_index();
+	lp->next_module = root_lance_dev;
+	root_lance_dev = lp;
+#endif
 	return 0;
 }
 
@@ -1064,7 +1094,7 @@
 {
 	struct Linux_SBus_DMA *p;
 
-	for (p = dma_chain; p; p = p->next)
+	for_each_dvma(p)
 		if (p->SBus_dev == dev)
 			return p;
 	return 0;
@@ -1113,9 +1143,27 @@
 	return 0;
 }
 
-/*
- * Local variables:
- *  version-control: t
- *  kept-new-versions: 5
- * End:
- */
+#ifdef MODULE
+
+int
+init_module(void)
+{
+	root_lance_dev = NULL;
+	return sparc_lance_probe(NULL);
+}
+
+void
+cleanup_module(void)
+{
+	struct lance_private *lp;
+
+	while (root_lance_dev) {
+		lp = root_lance_dev->next_module;
+
+		unregister_netdev(root_lance_dev->dev);
+		kfree(root_lance_dev->dev);
+		root_lance_dev = lp;
+	}
+}
+
+#endif /* MODULE */
diff -u --recursive --new-file v2.1.22/linux/drivers/pci/pci.c linux/drivers/pci/pci.c
--- v2.1.22/linux/drivers/pci/pci.c	Thu Jan 23 21:06:49 1997
+++ linux/drivers/pci/pci.c	Fri Jan 24 20:57:22 1997
@@ -93,6 +93,7 @@
 	DEVICE( MATROX,		MATROX_MGA_IMP,	"MGA Impression"),
 	DEVICE( CT,		CT_65545,	"65545"),
 	DEVICE( CT,		CT_65548,	"65548"),
+	DEVICE(	CT,		CT_65550,	"65550"),
 	DEVICE( MIRO,		MIRO_36050,	"ZR36050"),
 	DEVICE( FD,		FD_36C70,	"TMC-18C30"),
 	DEVICE( SI,		SI_6201,	"6201"),
diff -u --recursive --new-file v2.1.22/linux/drivers/sbus/audio/Config.in linux/drivers/sbus/audio/Config.in
--- v2.1.22/linux/drivers/sbus/audio/Config.in	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sbus/audio/Config.in	Sun Jan 26 12:07:17 1997
@@ -0,0 +1,11 @@
+#
+# Configuration script for sparcaudio subsystem
+#
+
+if [ "x$CONFIG_EXPERIMENTAL" = "xy" ]; then
+
+  comment 'Linux/SPARC audio subsystem'
+
+  tristate 'Audio support' CONFIG_SPARCAUDIO
+  dep_tristate '  AMD7930 Lowlevel Driver' CONFIG_SPARCAUDIO_AMD7930 $CONFIG_SPARCAUDIO
+fi
diff -u --recursive --new-file v2.1.22/linux/drivers/sbus/audio/Makefile linux/drivers/sbus/audio/Makefile
--- v2.1.22/linux/drivers/sbus/audio/Makefile	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sbus/audio/Makefile	Sun Jan 26 12:07:17 1997
@@ -0,0 +1,36 @@
+#
+# Makefile for the linux kernel.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+#
+# sbus audio drivers
+#
+
+O_TARGET := sparcaudio.o
+O_OBJS   :=
+M_OBJS   :=
+
+ifeq ($(CONFIG_SPARCAUDIO_AMD7930),y)
+M=y
+O_OBJS += amd7930.o
+else
+  ifeq ($(CONFIG_SPARCAUDIO_AMD7930),m)
+  MM=y
+  M_OBJS += amd7930.o
+  endif
+endif
+
+ifdef M
+O_OBJS += audio.o
+else
+  ifdef MM
+  M_OBJS += audio.o
+  endif
+endif
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.22/linux/drivers/sbus/audio/amd7930.c linux/drivers/sbus/audio/amd7930.c
--- v2.1.22/linux/drivers/sbus/audio/amd7930.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sbus/audio/amd7930.c	Sun Jan 26 12:07:17 1997
@@ -0,0 +1,372 @@
+/*
+ * drivers/sbus/audio/amd7930.c
+ *
+ * Copyright (C) 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu)
+ *
+ * This is the lowlevel driver for the AMD7930 audio chip found on all
+ * sun4c machines and some sun4m machines.
+ *
+ * XXX Add note about the fun of getting the docs.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include "audio.h"
+#include "amd7930.h"
+
+/*
+ * Chip interface
+ */
+struct mapreg {
+        u_short mr_x[8];
+        u_short mr_r[8];
+        u_short mr_gx;
+        u_short mr_gr;
+        u_short mr_ger;
+        u_short mr_stgr;
+        u_short mr_ftgr;
+        u_short mr_atgr;
+        u_char  mr_mmr1;
+        u_char  mr_mmr2;
+} map;
+
+
+/* Write 16 bits of data from variable v to the data port of the audio chip */
+#define	WAMD16(amd, v) ((amd)->dr = (v), (amd)->dr = (v) >> 8)
+
+/* The following tables stolen from former (4.4Lite's) sys/sparc/bsd_audio.c */
+
+/*
+ * gx, gr & stg gains.  this table must contain 256 elements with
+ * the 0th being "infinity" (the magic value 9008).  The remaining
+ * elements match sun's gain curve (but with higher resolution):
+ * -18 to 0dB in .16dB steps then 0 to 12dB in .08dB steps.
+ */
+static const u_short gx_coeff[256] = {
+	0x9008, 0x8b7c, 0x8b51, 0x8b45, 0x8b42, 0x8b3b, 0x8b36, 0x8b33,
+	0x8b32, 0x8b2a, 0x8b2b, 0x8b2c, 0x8b25, 0x8b23, 0x8b22, 0x8b22,
+	0x9122, 0x8b1a, 0x8aa3, 0x8aa3, 0x8b1c, 0x8aa6, 0x912d, 0x912b,
+	0x8aab, 0x8b12, 0x8aaa, 0x8ab2, 0x9132, 0x8ab4, 0x913c, 0x8abb,
+	0x9142, 0x9144, 0x9151, 0x8ad5, 0x8aeb, 0x8a79, 0x8a5a, 0x8a4a,
+	0x8b03, 0x91c2, 0x91bb, 0x8a3f, 0x8a33, 0x91b2, 0x9212, 0x9213,
+	0x8a2c, 0x921d, 0x8a23, 0x921a, 0x9222, 0x9223, 0x922d, 0x9231,
+	0x9234, 0x9242, 0x925b, 0x92dd, 0x92c1, 0x92b3, 0x92ab, 0x92a4,
+	0x92a2, 0x932b, 0x9341, 0x93d3, 0x93b2, 0x93a2, 0x943c, 0x94b2,
+	0x953a, 0x9653, 0x9782, 0x9e21, 0x9d23, 0x9cd2, 0x9c23, 0x9baa,
+	0x9bde, 0x9b33, 0x9b22, 0x9b1d, 0x9ab2, 0xa142, 0xa1e5, 0x9a3b,
+	0xa213, 0xa1a2, 0xa231, 0xa2eb, 0xa313, 0xa334, 0xa421, 0xa54b,
+	0xada4, 0xac23, 0xab3b, 0xaaab, 0xaa5c, 0xb1a3, 0xb2ca, 0xb3bd,
+	0xbe24, 0xbb2b, 0xba33, 0xc32b, 0xcb5a, 0xd2a2, 0xe31d, 0x0808,
+	0x72ba, 0x62c2, 0x5c32, 0x52db, 0x513e, 0x4cce, 0x43b2, 0x4243,
+	0x41b4, 0x3b12, 0x3bc3, 0x3df2, 0x34bd, 0x3334, 0x32c2, 0x3224,
+	0x31aa, 0x2a7b, 0x2aaa, 0x2b23, 0x2bba, 0x2c42, 0x2e23, 0x25bb,
+	0x242b, 0x240f, 0x231a, 0x22bb, 0x2241, 0x2223, 0x221f, 0x1a33,
+	0x1a4a, 0x1acd, 0x2132, 0x1b1b, 0x1b2c, 0x1b62, 0x1c12, 0x1c32,
+	0x1d1b, 0x1e71, 0x16b1, 0x1522, 0x1434, 0x1412, 0x1352, 0x1323,
+	0x1315, 0x12bc, 0x127a, 0x1235, 0x1226, 0x11a2, 0x1216, 0x0a2a,
+	0x11bc, 0x11d1, 0x1163, 0x0ac2, 0x0ab2, 0x0aab, 0x0b1b, 0x0b23,
+	0x0b33, 0x0c0f, 0x0bb3, 0x0c1b, 0x0c3e, 0x0cb1, 0x0d4c, 0x0ec1,
+	0x079a, 0x0614, 0x0521, 0x047c, 0x0422, 0x03b1, 0x03e3, 0x0333,
+	0x0322, 0x031c, 0x02aa, 0x02ba, 0x02f2, 0x0242, 0x0232, 0x0227,
+	0x0222, 0x021b, 0x01ad, 0x0212, 0x01b2, 0x01bb, 0x01cb, 0x01f6,
+	0x0152, 0x013a, 0x0133, 0x0131, 0x012c, 0x0123, 0x0122, 0x00a2,
+	0x011b, 0x011e, 0x0114, 0x00b1, 0x00aa, 0x00b3, 0x00bd, 0x00ba,
+	0x00c5, 0x00d3, 0x00f3, 0x0062, 0x0051, 0x0042, 0x003b, 0x0033,
+	0x0032, 0x002a, 0x002c, 0x0025, 0x0023, 0x0022, 0x001a, 0x0021,
+	0x001b, 0x001b, 0x001d, 0x0015, 0x0013, 0x0013, 0x0012, 0x0012,
+	0x000a, 0x000a, 0x0011, 0x0011, 0x000b, 0x000b, 0x000c, 0x000e,
+};
+
+/*
+ * second stage play gain.
+ */
+static const u_short ger_coeff[] = {
+	0x431f, /* 5. dB */
+	0x331f, /* 5.5 dB */
+	0x40dd, /* 6. dB */
+	0x11dd, /* 6.5 dB */
+	0x440f, /* 7. dB */
+	0x411f, /* 7.5 dB */
+	0x311f, /* 8. dB */
+	0x5520, /* 8.5 dB */
+	0x10dd, /* 9. dB */
+	0x4211, /* 9.5 dB */
+	0x410f, /* 10. dB */
+	0x111f, /* 10.5 dB */
+	0x600b, /* 11. dB */
+	0x00dd, /* 11.5 dB */
+	0x4210, /* 12. dB */
+	0x110f, /* 13. dB */
+	0x7200, /* 14. dB */
+	0x2110, /* 15. dB */
+	0x2200, /* 15.9 dB */
+	0x000b, /* 16.9 dB */
+	0x000f  /* 18. dB */
+#define NGER (sizeof(ger_coeff) / sizeof(ger_coeff[0]))
+};
+
+#if 0
+int
+amd7930_commit_settings(addr)
+	void *addr;
+{
+	register struct amd7930_softc *sc = addr;
+	register struct mapreg *map;
+	register volatile struct amd7930 *amd;
+	register int s, level;
+
+	DPRINTF(("sa_commit.\n"));
+
+	map = &sc->sc_map;
+	amd = sc->sc_au.au_amd;
+
+	map->mr_gx = gx_coeff[sc->sc_rlevel];
+	map->mr_stgr = gx_coeff[sc->sc_mlevel];
+
+	level = (sc->sc_plevel * (256 + NGER)) >> 8;
+	if (level >= 256) {
+		map->mr_ger = ger_coeff[level - 256];
+		map->mr_gr = gx_coeff[255];
+	} else {
+		map->mr_ger = ger_coeff[0];
+		map->mr_gr = gx_coeff[level];
+	}
+
+	if (sc->sc_out_port == SUNAUDIO_SPEAKER)
+		map->mr_mmr2 |= AMD_MMR2_LS;
+	else
+		map->mr_mmr2 &= ~AMD_MMR2_LS;
+
+	s = splaudio();
+
+	amd->cr = AMDR_MAP_MMR1;
+	amd->dr = map->mr_mmr1;
+	amd->cr = AMDR_MAP_GX;
+	WAMD16(amd, map->mr_gx);
+	amd->cr = AMDR_MAP_STG;
+	WAMD16(amd, map->mr_stgr);
+	amd->cr = AMDR_MAP_GR;
+	WAMD16(amd, map->mr_gr);
+	amd->cr = AMDR_MAP_GER;
+	WAMD16(amd, map->mr_ger);
+	amd->cr = AMDR_MAP_MMR2;
+	amd->dr = map->mr_mmr2;
+
+	splx(s);
+	return(0);
+}
+#endif
+
+static int amd7930_node, amd7930_irq, amd7930_regs_size, amd7930_ints_on = 0;
+static struct amd7930 *amd7930_regs = NULL;
+static __u8 * ptr;
+static size_t count;
+
+/* Enable amd7930 interrupts atomically. */
+static __inline__ void amd7930_enable_ints(void)
+{
+	register unsigned long flags;
+
+	if (amd7930_ints_on)
+		return;
+
+	save_and_cli(flags);
+	amd7930_regs->cr = AMR_INIT;
+	amd7930_regs->dr = AM_INIT_ACTIVE;
+	restore_flags(flags);
+
+	amd7930_ints_on = 1;
+}
+
+/* Disable amd7930 interrupts atomically. */
+static __inline__ void amd7930_disable_ints(void)
+{
+	register unsigned long flags;
+
+	if (!amd7930_ints_on)
+		return;
+
+	save_and_cli(flags);
+	amd7930_regs->cr = AMR_INIT;
+	amd7930_regs->dr = AM_INIT_ACTIVE | AM_INIT_DISABLE_INTS;
+	restore_flags(flags);
+
+	amd7930_ints_on = 0;
+}  
+
+
+/* Audio interrupt handler. */
+static void amd7930_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	__u8 dummy;
+
+	/* Clear the interrupt. */
+	dummy = amd7930_regs->ir;
+
+	/* Send the next byte of outgoing data. */
+	if (ptr && count > 0) {
+		/* Send the next byte and advance the head pointer. */
+		amd7930_regs->bbtb = *ptr;
+		ptr++;
+		count--;
+
+		/* Empty buffer? Notify the midlevel driver. */
+		if (count == 0)
+			sparcaudio_output_done();
+	}
+}
+
+static int amd7930_open(struct inode * inode, struct file * file, struct sparcaudio_driver *drv)
+{
+	int level;
+
+	/* Set the default audio parameters. */
+	map.mr_gx = gx_coeff[128];
+	map.mr_stgr = gx_coeff[0];
+
+	level = (128 * (256 + NGER)) >> 8;
+	if (level >= 256) {
+		map.mr_ger = ger_coeff[level-256];
+		map.mr_gr = gx_coeff[255];
+	} else {
+		map.mr_ger = ger_coeff[0];
+		map.mr_gr = gx_coeff[level];
+	}
+
+	map.mr_mmr2 |= AM_MAP_MMR2_LS;
+
+	cli();
+
+	amd7930_regs->cr = AMR_MAP_MMR1;
+	amd7930_regs->dr = map.mr_mmr1;
+	amd7930_regs->cr = AMR_MAP_GX;
+	WAMD16(amd7930_regs,map.mr_gx);
+	amd7930_regs->cr = AMR_MAP_STG;
+	WAMD16(amd7930_regs,map.mr_stgr);
+	amd7930_regs->cr = AMR_MAP_GR;
+	WAMD16(amd7930_regs,map.mr_gr);
+	amd7930_regs->cr = AMR_MAP_GER;
+	WAMD16(amd7930_regs,map.mr_ger);
+	amd7930_regs->cr = AMR_MAP_MMR2;
+	amd7930_regs->dr = map.mr_mmr2;
+
+	sti();
+
+	MOD_INC_USE_COUNT;
+
+	return 0;
+}
+
+static void amd7930_release(struct inode * inode, struct file * file, struct sparcaudio_driver *drv)
+{
+	amd7930_disable_ints();
+	MOD_DEC_USE_COUNT;
+}
+
+static void amd7930_start_output(struct sparcaudio_driver *drv, __u8 * buffer, size_t the_count)
+{
+	count = the_count;
+	ptr = buffer;
+	amd7930_enable_ints();
+}
+
+static void amd7930_stop_output(struct sparcaudio_driver *drv)
+{
+	amd7930_disable_ints();
+	ptr = NULL;
+	count = 0;
+}
+
+
+static struct sparcaudio_operations amd7930_ops = {
+	amd7930_open,
+	amd7930_release,
+	NULL,			/* amd7930_ioctl */
+	amd7930_start_output,
+	amd7930_stop_output,
+};
+
+static struct sparcaudio_driver amd7930_drv = {
+	"amd7930",
+	&amd7930_ops,
+};
+
+/* Probe for the amd7930 chip and then attach the driver. */
+#ifdef MODULE
+int init_module(void)
+#else
+__initfunc(int amd7930_init(void))
+#endif
+{
+	struct linux_prom_registers regs[1];
+	struct linux_prom_irqs irq;
+	int err;
+
+#ifdef MODULE
+	register_symtab(0);
+#endif
+
+	/* Find the PROM "audio" node. */
+	amd7930_node = prom_getchild(prom_root_node);
+	amd7930_node = prom_searchsiblings(amd7930_node, "audio");
+	if (!amd7930_node)
+		return -EIO;
+
+	/* Map the registers into memory. */
+	prom_getproperty(amd7930_node, "reg", (char *)regs, sizeof(regs));
+	amd7930_regs_size = regs[0].reg_size;
+	amd7930_regs = sparc_alloc_io(regs[0].phys_addr, 0, regs[0].reg_size,
+				      "amd7930", regs[0].which_io, 0);
+	if (!amd7930_regs) {
+		printk(KERN_ERR "amd7930: could not allocate registers\n");
+		return -EIO;
+	}
+
+	/* Disable amd7930 interrupt generation. */
+	amd7930_disable_ints();
+
+	/* Initialize the MUX unit to connect the MAP to the CPU. */
+	amd7930_regs->cr = AMR_MUX_1_4;
+	amd7930_regs->dr = (AM_MUX_CHANNEL_Bb << 4) | AM_MUX_CHANNEL_Ba;
+	amd7930_regs->dr = 0;
+	amd7930_regs->dr = 0;
+	amd7930_regs->dr = AM_MUX_MCR4_ENABLE_INTS;
+
+	/* Attach the interrupt handler to the audio interrupt. */
+	prom_getproperty(amd7930_node, "intr", (char *)&irq, sizeof(irq));
+	amd7930_irq = irq.pri;
+	request_irq(amd7930_irq, amd7930_interrupt, SA_INTERRUPT, "amd7930", NULL);
+	enable_irq(amd7930_irq);
+
+	memset(&map, 0, sizeof(map));
+	map.mr_mmr1 = AM_MAP_MMR1_GX | AM_MAP_MMR1_GER | AM_MAP_MMR1_GR | AM_MAP_MMR1_STG;
+
+	/* Register ourselves with the midlevel audio driver. */
+	err = register_sparcaudio_driver(&amd7930_drv);
+	if (err < 0) {
+		/* XXX We should do something. Complain for now. */
+		printk(KERN_ERR "amd7930: really screwed now\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+	amd7930_disable_ints();
+	disable_irq(amd7930_irq);
+	free_irq(amd7930_irq, NULL);
+	sparc_free_io(amd7930_regs, amd7930_regs_size);
+}
+#endif
diff -u --recursive --new-file v2.1.22/linux/drivers/sbus/audio/audio.c linux/drivers/sbus/audio/audio.c
--- v2.1.22/linux/drivers/sbus/audio/audio.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sbus/audio/audio.c	Sun Jan 26 12:07:17 1997
@@ -0,0 +1,271 @@
+/*
+ * drivers/sbus/audio/audio.c
+ *
+ * Copyright (C) 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu)
+ *
+ * This is the audio midlayer that sits between the VFS character
+ * devices and the low-level audio hardware device drivers.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/tqueue.h>
+#include <linux/major.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
+
+#include "audio.h"
+
+
+/*
+ *	Low-level driver interface.
+ */
+
+/* We only support one low-level audio driver. */
+static struct sparcaudio_driver *driver;
+
+int register_sparcaudio_driver(struct sparcaudio_driver *drv)
+{
+	/* If a driver is already present, don't allow it to register. */
+	if (driver)
+		return -EIO;
+
+	MOD_INC_USE_COUNT;
+
+	driver = drv;
+	return 0;
+}
+
+int unregister_sparcaudio_driver(struct sparcaudio_driver *drv)
+{
+	/* Make sure that the current driver is unregistering. */
+	if (driver != drv)
+		return -EIO;
+
+	MOD_DEC_USE_COUNT;
+
+	driver = NULL;
+	return 0;
+}
+
+static void sparcaudio_output_done_task(void * unused)
+{
+	unsigned long flags;
+
+	save_and_cli(flags);
+	printk(KERN_DEBUG "sparcaudio: next buffer\n");
+	driver->ops->start_output(driver, driver->output_buffers[driver->output_front],
+				  driver->output_sizes[driver->output_front]);
+	driver->output_active = 1;
+	restore_flags(flags);
+}
+
+static struct tq_struct sparcaudio_output_tqueue = {
+	0, 0, sparcaudio_output_done_task, 0 };
+
+void sparcaudio_output_done(void)
+{
+	/* Point the queue after the "done" buffer. */
+	driver->output_front++;
+	driver->output_count--;
+
+	/* If the output queue is empty, shutdown the driver. */
+	if (driver->output_count == 0) {
+		/* Stop the lowlevel driver from outputing. */
+		printk(KERN_DEBUG "sparcaudio: lowlevel driver shutdown\n");
+		driver->ops->stop_output(driver);
+		driver->output_active = 0;
+		return;
+	}
+
+	/* Otherwise, queue a task to give the driver the next buffer. */
+	queue_task(&sparcaudio_output_tqueue, &tq_immediate);
+
+	/* Wake up any tasks that are waiting. */
+	wake_up_interruptible(&driver->output_write_wait);
+}
+
+
+/*
+ *	VFS layer interface
+ */
+
+static int sparcaudio_lseek(struct inode * inode, struct file * file,
+			    off_t offset, int origin)
+{
+	return -ESPIPE;
+}
+
+static int sparcaudio_read(struct inode * inode, struct file * file,
+			   char *buf, int count)
+{
+	return -EINVAL;
+}
+
+static int sparcaudio_write(struct inode * inode, struct file * file,
+			    const char *buf, int count)
+{
+	unsigned long flags;
+	int bytes_written = 0, bytes_to_copy, err;
+
+	/* Ensure that we have something to write. */
+	if (count < 1)
+		return 0;
+
+	/* Loop until all output is written to device. */
+	while (count > 0) {
+		/* Check to make sure that an output buffer is available. */
+		if (driver->output_count == driver->num_output_buffers) {
+			printk(KERN_DEBUG "sparcaudio: waiting for free buffer\n");
+			interruptible_sleep_on(&driver->output_write_wait);
+			if (current->signal & ~current->blocked)
+				return bytes_written > 0 ? bytes_written : -EINTR;
+		}
+
+		/* Determine how much we can copy in this run. */
+		bytes_to_copy = count;
+		if (bytes_to_copy > PAGE_SIZE)
+			bytes_to_copy = PAGE_SIZE;
+
+		err = verify_area(VERIFY_READ, buf, bytes_to_copy);
+		if (err)
+			return err;
+
+		memcpy_fromfs(driver->output_buffers[driver->output_rear], buf, bytes_to_copy);
+
+		/* Update the queue pointers. */
+		bytes_written += bytes_to_copy;
+		driver->output_sizes[driver->output_rear] = bytes_to_copy;
+		driver->output_rear = (driver->output_rear + 1) % driver->num_output_buffers;
+		driver->output_count++;
+
+		/* If the low-level driver is not active, activate it. */
+		save_and_cli(flags);
+		if (! driver->output_active) {
+			printk(KERN_DEBUG "sparcaudio: activating lowlevel driver\n");
+			driver->ops->start_output(driver, driver->output_buffers[driver->output_front],
+						  driver->output_sizes[driver->output_front]);
+			driver->output_active = 1;
+		}
+		restore_flags(flags);
+	}
+
+	/* Return the number of bytes written to the caller. */
+	return bytes_written;
+}
+
+static int sparcaudio_ioctl(struct inode * inode, struct file * file,
+			    unsigned int cmd, unsigned long arg)
+{
+	switch (cmd) {
+	default:
+		if (driver->ops->ioctl)
+			return driver->ops->ioctl(inode,file,cmd,arg,driver);
+		else
+			return -EINVAL;
+	}
+	return 0;
+}
+
+static int sparcaudio_open(struct inode * inode, struct file * file)
+{
+	unsigned int minor = MINOR(inode->i_rdev);
+	int i;
+
+	/* We only support minor #4 (/dev/audio right now. */
+	if (minor != 4)
+		return -ENXIO;
+
+	/* Make sure that the driver is not busy. */
+	if (driver->busy)
+		return -EBUSY;
+
+	/* Setup the queue of output buffers. */
+	driver->num_output_buffers = 32;
+	driver->output_front = 0;
+	driver->output_rear = 0;
+	driver->output_count = 0;
+	driver->output_active = 0;
+	driver->output_buffers = kmalloc(32 * sizeof(__u8 *), GFP_KERNEL);
+	driver->output_sizes = kmalloc(32 * sizeof(__u8 *), GFP_KERNEL);
+	if (!driver->output_buffers || !driver->output_sizes)
+		return -ENOMEM;
+
+	/* Allocate space for the output buffers. */
+	for (i = 0; i < driver->num_output_buffers; i++) {
+		driver->output_buffers[i] = (void *) __get_free_page(GFP_KERNEL);
+		if (!driver->output_buffers[i])
+			return -ENOMEM;
+	}
+
+	/* Allow the low-level driver to initialize itself. */
+	if (driver->ops->open)
+		driver->ops->open(inode,file,driver);
+
+
+	/* Mark the driver as busy. */
+	driver->busy = 1;
+
+	MOD_INC_USE_COUNT;
+
+	/* Success return. */
+	return 0;
+}
+
+static void sparcaudio_release(struct inode * inode, struct file * file)
+{
+	int i;
+
+	if (driver->ops->release)
+		driver->ops->release(inode,file,driver);
+
+	MOD_DEC_USE_COUNT;
+
+	driver->busy = 0;
+
+	for (i = 0; i < driver->num_output_buffers; i++)
+		kfree(driver->output_buffers[i]);
+	kfree(driver->output_buffers);
+	kfree(driver->output_sizes);
+}
+
+static struct file_operations sparcaudio_fops = {
+	sparcaudio_lseek,
+	sparcaudio_read,
+	sparcaudio_write,
+	NULL,			/* sparcaudio_readdir */
+	NULL,			/* sparcaudio_poll */
+	sparcaudio_ioctl,
+	NULL,			/* sparcaudio_mmap */
+	sparcaudio_open,
+	sparcaudio_release
+};
+
+
+#ifdef MODULE
+int init_module(void)
+#else
+__initfunc(int sparcaudio_init(void))
+#endif
+{
+	/* Register our character device driver with the VFS. */
+	if (register_chrdev(SOUND_MAJOR, "sparcaudio", &sparcaudio_fops))
+		return -EIO;
+
+#ifdef CONFIG_SPARCAUDIO_AMD7930
+	amd7930_init();
+#endif
+
+	return 0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+}
+#endif
diff -u --recursive --new-file v2.1.22/linux/drivers/sbus/audio/audio.h linux/drivers/sbus/audio/audio.h
--- v2.1.22/linux/drivers/sbus/audio/audio.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sbus/audio/audio.h	Sun Jan 26 12:07:17 1997
@@ -0,0 +1,75 @@
+/*
+ * drivers/sbus/audio/audio.h
+ *
+ * Sparc Audio Midlayer
+ * Copyright (C) 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu)
+ */
+
+#ifndef _AUDIO_H_
+#define _AUDIO_H_
+
+#ifdef __KERNEL__
+
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/wait.h>
+
+
+#define NR_SPARCAUDIO_DRIVERS 1
+
+
+struct sparcaudio_driver
+{
+	const char * name;
+	struct sparcaudio_operations *ops;
+	void *private;
+
+	/* Nonzero if the driver is busy. */
+	int busy;
+
+	/* Support for a circular queue of output buffers. */
+	__u8 **output_buffers;
+	size_t *output_sizes;
+	int num_output_buffers, output_front, output_rear, output_count, output_active;
+	struct wait_queue *output_write_wait, *output_drain_wait;
+};
+
+struct sparcaudio_operations
+{
+	int (*open)(struct inode *, struct file *, struct sparcaudio_driver *);
+	void (*release)(struct inode *, struct file *, struct sparcaudio_driver *);
+	int (*ioctl)(struct inode *, struct file *, unsigned int, unsigned long,
+		     struct sparcaudio_driver *);
+
+	/* Ask driver to begin playing a buffer. */
+	void (*start_output)(struct sparcaudio_driver *, __u8 * buffer, size_t count);
+
+	/* Ask driver to stop playing a buffer. */
+	void (*stop_output)(struct sparcaudio_driver *);
+
+	/* Set and get the audio encoding method. */
+	int (*set_encoding)(int encoding);
+	int (*get_encoding)(void);
+
+	/* Set and get the audio sampling rate (samples per second). */
+	int (*set_sampling_rate)(int sampling_rate);
+	int (*get_sampling_rate)(void);
+
+	/* Set and get the audio output port. */
+	int (*set_output_port)(int output_port);
+	int (*get_output_port)(void);
+
+	/* Set and get the audio input port. */
+	int (*set_input_port)(int input_port);
+	int (*get_input_port)(void);
+};
+
+extern int register_sparcaudio_driver(struct sparcaudio_driver *);
+extern int unregister_sparcaudio_driver(struct sparcaudio_driver *);
+extern void sparcaudio_output_done(void);
+extern int sparcaudio_init(void);
+extern int amd7930_init(void);
+
+#endif
+
+#endif
diff -u --recursive --new-file v2.1.22/linux/drivers/sbus/audio/bounce.c linux/drivers/sbus/audio/bounce.c
--- v2.1.22/linux/drivers/sbus/audio/bounce.c	Sun Dec 22 16:37:36 1996
+++ linux/drivers/sbus/audio/bounce.c	Thu Jan  1 02:00:00 1970
@@ -1,150 +0,0 @@
-/*
- * drivers/sbus/audio/bounce.c
- *
- * Copyright (C) 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu)
- *
- * Simple bounce buffer allocator used for allocating pages for use in
- * DMA and pseudo-DMA (byte-by-byte using an interrupt)
- * applications. For safety, we do most operations in bottom half so
- * we have some guarnatee of atomicity. System calls can do
- * "start_bh_atomic" to get some atomicity.
- */
-
-#include <linux/kernel.h>
-#include <linux/malloc.h>
-#include "bounce.h"
-
-
-static struct bounce_page *pages[NR_BOUNCE_PAGES];
-static struct bounce_page *free_list_head, *free_list_tail;
-
-/* Add a bounce page to the free list. */
-static void add_bounce_page(struct bounce_page *page)
-{
-  unsigned long flags;
-
-#ifdef DEBUG_BOUNCE
-  if (page->next) {
-    printk(KERN_DEBUG "add_bounce_page: page already on list from %p\n",
-	   __builtin_return_address(0));
-    return;
-  }
-#endif
-
-  save_flags(flags);
-  cli();
-
-  /* Case #1: Nothing on the list. */
-  if (!free_list_tail) {
-#ifdef DEBUG_BOUNCE
-    if (free_list_head) {
-      printk(KERN_DEBUG "add_bounce_page: inconsistent free list from %p\n",
-	     __builtin_return_address(0));
-      restore_flags(flags);
-      return;
-    }
-#endif
-    free_list_head = free_list_tail = page;
-  } else {
-    free_list_tail->next = page;
-    page->next = NULL;
-    free_list_tail = page;
-  }
-
-  restore_flags(flags);
-}
-
-/* Remove a bounce page from the free list. */
-static struct bounce_page *next_bounce_page(void)
-{
-  struct bounce_page *p;
-  unsigned long flags;
-
-  save_flags(flags);
-  cli();
-
-  /* If the free list is empty, return empty handed. */
-  if (!free_list_head) {
-    restore_flags(flags);
-    return NULL;
-  }
-
-  /* Remove the next available bounce page from the free list. */
-  p = free_list_head;
-
-  /* Update the free list pointers. */
-  free_list_head = free_list_head->next;
-  if (!free_list_head)
-    free_list_tail = NULL;
-
-  /* Return the page that we found. */
-  p->next = NULL;
-  restore_flags(flags);
-  return p;
-}
-
-/* Allocate the bounce buffers and the page lists. */
-int bounce_init(void)
-{
-  register int i;
-
-  /* Allocate space for all of the bounce pages. */
-  for (i = 0; i < NR_BOUNCE_PAGES; i++) {
-    pages[i] = __get_free_page(GFP_KERNEL);
-    if (!pages[i]) {
-      register int j;
-      for (j = 0; j < i; j++) free_page(pages[i]);
-      return -ENOMEM;
-    }
-  }
-
-  /* Place all of the pages onto the free list. */
-  for (i = 0; i < NR_BOUNCE_PAGES - 1; i++)
-    pages[i]->next = pages[i+1];
-  pages[NR_BOUNCE_BUFFERS-1]->next = NULL;
-
-  /* Setup pointers to the free list head and tail. */
-  free_list_head = pages[0];
-  free_list_tail = pages[NR_BOUNCE_BUFFERS-1];
-  return 0;
-}
-
-/* Allocate a bounce buffer to a process. */
-struct bounce_page * get_bounce_page(int timeout)
-{
-  struct bounce_page *p;
-  int tries;
-
-  do {
-    /* Do not allow interrupts to muck with the lists. */
-    start_bh_atomic();
-
-    /* Check to see if a bounce page is available. */
-    p = next_bounce_page();
-    if (p) {
-      end_bh_atomic();
-      return p;
-    }
-
-    /* No bounce page was available. Sleep and wait for one. */
-    end_bh_atomic();
-    current->state = TASK_INTERRUPTIBLE;
-    current->timeout = jiffies + HZ / 10;
-    schedule();
-
-    /* If we received a signal, then bail out. */
-    if (current->signal & ~current->blocked)
-      return NULL;
-    
-  } while (jiffies <= timeout);
-
-  /* We did not find anything before the timeout. */
-  return NULL;
-}
-
-/* Return a bounce buffer to the free list. */
-void put_bounce_page(struct bounce_page *page)
-{
-  add_bounce_page(page);
-}
-
diff -u --recursive --new-file v2.1.22/linux/drivers/sbus/audio/bounce.h linux/drivers/sbus/audio/bounce.h
--- v2.1.22/linux/drivers/sbus/audio/bounce.h	Sun Dec 22 16:37:36 1996
+++ linux/drivers/sbus/audio/bounce.h	Thu Jan  1 02:00:00 1970
@@ -1,23 +0,0 @@
-#ifndef _BOUNCE_H_
-#define _BOUNCE_H_
-
-#include <linux/types.h>
-
-/* Each page that is used for a bounce buffer has the following header
- * at the top which points to the next page in the free or in-use list
- * and provides some other stats for drivers.
- */
-
-#define NR_BOUNCE_PAGES 32
-
-struct bounce_page
-{
-  struct bounce_page *next;
-  __u32 size;
-  __u32 remaining;
-  __u8 *current;
-  __u8 data[PAGE_SIZE - 1*sizeof(struct bounce_page *)
-	   - 2*sizeof(__u32) - sizeof(__u8)];
-};
-
-#endif
diff -u --recursive --new-file v2.1.22/linux/drivers/sbus/audio/cs4231.c linux/drivers/sbus/audio/cs4231.c
--- v2.1.22/linux/drivers/sbus/audio/cs4231.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sbus/audio/cs4231.c	Sun Jan 26 12:07:17 1997
@@ -0,0 +1,518 @@
+/*
+ * drivers/sbus/audio/cs4231.c
+ *
+ * Copyright (C) 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu)
+ * Copyright (C) 1996 Derrick J Brashear (shadow@andrew.cmu.edu)
+ *
+ * This is the lowlevel driver for the CS4231 audio chip found on some
+ * sun4m machines.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/auxio.h>
+#include <asm/delay.h>
+#include "audio.h"
+#include "cs4231.h"
+
+/* Stolen for now from compat.h */
+#ifndef MAX                             /* Usually found in <sys/param.h>. */
+#define MAX(_a,_b)      ((_a)<(_b)?(_b):(_a))
+#endif
+#ifndef MIN                             /* Usually found in <sys/param.h>. */
+#define MIN(_a,_b)      ((_a)<(_b)?(_a):(_b))
+#endif
+
+static int cs4231_node, cs4231_irq, cs4231_is_revision_a, cs4231_ints_on = 0;
+static unsigned int cs4231_monitor_gain_value; 
+cs4231_regs_size
+
+static int cs4231_output_muted_value;
+
+static struct cs4231_stream_info cs4231_input;
+static struct cs4231_stream_info cs4231_output;
+
+static int cs4231_busy = 0, cs4231_need_init = 0;
+
+static volatile struct cs4231_chip *cs4231_chip = NULL;
+
+static __u8 * ptr;
+static size_t count;
+
+#define CHIP_BUG udelay(100); cs4231_ready(); udelay(1000);
+
+static void cs4231_ready(void) 
+{
+  register unsigned int x = 0;
+
+  cs4231_chip->pioregs.iar = (u_char)IAR_AUTOCAL_END;
+  while (cs4231_chip->pioregs.iar == IAR_NOT_READY && x <= CS_TIMEOUT) {
+    x++;
+  }
+
+  x = 0;
+
+  cs4231_chip->pioregs.iar = 0x0b;
+
+  while (cs4231_chip->pioregs.idr == AUTOCAL_IN_PROGRESS && x <= CS_TIMEOUT) {
+    x++;
+  }
+}
+
+/* Enable cs4231 interrupts atomically. */
+static __inline__ void cs4231_enable_ints(void)
+{
+	register unsigned long flags;
+
+	if (cs4231_ints_on)
+		return;
+
+	save_and_cli(flags);
+	/* do init here
+	amd7930_regs->cr = AMR_INIT;
+	amd7930_regs->dr = AM_INIT_ACTIVE;
+	*/
+	restore_flags(flags);
+
+	cs4231_ints_on = 1;
+}
+
+/* Disable cs4231 interrupts atomically. */
+static __inline__ void cs4231_disable_ints(void)
+{
+	register unsigned long flags;
+
+	if (!cs4231_ints_on)
+		return;
+
+	save_and_cli(flags);
+/*
+	amd7930_regs->cr = AMR_INIT;
+	amd7930_regs->dr = AM_INIT_ACTIVE | AM_INIT_DISABLE_INTS;
+*/
+	restore_flags(flags);
+
+	cs4231_ints_on = 0;
+}  
+
+
+/* Audio interrupt handler. */
+static void cs4231_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	__u8 dummy;
+
+        /* Clear the interrupt. */
+        dummy = cs4231_chip->dmaregs.dmacsr;
+
+        cs4231_chip->dmaregs.dmacsr = dummy;
+
+}
+
+static unsigned int cs4231_output_muted(unsigned int value)
+{
+  if (!value) {
+    cs4231_chip->pioregs.iar = 0x7;
+    cs4231_chip->pioregs.idr &= OUTCR_UNMUTE;
+    cs4231_chip->pioregs.iar = 0x6;
+    cs4231_chip->pioregs.idr &= OUTCR_UNMUTE;
+    cs4231_output_muted_value = 0;
+  } else {
+    cs4231_chip->pioregs.iar = 0x7;
+    cs4231_chip->pioregs.idr |= OUTCR_MUTE;
+    cs4231_chip->pioregs.iar = 0x6;
+    cs4231_chip->pioregs.idr |= OUTCR_MUTE;
+    cs4231_output_muted_value = 1;
+  }
+  return (cs4231_output_muted_value);
+}
+
+static unsigned int cs4231_out_port(unsigned int value)
+{
+  unsigned int r = 0;
+
+  /* You can have any combo you want. Just don't tell anyone. */
+
+  cs4231_chip->pioregs.iar = 0x1a;
+  cs4231_chip->pioregs.idr |= MONO_IOCR_MUTE;
+  cs4231_chip->pioregs.iar = 0x0a;
+  cs4231_chip->pioregs.idr |= PINCR_LINE_MUTE;
+  cs4231_chip->pioregs.idr |= PINCR_HDPH_MUTE;
+
+  if (value & AUDIO_SPEAKER) {
+    cs4231_chip->pioregs.iar = 0x1a;
+    cs4231_chip->pioregs.idr &= ~MONO_IOCR_MUTE;
+    r |= AUDIO_SPEAKER;
+  }
+
+  if (value & AUDIO_HEADPHONE) {
+   cs4231_chip->pioregs.iar = 0x0a;
+   cs4231_chip->pioregs.idr &= ~PINCR_HDPH_MUTE;
+   r |= AUDIO_HEADPHONE;
+  }
+
+  if (value & AUDIO_LINE_OUT) {
+    cs4231_chip->pioregs.iar = 0x0a;
+    cs4231_chip->pioregs.idr &= ~PINCR_LINE_MUTE;
+    r |= AUDIO_LINE_OUT;
+  }
+  
+  return (r);
+}
+
+static unsigned int cs4231_in_port(unsigned int value)
+{
+  unsigned int r = 0;
+
+  /* The order of these seems to matter. Can't tell yet why. */
+
+  if (value & AUDIO_INTERNAL_CD_IN) {
+    cs4231_chip->pioregs.iar = 0x1;
+    cs4231_chip->pioregs.idr = CDROM_ENABLE(cs4231_chip->pioregs.idr);
+    cs4231_chip->pioregs.iar = 0x0;
+    cs4231_chip->pioregs.idr = CDROM_ENABLE(cs4231_chip->pioregs.idr);
+    r = AUDIO_INTERNAL_CD_IN;
+  }
+  if ((value & AUDIO_LINE_IN)) {
+    cs4231_chip->pioregs.iar = 0x1;
+    cs4231_chip->pioregs.idr = LINE_ENABLE(cs4231_chip->pioregs.idr);
+    cs4231_chip->pioregs.iar = 0x0;
+    cs4231_chip->pioregs.idr = LINE_ENABLE(cs4231_chip->pioregs.idr);
+    r = AUDIO_LINE_IN;
+  } else if (value & AUDIO_MICROPHONE) {
+    cs4231_chip->pioregs.iar = 0x1;
+    cs4231_chip->pioregs.idr = MIC_ENABLE(cs4231_chip->pioregs.idr);
+    cs4231_chip->pioregs.iar = 0x0;
+    cs4231_chip->pioregs.idr = MIC_ENABLE(cs4231_chip->pioregs.idr);
+    r = AUDIO_MICROPHONE;
+  }
+
+  return (r);
+}
+
+static unsigned int cs4231_monitor_gain(unsigned int value)
+{
+  int a = 0;
+
+  a = CS4231_MON_MAX_ATEN - (value * (CS4231_MON_MAX_ATEN + 1) /
+                            (AUDIO_MAX_GAIN + 1));
+
+  cs4231_chip->pioregs.iar = 0x0d;
+  if (a >= CS4231_MON_MAX_ATEN) 
+    cs4231_chip->pioregs.idr = LOOPB_OFF;
+  else 
+    cs4231_chip->pioregs.idr = ((a << 2) | LOOPB_ON);
+
+
+  if (value == AUDIO_MAX_GAIN)
+    return AUDIO_MAX_GAIN;
+
+  return ((CS4231_MAX_DEV_ATEN - a) * (AUDIO_MAX_GAIN + 1) /
+          (CS4231_MAX_DEV_ATEN + 1));
+}
+
+/* Set record gain */
+static unsigned int cs4231_record_gain(unsigned int value, unsigned char balance)
+{
+  unsigned int tmp = 0, r, l, ra, la;
+  unsigned char old_gain;
+
+
+  r = l = value;
+
+  if (balance < AUDIO_MID_BALANCE) {
+    r = MAX(0, (int)(value -
+                     ((AUDIO_MID_BALANCE - balance) << AUDIO_BALANCE_SHIFT)));
+  } else if (balance > AUDIO_MID_BALANCE) {
+    l = MAX(0, (int)(value -
+                     ((balance - AUDIO_MID_BALANCE) << AUDIO_BALANCE_SHIFT)));
+  }
+
+  la = l * (CS4231_MAX_GAIN + 1) / (AUDIO_MAX_GAIN + 1);
+  ra = r * (CS4231_MAX_GAIN + 1) / (AUDIO_MAX_GAIN + 1);
+  
+  cs4231_chip->pioregs.iar = 0x0;
+  old_gain = cs4231_chip->pioregs.idr;
+  cs4231_chip->pioregs.idr = RECGAIN_SET(old_gain, la);
+  cs4231_chip->pioregs.iar = 0x1;
+  old_gain = cs4231_chip->pioregs.idr;
+  cs4231_chip->pioregs.idr = RECGAIN_SET(old_gain, ra);
+  
+  if (l == value) {
+    (l == 0) ? (tmp = 0) : (tmp = ((la + 1) * AUDIO_MAX_GAIN) / (CS4231_MAX_GAIN + 1));
+  } else if (r == value) {
+    (r == 0) ? (tmp = 0) : (tmp = ((ra + 1) * AUDIO_MAX_GAIN) / (CS4231_MAX_GAIN + 1));
+  }
+  return (tmp);
+}
+
+/* Set play gain */
+static unsigned int cs4231_play_gain(unsigned int value, unsigned char balance)
+{
+  unsigned int tmp = 0, r, l, ra, la;
+  unsigned char old_gain;
+
+  r = l = value;
+  if (balance < AUDIO_MID_BALANCE) {
+    r = MAX(0, (int)(value -
+                     ((AUDIO_MID_BALANCE - balance) << AUDIO_BALANCE_SHIFT)));
+  } else if (balance > AUDIO_MID_BALANCE) {
+    l = MAX(0, (int)(value -
+                     ((balance - AUDIO_MID_BALANCE) << AUDIO_BALANCE_SHIFT)));
+  }
+
+  if (l == 0) {
+    la = CS4231_MAX_DEV_ATEN;
+  } else {
+    la = CS4231_MAX_ATEN -
+      (l * (CS4231_MAX_ATEN + 1) / (AUDIO_MAX_GAIN + 1));
+  }
+  if (r == 0) {
+    ra = CS4231_MAX_DEV_ATEN;
+  } else {
+    ra = CS4231_MAX_ATEN -
+      (r * (CS4231_MAX_ATEN + 1) / (AUDIO_MAX_GAIN + 1));
+  }
+  
+  cs4231_chip->pioregs.iar = 0x6;
+  old_gain = cs4231_chip->pioregs.idr;
+  cs4231_chip->pioregs.idr = GAIN_SET(old_gain, la);
+  cs4231_chip->pioregs.iar = 0x7;
+  old_gain = cs4231_chip->pioregs.idr;
+  cs4231_chip->pioregs.idr = GAIN_SET(old_gain, ra);
+  
+  if ((value == 0) || (value == AUDIO_MAX_GAIN)) {
+    tmp = value;
+  } else {
+    if (l == value) {
+      tmp = ((CS4231_MAX_ATEN - la) *
+                 (AUDIO_MAX_GAIN + 1) /
+                 (CS4231_MAX_ATEN + 1));
+    } else if (r == value) {
+      tmp = ((CS4231_MAX_ATEN - ra) *
+                 (AUDIO_MAX_GAIN + 1) /
+                 (CS4231_MAX_ATEN + 1));
+    }
+  }
+  return (tmp);
+}
+
+/* Reset the audio chip to a sane state. */
+static void cs4231_reset(void)
+{
+        cs4231_chip->dmaregs.dmacsr = APC_RESET;
+        cs4231_chip->dmaregs.dmacsr = 0x00;
+        cs4231_chip->dmaregs.dmacsr |= APC_CODEC_PDN;
+
+        udelay(20);
+
+        cs4231_chip->dmaregs.dmacsr &= ~(APC_CODEC_PDN);
+        cs4231_chip->pioregs.iar |= IAR_AUTOCAL_BEGIN;
+
+        CHIP_BUG
+
+        cs4231_chip->pioregs.iar = IAR_AUTOCAL_BEGIN | 0x0c;
+        cs4231_chip->pioregs.idr = MISC_IR_MODE2;
+        cs4231_chip->pioregs.iar = IAR_AUTOCAL_BEGIN | 0x08;
+        cs4231_chip->pioregs.idr = DEFAULT_DATA_FMAT;
+
+        CHIP_BUG
+
+        cs4231_chip->pioregs.iar = IAR_AUTOCAL_BEGIN | 0x1c;
+        cs4231_chip->pioregs.idr = DEFAULT_DATA_FMAT;
+
+        CHIP_BUG
+
+        cs4231_chip->pioregs.iar = 0x19;
+
+        if (cs4231_chip->pioregs.idr & CS4231A)
+                cs4231_is_revision_a = 1;
+        else
+                cs4231_is_revision_a = 0;
+
+        cs4231_chip->pioregs.iar = IAR_AUTOCAL_BEGIN | 0x10;
+        cs4231_chip->pioregs.idr = (u_char)OLB_ENABLE;
+
+        cs4231_chip->pioregs.iar = IAR_AUTOCAL_BEGIN | 0x11;
+        if (cs4231_is_revision_a)
+                cs4231_chip->pioregs.idr = (HPF_ON | XTALE_ON);
+        else
+                cs4231_chip->pioregs.idr = (HPF_ON);
+
+        cs4231_chip->pioregs.iar = IAR_AUTOCAL_BEGIN | 0x1a;
+        cs4231_chip->pioregs.idr = 0x00;
+
+        cs4231_output.gain = cs4231_play_gain(CS4231_DEFAULT_PLAYGAIN,
+                                              AUDIO_MID_BALANCE);
+        cs4231_input.gain = cs4231_record_gain(CS4231_DEFAULT_RECGAIN,
+                                               AUDIO_MID_BALANCE);
+
+        cs4231_output.port = cs4231_out_port(AUDIO_SPEAKER);
+        cs4231_input.port = cs4231_in_port(AUDIO_MICROPHONE);
+
+        cs4231_monitor_gain_value = cs4231_monitor_gain(LOOPB_OFF);
+
+        cs4231_chip->pioregs.iar = (u_char)IAR_AUTOCAL_END;
+
+        cs4231_ready();
+
+        cs4231_chip->pioregs.iar = IAR_AUTOCAL_BEGIN | 0x09;
+        cs4231_chip->pioregs.idr &= ACAL_DISABLE;
+        cs4231_chip->pioregs.iar = (u_char)IAR_AUTOCAL_END;
+
+        cs4231_ready();
+
+        cs4231_output_muted_value = cs4231_output_muted(0x0);
+}
+
+static int cs4231_open(struct inode * inode, struct file * file, struct sparcaudio_driver *drv)
+{
+	int level;
+
+        /* Set the default audio parameters. */
+
+        cs4231_output.sample_rate = CS4231_RATE;
+        cs4231_output.channels = CS4231_CHANNELS;
+        cs4231_output.precision = CS4231_PRECISION;
+        cs4231_output.encoding = AUDIO_ENCODING_ULAW;
+
+        cs4231_input.sample_rate = CS4231_RATE;
+        cs4231_input.channels = CS4231_CHANNELS;
+        cs4231_input.precision = CS4231_PRECISION;
+        cs4231_input.encoding = AUDIO_ENCODING_ULAW;
+
+        cs4231_ready();
+
+        cs4231_need_init = 1;
+#if 1
+        /* Arguably this should only happen once. I need to play around 
+         * on a Solaris box and see what happens
+         */
+        cs4231_chip->pioregs.iar = IAR_AUTOCAL_BEGIN | 0x08;
+        cs4231_chip->pioregs.idr = DEFAULT_DATA_FMAT;
+        cs4231_chip->pioregs.iar = IAR_AUTOCAL_BEGIN | 0x1c;
+        cs4231_chip->pioregs.idr = DEFAULT_DATA_FMAT;
+
+#endif
+
+        CHIP_BUG
+
+	MOD_INC_USE_COUNT;
+
+	return 0;
+}
+
+static void cs4231_release(struct inode * inode, struct file * file, struct sparcaudio_driver *drv)
+{
+	cs4231_disable_ints();
+	MOD_DEC_USE_COUNT;
+}
+
+static void cs4231_start_output(struct sparcaudio_driver *drv, __u8 * buffer, size_t the_count)
+{
+	count = the_count;
+	ptr = buffer;
+	cs4231_enable_ints();
+}
+
+static void cs4231_stop_output(struct sparcaudio_driver *drv)
+{
+	cs4231_disable_ints();
+	ptr = NULL;
+	count = 0;
+}
+
+
+static struct sparcaudio_operations cs4231_ops = {
+	cs4231_open,
+	cs4231_release,
+	NULL,			/* cs4231_ioctl */
+	cs4231_start_output,
+	cs4231_stop_output,
+};
+
+static struct sparcaudio_driver cs4231_drv = {
+	"cs4231",
+	&cs4231_ops,
+};
+
+/* Probe for the cs4231 chip and then attach the driver. */
+#ifdef MODULE
+int init_module(void)
+#else
+__initfunc(int cs4231_init(void))
+#endif
+{
+	struct linux_prom_registers regs[1];
+	struct linux_prom_irqs irq;
+	int err;
+
+#ifdef MODULE
+	register_symtab(0);
+#endif
+
+        /* Find the PROM CS4231 node. */
+        cs4231_node = prom_getchild(prom_root_node);
+        cs4231_node = prom_searchsiblings(cs4231_node,"iommu");
+        cs4231_node = prom_getchild(cs4231_node);
+        cs4231_node = prom_searchsiblings(cs4231_node,"sbus");
+        cs4231_node = prom_getchild(cs4231_node);
+        cs4231_node = prom_searchsiblings(cs4231_node,"SUNW,CS4231");
+
+	if (!cs4231_node)
+		return -EIO;
+
+	/* XXX Add for_each_sbus() search as well for LX and friends. */
+	/* XXX Copy out for prom_apply_sbus_ranges. */
+
+	/* Map the registers into memory. */
+        prom_getproperty(cs4231_node, "reg", (char *)regs, sizeof(regs));
+	cs4231_regs_size = regs[0].reg_size;
+	cs4231_regs = sparc_alloc_io(regs[0].phys_addr, 0, regs[0].reg_size,
+				      "cs4231", regs[0].which_io, 0);
+	if (!cs4231_regs) {
+		printk(KERN_ERR "cs4231: could not allocate registers\n");
+		return -EIO;
+	}
+
+	/* Disable cs4231 interrupt generation. */
+	cs4231_disable_ints();
+
+        /* Reset the audio chip. */
+        cs4231_reset();
+
+	/* Attach the interrupt handler to the audio interrupt. */
+        prom_getproperty(cs4231_node, "intr", (char *)&irq, sizeof(irq));
+        cs4231_irq = irq.pri;
+        request_irq(cs4231_irq, cs4231_interrupt, SA_INTERRUPT, "cs4231", NULL);
+        enable_irq(cs4231_irq);
+
+	/* Register ourselves with the midlevel audio driver. */
+	err = register_sparcaudio_driver(&cs4231_drv);
+	if (err < 0) {
+		/* XXX We should do something. Complain for now. */
+		printk(KERN_ERR "cs4231: really screwed now\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+	unregister_sparcaudio_driver(&cs4231_drv);
+	cs4231_disable_ints();
+	disable_irq(cs4231_irq);
+	free_irq(cs4231_irq, NULL);
+	sparc_free_io(cs4231_regs, cs4231_regs_size);
+}
+#endif
diff -u --recursive --new-file v2.1.22/linux/drivers/sbus/audio/cs4231.h linux/drivers/sbus/audio/cs4231.h
--- v2.1.22/linux/drivers/sbus/audio/cs4231.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sbus/audio/cs4231.h	Sun Jan 26 12:07:18 1997
@@ -0,0 +1,138 @@
+/*
+ * drivers/sbus/audio/cs4231.h
+ *
+ * Copyright (C) 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu)
+ * Copyright (C) 1997 Derrick J. Brashear (shadow@dementia.org)
+ */
+
+#ifndef _CS4231_H_
+#define _CS4231_H_
+
+#include <linux/types.h>
+
+struct cs4231_regs {
+         u_char iar;            /* Index Address Register */
+         u_char pad0[3];         
+         u_char idr;            /* Indexed Data Register */
+         u_char pad1[3];        
+         u_char statr;          /* Status Register */
+         u_char pad2[3];        
+         u_char piodr;          /* PIO Data Register I/O */
+         u_char pad3[3];        
+};
+
+struct cs4231_dma {
+         u_long         dmacsr;         /* APC CSR */
+         u_long         dmapad[3];        
+         u_long         dmacva;         /* Capture Virtual Address */
+         u_long         dmacc;          /* Capture Count */
+         u_long         dmacnva;        /* Capture Next VAddress */
+         u_long         dmacnc;         /* Capture Next Count */
+         u_long         dmapva;         /* Playback Virtual Address */
+         u_long         dmapc;          /* Playback Count */
+         u_long         dmapnva;        /* Playback Next VAddress */
+         u_long         dmapnc;         /* Playback Next Count */
+};
+
+struct cs4231_chip {
+        struct cs4231_regs pioregs;
+        struct cs4231_dma dmaregs;
+};
+
+struct cs4231_stream_info {
+        unsigned int sample_rate;     /* samples per second */
+        unsigned int channels;        /* number of interleaved channels */
+        unsigned int precision;       /* bit-width of each sample */
+        unsigned int encoding;        /* data encoding method */
+        unsigned int gain;            /* gain level: 0 - 255 */
+        unsigned int port;
+};
+
+#define CS_TIMEOUT      9000000
+
+#define GAIN_SET(var, gain)     ((var & ~(0x3f)) | gain)
+#define RECGAIN_SET(var, gain)  ((var & ~(0x1f)) | gain)
+
+#define IAR_AUTOCAL_BEGIN       0x40
+#define IAR_AUTOCAL_END         ~(0x40)
+#define IAR_NOT_READY            0x80    /* 80h not ready CODEC state */
+
+#define MIC_ENABLE(var)         ((var & 0x2f) | 0x80)
+#define LINE_ENABLE(var)        (var & 0x2f)
+#define CDROM_ENABLE(var)       ((var & 0x2f) | 0x40)
+
+#define OUTCR_MUTE              0x80
+#define OUTCR_UNMUTE            ~0x80
+
+/* 8 */
+#define DEFAULT_DATA_FMAT               0x20
+
+/* 10 */
+#define PINCR_LINE_MUTE         0x40
+#define PINCR_HDPH_MUTE         0x80
+
+/* 11 */
+#define AUTOCAL_IN_PROGRESS      0x20
+
+/* 12 */
+#define MISC_IR_MODE2           0x40
+
+/* 13 */
+#define LOOPB_ON                0x01
+#define LOOPB_OFF               0x00
+
+/* 16 */
+#define OLB_ENABLE              0x80
+
+/* 17 */
+#define HPF_ON                  0x01
+#define XTALE_ON                0x20
+
+#define MONO_IOCR_MUTE       0x40;
+
+/* 30 */
+#define CS4231A         0x20
+
+
+#define APC_CODEC_PDN   0x20            
+#define APC_RESET       0x01            
+
+#define CS4231_DEFAULT_PLAYGAIN     (132)
+#define CS4231_DEFAULT_RECGAIN      (126)
+
+#define CS4231_MIN_ATEN     (0)
+#define CS4231_MAX_ATEN     (31)
+#define CS4231_MAX_DEV_ATEN (63)
+#define CS4231_MIN_GAIN     (0)
+#define CS4231_MAX_GAIN     (15)
+#define CS4231_MON_MIN_ATEN         (0)
+#define CS4231_MON_MAX_ATEN         (63)
+
+#define CS4231_PRECISION    (8)             /* Bits per sample unit */
+#define CS4231_CHANNELS     (1)             /* Channels per sample frame */
+
+#define CS4231_RATE   (8000)          
+
+#define AUDIO_ENCODING_NONE     (0) /* no encoding assigned */
+#define AUDIO_ENCODING_ULAW     (1) /* u-law encoding */
+#define AUDIO_ENCODING_ALAW     (2) /* A-law encoding */
+#define AUDIO_ENCODING_LINEAR   (3) /* Linear PCM encoding */
+#define AUDIO_ENCODING_DVI      (104) /* DVI ADPCM */
+#define AUDIO_ENCODING_LINEAR8  (105) /* 8 bit UNSIGNED */
+
+#define AUDIO_LEFT_BALANCE      (0)
+#define AUDIO_MID_BALANCE       (32)
+#define AUDIO_RIGHT_BALANCE     (64)
+#define AUDIO_BALANCE_SHIFT     (3)
+
+#define AUDIO_SPEAKER           0x01
+#define AUDIO_HEADPHONE         0x02
+#define AUDIO_LINE_OUT          0x04
+
+#define AUDIO_MICROPHONE        0x01
+#define AUDIO_LINE_IN           0x02
+#define AUDIO_INTERNAL_CD_IN    0x04
+
+#define AUDIO_MAX_GAIN  (255)
+
+#endif
diff -u --recursive --new-file v2.1.22/linux/drivers/sbus/char/openprom.c linux/drivers/sbus/char/openprom.c
--- v2.1.22/linux/drivers/sbus/char/openprom.c	Wed Dec 18 15:58:48 1996
+++ linux/drivers/sbus/char/openprom.c	Sun Jan 26 12:07:18 1997
@@ -558,23 +558,29 @@
 	NULL,			/* openprom_read */
 	NULL,			/* openprom_write */
 	NULL,			/* openprom_readdir */
-	NULL,			/* openprom_select */
+	NULL,			/* openprom_poll */
 	openprom_ioctl,
 	NULL,			/* openprom_mmap */
 	openprom_open,
 	openprom_release
 };
 
-static struct miscdevice misc_openprom = {
+static struct miscdevice openprom_dev = {
 	SUN_OPENPROM_MINOR, "openprom", &openprom_fops
 };
 
+EXPORT_NO_SYMBOLS;
+
+#ifdef MODULE
+int init_module(void)
+#else
 __initfunc(int openprom_init(void))
+#endif
 {
 	unsigned long flags;
 	int error;
 
-	error = misc_register(&misc_openprom);
+	error = misc_register(&openprom_dev);
 	if (error) {
 		printk(KERN_ERR "openprom: unable to get misc minor\n");
 		return error;
@@ -587,7 +593,7 @@
 
 	if (options_node == 0 || options_node == -1) {
 		printk(KERN_ERR "openprom: unable to find options node\n");
-		misc_deregister(&misc_openprom);
+		misc_deregister(&openprom_dev);
 		return -EIO;
 	}
 
@@ -596,15 +602,9 @@
 
 #ifdef MODULE
 
-int init_module(void)
-{
-	register_symtab(0);
-	return openprom_init();
-}
-
 void cleanup_module(void)
 {
-	misc_deregister(&misc_openprom);
+	misc_deregister(&openprom_dev);
 }
 
 #endif
diff -u --recursive --new-file v2.1.22/linux/drivers/sbus/char/rtc.c linux/drivers/sbus/char/rtc.c
--- v2.1.22/linux/drivers/sbus/char/rtc.c	Wed Dec 18 15:58:48 1996
+++ linux/drivers/sbus/char/rtc.c	Sun Jan 26 12:07:18 1997
@@ -1,4 +1,4 @@
-/* $Id: rtc.c,v 1.6 1996/11/21 16:57:50 jj Exp $
+/* $Id: rtc.c,v 1.9 1997/01/26 07:13:40 davem Exp $
  *
  * Linux/SPARC Real Time Clock Driver
  * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
@@ -17,6 +17,7 @@
 #include <linux/miscdevice.h>
 #include <linux/malloc.h>
 #include <linux/fcntl.h>
+#include <linux/poll.h>
 #include <linux/init.h>
 #include <asm/mostek.h>
 #include <asm/system.h>
@@ -128,7 +129,7 @@
 	NULL,		/* rtc_read */
 	NULL,		/* rtc_write */
 	NULL,		/* rtc_readdir */
-	NULL,		/* rtc_select */
+	NULL,		/* rtc_poll */
 	rtc_ioctl,
 	NULL,		/* rtc_mmap */
 	rtc_open,
@@ -137,16 +138,22 @@
 
 static struct miscdevice rtc_dev = { RTC_MINOR, "rtc", &rtc_fops };
 
+EXPORT_NO_SYMBOLS;
+
 #ifdef MODULE
 int init_module(void)
 #else
 __initfunc(int rtc_init(void))
 #endif
 {
-#ifdef MODULE
-	register_symtab(0);
-#endif
-	misc_register(&rtc_dev);
+	int error;
+
+	error = misc_register(&rtc_dev);
+	if (error) {
+		printk(KERN_ERR "rtc: unable to get misc minor\n");
+		return error;
+	}
+
 	return 0;
 }
 
diff -u --recursive --new-file v2.1.22/linux/drivers/sbus/char/suncons.c linux/drivers/sbus/char/suncons.c
--- v2.1.22/linux/drivers/sbus/char/suncons.c	Tue Dec 31 21:41:07 1996
+++ linux/drivers/sbus/char/suncons.c	Sun Jan 26 12:07:18 1997
@@ -1,4 +1,4 @@
-/* $Id: suncons.c,v 1.43 1996/12/23 10:16:12 ecd Exp $
+/* $Id: suncons.c,v 1.44 1997/01/25 02:47:10 miguel Exp $
  *
  * suncons.c: Sun SparcStation console support.
  *
@@ -74,6 +74,7 @@
 #include <asm/sbus.h>
 #include <asm/fbio.h>
 #include <asm/io.h>
+#include <asm/smp.h>
 
 #include "../../char/kbd_kern.h"
 #include "../../char/vt_kern.h"
@@ -383,7 +384,7 @@
 
 __initfunc(void con_type_init_finish(void))
 {
-	int i;
+	int i, cpu;
 	char *p = con_fb_base + skip_bytes;
 	char q[2] = {0,5};
 	int currcons = 0;
@@ -408,14 +409,17 @@
 			fbinfo[0].color_map CM(i+32,2) = linux_logo_blue [i];
 		}
 		(*fbinfo [0].loadcmap)(&fbinfo [0], 0, LINUX_LOGO_COLORS + 32);
-		for (i = 0; i < 80; i++, p += chars_per_line)
-			memcpy (p, linux_logo + 80 * i, 80);
+		for (i = 0; i < 80; i++, p += chars_per_line){
+		        for (cpu = 0; cpu < linux_num_cpus; cpu++){
+				memcpy (p + (cpu * 84), linux_logo + 80 * i, 80);
+			}
+		}
 	} else if (con_depth == 1) {
 		for (i = 0; i < 80; i++, p += chars_per_line)
 			memcpy (p, linux_logo_bw + 10 * i, 10);
 	}
 	putconsxy(0, q);
-	ush = (unsigned short *) video_mem_base + video_num_columns * 2 + 20;
+	ush = (unsigned short *) video_mem_base + video_num_columns * 2 + 20 + 80 * (linux_num_cpus - 1);
 
 	for (p = "Linux/SPARC version " UTS_RELEASE; *p; p++, ush++) {
 		*ush = (attr << 8) + *p;
@@ -1163,6 +1167,7 @@
 		prom_printf("Could not probe console, bailing out...\n");
 		prom_halt();
 	}
+	
 	sun_clear_screen();
 	for (i = FRAME_BUFFERS; i > 1; i--)
 		if (fbinfo[i - 1].type.fb_type != FBTYPE_NOTYPE) break;
diff -u --recursive --new-file v2.1.22/linux/drivers/sbus/char/sunfb.c linux/drivers/sbus/char/sunfb.c
--- v2.1.22/linux/drivers/sbus/char/sunfb.c	Tue Dec 31 21:41:07 1996
+++ linux/drivers/sbus/char/sunfb.c	Sun Jan 26 12:07:18 1997
@@ -1,4 +1,4 @@
-/* $Id: sunfb.c,v 1.19 1996/12/23 10:16:15 ecd Exp $
+/* $Id: sunfb.c,v 1.20 1997/01/26 07:13:40 davem Exp $
  * sunfb.c: Sun generic frame buffer support.
  *
  * Copyright (C) 1995, 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -298,7 +298,7 @@
 	NULL,			/* read */
 	NULL,			/* write */
 	NULL,			/* readdir */
-	NULL,			/* select */
+	NULL,			/* poll */
 	fb_ioctl,
 	fb_mmap,
 	fb_open,		/* open */
diff -u --recursive --new-file v2.1.22/linux/drivers/sbus/char/sunkbd.c linux/drivers/sbus/char/sunkbd.c
--- v2.1.22/linux/drivers/sbus/char/sunkbd.c	Wed Dec 18 15:58:48 1996
+++ linux/drivers/sbus/char/sunkbd.c	Sun Jan 26 12:07:18 1997
@@ -14,6 +14,7 @@
 #include <linux/signal.h>
 #include <linux/string.h>
 #include <linux/fcntl.h>
+#include <linux/poll.h>
 #include <linux/random.h>
 #include <linux/init.h>
 
@@ -62,7 +63,8 @@
 extern void scrollback(int);
 extern void scrollfront(int);
 
-unsigned char kbd_read_mask = 0x01;	/* modified by psaux.c */
+unsigned char kbd_read_mask = 0x01;	  /* modified by psaux.c */
+unsigned char aux_device_present = 0x00;  /* To make kernel/ksyms.c happy */
 
 /*
  * global state includes the following, and various static variables
@@ -1240,14 +1242,11 @@
 	return 0;
 }
 
-static int
-kbd_select (struct inode *i, struct file *f, int sel_type, select_table *wait)
+static unsigned int kbd_poll (struct file *f, poll_table *wait)
 {
-	if (sel_type != SEL_IN)
-		return 0;
+	poll_wait(&kbd_wait, wait);
 	if (kbd_head != kbd_tail)
-		return 1;
-	select_wait (&kbd_wait, wait);
+		return POLLIN | POLLRDNORM;
 	return 0;
 }
 
@@ -1355,7 +1354,7 @@
 	kbd_read,		/* read */
 	NULL,			/* write */
 	NULL,			/* readdir */
-	kbd_select,		/* select */
+	kbd_poll,		/* poll */
 	kbd_ioctl,		/* ioctl */
 	NULL,			/* mmap */
 	kbd_open,		/* open */
diff -u --recursive --new-file v2.1.22/linux/drivers/sbus/char/sunmouse.c linux/drivers/sbus/char/sunmouse.c
--- v2.1.22/linux/drivers/sbus/char/sunmouse.c	Wed Dec 18 15:58:48 1996
+++ linux/drivers/sbus/char/sunmouse.c	Sun Jan 26 12:07:18 1997
@@ -45,6 +45,7 @@
 #include <linux/errno.h>
 #include <linux/miscdevice.h>
 #include <linux/mm.h>
+#include <linux/poll.h>
 #include <linux/init.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -346,15 +347,11 @@
 	return 0;
 }
 
-static int
-sun_mouse_select(struct inode *inode, struct file *file, int sel_type,
-			    select_table *wait)
+static unsigned int sun_mouse_poll(struct file *file, poll_table *wait)
 {
-	if(sel_type != SEL_IN)
-		return 0;
+	poll_wait(&sunmouse.proc_list, wait);
 	if(sunmouse.ready)
-		return 1;
-	select_wait(&sunmouse.proc_list, wait);
+		return POLLIN | POLLRDNORM;
 	return 0;
 }
 int
@@ -400,7 +397,7 @@
 	sun_mouse_read,
 	sun_mouse_write,
 	NULL,
-	sun_mouse_select,
+	sun_mouse_poll,
 	sun_mouse_ioctl,
 	NULL,
 	sun_mouse_open,
diff -u --recursive --new-file v2.1.22/linux/drivers/scsi/ChangeLog linux/drivers/scsi/ChangeLog
--- v2.1.22/linux/drivers/scsi/ChangeLog	Fri May 17 10:50:58 1996
+++ linux/drivers/scsi/ChangeLog	Sun Jan 26 12:07:18 1997
@@ -1,3 +1,8 @@
+Sat Jan 18 15:51:45 1997  Richard Henderson  <richard@twiddle.rth.home>
+
+	* Don't play with usage_count directly, instead hand around
+	the module header and use the module macros.
+
 Fri May 17 00:00:00 1996  Leonard N. Zubkoff <lnz@dandelion.com>
 
 	* BusLogic Driver Version 2.0.3 Released.
@@ -40,10 +45,10 @@
 
 	* eata_dma.c (eata_queue)(eata_int_handler): Added code to do
 	command latency measurements if requested by root through
-	/proc/scsi interface. 
+	/proc/scsi interface.
 	Throughout Use HZ constant for time references.
 
-	* eata_pio.c: Use HZ constant for time references. 
+	* eata_pio.c: Use HZ constant for time references.
 
 	* aic7xxx.c, aic7xxx.h, aic7xxx_asm.c: Changed copyright from BSD
 	to GNU style.
@@ -54,7 +59,7 @@
 
 	* Linux 1.3.10 released.
 
-	* scsi_proc.c (dispatch_scsi_info): Removed unused variable.	
+	* scsi_proc.c (dispatch_scsi_info): Removed unused variable.
 
 Wed Jul 19 09:25:30 1995  Michael Neuffer  <neuffer@goofy.zdv.uni-mainz.de>
 
@@ -62,11 +67,11 @@
 
 	* scsi.c Blacklist concept expanded to 'support' more device
 	deficiencies. blacklist[] renamed to device_list[]
-	(scan_scsis): Code cleanup.  
-	
+	(scan_scsis): Code cleanup.
+
 	* scsi_debug.c (scsi_debug_proc_info): Added support to control
-	device lockup simulation via /proc/scsi interface.  
-	
+	device lockup simulation via /proc/scsi interface.
+
 
 Wed Jul 19 09:22:34 1995  Michael Neuffer  <neuffer@goofy.zdv.uni-mainz.de>
 
@@ -80,7 +85,7 @@
 
 	* Native wide, multichannel and /proc/scsi support now in official
 	kernel distribution.
- 
+
         * scsi.c/h, hosts.c/h et al reindented to increase readability
 	(especially on 80 column wide terminals).
 
@@ -94,7 +99,7 @@
 
 Thu Jun 20 15:20:27 1995  Michael Neuffer  <neuffer@goofy.zdv.uni-mainz.de>
 
-        * proc.c: Renamed to scsi_proc.c 
+        * proc.c: Renamed to scsi_proc.c
 
 Mon Jun 12 20:32:45 1995  Michael Neuffer  <neuffer@goofy.zdv.uni-mainz.de>
 
@@ -102,15 +107,15 @@
 
 Mon May 15 19:33:14 1995  Michael Neuffer  <neuffer@goofy.zdv.uni-mainz.de>
 
-	* scsi.c: Added native multichannel and wide scsi support. 
+	* scsi.c: Added native multichannel and wide scsi support.
 
-	* proc.c (dispatch_scsi_info) (build_proc_dir_hba_entries): 
-	Updated /proc/scsi interface.  
+	* proc.c (dispatch_scsi_info) (build_proc_dir_hba_entries):
+	Updated /proc/scsi interface.
 
 Thu May  4 17:58:48 1995  Michael Neuffer  <neuffer@goofy.zdv.uni-mainz.de>
 
 	* sd.c (requeue_sd_request): Zero out the scatterlist only if
-	scsi_malloc returned memory for it.	
+	scsi_malloc returned memory for it.
 
 	* eata_dma.c (register_HBA) (eata_queue): Add support for
 	large scatter/gather tables and set use_clustering accordingly
@@ -127,11 +132,11 @@
 	cards.
 
 	* eata_dma.c: Update to 2.3.5r. Modularize. Improved error handling
-        throughout and fixed bug interrupt routine which resulted in shifted 
+        throughout and fixed bug interrupt routine which resulted in shifted
         status bytes. Added blink LED state checks for ISA and EISA HBAs.
-        Memory management bug seems to have disappeared ==> increasing 
-        C_P_L_CURRENT_MAX to 16 for now. Decreasing C_P_L_DIV to 3 for 
-        performance reasons.  
+        Memory management bug seems to have disappeared ==> increasing
+        C_P_L_CURRENT_MAX to 16 for now. Decreasing C_P_L_DIV to 3 for
+        performance reasons.
 
 	* scsi.c: If we get a FMK, EOM, or ILI when attempting to scan
 	the bus, assume that it was just noise on the bus, and ignore
@@ -211,8 +216,8 @@
 	* hosts.h: Change io_port to long int from short.
 
  	* 53c7,8xx.c: crash on AEN fixed, SCSI reset is no longer a NOP,
- 	  NULL pointer panic on odd UDCs fixed, two bugs in diagnostic output 
- 	  fixed, should initialize correctly if left running, now loadable, 
+ 	  NULL pointer panic on odd UDCs fixed, two bugs in diagnostic output
+ 	  fixed, should initialize correctly if left running, now loadable,
   	  new memory allocation, extraneous diagnostic output suppressed,
  	  splx() replaced with save/restore flags. [ Drew ]
 
@@ -243,7 +248,7 @@
 
 	* eata.c: Update to 1.17.
 
-	* eata_dma.c: Update to 2.31a. Add more support for /proc/scsi. 
+	* eata_dma.c: Update to 2.31a. Add more support for /proc/scsi.
         Continuing modularization. Less crashes because of the bug in the
         memory management ==> increase C_P_L_CURRENT_MAX to 10
         and decrease C_P_L_DIV to 4.
@@ -315,13 +320,13 @@
 	* NCR5380.c: Update interrupt handler with new arglist.  Minor
 	cleanups.
 
-	* eata_dma.c: Begin to modularize.  Add hooks for /proc/scsi.  
+	* eata_dma.c: Begin to modularize.  Add hooks for /proc/scsi.
 	New version 2.3.0a. Add code in interrupt handler to allow
-        certain CDROM drivers to be detected which return a 
+        certain CDROM drivers to be detected which return a
         CHECK_CONDITION during SCSI bus scan. Add opcode check to get
         all DATA IN and DATA OUT phases right. Utilize HBA_interpret flag.
 	Improvements in HBA identification. Various other minor stuff.
-	
+
 	* hosts.c: Initialize ->dma_channel and ->io_port when registering
 	a new host.
 
@@ -370,7 +375,7 @@
 	* 53c7,8xx.h: Change SG size to 127.
 
 	* eata_dma: Update to version 2.10i. Remove bug in the registration
-        of multiple HBAs and channels. Minor other improvements and stylistic 
+        of multiple HBAs and channels. Minor other improvements and stylistic
         changes.
 
 	* scsi.c: Test for Toshiba XM-3401TA and exclude from detection
@@ -396,7 +401,7 @@
 	* aha152x.c: Update to version 1.8 from Juergen.
 
 	* eata_dma.c: Update from Michael Neuffer.
-        Remove hard limit of 2 commands per lun and make it better 
+        Remove hard limit of 2 commands per lun and make it better
         configurable. Improvements in HBA identification.
 
 	* in2000.c: Fix biosparam to support large disks.
@@ -413,7 +418,7 @@
 	* buslogic.c: Likewise.
 
 	* eata_dma.c: Use min of 2 cmd_per_lun for OCS_enabled boards.
-          
+
 	* scsi.c: Make RECOVERED_ERROR a SUGGEST_IS_OK.
 
 	* sd.c: Fail if we are opening a non-existent partition.
@@ -425,7 +430,7 @@
 	* sr_ioctl.c: Remove CDROMMULTISESSION_SYS ioctl.
 
 	* ultrastor.c: Fix bug in call to ultrastor_interrupt (wrong #args).
- 
+
 Mon Jan 16 07:18:23 1995  Eric Youngdale  (eric@andante)
 
 	* Linux 1.1.82 released.
@@ -635,7 +640,7 @@
 
 	* st.c: New version from Kai - add better support for backspace.
 
-	* u14-34f.c: New version from Dario.  Supports blocking. 
+	* u14-34f.c: New version from Dario.  Supports blocking.
 
 Wed Dec 14 14:46:30 1994  Eric Youngdale  (eric@andante)
 
@@ -733,7 +738,7 @@
 	status.
 
 	* README.st: Document this.
-	
+
 	* sr.c: Bugfix (do not subtract CD_BLOCK_OFFSET) for photo-cd
 	code.
 
@@ -811,7 +816,7 @@
 	* hosts.h: Add n_io_port to Scsi_Host (used when releasing module).
 
 	* hosts.c: Initialize block field.
-	
+
 	* in2000.c: Remove "static" declarations from exported functions.
 
 	* in2000.h: Likewise.
@@ -1083,7 +1088,7 @@
 
 	* constants.c: Fix typo (;;).
 
-	* g_NCR5380.c: 
+	* g_NCR5380.c:
 	* pas16.c:  Correct usage of NCR5380_init.
 
 	* scsi.c: Remove redundant (and unused variables).
@@ -1279,7 +1284,7 @@
 	when we discover a device.  Free pointer before returning.
 	Change scsi_devices into a linked list.
 
-	* scsi.c (scan_scsis): Change to only scan one host. 
+	* scsi.c (scan_scsis): Change to only scan one host.
 	(scsi_dev_init): Loop over all detected hosts, and scan them.
 
 	* hosts.c  (scsi_init_free): Change so that  number of extra bytes
@@ -1331,7 +1336,7 @@
 	larger SG lists.
 
 	* ultrastor.c: Changes from me - use scsi_register to register
-	host.  Add some consistency checking, 
+	host.  Add some consistency checking,
 
 Wed Jun  1 21:12:13 1994  Eric Youngdale  (eric@esp22)
 
@@ -1447,7 +1452,7 @@
 	* Linux 1.1.3 released.
 
 	* fdomain.c: Update to version 5.16 (Handle different FIFO sizes
-	better).  
+	better).
 
 Fri Apr  8 08:57:19 1994
 
@@ -1472,7 +1477,7 @@
 	* Linux 1.0, patchlevel 9 released.
 
 	* fdomain.c: Update to version 5.16 (Handle different FIFO sizes
-	better).  
+	better).
 
 Thu Apr  7 08:36:20 1994
 
@@ -1555,7 +1560,7 @@
 
 	* wd7000.c (wd_bases): Fix typo in last change.
 
-Mon Jan 24 17:37:23 1994  
+Mon Jan 24 17:37:23 1994
 
 	* pl14u released.
 
@@ -1569,25 +1574,25 @@
 
 	* NCR5380.c: Update from Drew - should work a lot better now.
 
-Sat Jan  8 15:13:10 1994  
+Sat Jan  8 15:13:10 1994
 
 	* pl14o released.
 
 	* sr_ioctl.c: Zero reserved field before trying to set audio volume.
 
-Wed Jan  5 13:21:10 1994  
+Wed Jan  5 13:21:10 1994
 
 	* pl14m released.
 
 	* fdomain.c: Update to version 5.8.  No functional difference???
 
-Tue Jan  4 14:26:13 1994  
+Tue Jan  4 14:26:13 1994
 
 	* pl14l released.
 
 	* ultrastor.c: Remove outl, inl functions (now provided elsewhere).
 
-Mon Jan  3 12:27:25 1994  
+Mon Jan  3 12:27:25 1994
 
 	* pl14k released.
 
@@ -1595,7 +1600,7 @@
 
 	* fdomain.c: Ditto.
 
-Wed Dec 29 09:47:20 1993  
+Wed Dec 29 09:47:20 1993
 
 	* pl14i released.
 
@@ -1603,7 +1608,7 @@
 
 	* st.c: Update of tape driver from Kai.
 
-Tue Dec 21 09:18:30 1993  
+Tue Dec 21 09:18:30 1993
 
 	* pl14g released.
 
@@ -1617,11 +1622,11 @@
 	do not report this properly).  Set needs_sector_size flag if
 	drive did not return sensible sector size.
 
-Mon Dec 13 12:13:47 1993  
+Mon Dec 13 12:13:47 1993
 
 	* aha152x.c: Update to version .101 from Juergen.
 
-Mon Nov 29 03:03:00 1993  
+Mon Nov 29 03:03:00 1993
 
         * linux 0.99.14 released.
 
@@ -1655,7 +1660,7 @@
 	* hosts.c: Support new low-level adapters.  Allow for more than
 	one adapter of a given type.
 
-	* hosts.h: Allow for more than one adapter of a given type. 
+	* hosts.h: Allow for more than one adapter of a given type.
 
 	* scsi.c:  Add scsi_device_types array, if NEEDS_JUMPSTART is set
 	after a low-level reset, start the command again.  Sort blacklist,
@@ -1699,7 +1704,7 @@
 	wd7000.c: Supply jumpstart flag for reset.  Do not round up
 	number of cylinders in biosparam function.
 
-Sat Sep  4 20:49:56 1993  
+Sat Sep  4 20:49:56 1993
 
     * 0.99pl13 released.
 
@@ -1721,7 +1726,7 @@
 
     * st.c: Change sense to unsigned.
 
-Thu Aug  5 11:59:18 1993  
+Thu Aug  5 11:59:18 1993
 
     * 0.99pl12 released.
 
@@ -1775,7 +1780,7 @@
     unchecked_isa_dma flag, even though this may not be needed (gets set
     later).
 
-Sat Jul 17 18:32:44 1993  
+Sat Jul 17 18:32:44 1993
 
     * 0.99pl11 released.  C++ compilable.
 
@@ -1807,7 +1812,7 @@
     * sr.c: Set up blocksize array for all discs.  Fix bug in freeing
     buffers if we run out of dma pool.
 
-Thu Jun  2 17:58:11 1993  
+Thu Jun  2 17:58:11 1993
 
     * 0.99pl10 released.
 
@@ -1833,7 +1838,7 @@
     * wd7000.c: Allow another condition for power on that are normal
     and do not require a panic.
 
-Thu Apr 22 23:10:11 1993  
+Thu Apr 22 23:10:11 1993
 
     * 0.99pl9 released.
 
@@ -1848,7 +1853,7 @@
     * scsi_ioctl.c: Further bugfix to ioctl_probe.
 
     * sd.c: Use long instead of int for last parameter in sd_ioctl.
-    Initialize transfersize and underflow fields.    
+    Initialize transfersize and underflow fields.
 
     * sd_ioctl.c: Ditto for sd_ioctl(,,,,);
 
@@ -1866,7 +1871,7 @@
 
     * wd7000.c: Change () to (void) in wd7000_enable_dma.
 
-Wed Mar 31 16:36:25 1993  
+Wed Mar 31 16:36:25 1993
 
     * 0.99pl8 released.
 
@@ -1912,7 +1917,7 @@
 
 
 
-Sat Mar 13 17:31:29 1993  
+Sat Mar 13 17:31:29 1993
 
     * 0.99pl7 released.
 
@@ -1928,7 +1933,7 @@
 
     * ultrastor.c: Update to use scatter-gather.
 
-Sat Feb 20 17:57:15 1993  
+Sat Feb 20 17:57:15 1993
 
     * 0.99pl6 released.
 
@@ -1943,7 +1948,7 @@
 
     * wd7000.c: Undo previous change.
 
-Sat Feb  6 11:20:43 1993  
+Sat Feb  6 11:20:43 1993
 
     * 0.99pl5 released.
 
@@ -1952,7 +1957,7 @@
     * wd7000.c: Check at more addresses for bios.  Fix bug in biosparam
     (heads & sectors turned around).
 
-Wed Jan 20 18:13:59 1993  
+Wed Jan 20 18:13:59 1993
 
     * 0.99pl4 released.
 
@@ -1965,7 +1970,7 @@
     with Syquest cartridge drives (used to crash kernel), because
     they do not disconnect with large data transfers.
 
-Tue Jan 12 14:33:36 1993  
+Tue Jan 12 14:33:36 1993
 
     * 0.99pl3 released.
 
@@ -1980,7 +1985,7 @@
 
     * st.c: Changes from Kai.
 
-Wed Dec 30 20:03:47 1992  
+Wed Dec 30 20:03:47 1992
 
     * 0.99pl2 released.
 
@@ -2001,7 +2006,7 @@
 
     * wd7000.c (wd7000_set_sync): Remove redundant function.
 
-Sun Dec 20 16:26:24 1992  
+Sun Dec 20 16:26:24 1992
 
     * 0.99pl1 released.
 
@@ -2013,6 +2018,6 @@
     * st.c: Patches from Kai - change timeout values, improve end of tape
     handling.
 
-Sun Dec 13 18:15:23 1992  
+Sun Dec 13 18:15:23 1992
 
     * 0.99 kernel released.  Baseline for this ChangeLog.
diff -u --recursive --new-file v2.1.22/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile
--- v2.1.22/linux/drivers/scsi/Makefile	Wed Jan 15 19:45:41 1997
+++ linux/drivers/scsi/Makefile	Fri Jan 24 19:35:50 1997
@@ -392,7 +392,7 @@
 	./aic7xxx_asm -o $@ aic7xxx.seq
 
 seagate.o: seagate.c
-	$(CC) $(CFLAGS) -DARBITRATE -DSLOW_HANDSHAKE -DFAST32 -c seagate.c 
+	$(CC) $(CFLAGS) -DARBITRATE -DSLOW_HANDSHAKE -DFAST32 -DPARITY -c seagate.c 
 
 # For debugging, use the -g flag
 53c7,8xx.o : 53c7,8xx.c
diff -u --recursive --new-file v2.1.22/linux/drivers/scsi/a2091.h linux/drivers/scsi/a2091.h
--- v2.1.22/linux/drivers/scsi/a2091.h	Sun Dec 22 16:37:36 1996
+++ linux/drivers/scsi/a2091.h	Sun Jan 26 12:07:18 1997
@@ -1,6 +1,6 @@
 #ifndef A2091_H
 
-/* $Id: a2091.h,v 1.4 1996/04/25 20:57:48 root Exp root $
+/* $Id: a2091.h,v 1.4 1997/01/19 23:07:09 davem Exp $
  *
  * Header file for the Commodore A2091 Zorro II SCSI controller for Linux
  *
@@ -34,7 +34,7 @@
 extern struct proc_dir_entry proc_scsi_a2091;
 
 #define A2091_SCSI {  /* next */                NULL,            \
-		      /* usage_count */         NULL,	         \
+		      /* module */         NULL,	         \
 		      /* proc_dir_entry */      &proc_scsi_a2091, \
 		      /* proc_info */           NULL,            \
 		      /* name */                "Commodore A2091/A590 SCSI", \
@@ -59,7 +59,7 @@
 /*
  * if the transfer address ANDed with this results in a non-zero
  * result, then we can't use DMA.
- */ 
+ */
 #define A2091_XFER_MASK  (0xff000001)
 
 typedef struct {
diff -u --recursive --new-file v2.1.22/linux/drivers/scsi/a3000.h linux/drivers/scsi/a3000.h
--- v2.1.22/linux/drivers/scsi/a3000.h	Sun Dec 22 16:37:36 1996
+++ linux/drivers/scsi/a3000.h	Sun Jan 26 12:07:18 1997
@@ -1,6 +1,6 @@
 #ifndef A3000_H
 
-/* $Id: a3000.h,v 1.3 1996/04/25 20:58:09 root Exp root $
+/* $Id: a3000.h,v 1.4 1997/01/19 23:07:10 davem Exp $
  *
  * Header file for the Amiga 3000 built-in SCSI controller for Linux
  *
@@ -34,7 +34,7 @@
 extern struct proc_dir_entry proc_scsi_a3000;
 
 #define A3000_SCSI {  /* next */                NULL,            \
-		      /* usage_count */         NULL,	         \
+		      /* module */         NULL,	         \
 		      /* proc_dir_entry */      &proc_scsi_a3000, \
 		      /* proc_info */           NULL,            \
 		      /* name */                "Amiga 3000 built-in SCSI", \
@@ -59,7 +59,7 @@
 /*
  * if the transfer address ANDed with this results in a non-zero
  * result, then we can't use DMA.
- */ 
+ */
 #define A3000_XFER_MASK  (0x00000003)
 
 typedef struct {
diff -u --recursive --new-file v2.1.22/linux/drivers/scsi/advansys.h linux/drivers/scsi/advansys.h
--- v2.1.22/linux/drivers/scsi/advansys.h	Fri Sep 27 07:52:57 1996
+++ linux/drivers/scsi/advansys.h	Sun Jan 26 12:07:18 1997
@@ -1,4 +1,4 @@
-/* $Id: advansys.h,v 1.12 1996/09/23 18:12:02 bobf Exp bobf $ */
+/* $Id: advansys.h,v 1.5 1997/01/19 23:07:10 davem Exp $ */
 /*
  * advansys.h - Linux Host Driver for AdvanSys SCSI Adapters
  *
@@ -57,7 +57,7 @@
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
 #define ADVANSYS { \
 	NULL,					/* struct SHT *next */ \
-	NULL,					/* int *usage_count */ \
+	NULL,					/* struct module *module */ \
 	"advansys",				/* char *name */ \
 	advansys_detect,		/* int (*detect)(struct SHT *) */ \
 	advansys_release,		/* int (*release)(struct Scsi_Host *) */ \
@@ -95,7 +95,7 @@
 #else /* version >= v1.3.0 */
 #define ADVANSYS { \
 	NULL,					/* struct SHT *next */ \
-	NULL,					/* long *usage_count */ \
+	NULL,					/* struct module *module */ \
 	&proc_scsi_advansys,	/* struct proc_dir_entry *proc_dir */ \
 	advansys_proc_info,	\
 			/* int (*proc_info)(char *, char **, off_t, int, int, int) */ \
diff -u --recursive --new-file v2.1.22/linux/drivers/scsi/aha152x.h linux/drivers/scsi/aha152x.h
--- v2.1.22/linux/drivers/scsi/aha152x.h	Sun Sep  8 19:45:51 1996
+++ linux/drivers/scsi/aha152x.h	Sun Jan 26 12:07:18 1997
@@ -2,7 +2,7 @@
 #define _AHA152X_H
 
 /*
- * $Id: aha152x.h,v 1.18 1996/09/07 20:10:26 fischer Exp $
+ * $Id: aha152x.h,v 1.7 1997/01/19 23:07:11 davem Exp $
  */
 
 #if defined(__KERNEL__)
@@ -23,13 +23,13 @@
    (unless we support more than 1 cmd_per_lun this should do) */
 #define AHA152X_MAXQUEUE 7
 
-#define AHA152X_REVID "Adaptec 152x SCSI driver; $Revision: 1.18 $"
+#define AHA152X_REVID "Adaptec 152x SCSI driver; $Revision: 1.7 $"
 
 extern struct proc_dir_entry proc_scsi_aha152x;
 
 /* Initial value of Scsi_Host entry */
 #define AHA152X { /* next */               0, \
-                  /* usage_count */        0, \
+                  /* module */             0, \
                   /* proc_dir */           &proc_scsi_aha152x, \
                   /* proc_info */          aha152x_proc_info, \
                   /* name */               AHA152X_REVID, \
diff -u --recursive --new-file v2.1.22/linux/drivers/scsi/esp.h linux/drivers/scsi/esp.h
--- v2.1.22/linux/drivers/scsi/esp.h	Wed Dec 18 15:58:51 1996
+++ linux/drivers/scsi/esp.h	Sun Jan 26 12:07:18 1997
@@ -396,7 +396,7 @@
 
 #define SCSI_SPARC_ESP {                                                               \
 /* struct SHT *next */                                         NULL,                   \
-/* long *usage_count */                                        NULL,                   \
+/* struct module *module */                                    NULL,                   \
 /* struct proc_dir_entry *proc_dir */                          &proc_scsi_esp,         \
 /* int (*proc_info)(char *, char **, off_t, int, int, int) */  &esp_proc_info,         \
 /* const char *name */                                         "Sun ESP 100/100a/200", \
diff -u --recursive --new-file v2.1.22/linux/drivers/scsi/gvp11.h linux/drivers/scsi/gvp11.h
--- v2.1.22/linux/drivers/scsi/gvp11.h	Sun Dec 22 16:37:37 1996
+++ linux/drivers/scsi/gvp11.h	Sun Jan 26 12:07:18 1997
@@ -1,6 +1,6 @@
 #ifndef GVP11_H
 
-/* $Id: gvp11.h,v 1.5 1996/04/25 20:58:31 root Exp root $
+/* $Id: gvp11.h,v 1.4 1997/01/19 23:07:12 davem Exp $
  *
  * Header file for the GVP Series II SCSI controller for Linux
  *
@@ -35,7 +35,7 @@
 extern struct proc_dir_entry proc_scsi_gvp11;
 
 #define GVP11_SCSI {  /* next */                NULL,            \
-		      /* usage_count */         NULL,	         \
+		      /* module */              NULL,	         \
                       /* proc_dir_entry */      &proc_scsi_gvp11, \
 		      /* proc_info */           NULL,            \
 		      /* name */                "GVP Series II SCSI", \
@@ -60,7 +60,7 @@
 /*
  * if the transfer address ANDed with this results in a non-zero
  * result, then we can't use DMA.
- */ 
+ */
 #define GVP11_XFER_MASK  (0xff000001)
 
 typedef struct {
diff -u --recursive --new-file v2.1.22/linux/drivers/scsi/hosts.h linux/drivers/scsi/hosts.h
--- v2.1.22/linux/drivers/scsi/hosts.h	Mon Jul  1 20:06:05 1996
+++ linux/drivers/scsi/hosts.h	Sun Jan 26 12:07:18 1997
@@ -1,5 +1,5 @@
 /*
- *  hosts.h Copyright (C) 1992 Drew Eckhardt 
+ *  hosts.h Copyright (C) 1992 Drew Eckhardt
  *          Copyright (C) 1993, 1994, 1995 Eric Youngdale
  *
  *  mid to low-level SCSI driver interface header
@@ -11,7 +11,7 @@
  *	 Modified by Eric Youngdale eric@aib.com to
  *	 add scatter-gather, multiple outstanding request, and other
  *	 enhancements.
- * 
+ *
  *  Further modified by Eric Youngdale to support multiple host adapters
  *  of the same type.
  */
@@ -20,13 +20,13 @@
 #define _HOSTS_H
 
 /*
-    $Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/hosts.h,v 1.3 1993/09/24 12:21:00 drew Exp drew $
+    $Header: /vger/u4/cvs/linux/drivers/scsi/hosts.h,v 1.6 1997/01/19 23:07:13 davem Exp $
 */
 
 #include <linux/proc_fs.h>
 
 /* It is senseless to set SG_ALL any higher than this - the performance
- *  does not get any better, and it wastes memory 
+ *  does not get any better, and it wastes memory
  */
 #define SG_NONE 0
 #define SG_ALL 0xff
@@ -53,18 +53,18 @@
 
 typedef struct	SHT
 {
-    
+
     /* Used with loadable modules so we can construct a linked list. */
     struct SHT * next;
-    
+
     /* Used with loadable modules so that we know when it is safe to unload */
-    long * usage_count;
-    
+    struct module * module;
+
     /* The pointer to the /proc/scsi directory entry */
     struct proc_dir_entry *proc_dir;
 
     /* proc-fs info function.
-     * Can be used to export driver statistics and other infos to the world 
+     * Can be used to export driver statistics and other infos to the world
      * outside the kernel ie. userspace and it also provides an interface
      * to feed the driver with information. Check eata_dma_proc.c for reference
      */
@@ -75,7 +75,7 @@
      * device detected.
      */
     const char *name;
-    
+
     /*
      * The detect function shall return non zero on detection,
      * indicating the number of host adapters of this particular
@@ -83,7 +83,7 @@
      * initialize all data necessary for this particular
      * SCSI driver.  It is passed the host number, so this host
      * knows where the first entry is in the scsi_hosts[] array.
-     * 
+     *
      * Note that the detect routine MUST not call any of the mid level
      * functions to queue commands because things are not guaranteed
      * to be set up yet.  The detect routine can send commands to
@@ -91,12 +91,12 @@
      * passed to scsi.c in the processing of the command.  Note
      * especially that scsi_malloc/scsi_free must not be called.
      */
-    int (* detect)(struct SHT *); 
-    
+    int (* detect)(struct SHT *);
+
     /* Used with loadable modules to unload the host structures.  Note:
      * there is a default action built into the modules code which may
      * be sufficient for most host adapters.  Thus you may not have to supply
-     * this at all. 
+     * this at all.
      */
     int (*release)(struct Scsi_Host *);
 
@@ -106,12 +106,12 @@
      * the name field will be used instead.
      */
     const char *(* info)(struct Scsi_Host *);
-    
+
     /*
-     * The command function takes a target, a command (this is a SCSI 
-     * command formatted as per the SCSI spec, nothing strange), a 
+     * The command function takes a target, a command (this is a SCSI
+     * command formatted as per the SCSI spec, nothing strange), a
      * data buffer pointer, and data buffer length pointer.  The return
-     * is a status int, bit fielded as follows : 
+     * is a status int, bit fielded as follows :
      * Byte What
      * 0    SCSI status code
      * 1    SCSI 1 byte message
@@ -123,31 +123,31 @@
     /*
      * The QueueCommand function works in a similar manner
      * to the command function.	 It takes an additional parameter,
-     * void (* done)(int host, int code) which is passed the host 
-     * # and exit result when the command is complete.	
+     * void (* done)(int host, int code) which is passed the host
+     * # and exit result when the command is complete.
      * Host number is the POSITION IN THE hosts array of THIS
      * host adapter.
      */
     int (* queuecommand)(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-    
+
     /*
-     * Since the mid level driver handles time outs, etc, we want to 
-     * be able to abort the current command.  Abort returns 0 if the 
+     * Since the mid level driver handles time outs, etc, we want to
+     * be able to abort the current command.  Abort returns 0 if the
      * abortion was successful.	 The field SCpnt->abort reason
      * can be filled in with the appropriate reason why we wanted
      * the abort in the first place, and this will be used
      * in the mid-level code instead of the host_byte().
-     * If non-zero, the code passed to it 
-     * will be used as the return code, otherwise 
+     * If non-zero, the code passed to it
+     * will be used as the return code, otherwise
      * DID_ABORT  should be returned.
-     * 
-     * Note that the scsi driver should "clean up" after itself, 
-     * resetting the bus, etc.	if necessary. 
+     *
+     * Note that the scsi driver should "clean up" after itself,
+     * resetting the bus, etc.	if necessary.
      */
     int (* abort)(Scsi_Cmnd *);
 
     /*
-     * The reset function will reset the SCSI bus.  Any executing 
+     * The reset function will reset the SCSI bus.  Any executing
      * commands should fail with a DID_RESET in the host byte.
      * The Scsi_Cmnd  is passed so that the reset routine can figure
      * out which host adapter should be reset, and also which command
@@ -155,24 +155,24 @@
      * the first place.	 Some hosts do not implement a reset function,
      * and these hosts must call scsi_request_sense(SCpnt) to keep
      * the command alive.
-     */ 
+     */
     int (* reset)(Scsi_Cmnd *, unsigned int);
 
     /*
      * This function is used to select synchronous communications,
      * which will result in a higher data throughput.  Not implemented
      * yet.
-     */ 
+     */
     int (* slave_attach)(int, int);
-    
+
     /*
      * This function determines the bios parameters for a given
      * harddisk.  These tend to be numbers that are made up by
      * the host adapter.  Parameters:
      * size, device number, list (heads, sectors, cylinders)
-     */ 
+     */
     int (* bios_param)(Disk *, kdev_t, int []);
-    
+
     /*
      * This determines if we will use a non-interrupt driven
      * or an interrupt driven scheme,  It is set to the maximum number
@@ -181,10 +181,10 @@
     int can_queue;
 
     /*
-     * In many instances, especially where disconnect / reconnect are 
-     * supported, our host also has an ID on the SCSI bus.  If this is 
+     * In many instances, especially where disconnect / reconnect are
+     * supported, our host also has an ID on the SCSI bus.  If this is
      * the case, then it must be reserved.  Please set this_id to -1 if
-     * your setup is in single initiator mode, and the host lacks an 
+     * your setup is in single initiator mode, and the host lacks an
      * ID.
      */
     int this_id;
@@ -210,13 +210,13 @@
      * present contains counter indicating how many boards of this
      * type were found when we did the scan.
      */
-    unsigned char present;  
-    
+    unsigned char present;
+
     /*
      * true if this host adapter uses unchecked DMA onto an ISA bus.
      */
     unsigned unchecked_isa_dma:1;
-    
+
     /*
      * true if this host adapter can make good use of clustering.
      * I originally thought that if the tablesize was large that it
@@ -230,7 +230,7 @@
 } Scsi_Host_Template;
 
 /*
- * The scsi_hosts array is the array containing the data for all 
+ * The scsi_hosts array is the array containing the data for all
  * possible <supported> scsi hosts.   This is similar to the
  * Scsi_Host_Template, except that we have one entry for each
  * actual physical host adapter on the system, stored as a linked
@@ -248,32 +248,32 @@
     struct wait_queue *host_wait;
     Scsi_Cmnd *host_queue;
     Scsi_Host_Template * hostt;
-    
+
     /*
      *	These three parameters can be used to allow for wide scsi,
-     *	and for host adapters that support multiple busses 
+     *	and for host adapters that support multiple busses
      *	The first two should be set to 1 more than the actual max id
      *	or lun (i.e. 8 for normal systems).
      */
     unsigned int max_id;
     unsigned int max_lun;
     unsigned int max_channel;
-   
+
     /*
      * Pointer to a circularly linked list - this indicates the hosts
      * that should be locked out of performing I/O while we have an active
-     * command on this host. 
+     * command on this host.
      */
     struct Scsi_Host * block;
     unsigned wish_block:1;
-    
+
     /* These parameters should be set by the detect routine */
     unsigned char *base;
     unsigned int  io_port;
     unsigned char n_io_port;
     unsigned char irq;
     unsigned char dma_channel;
-    
+
     /*
      * This is a unique identifier that must be assigned so that we
      * have some way of identifying each detected host adapter properly
@@ -282,12 +282,12 @@
      * initialized to 0 in scsi_register.
      */
     unsigned int unique_id;
-    
+
     /*
      * The rest can be copied from the template, or specifically
      * initialized, as required.
      */
-    
+
     int this_id;
     int can_queue;
     short cmd_per_lun;
@@ -298,7 +298,7 @@
      * True if this host was loaded as a loadable module
      */
     unsigned loaded_as_module:1;
- 
+
     void (*select_queue_depths)(struct Scsi_Host *, Scsi_Device *);
 
     unsigned long hostdata[0];  /* Used for storage of host specific stuff */
@@ -316,11 +316,11 @@
  *  scsi_init initializes the scsi hosts.
  */
 
-/* 
+/*
  * We use these goofy things because the MM is not set up when we init
  * the scsi subsystem.	By using these functions we can write code that
  * looks normal.  Also, it makes it possible to use the same code for a
- * loadable module. 
+ * loadable module.
  */
 
 extern void * scsi_init_malloc(unsigned int size, int priority);
@@ -340,7 +340,7 @@
     struct Scsi_Device_Template * next;
     const char * name;
     const char * tag;
-    long * usage_count;		  /* Used for loadable modules */
+    struct module * module;	  /* Used for loadable modules */
     unsigned char scsi_type;
     unsigned char major;
     unsigned char nr_dev;	  /* Number currently attached */
@@ -375,8 +375,8 @@
 
 /*
  * This is an ugly hack.  If we expect to be able to load devices at run time,
- * we need to leave extra room in some of the data structures.	Doing a 
- * realloc to enlarge the structures would be riddled with race conditions, 
+ * we need to leave extra room in some of the data structures.	Doing a
+ * realloc to enlarge the structures would be riddled with race conditions,
  * so until a better solution is discovered, we use this crude approach
  */
 #define SD_EXTRA_DEVS 2
diff -u --recursive --new-file v2.1.22/linux/drivers/scsi/ibmmca.h linux/drivers/scsi/ibmmca.h
--- v2.1.22/linux/drivers/scsi/ibmmca.h	Thu Dec 12 19:37:07 1996
+++ linux/drivers/scsi/ibmmca.h	Sun Jan 26 12:07:18 1997
@@ -2,7 +2,7 @@
 #ifndef _IBMMCA_H
 #define _IBMMCA_H
 
-/* 
+/*
  * Low Level Driver for the IBM Microchannel SCSI Subsystem
  */
 
@@ -20,7 +20,7 @@
 /*initialization for Scsi_host_template type */
 #define IBMMCA {                                      \
           NULL,                 /*next*/              \
-          NULL,                 /*usage_count*/       \
+          NULL,                 /*module*/	      \
           &proc_scsi_ibmmca,    /*proc_dir*/          \
           NULL,                 /*proc info fn*/      \
           "IBMMCA",             /*name*/              \
diff -u --recursive --new-file v2.1.22/linux/drivers/scsi/ide-scsi.c linux/drivers/scsi/ide-scsi.c
--- v2.1.22/linux/drivers/scsi/ide-scsi.c	Mon Dec 30 15:39:11 1996
+++ linux/drivers/scsi/ide-scsi.c	Sun Jan 26 12:07:18 1997
@@ -1,7 +1,7 @@
 /*
- * linux/drivers/scsi/ide-scsi.c	Version 0.1 - ALPHA	Dec   3, 1996
+ * linux/drivers/scsi/ide-scsi.c	Version 0.2 - ALPHA	Jan  26, 1997
  *
- * Copyright (C) 1996 Gadi Oxman <gadio@netvision.net.il>
+ * Copyright (C) 1996, 1997 Gadi Oxman <gadio@netvision.net.il>
  */
 
 /*
@@ -11,6 +11,11 @@
  * native IDE ATAPI drivers.
  *
  * Ver 0.1   Dec  3 96   Initial version.
+ * Ver 0.2   Jan 26 97   Fixed bug in cleanup_module() and added emulation
+ *                        of MODE_SENSE_6/MODE_SELECT_6 for cdroms. Thanks
+ *                        to Janos Farkas for pointing this out.
+ *                       Avoid using bitfields in structures for m68k.
+ *                       Added Scather/Gather and DMA support.
  */
 
 #include <linux/module.h>
@@ -44,49 +49,40 @@
 	struct request *rq;			/* The corresponding request */
 	byte *buffer;				/* Data buffer */
 	byte *current_position;			/* Pointer into the above buffer */
+	struct scatterlist *sg;			/* Scather gather table */
+	int b_count;				/* Bytes transferred from current entry */
 	Scsi_Cmnd *scsi_cmd;			/* SCSI command */
 	void (*done)(Scsi_Cmnd *);		/* Scsi completion routine */
+	unsigned int flags;			/* Status/Action flags */
 } idescsi_pc_t;
 
+/*
+ *	Packet command status bits.
+ */
+#define PC_DMA_IN_PROGRESS		0	/* 1 while DMA in progress */
+#define PC_WRITING			1	/* Data direction */
+
 typedef struct {
 	ide_drive_t *drive;
 	idescsi_pc_t *pc;			/* Current packet command */
 	unsigned int flags;			/* Status/Action flags */
 } idescsi_scsi_t;
 
+/*
+ *	Per ATAPI device status bits.
+ */
 #define IDESCSI_DRQ_INTERRUPT		0	/* DRQ interrupt device */
+
+/*
+ *	ide-scsi requests.
+ */
 #define IDESCSI_PC_RQ			90
 
-typedef union {
-	unsigned all			:8;
-	struct {
-		unsigned check		:1;	/* Error occurred */
-		unsigned idx		:1;	/* Reserved */
-		unsigned corr		:1;	/* Correctable error occurred */
-		unsigned drq		:1;	/* Data is request by the device */
-		unsigned dsc		:1;	/* Media access command finished */
-		unsigned reserved5	:1;	/* Reserved */
-		unsigned drdy		:1;	/* Ignored for ATAPI commands (ready to accept ATA command) */
-		unsigned bsy		:1;	/* The device has access to the command block */
-	} b;
-} idescsi_status_reg_t;
-
-typedef union {
-	unsigned all			:16;
-	struct {
-		unsigned low		:8;	/* LSB */
-		unsigned high		:8;	/* MSB */
-	} b;
-} idescsi_bcount_reg_t;
-
-typedef union {
-	unsigned all			:8;
-	struct {
-		unsigned cod		:1;	/* Information transferred is command (1) or data (0) */
-		unsigned io		:1;	/* The device requests us to read (1) or write (0) */
-		unsigned reserved	:6;	/* Reserved */
-	} b;
-} idescsi_ireason_reg_t;
+/*
+ *	Bits of the interrupt reason register.
+ */
+#define IDESCSI_IREASON_COD	0x1		/* Information transferred is command */
+#define IDESCSI_IREASON_IO	0x2		/* The device requests us to read */
 
 static void idescsi_discard_data (ide_drive_t *drive, unsigned int bcount)
 {
@@ -94,6 +90,107 @@
 		IN_BYTE (IDE_DATA_REG);
 }
 
+static void idescsi_output_zeros (ide_drive_t *drive, unsigned int bcount)
+{
+	while (bcount--)
+		OUT_BYTE (0, IDE_DATA_REG);
+}
+
+/*
+ *	PIO data transfer routines using the scather gather table.
+ */
+static void idescsi_input_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsigned int bcount)
+{
+	int count;
+
+	while (bcount) {
+		if (pc->sg - (struct scatterlist *) pc->scsi_cmd->request_buffer > pc->scsi_cmd->use_sg) {
+			printk (KERN_ERR "ide-scsi: scather gather table too small, discarding data\n");
+			idescsi_discard_data (drive, bcount);
+			return;
+		}
+		count = IDE_MIN (pc->sg->length - pc->b_count, bcount);
+		atapi_input_bytes (drive, pc->sg->address + pc->b_count, count);
+		bcount -= count; pc->b_count += count;
+		if (pc->b_count == pc->sg->length) {
+			pc->sg++;
+			pc->b_count = 0;
+		}
+	}
+}
+
+static void idescsi_output_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsigned int bcount)
+{
+	int count;
+
+	while (bcount) {
+		if (pc->sg - (struct scatterlist *) pc->scsi_cmd->request_buffer > pc->scsi_cmd->use_sg) {
+			printk (KERN_ERR "ide-scsi: scather gather table too small, padding with zeros\n");
+			idescsi_output_zeros (drive, bcount);
+			return;
+		}
+		count = IDE_MIN (pc->sg->length - pc->b_count, bcount);
+		atapi_output_bytes (drive, pc->sg->address + pc->b_count, count);
+		bcount -= count; pc->b_count += count;
+		if (pc->b_count == pc->sg->length) {
+			pc->sg++;
+			pc->b_count = 0;
+		}
+	}
+}
+
+/*
+ *	Most of the SCSI commands are supported directly by ATAPI devices.
+ *	idescsi_transform_pc handles the few exceptions.
+ */
+static inline void idescsi_transform_pc1 (ide_drive_t *drive, idescsi_pc_t *pc)
+{
+	u8 *c = pc->c, *buf = pc->buffer, *sc = pc->scsi_cmd->cmnd;
+	int i;
+
+	if (drive->media == ide_cdrom) {
+		if (c[0] == READ_6) {
+			c[8] = c[4];		c[5] = c[3];		c[4] = c[2];
+			c[3] = c[1] & 0x1f;	c[2] = 0;		c[1] &= 0xe0;
+			c[0] = READ_10;
+		}
+		if (c[0] == MODE_SENSE || (c[0] == MODE_SELECT && buf[3] == 8)) {
+			pc->request_transfer -= 4;
+			memset (c, 0, 12);
+			c[0] = sc[0] | 0x40;	c[2] = sc[2];		c[8] = sc[4] - 4;
+			if (c[0] == MODE_SENSE_10) return;
+			for (i = 0; i <= 7; i++) buf[i] = 0;
+			for (i = 8; i < pc->buffer_size - 4; i++) buf[i] = buf[i + 4];
+		}
+	}
+}
+
+static inline void idescsi_transform_pc2 (ide_drive_t *drive, idescsi_pc_t *pc)
+{
+	u8 *buf = pc->buffer;
+	int i;
+
+	if (drive->media == ide_cdrom) {
+		if (pc->c[0] == MODE_SENSE_10 && pc->scsi_cmd->cmnd[0] == MODE_SENSE) {
+			buf[0] = buf[1];	buf[1] = buf[2];
+			buf[2] = 0;		buf[3] = 8;
+			for (i = pc->buffer_size - 1; i >= 12; i--) buf[i] = buf[i - 4];
+			for (i = 11; i >= 4; i--) buf[i] = 0;
+		}
+	}
+}
+
+static inline void idescsi_free_bh (struct buffer_head *bh)
+{
+	struct buffer_head *bhp;
+
+	while (bh) {
+		bhp = bh;
+		bh = bh->b_reqnext;
+		kfree (bhp);
+	}
+}
+
 static void idescsi_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
 {
 	ide_drive_t *drive = hwgroup->drive;
@@ -121,53 +218,64 @@
 		printk ("ide-scsi: %s: success for %lu\n", drive->name, pc->scsi_cmd->serial_number);
 #endif /* IDESCSI_DEBUG_LOG */
 		pc->scsi_cmd->result = DID_OK << 16;
+		idescsi_transform_pc2 (drive, pc);
 	}
 	pc->done(pc->scsi_cmd);
+	idescsi_free_bh (rq->bh);
 	kfree(pc); kfree(rq);
 	scsi->pc = NULL;
 }
 
+/*
+ *	Our interrupt handler.
+ */
 static void idescsi_pc_intr (ide_drive_t *drive)
 {
 	idescsi_scsi_t *scsi = drive->driver_data;
-	idescsi_status_reg_t status;
-	idescsi_bcount_reg_t bcount;
-	idescsi_ireason_reg_t ireason;
+	byte status, ireason;
+	int bcount;
 	idescsi_pc_t *pc=scsi->pc;
 	struct request *rq = pc->rq;
 	unsigned int temp;
 
 #if IDESCSI_DEBUG_LOG
 	printk (KERN_INFO "ide-scsi: Reached idescsi_pc_intr interrupt handler\n");
-#endif /* IDESCSI_DEBUG_LOG */	
+#endif /* IDESCSI_DEBUG_LOG */
 
-	status.all = GET_STAT();					/* Clear the interrupt */
+	if (clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
+#if IDESCSI_DEBUG_LOG
+		printk ("ide-scsi: %s: DMA complete\n", drive->name);
+#endif /* IDESCSI_DEBUG_LOG */
+		pc->actually_transferred=pc->request_transfer;
+		(void) (HWIF(drive)->dmaproc(ide_dma_abort, drive));
+	}
 
-	if (!status.b.drq) {						/* No more interrupts */
+	status = GET_STAT();						/* Clear the interrupt */
+
+	if ((status & DRQ_STAT) == 0) {					/* No more interrupts */
 #if IDESCSI_DEBUG_LOG
 		printk (KERN_INFO "Packet command completed, %d bytes transferred\n", pc->actually_transferred);
 #endif /* IDESCSI_DEBUG_LOG */
 		ide_sti();
-		if (status.b.check)
+		if (status & ERR_STAT)
 			rq->errors++;
 		idescsi_end_request (1, HWGROUP(drive));
 		return;
 	}
-	bcount.b.high=IN_BYTE (IDE_BCOUNTH_REG);
-       	bcount.b.low=IN_BYTE (IDE_BCOUNTL_REG);
-	ireason.all=IN_BYTE (IDE_IREASON_REG);
+	bcount = IN_BYTE (IDE_BCOUNTH_REG) << 8 | IN_BYTE (IDE_BCOUNTL_REG);
+	ireason = IN_BYTE (IDE_IREASON_REG);
 
-	if (ireason.b.cod) {
+	if (ireason & IDESCSI_IREASON_COD) {
 		printk (KERN_ERR "ide-scsi: CoD != 0 in idescsi_pc_intr\n");
 		ide_do_reset (drive);
 		return;
 	}
-	if (ireason.b.io) {
-		temp = pc->actually_transferred + bcount.all;
+	if (ireason & IDESCSI_IREASON_IO) {
+		temp = pc->actually_transferred + bcount;
 		if ( temp > pc->request_transfer) {
 			if (temp > pc->buffer_size) {
 				printk (KERN_ERR "ide-scsi: The scsi wants to send us more data than expected - discarding data\n");
-				idescsi_discard_data (drive,bcount.all);
+				idescsi_discard_data (drive,bcount);
 				ide_set_handler (drive,&idescsi_pc_intr,WAIT_CMD);
 				return;
 			}
@@ -176,12 +284,19 @@
 #endif /* IDESCSI_DEBUG_LOG */
 		}
 	}
-	if (ireason.b.io)
-		atapi_input_bytes (drive,pc->current_position,bcount.all);	/* Read the current buffer */
-	else
-		atapi_output_bytes (drive,pc->current_position,bcount.all);	/* Write the current buffer */
-	pc->actually_transferred+=bcount.all;				/* Update the current position */
-	pc->current_position+=bcount.all;
+	if (ireason & IDESCSI_IREASON_IO) {
+		if (pc->sg)
+			idescsi_input_buffers (drive, pc, bcount);
+		else
+			atapi_input_bytes (drive,pc->current_position,bcount);
+	} else {
+		if (pc->sg)
+			idescsi_output_buffers (drive, pc, bcount);
+		else
+			atapi_output_bytes (drive,pc->current_position,bcount);
+	}
+	pc->actually_transferred+=bcount;				/* Update the current position */
+	pc->current_position+=bcount;
 
 	ide_set_handler (drive,&idescsi_pc_intr,WAIT_CMD);		/* And set the interrupt handler again */
 }
@@ -189,14 +304,14 @@
 static void idescsi_transfer_pc (ide_drive_t *drive)
 {
 	idescsi_scsi_t *scsi = drive->driver_data;
-	idescsi_ireason_reg_t ireason;
+	byte ireason;
 
 	if (ide_wait_stat (drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
 		printk (KERN_ERR "ide-scsi: Strange, packet command initiated yet DRQ isn't asserted\n");
 		return;
 	}
-	ireason.all=IN_BYTE (IDE_IREASON_REG);
-	if (!ireason.b.cod || ireason.b.io) {
+	ireason = IN_BYTE (IDE_IREASON_REG);
+	if ((ireason & (IDESCSI_IREASON_IO | IDESCSI_IREASON_COD)) != IDESCSI_IREASON_COD) {
 		printk (KERN_ERR "ide-scsi: (IO,CoD) != (0,1) while issuing a packet command\n");
 		ide_do_reset (drive);
 		return;
@@ -211,19 +326,28 @@
 static void idescsi_issue_pc (ide_drive_t *drive, idescsi_pc_t *pc)
 {
 	idescsi_scsi_t *scsi = drive->driver_data;
-	idescsi_bcount_reg_t bcount;
+	int bcount;
+	struct request *rq = pc->rq;
+	int dma_ok = 0;
 
 	scsi->pc=pc;							/* Set the current packet command */
 	pc->actually_transferred=0;					/* We haven't transferred any data yet */
 	pc->current_position=pc->buffer;
-	bcount.all = IDE_MIN (pc->request_transfer, 63 * 1024);		/* Request to transfer the entire buffer at once */
+	bcount = IDE_MIN (pc->request_transfer, 63 * 1024);		/* Request to transfer the entire buffer at once */
+
+	if (drive->using_dma && rq->bh)
+		dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
 
 	OUT_BYTE (drive->ctl,IDE_CONTROL_REG);
-	OUT_BYTE (0,IDE_FEATURE_REG);
-	OUT_BYTE (bcount.b.high,IDE_BCOUNTH_REG);
-	OUT_BYTE (bcount.b.low,IDE_BCOUNTL_REG);
+	OUT_BYTE (dma_ok,IDE_FEATURE_REG);
+	OUT_BYTE (bcount >> 8,IDE_BCOUNTH_REG);
+	OUT_BYTE (bcount & 0xff,IDE_BCOUNTL_REG);
 	OUT_BYTE (drive->select.all,IDE_SELECT_REG);
 
+	if (dma_ok) {
+		set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
+		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+	}
 	if (test_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags)) {
 		ide_set_handler (drive, &idescsi_transfer_pc, WAIT_CMD);
 		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);		/* Issue the packet command */
@@ -304,7 +428,7 @@
 static ide_driver_t idescsi_driver = {
 	ide_scsi,		/* media */
 	0,			/* busy */
-	0,			/* supports_dma */
+	1,			/* supports_dma */
 	0,			/* supports_dsc_overlap */
 	idescsi_cleanup,	/* cleanup */
 	idescsi_do_request,	/* do_request */
@@ -389,23 +513,74 @@
 	return "SCSI host adapter emulation for IDE ATAPI devices";
 }
 
-/*
- *	Most of the SCSI commands are supported directly by ATAPI devices.
- *	idescsi_transform_pc handles the few exceptions.
- */
-static inline void idescsi_transform_pc (ide_drive_t *drive, idescsi_pc_t *pc)
+static inline struct buffer_head *idescsi_kmalloc_bh (int count)
 {
-	if (drive->media == ide_cdrom) {
-		if (pc->c[0] == READ_6) {
-			pc->c[8] = pc->c[4];
-			pc->c[5] = pc->c[3];
-			pc->c[4] = pc->c[2];
-			pc->c[3] = pc->c[1] & 0x1f;
-			pc->c[2] = 0;
-			pc->c[1] &= 0xe0;
-			pc->c[0] = READ_10;
+	struct buffer_head *bh, *bhp, *first_bh;
+
+	if ((first_bh = bhp = bh = kmalloc (sizeof(struct buffer_head), GFP_ATOMIC)) == NULL)
+		goto abort;
+	memset (bh, 0, sizeof (struct buffer_head));
+	bh->b_reqnext = NULL;
+	while (--count) {
+		if ((bh = kmalloc (sizeof(struct buffer_head), GFP_ATOMIC)) == NULL)
+			goto abort;
+		memset (bh, 0, sizeof (struct buffer_head));
+		bhp->b_reqnext = bh;
+		bhp = bh;
+		bh->b_reqnext = NULL;
+	}
+	return first_bh;
+abort:
+	idescsi_free_bh (first_bh);
+	return NULL;
+}
+
+static inline int idescsi_set_direction (idescsi_pc_t *pc)
+{
+	switch (pc->c[0]) {
+		case READ_6: case READ_10: case READ_12:
+			clear_bit (PC_WRITING, &pc->flags);
+			return 0;
+		case WRITE_6: case WRITE_10: case WRITE_12:
+			set_bit (PC_WRITING, &pc->flags);
+			return 0;
+		default:
+			return 1;
+	}
+}
+
+static inline struct buffer_head *idescsi_dma_bh (ide_drive_t *drive, idescsi_pc_t *pc)
+{
+	struct buffer_head *bh = NULL, *first_bh = NULL;
+	int segments = pc->scsi_cmd->use_sg;
+	struct scatterlist *sg = pc->scsi_cmd->request_buffer;
+
+	if (!drive->using_dma || pc->request_transfer % 1024)
+		return NULL;
+	if (idescsi_set_direction(pc))
+		return NULL;
+	if (segments) {
+		if ((first_bh = bh = idescsi_kmalloc_bh (segments)) == NULL)
+			return NULL;
+#if IDESCSI_DEBUG_LOG
+		printk ("ide-scsi: %s: building DMA table, %d segments, %dkB total\n", drive->name, segments, pc->request_transfer >> 10);
+#endif /* IDESCSI_DEBUG_LOG */
+		while (segments--) {
+			bh->b_data = sg->address;
+			bh->b_size = sg->length;
+			bh = bh->b_reqnext;
+			sg++;
 		}
+	} else {
+		if ((first_bh = bh = idescsi_kmalloc_bh (1)) == NULL)
+			return NULL;
+#if IDESCSI_DEBUG_LOG
+		printk ("ide-scsi: %s: building DMA table for a single buffer (%dkB)\n", drive->name, pc->request_transfer >> 10);
+#endif /* IDESCSI_DEBUG_LOG */
+		bh->b_data = pc->scsi_cmd->request_buffer;
+		bh->b_size = pc->request_transfer;
 	}
+	return first_bh;
 }
 
 int idescsi_queue (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
@@ -430,16 +605,25 @@
 	}
 
 	memset (pc->c, 0, 12);
+	pc->flags = 0;
 	pc->rq = rq;
 	memcpy (pc->c, cmd->cmnd, cmd->cmd_len);
-	pc->buffer = cmd->request_buffer;
+	if (cmd->use_sg) {
+		pc->buffer = NULL;
+		pc->sg = cmd->request_buffer;
+	} else {
+		pc->buffer = cmd->request_buffer;
+		pc->sg = NULL;
+	}
+	pc->b_count = 0;
 	pc->request_transfer = pc->buffer_size = cmd->request_bufflen;
 	pc->scsi_cmd = cmd;
 	pc->done = done;
-	idescsi_transform_pc (drive, pc);
+	idescsi_transform_pc1 (drive, pc);
 
 	ide_init_drive_cmd (rq);
 	rq->buffer = (char *) pc;
+	rq->bh = idescsi_dma_bh (drive, pc);
 	rq->cmd = IDESCSI_PC_RQ;
 	(void) ide_do_drive_cmd (drive, rq, ide_end);
 	return 0;
@@ -467,7 +651,7 @@
 int init_module (void)
 {
 	idescsi_init ();
-	idescsi_template.usage_count = &__this_module.usecount;
+	idescsi_template.module = &__this_module;
 	scsi_register_module (MODULE_SCSI_HA, &idescsi_template);
 	return 0;
 }
@@ -481,7 +665,7 @@
 	scsi_unregister_module (MODULE_SCSI_HA, &idescsi_template);
 	for (i = 0; media[i] != 255; i++) {
 		failed = 0;
-		while ((drive = ide_scan_devices (media[i], &idescsi_driver, failed++)) != NULL)
+		while ((drive = ide_scan_devices (media[i], &idescsi_driver, failed)) != NULL)
 			if (idescsi_cleanup (drive)) {
 				printk ("%s: cleanup_module() called while still busy\n", drive->name);
 				failed++;
diff -u --recursive --new-file v2.1.22/linux/drivers/scsi/ide-scsi.h linux/drivers/scsi/ide-scsi.h
--- v2.1.22/linux/drivers/scsi/ide-scsi.h	Thu Dec 12 19:37:07 1996
+++ linux/drivers/scsi/ide-scsi.h	Sun Jan 26 12:07:18 1997
@@ -1,7 +1,7 @@
 /*
  * linux/drivers/scsi/ide-scsi.h
  *
- * Copyright (C) 1996 Gadi Oxman <gadio@netvision.net.il>
+ * Copyright (C) 1996, 1997 Gadi Oxman <gadio@netvision.net.il>
  */
 
 #ifndef IDESCSI_H
@@ -16,7 +16,7 @@
 
 #define IDESCSI								\
 {	NULL,			/* next		*/			\
-	NULL,			/* usage_count	*/			\
+	NULL,			/* module	*/			\
 	NULL,			/* proc_dir	*/			\
 	NULL,			/* proc_info	*/			\
 	"idescsi",		/* name		*/			\
@@ -31,7 +31,7 @@
 	NULL,			/* bios_param	*/			\
 	10,			/* can_queue	*/			\
 	-1,			/* this_id	*/			\
-	SG_NONE,		/* sg_tablesize	*/			\
+	256,			/* sg_tablesize	*/			\
 	5,			/* cmd_per_lun	*/			\
 	0,			/* present	*/			\
 	0,			/* isa_dma	*/			\
diff -u --recursive --new-file v2.1.22/linux/drivers/scsi/in2000.h linux/drivers/scsi/in2000.h
--- v2.1.22/linux/drivers/scsi/in2000.h	Wed Oct 16 10:48:21 1996
+++ linux/drivers/scsi/in2000.h	Sun Jan 26 12:07:18 1997
@@ -325,7 +325,7 @@
 #define IN2000_HOST_ID  7
 
 #define IN2000 {  NULL,                /* link pointer for modules */ \
-                  NULL,                /* usage_count for modules */ \
+                  NULL,                /* module pointer for modules */ \
                   &proc_scsi_in2000,   /* pointer to /proc/scsi directory entry */ \
                   in2000_proc_info,    /* pointer to proc info function */ \
                   "Always IN2000",     /* device name */ \
diff -u --recursive --new-file v2.1.22/linux/drivers/scsi/qlogicisp.h linux/drivers/scsi/qlogicisp.h
--- v2.1.22/linux/drivers/scsi/qlogicisp.h	Mon Jul  1 20:06:05 1996
+++ linux/drivers/scsi/qlogicisp.h	Sun Jan 26 12:07:18 1997
@@ -74,7 +74,7 @@
 
 #define QLOGICISP {							   \
 	/* next */		NULL,					   \
-	/* usage_count */	NULL,					   \
+	/* module */		NULL,					   \
 	/* proc dir */		NULL,					   \
 	/* procfs info */	NULL,					   \
 	/* name */		NULL,					   \
diff -u --recursive --new-file v2.1.22/linux/drivers/scsi/qlogicpti.h linux/drivers/scsi/qlogicpti.h
--- v2.1.22/linux/drivers/scsi/qlogicpti.h	Wed Dec 18 15:58:51 1996
+++ linux/drivers/scsi/qlogicpti.h	Sun Jan 26 12:07:19 1997
@@ -475,7 +475,7 @@
 	unsigned char             bursts;
 	struct	host_param        host_param;
 	struct	dev_param         dev_param[MAX_TARGETS];
-	
+
 	volatile unsigned char   *sreg;
 #define SREG_TPOWER               0x80   /* State of termpwr           */
 #define SREG_FUSE                 0x40   /* State of on board fuse     */
@@ -717,7 +717,7 @@
 
 #define QLOGICPTI {							   \
 	/* next */		NULL,					   \
-	/* usage_count */	NULL,					   \
+	/* module */		NULL,					   \
 	/* proc dir */		NULL,					   \
 	/* procfs info */	NULL,					   \
 	/* name */		NULL,					   \
diff -u --recursive --new-file v2.1.22/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v2.1.22/linux/drivers/scsi/scsi.c	Mon Dec 30 15:39:11 1996
+++ linux/drivers/scsi/scsi.c	Sun Jan 26 12:07:19 1997
@@ -17,7 +17,7 @@
  *  add scatter-gather, multiple outstanding request, and other
  *  enhancements.
  *
- *  Native multichannel, wide scsi, /proc/scsi and hot plugging 
+ *  Native multichannel, wide scsi, /proc/scsi and hot plugging
  *  support added by Michael Neuffer <mike@i-connect.net>
  *
  *  Added request_module("scsi_hostadapter") for kerneld:
@@ -64,7 +64,7 @@
 #undef USE_STATIC_SCSI_MEMORY
 
 /*
-static const char RCSid[] = "$Header: /vger/u4/cvs/linux/drivers/scsi/scsi.c,v 1.34 1996/11/19 11:25:50 davem Exp $";
+static const char RCSid[] = "$Header: /vger/u4/cvs/linux/drivers/scsi/scsi.c,v 1.38 1997/01/19 23:07:18 davem Exp $";
 */
 
 
@@ -145,18 +145,18 @@
 /* This variable is merely a hook so that we can debug the kernel with gdb. */
 Scsi_Cmnd * last_cmnd = NULL;
 
-/* This is the pointer to the /proc/scsi code. 
- * It is only initialized to !=0 if the scsi code is present 
- */ 
-#if CONFIG_PROC_FS 
-extern int (* dispatch_scsi_info_ptr)(int ino, char *buffer, char **start, 
-				      off_t offset, int length, int inout); 
-extern int dispatch_scsi_info(int ino, char *buffer, char **start, 
-			      off_t offset, int length, int inout); 
+/* This is the pointer to the /proc/scsi code.
+ * It is only initialized to !=0 if the scsi code is present
+ */
+#if CONFIG_PROC_FS
+extern int (* dispatch_scsi_info_ptr)(int ino, char *buffer, char **start,
+				      off_t offset, int length, int inout);
+extern int dispatch_scsi_info(int ino, char *buffer, char **start,
+			      off_t offset, int length, int inout);
 
 struct proc_dir_entry proc_scsi_scsi = {
     PROC_SCSI_SCSI, 4, "scsi",
-    S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0, 0, 
+    S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0, 0,
     NULL,
     NULL, NULL,
     NULL, NULL, NULL
@@ -201,7 +201,7 @@
 
 /* The following devices are known not to tolerate a lun != 0 scan for
  * one reason or another.  Some will respond to all luns, others will
- * lock up. 
+ * lock up.
  */
 
 #define BLIST_NOLUN     0x01
@@ -241,11 +241,11 @@
 {"MICROP", "4110", "*", BLIST_NOTQ},		/* Buggy Tagged Queuing */
 {"NEC","CD-ROM DRIVE:841","1.0", BLIST_NOLUN},  /* Locks-up when LUN>0 polled. */
 {"RODIME","RO3000S","2.33", BLIST_NOLUN},       /* Locks up if polled for lun != 0 */
-{"SANYO", "CRD-250S", "1.20", BLIST_NOLUN},     /* causes failed REQUEST SENSE on lun 1 
-						 * for aha152x controller, which causes 
+{"SANYO", "CRD-250S", "1.20", BLIST_NOLUN},     /* causes failed REQUEST SENSE on lun 1
+						 * for aha152x controller, which causes
 						 * SCSI code to reset bus.*/
-{"SEAGATE", "ST157N", "\004|j", BLIST_NOLUN},   /* causes failed REQUEST SENSE on lun 1 
-						 * for aha152x controller, which causes 
+{"SEAGATE", "ST157N", "\004|j", BLIST_NOLUN},   /* causes failed REQUEST SENSE on lun 1
+						 * for aha152x controller, which causes
 						 * SCSI code to reset bus.*/
 {"SEAGATE", "ST296","921", BLIST_NOLUN},        /* Responds to all lun */
 {"SEAGATE","ST1581","6538",BLIST_NOLUN},	/* Responds to all lun */
@@ -253,11 +253,11 @@
 {"SONY","CD-ROM CDU-55S","1.0i", BLIST_NOLUN},
 {"SONY","CD-ROM CDU-561","1.7x", BLIST_NOLUN},
 {"TANDBERG","TDC 3600","U07", BLIST_NOLUN},     /* Locks up if polled for lun != 0 */
-{"TEAC","CD-ROM","1.06", BLIST_NOLUN},          /* causes failed REQUEST SENSE on lun 1 
-						 * for seagate controller, which causes 
+{"TEAC","CD-ROM","1.06", BLIST_NOLUN},          /* causes failed REQUEST SENSE on lun 1
+						 * for seagate controller, which causes
 						 * SCSI code to reset bus.*/
-{"TEXEL","CD-ROM","1.06", BLIST_NOLUN},         /* causes failed REQUEST SENSE on lun 1 
-						 * for seagate controller, which causes 
+{"TEXEL","CD-ROM","1.06", BLIST_NOLUN},         /* causes failed REQUEST SENSE on lun 1
+						 * for seagate controller, which causes
 						 * SCSI code to reset bus.*/
 {"QUANTUM","LPS525S","3110", BLIST_NOLUN},      /* Locks sometimes if polled for lun != 0 */
 {"QUANTUM","PD1225S","3110", BLIST_NOLUN},      /* Locks sometimes if polled for lun != 0 */
@@ -310,7 +310,7 @@
     int block_count = 0, index;
     unsigned long flags;
     struct Scsi_Host * sh[128], * shpnt;
-    
+
     /*
      * Create a circular linked list from the scsi hosts which have
      * the "wish_block" field in the Scsi_Host structure set.
@@ -328,13 +328,13 @@
      *
      * (DB, 4 Feb 1995)
      */
-    
+
     save_flags(flags);
     cli();
     host_active = NULL;
-    
+
     for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next) {
-	
+
 #if 0
 	/*
 	 * Is this is a candidate for the blocked list?
@@ -343,12 +343,12 @@
 	 */
 	if (shpnt->unchecked_isa_dma) shpnt->wish_block = 1;
 #endif
-	
+
 	if (shpnt->wish_block) sh[block_count++] = shpnt;
     }
-    
+
     if (block_count == 1) sh[0]->block = NULL;
-    
+
     else if (block_count > 1) {
 	
 	for(index = 0; index < block_count - 1; index++) {
@@ -356,23 +356,23 @@
 	    printk("scsi%d : added to blocked host list.\n",
 		   sh[index]->host_no);
 	}
-	
+
 	sh[block_count - 1]->block = sh[0];
 	printk("scsi%d : added to blocked host list.\n",
 	       sh[index]->host_no);
     }
-    
+
     restore_flags(flags);
 }
 
 static void scan_scsis_done (Scsi_Cmnd * SCpnt)
 {
-    
+
 #ifdef DEBUG
     printk ("scan_scsis_done(%p, %06x)\n", SCpnt->host, SCpnt->result);
 #endif
     SCpnt->request.rq_status = RQ_SCSI_DONE;
-    
+
     if (SCpnt->request.sem != NULL)
 	up(SCpnt->request.sem);
 }
@@ -452,7 +452,7 @@
 		  (*sdtpnt->attach)(oldSDpnt);
                   if(oldSDpnt->attached) scsi_build_commandblocks(oldSDpnt);}
 	    resize_dma_pool();
-  
+
         for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) {
             if(sdtpnt->finish && sdtpnt->nr_dev)
                 {(*sdtpnt->finish)();}
@@ -493,14 +493,14 @@
     if(hqptr) {
       prev = hqptr->prev;
       next = hqptr->next;
-      if(prev) 
+      if(prev)
      	prev->next = next;
-      else 
+      else
      	shpnt->host_queue = next;
       if(next) next->prev = prev;
     }
   }
- 
+
      /* Last device block does not exist.  Free memory. */
     if (SDpnt != NULL)
       scsi_init_free ((char *) SDpnt, sizeof (Scsi_Device));
@@ -819,7 +819,7 @@
 
 static void scsi_times_out (Scsi_Cmnd * SCpnt)
 {
-    
+
     switch (SCpnt->internal_timeout & (IN_ABORT | IN_RESET | IN_RESET2 | IN_RESET3))
     {
     case NORMAL_TIMEOUT:
@@ -828,7 +828,7 @@
 	    scsi_dump_status();
 #endif
 	}
-	
+
 	if (!scsi_abort (SCpnt, DID_TIME_OUT))
 	    return;
     case IN_ABORT:
@@ -840,7 +840,7 @@
     case (IN_ABORT | IN_RESET):
 	/* This might be controversial, but if there is a bus hang,
 	 * you might conceivably want the machine up and running
-	 * esp if you have an ide disk. 
+	 * esp if you have an ide disk.
 	 */
 	printk("SCSI host %d channel %d reset (pid %ld) timed out - "
                "trying harder\n",
@@ -862,7 +862,7 @@
         scsi_reset (SCpnt,
 		    SCSI_RESET_ASYNCHRONOUS | SCSI_RESET_SUGGEST_HOST_RESET);
 	return;
-		
+
     default:
 	printk("SCSI host %d reset (pid %ld) timed out again -\n",
 	       SCpnt->host->host_no, SCpnt->pid);
@@ -870,7 +870,7 @@
 	return;
 
     }
-    
+
 }
 
 
@@ -878,7 +878,7 @@
  * can be queued now, or if there would be a stall while waiting for
  * something else to finish.  This routine assumes that interrupts are
  * turned off when entering the routine.  It is the responsibility
- * of the calling code to ensure that this is the case. 
+ * of the calling code to ensure that this is the case.
  */
 
 Scsi_Cmnd * request_queueable (struct request * req, Scsi_Device * device)
@@ -887,19 +887,19 @@
     int tablesize;
     Scsi_Cmnd * found = NULL;
     struct buffer_head * bh, *bhp;
-    
+
     if (!device)
 	panic ("No device passed to request_queueable().\n");
-    
+
     if (req && req->rq_status == RQ_INACTIVE)
 	panic("Inactive in request_queueable");
 
     /*
      * Look for a free command block.  If we have been instructed not to queue
-     * multiple commands to multi-lun devices, then check to see what else is 
+     * multiple commands to multi-lun devices, then check to see what else is
      * going for this device first.
      */
-      
+
     if (!device->single_lun) {
 	SCpnt = device->device_queue;
 	while(SCpnt){
@@ -909,19 +909,19 @@
     } else {
 	SCpnt = device->host->host_queue;
 	while(SCpnt){
-	    if(SCpnt->channel == device->channel 
+	    if(SCpnt->channel == device->channel
                 && SCpnt->target == device->id) {
 		if (SCpnt->lun == device->lun) {
-		    if(found == NULL 
-		       && SCpnt->request.rq_status == RQ_INACTIVE) 
+		    if(found == NULL
+		       && SCpnt->request.rq_status == RQ_INACTIVE)
 		    {
 			found=SCpnt;
 		    }
-		} 
+		}
 		if(SCpnt->request.rq_status != RQ_INACTIVE) {
 		    /*
 		     * I think that we should really limit things to one
-		     * outstanding command per device - this is what tends 
+		     * outstanding command per device - this is what tends
                      * to trip up buggy firmware.
 		     */
 		    return NULL;
@@ -931,19 +931,19 @@
 	}
 	SCpnt = found;
     }
-    
+
     if (!SCpnt) return NULL;
-    
+
     if (SCSI_BLOCK(device->host)) return NULL;
-    
+
     if (req) {
 	memcpy(&SCpnt->request, req, sizeof(struct request));
 	tablesize = device->host->sg_tablesize;
 	bhp = bh = req->bh;
 	if(!tablesize) bh = NULL;
-	/* Take a quick look through the table to see how big it is.  
-	 * We already have our copy of req, so we can mess with that 
-	 * if we want to. 
+	/* Take a quick look through the table to see how big it is.
+	 * We already have our copy of req, so we can mess with that
+	 * if we want to.
 	 */
 	while(req->nr_sectors && bh){
 	    bhp = bhp->b_reqnext;
@@ -958,7 +958,7 @@
 	    req->bh = bh->b_reqnext; /* Divide request */
 	    bh->b_reqnext = NULL;
 	    bh = req->bh;
-	    
+
 	    /* Now reset things so that req looks OK */
 	    SCpnt->request.nr_sectors -= req->nr_sectors;
 	    req->current_nr_sectors = bh->b_size >> 9;
@@ -970,10 +970,10 @@
 	}
     } else {
 	SCpnt->request.rq_status = RQ_SCSI_BUSY;  /* Busy, but no request */
-	SCpnt->request.sem = NULL;   /* And no one is waiting for the device 
+	SCpnt->request.sem = NULL;   /* And no one is waiting for the device
 				      * either */
     }
-    
+
     SCpnt->use_sg = 0;               /* Reset the scatter-gather flag */
     SCpnt->old_use_sg  = 0;
     SCpnt->transfersize = 0;
@@ -982,7 +982,7 @@
 
 /* Since not everyone seems to set the device info correctly
  * before Scsi_Cmnd gets send out to scsi_do_command, we do it here.
- */ 
+ */
     SCpnt->channel = device->channel;
     SCpnt->lun = device->lun;
     SCpnt->target = device->id;
@@ -997,7 +997,7 @@
  * commands for the time being.  We need to keep in mind that there is no
  * guarantee that the host remain not busy.  Keep in mind the
  * request_queueable function also knows the internal allocation scheme
- * of the packets for each device 
+ * of the packets for each device
  */
 
 Scsi_Cmnd * allocate_device (struct request ** reqp, Scsi_Device * device,
@@ -1012,23 +1012,23 @@
     Scsi_Cmnd * SCpnt = NULL;
     Scsi_Cmnd * SCwait = NULL;
     Scsi_Cmnd * found = NULL;
-    
+
     if (!device)
 	panic ("No device passed to allocate_device().\n");
-    
+
     if (reqp) req = *reqp;
-    
+
     /* See if this request has already been queued by an interrupt routine */
     if (req) {
 	if(req->rq_status == RQ_INACTIVE) return NULL;
 	dev = req->rq_dev;
     } else
         dev = 0;		/* unused */
-    
+
     host = device->host;
-    
+
     if (intr_count && SCSI_BLOCK(host)) return NULL;
-    
+
     while (1==1){
 	if (!device->single_lun) {
 	    SCpnt = device->device_queue;
@@ -1040,16 +1040,16 @@
 	} else {
 	    SCpnt = device->host->host_queue;
 	    while(SCpnt){
-		if(SCpnt->channel == device->channel 
+		if(SCpnt->channel == device->channel
                    && SCpnt->target == device->id) {
 		    if (SCpnt->lun == device->lun) {
 			SCwait = SCpnt;
-			if(found == NULL 
-			   && SCpnt->request.rq_status == RQ_INACTIVE) 
+			if(found == NULL
+			   && SCpnt->request.rq_status == RQ_INACTIVE)
 			{
 			    found=SCpnt;
 			}
-		    } 
+		    }
 		    if(SCpnt->request.rq_status != RQ_INACTIVE) {
 			/*
 			 * I think that we should really limit things to one
@@ -1094,7 +1094,7 @@
 		    if(!wait) return NULL;
 		    if (!SCwait) {
 			printk("Attempt to allocate device channel %d, target"
-                               " %d, lun %d\n", device->channel, device->id, 
+                               " %d, lun %d\n", device->channel, device->id,
                                device->lun);
 			panic("No device found in allocate_device\n");
 		    }
@@ -1107,9 +1107,9 @@
 		tablesize = device->host->sg_tablesize;
 		bhp = bh = req->bh;
 		if(!tablesize) bh = NULL;
-		/* Take a quick look through the table to see how big it is.  
-		 * We already have our copy of req, so we can mess with that 
-		 * if we want to.  
+		/* Take a quick look through the table to see how big it is.
+		 * We already have our copy of req, so we can mess with that
+		 * if we want to.
 		 */
 		while(req->nr_sectors && bh){
 		    bhp = bhp->b_reqnext;
@@ -1138,14 +1138,14 @@
 		}
 	    } else {
 		SCpnt->request.rq_status = RQ_SCSI_BUSY;
-		SCpnt->request.sem = NULL;   /* And no one is waiting for this 
+		SCpnt->request.sem = NULL;   /* And no one is waiting for this
 					      * to complete */
 	    }
 	    restore_flags(flags);
 	    break;
 	}
     }
-    
+
     SCpnt->use_sg = 0;            /* Reset the scatter-gather flag */
     SCpnt->old_use_sg  = 0;
     SCpnt->transfersize = 0;      /* No default transfer size */
@@ -1155,7 +1155,7 @@
 
     /* Since not everyone seems to set the device info correctly
      * before Scsi_Cmnd gets send out to scsi_do_command, we do it here.
-     */ 
+     */
     SCpnt->channel = device->channel;
     SCpnt->lun = device->lun;
     SCpnt->target = device->id;
@@ -1183,9 +1183,9 @@
    ret =  __builtin_return_address(0);
 #endif
 #endif
-    
+
     host = SCpnt->host;
-    
+
     save_flags(flags);
     cli();
     /* Assign a unique nonzero serial_number. */
@@ -1213,20 +1213,20 @@
 	host->last_reset = jiffies - MIN_RESET_DELAY;
     }
     restore_flags(flags);
-    
+
     update_timeout(SCpnt, SCpnt->timeout_per_command);
-    
+
     /*
      * We will use a queued command if possible, otherwise we will emulate the
      * queuing and calling of completion function ourselves.
      */
 #ifdef DEBUG
     printk("internal_cmnd (host = %d, channel = %d, target = %d, "
-	   "command = %p, buffer = %p, \nbufflen = %d, done = %p)\n", 
-	   SCpnt->host->host_no, SCpnt->channel, SCpnt->target, SCpnt->cmnd, 
+	   "command = %p, buffer = %p, \nbufflen = %d, done = %p)\n",
+	   SCpnt->host->host_no, SCpnt->channel, SCpnt->target, SCpnt->cmnd,
 	   SCpnt->buffer, SCpnt->bufflen, SCpnt->done);
 #endif
-    
+
     if (host->can_queue)
     {
 #ifdef DEBUG
@@ -1239,14 +1239,14 @@
 	 * any given time, and we can only be in the interrupt
 	 * handler and the queuecommand function at the same time
 	 * when queuecommand is called while servicing the
-	 * interrupt. 
+	 * interrupt.
 	 */
-	
+
 	if(!intr_count && SCpnt->host->irq)
 	    disable_irq(SCpnt->host->irq);
-	
+
 	host->hostt->queuecommand (SCpnt, scsi_done);
-	
+
 	if(!intr_count && SCpnt->host->irq)
 	    enable_irq(SCpnt->host->irq);
     }
@@ -1262,7 +1262,7 @@
 #ifdef DEBUG_DELAY
 	clock = jiffies + 4 * HZ;
 	while (jiffies < clock) barrier();
-	printk("done(host = %d, result = %04x) : routine at %p\n", 
+	printk("done(host = %d, result = %04x) : routine at %p\n",
 	       host->host_no, temp, host->hostt->command);
 #endif
 	scsi_done(SCpnt);
@@ -1275,20 +1275,20 @@
 static void scsi_request_sense (Scsi_Cmnd * SCpnt)
 {
     unsigned long flags;
-    
+
     save_flags(flags);
     cli();
     SCpnt->flags |= WAS_SENSE | ASKED_FOR_SENSE;
     update_timeout(SCpnt, SENSE_TIMEOUT);
     restore_flags(flags);
-    
-    
-    memcpy ((void *) SCpnt->cmnd , (void *) generic_sense, 
+
+
+    memcpy ((void *) SCpnt->cmnd , (void *) generic_sense,
 	    sizeof(generic_sense));
-    
+
     SCpnt->cmnd[1] = SCpnt->lun << 5;
     SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer);
-    
+
     SCpnt->request_buffer = &SCpnt->sense_buffer;
     SCpnt->request_bufflen = sizeof(SCpnt->sense_buffer);
     SCpnt->use_sg = 0;
@@ -1311,7 +1311,7 @@
 {
     unsigned long flags;
     struct Scsi_Host * host = SCpnt->host;
-    
+
 #ifdef DEBUG
     {
 	int i;
@@ -1319,20 +1319,20 @@
 	printk ("scsi_do_cmd (host = %d, channel = %d target = %d, "
 		"buffer =%p, bufflen = %d, done = %p, timeout = %d, "
 		"retries = %d)\n"
-		"command : " , host->host_no, SCpnt->channel, target, buffer, 
+		"command : " , host->host_no, SCpnt->channel, target, buffer,
 		bufflen, done, timeout, retries);
 	for (i = 0; i < 10; ++i)
 	    printk ("%02x  ", ((unsigned char *) cmnd)[i]);
 	printk("\n");
     }
 #endif
-    
+
     if (!host)
     {
 	panic ("Invalid or not present host.\n");
     }
-    
-    
+
+
     /*
      * We must prevent reentrancy to the lowlevel host driver.  This prevents
      * it - we enter a loop until the host we want to talk to is not busy.
@@ -1344,25 +1344,25 @@
     save_flags(flags);
     cli();
     SCpnt->pid = scsi_pid++;
-    
+
     while (SCSI_BLOCK(host)) {
 	restore_flags(flags);
 	SCSI_SLEEP(&host->host_wait, SCSI_BLOCK(host));
 	cli();
     }
-    
+
     if (host->block) host_active = host;
-    
+
     host->host_busy++;
     restore_flags(flags);
-    
+
     /*
      * Our own function scsi_done (which marks the host as not busy, disables
      * the timeout counter, etc) will be called by us or by the
      * scsi_hosts[host].queuecommand() function needs to also call
      * the completion function for the high level driver.
      */
-    
+
     memcpy ((void *) SCpnt->data_cmnd , (const void *) cmnd, 12);
 #if 0
     SCpnt->host = host;
@@ -1382,7 +1382,7 @@
 
     memcpy ((void *) SCpnt->cmnd , (const void *) cmnd, 12);
     /* Zero the sense buffer.  Some host adapters automatically request
-     * sense on error.  0 is not a valid sense code.  
+     * sense on error.  0 is not a valid sense code.
      */
     memset ((void *) SCpnt->sense_buffer, 0, sizeof SCpnt->sense_buffer);
     SCpnt->request_buffer = buffer;
@@ -1407,7 +1407,7 @@
 {
     /* If there is no sense information, request it.  If we have already
      * requested it, there is no point in asking again - the firmware must
-     * be confused. 
+     * be confused.
      */
     if (((SCpnt->sense_buffer[0] & 0x70) >> 4) != 7) {
 	if(!(SCpnt->flags & ASKED_FOR_SENSE))
@@ -1415,9 +1415,9 @@
 	else
 	    return SUGGEST_RETRY;
     }
-    
+
     SCpnt->flags &= ~ASKED_FOR_SENSE;
-    
+
 #ifdef DEBUG_INIT
     printk("scsi%d, channel%d : ", SCpnt->host->host_no, SCpnt->channel);
     print_sense("", SCpnt);
@@ -1425,14 +1425,14 @@
 #endif
     if (SCpnt->sense_buffer[2] & 0xe0)
 	return SUGGEST_ABORT;
-    
+
     switch (SCpnt->sense_buffer[2] & 0xf)
     {
     case NO_SENSE:
 	return 0;
     case RECOVERED_ERROR:
 	return SUGGEST_IS_OK;
-	
+
     case ABORTED_COMMAND:
 	return SUGGEST_RETRY;
     case NOT_READY:
@@ -1449,12 +1449,12 @@
             return SUGGEST_RETRY;
         }
 	return SUGGEST_ABORT;
-	
+
     /* these three are not supported */
     case COPY_ABORTED:
     case VOLUME_OVERFLOW:
     case MISCOMPARE:
-	
+
     case MEDIUM_ERROR:
 	return SUGGEST_REMAP;
     case BLANK_CHECK:
@@ -1497,14 +1497,14 @@
     int result = SCpnt->result;
     SCpnt->serial_number = 0;
     oldto = update_timeout(SCpnt, 0);
-    
+
 #ifdef DEBUG_TIMEOUT
     if(result) printk("Non-zero result in scsi_done %x %d:%d\n",
 		      result, SCpnt->target, SCpnt->lun);
 #endif
-    
+
     /* If we requested an abort, (and we got it) then fix up the return
-     *  status to say why 
+     *  status to say why
      */
     if(host_byte(result) == DID_ABORT && SCpnt->abort_reason)
 	SCpnt->result = result = (result & 0xff00ffff) |
@@ -1536,12 +1536,12 @@
 #if 0	/* This cannot possibly be correct. */
 	    SCpnt->internal_timeout &= ~SENSE_TIMEOUT;
 #endif
-	    
+
 	    if (!(SCpnt->flags & WAS_RESET))
 	    {
 		printk("scsi%d : channel %d target %d lun %d request sense"
 		       " failed, performing reset.\n",
-		       SCpnt->host->host_no, SCpnt->channel, SCpnt->target, 
+		       SCpnt->host->host_no, SCpnt->channel, SCpnt->target,
 		       SCpnt->lun);
 		scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS);
 		return;
@@ -1568,7 +1568,7 @@
 #if 0	/* This cannot possibly be correct. */
 		    SCpnt->internal_timeout &= ~SENSE_TIMEOUT;
 #endif
-		    
+
 		    switch (checked = check_sense(SCpnt))
 		    {
 		    case SUGGEST_SENSE:
@@ -1617,7 +1617,7 @@
 		    status = FINISHED;
 		}
 		break;
-		
+
 	    case CHECK_CONDITION:
 	    case COMMAND_TERMINATED:
 		switch (check_sense(SCpnt))
@@ -1644,18 +1644,18 @@
 		    break;
 		}
 		break;
-		
+
 	    case CONDITION_GOOD:
 	    case INTERMEDIATE_GOOD:
 	    case INTERMEDIATE_C_GOOD:
 		break;
-		
+
 	    case BUSY:
 	    case QUEUE_FULL:
 		update_timeout(SCpnt, oldto);
 		status = REDO;
 		break;
-		
+
 	    case RESERVATION_CONFLICT:
 		printk("scsi%d, channel %d : RESERVATION CONFLICT performing"
 		       " reset.\n", SCpnt->host->host_no, SCpnt->channel);
@@ -1670,11 +1670,11 @@
 		printk ("Internal error %s %d \n"
 			"status byte = %d \n", __FILE__,
 			__LINE__, status_byte(result));
-		
+
 	    }
 	    break;
 	default:
-	    panic("scsi: unsupported message byte %d received\n", 
+	    panic("scsi: unsupported message byte %d received\n",
 		  msg_byte(result));
 	}
 	break;
@@ -1682,7 +1682,7 @@
 #ifdef DEBUG
 	printk("Host returned DID_TIME_OUT - ");
 #endif
-	
+
 	if (SCpnt->flags & WAS_TIMEDOUT)
 	{
 #ifdef DEBUG
@@ -1732,7 +1732,7 @@
 	    status = REDO;
 	    break;
 	}
-	
+
 	if(msg_byte(result) == GOOD &&
 	   status_byte(result) == CHECK_CONDITION) {
 	    switch (check_sense(SCpnt)) {
@@ -1762,7 +1762,7 @@
     default :
 	exit = (DRIVER_ERROR | SUGGEST_DIE);
     }
-    
+
     switch (status)
     {
     case FINISHED:
@@ -1785,7 +1785,7 @@
 		scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS);
 		break;
 	    }
-	    
+
 	}
 	else
 	{
@@ -1793,9 +1793,9 @@
 	    break;
 	}
 	/* fall through to REDO */
-	
+
     case REDO:
-	
+
 	if (SCpnt->flags & WAS_SENSE)
 	    scsi_request_sense(SCpnt);
 	else
@@ -1813,34 +1813,34 @@
     default:
 	INTERNAL_ERROR;
     }
-    
+
     if (status == FINISHED) {
 #ifdef DEBUG
 	printk("Calling done function - at address %p\n", SCpnt->done);
 #endif
 	host->host_busy--; /* Indicate that we are free */
-	
+
 	if (host->block && host->host_busy == 0) {
 	    host_active = NULL;
-	    
+
 	    /* For block devices "wake_up" is done in end_scsi_request */
 	    if (MAJOR(SCpnt->request.rq_dev) != SCSI_DISK_MAJOR &&
 		MAJOR(SCpnt->request.rq_dev) != SCSI_CDROM_MAJOR) {
 		struct Scsi_Host * next;
-		
+
 		for (next = host->block; next != host; next = next->block)
 		    wake_up(&next->host_wait);
 	    }
-	    
+
 	}
-	
+
 	wake_up(&host->host_wait);
 	SCpnt->result = result | ((exit & 0xff) << 24);
 	SCpnt->use_sg = SCpnt->old_use_sg;
 	SCpnt->cmd_len = SCpnt->old_cmd_len;
 	SCpnt->done (SCpnt);
     }
-    
+
 #undef FINISHED
 #undef REDO
 #undef MAYREDO
@@ -1852,7 +1852,7 @@
  * we are aborting, and causes the current command to not complete.  The
  * caller should deal with any error messages or status returned on the
  * next call.
- * 
+ *
  * This will not be called reentrantly for a given host.
  */
 
@@ -1868,12 +1868,12 @@
     int oldto;
     unsigned long flags;
     struct Scsi_Host * host = SCpnt->host;
-    
+
     while(1)
     {
 	save_flags(flags);
 	cli();
-	
+
 	/*
 	 * Protect against races here.  If the command is done, or we are
 	 * on a different command forget it.
@@ -1893,16 +1893,16 @@
 	{
 	    SCpnt->internal_timeout |= IN_ABORT;
 	    oldto = update_timeout(SCpnt, ABORT_TIMEOUT);
-	    
+
 	    if ((SCpnt->flags & IS_RESETTING) && SCpnt->device->soft_reset) {
 		/* OK, this command must have died when we did the
-		 *  reset.  The device itself must have lied. 
+		 *  reset.  The device itself must have lied.
 		 */
 		printk("Stale command on %d %d:%d appears to have died when"
-		       " the bus was reset\n", 
+		       " the bus was reset\n",
 		       SCpnt->channel, SCpnt->target, SCpnt->lun);
 	    }
-	    
+
 	    restore_flags(flags);
 	    if (!host->host_busy) {
 		SCpnt->internal_timeout &= ~IN_ABORT;
@@ -1911,7 +1911,7 @@
 	    }
 	    printk("scsi : aborting command due to timeout : pid %lu, scsi%d,"
 		   " channel %d, id %d, lun %d ",
-		   SCpnt->pid, SCpnt->host->host_no, (int) SCpnt->channel, 
+		   SCpnt->pid, SCpnt->host->host_no, (int) SCpnt->channel,
 		   (int) SCpnt->target, (int) SCpnt->lun);
 	    print_command (SCpnt->cmnd);
 	    if (SCpnt->serial_number != SCpnt->serial_number_at_timeout)
@@ -1923,7 +1923,7 @@
 		 * WAS_TIMEDOUT flag set so we do not try this twice
 		 */
 	    case SCSI_ABORT_BUSY: /* Tough call - returning 1 from
-				   * this is too severe 
+				   * this is too severe
 				   */
 	    case SCSI_ABORT_SNOOZE:
 		if(why == DID_TIME_OUT) {
@@ -1934,7 +1934,7 @@
 			restore_flags(flags);
 			return 1; /* Indicate we cannot handle this.
 				   * We drop down into the reset handler
-				   * and try again 
+				   * and try again
 				   */
 		    } else {
 			SCpnt->flags |= WAS_TIMEDOUT;
@@ -1954,7 +1954,7 @@
 		return 0;
 	    case SCSI_ABORT_SUCCESS:
 		/* We should have already aborted this one.  No
-		 * need to adjust timeout 
+		 * need to adjust timeout
 		 */
                  SCpnt->internal_timeout &= ~IN_ABORT;
                  return 0;
@@ -2011,7 +2011,7 @@
 
     printk("SCSI bus is being reset for host %d channel %d.\n",
 	   host->host_no, SCpnt->channel);
- 
+
 #if 0
     /*
      * First of all, we need to make a recommendation to the low-level
@@ -2021,7 +2021,7 @@
      * to determine what we should do.
      */
     SCpnt->host->suggest_bus_reset = FALSE;
-    
+
     /*
      * First see if all of the active devices on the bus have
      * been jammed up so that we are attempting resets.  If so,
@@ -2047,7 +2047,7 @@
     if( SCpnt1 == NULL ) {
         reset_flags |= SCSI_RESET_SUGGEST_BUS_RESET;
     }
-    
+
     /*
      * If the code that called us is suggesting a hard reset, then
      * definitely request it.  This usually occurs because a
@@ -2059,7 +2059,7 @@
         SCpnt->host->suggest_bus_reset = TRUE;
     }
 #endif
-    
+
     while (1) {
 	save_flags(flags);
 	cli();
@@ -2084,7 +2084,7 @@
 	{
 	    SCpnt->internal_timeout |= IN_RESET;
 	    update_timeout(SCpnt, RESET_TIMEOUT);
-	    
+
 	    if (host->host_busy)
 	    {
 		restore_flags(flags);
@@ -2100,7 +2100,7 @@
 		    }
 		    SCpnt1 = SCpnt1->next;
 		}
-		
+
 		host->last_reset = jiffies;
 		temp = host->hostt->reset(SCpnt, reset_flags);
 		/*
@@ -2123,16 +2123,16 @@
 		host->last_reset = jiffies;
 	        SCpnt->flags |= (WAS_RESET | IS_RESETTING);
 		temp = host->hostt->reset(SCpnt, reset_flags);
-		if ((host->last_reset < jiffies) || 
+		if ((host->last_reset < jiffies) ||
 		    (host->last_reset > (jiffies + 20 * HZ)))
 		  host->last_reset = jiffies;
 		if (!host->block) host->host_busy--;
 	    }
-	    
+
 #ifdef DEBUG
 	    printk("scsi reset function returned %d\n", temp);
 #endif
-            
+
             /*
              * Now figure out what we need to do, based upon
              * what the low level driver said that it did.
@@ -2193,7 +2193,7 @@
                     SCpnt1 = host->host_queue;
                     while(SCpnt1) {
                         if(SCpnt1->request.rq_status != RQ_INACTIVE
-                           && SCpnt1 != SCpnt 
+                           && SCpnt1 != SCpnt
                            && SCpnt1->channel == SCpnt->channel)
                             scsi_request_sense (SCpnt);
                         SCpnt1 = SCpnt1->next;
@@ -2204,7 +2204,7 @@
 		/* In this case, we set the timeout field to 0
 		 * so that this command does not time out any more,
 		 * and we return 1 so that we get a message on the
-		 * screen. 
+		 * screen.
 		 */
 		save_flags(flags);
 		cli();
@@ -2216,7 +2216,7 @@
 	    default:
 		return 1;
 	    }
-	    
+
 	    return temp;
 	}
     }
@@ -2228,12 +2228,12 @@
     /*
      * We must not enter update_timeout with a timeout condition still pending.
      */
-    
+
     int timed_out;
     unsigned long flags;
     struct Scsi_Host * host;
     Scsi_Cmnd * SCpnt = NULL;
-    
+
     save_flags(flags);
     cli();
 
@@ -2323,14 +2323,14 @@
      */
 
     oldto = 0;
-    
+
     if(SCset){
 	oldto = SCset->timeout - used;
 	SCset->timeout = timeout;
     }
 
     least = 0xffffffff;
-    
+
     for(host = scsi_hostlist; host; host = host->next)
 	for(SCpnt = host->host_queue; SCpnt; SCpnt = SCpnt->next)
 	    if (SCpnt->timeout > 0) {
@@ -2340,12 +2340,12 @@
 		if(SCpnt->timeout > 0 && SCpnt->timeout < least)
 		    least = SCpnt->timeout;
 	    }
-    
+
     /*
      * If something is due to timeout again, then we will set the next timeout
      * interrupt to occur.  Otherwise, timeouts are disabled.
      */
-    
+
     if (least != 0xffffffff)
     {
 	time_start = jiffies;
@@ -2373,12 +2373,12 @@
     int i, j;
     if(len % SECTOR_SIZE != 0 || len > PAGE_SIZE)
 	return NULL;
-    
+
     save_flags(flags);
     cli();
     nbits = len >> 9;
     mask = (1 << nbits) - 1;
-    
+
     for(i=0;i < dma_sectors / SECTORS_PER_PAGE; i++)
 	for(j=0; j<=SECTORS_PER_PAGE - nbits; j++){
 	    if ((dma_malloc_freelist[i] & (mask << j)) == 0){
@@ -2410,7 +2410,7 @@
 #endif
     printk("scsi_free %p %d\n",obj, len);
 #endif
-    
+
     for (page = 0; page < dma_sectors / SECTORS_PER_PAGE; page++) {
         unsigned long page_addr = (unsigned long) dma_malloc_pages[page];
         if ((unsigned long) obj >= page_addr &&
@@ -2426,10 +2426,10 @@
 
             save_flags(flags);
             cli();
-            if((dma_malloc_freelist[page] & 
+            if((dma_malloc_freelist[page] &
                 (mask << sector)) != (mask<<sector)){
 #ifdef DEBUG
-		printk("scsi_free(obj=%p, len=%d) called from %08lx\n", 
+		printk("scsi_free(obj=%p, len=%d) called from %08lx\n",
                        obj, len, ret);
 #endif
                 panic("scsi_free:Trying to free unused memory");
@@ -2449,7 +2449,7 @@
 void * scsi_init_malloc(unsigned int size, int priority)
 {
     void * retval;
-    
+
     /*
      * For buffers used by the DMA pool, we assume page aligned 
      * structures.
@@ -2471,7 +2471,7 @@
 
 
 void scsi_init_free(char * ptr, unsigned int size)
-{ 
+{
     /*
      * We need this special code here because the DMA pool assumes
      * page aligned data.  Besides, it is wasteful to allocate
@@ -2492,12 +2492,12 @@
 {
     struct Scsi_Host *host = SDpnt->host;
     int j;
-    Scsi_Cmnd * SCpnt;                 
+    Scsi_Cmnd * SCpnt;
 
     if (SDpnt->queue_depth == 0)
         SDpnt->queue_depth = host->cmd_per_lun;
     SDpnt->device_queue = NULL;
- 
+
     for(j=0;j<SDpnt->queue_depth;j++){
       SCpnt = (Scsi_Cmnd *)
               scsi_init_malloc(sizeof(Scsi_Cmnd),
@@ -2531,7 +2531,7 @@
 
 /*
  * scsi_dev_init() is our initialization routine, which in turn calls host
- * initialization, bus scanning, and sd/st initialization routines. 
+ * initialization, bus scanning, and sd/st initialization routines.
  */
 
 int scsi_dev_init(void)
@@ -2544,19 +2544,19 @@
 #endif
 
     /* Yes we're here... */
-#if CONFIG_PROC_FS 
+#if CONFIG_PROC_FS
     dispatch_scsi_info_ptr = dispatch_scsi_info;
 #endif
 
     /* Init a few things so we can "malloc" memory. */
     scsi_loadable_module_flag = 0;
-    
+
     timer_table[SCSI_TIMER].fn = scsi_main_timeout;
     timer_table[SCSI_TIMER].expires = 0;
 
     /* Register the /proc/scsi/scsi entry */
-#if CONFIG_PROC_FS 
-    proc_scsi_register(0, &proc_scsi_scsi);    
+#if CONFIG_PROC_FS
+    proc_scsi_register(0, &proc_scsi_scsi);
 #endif
 
     /* initialize all hosts */
@@ -2576,7 +2576,7 @@
 	    printk("%d SCSI %s%s ", sdtpnt->dev_noticed, sdtpnt->name,
 		   (sdtpnt->dev_noticed != 1) ? "s" : "");
     printk("total.\n");
-    
+
     for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
 	if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)();
 
@@ -2586,7 +2586,7 @@
 	    if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt);
 	if(SDpnt->attached) scsi_build_commandblocks(SDpnt);
     }
-    
+
 
     /*
      * This should build the DMA pool.
@@ -2595,7 +2595,7 @@
 
     /*
      * OK, now we finish the initialization by doing spin-up, read
-     * capacity, etc, etc 
+     * capacity, etc, etc
      */
     for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
 	if(sdtpnt->finish && sdtpnt->nr_dev)
@@ -2609,7 +2609,7 @@
 static void print_inquiry(unsigned char *data)
 {
     int i;
-    
+
     printk("  Vendor: ");
     for (i = 8; i < 16; i++)
     {
@@ -2618,7 +2618,7 @@
 	else
 	    printk(" ");
     }
-    
+
     printk("  Model: ");
     for (i = 16; i < 32; i++)
     {
@@ -2627,7 +2627,7 @@
 	else
 	    printk(" ");
     }
-    
+
     printk("  Rev: ");
     for (i = 32; i < 36; i++)
     {
@@ -2636,11 +2636,11 @@
 	else
 	    printk(" ");
     }
-    
+
     printk("\n");
-    
+
     i = data[0] & 0x1f;
-    
+
     printk("  Type:   %s ",
 	   i < MAX_SCSI_DEVICE_CODE ? scsi_device_types[i] : "Unknown          " );
     printk("                 ANSI SCSI revision: %02x", data[2] & 0x07);
@@ -2652,7 +2652,7 @@
 
 
 #ifdef CONFIG_PROC_FS
-int scsi_proc_info(char *buffer, char **start, off_t offset, int length, 
+int scsi_proc_info(char *buffer, char **start, off_t offset, int length,
 		    int hostno, int inout)
 {
     Scsi_Cmnd *SCpnt;
@@ -2668,24 +2668,24 @@
     scd = scsi_devices;
     HBA_ptr = scsi_hostlist;
 
-    if(inout == 0) { 
+    if(inout == 0) {
 	size = sprintf(buffer+len,"Attached devices: %s\n", (scd)?"":"none");
-	len += size; 
+	len += size;
 	pos = begin + len;
 	while (HBA_ptr) {
 #if 0
-	    size += sprintf(buffer+len,"scsi%2d: %s\n", (int) HBA_ptr->host_no, 
+	    size += sprintf(buffer+len,"scsi%2d: %s\n", (int) HBA_ptr->host_no,
 	                    HBA_ptr->hostt->procname);
-	    len += size; 
+	    len += size;
 	    pos = begin + len;
 #endif
 	    scd = scsi_devices;
 	    while (scd) {
 		if (scd->host == HBA_ptr) {
 		    proc_print_scsidevice(scd, buffer, &size, len);
-		    len += size; 
+		    len += size;
 		    pos = begin + len;
-		    
+
 		    if (pos < offset) {
 			len = 0;
 			begin = pos;
@@ -2697,13 +2697,13 @@
 	    }
 	    HBA_ptr = HBA_ptr->next;
 	}
-	
+
     stop_output:
 	*start=buffer+(offset-begin);   /* Start of wanted data */
 	len-=(offset-begin);	        /* Start slop */
 	if(len>length)
 	    len = length;		/* Ending slop */
-	return (len);     
+	return (len);
     }
 
     if(!buffer || length < 25 || strncmp("scsi", buffer, 4))
@@ -2715,9 +2715,9 @@
      * Consider this feature BETA.
      *     CAUTION: This is not for hotplugging your peripherals. As
      *     SCSI was not designed for this you could damage your
-     *     hardware !  
+     *     hardware !
      * However perhaps it is legal to switch on an
-     * already connected device. It is perhaps not 
+     * already connected device. It is perhaps not
      * guaranteed this device doesn't corrupt an ongoing data transfer.
      */
     if(!strncmp("add-single-device", buffer + 5, 17)) {
@@ -2731,9 +2731,9 @@
 	printk("scsi singledevice %d %d %d %d\n", host, channel,
 			id, lun);
 
-	while(scd && (scd->host->host_no != host 
-	      || scd->channel != channel 
-	      || scd->id != id 
+	while(scd && (scd->host->host_no != host
+	      || scd->channel != channel
+	      || scd->id != id
 	      || scd->lun != lun)) {
 	    scd = scd->next;
 	}
@@ -2747,8 +2747,8 @@
 
 	scan_scsis (HBA_ptr, 1, channel, id, lun);
 	return(length);
-        
-    } 
+
+    }
 
     /*
      * Usage: echo "scsi remove-single-device 0 1 2 3" >/proc/scsi/scsi
@@ -2758,40 +2758,40 @@
      *
      *     CAUTION: This is not for hotplugging your peripherals. As
      *     SCSI was not designed for this you could damage your
-     *     hardware and thoroughly confuse the SCSI subsystem.  
+     *     hardware and thoroughly confuse the SCSI subsystem.
      *
      */
     else if(!strncmp("remove-single-device", buffer + 5, 20)) {
         p = buffer + 26;
-        
+
         host    = simple_strtoul(p, &p, 0);
         channel = simple_strtoul(p+1, &p, 0);
         id      = simple_strtoul(p+1, &p, 0);
         lun     = simple_strtoul(p+1, &p, 0);
-        
+
         while(scd != NULL) {
-            if(scd->host->host_no == host  
-               && scd->channel == channel 
-               && scd->id == id 
+            if(scd->host->host_no == host
+               && scd->channel == channel
+               && scd->id == id
                && scd->lun == lun){
-                break;                
+                break;
             }
             scd_h = scd;
             scd = scd->next;
         }
-        
+
         if(scd == NULL)
             return(-ENODEV);  /* there is no such device attached */
-        
+
         if(scd->access_count)
             return(-EBUSY);
-        
+
         SDTpnt = scsi_devicelist;
         while(SDTpnt != NULL) {
             if(SDTpnt->detach) (*SDTpnt->detach)(scd);
             SDTpnt = SDTpnt->next;
         }
-        
+
         if(scd->attached == 0) {
             /*
              * Nobody is using this device any more.
@@ -2814,7 +2814,7 @@
             } else if (scsi_devices == scd) {
                 /* We had a hit on the first entry of the device list */
                 scsi_devices = scd->next;
-            } 
+            }
             scsi_init_free((char *) scd, sizeof(Scsi_Device));
         } else {
             return(-EBUSY);
@@ -2865,24 +2865,24 @@
 	return;
     }
     /* Next, check to see if we need to extend the DMA buffer pool */
-	
+
     new_dma_sectors = 2*SECTORS_PER_PAGE;		/* Base value we use */
 
     if (__pa(high_memory)-1 > ISA_DMA_THRESHOLD)
 	scsi_need_isa_bounce_buffers = 1;
     else
 	scsi_need_isa_bounce_buffers = 0;
-    
+
     if (scsi_devicelist)
 	for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
 	    new_dma_sectors += SECTORS_PER_PAGE;	/* Increment for each host */
-    
+
     for (SDpnt=scsi_devices; SDpnt; SDpnt = SDpnt->next) {
 	host = SDpnt->host;
 
 	/*
 	 * sd and sr drivers allocate scatterlists.
-	 * sr drivers may allocate for each command 1x2048 or 2x1024 extra 
+	 * sr drivers may allocate for each command 1x2048 or 2x1024 extra
 	 * buffers for 2k sector size and 1k fs.
 	 * sg driver allocates buffers < 4k.
 	 * st driver does not need buffers from the dma pool.
@@ -2921,7 +2921,7 @@
 
     /* limit DMA memory to 32MB: */
     new_dma_sectors = (new_dma_sectors + 15) & 0xfff0;
-    
+
     /*
      * We never shrink the buffers - this leads to
      * race conditions that I would rather not even think
@@ -2929,7 +2929,7 @@
      */
     if( new_dma_sectors < dma_sectors )
 	new_dma_sectors = dma_sectors;
-    
+
     if (new_dma_sectors)
     {
         size = (new_dma_sectors / SECTORS_PER_PAGE)*sizeof(FreeSectorBitmap);
@@ -2940,7 +2940,7 @@
 	new_dma_malloc_pages = (unsigned char **) scsi_init_malloc(size, GFP_ATOMIC);
 	memset(new_dma_malloc_pages, 0, size);
     }
-    
+
     /*
      * If we need more buffers, expand the list.
      */
@@ -2949,9 +2949,9 @@
 	    new_dma_malloc_pages[i] = (unsigned char *)
 	        scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA);
     }
-    
-    /* When we dick with the actual DMA list, we need to 
-     * protect things 
+
+    /* When we dick with the actual DMA list, we need to
+     * protect things
      */
     save_flags(flags);
     cli();
@@ -2962,14 +2962,14 @@
 	scsi_init_free((char *) dma_malloc_freelist, size);
     }
     dma_malloc_freelist = new_dma_malloc_freelist;
-    
+
     if (dma_malloc_pages)
     {
         size = (dma_sectors / SECTORS_PER_PAGE)*sizeof(*dma_malloc_pages);
 	memcpy(new_dma_malloc_pages, dma_malloc_pages, size);
 	scsi_init_free((char *) dma_malloc_pages, size);
     }
-    
+
     dma_free_sectors += new_dma_sectors - dma_sectors;
     dma_malloc_pages = new_dma_malloc_pages;
     dma_sectors = new_dma_sectors;
@@ -2996,9 +2996,9 @@
     Scsi_Device * SDpnt;
     struct Scsi_Device_Template * sdtpnt;
     const char * name;
-    
+
     if (tpnt->next || !tpnt->detect) return 1;/* Must be already loaded, or
-					       * no detect routine available 
+					       * no detect routine available
 					       */
     pcount = next_scsi_host;
     if ((tpnt->present = tpnt->detect(tpnt)))
@@ -3010,18 +3010,18 @@
 		return 1;
 	    }
 	    /* The low-level driver failed to register a driver.  We
-	     *  can do this now. 
+	     *  can do this now.
 	     */
 	    scsi_register(tpnt,0);
 	}
 	tpnt->next = scsi_hosts; /* Add to the linked list */
 	scsi_hosts = tpnt;
-	
+
 	/* Add the new driver to /proc/scsi */
-#if CONFIG_PROC_FS 
+#if CONFIG_PROC_FS
 	build_proc_dir_entries(tpnt);
 #endif
-	
+
 	for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
 	    if(shpnt->hostt == tpnt)
 	    {
@@ -3032,28 +3032,28 @@
 		printk ("scsi%d : %s\n", /* And print a little message */
 			shpnt->host_no, name);
 	    }
-	
+
 	printk ("scsi : %d host%s.\n", next_scsi_host,
 		(next_scsi_host == 1) ? "" : "s");
-	
+
 	scsi_make_blocked_list();
-	
+
 	/* The next step is to call scan_scsis here.  This generates the
-	 * Scsi_Devices entries 
+	 * Scsi_Devices entries
 	 */
-	
+
 	for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
 	    if(shpnt->hostt == tpnt) {
 	      scan_scsis(shpnt,0,0,0,0);
 	      if (shpnt->select_queue_depths != NULL)
 		  (shpnt->select_queue_depths)(shpnt, scsi_devices);
 	    }
-	
+
 	for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
 	    if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)();
-	
+
 	/* Next we create the Scsi_Cmnd structures for this host */
-	
+
 	for(SDpnt = scsi_devices; SDpnt; SDpnt = SDpnt->next)
 	    if(SDpnt->host->hostt == tpnt)
 	    {
@@ -3061,7 +3061,7 @@
 		    if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt);
 		if(SDpnt->attached) scsi_build_commandblocks(SDpnt);
 	    }
-	
+
 	/*
 	 * Now that we have all of the devices, resize the DMA pool,
 	 * as required.  */
@@ -3073,14 +3073,14 @@
 	    if(sdtpnt->finish && sdtpnt->nr_dev)
 		(*sdtpnt->finish)();
     }
-    
+
 #if defined(USE_STATIC_SCSI_MEMORY)
     printk ("SCSI memory: total %ldKb, used %ldKb, free %ldKb.\n",
 	    (scsi_memory_upper_value - scsi_memory_lower_value) / 1024,
 	    (scsi_init_memory_start - scsi_memory_lower_value) / 1024,
 	    (scsi_memory_upper_value - scsi_init_memory_start) / 1024);
 #endif
-	
+
     MOD_INC_USE_COUNT;
     return 0;
 }
@@ -3098,14 +3098,14 @@
     struct Scsi_Device_Template * sdtpnt;
     struct Scsi_Host * shpnt, *sh1;
     int pcount;
-    
+
     /* First verify that this host adapter is completely free with no pending
      * commands */
-    
+
     for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt->next)
-	if(sdpnt->host->hostt == tpnt && sdpnt->host->hostt->usage_count
-	   && *sdpnt->host->hostt->usage_count) return;
-    
+	if(sdpnt->host->hostt == tpnt && sdpnt->host->hostt->module
+	   && sdpnt->host->hostt->module->usecount) return;
+
     for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
     {
 	if (shpnt->hostt != tpnt) continue;
@@ -3126,7 +3126,7 @@
 	}
     }
     /* Next we detach the high level drivers from the Scsi_Device structures */
-    
+
     for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt->next)
 	if(sdpnt->host->hostt == tpnt)
 	{
@@ -3138,9 +3138,9 @@
 		return;
 	    }
 	}
-    
+
     /* Next we free up the Scsi_Cmnd structures for this host */
-    
+
     for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt->next)
 	if(sdpnt->host->hostt == tpnt)
 	    while (sdpnt->host->host_queue) {
@@ -3150,9 +3150,9 @@
 		if (SCpnt) SCpnt->prev = NULL;
 		sdpnt->has_cmdblocks = 0;
 	    }
-    
+
     /* Next free up the Scsi_Device structures for this host */
-    
+
     sdppnt = NULL;
     for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt1)
     {
@@ -3166,10 +3166,10 @@
 	} else
 	    sdppnt = sdpnt;
     }
-    
+
     /* Next we go through and remove the instances of the individual hosts
      * that were detected */
-    
+
     shpnt = scsi_hostlist;
     while(shpnt) {
 	sh1 = shpnt->next;
@@ -3177,16 +3177,16 @@
 	    if(shpnt->loaded_as_module) {
 		pcount = next_scsi_host;
 	        /* Remove the /proc/scsi directory entry */
-#if CONFIG_PROC_FS 
-	        proc_scsi_unregister(tpnt->proc_dir, 
+#if CONFIG_PROC_FS
+	        proc_scsi_unregister(tpnt->proc_dir,
 	                             shpnt->host_no + PROC_SCSI_FILE);
-#endif   
+#endif
 		if(tpnt->release)
 		    (*tpnt->release)(shpnt);
 		else {
-		    /* This is the default case for the release function.  
-		     * It should do the right thing for most correctly 
-		     * written host adapters. 
+		    /* This is the default case for the release function.
+		     * It should do the right thing for most correctly
+		     * written host adapters.
 		     */
 		    if (shpnt->irq) free_irq(shpnt->irq, NULL);
 		    if (shpnt->dma_channel != 0xff) free_dma(shpnt->dma_channel);
@@ -3199,7 +3199,7 @@
 	}
 	shpnt = sh1;
     }
-    
+
     /*
      * If there are absolutely no more hosts left, it is safe
      * to completely nuke the DMA pool.  The resize operation will
@@ -3210,20 +3210,20 @@
 
     printk ("scsi : %d host%s.\n", next_scsi_host,
 	    (next_scsi_host == 1) ? "" : "s");
-    
+
 #if defined(USE_STATIC_SCSI_MEMORY)
     printk ("SCSI memory: total %ldKb, used %ldKb, free %ldKb.\n",
 	    (scsi_memory_upper_value - scsi_memory_lower_value) / 1024,
 	    (scsi_init_memory_start - scsi_memory_lower_value) / 1024,
 	    (scsi_memory_upper_value - scsi_init_memory_start) / 1024);
 #endif
-    
+
     scsi_make_blocked_list();
-    
+
     /* There were some hosts that were loaded at boot time, so we cannot
        do any more than this */
     if (tpnt->present) return;
-    
+
     /* OK, this is the very last step.  Remove this host adapter from the
        linked list. */
     for(SHTp=NULL, SHT=scsi_hosts; SHT; SHTp=SHT, SHT=SHT->next)
@@ -3235,9 +3235,9 @@
 	    SHT->next = NULL;
 	    break;
 	}
-    
+
     /* Rebuild the /proc/scsi directory entries */
-#if CONFIG_PROC_FS 
+#if CONFIG_PROC_FS
     proc_scsi_unregister(tpnt->proc_dir, tpnt->proc_dir->low_ino);
 #endif
     MOD_DEC_USE_COUNT;
@@ -3250,24 +3250,24 @@
 static int scsi_register_device_module(struct Scsi_Device_Template * tpnt)
 {
     Scsi_Device * SDpnt;
-    
+
     if (tpnt->next) return 1;
-    
+
     scsi_register_device(tpnt);
     /*
      * First scan the devices that we know about, and see if we notice them.
      */
-    
+
     for(SDpnt = scsi_devices; SDpnt; SDpnt = SDpnt->next)
 	if(tpnt->detect) SDpnt->attached += (*tpnt->detect)(SDpnt);
-    
+
     /*
      * If any of the devices would match this driver, then perform the
      * init function.
      */
     if(tpnt->init && tpnt->dev_noticed)
 	if ((*tpnt->init)()) return 1;
-    
+
     /*
      * Now actually connect the devices to the new driver.
      */
@@ -3281,9 +3281,9 @@
 	if(SDpnt->attached && SDpnt->has_cmdblocks == 0)
 	    scsi_build_commandblocks(SDpnt);
     }
-    
+
     /*
-     * This does any final handling that is required. 
+     * This does any final handling that is required.
      */
     if(tpnt->finish && tpnt->nr_dev)  (*tpnt->finish)();
     MOD_INC_USE_COUNT;
@@ -3296,15 +3296,16 @@
     Scsi_Cmnd * SCpnt;
     struct Scsi_Device_Template * spnt;
     struct Scsi_Device_Template * prev_spnt;
-    
+
     /*
      * If we are busy, this is not going to fly.
      */
-    if( *tpnt->usage_count != 0) return 0;
+    if(tpnt->module->usecount != 0) return 0;
+
     /*
      * Next, detach the devices from the driver.
      */
-    
+
     for(SDpnt = scsi_devices; SDpnt; SDpnt = SDpnt->next)
     {
 	if(tpnt->detach) (*tpnt->detach)(SDpnt);
@@ -3344,10 +3345,10 @@
 	scsi_devicelist = tpnt->next;
     else
 	prev_spnt->next = spnt->next;
-    
+
     MOD_DEC_USE_COUNT;
     /*
-     * Final cleanup for the driver is done in the driver sources in the 
+     * Final cleanup for the driver is done in the driver sources in the
      * cleanup function.
      */
     return 0;
@@ -3359,7 +3360,7 @@
     switch(module_type){
     case MODULE_SCSI_HA:
 	return scsi_register_host((Scsi_Host_Template *) ptr);
-	
+
 	/* Load upper level device handler of some kind */
     case MODULE_SCSI_DEV:
 #ifdef CONFIG_KERNELD
@@ -3368,14 +3369,14 @@
 #endif
 	return scsi_register_device_module((struct Scsi_Device_Template *) ptr);
 	/* The rest of these are not yet implemented */
-	
+
 	/* Load constants.o */
     case MODULE_SCSI_CONST:
-	
-	/* Load specialized ioctl handler for some device.  Intended for 
+
+	/* Load specialized ioctl handler for some device.  Intended for
 	 * cdroms that have non-SCSI2 audio command sets. */
     case MODULE_SCSI_IOCTL:
-	
+
     default:
 	return 1;
     }
@@ -3478,14 +3479,14 @@
     proc_scsi_register(0, &proc_scsi_scsi);
 #endif
 
-    
+
     dma_sectors = PAGE_SIZE / SECTOR_SIZE;
     dma_free_sectors= dma_sectors;
     /*
      * Set up a minimal DMA buffer list - this will be used during scan_scsis
      * in some cases.
      */
-    
+
     /* One bit per sector to indicate free/busy */
     size = (dma_sectors / SECTORS_PER_PAGE)*sizeof(FreeSectorBitmap);
     dma_malloc_freelist = (unsigned char *) scsi_init_malloc(size, GFP_ATOMIC);
@@ -3499,7 +3500,7 @@
     return 0;
 }
 
-void cleanup_module( void) 
+void cleanup_module( void)
 {
 #if CONFIG_PROC_FS
     proc_scsi_unregister(0, PROC_SCSI_SCSI);
diff -u --recursive --new-file v2.1.22/linux/drivers/scsi/scsi_module.c linux/drivers/scsi/scsi_module.c
--- v2.1.22/linux/drivers/scsi/scsi_module.c	Mon Dec 30 15:39:11 1996
+++ linux/drivers/scsi/scsi_module.c	Sun Jan 26 12:07:19 1997
@@ -32,7 +32,7 @@
 #include <linux/module.h>
 
 int init_module(void) {
-    driver_template.usage_count = &__this_module.usecount;
+    driver_template.module = &__this_module;
     scsi_register_module(MODULE_SCSI_HA, &driver_template);
     return (driver_template.present == 0);
 }
diff -u --recursive --new-file v2.1.22/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- v2.1.22/linux/drivers/scsi/sd.c	Thu Jan 23 21:06:49 1997
+++ linux/drivers/scsi/sd.c	Sun Jan 26 12:07:20 1997
@@ -1,9 +1,9 @@
 /*
- *      sd.c Copyright (C) 1992 Drew Eckhardt 
+ *      sd.c Copyright (C) 1992 Drew Eckhardt
  *           Copyright (C) 1993, 1994, 1995 Eric Youngdale
  *
  *      Linux scsi disk driver
- *              Initial versions: Drew Eckhardt 
+ *              Initial versions: Drew Eckhardt
  *              Subsequent revisions: Eric Youngdale
  *
  *      <drew@colorado.edu>
@@ -87,8 +87,8 @@
 static int sd_detect(Scsi_Device *);
 static void sd_detach(Scsi_Device *);
 
-struct Scsi_Device_Template sd_template = 
-{ NULL, "disk", "sd", NULL, TYPE_DISK, 
+struct Scsi_Device_Template sd_template =
+{ NULL, "disk", "sd", NULL, TYPE_DISK,
       SCSI_DISK_MAJOR, 0, 0, 0, 1,
       sd_detect, sd_init,
       sd_finish, sd_attach, sd_detach
@@ -98,21 +98,21 @@
 {
     int target;
     target =  DEVICE_NR(inode->i_rdev);
-    
+
     if(target >= sd_template.dev_max || !rscsi_disks[target].device)
 	return -ENXIO;   /* No such device */
-    
-    /* 
+
+    /*
      * Make sure that only one process can do a check_change_disk at one time.
-     * This is also used to lock out further access when the partition table 
-     * is being re-read. 
+     * This is also used to lock out further access when the partition table
+     * is being re-read.
      */
-    
+
     while (rscsi_disks[target].device->busy)
-        barrier();   
+        barrier();
     if(rscsi_disks[target].device->removable) {
 	check_disk_change(inode->i_rdev);
-	
+
 	/*
 	 * If the drive is empty, just let the open fail.
 	 */
@@ -134,15 +134,16 @@
      */
     if(sd_sizes[MINOR(inode->i_rdev)] == 0)
 	return -ENXIO;
-    
+
     if(rscsi_disks[target].device->removable)
 	if(!rscsi_disks[target].device->access_count)
 	    sd_ioctl(inode, NULL, SCSI_IOCTL_DOORLOCK, 0);
 
     rscsi_disks[target].device->access_count++;
-    if (rscsi_disks[target].device->host->hostt->usage_count)
-	(*rscsi_disks[target].device->host->hostt->usage_count)++;
-    if(sd_template.usage_count) (*sd_template.usage_count)++;
+    if (rscsi_disks[target].device->host->hostt->module)
+        __MOD_INC_USE_COUNT(rscsi_disks[target].device->host->hostt->module);
+    if(sd_template.module)
+        __MOD_INC_USE_COUNT(sd_template.module);
     return 0;
 }
 
@@ -150,18 +151,20 @@
 {
     int target;
     fsync_dev(inode->i_rdev);
-    
+
     target =  DEVICE_NR(inode->i_rdev);
-    
+
     rscsi_disks[target].device->access_count--;
-    if (rscsi_disks[target].device->host->hostt->usage_count)
-	(*rscsi_disks[target].device->host->hostt->usage_count)--;
-    if(sd_template.usage_count) (*sd_template.usage_count)--;
-    
+
     if(rscsi_disks[target].device->removable) {
 	if(!rscsi_disks[target].device->access_count)
 	    sd_ioctl(inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0);
     }
+
+    if(rscsi_disks[target].device->host->hostt->module)
+        __MOD_DEC_USE_COUNT(rscsi_disks[target].device->host->hostt->module);
+    if(sd_template.module)
+        __MOD_DEC_USE_COUNT(sd_template.module);
 }
 
 static void sd_geninit(struct gendisk *);
@@ -199,9 +202,9 @@
 static void sd_geninit (struct gendisk *ignored)
 {
     int i;
-    
+
     for (i = 0; i < sd_template.dev_max; ++i)
-	if(rscsi_disks[i].device) 
+	if(rscsi_disks[i].device)
 	    sd[i << 4].nr_sects = rscsi_disks[i].capacity;
 #if 0
     /* No longer needed - we keep track of this as we attach/detach */
@@ -221,9 +224,9 @@
     int this_count = SCpnt->bufflen >> 9;
     int good_sectors = (result == 0 ? this_count : 0);
     int block_sectors = 1;
-    
+
 #ifdef DEBUG
-    printk("sd%c : rw_intr(%d, %d)\n", 'a' + MINOR(SCpnt->request.rq_dev), 
+    printk("sd%c : rw_intr(%d, %d)\n", 'a' + MINOR(SCpnt->request.rq_dev),
 	   SCpnt->host->host_no, result);
 #endif
 
@@ -258,15 +261,15 @@
 	if (good_sectors < 0 || good_sectors >= this_count)
 	  good_sectors = 0;
       }
-    
+
     /*
-     * First case : we assume that the command succeeded.  One of two things 
+     * First case : we assume that the command succeeded.  One of two things
      * will happen here.  Either we will be finished, or there will be more
      * sectors that we were unable to read last time.
      */
 
     if (good_sectors > 0) {
-	
+
 #ifdef DEBUG
 	printk("sd%c : %d sectors remain.\n", 'a' + MINOR(SCpnt->request.rq_dev),
 	       SCpnt->request.nr_sectors);
@@ -278,25 +281,25 @@
 	    sgpnt = (struct scatterlist *) SCpnt->buffer;
 	    for(i=0; i<SCpnt->use_sg; i++) {
 #ifdef DEBUG
-		printk(":%x %x %d\n",sgpnt[i].alt_address, sgpnt[i].address, 
+		printk(":%x %x %d\n",sgpnt[i].alt_address, sgpnt[i].address,
 		       sgpnt[i].length);
 #endif
 		if (sgpnt[i].alt_address) {
 		    if (SCpnt->request.cmd == READ)
-			memcpy(sgpnt[i].alt_address, sgpnt[i].address, 
+			memcpy(sgpnt[i].alt_address, sgpnt[i].address,
 			       sgpnt[i].length);
 		    scsi_free(sgpnt[i].address, sgpnt[i].length);
 		}
 	    }
 
 	    /* Free list of scatter-gather pointers */
-	    scsi_free(SCpnt->buffer, SCpnt->sglist_len);  
+	    scsi_free(SCpnt->buffer, SCpnt->sglist_len);
 	} else {
 	    if (SCpnt->buffer != SCpnt->request.buffer) {
 #ifdef DEBUG
 		printk("nosg: %x %x %d\n",SCpnt->request.buffer, SCpnt->buffer,
 		       SCpnt->bufflen);
-#endif  
+#endif
 		if (SCpnt->request.cmd == READ)
 		    memcpy(SCpnt->request.buffer, SCpnt->buffer,
 			   SCpnt->bufflen);
@@ -311,7 +314,7 @@
 	if (SCpnt->request.nr_sectors > this_count)
 	{
 	    SCpnt->request.errors = 0;
-	    
+
 	    if (!SCpnt->request.bh)
 	    {
 #ifdef DEBUG
@@ -319,7 +322,7 @@
 		       'a' + MINOR(SCpnt->request.rq_dev));
 #endif
 		/*
-		 * The SCpnt->request.nr_sectors field is always done in 
+		 * The SCpnt->request.nr_sectors field is always done in
 		 * 512 byte sectors, even if this really isn't the case.
 		 */
 		panic("sd.c: linked page request (%lx %x)",
@@ -333,7 +336,7 @@
 	    return;
 	  }
     }
-    
+
     if (good_sectors == 0) {
 
     /* Free up any indirection buffers we allocated for DMA purposes. */
@@ -381,13 +384,13 @@
 	    else
 #endif
 	}
-	
+
 	if ((SCpnt->sense_buffer[0] & 0x7f) == 0x70) {
 	    if ((SCpnt->sense_buffer[2] & 0xf) == UNIT_ATTENTION) {
 		if(rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->removable) {
 		    /* detected disc change.  set a bit and quietly refuse
 		     * further access.
-		     */  
+		     */
 		    rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->changed = 1;
 		    SCpnt = end_scsi_request(SCpnt, 0, this_count);
 		    requeue_sd_request(SCpnt);
@@ -405,13 +408,13 @@
                 }
 	    }
 	}
-	
-	
+
+
 	/* If we had an ILLEGAL REQUEST returned, then we may have
-	 * performed an unsupported command.  The only thing this should be 
+	 * performed an unsupported command.  The only thing this should be
 	 * would be a ten byte read where only a six byte read was supported.
-	 * Also, on a system where READ CAPACITY failed, we have have read 
-	 * past the end of the disk. 
+	 * Also, on a system where READ CAPACITY failed, we have have read
+	 * past the end of the disk.
 	 */
 
 	if (SCpnt->sense_buffer[2] == ILLEGAL_REQUEST) {
@@ -426,7 +429,7 @@
 
 	if (SCpnt->sense_buffer[2] == MEDIUM_ERROR) {
 	    printk("scsi%d: MEDIUM ERROR on channel %d, id %d, lun %d, CDB: ",
-		   SCpnt->host->host_no, (int) SCpnt->channel, 
+		   SCpnt->host->host_no, (int) SCpnt->channel,
 		   (int) SCpnt->target, (int) SCpnt->lun);
 	    print_command(SCpnt->cmnd);
 	    print_sense("sd", SCpnt);
@@ -441,7 +444,7 @@
 	       rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->channel,
 	   rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->id,
 	     rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->lun, result);
-	
+
 	if (driver_byte(result) & DRIVER_SENSE)
 	    print_sense("sd", SCpnt);
 	SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.current_nr_sectors);
@@ -463,7 +466,7 @@
     struct request * req = NULL;
     unsigned long flags;
     int flag = 0;
-    
+
     save_flags(flags);
     while (1==1){
 	cli();
@@ -471,10 +474,10 @@
 	    restore_flags(flags);
 	    return;
 	}
-	
+
 	INIT_SCSI_REQUEST;
         SDev = rscsi_disks[DEVICE_NR(CURRENT->rq_dev)].device;
-        
+
         /*
          * I am not sure where the best place to do this is.  We need
          * to hook in a place where we are likely to come if in user
@@ -497,25 +500,25 @@
 	    }
 	    SDev->was_reset = 0;
         }
-		
+
 	/* We have to be careful here. allocate_device will get a free pointer,
-	 * but there is no guarantee that it is queueable.  In normal usage, 
-	 * we want to call this, because other types of devices may have the 
-	 * host all tied up, and we want to make sure that we have at least 
-	 * one request pending for this type of device. We can also come 
-	 * through here while servicing an interrupt, because of the need to 
-	 * start another command. If we call allocate_device more than once, 
-	 * then the system can wedge if the command is not queueable. The 
-	 * request_queueable function is safe because it checks to make sure 
+	 * but there is no guarantee that it is queueable.  In normal usage,
+	 * we want to call this, because other types of devices may have the
+	 * host all tied up, and we want to make sure that we have at least
+	 * one request pending for this type of device. We can also come
+	 * through here while servicing an interrupt, because of the need to
+	 * start another command. If we call allocate_device more than once,
+	 * then the system can wedge if the command is not queueable. The
+	 * request_queueable function is safe because it checks to make sure
 	 * that the host is able to take another command before it returns
-	 * a pointer.  
+	 * a pointer.
 	 */
 
 	if (flag++ == 0)
 	    SCpnt = allocate_device(&CURRENT,
-			   rscsi_disks[DEVICE_NR(CURRENT->rq_dev)].device, 0); 
+			   rscsi_disks[DEVICE_NR(CURRENT->rq_dev)].device, 0);
 	else SCpnt = NULL;
-	
+
 	/*
 	 * The following restore_flags leads to latency problems.  FIXME.
 	 * Using a "sti()" gets rid of the latency problems but causes
@@ -523,13 +526,13 @@
 	 */
 	restore_flags(flags);
 
-	/* This is a performance enhancement. We dig down into the request 
-	 * list and try to find a queueable request (i.e. device not busy, 
-	 * and host able to accept another command. If we find one, then we 
-	 * queue it. This can make a big difference on systems with more than 
-	 * one disk drive.  We want to have the interrupts off when monkeying 
-	 * with the request list, because otherwise the kernel might try to 
-	 * slip in a request in between somewhere. 
+	/* This is a performance enhancement. We dig down into the request
+	 * list and try to find a queueable request (i.e. device not busy,
+	 * and host able to accept another command. If we find one, then we
+	 * queue it. This can make a big difference on systems with more than
+	 * one disk drive.  We want to have the interrupts off when monkeying
+	 * with the request list, because otherwise the kernel might try to
+	 * slip in a request in between somewhere.
 	 */
 
 	if (!SCpnt && sd_template.nr_dev > 1){
@@ -538,27 +541,27 @@
 	    cli();
 	    req = CURRENT;
 	    while(req){
-		SCpnt = request_queueable(req, 
+		SCpnt = request_queueable(req,
                                    rscsi_disks[DEVICE_NR(req->rq_dev)].device);
 		if(SCpnt) break;
 		req1 = req;
 		req = req->next;
 	    }
 	    if (SCpnt && req->rq_status == RQ_INACTIVE) {
-		if (req == CURRENT) 
+		if (req == CURRENT)
 		    CURRENT = CURRENT->next;
 		else
 		    req1->next = req->next;
 	    }
 	    restore_flags(flags);
 	}
-	
+
 	if (!SCpnt) return; /* Could not find anything to do */
-	
+
 	/* Queue command */
 	requeue_sd_request(SCpnt);
     }  /* While */
-}    
+}
 
 static void requeue_sd_request (Scsi_Cmnd * SCpnt)
 {
@@ -568,14 +571,14 @@
     int max_sg;
     struct buffer_head * bh, *bhp;
     char * buff, *bounce_buffer;
-    
+
  repeat:
-    
+
     if(!SCpnt || SCpnt->request.rq_status == RQ_INACTIVE) {
 	do_sd_request();
 	return;
     }
-    
+
     devm =  MINOR(SCpnt->request.rq_dev);
     dev = DEVICE_NR(SCpnt->request.rq_dev);
 
@@ -585,33 +588,33 @@
 #ifdef DEBUG
     printk("Doing sd request, dev = %d, block = %d\n", devm, block);
 #endif
-    
-    if (devm >= (sd_template.dev_max << 4) || 
+
+    if (devm >= (sd_template.dev_max << 4) ||
 	!rscsi_disks[dev].device ||
 	block + SCpnt->request.nr_sectors > sd[devm].nr_sects)
     {
 	SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
 	goto repeat;
     }
-    
+
     block += sd[devm].start_sect;
-    
+
     if (rscsi_disks[dev].device->changed)
     {
 	/*
-	 * quietly refuse to do anything to a changed disc until the changed 
+	 * quietly refuse to do anything to a changed disc until the changed
 	 * bit has been reset
 	 */
 	/* printk("SCSI disk has been changed. Prohibiting further I/O.\n"); */
 	SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
 	goto repeat;
     }
-    
+
 #ifdef DEBUG
-    printk("sd%c : real dev = /dev/sd%c, block = %d\n", 
+    printk("sd%c : real dev = /dev/sd%c, block = %d\n",
 	   'a' + devm, dev, block);
 #endif
-    
+
     /*
      * If we have a 1K hardware sectorsize, prevent access to single
      * 512 byte sectors.  In theory we could handle this - in fact
@@ -629,7 +632,7 @@
 	    SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
 	    goto repeat;
 	}
-    
+
     switch (SCpnt->request.cmd)
     {
     case WRITE :
@@ -646,71 +649,71 @@
     default :
 	panic ("Unknown sd command %d\n", SCpnt->request.cmd);
     }
-    
+
     SCpnt->this_count = 0;
-    
+
     /* If the host adapter can deal with very large scatter-gather
-     * requests, it is a waste of time to cluster 
+     * requests, it is a waste of time to cluster
      */
     contiguous = (!CLUSTERABLE_DEVICE(SCpnt) ? 0 :1);
     bounce_buffer = NULL;
     bounce_size = (SCpnt->request.nr_sectors << 9);
-    
-    /* First see if we need a bounce buffer for this request. If we do, make 
-     * sure that we can allocate a buffer. Do not waste space by allocating 
-     * a bounce buffer if we are straddling the 16Mb line 
-     */ 
+
+    /* First see if we need a bounce buffer for this request. If we do, make
+     * sure that we can allocate a buffer. Do not waste space by allocating
+     * a bounce buffer if we are straddling the 16Mb line
+     */
     if (contiguous && SCpnt->request.bh &&
-      virt_to_phys(SCpnt->request.bh->b_data) 
-	+ (SCpnt->request.nr_sectors << 9) - 1 > ISA_DMA_THRESHOLD 
+      virt_to_phys(SCpnt->request.bh->b_data)
+	+ (SCpnt->request.nr_sectors << 9) - 1 > ISA_DMA_THRESHOLD
 	&& SCpnt->host->unchecked_isa_dma) {
       if(virt_to_phys(SCpnt->request.bh->b_data) > ISA_DMA_THRESHOLD)
 	    bounce_buffer = (char *) scsi_malloc(bounce_size);
 	if(!bounce_buffer) contiguous = 0;
     }
-    
+
     if(contiguous && SCpnt->request.bh && SCpnt->request.bh->b_reqnext)
-	for(bh = SCpnt->request.bh, bhp = bh->b_reqnext; bhp; bh = bhp, 
+	for(bh = SCpnt->request.bh, bhp = bh->b_reqnext; bhp; bh = bhp,
 	    bhp = bhp->b_reqnext) {
-	    if(!CONTIGUOUS_BUFFERS(bh,bhp)) { 
+	    if(!CONTIGUOUS_BUFFERS(bh,bhp)) {
 		if(bounce_buffer) scsi_free(bounce_buffer, bounce_size);
 		contiguous = 0;
 		break;
-	    } 
+	    }
 	}
     if (!SCpnt->request.bh || contiguous) {
-	
+
 	/* case of page request (i.e. raw device), or unlinked buffer */
 	this_count = SCpnt->request.nr_sectors;
 	buff = SCpnt->request.buffer;
 	SCpnt->use_sg = 0;
-	
+
     } else if (SCpnt->host->sg_tablesize == 0 ||
 	       (need_isa_buffer && dma_free_sectors <= 10)) {
-	
+
 	/* Case of host adapter that cannot scatter-gather.  We also
 	 * come here if we are running low on DMA buffer memory.  We set
 	 * a threshold higher than that we would need for this request so
 	 * we leave room for other requests.  Even though we would not need
 	 * it all, we need to be conservative, because if we run low enough
-	 * we have no choice but to panic. 
+	 * we have no choice but to panic.
 	 */
 	if (SCpnt->host->sg_tablesize != 0 &&
-	    need_isa_buffer && 
+	    need_isa_buffer &&
 	    dma_free_sectors <= 10)
 	    printk("Warning: SCSI DMA buffer space running low.  Using non scatter-gather I/O.\n");
-	
+
 	this_count = SCpnt->request.current_nr_sectors;
 	buff = SCpnt->request.buffer;
 	SCpnt->use_sg = 0;
-	
+
     } else {
-	
+
 	/* Scatter-gather capable host adapter */
 	struct scatterlist * sgpnt;
 	int count, this_count_max;
 	int counted;
-	
+
 	bh = SCpnt->request.bh;
 	this_count = 0;
 	this_count_max = (rscsi_disks[dev].ten ? 0xffff : 0xff);
@@ -739,7 +742,7 @@
 
 	SCpnt->sglist_len = count;
 	max_sg = count / sizeof(struct scatterlist);
-	if(SCpnt->host->sg_tablesize < max_sg) 
+	if(SCpnt->host->sg_tablesize < max_sg)
 	    max_sg = SCpnt->host->sg_tablesize;
 	sgpnt = (struct scatterlist * ) scsi_malloc(count);
 	if (!sgpnt) {
@@ -749,37 +752,37 @@
 	    buff = SCpnt->request.buffer;
 	} else {
 	    memset(sgpnt, 0, count);  /* Zero so it is easy to fill, but only
-				       * if memory is available 
+				       * if memory is available
 				       */
 	    buff = (char *) sgpnt;
 	    counted = 0;
 	    for(count = 0, bh = SCpnt->request.bh, bhp = bh->b_reqnext;
-		count < SCpnt->use_sg && bh; 
+		count < SCpnt->use_sg && bh;
 		count++, bh = bhp) {
-		
+
 		bhp = bh->b_reqnext;
-		
+
 		if(!sgpnt[count].address) sgpnt[count].address = bh->b_data;
 		sgpnt[count].length += bh->b_size;
 		counted += bh->b_size >> 9;
-		
+
 		if (virt_to_phys(sgpnt[count].address) + sgpnt[count].length - 1 >
 		    ISA_DMA_THRESHOLD && (SCpnt->host->unchecked_isa_dma) &&
 		    !sgpnt[count].alt_address) {
 		    sgpnt[count].alt_address = sgpnt[count].address;
-		    /* We try to avoid exhausting the DMA pool, since it is 
-		     * easier to control usage here. In other places we might 
-		     * have a more pressing need, and we would be screwed if 
+		    /* We try to avoid exhausting the DMA pool, since it is
+		     * easier to control usage here. In other places we might
+		     * have a more pressing need, and we would be screwed if
 		     * we ran out */
 		    if(dma_free_sectors < (sgpnt[count].length >> 9) + 10) {
 			sgpnt[count].address = NULL;
 		    } else {
-			sgpnt[count].address = 
+			sgpnt[count].address =
 			    (char *) scsi_malloc(sgpnt[count].length);
 		    }
-		    /* If we start running low on DMA buffers, we abort the 
-		     * scatter-gather operation, and free all of the memory 
-		     * we have allocated.  We want to ensure that all scsi 
+		    /* If we start running low on DMA buffers, we abort the
+		     * scatter-gather operation, and free all of the memory
+		     * we have allocated.  We want to ensure that all scsi
 		     * operations are able to do at least a non-scatter/gather
 		     * operation */
 		    if(sgpnt[count].address == NULL){ /* Out of dma memory */
@@ -787,8 +790,8 @@
 			printk("Warning: Running low on SCSI DMA buffers");
 			/* Try switching back to a non s-g operation. */
 			while(--count >= 0){
-			    if(sgpnt[count].alt_address) 
-				scsi_free(sgpnt[count].address, 
+			    if(sgpnt[count].alt_address)
+				scsi_free(sgpnt[count].address,
 					  sgpnt[count].length);
 			}
 			this_count = SCpnt->request.current_nr_sectors;
@@ -799,25 +802,25 @@
 			SCpnt->use_sg = count;
 			this_count = counted -= bh->b_size >> 9;
 			break;
-		    }		    
+		    }
 		}
-		
-		/* Only cluster buffers if we know that we can supply DMA 
+
+		/* Only cluster buffers if we know that we can supply DMA
 		 * buffers large enough to satisfy the request. Do not cluster
-		 * a new request if this would mean that we suddenly need to 
+		 * a new request if this would mean that we suddenly need to
 		 * start using DMA bounce buffers */
-		if(bhp && CONTIGUOUS_BUFFERS(bh,bhp) 
+		if(bhp && CONTIGUOUS_BUFFERS(bh,bhp)
 		   && CLUSTERABLE_DEVICE(SCpnt)) {
 		    char * tmp;
-		    
+
 		  if (virt_to_phys(sgpnt[count].address) + sgpnt[count].length +
-			bhp->b_size - 1 > ISA_DMA_THRESHOLD && 
+			bhp->b_size - 1 > ISA_DMA_THRESHOLD &&
 			(SCpnt->host->unchecked_isa_dma) &&
 			!sgpnt[count].alt_address) continue;
-		    
+
 		    if(!sgpnt[count].alt_address) {count--; continue; }
 		    if(dma_free_sectors > 10)
-			tmp = (char *) scsi_malloc(sgpnt[count].length 
+			tmp = (char *) scsi_malloc(sgpnt[count].length
 						   + bhp->b_size);
 		    else {
 			tmp = NULL;
@@ -829,24 +832,24 @@
 			count--;
 			continue;
 		    }
-		    
-		    /* If we are allowed another sg chain, then increment 
-		     * counter so we can insert it.  Otherwise we will end 
+
+		    /* If we are allowed another sg chain, then increment
+		     * counter so we can insert it.  Otherwise we will end
 		     up truncating */
-		    
+
 		    if (SCpnt->use_sg < max_sg) SCpnt->use_sg++;
 		}  /* contiguous buffers */
 	    } /* for loop */
-	    
+
 	    /* This is actually how many we are going to transfer */
-	    this_count = counted; 
-	    
-	    if(count < SCpnt->use_sg || SCpnt->use_sg 
+	    this_count = counted;
+
+	    if(count < SCpnt->use_sg || SCpnt->use_sg
 	       > SCpnt->host->sg_tablesize){
 		bh = SCpnt->request.bh;
-		printk("Use sg, count %d %x %d\n", 
+		printk("Use sg, count %d %x %d\n",
 		       SCpnt->use_sg, count, dma_free_sectors);
-		printk("maxsg = %x, counted = %d this_count = %d\n", 
+		printk("maxsg = %x, counted = %d this_count = %d\n",
 		       max_sg, counted, this_count);
 		while(bh){
 		    printk("[%p %lx] ", bh->b_data, bh->b_size);
@@ -860,19 +863,19 @@
 			       sgpnt[count].length);
 		panic("Ooops");
 	    }
-	    
+
 	    if (SCpnt->request.cmd == WRITE)
 		for(count=0; count<SCpnt->use_sg; count++)
 		    if(sgpnt[count].alt_address)
-			memcpy(sgpnt[count].address, sgpnt[count].alt_address, 
+			memcpy(sgpnt[count].address, sgpnt[count].alt_address,
 			       sgpnt[count].length);
 	}  /* Able to malloc sgpnt */
     }  /* Host adapter capable of scatter-gather */
-    
+
     /* Now handle the possibility of DMA to addresses > 16Mb */
-    
+
     if(SCpnt->use_sg == 0){
-      if (virt_to_phys(buff) + (this_count << 9) - 1 > ISA_DMA_THRESHOLD && 
+      if (virt_to_phys(buff) + (this_count << 9) - 1 > ISA_DMA_THRESHOLD &&
 	    (SCpnt->host->unchecked_isa_dma)) {
 	    if(bounce_buffer)
 		buff = bounce_buffer;
@@ -888,31 +891,31 @@
 	}
     }
 #ifdef DEBUG
-    printk("sd%c : %s %d/%d 512 byte blocks.\n", 
+    printk("sd%c : %s %d/%d 512 byte blocks.\n",
 	   'a' + devm,
 	   (SCpnt->request.cmd == WRITE) ? "writing" : "reading",
 	   this_count, SCpnt->request.nr_sectors);
 #endif
-    
+
     cmd[1] = (SCpnt->lun << 5) & 0xe0;
-    
+
     if (rscsi_disks[dev].sector_size == 1024){
 	if(block & 1) panic("sd.c:Bad block number requested");
 	if(this_count & 1) panic("sd.c:Bad block number requested");
 	block = block >> 1;
 	this_count = this_count >> 1;
     }
-    
+
     if (rscsi_disks[dev].sector_size == 256){
 	block = block << 1;
 	this_count = this_count << 1;
     }
-    
+
     if (((this_count > 0xff) ||  (block > 0x1fffff)) && rscsi_disks[dev].ten)
     {
 	if (this_count > 0xffff)
 	    this_count = 0xffff;
-	
+
 	cmd[0] += READ_10 - READ_6 ;
 	cmd[2] = (unsigned char) (block >> 24) & 0xff;
 	cmd[3] = (unsigned char) (block >> 16) & 0xff;
@@ -926,26 +929,26 @@
     {
 	if (this_count > 0xff)
 	    this_count = 0xff;
-	
+
 	cmd[1] |= (unsigned char) ((block >> 16) & 0x1f);
 	cmd[2] = (unsigned char) ((block >> 8) & 0xff);
 	cmd[3] = (unsigned char) block & 0xff;
 	cmd[4] = (unsigned char) this_count;
 	cmd[5] = 0;
     }
-    
+
     /*
-     * We shouldn't disconnect in the middle of a sector, so with a dumb 
-     * host adapter, it's safe to assume that we can at least transfer 
-     * this many bytes between each connect / disconnect.  
+     * We shouldn't disconnect in the middle of a sector, so with a dumb
+     * host adapter, it's safe to assume that we can at least transfer
+     * this many bytes between each connect / disconnect.
      */
-    
+
     SCpnt->transfersize = rscsi_disks[dev].sector_size;
-    SCpnt->underflow = this_count << 9; 
-    scsi_do_cmd (SCpnt, (void *) cmd, buff, 
+    SCpnt->underflow = this_count << 9;
+    scsi_do_cmd (SCpnt, (void *) cmd, buff,
 		 this_count * rscsi_disks[dev].sector_size,
-		 rw_intr, 
-		 (SCpnt->device->type == TYPE_DISK ? 
+		 rw_intr,
+		 (SCpnt->device->type == TYPE_DISK ?
 		  SD_TIMEOUT : SD_MOD_TIMEOUT),
 		 MAX_RETRIES);
 }
@@ -955,37 +958,37 @@
     int target;
     struct inode inode;
     int flag = 0;
-    
+
     target =  DEVICE_NR(full_dev);
-    
+
     if (target >= sd_template.dev_max ||
 	!rscsi_disks[target].device) {
 	printk("SCSI disk request error: invalid device.\n");
 	return 0;
     }
-    
+
     if(!rscsi_disks[target].device->removable) return 0;
-    
+
     inode.i_rdev = full_dev;  /* This is all we really need here */
     retval = sd_ioctl(&inode, NULL, SCSI_IOCTL_TEST_UNIT_READY, 0);
-    
+
     if(retval){ /* Unable to test, unit probably not ready.  This usually
 		 * means there is no disc in the drive.  Mark as changed,
 		 * and we will figure it out later once the drive is
 		 * available again.  */
-	
+
 	rscsi_disks[target].ready = 0;
 	rscsi_disks[target].device->changed = 1;
 	return 1; /* This will force a flush, if called from
 		   * check_disk_change */
     }
-    
-    /* 
+
+    /*
      * for removable scsi disk ( FLOPTICAL ) we have to recognise the
      * presence of disk in the drive. This is kept in the Scsi_Disk
-     * struct and tested at open !  Daniel Roche ( dan@lectra.fr ) 
+     * struct and tested at open !  Daniel Roche ( dan@lectra.fr )
      */
-    
+
     rscsi_disks[target].ready = 1;	/* FLOPTICAL */
 
     retval = rscsi_disks[target].device->changed;
@@ -996,10 +999,10 @@
 static void sd_init_done (Scsi_Cmnd * SCpnt)
 {
     struct request * req;
-    
+
     req = &SCpnt->request;
     req->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */
-    
+
     if (req->sem != NULL) {
 	up(req->sem);
     }
@@ -1012,17 +1015,17 @@
     unsigned long spintime;
     int the_result, retries;
     Scsi_Cmnd * SCpnt;
-    
-    /* We need to retry the READ_CAPACITY because a UNIT_ATTENTION is 
-     * considered a fatal error, and many devices report such an error 
-     * just after a scsi bus reset. 
+
+    /* We need to retry the READ_CAPACITY because a UNIT_ATTENTION is
+     * considered a fatal error, and many devices report such an error
+     * just after a scsi bus reset.
      */
-    
+
     SCpnt = allocate_device(NULL, rscsi_disks[i].device, 1);
     buffer = (unsigned char *) scsi_malloc(512);
-    
+
     spintime = 0;
-    
+
     /* Spin up drives, as required.  Only do this at boot time */
     if (!MODULE_FLAG){
 	do{
@@ -1054,10 +1057,10 @@
 		   || SCpnt->sense_buffer[2] != UNIT_ATTENTION)
 		    break;
 	    }
-	    
-	    /* Look for non-removable devices that return NOT_READY.  
+
+	    /* Look for non-removable devices that return NOT_READY.
 	     * Issue command to spin up drive for these cases. */
-	    if(the_result && !rscsi_disks[i].device->removable && 
+	    if(the_result && !rscsi_disks[i].device->removable &&
 	       SCpnt->sense_buffer[2] == NOT_READY) {
 		unsigned long time1;
 		if(!spintime){
@@ -1070,11 +1073,11 @@
 		    SCpnt->cmd_len = 0;
 		    SCpnt->sense_buffer[0] = 0;
 		    SCpnt->sense_buffer[2] = 0;
-		    
+
 		    {
 		    	struct semaphore sem = MUTEX_LOCKED;
 			/* Mark as really busy again */
-			SCpnt->request.rq_status = RQ_SCSI_BUSY; 
+			SCpnt->request.rq_status = RQ_SCSI_BUSY;
 		    	SCpnt->request.sem = &sem;
 			scsi_do_cmd (SCpnt,
 				     (void *) cmd, (void *) buffer,
@@ -1082,10 +1085,10 @@
 				     MAX_RETRIES);
 			down(&sem);
 		    }
-		    
+
 		    spintime = jiffies;
 		}
-		
+
 		time1 = jiffies + HZ;
 		while(jiffies < time1); /* Wait 1 second for next try */
 		printk( "." );
@@ -1098,7 +1101,7 @@
 		printk( "ready\n" );
 	}
     }  /* !MODULE_FLAG */
-    
+
     retries = 3;
     do {
 	cmd[0] = READ_CAPACITY;
@@ -1120,32 +1123,32 @@
 			 MAX_RETRIES);
 	    down(&sem);	/* sleep until it is ready */
 	}
-	
+
 	the_result = SCpnt->result;
 	retries--;
-	
+
     } while(the_result && retries);
-    
+
     SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
-    
-    wake_up(&SCpnt->device->device_wait); 
-    
+
+    wake_up(&SCpnt->device->device_wait);
+
     /* Wake up a process waiting for device */
-    
+
     /*
-     * The SCSI standard says: 
+     * The SCSI standard says:
      * "READ CAPACITY is necessary for self configuring software"
      *  While not mandatory, support of READ CAPACITY is strongly encouraged.
      *  We used to die if we couldn't successfully do a READ CAPACITY.
      *  But, now we go on about our way.  The side effects of this are
      *
-     *  1. We can't know block size with certainty. I have said "512 bytes 
+     *  1. We can't know block size with certainty. I have said "512 bytes
      *     is it" as this is most common.
      *
-     *  2. Recovery from when some one attempts to read past the end of the 
+     *  2. Recovery from when some one attempts to read past the end of the
      *     raw device will be slower.
      */
-    
+
     if (the_result)
     {
 	printk ("sd%c : READ CAPACITY failed.\n"
@@ -1157,27 +1160,27 @@
 		driver_byte(the_result)
 		);
 	if (driver_byte(the_result)  & DRIVER_SENSE)
-	    printk("sd%c : extended sense code = %1x \n", 
+	    printk("sd%c : extended sense code = %1x \n",
 		   'a' + i, SCpnt->sense_buffer[2] & 0xf);
 	else
 	    printk("sd%c : sense not available. \n", 'a' + i);
-	
+
 	printk("sd%c : block size assumed to be 512 bytes, disk size 1GB.  \n",
 	       'a' + i);
 	rscsi_disks[i].capacity = 0x1fffff;
 	rscsi_disks[i].sector_size = 512;
-	
+
 	/* Set dirty bit for removable devices if not ready - sometimes drives
 	 * will not report this properly. */
-	if(rscsi_disks[i].device->removable && 
+	if(rscsi_disks[i].device->removable &&
 	   SCpnt->sense_buffer[2] == NOT_READY)
 	    rscsi_disks[i].device->changed = 1;
-	
+
     }
     else
     {
 	/*
-	 * FLOPTICAL , if read_capa is ok , drive is assumed to be ready 
+	 * FLOPTICAL , if read_capa is ok , drive is assumed to be ready
 	 */
 	rscsi_disks[i].ready = 1;
 
@@ -1185,7 +1188,7 @@
 				       (buffer[1] << 16) |
 				       (buffer[2] << 8) |
 				       buffer[3]);
-	
+
 	rscsi_disks[i].sector_size = (buffer[4] << 24) |
 	    (buffer[5] << 16) | (buffer[6] << 8) | buffer[7];
 
@@ -1193,8 +1196,8 @@
 	  rscsi_disks[i].sector_size = 512;
 	  printk("sd%c : sector size 0 reported, assuming 512.\n", 'a' + i);
 	}
- 
-	
+
+
 	if (rscsi_disks[i].sector_size != 512 &&
 	    rscsi_disks[i].sector_size != 1024 &&
 	    rscsi_disks[i].sector_size != 256)
@@ -1230,7 +1233,7 @@
         sz_rem = m - (10 * sz_quot);
 	printk ("SCSI device sd%c: hdwr sector= %d bytes."
                " Sectors= %d [%d MB] [%d.%1d GB]\n",
-		i+'a', hard_sector, rscsi_disks[i].capacity, 
+		i+'a', hard_sector, rscsi_disks[i].capacity,
                 mb, sz_quot, sz_rem);
     }
 	if(rscsi_disks[i].sector_size == 1024)
@@ -1238,7 +1241,7 @@
 	if(rscsi_disks[i].sector_size == 256)
 	    rscsi_disks[i].capacity >>= 1;  /* Change into 512 byte sectors */
     }
-    
+
 
     /*
      * Unless otherwise specified, this is not write protected.
@@ -1247,13 +1250,13 @@
     if ( rscsi_disks[i].device->removable && rscsi_disks[i].ready ) {
 	/* FLOPTICAL */
 
-	/* 
-	 *	for removable scsi disk ( FLOPTICAL ) we have to recognise  
+	/*
+	 *	for removable scsi disk ( FLOPTICAL ) we have to recognise
 	 * the Write Protect Flag. This flag is kept in the Scsi_Disk struct
 	 * and tested at open !
 	 * Daniel Roche ( dan@lectra.fr )
 	 */
-	
+
 	memset ((void *) &cmd[0], 0, 8);
 	cmd[0] = MODE_SENSE;
 	cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
@@ -1274,11 +1277,11 @@
 			 MAX_RETRIES);
 	    down(&sem);
 	}
-	
+
 	the_result = SCpnt->result;
 	SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
-	wake_up(&SCpnt->device->device_wait); 
-	
+	wake_up(&SCpnt->device->device_wait);
+
 	if ( the_result ) {
 	    printk ("sd%c: test WP failed, assume Write Protected\n",i+'a');
 	    rscsi_disks[i].write_prot = 1;
@@ -1287,9 +1290,9 @@
 	    printk ("sd%c: Write Protect is %s\n",i+'a',
 	            rscsi_disks[i].write_prot ? "on" : "off");
 	}
-	
+
     }	/* check for write protect */
- 
+
     rscsi_disks[i].ten = 1;
     rscsi_disks[i].remap = 1;
     scsi_free(buffer, 512);
@@ -1306,9 +1309,9 @@
 static int sd_init()
 {
     int i;
-    
+
     if (sd_template.dev_noticed == 0) return 0;
-    
+
     if(!sd_registered) {
 	  if (register_blkdev(MAJOR_NR,"sd",&sd_fops)) {
 	      printk("Unable to get major %d for SCSI disk\n",MAJOR_NR);
@@ -1316,26 +1319,26 @@
 	  }
 	  sd_registered++;
       }
-    
+
     /* We do not support attaching loadable devices yet. */
     if(rscsi_disks) return 0;
-    
+
     sd_template.dev_max = sd_template.dev_noticed + SD_EXTRA_DEVS;
-    
-    rscsi_disks = (Scsi_Disk *) 
+
+    rscsi_disks = (Scsi_Disk *)
 	scsi_init_malloc(sd_template.dev_max * sizeof(Scsi_Disk), GFP_ATOMIC);
     memset(rscsi_disks, 0, sd_template.dev_max * sizeof(Scsi_Disk));
-    
-    sd_sizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * 
+
+    sd_sizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) *
 					sizeof(int), GFP_ATOMIC);
     memset(sd_sizes, 0, (sd_template.dev_max << 4) * sizeof(int));
-    
-    sd_blocksizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * 
+
+    sd_blocksizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) *
 					     sizeof(int), GFP_ATOMIC);
-    
-    sd_hardsizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * 
+
+    sd_hardsizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) *
 					    sizeof(int), GFP_ATOMIC);
-    
+
     for(i=0;i<(sd_template.dev_max << 4);i++){
 	sd_blocksizes[i] = 1024;
 	sd_hardsizes[i] = 512;
@@ -1345,8 +1348,8 @@
     sd = (struct hd_struct *) scsi_init_malloc((sd_template.dev_max << 4) *
 					       sizeof(struct hd_struct),
 					       GFP_ATOMIC);
-    
-    
+
+
     sd_gendisk.max_nr = sd_template.dev_max;
     sd_gendisk.part = sd;
     sd_gendisk.sizes = sd_sizes;
@@ -1359,12 +1362,12 @@
     int i;
 
     blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
-    
+
     sd_gendisk.next = gendisk_head;
     gendisk_head = &sd_gendisk;
-    
+
     for (i = 0; i < sd_template.dev_max; ++i)
-	if (!rscsi_disks[i].capacity && 
+	if (!rscsi_disks[i].capacity &&
 	    rscsi_disks[i].device)
 	{
 	    if (MODULE_FLAG
@@ -1377,10 +1380,10 @@
 	    	i=sd_init_onedisk(i);
 	    rscsi_disks[i].has_part_table = 1;
 	}
-    
+
     /* If our host adapter is capable of scatter-gather, then we increase
      * the read-ahead to 16 blocks (32 sectors).  If not, we use
-     * a two block (4 sector) read ahead. 
+     * a two block (4 sector) read ahead.
      */
     if(rscsi_disks[0].device && rscsi_disks[0].device->host->sg_tablesize)
 	read_ahead[MAJOR_NR] = 120;  /* 120 sector read-ahead */
@@ -1392,31 +1395,31 @@
 
 static int sd_detect(Scsi_Device * SDp){
     if(SDp->type != TYPE_DISK && SDp->type != TYPE_MOD) return 0;
-    
-    printk("Detected scsi %sdisk sd%c at scsi%d, channel %d, id %d, lun %d\n", 
+
+    printk("Detected scsi %sdisk sd%c at scsi%d, channel %d, id %d, lun %d\n",
            SDp->removable ? "removable " : "",
 	   'a'+ (sd_template.dev_noticed++),
-	   SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); 
-    
+	   SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
+
     return 1;
 }
 
 static int sd_attach(Scsi_Device * SDp){
     Scsi_Disk * dpnt;
     int i;
-    
+
     if(SDp->type != TYPE_DISK && SDp->type != TYPE_MOD) return 0;
-    
+
     if(sd_template.nr_dev >= sd_template.dev_max) {
 	SDp->attached--;
 	return 1;
     }
-    
-    for(dpnt = rscsi_disks, i=0; i<sd_template.dev_max; i++, dpnt++) 
+
+    for(dpnt = rscsi_disks, i=0; i<sd_template.dev_max; i++, dpnt++)
 	if(!dpnt->device) break;
-    
+
     if(i >= sd_template.dev_max) panic ("scsi_devices corrupt (sd)");
-    
+
     SDp->scsi_request_fn = do_sd_request;
     rscsi_disks[i].device = SDp;
     rscsi_disks[i].has_part_table = 0;
@@ -1445,10 +1448,10 @@
     int max_p;
     int start;
     int i;
-    
+
     target =  DEVICE_NR(dev);
     gdev = &GENDISK_STRUCT;
-    
+
     save_flags(flags);
     cli();
     if (DEVICE_BUSY || USAGE > maxusage) {
@@ -1458,10 +1461,10 @@
     }
     DEVICE_BUSY = 1;
     restore_flags(flags);
-    
+
     max_p = gdev->max_p;
     start = target << gdev->minor_shift;
-    
+
     for (i=max_p - 1; i >=0 ; i--) {
 	int minor = start+i;
 	kdev_t devi = MKDEV(MAJOR_NR, minor);
@@ -1476,14 +1479,14 @@
          */
         blksize_size[MAJOR_NR][minor] = 1024;
     }
-    
+
 #ifdef MAYBE_REINIT
     MAYBE_REINIT;
 #endif
-    
+
     gdev->part[start].nr_sects = CAPACITY;
     resetup_one_dev(gdev, target);
-    
+
     DEVICE_BUSY = 0;
     return 0;
 }
@@ -1499,15 +1502,15 @@
     int i;
     int max_p;
     int start;
-    
-    for(dpnt = rscsi_disks, i=0; i<sd_template.dev_max; i++, dpnt++) 
+
+    for(dpnt = rscsi_disks, i=0; i<sd_template.dev_max; i++, dpnt++)
 	if(dpnt->device == SDp) {
-	    
-	    /* If we are disconnecting a disk driver, sync and invalidate 
+
+	    /* If we are disconnecting a disk driver, sync and invalidate
 	     * everything */
 	    max_p = sd_gendisk.max_p;
 	    start = i << sd_gendisk.minor_shift;
-	    
+
 	    for (i=max_p - 1; i >=0 ; i--) {
 		int minor = start+i;
 		kdev_t devi = MKDEV(MAJOR_NR, minor);
@@ -1518,7 +1521,7 @@
 		sd_gendisk.part[minor].nr_sects = 0;
 		sd_sizes[minor] = 0;
 	    }
-	    
+
 	    dpnt->has_part_table = 0;
 	    dpnt->device = NULL;
 	    dpnt->capacity = 0;
@@ -1534,28 +1537,28 @@
 #ifdef MODULE
 
 int init_module(void) {
-    sd_template.usage_count = &__this_module.usecount;
+    sd_template.module = &__this_module;
     return scsi_register_module(MODULE_SCSI_DEV, &sd_template);
 }
 
-void cleanup_module( void) 
+void cleanup_module( void)
 {
     struct gendisk * prev_sdgd;
     struct gendisk * sdgd;
-    
+
     scsi_unregister_module(MODULE_SCSI_DEV, &sd_template);
     unregister_blkdev(SCSI_DISK_MAJOR, "sd");
     sd_registered--;
     if( rscsi_disks != NULL )
     {
 	scsi_init_free((char *) rscsi_disks,
-		       (sd_template.dev_noticed + SD_EXTRA_DEVS) 
+		       (sd_template.dev_noticed + SD_EXTRA_DEVS)
 		       * sizeof(Scsi_Disk));
-	
+
 	scsi_init_free((char *) sd_sizes, sd_template.dev_max * sizeof(int));
 	scsi_init_free((char *) sd_blocksizes, sd_template.dev_max * sizeof(int));
 	scsi_init_free((char *) sd_hardsizes, sd_template.dev_max * sizeof(int));
-	scsi_init_free((char *) sd, 
+	scsi_init_free((char *) sd,
 		       (sd_template.dev_max << 4) * sizeof(struct hd_struct));
 	/*
 	 * Now remove sd_gendisk from the linked list
@@ -1567,7 +1570,7 @@
 	    prev_sdgd = sdgd;
 	    sdgd = sdgd->next;
 	}
-	
+
 	if(sdgd != &sd_gendisk)
 	    printk("sd_gendisk not in disk chain.\n");
 	else {
@@ -1577,10 +1580,10 @@
 		gendisk_head = sdgd->next;
 	}
     }
-    
+
     blksize_size[MAJOR_NR] = NULL;
     blk_dev[MAJOR_NR].request_fn = NULL;
-    blk_size[MAJOR_NR] = NULL;  
+    blk_size[MAJOR_NR] = NULL;
     hardsect_size[MAJOR_NR] = NULL;
     read_ahead[MAJOR_NR] = 0;
     sd_template.dev_max = 0;
diff -u --recursive --new-file v2.1.22/linux/drivers/scsi/seagate.c linux/drivers/scsi/seagate.c
--- v2.1.22/linux/drivers/scsi/seagate.c	Thu Dec 12 19:37:07 1996
+++ linux/drivers/scsi/seagate.c	Fri Jan 24 19:35:51 1997
@@ -43,20 +43,41 @@
  * will configure the driver for a TMC-8xx style controller using IRQ 15
  * with a base address of 0xC8000.
  *
- * -DFAST or -DFAST32 will use blind transfers where possible
- *
- * -DARBITRATE will cause the host adapter to arbitrate for the
+ * -DARBITRATE 
+ *      Will cause the host adapter to arbitrate for the
  *      bus for better SCSI-II compatibility, rather than just
  *      waiting for BUS FREE and then doing its thing.  Should
  *      let us do one command per Lun when I integrate my
  *      reorganization changes into the distribution sources.
  *
- * -DSLOW_HANDSHAKE will allow compatibility with broken devices that don't
+ * -DDEBUG
+ *      Will activate debug code.
+ *
+ * -DFAST or -DFAST32 
+ *      Will use blind transfers where possible
+ *
+ * -DPARITY  
+ *      This will enable parity.
+ *
+ * -DSEAGATE_USE_ASM
+ *      Will use older seagate assembly code. should be (very small amount)
+ *      Faster.
+ *
+ * -DSLOW_HANDSHAKE
+ *      Will allow compatibility with broken devices that don't
  *      handshake fast enough (ie, some CD ROM's) for the Seagate
  *      code.
  *
- * -DSLOW_RATE=x, x some number will let you specify a default
+ * -DSLOW_RATE=x
+ *      x is some number, It will let you specify a default
  *      transfer rate if handshaking isn't working correctly.
+ *
+ * The following to options are patches from the SCSI.HOWTO
+ *
+ * -DSWAPSTAT  This will swap the definitions for STAT_MSG and STAT_CD.
+ *
+ * -DSWAPCNTDATA  This will swap the order that seagate.c messes with
+ *                the CONTROL an DATA registers.
  */
 
 #include <linux/module.h>
@@ -396,8 +417,8 @@
 #ifdef ARBITRATE
             " ARBITRATE"
 #endif
-#ifdef SLOW_HANDSHAKE
-            " SLOW_HANDSHAKE"
+#ifdef DEBUG
+            " DEBUG"
 #endif
 #ifdef FAST
 #ifdef FAST32
@@ -409,6 +430,21 @@
 #ifdef LINKED
             " LINKED"
 #endif
+#ifdef PARITY
+            " PARITY"
+#endif
+#ifdef SEAGATE_USE_ASM
+            " SEAGATE_USE_ASM"
+#endif
+#ifdef SLOW_HANDSHAKE
+            " SLOW_HANDSHAKE"
+#endif
+#ifdef SWAPSTAT
+            " SWAPSTAT"
+#endif
+#ifdef SWAPCNTDATA
+            " SWAPCNTDATA"
+#endif
             "\n", tpnt->name);
     return 1;
   }
@@ -926,12 +962,21 @@
  *    try this with a SCSI protocol or logic analyzer to see what is
  *    going on.
  */
+#ifdef SWAPCNTDATA
+	cli();
+      WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE | CMD_SEL |
+                     (reselect ? CMD_ATTN : 0));
+      WRITE_DATA ((unsigned char) ((1 << target) |
+                               (controller_type == SEAGATE ? 0x80 : 0x40)));
+	sti();
+#else
       cli ();
       WRITE_DATA ((unsigned char) ((1 << target) |
                                (controller_type == SEAGATE ? 0x80 : 0x40)));
       WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE | CMD_SEL |
                      (reselect ? CMD_ATTN : 0));
       sti ();
+#endif
       while (!((status_read = STATUS) & STAT_BSY) && (jiffies < clock)
              && !st0x_aborted)
 #if 0 && (DEBUG & PHASE_SELECTION)
diff -u --recursive --new-file v2.1.22/linux/drivers/scsi/seagate.h linux/drivers/scsi/seagate.h
--- v2.1.22/linux/drivers/scsi/seagate.h	Mon May 27 13:37:18 1996
+++ linux/drivers/scsi/seagate.h	Fri Jan 24 19:35:51 1997
@@ -37,14 +37,6 @@
 			 1, 7, SG_ALL, 1, 0, 0, DISABLE_CLUSTERING}
 #endif
 
-
-/*
-	defining PARITY causes parity data to be checked
-*/
-
-#define PARITY
-
-
 /*
 	Thanks to Brian Antoine for the example code in his Messy-Loss ST-01
 		driver, and Mitsugu Suzuki for information on the ST-01
@@ -67,11 +59,16 @@
 /*
 	STATUS
 */
+#ifdef SWAPSTAT
+	#define STAT_MSG		0x08
+	#define STAT_CD			0x02
+#else
+	#define STAT_MSG		0x02
+	#define STAT_CD			0x08
+#endif
 
 #define STAT_BSY		0x01
-#define STAT_MSG		0x02
 #define STAT_IO			0x04
-#define STAT_CD			0x08
 #define STAT_REQ		0x10
 #define STAT_SEL		0x20
 #define STAT_PARITY		0x40
diff -u --recursive --new-file v2.1.22/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c
--- v2.1.22/linux/drivers/scsi/sg.c	Mon Dec 30 15:39:11 1996
+++ linux/drivers/scsi/sg.c	Sun Jan 26 12:07:21 1997
@@ -1,9 +1,9 @@
 /*
  *  History:
- *  Started: Aug 9 by Lawrence Foard (entropy@world.std.com), 
+ *  Started: Aug 9 by Lawrence Foard (entropy@world.std.com),
  *           to allow user process control of SCSI devices.
  *  Development Sponsored by Killy Corp. NY NY
- *   
+ *
  *  Borrows code from st driver.
  */
 #include <linux/module.h>
@@ -17,6 +17,7 @@
 #include <linux/mtio.h>
 #include <linux/ioctl.h>
 #include <linux/fcntl.h>
+#include <linux/poll.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -33,7 +34,7 @@
 static void sg_detach(Scsi_Device *);
 
 
-struct Scsi_Device_Template sg_template = {NULL, NULL, "sg", NULL, 0xff, 
+struct Scsi_Device_Template sg_template = {NULL, NULL, "sg", NULL, 0xff,
 					       SCSI_GENERIC_MAJOR, 0, 0, 0, 0,
 					       sg_detect, sg_init,
 					       NULL, sg_attach, sg_detach};
@@ -129,7 +130,7 @@
      * that other processes know that we have it, and initialize the
      * state variables to known values.
      */
-    if (!scsi_generics[dev].users 
+    if (!scsi_generics[dev].users
         && scsi_generics[dev].pending
         && scsi_generics[dev].complete)
     {
@@ -140,9 +141,10 @@
     }
     if (!scsi_generics[dev].users)
 	scsi_generics[dev].timeout=SG_DEFAULT_TIMEOUT;
-    if (scsi_generics[dev].device->host->hostt->usage_count)
-	(*scsi_generics[dev].device->host->hostt->usage_count)++;
-    if(sg_template.usage_count) (*sg_template.usage_count)++;
+    if (scsi_generics[dev].device->host->hostt->module)
+	__MOD_INC_USE_COUNT(scsi_generics[dev].device->host->hostt->module);
+    if (sg_template.module)
+        __MOD_INC_USE_COUNT(sg_template.module);
     scsi_generics[dev].users++;
     return 0;
 }
@@ -151,9 +153,10 @@
 {
     int dev=MINOR(inode->i_rdev);
     scsi_generics[dev].users--;
-    if (scsi_generics[dev].device->host->hostt->usage_count)
-	(*scsi_generics[dev].device->host->hostt->usage_count)--;
-    if(sg_template.usage_count) (*sg_template.usage_count)--;
+    if (scsi_generics[dev].device->host->hostt->module)
+	__MOD_DEC_USE_COUNT(scsi_generics[dev].device->host->hostt->module);
+    if(sg_template.module)
+        __MOD_DEC_USE_COUNT(sg_template.module);
     scsi_generics[dev].exclude=0;
     wake_up(&scsi_generics[dev].generic_wait);
 }
@@ -174,11 +177,11 @@
 	big_inuse=1;
 	return big_buff;
     }
-#endif   
+#endif
     return NULL;
 }
 
-static void sg_free(char *buff,int size) 
+static void sg_free(char *buff,int size)
 {
 #ifdef SG_BIG_BUFF
     if (buff==big_buff)
@@ -243,7 +246,7 @@
     }
     else
 	count= device->header.result==0 ? 0 : -EIO;
-    
+
     /*
      * Clean up, and release the device so that we can send another
      * command.
@@ -283,14 +286,14 @@
       break;
     case DID_NO_CONNECT:
     case DID_BUS_BUSY:
-    case DID_TIME_OUT: 
+    case DID_TIME_OUT:
       device->header.result = EBUSY;
       break;
-    case DID_BAD_TARGET: 
-    case DID_ABORT: 
-    case DID_PARITY: 
+    case DID_BAD_TARGET:
+    case DID_ABORT:
+    case DID_PARITY:
     case DID_RESET:
-    case DID_BAD_INTR: 
+    case DID_BAD_INTR:
       device->header.result = EIO;
       break;
     case DID_ERROR:
@@ -328,12 +331,12 @@
     int			  input_size;
     unsigned char	  opcode;
     Scsi_Cmnd		* SCpnt;
-    
+
     if ((i=verify_area(VERIFY_READ,buf,count)))
 	return i;
     /*
      * The minimum scsi command length is 6 bytes.  If we get anything
-     * less than this, it is clearly bogus.  
+     * less than this, it is clearly bogus.
      */
     if (count<(sizeof(struct sg_header) + 6))
 	return -EIO;
@@ -349,7 +352,7 @@
 	    return -EAGAIN;
 #ifdef DEBUG
 	printk("sg_write: sleeping on pending request\n");
-#endif     
+#endif
 	interruptible_sleep_on(&device->write_wait);
 	if (current->signal & ~current->blocked)
 	    return -ERESTARTSYS;
@@ -382,7 +385,7 @@
     } else {
         bsize = device->header.reply_len;
     }
-    
+
     /*
      * Don't include the command header itself in the size.
      */
@@ -398,7 +401,7 @@
         wake_up( &device->write_wait );
 	return -EIO;
     }
-    
+
     /*
      * Allocate a buffer that is large enough to hold the data
      * that has been requested.  Round up to an even number of sectors,
@@ -434,10 +437,10 @@
 	sg_free(device->buff,device->buff_len);
 	device->buff = NULL;
 	return -EAGAIN;
-    } 
+    }
 #ifdef DEBUG
     printk("device allocated\n");
-#endif    
+#endif
 
     SCpnt->request.rq_dev = devt;
     SCpnt->request.rq_status = RQ_ACTIVE;
@@ -456,7 +459,7 @@
      * so we need to subtract these off.
      */
     if (input_size > 0) copy_from_user(device->buff, buf, input_size);
-    
+
     /*
      * Set the LUN field in the command structure.
      */
@@ -477,36 +480,25 @@
 
 #ifdef DEBUG
     printk("done cmd\n");
-#endif               
+#endif
 
     return count;
 }
 
-static int sg_select(struct inode *inode, struct file *file, int sel_type, select_table * wait)
+static unsigned int sg_poll(struct file *file, poll_table * wait)
 {
-    int dev=MINOR(inode->i_rdev);
-    int r = 0;
-    struct scsi_generic *device=&scsi_generics[dev];
+        int dev = MINOR(file->f_inode->i_rdev);
+        struct scsi_generic *device = &scsi_generics[dev];
+        unsigned int mask = 0;
 
-    if (sel_type == SEL_IN) {
+        poll_wait(&scsi_generics[dev].read_wait, wait);
+        poll_wait(&scsi_generics[dev].write_wait, wait);
         if(device->pending && device->complete)
-        {
-            r = 1;
-    	} else {
-	    select_wait(&scsi_generics[dev].read_wait, wait);
-    	}
-    }
-    if (sel_type == SEL_OUT) {
-        if(!device->pending){
-            r = 1;
-        }
-        else
-        {
-	    select_wait(&scsi_generics[dev].write_wait, wait);
-        }
-    }
+                mask |= POLLIN | POLLRDNORM;
+        if(!device->pending)
+                mask |= POLLOUT | POLLWRNORM;
 
-    return(r);
+        return mask;
 }
 
 static struct file_operations sg_fops = {
@@ -514,7 +506,7 @@
     sg_read,         /* read */
     sg_write,        /* write */
     NULL,            /* readdir */
-    sg_select,       /* select */
+    sg_poll,         /* poll */
     sg_ioctl,        /* ioctl */
     NULL,            /* mmap */
     sg_open,         /* open */
@@ -531,7 +523,7 @@
 	case TYPE_ROM:
 	case TYPE_WORM:
 	case TYPE_TAPE: break;
-	default: 
+	default:
 	printk("Detected scsi generic sg%c at scsi%d, channel %d, id %d, lun %d\n",
            'a'+sg_template.dev_noticed,
            SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
@@ -544,11 +536,11 @@
 static int sg_init()
 {
     static int sg_registered = 0;
-    
+
     if (sg_template.dev_noticed == 0) return 0;
-    
+
     if(!sg_registered) {
-	if (register_chrdev(SCSI_GENERIC_MAJOR,"sg",&sg_fops)) 
+	if (register_chrdev(SCSI_GENERIC_MAJOR,"sg",&sg_fops))
 	{
 	    printk("Unable to get major %d for generic SCSI device\n",
 		   SCSI_GENERIC_MAJOR);
@@ -556,24 +548,24 @@
 	}
 	sg_registered++;
     }
-    
+
     /* If we have already been through here, return */
     if(scsi_generics) return 0;
-    
+
 #ifdef DEBUG
     printk("sg: Init generic device.\n");
 #endif
-    
+
 #ifdef SG_BIG_BUFF
     big_buff= (char *) scsi_init_malloc(SG_BIG_BUFF, GFP_ATOMIC | GFP_DMA);
 #endif
-    
-    scsi_generics = (struct scsi_generic *) 
-	scsi_init_malloc((sg_template.dev_noticed + SG_EXTRA_DEVS) 
+
+    scsi_generics = (struct scsi_generic *)
+	scsi_init_malloc((sg_template.dev_noticed + SG_EXTRA_DEVS)
 			 * sizeof(struct scsi_generic), GFP_ATOMIC);
     memset(scsi_generics, 0, (sg_template.dev_noticed + SG_EXTRA_DEVS)
 	   * sizeof(struct scsi_generic));
-    
+
     sg_template.dev_max = sg_template.dev_noticed + SG_EXTRA_DEVS;
     return 0;
 }
@@ -582,18 +574,18 @@
 {
     struct scsi_generic * gpnt;
     int i;
-    
-    if(sg_template.nr_dev >= sg_template.dev_max) 
+
+    if(sg_template.nr_dev >= sg_template.dev_max)
     {
 	SDp->attached--;
 	return 1;
     }
-    
-    for(gpnt = scsi_generics, i=0; i<sg_template.dev_max; i++, gpnt++) 
+
+    for(gpnt = scsi_generics, i=0; i<sg_template.dev_max; i++, gpnt++)
 	if(!gpnt->device) break;
-    
+
     if(i >= sg_template.dev_max) panic ("scsi_devices corrupt (sg)");
-    
+
     scsi_generics[i].device=SDp;
     scsi_generics[i].users=0;
     scsi_generics[i].generic_wait=NULL;
@@ -613,14 +605,14 @@
 {
     struct scsi_generic * gpnt;
     int i;
-    
-    for(gpnt = scsi_generics, i=0; i<sg_template.dev_max; i++, gpnt++) 
+
+    for(gpnt = scsi_generics, i=0; i<sg_template.dev_max; i++, gpnt++)
 	if(gpnt->device == SDp) {
 	    gpnt->device = NULL;
 	    SDp->attached--;
 	    sg_template.nr_dev--;
-            /* 
-             * avoid associated device /dev/sg? bying incremented 
+            /*
+             * avoid associated device /dev/sg? bying incremented
              * each time module is inserted/removed , <dan@lectra.fr>
              */
             sg_template.dev_noticed--;
@@ -632,18 +624,18 @@
 #ifdef MODULE
 
 int init_module(void) {
-    sg_template.usage_count = &__this_module.usecount;
+    sg_template.module = &__this_module;
     return scsi_register_module(MODULE_SCSI_DEV, &sg_template);
 }
 
-void cleanup_module( void) 
+void cleanup_module( void)
 {
     scsi_unregister_module(MODULE_SCSI_DEV, &sg_template);
     unregister_chrdev(SCSI_GENERIC_MAJOR, "sg");
-    
+
     if(scsi_generics != NULL) {
 	scsi_init_free((char *) scsi_generics,
-		       (sg_template.dev_noticed + SG_EXTRA_DEVS) 
+		       (sg_template.dev_noticed + SG_EXTRA_DEVS)
 		       * sizeof(struct scsi_generic));
     }
     sg_template.dev_max = 0;
diff -u --recursive --new-file v2.1.22/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c
--- v2.1.22/linux/drivers/scsi/sr.c	Mon Dec 30 15:39:11 1996
+++ linux/drivers/scsi/sr.c	Sun Jan 26 12:07:21 1997
@@ -3,7 +3,7 @@
  *	     Copyright (C) 1993, 1994, 1995 Eric Youngdale
  *
  *  adapted from:
- *	sd.c Copyright (C) 1992 Drew Eckhardt 
+ *	sd.c Copyright (C) 1992 Drew Eckhardt
  *	Linux scsi disk driver by
  *		Drew Eckhardt <drew@colorado.edu>
  *
@@ -54,7 +54,7 @@
 static int sr_detect(Scsi_Device *);
 static void sr_detach(Scsi_Device *);
 
-struct Scsi_Device_Template sr_template = {NULL, "cdrom", "sr", NULL, TYPE_ROM, 
+struct Scsi_Device_Template sr_template = {NULL, "cdrom", "sr", NULL, TYPE_ROM,
                                            SCSI_CDROM_MAJOR, 0, 0, 0, 1,
                                            sr_detect, sr_init,
                                            sr_finish, sr_attach, sr_detach};
@@ -74,9 +74,10 @@
 {
 	sync_dev(cdi->dev);
 	scsi_CDs[MINOR(cdi->dev)].device->access_count--;
-	if (scsi_CDs[MINOR(cdi->dev)].device->host->hostt->usage_count)
-	    (*scsi_CDs[MINOR(cdi->dev)].device->host->hostt->usage_count)--;
-	if(sr_template.usage_count) (*sr_template.usage_count)--;
+	if (scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module)
+		__MOD_DEC_USE_COUNT(scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module);
+	if(sr_template.module)
+        	__MOD_DEC_USE_COUNT(sr_template.module);
 }
 
 static struct cdrom_device_ops sr_dops = {
@@ -116,21 +117,21 @@
                 /* no changer support */
                 return -EINVAL;
         }
-        
+
 	retval = scsi_ioctl(scsi_CDs[MINOR(cdi->dev)].device,
                             SCSI_IOCTL_TEST_UNIT_READY, 0);
-    
+
 	if(retval){
                 /* Unable to test, unit probably not ready.  This usually
 		 * means there is no disc in the drive.  Mark as changed,
 		 * and we will figure it out later once the drive is
 		 * available again.  */
-	
+
                 scsi_CDs[MINOR(cdi->dev)].device->changed = 1;
                 return 1; /* This will force a flush, if called from
                            * check_disk_change */
 	};
-    
+
 	retval = scsi_CDs[MINOR(cdi->dev)].device->changed;
         scsi_CDs[MINOR(cdi->dev)].device->changed = 0;
         /* If the disk changed, the capacity will now be different,
@@ -145,7 +146,7 @@
 }
 
 /*
- * rw_intr is the interrupt routine for the device driver.  It will be notified on the 
+ * rw_intr is the interrupt routine for the device driver.  It will be notified on the
  * end of a SCSI read / write, and will take on of several actions based on success or failure.
  */
 
@@ -155,7 +156,7 @@
 	int this_count = SCpnt->this_count;
 	int good_sectors = (result == 0 ? this_count : 0);
 	int block_sectors = 0;
-    
+
 #ifdef DEBUG
 	printk("sr.c done: %x %x\n",result, SCpnt->request.bh->b_data);
 #endif
@@ -203,24 +204,24 @@
 	    {
 		int offset;
 		offset = (SCpnt->request.sector % 4) << 9;
-		memcpy((char *)SCpnt->request.buffer, 
-		       (char *)SCpnt->buffer + offset, 
+		memcpy((char *)SCpnt->request.buffer,
+		       (char *)SCpnt->buffer + offset,
 		       good_sectors << 9);
 		/* Even though we are not using scatter-gather, we look
 		 * ahead and see if there is a linked request for the
 		 * other half of this buffer.  If there is, then satisfy
 		 * it. */
 		if((offset == 0) && good_sectors == 2 &&
-		   SCpnt->request.nr_sectors > good_sectors && 
+		   SCpnt->request.nr_sectors > good_sectors &&
 		   SCpnt->request.bh &&
 		   SCpnt->request.bh->b_reqnext &&
 		   SCpnt->request.bh->b_reqnext->b_size == 1024) {
-		    memcpy((char *)SCpnt->request.bh->b_reqnext->b_data, 
-			   (char *)SCpnt->buffer + 1024, 
+		    memcpy((char *)SCpnt->request.bh->b_reqnext->b_data,
+			   (char *)SCpnt->buffer + 1024,
 			   1024);
 		    good_sectors += 2;
 		};
-		
+
 		scsi_free(SCpnt->buffer, 2048);
 	    }
 	} else {
@@ -241,19 +242,19 @@
 		    if(good_sectors > SCpnt->request.nr_sectors)
 		good_sectors -= 2;
 	};
-	
+
 #ifdef DEBUG
-		printk("(%x %x %x) ",SCpnt->request.bh, SCpnt->request.nr_sectors, 
+		printk("(%x %x %x) ",SCpnt->request.bh, SCpnt->request.nr_sectors,
 		       good_sectors);
 #endif
 		if (SCpnt->request.nr_sectors > this_count)
-	{	 
+	{
 			SCpnt->request.errors = 0;
 			if (!SCpnt->request.bh)
 			    panic("sr.c: linked page request (%lx %x)",
 		      SCpnt->request.sector, this_count);
 	}
-	
+
 	SCpnt = end_scsi_request(SCpnt, 1, good_sectors);  /* All done */
 	if (result == 0)
 	  {
@@ -261,10 +262,10 @@
 	    return;
 	  }
     }
-    
+
     if (good_sectors == 0) {
 	/* We only come through here if no sectors were read successfully. */
-    
+
     /* Free up any indirection buffers we allocated for DMA purposes. */
 	if (SCpnt->use_sg) {
 	struct scatterlist * sgpnt;
@@ -280,22 +281,22 @@
 	if (SCpnt->buffer != SCpnt->request.buffer)
 	    scsi_free(SCpnt->buffer, SCpnt->bufflen);
 	}
-    
+
     }
 
 	if (driver_byte(result) != 0) {
 		if ((SCpnt->sense_buffer[0] & 0x7f) == 0x70) {
 			if ((SCpnt->sense_buffer[2] & 0xf) == UNIT_ATTENTION) {
-				/* detected disc change.  set a bit and quietly refuse 
+				/* detected disc change.  set a bit and quietly refuse
 				 * further access.	*/
-		
+
 				scsi_CDs[DEVICE_NR(SCpnt->request.rq_dev)].device->changed = 1;
 				SCpnt = end_scsi_request(SCpnt, 0, this_count);
 				requeue_sr_request(SCpnt);
 				return;
 			}
 		}
-	    
+
 		if (SCpnt->sense_buffer[2] == ILLEGAL_REQUEST) {
 			printk("CD-ROM error: ");
 			print_sense("sr", SCpnt);
@@ -311,7 +312,7 @@
 				requeue_sr_request(SCpnt); /* Do next request */
 				return;
 			}
-	    
+
 		}
 
 		if (SCpnt->sense_buffer[2] == NOT_READY) {
@@ -324,7 +325,7 @@
 		if (SCpnt->sense_buffer[2] == MEDIUM_ERROR) {
 		    printk("scsi%d: MEDIUM ERROR on "
 			   "channel %d, id %d, lun %d, CDB: ",
-			   SCpnt->host->host_no, (int) SCpnt->channel, 
+			   SCpnt->host->host_no, (int) SCpnt->channel,
 			   (int) SCpnt->target, (int) SCpnt->lun);
 		    print_command(SCpnt->cmnd);
 		    print_sense("sr", SCpnt);
@@ -336,7 +337,7 @@
 		if (SCpnt->sense_buffer[2] == VOLUME_OVERFLOW) {
 		    printk("scsi%d: VOLUME OVERFLOW on "
 			   "channel %d, id %d, lun %d, CDB: ",
-			   SCpnt->host->host_no, (int) SCpnt->channel, 
+			   SCpnt->host->host_no, (int) SCpnt->channel,
 			   (int) SCpnt->target, (int) SCpnt->lun);
 		    print_command(SCpnt->cmnd);
 		    print_sense("sr", SCpnt);
@@ -345,18 +346,18 @@
 		    return;
 		}
     }
-	
+
 	/* We only get this far if we have an error we have not recognized */
 	if(result) {
-	printk("SCSI CD error : host %d id %d lun %d return code = %03x\n", 
-	       scsi_CDs[DEVICE_NR(SCpnt->request.rq_dev)].device->host->host_no, 
+	printk("SCSI CD error : host %d id %d lun %d return code = %03x\n",
+	       scsi_CDs[DEVICE_NR(SCpnt->request.rq_dev)].device->host->host_no,
 	       scsi_CDs[DEVICE_NR(SCpnt->request.rq_dev)].device->id,
 	       scsi_CDs[DEVICE_NR(SCpnt->request.rq_dev)].device->lun,
 	       result);
-	    
+
 	if (status_byte(result) == CHECK_CONDITION)
 	    print_sense("sr", SCpnt);
-	
+
 	SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.current_nr_sectors);
 	requeue_sr_request(SCpnt);
     }
@@ -367,9 +368,10 @@
     check_disk_change(cdi->dev);
 
     scsi_CDs[MINOR(cdi->dev)].device->access_count++;
-    if (scsi_CDs[MINOR(cdi->dev)].device->host->hostt->usage_count)
-	(*scsi_CDs[MINOR(cdi->dev)].device->host->hostt->usage_count)++;
-    if(sr_template.usage_count) (*sr_template.usage_count)++;
+    if (scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module)
+	__MOD_INC_USE_COUNT(scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module);
+    if(sr_template.module)
+        __MOD_INC_USE_COUNT(sr_template.module);
 
     /* If this device did not have media in the drive at boot time, then
      * we would have been unable to get the sector size.  Check to see if
@@ -385,7 +387,7 @@
 /*
  * do_sr_request() is the request handler function for the sr driver.
  * Its function in life is to take block device requests, and
- * translate them to SCSI commands.  
+ * translate them to SCSI commands.
  */
 
 static void do_sr_request (void)
@@ -395,7 +397,7 @@
     Scsi_Device * SDev;
     unsigned long flags;
     int flag = 0;
-    
+
     while (1==1){
 	save_flags(flags);
 	cli();
@@ -403,11 +405,11 @@
 	    restore_flags(flags);
 	    return;
 	};
-	
+
 	INIT_SCSI_REQUEST;
- 
+
 	SDev = scsi_CDs[DEVICE_NR(CURRENT->rq_dev)].device;
-	
+
 	/*
 	 * I am not sure where the best place to do this is.  We need
 	 * to hook in a place where we are likely to come if in user
@@ -427,20 +429,20 @@
  	    }
  	    SDev->was_reset = 0;
 	}
-	
+
 	if (flag++ == 0)
 	    SCpnt = allocate_device(&CURRENT,
-				    scsi_CDs[DEVICE_NR(CURRENT->rq_dev)].device, 0); 
+				    scsi_CDs[DEVICE_NR(CURRENT->rq_dev)].device, 0);
 	else SCpnt = NULL;
 	restore_flags(flags);
-	
+
 	/* This is a performance enhancement.  We dig down into the request list and
 	 * try to find a queueable request (i.e. device not busy, and host able to
 	 * accept another command.  If we find one, then we queue it. This can
 	 * make a big difference on systems with more than one disk drive.  We want
 	 * to have the interrupts off when monkeying with the request list, because
 	 * otherwise the kernel might try to slip in a request in between somewhere. */
-	
+
 	if (!SCpnt && sr_template.nr_dev > 1){
 	    struct request *req1;
 	    req1 = NULL;
@@ -455,60 +457,60 @@
 		req = req->next;
 	    };
 	    if (SCpnt && req->rq_status == RQ_INACTIVE) {
-		if (req == CURRENT) 
+		if (req == CURRENT)
 		    CURRENT = CURRENT->next;
 		else
 		    req1->next = req->next;
 	    };
 	    restore_flags(flags);
 	};
-	
+
 	if (!SCpnt)
 	    return; /* Could not find anything to do */
-	
+
 	wake_up(&wait_for_request);
 
 	/* Queue command */
 	requeue_sr_request(SCpnt);
     };  /* While */
-}    
+}
 
 void requeue_sr_request (Scsi_Cmnd * SCpnt)
 {
 	unsigned int dev, block, realcount;
 	unsigned char cmd[10], *buffer, tries;
 	int this_count, start, end_rec;
-    
+
 	tries = 2;
-    
+
  repeat:
 	if(!SCpnt || SCpnt->request.rq_status == RQ_INACTIVE) {
 		do_sr_request();
 		return;
 	}
-    
+
 	dev =  MINOR(SCpnt->request.rq_dev);
-	block = SCpnt->request.sector;	
+	block = SCpnt->request.sector;
 	buffer = NULL;
 	this_count = 0;
-    
+
 	if (dev >= sr_template.nr_dev) {
 		/* printk("CD-ROM request error: invalid device.\n");			*/
 		SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
 		tries = 2;
 		goto repeat;
 	}
-    
+
 	if (!scsi_CDs[dev].use) {
 		/* printk("CD-ROM request error: device marked not in use.\n");		*/
 		SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
 		tries = 2;
 		goto repeat;
 	}
-    
+
 	if (scsi_CDs[dev].device->changed) {
-	/* 
-	 * quietly refuse to do anything to a changed disc 
+	/*
+	 * quietly refuse to do anything to a changed disc
 	 * until the changed bit has been reset
 	 */
 		/* printk("CD-ROM has been changed.  Prohibiting further I/O.\n");	*/
@@ -516,41 +518,41 @@
 		tries = 2;
 		goto repeat;
 	}
-	
+
 	switch (SCpnt->request.cmd)
     {
-    case WRITE: 		
+    case WRITE:
 	SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
 	goto repeat;
 	break;
-    case READ : 
+    case READ :
 	cmd[0] = READ_6;
 	break;
-    default : 
+    default :
 	panic ("Unknown sr command %d\n", SCpnt->request.cmd);
     }
-	
+
 	cmd[1] = (SCpnt->lun << 5) & 0xe0;
-    
+
     /*
      * Now do the grungy work of figuring out which sectors we need, and
      * where in memory we are going to put them.
-     * 
+     *
      * The variables we need are:
-     * 
-     * this_count= number of 512 byte sectors being read 
+     *
+     * this_count= number of 512 byte sectors being read
      * block     = starting cdrom sector to read.
      * realcount = # of cdrom sectors to read
-     * 
+     *
      * The major difference between a scsi disk and a scsi cdrom
      * is that we will always use scatter-gather if we can, because we can
      * work around the fact that the buffer cache has a block size of 1024,
      * and we have 2048 byte sectors.  This code should work for buffers that
      * are any multiple of 512 bytes long.
      */
-    
+
 	SCpnt->use_sg = 0;
-    
+
 	if (SCpnt->host->sg_tablesize > 0 &&
 	    (!need_isa_buffer ||
 	 dma_free_sectors >= 10)) {
@@ -604,7 +606,7 @@
 								    if needed */
 		count++;
 	    };
-	    for(bh = SCpnt->request.bh; count < SCpnt->use_sg; 
+	    for(bh = SCpnt->request.bh; count < SCpnt->use_sg;
 		count++, bh = bh->b_reqnext) {
 		if (bh) { /* Need a placeholder at the end of the record? */
 		    sgpnt[count].address = bh->b_data;
@@ -637,7 +639,7 @@
 			printk("Warning: Running low on SCSI DMA buffers");
 			/* Try switching back to a non scatter-gather operation. */
 			while(--count >= 0){
-			    if(sgpnt[count].alt_address) 
+			    if(sgpnt[count].alt_address)
 				scsi_free(sgpnt[count].address, sgpnt[count].length);
 			};
 			SCpnt->use_sg = 0;
@@ -648,32 +650,32 @@
 	    };  /* for loop to fill list */
 #ifdef DEBUG
 	    printk("SR: %d %d %d %d %d *** ",SCpnt->use_sg, SCpnt->request.sector,
-		   this_count, 
+		   this_count,
 		   SCpnt->request.current_nr_sectors,
 		   SCpnt->request.nr_sectors);
 	    for(count=0; count<SCpnt->use_sg; count++)
 		printk("SGlist: %d %x %x %x\n", count,
-		       sgpnt[count].address, 
-		       sgpnt[count].alt_address, 
+		       sgpnt[count].address,
+		       sgpnt[count].alt_address,
 		       sgpnt[count].length);
 #endif
 	};  /* Able to allocate scatter-gather list */
 	};
-	
+
 	if (SCpnt->use_sg == 0){
 	/* We cannot use scatter-gather.  Do this the old fashion way */
-	if (!SCpnt->request.bh)  	
+	if (!SCpnt->request.bh)
 	    this_count = SCpnt->request.nr_sectors;
 	else
 	    this_count = (SCpnt->request.bh->b_size >> 9);
-	
+
 	start = block % 4;
 	if (start)
-	    {				  
-	    this_count = ((this_count > 4 - start) ? 
+	    {
+	    this_count = ((this_count > 4 - start) ?
 			  (4 - start) : (this_count));
 	    buffer = (unsigned char *) scsi_malloc(2048);
-	    } 
+	    }
 	else if (this_count < 4)
 	    {
 	    buffer = (unsigned char *) scsi_malloc(2048);
@@ -687,24 +689,24 @@
 		buffer = (unsigned char *) scsi_malloc(this_count << 9);
 	    }
 	};
-    
+
 	if (scsi_CDs[dev].sector_size == 2048)
 	block = block >> 2; /* These are the sectors that the cdrom uses */
 	else
 	block = block & 0xfffffffc;
-    
+
 	realcount = (this_count + 3) / 4;
-    
+
 	if (scsi_CDs[dev].sector_size == 512) realcount = realcount << 2;
-    
-	if (((realcount > 0xff) || (block > 0x1fffff)) && scsi_CDs[dev].ten) 
+
+	if (((realcount > 0xff) || (block > 0x1fffff)) && scsi_CDs[dev].ten)
     {
 		if (realcount > 0xffff)
 	{
 			realcount = 0xffff;
 			this_count = realcount * (scsi_CDs[dev].sector_size >> 9);
 	}
-	
+
 		cmd[0] += READ_10 - READ_6 ;
 		cmd[2] = (unsigned char) (block >> 24) & 0xff;
 		cmd[3] = (unsigned char) (block >> 16) & 0xff;
@@ -721,16 +723,16 @@
 	    realcount = 0xff;
 	    this_count = realcount * (scsi_CDs[dev].sector_size >> 9);
 	}
-	
+
 	cmd[1] |= (unsigned char) ((block >> 16) & 0x1f);
 	cmd[2] = (unsigned char) ((block >> 8) & 0xff);
 	cmd[3] = (unsigned char) block & 0xff;
 	cmd[4] = (unsigned char) realcount;
 	cmd[5] = 0;
-    }   
-    
+    }
+
 #ifdef DEBUG
-    { 
+    {
 	int i;
 	printk("ReadCD: %d %d %d %d\n",block, realcount, buffer, this_count);
 	printk("Use sg: %d\n", SCpnt->use_sg);
@@ -739,7 +741,7 @@
 	printk("\n");
     };
 #endif
-    
+
     /* Some dumb host adapters can speed transfers by knowing the
      * minimum transfersize in advance.
      *
@@ -749,47 +751,47 @@
      * assume that we can at least transfer the minimum of the buffer
      * size (1024) and the sector size between each connect / disconnect.
      */
-    
+
     SCpnt->transfersize = (scsi_CDs[dev].sector_size > 1024) ?
 	1024 : scsi_CDs[dev].sector_size;
-    
+
 	SCpnt->this_count = this_count;
-	scsi_do_cmd (SCpnt, (void *) cmd, buffer, 
-		 realcount * scsi_CDs[dev].sector_size, 
+	scsi_do_cmd (SCpnt, (void *) cmd, buffer,
+		 realcount * scsi_CDs[dev].sector_size,
 		 rw_intr, SR_TIMEOUT, MAX_RETRIES);
 }
 
 static int sr_detect(Scsi_Device * SDp){
-    
+
     if(SDp->type != TYPE_ROM && SDp->type != TYPE_WORM) return 0;
-    
-    printk("Detected scsi CD-ROM sr%d at scsi%d, channel %d, id %d, lun %d\n", 
+
+    printk("Detected scsi CD-ROM sr%d at scsi%d, channel %d, id %d, lun %d\n",
 	   sr_template.dev_noticed++,
-	   SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); 
-    
+	   SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
+
     return 1;
 }
 
 static int sr_attach(Scsi_Device * SDp){
     Scsi_CD * cpnt;
     int i;
-    
+
     if(SDp->type != TYPE_ROM && SDp->type != TYPE_WORM) return 1;
-    
+
     if (sr_template.nr_dev >= sr_template.dev_max)
     {
 	SDp->attached--;
 	return 1;
     }
-    
-    for(cpnt = scsi_CDs, i=0; i<sr_template.dev_max; i++, cpnt++) 
+
+    for(cpnt = scsi_CDs, i=0; i<sr_template.dev_max; i++, cpnt++)
 	if(!cpnt->device) break;
-    
+
     if(i >= sr_template.dev_max) panic ("scsi_devices corrupt (sr)");
-    
+
     SDp->scsi_request_fn = do_sr_request;
     scsi_CDs[i].device = SDp;
-    
+
     scsi_CDs[i].cdi.ops        = &sr_dops;
     scsi_CDs[i].cdi.handle     = &scsi_CDs[i];
     scsi_CDs[i].cdi.dev        = MKDEV(MAJOR_NR,i);
@@ -797,7 +799,7 @@
     scsi_CDs[i].cdi.speed      = 1;
     scsi_CDs[i].cdi.capacity   = 1;
     register_cdrom(&scsi_CDs[i].cdi, "sr");
-            
+
 #ifdef CONFIG_BLK_DEV_SR_VENDOR
     sr_vendor_init(i);
 #endif
@@ -812,10 +814,10 @@
 static void sr_init_done (Scsi_Cmnd * SCpnt)
 {
     struct request * req;
-    
+
     req = &SCpnt->request;
     req->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */
-    
+
     if (req->sem != NULL) {
 	up(req->sem);
     }
@@ -826,10 +828,10 @@
     unsigned char *buffer;
     int the_result, retries;
     Scsi_Cmnd * SCpnt;
-    
+
     buffer = (unsigned char *) scsi_malloc(512);
     SCpnt = allocate_device(NULL, scsi_CDs[i].device, 1);
-    
+
     retries = 3;
     do {
 	cmd[0] = READ_CAPACITY;
@@ -837,7 +839,7 @@
 	memset ((void *) &cmd[2], 0, 8);
 	SCpnt->request.rq_status = RQ_SCSI_BUSY;  /* Mark as really busy */
 	SCpnt->cmd_len = 0;
-	
+
 	memset(buffer, 0, 8);
 
 	/* Do the command and wait.. */
@@ -850,16 +852,16 @@
 			 MAX_RETRIES);
 	    down(&sem);
 	}
-	
+
 	the_result = SCpnt->result;
 	retries--;
-	
+
     } while(the_result && retries);
-    
+
     SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
-    
-    wake_up(&SCpnt->device->device_wait); 
-    
+
+    wake_up(&SCpnt->device->device_wait);
+
     if (the_result) {
 	scsi_CDs[i].capacity = 0x1fffff;
 	scsi_CDs[i].sector_size = 2048;  /* A guess, just in case */
@@ -914,7 +916,7 @@
 	sr_registered++;
     }
 
-    
+
     if (scsi_CDs) return 0;
     sr_template.dev_max =
             sr_template.dev_noticed + SR_EXTRA_DEVS;
@@ -924,7 +926,7 @@
     sr_sizes = (int *) scsi_init_malloc(sr_template.dev_max * sizeof(int), GFP_ATOMIC);
     memset(sr_sizes, 0, sr_template.dev_max * sizeof(int));
 
-    sr_blocksizes = (int *) scsi_init_malloc(sr_template.dev_max * 
+    sr_blocksizes = (int *) scsi_init_malloc(sr_template.dev_max *
 					 sizeof(int), GFP_ATOMIC);
     for(i=0;i<sr_template.dev_max;i++) sr_blocksizes[i] = 2048;
     blksize_size[MAJOR_NR] = sr_blocksizes;
@@ -934,9 +936,9 @@
 void sr_finish()
 {
     int i;
-    
+
     blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
-    blk_size[MAJOR_NR] = sr_sizes;	
+    blk_size[MAJOR_NR] = sr_sizes;
 
     for (i = 0; i < sr_template.nr_dev; ++i)
     {
@@ -957,8 +959,8 @@
 	scsi_CDs[i].remap = 1;
 	sr_sizes[i] = scsi_CDs[i].capacity >> (BLOCK_SIZE_BITS - 9);
     }
-    
-    
+
+
     /* If our host adapter is capable of scatter-gather, then we increase
      * the read-ahead to 16 blocks (32 sectors).  If not, we use
      * a two block (4 sector) read ahead. */
@@ -968,14 +970,14 @@
 	read_ahead[MAJOR_NR] = 4;  /* 4 sector read-ahead */
 
     return;
-}	
+}
 
 static void sr_detach(Scsi_Device * SDp)
 {
     Scsi_CD * cpnt;
     int i;
-    
-    for(cpnt = scsi_CDs, i=0; i<sr_template.dev_max; i++, cpnt++) 
+
+    for(cpnt = scsi_CDs, i=0; i<sr_template.dev_max; i++, cpnt++)
 	if(cpnt->device == SDp) {
 	    kdev_t devi = MKDEV(MAJOR_NR, i);
 
@@ -985,7 +987,7 @@
 	     */
 	    invalidate_inodes(devi);
 	    invalidate_buffers(devi);
-	    
+
 	    /*
 	     * Reset things back to a sane state so that one can re-load a new
 	     * driver (perhaps the same one).
@@ -1006,29 +1008,29 @@
 #ifdef MODULE
 
 int init_module(void) {
-        sr_template.usage_count = &__this_module.usecount;
+        sr_template.module = &__this_module;
         return scsi_register_module(MODULE_SCSI_DEV, &sr_template);
 }
 
-void cleanup_module( void) 
+void cleanup_module( void)
 {
     scsi_unregister_module(MODULE_SCSI_DEV, &sr_template);
     unregister_blkdev(MAJOR_NR, "sr");
     sr_registered--;
     if(scsi_CDs != NULL) {
 	scsi_init_free((char *) scsi_CDs,
-		       (sr_template.dev_noticed + SR_EXTRA_DEVS) 
+		       (sr_template.dev_noticed + SR_EXTRA_DEVS)
 		       * sizeof(Scsi_CD));
-	
+
 	scsi_init_free((char *) sr_sizes, sr_template.dev_max * sizeof(int));
 	scsi_init_free((char *) sr_blocksizes, sr_template.dev_max * sizeof(int));
     }
-    
+
     blksize_size[MAJOR_NR] = NULL;
     blk_dev[MAJOR_NR].request_fn = NULL;
-    blk_size[MAJOR_NR] = NULL;	
+    blk_size[MAJOR_NR] = NULL;
     read_ahead[MAJOR_NR] = 0;
-    
+
     sr_template.dev_max = 0;
 }
 #endif /* MODULE */
diff -u --recursive --new-file v2.1.22/linux/drivers/scsi/st.c linux/drivers/scsi/st.c
--- v2.1.22/linux/drivers/scsi/st.c	Thu Jan  2 15:55:22 1997
+++ linux/drivers/scsi/st.c	Sun Jan 26 12:07:23 1997
@@ -101,7 +101,7 @@
 static int st_detect(Scsi_Device *);
 static void st_detach(Scsi_Device *);
 
-struct Scsi_Device_Template st_template = {NULL, "tape", "st", NULL, TYPE_TAPE, 
+struct Scsi_Device_Template st_template = {NULL, "tape", "st", NULL, TYPE_TAPE,
 					     SCSI_TAPE_MAJOR, 0, 0, 0, 0,
 					     st_detect, st_init,
 					     NULL, st_attach, st_detach};
@@ -586,19 +586,21 @@
     STp->nbr_waits = STp->nbr_finished = 0;
 #endif
 
-    if (scsi_tapes[dev].device->host->hostt->usage_count)
-	(*scsi_tapes[dev].device->host->hostt->usage_count)++;
-    if(st_template.usage_count) (*st_template.usage_count)++;
+    if (scsi_tapes[dev].device->host->hostt->module)
+	__MOD_INC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
+    if(st_template.module)
+	__MOD_INC_USE_COUNT(st_template.module);
 
     memset ((void *) &cmd[0], 0, 10);
     cmd[0] = TEST_UNIT_READY;
 
     SCpnt = st_do_scsi(NULL, STp, cmd, 0, ST_LONG_TIMEOUT, MAX_READY_RETRIES);
     if (!SCpnt) {
-      if (scsi_tapes[dev].device->host->hostt->usage_count)
-	  (*scsi_tapes[dev].device->host->hostt->usage_count)--;
-      if(st_template.usage_count) (*st_template.usage_count)--;
-      return (-EBUSY);
+	if (scsi_tapes[dev].device->host->hostt->module)
+	    __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
+	if(st_template.module)
+	    __MOD_DEC_USE_COUNT(st_template.module);
+	return (-EBUSY);
     }
 
     if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
@@ -715,9 +717,10 @@
 	       STp->block_size);
 	(STp->buffer)->in_use = 0;
 	STp->buffer = NULL;
-	if (scsi_tapes[dev].device->host->hostt->usage_count)
-	    (*scsi_tapes[dev].device->host->hostt->usage_count)--;
-	if(st_template.usage_count) (*st_template.usage_count)--;
+	if (scsi_tapes[dev].device->host->hostt->module)
+	    __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
+	if(st_template.module)
+	    __MOD_DEC_USE_COUNT(st_template.module);
 	return (-EIO);
       }
       STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0;
@@ -746,9 +749,10 @@
       if ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR) {
 	(STp->buffer)->in_use = 0;
 	STp->buffer = NULL;
-	if (scsi_tapes[dev].device->host->hostt->usage_count)
-	    (*scsi_tapes[dev].device->host->hostt->usage_count)--;
-	if(st_template.usage_count) (*st_template.usage_count)--;
+	if (scsi_tapes[dev].device->host->hostt->module)
+	    __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
+	if(st_template.module)
+	    __MOD_DEC_USE_COUNT(st_template.module);
 	return (-EROFS);
       }
     }
@@ -764,9 +768,10 @@
       if ((STp->partition = find_partition(inode)) < 0) {
 	(STp->buffer)->in_use = 0;
 	STp->buffer = NULL;
-	if (scsi_tapes[dev].device->host->hostt->usage_count)
-	    (*scsi_tapes[dev].device->host->hostt->usage_count)--;
-	if(st_template.usage_count) (*st_template.usage_count)--;
+	if (scsi_tapes[dev].device->host->hostt->module)
+	    __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
+	if(st_template.module)
+	    __MOD_DEC_USE_COUNT(st_template.module);
 	return STp->partition;
       }
       STp->new_partition = STp->partition;
@@ -780,9 +785,10 @@
 	  (i = set_mode_densblk(inode, STp, STm)) < 0) {
 	(STp->buffer)->in_use = 0;
 	STp->buffer = NULL;
-	if (scsi_tapes[dev].device->host->hostt->usage_count)
-	    (*scsi_tapes[dev].device->host->hostt->usage_count)--;
-	if(st_template.usage_count) (*st_template.usage_count)--;
+	if (scsi_tapes[dev].device->host->hostt->module)
+	    __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
+	if(st_template.module)
+	    __MOD_DEC_USE_COUNT(st_template.module);
 	return i;
       }
       if (STp->default_drvbuffer != 0xff) {
@@ -913,9 +919,10 @@
     }
 
     STp->in_use = 0;
-    if (scsi_tapes[dev].device->host->hostt->usage_count)
-      (*scsi_tapes[dev].device->host->hostt->usage_count)--;
-    if(st_template.usage_count) (*st_template.usage_count)--;
+    if (scsi_tapes[dev].device->host->hostt->module)
+	__MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
+    if(st_template.module)
+	__MOD_DEC_USE_COUNT(st_template.module);
 
     return;
 }
@@ -1215,7 +1222,7 @@
 	STps->eof = ST_NOEOF;
 
     return( total);
-}   
+}
 
 /* Read data from the tape. Returns zero in the normal case, one if the
    eof status has changed, and the negative error code in case of a
@@ -1573,7 +1580,7 @@
 #endif
 }
 
-  
+
 	static int
 st_set_options(struct inode * inode, long options)
 {
@@ -1850,7 +1857,7 @@
 	 fileno += arg;
        blkno = 0;
        at_sm &= (arg == 0);
-       break; 
+       break;
      case MTBSFM:
        chg_eof = FALSE; /* Changed from the FSF after this */
      case MTBSF:
@@ -1873,7 +1880,7 @@
 	 fileno -= arg;
        blkno = (-1);  /* We can't know the block number */
        at_sm &= (arg == 0);
-       break; 
+       break;
      case MTFSR:
        cmd[0] = SPACE;
        cmd[1] = 0x00; /* Space Blocks */
@@ -1888,7 +1895,7 @@
        if (blkno >= 0)
 	 blkno += arg;
        at_sm &= (arg == 0);
-       break; 
+       break;
      case MTBSR:
        cmd[0] = SPACE;
        cmd[1] = 0x00; /* Space Blocks */
@@ -1907,7 +1914,7 @@
        if (blkno >= 0)
 	 blkno -= arg;
        at_sm &= (arg == 0);
-       break; 
+       break;
      case MTFSS:
        cmd[0] = SPACE;
        cmd[1] = 0x04; /* Space Setmarks */
@@ -1923,7 +1930,7 @@
 	 blkno = fileno = (-1);
 	 at_sm = 1;
        }
-       break; 
+       break;
      case MTBSS:
        cmd[0] = SPACE;
        cmd[1] = 0x04; /* Space Setmarks */
@@ -1944,7 +1951,7 @@
 	 blkno = fileno = (-1);
 	 at_sm = 1;
        }
-       break; 
+       break;
      case MTWEOF:
      case MTWSM:
        if (STp->write_prot)
@@ -1970,7 +1977,7 @@
 	 fileno += arg;
        blkno = 0;
        at_sm = (cmd_in == MTWSM);
-       break; 
+       break;
      case MTREW:
        cmd[0] = REZERO_UNIT;
 #if ST_NOWAIT
@@ -1982,22 +1989,22 @@
 	 printk(ST_DEB_MSG "st%d: Rewinding tape.\n", dev);
 #endif
        fileno = blkno = at_sm = 0 ;
-       break; 
+       break;
      case MTOFFL:
      case MTLOAD:
      case MTUNLOAD:
        cmd[0] = START_STOP;
        if (cmd_in == MTLOAD)
 	 cmd[4] |= 1;
-       /* 
-        * If arg >= 1 && arg <= 6 Enhanced load/unload in HP C1553A 
+       /*
+        * If arg >= 1 && arg <= 6 Enhanced load/unload in HP C1553A
        */
        if (cmd_in != MTOFFL &&
 	   arg >= 1 + MT_ST_HPLOADER_OFFSET
 	   && arg <= 6 + MT_ST_HPLOADER_OFFSET) {
 #if DEBUG
 	   if (debugging) {
-	       printk(ST_DEB_MSG "st%d: Enhanced %sload slot %2ld.\n", 
+	       printk(ST_DEB_MSG "st%d: Enhanced %sload slot %2ld.\n",
 		      dev, (cmd[4]) ? "" : "un",
 		      arg - MT_ST_HPLOADER_OFFSET);
 	   }
@@ -2019,7 +2026,7 @@
        }
 #endif
        fileno = blkno = at_sm = 0 ;
-       break; 
+       break;
      case MTNOP:
 #if DEBUG
        if (debugging)
@@ -2039,7 +2046,7 @@
 	 printk(ST_DEB_MSG "st%d: Retensioning tape.\n", dev);
 #endif
        fileno = blkno = at_sm = 0;
-       break; 
+       break;
      case MTEOM:
        if (!STp->fast_mteom) {
 	 /* space to the end of tape */
@@ -2062,7 +2069,7 @@
 #endif
        blkno = 0;
        at_sm = 0;
-       break; 
+       break;
      case MTERASE:
        if (STp->write_prot)
 	 return (-EACCES);
@@ -2120,7 +2127,7 @@
        if (cmd_in == MTSETDRVBUFFER)
 	 (STp->buffer)->b_data[2] = (arg & 7) << 4;
        else
-	 (STp->buffer)->b_data[2] = 
+	 (STp->buffer)->b_data[2] =
 	   STp->drv_buffer << 4;
        (STp->buffer)->b_data[3] = 8;     /* block descriptor length */
        if (cmd_in == MTSETDENSITY) {
@@ -2349,15 +2356,15 @@
     else {
       result = 0;
       if ((STp->device)->scsi_level < SCSI_2) {
-	*block = ((STp->buffer)->b_data[0] << 16) 
-	+ ((STp->buffer)->b_data[1] << 8) 
+	*block = ((STp->buffer)->b_data[0] << 16)
+	+ ((STp->buffer)->b_data[1] << 8)
 	+ (STp->buffer)->b_data[2];
 	*partition = 0;
       }
       else {
 	*block = ((STp->buffer)->b_data[4] << 24)
-	  + ((STp->buffer)->b_data[5] << 16) 
-	  + ((STp->buffer)->b_data[6] << 8) 
+	  + ((STp->buffer)->b_data[5] << 16)
+	  + ((STp->buffer)->b_data[6] << 8)
 	  + (STp->buffer)->b_data[7];
 	*partition = (STp->buffer)->b_data[1];
 	if (((STp->buffer)->b_data[0] & 0x80) &&
@@ -2711,9 +2718,9 @@
 	* to this device.  If the user wants to rewind the tape,
 	* then reset the flag and allow access again.
 	*/
-       if(mtc.mt_op != MTREW && 
+       if(mtc.mt_op != MTREW &&
 	  mtc.mt_op != MTOFFL &&
-	  mtc.mt_op != MTRETEN && 
+	  mtc.mt_op != MTRETEN &&
 	  mtc.mt_op != MTERASE &&
 	  mtc.mt_op != MTSEEK &&
 	  mtc.mt_op != MTEOM)
@@ -3008,13 +3015,13 @@
 
    if(SDp->type != TYPE_TAPE) return 1;
 
-   if(st_template.nr_dev >= st_template.dev_max) 
+   if(st_template.nr_dev >= st_template.dev_max)
      {
      	SDp->attached--;
      	return 1;
      }
 
-   for(tpnt = scsi_tapes, i=0; i<st_template.dev_max; i++, tpnt++) 
+   for(tpnt = scsi_tapes, i=0; i<st_template.dev_max; i++, tpnt++)
      if(!tpnt->device) break;
 
    if(i >= st_template.dev_max) panic ("scsi_devices corrupt (st)");
@@ -3082,10 +3089,10 @@
   if(SDp->type != TYPE_TAPE) return 0;
 
   printk(KERN_INFO
-	 "Detected scsi tape st%d at scsi%d, channel %d, id %d, lun %d\n", 
+	 "Detected scsi tape st%d at scsi%d, channel %d, id %d, lun %d\n",
 	 st_template.dev_noticed++,
-	 SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); 
-  
+	 SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
+
   return 1;
 }
 
@@ -3189,8 +3196,8 @@
 {
   Scsi_Tape * tpnt;
   int i;
-  
-  for(tpnt = scsi_tapes, i=0; i<st_template.dev_max; i++, tpnt++) 
+
+  for(tpnt = scsi_tapes, i=0; i<st_template.dev_max; i++, tpnt++)
     if(tpnt->device == SDp) {
       tpnt->device = NULL;
       SDp->attached--;
@@ -3205,11 +3212,11 @@
 #ifdef MODULE
 
 int init_module(void) {
-  st_template.usage_count = &__this_module.usecount;
+  st_template.module = &__this_module;
   return scsi_register_module(MODULE_SCSI_DEV, &st_template);
 }
 
-void cleanup_module( void) 
+void cleanup_module( void)
 {
   int i;
 
diff -u --recursive --new-file v2.1.22/linux/drivers/sound/dev_table.h linux/drivers/sound/dev_table.h
--- v2.1.22/linux/drivers/sound/dev_table.h	Thu Dec 12 17:02:44 1996
+++ linux/drivers/sound/dev_table.h	Sun Jan 26 12:07:24 1997
@@ -508,9 +508,12 @@
 
 #if defined(MODULE) || (!defined(linux) && !defined(_AIX))
 	int trace_init = 0;
-#   else
+#else
 	int trace_init = 1;
-#   endif
+#endif
+#ifdef MODULE_PARM
+MODULE_PARM(trace_init, "i");
+#endif
 
 #else
 	extern struct audio_operations * audio_devs[MAX_AUDIO_DEV]; extern int num_audiodevs;
diff -u --recursive --new-file v2.1.22/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c
--- v2.1.22/linux/drivers/sound/soundcard.c	Tue Oct 29 19:58:19 1996
+++ linux/drivers/sound/soundcard.c	Sun Jan 26 12:07:24 1997
@@ -444,11 +444,6 @@
 {
   int             i;
 
-  if (MOD_IN_USE)
-    {
-      return;
-    }
-
   if (chrdev_registered)
     unregister_chrdev (sound_major, "sound");
 
@@ -638,6 +633,9 @@
 #endif
 
 static int      dma_buffsize = DSP_BUFFSIZE;
+#ifdef MODULE_PARM
+MODULE_PARM(dma_buffsize, "i");
+#endif
 
 int
 sound_alloc_dmap (int dev, struct dma_buffparms *dmap, int chan)
diff -u --recursive --new-file v2.1.22/linux/fs/affs/dir.c linux/fs/affs/dir.c
--- v2.1.22/linux/fs/affs/dir.c	Tue Nov 12 15:56:11 1996
+++ linux/fs/affs/dir.c	Sun Jan 26 12:07:24 1997
@@ -32,7 +32,7 @@
 	affs_dir_read,		/* read */
 	NULL,			/* write - bad */
 	affs_readdir,		/* readdir */
-	NULL,			/* select - default */
+	NULL,			/* poll - default */
 	NULL,			/* ioctl - default */
 	NULL,			/* mmap */
 	NULL,			/* no special open code */
diff -u --recursive --new-file v2.1.22/linux/fs/affs/file.c linux/fs/affs/file.c
--- v2.1.22/linux/fs/affs/file.c	Tue Nov 12 15:56:11 1996
+++ linux/fs/affs/file.c	Sun Jan 26 12:07:24 1997
@@ -49,7 +49,7 @@
 	generic_file_read,	/* read */
 	affs_file_write,	/* write */
 	NULL,			/* readdir - bad */
-	NULL,			/* select - default */
+	NULL,			/* poll - default */
 	NULL,			/* ioctl - default */
 	generic_file_mmap,	/* mmap */
 	affs_open_file,		/* special open is needed */
@@ -83,7 +83,7 @@
 	affs_file_read_ofs,	/* read */
 	affs_file_write_ofs,	/* write */
 	NULL,			/* readdir - bad */
-	NULL,			/* select - default */
+	NULL,			/* poll - default */
 	NULL,			/* ioctl - default */
 	NULL,			/* mmap */
 	affs_open_file,		/* special open is needed */
diff -u --recursive --new-file v2.1.22/linux/fs/binfmt_aout.c linux/fs/binfmt_aout.c
--- v2.1.22/linux/fs/binfmt_aout.c	Mon Dec 30 15:39:12 1996
+++ linux/fs/binfmt_aout.c	Sun Jan 26 12:07:24 1997
@@ -37,7 +37,7 @@
 #ifndef MODULE
 	NULL, NULL, load_aout_binary, load_aout_library, aout_core_dump
 #else
-	NULL, &__this_module.usecount, load_aout_binary, load_aout_library, aout_core_dump
+	NULL, &__this_module, load_aout_binary, load_aout_library, aout_core_dump
 #endif
 };
 
@@ -63,7 +63,7 @@
 if (file.f_op->llseek) { \
 	if (file.f_op->llseek(inode,&file,(offset),0) != (offset)) \
  		goto close_coredump; \
-} else file.f_pos = (offset)		
+} else file.f_pos = (offset)
 
 /*
  * Routine writes a core dump image in the current directory.
@@ -85,11 +85,18 @@
 	char corefile[6+sizeof(current->comm)];
 	unsigned long dump_start, dump_size;
 	struct user dump;
-#ifdef __alpha__
+#if defined(__alpha__)
 #       define START_DATA(u)	(u.start_data)
-#else
+#elif defined(__sparc__)
+#       define START_DATA(u)    (u.u_tsize)
+#elif defined(__i386__)
 #       define START_DATA(u)	(u.u_tsize << PAGE_SHIFT)
 #endif
+#ifdef __sparc__
+#       define START_STACK(u)   ((regs->u_regs[UREG_FP]) & ~(PAGE_SIZE - 1))
+#else
+#       define START_STACK(u)   (u.start_stack)
+#endif
 
 	if (!current->dumpable || current->mm->count != 1)
 		return 0;
@@ -131,45 +138,76 @@
 	has_dumped = 1;
 	current->flags |= PF_DUMPCORE;
        	strncpy(dump.u_comm, current->comm, sizeof(current->comm));
+#ifndef __sparc__
 	dump.u_ar0 = (void *)(((unsigned long)(&dump.regs)) - ((unsigned long)(&dump)));
+#endif
 	dump.signal = signr;
 	dump_thread(regs, &dump);
 
 /* If the size of the dump file exceeds the rlimit, then see what would happen
    if we wrote the stack, but not the data area.  */
+#ifdef __sparc__
+	if ((dump.u_dsize+dump.u_ssize) >
+	    current->rlim[RLIMIT_CORE].rlim_cur)
+		dump.u_dsize = 0;
+#else
 	if ((dump.u_dsize+dump.u_ssize+1) * PAGE_SIZE >
 	    current->rlim[RLIMIT_CORE].rlim_cur)
 		dump.u_dsize = 0;
+#endif
 
 /* Make sure we have enough room to write the stack and data areas. */
+#ifdef __sparc__
+	if ((dump.u_ssize) >
+	    current->rlim[RLIMIT_CORE].rlim_cur)
+		dump.u_ssize = 0;
+#else
 	if ((dump.u_ssize+1) * PAGE_SIZE >
 	    current->rlim[RLIMIT_CORE].rlim_cur)
 		dump.u_ssize = 0;
+#endif
 
 /* make sure we actually have a data and stack area to dump */
 	set_fs(USER_DS);
+#ifdef __sparc__
+	if (verify_area(VERIFY_READ, (void *) START_DATA(dump), dump.u_dsize))
+		dump.u_dsize = 0;
+	if (verify_area(VERIFY_READ, (void *) START_STACK(dump), dump.u_ssize))
+		dump.u_ssize = 0;
+#else
 	if (verify_area(VERIFY_READ, (void *) START_DATA(dump), dump.u_dsize << PAGE_SHIFT))
 		dump.u_dsize = 0;
-	if (verify_area(VERIFY_READ, (void *) dump.start_stack, dump.u_ssize << PAGE_SHIFT))
+	if (verify_area(VERIFY_READ, (void *) START_STACK(dump), dump.u_ssize << PAGE_SHIFT))
 		dump.u_ssize = 0;
+#endif
 
 	set_fs(KERNEL_DS);
 /* struct user */
 	DUMP_WRITE(&dump,sizeof(dump));
 /* Now dump all of the user data.  Include malloced stuff as well */
+#ifndef __sparc__
 	DUMP_SEEK(PAGE_SIZE);
+#endif
 /* now we start writing out the user space info */
 	set_fs(USER_DS);
 /* Dump the data area */
 	if (dump.u_dsize != 0) {
 		dump_start = START_DATA(dump);
+#ifdef __sparc__
+		dump_size = dump.u_dsize;
+#else
 		dump_size = dump.u_dsize << PAGE_SHIFT;
+#endif
 		DUMP_WRITE(dump_start,dump_size);
 	}
 /* Now prepare to dump the stack area */
 	if (dump.u_ssize != 0) {
-		dump_start = dump.start_stack;
+		dump_start = START_STACK(dump);
+#ifdef __sparc__
+		dump_size = dump.u_ssize;
+#else
 		dump_size = dump.u_ssize << PAGE_SHIFT;
+#endif
 		DUMP_WRITE(dump_start,dump_size);
 	}
 /* Finally dump the task struct.  Not be used by gdb, but could be useful */
@@ -210,6 +248,11 @@
 	int envc = bprm->envc;
 
 	sp = (unsigned long *) ((-(unsigned long)sizeof(char *)) & (unsigned long) p);
+#ifdef __sparc__
+	/* This imposes the proper stack alignment for a new process. */
+	sp = (unsigned long *) (((unsigned long) sp) & ~7);
+	if ((envc+argc+3)&1) --sp;
+#endif
 #ifdef __alpha__
 /* whee.. test-programs are so much fun. */
 	put_user(0, --sp);
@@ -259,8 +302,7 @@
  * libraries.  There is no binary dependent code anywhere else.
  */
 
-static inline int
-do_load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
+static inline int do_load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
 {
 	struct exec ex;
 	struct file * file;
@@ -271,8 +313,8 @@
 	unsigned long rlim;
 
 	ex = *((struct exec *) bprm->buf);		/* exec-header */
-	if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC && 
-	     N_MAGIC(ex) != QMAGIC) ||
+	if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC &&
+	     N_MAGIC(ex) != QMAGIC && N_MAGIC(ex) != NMAGIC) ||
 	    N_TRSIZE(ex) || N_DRSIZE(ex) ||
 	    bprm->inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
 		return -ENOEXEC;
@@ -306,6 +348,9 @@
 
 	/* OK, This is the point of no return */
 	flush_old_exec(bprm);
+#ifdef __sparc__
+	memcpy(&current->tss.core_exec, &ex, sizeof(struct exec));
+#endif
 
 	current->mm->end_code = ex.a_text +
 		(current->mm->start_code = N_TXTADDR(ex));
@@ -319,8 +364,25 @@
 	current->suid = current->euid = current->fsuid = bprm->e_uid;
 	current->sgid = current->egid = current->fsgid = bprm->e_gid;
  	current->flags &= ~PF_FORKNOEXEC;
+#ifdef __sparc__
+	if (N_MAGIC(ex) == NMAGIC) {
+		/* Fuck me plenty... */
+		error = do_mmap(NULL, N_TXTADDR(ex), ex.a_text,
+				PROT_READ|PROT_WRITE|PROT_EXEC,
+				MAP_FIXED|MAP_PRIVATE, 0);
+		read_exec(bprm->inode, fd_offset, (char *) N_TXTADDR(ex),
+			  ex.a_text, 0);
+		error = do_mmap(NULL, N_DATADDR(ex), ex.a_data,
+				PROT_READ|PROT_WRITE|PROT_EXEC,
+				MAP_FIXED|MAP_PRIVATE, 0);
+		read_exec(bprm->inode, fd_offset + ex.a_text, (char *) N_DATADDR(ex),
+			  ex.a_data, 0);
+		goto beyond_if;
+	}
+#endif
+
 	if (N_MAGIC(ex) == OMAGIC) {
-#ifdef __alpha__
+#if defined(__alpha__) || defined(__sparc__)
 		do_mmap(NULL, N_TXTADDR(ex) & PAGE_MASK,
 			ex.a_text+ex.a_data + PAGE_SIZE - 1,
 			PROT_READ|PROT_WRITE|PROT_EXEC,
@@ -334,11 +396,12 @@
 		read_exec(bprm->inode, 32, (char *) 0, ex.a_text+ex.a_data, 0);
 #endif
 	} else {
-		if (ex.a_text & 0xfff || ex.a_data & 0xfff)
+		if ((ex.a_text & 0xfff || ex.a_data & 0xfff) &&
+		    (N_MAGIC(ex) != NMAGIC))
 			printk(KERN_NOTICE "executable not page aligned\n");
-		
+
 		fd = open_inode(bprm->inode, O_RDONLY);
-		
+
 		if (fd < 0)
 			return fd;
 		file = current->files->fd[fd];
@@ -362,7 +425,7 @@
 			send_sig(SIGKILL, current, 0);
 			return error;
 		}
-		
+
  		error = do_mmap(file, N_DATADDR(ex), ex.a_data,
 				PROT_READ | PROT_WRITE | PROT_EXEC,
 				MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
@@ -374,21 +437,21 @@
 		}
 	}
 beyond_if:
-	if (current->exec_domain && current->exec_domain->use_count)
-		(*current->exec_domain->use_count)--;
-	if (current->binfmt && current->binfmt->use_count)
-		(*current->binfmt->use_count)--;
+	if (current->exec_domain && current->exec_domain->module)
+		__MOD_DEC_USE_COUNT(current->exec_domain->module);
+	if (current->binfmt && current->binfmt->module)
+		__MOD_DEC_USE_COUNT(current->binfmt->module);
 	current->exec_domain = lookup_exec_domain(current->personality);
 	current->binfmt = &aout_format;
-	if (current->exec_domain && current->exec_domain->use_count)
-		(*current->exec_domain->use_count)++;
-	if (current->binfmt && current->binfmt->use_count)
-		(*current->binfmt->use_count)++;
+	if (current->exec_domain && current->exec_domain->module)
+		__MOD_INC_USE_COUNT(current->exec_domain->module);
+	if (current->binfmt && current->binfmt->module)
+		__MOD_INC_USE_COUNT(current->binfmt->module);
 
 	set_brk(current->mm->start_brk, current->mm->brk);
 
 	p = setup_arg_pages(p, bprm);
-	
+
 	p = (unsigned long) create_aout_tables((char *)p, bprm);
 	current->mm->start_stack = p;
 #ifdef __alpha__
@@ -400,6 +463,7 @@
 	return 0;
 }
 
+
 static int
 load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
 {
@@ -421,10 +485,10 @@
 	unsigned int bss;
 	unsigned int start_addr;
 	unsigned long error;
-	
+
 	file = current->files->fd[fd];
 	inode = file->f_inode;
-	
+
 	if (!file || !file->f_op)
 		return -EACCES;
 
@@ -447,12 +511,12 @@
 	    inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
 		return -ENOEXEC;
 	}
-	if (N_MAGIC(ex) == ZMAGIC && N_TXTOFF(ex) && 
+	if (N_MAGIC(ex) == ZMAGIC && N_TXTOFF(ex) &&
 	    (N_TXTOFF(ex) < inode->i_sb->s_blocksize)) {
 		printk("N_TXTOFF < BLOCK_SIZE. Please convert library\n");
 		return -ENOEXEC;
 	}
-	
+
 	if (N_FLAGS(ex)) return -ENOEXEC;
 
 	/* For  QMAGIC, the starting address is 0x20 into the page.  We mask
@@ -504,4 +568,3 @@
 	unregister_binfmt(&aout_format);
 }
 #endif
-
diff -u --recursive --new-file v2.1.22/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- v2.1.22/linux/fs/binfmt_elf.c	Wed Jan 15 19:45:43 1997
+++ linux/fs/binfmt_elf.c	Sun Jan 26 12:07:30 1997
@@ -42,6 +42,10 @@
 extern int dump_fpu (struct pt_regs *, elf_fpregset_t *);
 extern void dump_thread(struct pt_regs *, struct user *);
 
+#ifdef __sparc__
+extern unsigned long get_unmapped_area(unsigned long addr, unsigned long len);
+#endif
+
 /*
  * If we don't support core dumping, then supply a NULL so we
  * don't even try.
@@ -59,7 +63,7 @@
 #ifndef MODULE
 	NULL, NULL, load_elf_binary, load_elf_library, elf_core_dump
 #else
-	NULL, &__this_module.usecount, load_elf_binary, load_elf_library, elf_core_dump
+	NULL, &__this_module, load_elf_binary, load_elf_library, elf_core_dump
 #endif
 };
 
@@ -67,7 +71,7 @@
 {
 	start = PAGE_ALIGN(start);
 	end = PAGE_ALIGN(end);
-	if (end <= start) 
+	if (end <= start)
 		return;
 	do_mmap(NULL, start, end - start,
 		PROT_READ | PROT_WRITE | PROT_EXEC,
@@ -84,7 +88,7 @@
 static void padzero(unsigned long elf_bss)
 {
 	unsigned long nbyte;
-  
+
 	nbyte = elf_bss & (PAGE_SIZE-1);
 	if (nbyte) {
 		nbyte = PAGE_SIZE - nbyte;
@@ -92,7 +96,7 @@
 	}
 }
 
-unsigned long * create_elf_tables(char *p, int argc, int envc, 
+unsigned long * create_elf_tables(char *p, int argc, int envc,
 				  struct elfhdr * exec,
 				  unsigned long load_addr,
 				  unsigned long interp_load_addr, int ibcs)
@@ -176,7 +180,7 @@
    an ELF header */
 
 static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
-				     struct inode * interpreter_inode, 
+				     struct inode * interpreter_inode,
 				     unsigned long *interp_load_addr)
 {
 	struct file * file;
@@ -189,31 +193,31 @@
 	unsigned long last_bss, elf_bss;
 	unsigned long error;
 	int i;
-	
+
 	elf_bss = 0;
 	last_bss = 0;
 	error = load_addr = 0;
-	
+
 	/* First of all, some simple consistency checks */
-	if ((interp_elf_ex->e_type != ET_EXEC && 
-	    interp_elf_ex->e_type != ET_DYN) || 
+	if ((interp_elf_ex->e_type != ET_EXEC &&
+	    interp_elf_ex->e_type != ET_DYN) ||
 	   !elf_check_arch(interp_elf_ex->e_machine) ||
 	   (!interpreter_inode->i_op ||
 	    !interpreter_inode->i_op->default_file_ops->mmap)){
 		return ~0UL;
 	}
-	
+
 	/* Now read in all of the header information */
-	
+
 	if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > PAGE_SIZE)
 	    return ~0UL;
-	
-	elf_phdata =  (struct elf_phdr *) 
-		kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, 
+
+	elf_phdata =  (struct elf_phdr *)
+		kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum,
 			GFP_KERNEL);
 	if (!elf_phdata)
 	  return ~0UL;
-	
+
 	/*
 	 * If the size of this structure has changed, then punt, since
 	 * we will be doing the wrong thing.
@@ -224,10 +228,10 @@
 	    return ~0UL;
 	  }
 
-	retval = read_exec(interpreter_inode, interp_elf_ex->e_phoff, 
+	retval = read_exec(interpreter_inode, interp_elf_ex->e_phoff,
 			   (char *) elf_phdata,
 			   sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, 1);
-	
+
 	if (retval < 0) {
 		kfree (elf_phdata);
 		return retval;
@@ -255,15 +259,20 @@
 	    if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) {
 	    	elf_type |= MAP_FIXED;
 	    	vaddr = eppnt->p_vaddr;
+#ifdef __sparc__
+	    } else {
+		load_addr = get_unmapped_area(0, eppnt->p_filesz +
+					ELF_PAGEOFFSET(eppnt->p_vaddr));
+#endif
 	    }
-	    
-	    error = do_mmap(file, 
+
+	    error = do_mmap(file,
 			    load_addr + ELF_PAGESTART(vaddr),
 			    eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr),
 			    elf_prot,
 			    elf_type,
 			    eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr));
-	    
+
 	    if (error > -1024UL) {
 	      /* Real error */
 	      sys_close(elf_exec_fileno);
@@ -290,7 +299,7 @@
 	    k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
 	    if (k > last_bss) last_bss = k;
 	  }
-	
+
 	/* Now use mmap to map the library into memory. */
 
 	sys_close(elf_exec_fileno);
@@ -320,18 +329,18 @@
 {
   int retval;
   unsigned long elf_entry;
-  
+
   current->mm->brk = interp_ex->a_bss +
     (current->mm->end_data = interp_ex->a_data +
      (current->mm->end_code = interp_ex->a_text));
   elf_entry = interp_ex->a_entry;
-  
-  
+
+
   if (N_MAGIC(*interp_ex) == OMAGIC) {
     do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data,
 	    PROT_READ|PROT_WRITE|PROT_EXEC,
 	    MAP_FIXED|MAP_PRIVATE, 0);
-    retval = read_exec(interpreter_inode, 32, (char *) 0, 
+    retval = read_exec(interpreter_inode, 32, (char *) 0,
 		       interp_ex->a_text+interp_ex->a_data, 0);
   } else if (N_MAGIC(*interp_ex) == ZMAGIC || N_MAGIC(*interp_ex) == QMAGIC) {
     do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data,
@@ -343,7 +352,7 @@
 		       interp_ex->a_text+interp_ex->a_data, 0);
   } else
     retval = -1;
-  
+
   if (retval >= 0)
     do_mmap(NULL, ELF_PAGESTART(interp_ex->a_text + interp_ex->a_data + ELF_EXEC_PAGESIZE - 1),
 	    interp_ex->a_bss,
@@ -388,62 +397,62 @@
 	unsigned long start_code, end_code, end_data;
 	unsigned long elf_stack;
 	char passed_fileno[6];
-	
+
 	ibcs2_interpreter = 0;
 	status = 0;
 	load_addr = 0;
 	elf_ex = *((struct elfhdr *) bprm->buf);	  /* exec-header */
-	
+
 	if (elf_ex.e_ident[0] != 0x7f ||
 	    strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) {
 		return  -ENOEXEC;
 	}
-	
-	
+
+
 	/* First of all, some simple consistency checks */
 	if ((elf_ex.e_type != ET_EXEC &&
-	    elf_ex.e_type != ET_DYN) || 
+	    elf_ex.e_type != ET_DYN) ||
 	   (! elf_check_arch(elf_ex.e_machine)) ||
 	   (!bprm->inode->i_op || !bprm->inode->i_op->default_file_ops ||
 	    !bprm->inode->i_op->default_file_ops->mmap)){
 		return -ENOEXEC;
 	}
-	
+
 	/* Now read in all of the header information */
-	
-	elf_phdata = (struct elf_phdr *) kmalloc(elf_ex.e_phentsize * 
+
+	elf_phdata = (struct elf_phdr *) kmalloc(elf_ex.e_phentsize *
 						 elf_ex.e_phnum, GFP_KERNEL);
 	if (elf_phdata == NULL) {
 		return -ENOMEM;
 	}
-	
+
 	retval = read_exec(bprm->inode, elf_ex.e_phoff, (char *) elf_phdata,
 			   elf_ex.e_phentsize * elf_ex.e_phnum, 1);
 	if (retval < 0) {
 		kfree (elf_phdata);
 		return retval;
 	}
-	
+
 	elf_ppnt = elf_phdata;
-	
+
 	elf_bss = 0;
 	elf_brk = 0;
-	
+
 	elf_exec_fileno = open_inode(bprm->inode, O_RDONLY);
 
 	if (elf_exec_fileno < 0) {
 		kfree (elf_phdata);
 		return elf_exec_fileno;
 	}
-	
+
 	file = current->files->fd[elf_exec_fileno];
-	
+
 	elf_stack = ~0UL;
 	elf_interpreter = NULL;
 	start_code = ~0UL;
 	end_code = 0;
 	end_data = 0;
-	
+
 	for(i=0;i < elf_ex.e_phnum; i++){
 		if (elf_ppnt->p_type == PT_INTERP) {
 		  	if ( elf_interpreter != NULL )
@@ -456,17 +465,17 @@
 
 			/* This is the program interpreter used for
 			 * shared libraries - for now assume that this
-			 * is an a.out format binary 
+			 * is an a.out format binary
 			 */
-			
-			elf_interpreter = (char *) kmalloc(elf_ppnt->p_filesz, 
+
+			elf_interpreter = (char *) kmalloc(elf_ppnt->p_filesz,
 							   GFP_KERNEL);
 			if (elf_interpreter == NULL) {
 				kfree (elf_phdata);
 				sys_close(elf_exec_fileno);
 				return -ENOMEM;
 			}
-			
+
 			retval = read_exec(bprm->inode,elf_ppnt->p_offset,
 					   elf_interpreter,
 					   elf_ppnt->p_filesz, 1);
@@ -489,11 +498,11 @@
 
 			if (retval >= 0)
 				retval = read_exec(interpreter_inode,0,bprm->buf,128, 1);
-			
+
 			if (retval >= 0) {
 				interp_ex = *((struct exec *) bprm->buf);		/* exec-header */
 				interp_elf_ex = *((struct elfhdr *) bprm->buf);	  /* exec-header */
-				
+
 			}
 			if (retval < 0) {
 				kfree (elf_phdata);
@@ -510,9 +519,9 @@
 		interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
 
 		/* Now figure out which format our binary is */
-		if ((N_MAGIC(interp_ex) != OMAGIC) && 
+		if ((N_MAGIC(interp_ex) != OMAGIC) &&
 		    (N_MAGIC(interp_ex) != ZMAGIC) &&
-		    (N_MAGIC(interp_ex) != QMAGIC)) 
+		    (N_MAGIC(interp_ex) != QMAGIC))
 		  interpreter_type = INTERPRETER_ELF;
 
 		if (interp_elf_ex.e_ident[0] != 0x7f ||
@@ -527,17 +536,17 @@
 		    return -ELIBBAD;
 		  }
 	}
-	
+
 	/* OK, we are done with that, now set up the arg stuff,
 	   and then start this sucker up */
-	
+
 	if (!bprm->sh_bang) {
 		char * passed_p;
-		
+
 		if (interpreter_type == INTERPRETER_AOUT) {
 		  sprintf(passed_fileno, "%d", elf_exec_fileno);
 		  passed_p = passed_fileno;
-		
+
 		  if (elf_interpreter) {
 		    bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p,2);
 		    bprm->argc++;
@@ -552,7 +561,7 @@
 			return -E2BIG;
 		}
 	}
-	
+
 	/* OK, This is the point of no return */
 	flush_old_exec(bprm);
 
@@ -561,18 +570,18 @@
 	current->mm->start_mmap = ELF_START_MMAP;
 	current->mm->mmap = NULL;
 	elf_entry = (unsigned long) elf_ex.e_entry;
-	
+
 	/* 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(bprm->p, bprm);
 	current->mm->start_stack = bprm->p;
-	
+
 	/* Now we do a little grungy work by mmaping the ELF image into
 	   the correct location in memory.  At this point, we assume that
 	   the image should be loaded at fixed address, not at a variable
 	   address. */
-	
+
 	old_fs = get_fs();
 	set_fs(get_ds());
 	for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
@@ -591,13 +600,13 @@
 					 MAP_DENYWRITE | MAP_EXECUTABLE),
 					(elf_ppnt->p_offset -
 					 ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
-			
+
 #ifdef LOW_ELF_STACK
-			if (ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack) 
+			if (ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack)
 				elf_stack = ELF_PAGESTART(elf_ppnt->p_vaddr);
 #endif
-			
-			if (!load_addr_set) { 
+
+			if (!load_addr_set) {
 			  load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
 			  load_addr_set = 1;
 			}
@@ -610,27 +619,27 @@
 #else
 			if ( !(elf_ppnt->p_flags & PF_W) && end_code <  k)
 #endif
-				end_code = k; 
-			if (end_data < k) end_data = k; 
+				end_code = k;
+			if (end_data < k) end_data = k;
 			k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
-			if (k > elf_brk) elf_brk = k;		     
+			if (k > elf_brk) elf_brk = k;
 		}
 	}
 	set_fs(old_fs);
 
 	if (elf_interpreter) {
-		if (interpreter_type & 1) 
+		if (interpreter_type & 1)
 			elf_entry = load_aout_interp(&interp_ex,
 						     interpreter_inode);
-		else if (interpreter_type & 2) 
-			elf_entry = load_elf_interp(&interp_elf_ex, 
-						    interpreter_inode, 
+		else if (interpreter_type & 2)
+			elf_entry = load_elf_interp(&interp_elf_ex,
+						    interpreter_inode,
 						    &interp_load_addr);
 
 		iput(interpreter_inode);
 		kfree(elf_interpreter);
-			
-		if (elf_entry == ~0UL) { 
+
+		if (elf_entry == ~0UL) {
 			printk("Unable to load interpreter\n");
 			kfree(elf_phdata);
 			send_sig(SIGSEGV, current, 0);
@@ -639,20 +648,20 @@
 	}
 
 	kfree(elf_phdata);
-	
+
 	if (interpreter_type != INTERPRETER_AOUT) sys_close(elf_exec_fileno);
 	current->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
 
-	if (current->exec_domain && current->exec_domain->use_count)
-		(*current->exec_domain->use_count)--;
-	if (current->binfmt && current->binfmt->use_count)
-		(*current->binfmt->use_count)--;
+	if (current->exec_domain && current->exec_domain->module)
+		__MOD_DEC_USE_COUNT(current->exec_domain->module);
+	if (current->binfmt && current->binfmt->module)
+		__MOD_DEC_USE_COUNT(current->binfmt->module);
 	current->exec_domain = lookup_exec_domain(current->personality);
 	current->binfmt = &elf_format;
-	if (current->exec_domain && current->exec_domain->use_count)
-		(*current->exec_domain->use_count)++;
-	if (current->binfmt && current->binfmt->use_count)
-		(*current->binfmt->use_count)++;
+	if (current->exec_domain && current->exec_domain->module)
+		__MOD_INC_USE_COUNT(current->exec_domain->module);
+	if (current->binfmt && current->binfmt->module)
+		__MOD_INC_USE_COUNT(current->binfmt->module);
 
 #ifndef VM_STACK_FLAGS
 	current->executable = bprm->inode;
@@ -664,7 +673,7 @@
 	current->suid = current->euid = current->fsuid = bprm->e_uid;
 	current->sgid = current->egid = current->fsgid = bprm->e_gid;
 	current->flags &= ~PF_FORKNOEXEC;
-	bprm->p = (unsigned long) 
+	bprm->p = (unsigned long)
 	  create_elf_tables((char *)bprm->p,
 			bprm->argc,
 			bprm->envc,
@@ -753,7 +762,7 @@
 	file = current->files->fd[fd];
 	inode = file->f_inode;
 	elf_bss = 0;
-	
+
 	if (!file || !file->f_op)
 		return -EACCES;
 
@@ -779,31 +788,31 @@
 	   !elf_check_arch(elf_ex.e_machine) ||
 	   (!inode->i_op || !inode->i_op->default_file_ops->mmap))
 		return -ENOEXEC;
-	
+
 	/* Now read in all of the header information */
-	
+
 	if (sizeof(struct elf_phdr) * elf_ex.e_phnum > PAGE_SIZE)
 		return -ENOEXEC;
-	
-	elf_phdata =  (struct elf_phdr *) 
+
+	elf_phdata =  (struct elf_phdr *)
 		kmalloc(sizeof(struct elf_phdr) * elf_ex.e_phnum, GFP_KERNEL);
 	if (elf_phdata == NULL)
 		return -ENOMEM;
-	
+
 	retval = read_exec(inode, elf_ex.e_phoff, (char *) elf_phdata,
 			   sizeof(struct elf_phdr) * elf_ex.e_phnum, 1);
-	
+
 	j = 0;
 	for(i=0; i<elf_ex.e_phnum; i++)
 		if ((elf_phdata + i)->p_type == PT_LOAD) j++;
-	
+
 	if (j != 1)  {
 		kfree(elf_phdata);
 		return -ENOEXEC;
 	}
-	
+
 	while(elf_phdata->p_type != PT_LOAD) elf_phdata++;
-	
+
 	/* Now use mmap to map the library into memory. */
 	error = do_mmap(file,
 			ELF_PAGESTART(elf_phdata->p_vaddr),
@@ -816,7 +825,7 @@
 
 	k = elf_phdata->p_vaddr + elf_phdata->p_filesz;
 	if (k > elf_bss) elf_bss = k;
-	
+
 	if (error != ELF_PAGESTART(elf_phdata->p_vaddr)) {
 		kfree(elf_phdata);
 		return error;
@@ -909,11 +918,11 @@
 static int notesize(struct memelfnote *en)
 {
 	int sz;
-	
+
 	sz = sizeof(struct elf_note);
 	sz += roundup(strlen(en->name), 4);
 	sz += roundup(en->datasz, 4);
-	
+
 	return sz;
 }
 
@@ -956,7 +965,7 @@
 	DUMP_SEEK(roundup((unsigned long)file->f_pos, 4));	/* XXX */
 	DUMP_WRITE(men->data, men->datasz);
 	DUMP_SEEK(roundup((unsigned long)file->f_pos, 4));	/* XXX */
-	
+
 	return 1;
 }
 #undef DUMP_WRITE
@@ -994,7 +1003,7 @@
 	struct elf_prstatus prstatus;	/* NT_PRSTATUS */
 	elf_fpregset_t fpu;		/* NT_PRFPREG */
 	struct elf_prpsinfo psinfo;	/* NT_PRPSINFO */
-	
+
 	if (!current->dumpable || limit < PAGE_SIZE || current->mm->count != 1)
 		return 0;
 	current->dumpable = 0;
@@ -1010,13 +1019,13 @@
 		if (maydump(vma))
 		{
 			int sz = vma->vm_end-vma->vm_start;
-		
+
 			if (size+sz >= limit)
 				break;
 			else
 				size += sz;
 		}
-		
+
 		segs++;
 	}
 #ifdef DEBUG
@@ -1029,7 +1038,7 @@
 	elf.e_ident[EI_DATA] = ELF_DATA;
 	elf.e_ident[EI_VERSION] = EV_CURRENT;
 	memset(elf.e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
-	
+
 	elf.e_type = ET_CORE;
 	elf.e_machine = ELF_ARCH;
 	elf.e_version = EV_CURRENT;
@@ -1043,7 +1052,7 @@
 	elf.e_shentsize = 0;
 	elf.e_shnum = 0;
 	elf.e_shstrndx = 0;
-	
+
 	fs = get_fs();
 	set_fs(KERNEL_DS);
 	memcpy(corefile,"core.",5);
@@ -1121,7 +1130,7 @@
 	else
 		*(struct pt_regs *)&prstatus.pr_reg = *regs;
 #endif
-	
+
 #ifdef DEBUG
 	dump_regs("Passed in regs", (elf_greg_t *)regs);
 	dump_regs("prstatus regs", (elf_greg_t *)&prstatus.pr_reg);
@@ -1142,7 +1151,7 @@
 		int i, len;
 
 		set_fs(fs);
-		
+
 		len = current->mm->arg_end - current->mm->arg_start;
 		len = len >= ELF_PRARGSZ ? ELF_PRARGSZ : len;
 		copy_from_user(&psinfo.pr_psargs,
@@ -1160,7 +1169,7 @@
 	notes[2].type = NT_TASKSTRUCT;
 	notes[2].datasz = sizeof(*current);
 	notes[2].data = current;
-	
+
 	/* Try to dump the fpu. */
 	prstatus.pr_fpvalid = dump_fpu (regs, &fpu);
 	if (!prstatus.pr_fpvalid)
@@ -1182,7 +1191,7 @@
 
 		for(i = 0; i < numnote; i++)
 			sz += notesize(&notes[i]);
-		
+
 		phdr.p_type = PT_NOTE;
 		phdr.p_offset = offset;
 		phdr.p_vaddr = 0;
@@ -1198,7 +1207,7 @@
 
 	/* Page-align dumped data */
 	dataoff = offset = roundup(offset, PAGE_SIZE);
-	
+
 	/* Write program headers for segments dump */
 	for(vma = current->mm->mmap, i = 0;
 		i < segs && vma != NULL; vma = vma->vm_next) {
@@ -1208,7 +1217,7 @@
 		i++;
 
 		sz = vma->vm_end - vma->vm_start;
-		
+
 		phdr.p_type = PT_LOAD;
 		phdr.p_offset = offset;
 		phdr.p_vaddr = vma->vm_start;
@@ -1227,17 +1236,17 @@
 	for(i = 0; i < numnote; i++)
 		if (!writenote(&notes[i], &file))
 			goto close_coredump;
-	
+
 	set_fs(fs);
 
 	DUMP_SEEK(dataoff);
-	
+
 	for(i = 0, vma = current->mm->mmap;
 	    i < segs && vma != NULL;
 	    vma = vma->vm_next) {
 		unsigned long addr = vma->vm_start;
 		unsigned long len = vma->vm_end - vma->vm_start;
-		
+
 		i++;
 		if (!maydump(vma))
 			continue;
@@ -1267,14 +1276,14 @@
 }
 #endif		/* USE_ELF_CORE_DUMP */
 
-int init_elf_binfmt(void) 
+int init_elf_binfmt(void)
 {
 	return register_binfmt(&elf_format);
 }
 
 #ifdef MODULE
 
-int init_module(void) 
+int init_module(void)
 {
 	/* Install the COFF, ELF and XOUT loaders.
 	 * N.B. We *rely* on the table being the right size with the
@@ -1284,7 +1293,7 @@
 }
 
 
-void cleanup_module( void) 
+void cleanup_module( void)
 {
 	/* Remove the COFF and ELF loaders. */
 	unregister_binfmt(&elf_format);
diff -u --recursive --new-file v2.1.22/linux/fs/binfmt_java.c linux/fs/binfmt_java.c
--- v2.1.22/linux/fs/binfmt_java.c	Mon Dec 30 15:39:13 1996
+++ linux/fs/binfmt_java.c	Sun Jan 26 12:07:30 1997
@@ -144,7 +144,7 @@
 #ifndef MODULE
 	NULL, 0, load_java, NULL, NULL
 #else
-	NULL, &__this_module.usecount, load_java, NULL, NULL
+	NULL, &__this_module, load_java, NULL, NULL
 #endif
 };
 
@@ -161,7 +161,7 @@
 #ifndef MODULE
 	NULL, 0, load_applet, NULL, NULL
 #else
-	NULL, &__this_module.usecount, load_applet, NULL, NULL
+	NULL, &__this_module, load_applet, NULL, NULL
 #endif
 };
 
diff -u --recursive --new-file v2.1.22/linux/fs/binfmt_script.c linux/fs/binfmt_script.c
--- v2.1.22/linux/fs/binfmt_script.c	Mon Dec 30 15:39:13 1996
+++ linux/fs/binfmt_script.c	Sun Jan 26 12:07:30 1997
@@ -100,7 +100,7 @@
 #ifndef MODULE
 	NULL, 0, load_script, NULL, NULL
 #else
-	NULL, &__this_module.usecount, load_script, NULL, NULL
+	NULL, &__this_module, load_script, NULL, NULL
 #endif
 };
 
diff -u --recursive --new-file v2.1.22/linux/fs/buffer.c linux/fs/buffer.c
--- v2.1.22/linux/fs/buffer.c	Thu Jan  2 15:55:22 1997
+++ linux/fs/buffer.c	Sun Jan 26 12:07:30 1997
@@ -249,7 +249,9 @@
 
 asmlinkage int sys_sync(void)
 {
+	lock_kernel();
 	fsync_dev(0);
+	unlock_kernel();
 	return 0;
 }
 
@@ -262,29 +264,39 @@
 {
 	struct file * file;
 	struct inode * inode;
+	int err = 0;
 
+	lock_kernel();
 	if (fd>=NR_OPEN || !(file=current->files->fd[fd]) || !(inode=file->f_inode))
-		return -EBADF;
-	if (!file->f_op || !file->f_op->fsync)
-		return -EINVAL;
-	if (file->f_op->fsync(inode,file))
-		return -EIO;
-	return 0;
+		err = -EBADF;
+	else if (!file->f_op || !file->f_op->fsync)
+		err = -EINVAL;
+	else if (file->f_op->fsync(inode,file))
+		err = -EIO;
+	unlock_kernel();
+	return err;
 }
 
 asmlinkage int sys_fdatasync(unsigned int fd)
 {
 	struct file * file;
 	struct inode * inode;
+	int err = -EBADF;
 
+	lock_kernel();
 	if (fd>=NR_OPEN || !(file=current->files->fd[fd]) || !(inode=file->f_inode))
-		return -EBADF;
+		goto out;
+	err = -EINVAL;
 	if (!file->f_op || !file->f_op->fsync)
-		return -EINVAL;
+		goto out;
 	/* this needs further work, at the moment it is identical to fsync() */
 	if (file->f_op->fsync(inode,file))
-		return -EIO;
-	return 0;
+		err = -EIO;
+	else
+		err = 0;
+out:
+	unlock_kernel();
+	return err;
 }
 
 void invalidate_buffers(kdev_t dev)
@@ -1546,33 +1558,42 @@
 
 asmlinkage int sys_bdflush(int func, long data)
 {
-	int i;
+	int i, error = -EPERM;
 
+	lock_kernel();
 	if (!suser())
-		return -EPERM;
+		goto out;
 
-	if (func == 1)
-		 return sync_old_buffers();
+	if (func == 1) {
+		 error = sync_old_buffers();
+		 goto out;
+	}
 
 	/* Basically func 1 means read param 1, 2 means write param 1, etc */
 	if (func >= 2) {
 		i = (func-2) >> 1;
+		error = -EINVAL;
 		if (i < 0 || i >= N_PARAM)
-			return -EINVAL;
+			goto out;
 		if((func & 1) == 0) {
-			return put_user(bdf_prm.data[i], (int*)data);
-		};
+			error = put_user(bdf_prm.data[i], (int*)data);
+			goto out;
+		}
 		if (data < bdflush_min[i] || data > bdflush_max[i])
-			return -EINVAL;
+			goto out;
 		bdf_prm.data[i] = data;
-		return 0;
+		error = 0;
+		goto out;
 	};
 
 	/* Having func 0 used to launch the actual bdflush and then never
-	return (unless explicitly killed). We return zero here to 
-	remain semi-compatible with present update(8) programs. */
-
-	return 0;
+	 * return (unless explicitly killed). We return zero here to 
+	 * remain semi-compatible with present update(8) programs.
+	 */
+	error = 0;
+out:
+	unlock_kernel();
+	return error;
 }
 
 /* This is the actual bdflush daemon itself. It used to be started from
@@ -1613,11 +1634,7 @@
 	 *	and other internals and thus be subject to the SMP locking
 	 *	rules. (On a uniprocessor box this does nothing).
 	 */
-	 
-#ifdef __SMP__
 	lock_kernel();
-	syscall_count++;
-#endif
 		 
 	for (;;) {
 #ifdef DEBUG
diff -u --recursive --new-file v2.1.22/linux/fs/devices.c linux/fs/devices.c
--- v2.1.22/linux/fs/devices.c	Wed Jan 15 19:45:43 1997
+++ linux/fs/devices.c	Sat Jan 25 23:46:13 1997
@@ -253,7 +253,7 @@
 	NULL,		/* read */
 	NULL,		/* write */
 	NULL,		/* readdir */
-	NULL,		/* select */
+	NULL,		/* poll */
 	NULL,		/* ioctl */
 	NULL,		/* mmap */
 	blkdev_open,	/* open */
@@ -306,7 +306,7 @@
 	NULL,		/* read */
 	NULL,		/* write */
 	NULL,		/* readdir */
-	NULL,		/* select */
+	NULL,		/* poll */
 	NULL,		/* ioctl */
 	NULL,		/* mmap */
 	chrdev_open,	/* open */
diff -u --recursive --new-file v2.1.22/linux/fs/dquot.c linux/fs/dquot.c
--- v2.1.22/linux/fs/dquot.c	Thu Jan 23 21:06:49 1997
+++ linux/fs/dquot.c	Sun Jan 26 12:07:30 1997
@@ -13,7 +13,7 @@
  * diskquota system. This implementation is not based on any BSD
  * kernel sourcecode.
  * 
- * Version: $Id: dquot.c,v 5.6 1995/11/15 20:30:27 mvw Exp mvw $
+ * Version: $Id: dquot.c,v 1.11 1997/01/06 06:53:02 davem Exp $
  * 
  * Author:  Marco van Wieringen <mvw@mcs.ow.nl> <mvw@tnix.net>
  * 
@@ -35,6 +35,8 @@
 #include <linux/tty.h>
 #include <linux/malloc.h>
 #include <linux/mount.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 
@@ -662,7 +664,7 @@
 	dqstats.allocated_dquots = nr_dquots;
 	dqstats.free_dquots = nr_free_dquots;
 	return copy_to_user(addr, (caddr_t)&dqstats, sizeof(struct dqstats)) 
-			? -EFAULT : 0; 
+		? -EFAULT : 0; 
 }
 
 /*
@@ -1005,12 +1007,15 @@
 	int cmds = 0, type = 0, flags = 0;
 	struct inode *ino;
 	kdev_t dev;
+	int ret = -EINVAL;
 
+	lock_kernel();
 	cmds = cmd >> SUBCMDSHIFT;
 	type = cmd & SUBCMDMASK;
 
 	if ((u_int) type >= MAXQUOTAS)
-		return(-EINVAL);
+		goto out;
+	ret = -EPERM;
 	switch (cmds) {
 		case Q_SYNC:
 		case Q_GETSTATS:
@@ -1018,33 +1023,39 @@
 		case Q_GETQUOTA:
 			if (((type == USRQUOTA && current->uid != id) ||
 			     (type == GRPQUOTA && current->gid != id)) && !fsuser())
-				return(-EPERM);
+				goto out;
 			break;
 		default:
 			if (!fsuser())
-				return(-EPERM);
+				goto out;
 	}
 
+	ret = -EINVAL;
 	if (special == (char *)NULL && (cmds == Q_SYNC || cmds == Q_GETSTATS))
 		dev = 0;
 	else {
 		if (namei(special, &ino))
-			return(-EINVAL);
+			goto out;
 		dev = ino->i_rdev;
+		ret = -ENOTBLK;
 		if (!S_ISBLK(ino->i_mode)) {
 			iput(ino);
-			return(-ENOTBLK);
+			goto out;
 		}
 		iput(ino);
 	}
 
+	ret = -EINVAL;
 	switch (cmds) {
 		case Q_QUOTAON:
-			return(quota_on(dev, type, (char *) addr));
+			ret = quota_on(dev, type, (char *) addr);
+			goto out;
 		case Q_QUOTAOFF:
-			return(quota_off(dev, type));
+			ret = quota_off(dev, type);
+			goto out;
 		case Q_GETQUOTA:
-			return(get_quota(dev, id, type, (struct dqblk *) addr));
+			ret = get_quota(dev, id, type, (struct dqblk *) addr);
+			goto out;
 		case Q_SETQUOTA:
 			flags |= SET_QUOTA;
 			break;
@@ -1055,15 +1066,20 @@
 			flags |= SET_QLIMIT;
 			break;
 		case Q_SYNC:
-			return(sync_dquots(dev, type));
+			ret = sync_dquots(dev, type);
+			goto out;
 		case Q_GETSTATS:
-			return(get_stats(addr));
+			ret = get_stats(addr);
 		default:
-			return(-EINVAL);
+			goto out;
 	}
 
 	flags |= QUOTA_SYSCALL;
 	if (has_quota_enabled(dev, type))
-		return(set_dqblk(dev, id, type, flags, (struct dqblk *) addr));
-	return(-ESRCH);
+		ret = set_dqblk(dev, id, type, flags, (struct dqblk *) addr);
+	else
+		ret = -ESRCH;
+out:
+	unlock_kernel();
+	return ret;
 }
diff -u --recursive --new-file v2.1.22/linux/fs/exec.c linux/fs/exec.c
--- v2.1.22/linux/fs/exec.c	Thu Jan  2 15:55:22 1997
+++ linux/fs/exec.c	Sun Jan 26 12:10:10 1997
@@ -26,6 +26,7 @@
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
+#include <linux/slab.h>
 #include <linux/mman.h>
 #include <linux/a.out.h>
 #include <linux/errno.h>
@@ -38,6 +39,8 @@
 #include <linux/malloc.h>
 #include <linux/binfmts.h>
 #include <linux/personality.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -158,9 +161,11 @@
 	struct file * file;
 	struct linux_binfmt * fmt;
 
+	lock_kernel();
 	fd = sys_open(library, 0, 0);
+	retval = fd;
 	if (fd < 0)
-		return fd;
+		goto out;
 	file = current->files->fd[fd];
 	retval = -ENOEXEC;
 	if (file && file->f_inode && file->f_op && file->f_op->read) {
@@ -174,6 +179,8 @@
 		}
 	}
 	sys_close(fd);
+out:
+	unlock_kernel();
   	return retval;
 }
 
@@ -286,7 +293,7 @@
 		bprm->loader += stack_base;
 	bprm->exec += stack_base;
 
-	mpnt = (struct vm_area_struct *)kmalloc(sizeof(*mpnt), GFP_KERNEL);
+	mpnt = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
 	if (mpnt) {
 		mpnt->vm_mm = current->mm;
 		mpnt->vm_start = PAGE_MASK & (unsigned long) p;
@@ -607,7 +614,7 @@
 			    printable(bprm->buf[2]) &&
 			    printable(bprm->buf[3]))
 				break; /* -ENOEXEC */
-			sprintf(modname, "binfmt-%hd", *(short*)(&bprm->buf));
+			sprintf(modname, "binfmt-%04x", *(unsigned short *)(&bprm->buf[2]));
 			request_module(modname);
 #endif
 		}
diff -u --recursive --new-file v2.1.22/linux/fs/ext2/dir.c linux/fs/ext2/dir.c
--- v2.1.22/linux/fs/ext2/dir.c	Wed Dec 18 15:58:51 1996
+++ linux/fs/ext2/dir.c	Sun Jan 26 12:07:43 1997
@@ -39,7 +39,7 @@
 	ext2_dir_read,		/* read */
 	NULL,			/* write - bad */
 	ext2_readdir,		/* readdir */
-	NULL,			/* select - default */
+	NULL,			/* poll - default */
 	ext2_ioctl,		/* ioctl */
 	NULL,			/* mmap */
 	NULL,			/* no special open code */
diff -u --recursive --new-file v2.1.22/linux/fs/ext2/file.c linux/fs/ext2/file.c
--- v2.1.22/linux/fs/ext2/file.c	Thu Dec 12 19:37:17 1996
+++ linux/fs/ext2/file.c	Sun Jan 26 12:07:43 1997
@@ -49,7 +49,7 @@
 	generic_file_read,	/* read */
 	ext2_file_write,	/* write */
 	NULL,			/* readdir - bad */
-	NULL,			/* select - default */
+	NULL,			/* poll - default */
 	ext2_ioctl,		/* ioctl */
 	generic_file_mmap,	/* mmap */
 	NULL,			/* no special open is needed */
diff -u --recursive --new-file v2.1.22/linux/fs/ext2/symlink.c linux/fs/ext2/symlink.c
--- v2.1.22/linux/fs/ext2/symlink.c	Thu Jan 23 21:06:49 1997
+++ linux/fs/ext2/symlink.c	Sat Jan 25 13:02:44 1997
@@ -122,12 +122,11 @@
 	}
 	else
 		link = (char *) inode->u.ext2_i.i_data;
-	
-	/* XXX I hope link is always '\0'-terminated. */ 	
-	i = strlen(link);
-	if (i >= buflen)
-		i = buflen-1;
-	if (copy_to_user(buffer, link, i+1))
+
+	i = 0;
+	while (i < buflen && link[i])
+		i++;
+	if (copy_to_user(buffer, link, i))
 		i = -EFAULT;
  	if (DO_UPDATE_ATIME(inode)) {
 		inode->i_atime = CURRENT_TIME;
diff -u --recursive --new-file v2.1.22/linux/fs/fat/dir.c linux/fs/fat/dir.c
--- v2.1.22/linux/fs/fat/dir.c	Tue Oct 29 19:58:42 1996
+++ linux/fs/fat/dir.c	Sun Jan 26 12:07:43 1997
@@ -40,7 +40,7 @@
 	fat_dir_read,		/* read */
 	NULL,			/* write - bad */
 	fat_readdir,		/* readdir */
-	NULL,			/* select - default */
+	NULL,			/* poll - default */
 	fat_dir_ioctl,		/* ioctl - default */
 	NULL,			/* mmap */
 	NULL,			/* no special open code */
diff -u --recursive --new-file v2.1.22/linux/fs/fat/file.c linux/fs/fat/file.c
--- v2.1.22/linux/fs/fat/file.c	Tue Oct 29 19:58:42 1996
+++ linux/fs/fat/file.c	Sun Jan 26 12:07:44 1997
@@ -32,7 +32,7 @@
 	fat_file_read,		/* read */
 	fat_file_write,		/* write */
 	NULL,			/* readdir - bad */
-	NULL,			/* select - default */
+	NULL,			/* poll - default */
 	NULL,			/* ioctl - default */
 	generic_file_mmap,	/* mmap */
 	NULL,			/* no special open is needed */
@@ -71,7 +71,7 @@
 	fat_file_read,		/* read */
 	fat_file_write,		/* write */
 	NULL,			/* readdir - bad */
-	NULL,			/* select - default */
+	NULL,			/* poll - default */
 	NULL,			/* ioctl - default */
 	fat_mmap,		/* mmap */
 	NULL,			/* no special open is needed */
diff -u --recursive --new-file v2.1.22/linux/fs/fcntl.c linux/fs/fcntl.c
--- v2.1.22/linux/fs/fcntl.c	Sun Dec 22 16:37:38 1996
+++ linux/fs/fcntl.c	Sun Jan 26 12:07:44 1997
@@ -10,6 +10,9 @@
 #include <linux/stat.h>
 #include <linux/fcntl.h>
 #include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/bitops.h>
 #include <asm/uaccess.h>
@@ -35,20 +38,33 @@
 
 asmlinkage int sys_dup2(unsigned int oldfd, unsigned int newfd)
 {
+	int err = -EBADF;
+
+	lock_kernel();
 	if (oldfd >= NR_OPEN || !current->files->fd[oldfd])
-		return -EBADF;
+		goto out;
+	err = newfd;
 	if (newfd == oldfd)
-		return newfd;
+		goto out;
+	err = -EBADF;
 	if (newfd >= NR_OPEN)
-		return -EBADF;	/* following POSIX.1 6.2.1 */
+		goto out;	/* following POSIX.1 6.2.1 */
 
 	sys_close(newfd);
-	return dupfd(oldfd,newfd);
+	err = dupfd(oldfd,newfd);
+out:
+	unlock_kernel();
+	return err;
 }
 
 asmlinkage int sys_dup(unsigned int fildes)
 {
-	return dupfd(fildes,0);
+	int ret;
+
+	lock_kernel();
+	ret = dupfd(fildes,0);
+	unlock_kernel();
+	return ret;
 }
 
 asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
@@ -56,29 +72,37 @@
 	struct file * filp;
 	struct task_struct *p;
 	int task_found = 0;
+	long err = -EBADF;
 
+	lock_kernel();
 	if (fd >= NR_OPEN || !(filp = current->files->fd[fd]))
-		return -EBADF;
+		goto out;
+	err = 0;
 	switch (cmd) {
 		case F_DUPFD:
-			return dupfd(fd,arg);
+			err = dupfd(fd,arg);
+			break;
 		case F_GETFD:
-			return FD_ISSET(fd, &current->files->close_on_exec);
+			err = FD_ISSET(fd, &current->files->close_on_exec);
+			break;
 		case F_SETFD:
 			if (arg&1)
 				FD_SET(fd, &current->files->close_on_exec);
 			else
 				FD_CLR(fd, &current->files->close_on_exec);
-			return 0;
+			break;
 		case F_GETFL:
-			return filp->f_flags;
+			err = filp->f_flags;
+			break;
 		case F_SETFL:
 			/*
 			 * In the case of an append-only file, O_APPEND
 			 * cannot be cleared
 			 */
+			err = -EPERM;
 			if (IS_APPEND(filp->f_inode) && !(arg & O_APPEND))
-				return -EPERM;
+				break;
+			err = 0;
 			if ((arg & FASYNC) && !(filp->f_flags & FASYNC) &&
 			    filp->f_op->fasync)
 				filp->f_op->fasync(filp->f_inode, filp, 1);
@@ -93,13 +117,16 @@
 					   O_NDELAY | FASYNC);
 			filp->f_flags |= arg & (O_APPEND | O_NONBLOCK |
 						O_NDELAY | FASYNC);
-			return 0;
+			break;
 		case F_GETLK:
-			return fcntl_getlk(fd, (struct flock *) arg);
+			err = fcntl_getlk(fd, (struct flock *) arg);
+			break;
 		case F_SETLK:
-			return fcntl_setlk(fd, cmd, (struct flock *) arg);
+			err = fcntl_setlk(fd, cmd, (struct flock *) arg);
+			break;
 		case F_SETLKW:
-			return fcntl_setlk(fd, cmd, (struct flock *) arg);
+			err = fcntl_setlk(fd, cmd, (struct flock *) arg);
+			break;
 		case F_GETOWN:
 			/*
 			 * XXX If f_owner is a process group, the
@@ -108,7 +135,8 @@
 			 * current syscall conventions, the only way
 			 * to fix this will be in libc.
 			 */
-			return filp->f_owner;
+			err = filp->f_owner;
+			break;
 		case F_SETOWN:
 			/*
 			 *	Add the security checks - AC. Without
@@ -139,29 +167,35 @@
 				if ((p->pid == arg) || (p->pid == -arg) || 
 				    (p->pgrp == -arg)) {
 					task_found++;
+					err = -EPERM;
 					if ((p->session != current->session) &&
 					    (p->uid != current->uid) &&
 					    (p->euid != current->euid) &&
 					    !suser())
-						return -EPERM;
+						goto out;
 					break;
 				}
 			}
+			err = -EINVAL;
 			if ((task_found == 0) && !suser())
-				return -EINVAL;
+				break;
 		fasync_ok:
+			err = 0;
 			filp->f_owner = arg;
 			if (S_ISSOCK (filp->f_inode->i_mode))
-				sock_fcntl (filp, F_SETOWN, arg);
-			return 0;
+				err = sock_fcntl (filp, F_SETOWN, arg);
+			break;
 		default:
 			/* sockets need a few special fcntls. */
 			if (S_ISSOCK (filp->f_inode->i_mode))
-			  {
-			     return (sock_fcntl (filp, cmd, arg));
-			  }
-			return -EINVAL;
+				err = sock_fcntl (filp, cmd, arg);
+			else
+				err = -EINVAL;
+			break;
 	}
+out:
+	unlock_kernel();
+	return err;
 }
 
 void kill_fasync(struct fasync_struct *fa, int sig)
diff -u --recursive --new-file v2.1.22/linux/fs/filesystems.c linux/fs/filesystems.c
--- v2.1.22/linux/fs/filesystems.c	Wed Jan 15 19:45:43 1997
+++ linux/fs/filesystems.c	Sun Jan 26 12:07:44 1997
@@ -24,17 +24,22 @@
 #include <linux/ufs_fs.h>
 #include <linux/romfs_fs.h>
 #include <linux/major.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 extern void device_setup(void);
 extern void binfmt_setup(void);
+extern void free_initmem(void);
 
 /* This may be used only once, enforced by 'static int callable' */
 asmlinkage int sys_setup(void)
 {
 	static int callable = 1;
+	int err = -1;
 
+	lock_kernel();
 	if (!callable)
-		return -1;
+		goto out;
 	callable = 0;
 
 	device_setup();
@@ -106,6 +111,12 @@
 #endif
 
 	mount_root();
-	return 0;
+	
+	free_initmem();
+	
+	err = 0;
+out:
+	unlock_kernel();
+	return err;
 }
 
diff -u --recursive --new-file v2.1.22/linux/fs/hpfs/hpfs_fs.c linux/fs/hpfs/hpfs_fs.c
--- v2.1.22/linux/fs/hpfs/hpfs_fs.c	Mon Dec 30 15:39:13 1996
+++ linux/fs/hpfs/hpfs_fs.c	Sun Jan 26 12:07:44 1997
@@ -153,7 +153,7 @@
 	hpfs_file_read,			/* read */
 	NULL,				/* write */
 	NULL,				/* readdir - bad */
-	NULL,				/* select - default */
+	NULL,				/* poll - default */
 	NULL,				/* ioctl - default */
 	generic_file_mmap,		/* mmap */
 	NULL,				/* no special open is needed */
@@ -197,7 +197,7 @@
 	hpfs_dir_read,			/* read */
 	NULL,				/* write - bad */
 	hpfs_readdir,			/* readdir */
-	NULL,				/* select - default */
+	NULL,				/* poll - default */
 	NULL,				/* ioctl - default */
 	NULL,				/* mmap */
 	NULL,				/* no special open code */
diff -u --recursive --new-file v2.1.22/linux/fs/ioctl.c linux/fs/ioctl.c
--- v2.1.22/linux/fs/ioctl.c	Sun Dec 22 16:37:38 1996
+++ linux/fs/ioctl.c	Sun Jan 26 12:07:44 1997
@@ -10,6 +10,8 @@
 #include <linux/string.h>
 #include <linux/stat.h>
 #include <linux/termios.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 #include <linux/fcntl.h> /* for f_flags values */
 
 #include <asm/uaccess.h>
@@ -48,22 +50,24 @@
 {	
 	struct file * filp;
 	unsigned int flag;
-	int on, error;
+	int on, error = -EBADF;
 
+	lock_kernel();
 	if (fd >= NR_OPEN || !(filp = current->files->fd[fd]))
-		return -EBADF;
+		goto out;
+	error = 0;
 	switch (cmd) {
 		case FIOCLEX:
 			FD_SET(fd, &current->files->close_on_exec);
-			return 0;
+			break;
 
 		case FIONCLEX:
 			FD_CLR(fd, &current->files->close_on_exec);
-			return 0;
+			break;
 
 		case FIONBIO:
 			if ((error = get_user(on, (int *)arg)) != 0)
-				return error;
+				break;
 			flag = O_NONBLOCK;
 #ifdef __sparc__
 			/* SunOS compatability item. */
@@ -74,25 +78,27 @@
 				filp->f_flags |= flag;
 			else
 				filp->f_flags &= ~flag;
-			return 0;
+			break;
 
 		case FIOASYNC: /* O_SYNC is not yet implemented,
 				  but it's here for completeness. */
 			if ((error = get_user(on, (int *)arg)) != 0)
-				return error;
+				break;
 			if (on)
 				filp->f_flags |= O_SYNC;
 			else
 				filp->f_flags &= ~O_SYNC;
-			return 0;
+			break;
 
 		default:
 			if (filp->f_inode && S_ISREG(filp->f_inode->i_mode))
-				return file_ioctl(filp, cmd, arg);
-
-			if (filp->f_op && filp->f_op->ioctl)
-				return filp->f_op->ioctl(filp->f_inode, filp, cmd, arg);
-
-			return -ENOTTY;
+				error = file_ioctl(filp, cmd, arg);
+			else if (filp->f_op && filp->f_op->ioctl)
+				error = filp->f_op->ioctl(filp->f_inode, filp, cmd, arg);
+			else
+				error = -ENOTTY;
 	}
+out:
+	unlock_kernel();
+	return error;
 }
diff -u --recursive --new-file v2.1.22/linux/fs/isofs/dir.c linux/fs/isofs/dir.c
--- v2.1.22/linux/fs/isofs/dir.c	Tue Oct 29 19:58:42 1996
+++ linux/fs/isofs/dir.c	Sun Jan 26 12:07:44 1997
@@ -31,7 +31,7 @@
 	NULL,			/* read */
 	NULL,			/* write - bad */
 	isofs_readdir,		/* readdir */
-	NULL,			/* select - default */
+	NULL,			/* poll - default */
 	NULL,			/* ioctl - default */
 	NULL,			/* no special open code */
 	NULL,			/* no special release code */
diff -u --recursive --new-file v2.1.22/linux/fs/isofs/file.c linux/fs/isofs/file.c
--- v2.1.22/linux/fs/isofs/file.c	Tue Feb 20 10:28:13 1996
+++ linux/fs/isofs/file.c	Sun Jan 26 12:07:44 1997
@@ -27,7 +27,7 @@
 	generic_file_read,	/* read */
 	NULL,			/* write */
 	NULL,			/* readdir - bad */
-	NULL,			/* select - default */
+	NULL,			/* poll - default */
 	NULL,			/* ioctl - default */
 	generic_file_mmap,	/* mmap */
 	NULL,			/* no special open is needed */
diff -u --recursive --new-file v2.1.22/linux/fs/locks.c linux/fs/locks.c
--- v2.1.22/linux/fs/locks.c	Thu Jan  2 15:55:23 1997
+++ linux/fs/locks.c	Sun Jan 26 12:07:44 1997
@@ -105,6 +105,8 @@
 #include <linux/errno.h>
 #include <linux/stat.h>
 #include <linux/fcntl.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 
@@ -240,17 +242,20 @@
 {
 	struct file_lock file_lock;
 	struct file *filp;
+	int err;
 
+	lock_kernel();
 	if ((fd >= NR_OPEN) || !(filp = current->files->fd[fd]))
-		return (-EBADF);
-
-	if (!flock_make_lock(filp, &file_lock, cmd))
-		return (-EINVAL);
-	
-	if ((file_lock.fl_type != F_UNLCK) && !(filp->f_mode & 3))
-		return (-EBADF);
-
-	return (flock_lock_file(filp, &file_lock, (cmd & (LOCK_UN | LOCK_NB)) ? 0 : 1));
+		err = -EBADF;
+	else if (!flock_make_lock(filp, &file_lock, cmd))
+		err = -EINVAL;
+	else if ((file_lock.fl_type != F_UNLCK) && !(filp->f_mode & 3))
+		err = -EBADF;
+	else
+		err = flock_lock_file(filp, &file_lock,
+				      (cmd & (LOCK_UN | LOCK_NB)) ? 0 : 1);
+	unlock_kernel();
+	return err;
 }
 
 /* Report the first existing lock that would conflict with l.
@@ -342,11 +347,23 @@
 		break;
 	case F_SHLCK:
 	case F_EXLCK:
+#ifdef __sparc__
+/* warn a bit for now, but don't overdo it */
+{
+	static int count = 0;
+	if (!count) {
+		count=1;
 		printk(KERN_WARNING
-		       "fcntl_setlk(): process %d (%s) requested broken flock() emulation\n",
+		       "fcntl_setlk() called by process %d (%s) with broken flock() emulation\n",
 		       current->pid, current->comm);
+	}
+}
+		if (!(filp->f_mode & 3))
+			return (-EBADF);
+		break;
+#endif
 	default:
-		return (-EINVAL);
+		return -EINVAL;
 	}
 	
 	return (posix_lock_file(filp, &file_lock, cmd == F_SETLKW));
diff -u --recursive --new-file v2.1.22/linux/fs/minix/dir.c linux/fs/minix/dir.c
--- v2.1.22/linux/fs/minix/dir.c	Tue Oct 29 19:58:43 1996
+++ linux/fs/minix/dir.c	Sun Jan 26 12:07:44 1997
@@ -27,7 +27,7 @@
 	minix_dir_read,		/* read */
 	NULL,			/* write - bad */
 	minix_readdir,		/* readdir */
-	NULL,			/* select - default */
+	NULL,			/* poll - default */
 	NULL,			/* ioctl - default */
 	NULL,			/* mmap */
 	NULL,			/* no special open code */
diff -u --recursive --new-file v2.1.22/linux/fs/minix/file.c linux/fs/minix/file.c
--- v2.1.22/linux/fs/minix/file.c	Tue Oct 29 19:58:43 1996
+++ linux/fs/minix/file.c	Sun Jan 26 12:07:44 1997
@@ -38,7 +38,7 @@
 	generic_file_read,	/* read */
 	minix_file_write,	/* write */
 	NULL,			/* readdir - bad */
-	NULL,			/* select - default */
+	NULL,			/* poll - default */
 	NULL,			/* ioctl - default */
 	generic_file_mmap,	/* mmap */
 	NULL,			/* no special open is needed */
diff -u --recursive --new-file v2.1.22/linux/fs/namei.c linux/fs/namei.c
--- v2.1.22/linux/fs/namei.c	Thu Jan 23 21:06:49 1997
+++ linux/fs/namei.c	Sun Jan 26 12:07:44 1997
@@ -15,12 +15,16 @@
 #include <linux/fcntl.h>
 #include <linux/stat.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 #include <asm/unaligned.h>
+#include <asm/namei.h>
 
 #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
 
+
 /*
  * In order to reduce some races, while at the same time doing additional
  * checking and hopefully speeding things up, we copy filenames to the
@@ -265,6 +269,7 @@
 	int namelen,error;
 	struct inode * inode;
 
+	translate_namei(pathname, base, follow_links, res_inode);
 	*res_inode = NULL;
 	error = dir_namei(pathname, &namelen, &basename, base, &base);
 	if (error)
@@ -331,13 +336,15 @@
  * which is a lot more logical, and also allows the "no perm" needed
  * for symlinks (where the permissions are checked later).
  */
-int open_namei(const char * pathname, int flag, int mode,
+int
+open_namei(const char * pathname, int flag, int mode,
                struct inode ** res_inode, struct inode * base)
 {
 	const char * basename;
 	int namelen,error;
 	struct inode * dir, *inode;
 
+	translate_open_namei(pathname, flag, mode, res_inode, base);
 	mode &= S_IALLUGO & ~current->fs->umask;
 	mode |= S_IFREG;
 	error = dir_namei(pathname, &namelen, &basename, base, &dir);
@@ -499,8 +506,11 @@
 	int error;
 	char * tmp;
 
+	lock_kernel();
+	error = -EPERM;
 	if (S_ISDIR(mode) || (!S_ISFIFO(mode) && !fsuser()))
-		return -EPERM;
+		goto out;
+	error = -EINVAL;
 	switch (mode & S_IFMT) {
 	case 0:
 		mode |= S_IFREG;
@@ -508,13 +518,15 @@
 	case S_IFREG: case S_IFCHR: case S_IFBLK: case S_IFIFO: case S_IFSOCK:
 		break;
 	default:
-		return -EINVAL;
+		goto out;
 	}
 	error = getname(filename,&tmp);
 	if (!error) {
 		error = do_mknod(tmp,mode,dev);
 		putname(tmp);
 	}
+out:
+	unlock_kernel();
 	return error;
 }
 
@@ -595,12 +607,14 @@
 	int error;
 	char * tmp;
 
+	lock_kernel();
 	error = getname(pathname,&tmp);
 	if (!error) {
 		remove_trailing_slashes(tmp);
 		error = do_mkdir(tmp,mode);
 		putname(tmp);
 	}
+	unlock_kernel();
 	return error;
 }
 
@@ -646,12 +660,14 @@
 	int error;
 	char * tmp;
 
+	lock_kernel();
 	error = getname(pathname,&tmp);
 	if (!error) {
 		remove_trailing_slashes(tmp);
 		error = do_rmdir(tmp);
 		putname(tmp);
 	}
+	unlock_kernel();
 	return error;
 }
 
@@ -697,11 +713,13 @@
 	int error;
 	char * tmp;
 
+	lock_kernel();
 	error = getname(pathname,&tmp);
 	if (!error) {
 		error = do_unlink(tmp);
 		putname(tmp);
 	}
+	unlock_kernel();
 	return error;
 }
 
@@ -745,6 +763,7 @@
 	int error;
 	char * from, * to;
 
+	lock_kernel();
 	error = getname(oldname,&from);
 	if (!error) {
 		error = getname(newname,&to);
@@ -754,6 +773,7 @@
 		}
 		putname(from);
 	}
+	unlock_kernel();
 	return error;
 }
 
@@ -817,16 +837,19 @@
 	char * to;
 	struct inode * oldinode;
 
+	lock_kernel();
 	error = lnamei(oldname, &oldinode);
 	if (error)
-		return error;
+		goto out;
 	error = getname(newname,&to);
 	if (error) {
 		iput(oldinode);
-		return error;
+		goto out;
 	}
 	error = do_link(oldinode,to);
 	putname(to);
+out:
+	unlock_kernel();
 	return error;
 }
 
@@ -905,6 +928,7 @@
 	int error;
 	char * from, * to;
 
+	lock_kernel();
 	error = getname(oldname,&from);
 	if (!error) {
 		error = getname(newname,&to);
@@ -916,5 +940,6 @@
 		}
 		putname(from);
 	}
+	unlock_kernel();
 	return error;
 }
diff -u --recursive --new-file v2.1.22/linux/fs/ncpfs/dir.c linux/fs/ncpfs/dir.c
--- v2.1.22/linux/fs/ncpfs/dir.c	Tue Dec 31 21:41:07 1996
+++ linux/fs/ncpfs/dir.c	Sun Jan 26 12:07:44 1997
@@ -115,7 +115,7 @@
 	ncp_dir_read,		/* read - bad */
 	NULL,			/* write - bad */
 	ncp_readdir,		/* readdir */
-	NULL,			/* select - default */
+	NULL,			/* poll - default */
 	ncp_ioctl,		/* ioctl */
 	NULL,			/* mmap */
 	NULL,			/* no special open code */
diff -u --recursive --new-file v2.1.22/linux/fs/ncpfs/file.c linux/fs/ncpfs/file.c
--- v2.1.22/linux/fs/ncpfs/file.c	Tue Oct 29 19:58:43 1996
+++ linux/fs/ncpfs/file.c	Sun Jan 26 12:07:44 1997
@@ -255,7 +255,7 @@
 	ncp_file_read,		/* read */
 	ncp_file_write,		/* write */
 	NULL,			/* readdir - bad */
-	NULL,			/* select - default */
+	NULL,			/* poll - default */
 	ncp_ioctl,		/* ioctl */
 	ncp_mmap,		/* mmap */
 	NULL,                   /* open */
diff -u --recursive --new-file v2.1.22/linux/fs/ncpfs/sock.c linux/fs/ncpfs/sock.c
--- v2.1.22/linux/fs/ncpfs/sock.c	Thu Dec 12 19:37:17 1996
+++ linux/fs/ncpfs/sock.c	Sun Jan 26 12:07:44 1997
@@ -341,9 +341,9 @@
 	unsigned short fs;
 	int result;
 	char *start = server->packet;
-	select_table wait_table;
-	struct select_table_entry entry;
-	int (*select) (struct inode *, struct file *, int, select_table *);
+	poll_table wait_table;
+	struct poll_table_entry entry;
+	int (*select) (struct inode *, poll_table *);
 	int init_timeout, max_timeout;
 	int timeout;
 	int retrans;
@@ -362,7 +362,7 @@
 
 	file = server->ncp_filp;
 	inode = file->f_inode;
-	select = file->f_op->select;
+	select = file->f_op->poll;
 	sock = &inode->u.socket_i;
 	if (!sock)
 	{
@@ -418,8 +418,7 @@
 		wait_table.nr = 0;
 		wait_table.entry = &entry;
 		current->state = TASK_INTERRUPTIBLE;
-		if (   !select(inode, file, SEL_IN, &wait_table)
-		    && !select(inode, file, SEL_IN, NULL))
+		if (!select(inode, &wait_table))
 		{
 			if (timeout > max_timeout)
 			{
diff -u --recursive --new-file v2.1.22/linux/fs/nfs/dir.c linux/fs/nfs/dir.c
--- v2.1.22/linux/fs/nfs/dir.c	Tue Oct 29 19:58:43 1996
+++ linux/fs/nfs/dir.c	Sun Jan 26 12:07:44 1997
@@ -39,7 +39,7 @@
 	nfs_dir_read,		/* read - bad */
 	NULL,			/* write - bad */
 	nfs_readdir,		/* readdir */
-	NULL,			/* select - default */
+	NULL,			/* poll - default */
 	NULL,			/* ioctl - default */
 	NULL,			/* mmap */
 	nfs_dir_open,		/* open - revalidate */
diff -u --recursive --new-file v2.1.22/linux/fs/nfs/file.c linux/fs/nfs/file.c
--- v2.1.22/linux/fs/nfs/file.c	Tue Oct 29 19:58:44 1996
+++ linux/fs/nfs/file.c	Sun Jan 26 12:07:44 1997
@@ -39,7 +39,7 @@
 	nfs_file_read,		/* read */
 	nfs_file_write,		/* write */
 	NULL,			/* readdir - bad */
-	NULL,			/* select - default */
+	NULL,			/* poll - default */
 	NULL,			/* ioctl - default */
 	nfs_file_mmap,		/* mmap */
 	NULL,			/* no special open is needed */
diff -u --recursive --new-file v2.1.22/linux/fs/nfs/inode.c linux/fs/nfs/inode.c
--- v2.1.22/linux/fs/nfs/inode.c	Wed Jan 15 19:45:43 1997
+++ linux/fs/nfs/inode.c	Sun Jan 26 12:07:44 1997
@@ -335,11 +335,7 @@
 {
 	int	ret;
 
-#ifdef __SMP__
 	lock_kernel();
-	syscall_count++;
-#endif
-
 	MOD_INC_USE_COUNT;
 	exit_mm(current);
 	current->session = 1;
@@ -347,6 +343,7 @@
 	sprintf(current->comm, "nfsiod");
 	ret = nfsiod();
 	MOD_DEC_USE_COUNT;
+	unlock_kernel();
 	return ret;
 }
 
diff -u --recursive --new-file v2.1.22/linux/fs/nfs/nfsroot.c linux/fs/nfs/nfsroot.c
--- v2.1.22/linux/fs/nfs/nfsroot.c	Thu Jan 23 21:06:49 1997
+++ linux/fs/nfs/nfsroot.c	Sun Jan 26 12:07:44 1997
@@ -172,7 +172,10 @@
 
 	last = &open_base;
 	for (dev = dev_base; dev != NULL; dev = dev->next) {
-		if (dev->type < ARPHRD_SLIP &&
+		if (
+#if !CONFIG_AP1000
+		    dev->type < ARPHRD_SLIP &&
+#endif
 		    dev->family == AF_INET &&
 		    !(dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) &&
 		    (0 != strncmp(dev->name, "dummy", 5)) &&
@@ -1289,6 +1292,9 @@
 		num++;
 	}
 	rarp_serv = server;
+#if CONFIG_AP1000
+	ap_nfs_hook(server.sin_addr.s_addr);
+#endif				
 }
 
 static int root_nfs_add_default_route(struct in_addr gw, struct device *dev)
diff -u --recursive --new-file v2.1.22/linux/fs/nfs/rpcsock.c linux/fs/nfs/rpcsock.c
--- v2.1.22/linux/fs/nfs/rpcsock.c	Thu Jan 23 21:06:51 1997
+++ linux/fs/nfs/rpcsock.c	Sat Jan 25 23:46:13 1997
@@ -40,6 +40,7 @@
 #include <linux/net.h>
 #include <linux/mm.h>
 #include <linux/rpcsock.h>
+#include <linux/poll.h>
 
 #include <linux/udp.h>
 #include <net/sock.h>
@@ -159,21 +160,20 @@
 
 /*
  * This code is slightly complicated. Since the networking code does not
- * honor the current->timeout value, we have to select on the socket.
+ * honor the current->timeout value, we have to poll on the socket.
  */
 static inline int
 rpc_select(struct rpc_sock *rsock)
 {
-	struct select_table_entry entry;
+	struct poll_table_entry entry;
 	struct file	*file = rsock->file;
-	select_table	wait_table;
+	poll_table	wait_table;
 
-	dprintk("RPC: selecting on socket...\n");
+	dprintk("RPC: polling socket...\n");
 	wait_table.nr = 0;
 	wait_table.entry = &entry;
 	current->state = TASK_INTERRUPTIBLE;
-	if (!file->f_op->select(file->f_inode, file, SEL_IN, &wait_table)
-	 && !file->f_op->select(file->f_inode, file, SEL_IN, NULL)) {
+	if (!(file->f_op->poll(file, &wait_table) & POLLIN)) {
 		schedule();
 		remove_wait_queue(entry.wait_address, &entry.wait);
 		current->state = TASK_RUNNING;
diff -u --recursive --new-file v2.1.22/linux/fs/open.c linux/fs/open.c
--- v2.1.22/linux/fs/open.c	Thu Jan  2 15:55:23 1997
+++ linux/fs/open.c	Sun Jan 26 12:07:44 1997
@@ -18,6 +18,8 @@
 #include <linux/time.h>
 #include <linux/mm.h>
 #include <linux/file.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 #include <asm/bitops.h>
@@ -27,19 +29,24 @@
 	struct inode * inode;
 	int error;
 
+	lock_kernel();
 	error = verify_area(VERIFY_WRITE, buf, sizeof(struct statfs));
 	if (error)
-		return error;
+		goto out;
 	error = namei(path,&inode);
 	if (error)
-		return error;
+		goto out;
+	error = -ENOSYS;
 	if (!inode->i_sb->s_op->statfs) {
 		iput(inode);
-		return -ENOSYS;
+		goto out;
 	}
 	inode->i_sb->s_op->statfs(inode->i_sb, buf, sizeof(struct statfs));
 	iput(inode);
-	return 0;
+	error = 0;
+out:
+	unlock_kernel();
+	return error;
 }
 
 asmlinkage int sys_fstatfs(unsigned int fd, struct statfs * buf)
@@ -48,19 +55,23 @@
 	struct file * file;
 	int error;
 
+	lock_kernel();
 	error = verify_area(VERIFY_WRITE, buf, sizeof(struct statfs));
 	if (error)
-		return error;
+		goto out;
 	if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
-		return -EBADF;
-	if (!(inode = file->f_inode))
-		return -ENOENT;
-	if (!inode->i_sb)
-	        return -ENODEV;
-	if (!inode->i_sb->s_op->statfs)
-		return -ENOSYS;
-	inode->i_sb->s_op->statfs(inode->i_sb, buf, sizeof(struct statfs));
-	return 0;
+		error = -EBADF;
+	else if (!(inode = file->f_inode))
+		error = -ENOENT;
+	else if (!inode->i_sb)
+		error = -ENODEV;
+	else if (!inode->i_sb->s_op->statfs)
+		error = -ENOSYS;
+	else
+		inode->i_sb->s_op->statfs(inode->i_sb, buf, sizeof(struct statfs));
+out:
+	unlock_kernel();
+	return error;
 }
 
 int do_truncate(struct inode *inode, unsigned long length)
@@ -87,29 +98,30 @@
 	struct inode * inode;
 	int error;
 
+	lock_kernel();
 	error = namei(path,&inode);
 	if (error)
-		return error;
+		goto out;
 
 	error = -EACCES;
 	if (S_ISDIR(inode->i_mode))
-		goto out;
+		goto iput_and_out;
 
 	error = permission(inode,MAY_WRITE);
 	if (error)
-		goto out;
+		goto iput_and_out;
 
 	error = -EROFS;
 	if (IS_RDONLY(inode))
-		goto out;
+		goto iput_and_out;
 
 	error = -EPERM;
 	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
-		goto out;
+		goto iput_and_out;
 
 	error = get_write_access(inode);
 	if (error)
-		goto out;
+		goto iput_and_out;
 
 	error = locks_verify_area(FLOCK_VERIFY_WRITE, inode, NULL,
 				  length < inode->i_size ? length : inode->i_size,
@@ -120,8 +132,10 @@
 		error = do_truncate(inode, length);
 	}
 	put_write_access(inode);
-out:
+iput_and_out:
 	iput(inode);
+out:
+	unlock_kernel();
 	return error;
 }
 
@@ -131,19 +145,23 @@
 	struct file * file;
 	int error;
 
+	lock_kernel();
 	if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
-		return -EBADF;
-	if (!(inode = file->f_inode))
-		return -ENOENT;
-	if (S_ISDIR(inode->i_mode) || !(file->f_mode & FMODE_WRITE))
-		return -EACCES;
-	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
-		return -EPERM;
-	error = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file,
-				  length < inode->i_size ? length : inode->i_size,
-				  abs(inode->i_size - length));
-	if (!error)
-		error = do_truncate(inode, length);
+		error = -EBADF;
+	else if (!(inode = file->f_inode))
+		error = -ENOENT;
+	else if (S_ISDIR(inode->i_mode) || !(file->f_mode & FMODE_WRITE))
+		error = -EACCES;
+	else if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+		error = -EPERM;
+	else {
+		error = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file,
+					  length<inode->i_size ? length : inode->i_size,
+					  abs(inode->i_size - length));
+		if (!error)
+			error = do_truncate(inode, length);
+	}
+	unlock_kernel();
 	return error;
 }
 
@@ -166,12 +184,14 @@
 	struct inode * inode;
 	struct iattr newattrs;
 
+	lock_kernel();
 	error = namei(filename,&inode);
 	if (error)
-		return error;
+		goto out;
+	error = -EROFS;
 	if (IS_RDONLY(inode)) {
 		iput(inode);
-		return -EROFS;
+		goto out;
 	}
 	/* Don't worry, the checks are done in inode_change_ok() */
 	newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
@@ -181,18 +201,20 @@
 			error = get_user(newattrs.ia_mtime, &times->modtime);
 		if (error) {
 			iput(inode);
-			return error;
+			goto out;
 		}
 		newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
 	} else {
 		if (current->fsuid != inode->i_uid &&
 		    (error = permission(inode,MAY_WRITE)) != 0) {
 			iput(inode);
-			return error;
+			goto out;
 		}
 	}
 	error = notify_change(inode, &newattrs);
 	iput(inode);
+out:
+	unlock_kernel();
 	return error;
 }
 
@@ -208,32 +230,32 @@
 	struct inode * inode;
 	struct iattr newattrs;
 
+	lock_kernel();
 	error = namei(filename,&inode);
 	if (error)
-		return error;
-	if (IS_RDONLY(inode)) {
-		iput(inode);
-		return -EROFS;
-	}
+		goto out;
+	error = -EROFS;
+	if (IS_RDONLY(inode))
+		goto iput_and_out;
 	/* Don't worry, the checks are done in inode_change_ok() */
 	newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
 	if (utimes) {
 		struct timeval times[2];
-		if (copy_from_user(&times, utimes, sizeof(times))) {
-			iput(inode);
-			return -EFAULT;
-		}		
+		error = -EFAULT;
+		if (copy_from_user(&times, utimes, sizeof(times)))
+			goto iput_and_out;
 		newattrs.ia_atime = times[0].tv_sec;
 		newattrs.ia_mtime = times[1].tv_sec;
 		newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
 	} else {
-		if ((error = permission(inode,MAY_WRITE)) != 0) {
-			iput(inode);
-			return error;
-		}
+		if ((error = permission(inode,MAY_WRITE)) != 0)
+			goto iput_and_out;
 	}
 	error = notify_change(inode, &newattrs);
+iput_and_out:
 	iput(inode);
+out:
+	unlock_kernel();
 	return error;
 }
 
@@ -245,10 +267,11 @@
 {
 	struct inode * inode;
 	int old_fsuid, old_fsgid;
-	int res;
+	int res = -EINVAL;
 
+	lock_kernel();
 	if (mode != (mode & S_IRWXO))	/* where's F_OK, X_OK, W_OK, R_OK? */
-		return -EINVAL;
+		goto out;
 	old_fsuid = current->fsuid;
 	old_fsgid = current->fsgid;
 	current->fsuid = current->uid;
@@ -260,6 +283,8 @@
 	}
 	current->fsuid = old_fsuid;
 	current->fsgid = old_fsgid;
+out:
+	unlock_kernel();
 	return res;
 }
 
@@ -268,40 +293,51 @@
 	struct inode * inode;
 	int error;
 
+	lock_kernel();
 	error = namei(filename,&inode);
 	if (error)
-		return error;
+		goto out;
+	error = -ENOTDIR;
 	if (!S_ISDIR(inode->i_mode)) {
 		iput(inode);
-		return -ENOTDIR;
+		goto out;
 	}
 	if ((error = permission(inode,MAY_EXEC)) != 0) {
 		iput(inode);
-		return error;
+		goto out;
 	}
 	iput(current->fs->pwd);
 	current->fs->pwd = inode;
-	return (0);
+	error = 0;
+out:
+	unlock_kernel();
+	return error;
 }
 
 asmlinkage int sys_fchdir(unsigned int fd)
 {
 	struct inode * inode;
 	struct file * file;
-	int error;
+	int error = -EBADF;
 
+	lock_kernel();
 	if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
-		return -EBADF;
+		goto out;
+	error = -ENOENT;
 	if (!(inode = file->f_inode))
-		return -ENOENT;
+		goto out;
+	error = -ENOTDIR;
 	if (!S_ISDIR(inode->i_mode))
-		return -ENOTDIR;
+		goto out;
 	if ((error = permission(inode,MAY_EXEC)) != 0)
-		return error;
+		goto out;
 	iput(current->fs->pwd);
 	current->fs->pwd = inode;
 	inode->i_count++;
-	return (0);
+	error = 0;
+out:
+	unlock_kernel();
+	return error;
 }
 
 asmlinkage int sys_chroot(const char * filename)
@@ -309,20 +345,26 @@
 	struct inode * inode;
 	int error;
 
+	lock_kernel();
 	error = namei(filename,&inode);
 	if (error)
-		return error;
+		goto out;
+	error = -ENOTDIR;
 	if (!S_ISDIR(inode->i_mode)) {
 		iput(inode);
-		return -ENOTDIR;
+		goto out;
 	}
+	error = -EPERM;
 	if (!fsuser()) {
 		iput(inode);
-		return -EPERM;
+		goto out;
 	}
 	iput(current->fs->root);
 	current->fs->root = inode;
-	return (0);
+	error = 0;
+out:
+	unlock_kernel();
+	return error;
 }
 
 asmlinkage int sys_fchmod(unsigned int fd, mode_t mode)
@@ -330,21 +372,29 @@
 	struct inode * inode;
 	struct file * file;
 	struct iattr newattrs;
+	int err = -EBADF;
 
+	lock_kernel();
 	if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
-		return -EBADF;
+		goto out;
+	err = -ENOENT;
 	if (!(inode = file->f_inode))
-		return -ENOENT;
+		goto out;
+	err = -EROFS;
 	if (IS_RDONLY(inode))
-		return -EROFS;
+		goto out;
+	err = -EPERM;
 	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
-		return -EPERM;
+		goto out;
 	if (mode == (mode_t) -1)
 		mode = inode->i_mode;
 	newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
 	newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
 	inode->i_dirt = 1;
-	return notify_change(inode, &newattrs);
+	err = notify_change(inode, &newattrs);
+out:
+	unlock_kernel();
+	return err;
 }
 
 asmlinkage int sys_chmod(const char * filename, mode_t mode)
@@ -353,24 +403,26 @@
 	int error;
 	struct iattr newattrs;
 
+	lock_kernel();
 	error = namei(filename,&inode);
 	if (error)
-		return error;
-	if (IS_RDONLY(inode)) {
-		iput(inode);
-		return -EROFS;
-	}
-	if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
-		iput(inode);
-		return -EPERM;
-	}
+		goto out;
+	error = -EROFS;
+	if (IS_RDONLY(inode))
+		goto iput_and_out;
+	error = -EPERM;
+	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+		goto iput_and_out;
 	if (mode == (mode_t) -1)
 		mode = inode->i_mode;
 	newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
 	newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
 	inode->i_dirt = 1;
 	error = notify_change(inode, &newattrs);
+iput_and_out:
 	iput(inode);
+out:
+	unlock_kernel();
 	return error;
 }
 
@@ -379,16 +431,20 @@
 	struct inode * inode;
 	struct file * file;
 	struct iattr newattrs;
-	int error;
+	int error = -EBADF;
 
+	lock_kernel();
 	if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
-		return -EBADF;
+		goto out;
+	error = -ENOENT;
 	if (!(inode = file->f_inode))
-		return -ENOENT;
+		goto out;
+	error = -EROFS;
 	if (IS_RDONLY(inode))
-		return -EROFS;
+		goto out;
+	error = -EPERM;
 	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
-		return -EPERM;
+		goto out;
 	if (user == (uid_t) -1)
 		user = inode->i_uid;
 	if (group == (gid_t) -1)
@@ -417,13 +473,16 @@
 	inode->i_dirt = 1;
 	if (inode->i_sb && inode->i_sb->dq_op) {
 		inode->i_sb->dq_op->initialize(inode, -1);
+		error = -EDQUOT;
 		if (inode->i_sb->dq_op->transfer(inode, &newattrs, 0))
-			return -EDQUOT;
+			goto out;
 		error = notify_change(inode, &newattrs);
 		if (error)
 			inode->i_sb->dq_op->transfer(inode, &newattrs, 1);
 	} else
 		error = notify_change(inode, &newattrs);
+out:
+	unlock_kernel();
 	return error;
 }
 
@@ -433,17 +492,16 @@
 	int error;
 	struct iattr newattrs;
 
+	lock_kernel();
 	error = lnamei(filename,&inode);
 	if (error)
-		return error;
-	if (IS_RDONLY(inode)) {
-		iput(inode);
-		return -EROFS;
-	}
-	if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
-		iput(inode);
-		return -EPERM;
-	}
+		goto out;
+	error = -EROFS;
+	if (IS_RDONLY(inode))
+		goto iput_and_out;
+	error = -EPERM;
+	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+		goto iput_and_out;
 	if (user == (uid_t) -1)
 		user = inode->i_uid;
 	if (group == (gid_t) -1)
@@ -472,14 +530,18 @@
 	inode->i_dirt = 1;
 	if (inode->i_sb->dq_op) {
 		inode->i_sb->dq_op->initialize(inode, -1);
+		error = -EDQUOT;
 		if (inode->i_sb->dq_op->transfer(inode, &newattrs, 0))
-			return -EDQUOT;
+			goto out;
 		error = notify_change(inode, &newattrs);
 		if (error)
 			inode->i_sb->dq_op->transfer(inode, &newattrs, 1);
 	} else
 		error = notify_change(inode, &newattrs);
+iput_and_out:
 	iput(inode);
+out:
+	unlock_kernel();
 	return(error);
 }
 
@@ -574,17 +636,24 @@
 	char * tmp;
 	int fd, error;
 
+	lock_kernel();
 	fd = get_unused_fd();
-	if (fd < 0)
-		return fd;
+	if (fd < 0) {
+		error = fd;
+		goto out;
+	}
 	error = getname(filename, &tmp);
 	if (!error) {
 		error = do_open(tmp,flags,mode, fd);
 		putname(tmp);
-		if (!error)
-			return fd;
+		if (!error) {
+			error = fd;
+			goto out;
+		}
 	}
 	put_unused_fd(fd);
+out:
+	unlock_kernel();
 	return error;
 }
 
@@ -596,7 +665,12 @@
  */
 asmlinkage int sys_creat(const char * pathname, int mode)
 {
-	return sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
+	int ret;
+
+	lock_kernel();
+	ret = sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
+	unlock_kernel();
+	return ret;
 }
 
 #endif
@@ -632,6 +706,7 @@
 	struct file * filp;
 	struct files_struct * files;
 
+	lock_kernel();
 	files = current->files;
 	error = -EBADF;
 	if (fd < NR_OPEN && (filp = files->fd[fd]) != NULL) {
@@ -640,6 +715,7 @@
 		files->fd[fd] = NULL;
 		error = close_fp(filp);
 	}
+	unlock_kernel();
 	return error;
 }
 
@@ -649,10 +725,16 @@
  */
 asmlinkage int sys_vhangup(void)
 {
+	int ret = -EPERM;
+
+	lock_kernel();
 	if (!suser())
-		return -EPERM;
+		goto out;
 	/* If there is a controlling tty, hang it up */
 	if (current->tty)
 		tty_vhangup(current->tty);
-	return 0;
+	ret = 0;
+out:
+	unlock_kernel();
+	return ret;
 }
diff -u --recursive --new-file v2.1.22/linux/fs/pipe.c linux/fs/pipe.c
--- v2.1.22/linux/fs/pipe.c	Thu Jan  2 15:55:23 1997
+++ linux/fs/pipe.c	Sat Jan 25 23:46:13 1997
@@ -12,6 +12,7 @@
 #include <linux/termios.h>
 #include <linux/mm.h>
 
+#include <asm/poll.h>
 #include <asm/uaccess.h>
 
 /*
@@ -159,57 +160,43 @@
 	}
 }
 
-static int pipe_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait)
+static unsigned int pipe_poll(struct file * filp, poll_table * wait)
 {
-	switch (sel_type) {
-		case SEL_IN:
-			if (!PIPE_EMPTY(*inode) || !PIPE_WRITERS(*inode))
-				return 1;
-			select_wait(&PIPE_WAIT(*inode), wait);
-			return 0;
-		case SEL_OUT:
-			if (PIPE_EMPTY(*inode) || !PIPE_READERS(*inode))
-				return 1;
-			select_wait(&PIPE_WAIT(*inode), wait);
-			return 0;
-		case SEL_EX:
-			if (!PIPE_READERS(*inode) || !PIPE_WRITERS(*inode))
-				return 1;
-			select_wait(&inode->i_wait,wait);
-			return 0;
-	}
-	return 0;
+	unsigned int mask;
+	struct inode * inode = filp->f_inode;
+
+	poll_wait(&PIPE_WAIT(*inode), wait);
+	mask = POLLIN | POLLRDNORM;
+	if (PIPE_EMPTY(*inode))
+		mask = POLLOUT | POLLWRNORM;
+	if (!PIPE_WRITERS(*inode))
+		mask |= POLLHUP;
+	if (!PIPE_READERS(*inode))
+		mask |= POLLERR;
+	return mask;
 }
 
 #ifdef FIFO_SUNOS_BRAINDAMAGE
 /*
  * Arggh. Why does SunOS have to have different select() behaviour
- * for pipes and fifos? Hate-Hate-Hate. See difference in SEL_IN..
+ * for pipes and fifos? Hate-Hate-Hate. SunOS lacks POLLHUP..
  */
-static int fifo_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait)
+static unsigned int fifo_poll(struct file * filp, poll_table * wait)
 {
-	switch (sel_type) {
-		case SEL_IN:
-			if (!PIPE_EMPTY(*inode))
-				return 1;
-			select_wait(&PIPE_WAIT(*inode), wait);
-			return 0;
-		case SEL_OUT:
-			if (!PIPE_FULL(*inode) || !PIPE_READERS(*inode))
-				return 1;
-			select_wait(&PIPE_WAIT(*inode), wait);
-			return 0;
-		case SEL_EX:
-			if (!PIPE_READERS(*inode) || !PIPE_WRITERS(*inode))
-				return 1;
-			select_wait(&inode->i_wait,wait);
-			return 0;
-	}
-	return 0;
+	unsigned int mask;
+	struct inode * inode = filp->f_inode;
+
+	poll_wait(&PIPE_WAIT(*inode), wait);
+	mask = POLLIN | POLLRDNORM;
+	if (PIPE_EMPTY(*inode))
+		mask = POLLOUT | POLLWRNORM;
+	if (!PIPE_READERS(*inode))
+		mask |= POLLERR;
+	return mask;
 }
 #else
 
-#define fifo_select pipe_select
+#define fifo_poll pipe_poll
 
 #endif /* FIFO_SUNOS_BRAINDAMAGE */
 
@@ -227,31 +214,18 @@
 	return pipe_read(inode,filp,buf,count);
 }
 
-static int connect_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait)
+static unsigned int connect_poll(struct file * filp, poll_table * wait)
 {
-	switch (sel_type) {
-		case SEL_IN:
-			if (!PIPE_EMPTY(*inode)) {
-				filp->f_op = &read_fifo_fops;
-				return 1;
-			}
-			if (PIPE_WRITERS(*inode)) {
-				filp->f_op = &read_fifo_fops;
-			}
-			select_wait(&PIPE_WAIT(*inode), wait);
-			return 0;
-		case SEL_OUT:
-			if (!PIPE_FULL(*inode))
-				return 1;
-			select_wait(&PIPE_WAIT(*inode), wait);
-			return 0;
-		case SEL_EX:
-			if (!PIPE_READERS(*inode) || !PIPE_WRITERS(*inode))
-				return 1;
-			select_wait(&inode->i_wait,wait);
-			return 0;
+	struct inode * inode = filp->f_inode;
+
+	poll_wait(&PIPE_WAIT(*inode), wait);
+	if (!PIPE_EMPTY(*inode)) {
+		filp->f_op = &read_fifo_fops;
+		return POLLIN | POLLRDNORM;
 	}
-	return 0;
+	if (PIPE_WRITERS(*inode))
+		filp->f_op = &read_fifo_fops;
+	return POLLOUT | POLLWRNORM;
 }
 
 static void pipe_read_release(struct inode * inode, struct file * filp)
@@ -305,7 +279,7 @@
 	connect_read,
 	bad_pipe_w,
 	NULL,		/* no readdir */
-	connect_select,
+	connect_poll,
 	pipe_ioctl,
 	NULL,		/* no mmap on pipes.. surprise */
 	pipe_read_open,
@@ -318,7 +292,7 @@
 	pipe_read,
 	bad_pipe_w,
 	NULL,		/* no readdir */
-	fifo_select,
+	fifo_poll,
 	pipe_ioctl,
 	NULL,		/* no mmap on pipes.. surprise */
 	pipe_read_open,
@@ -331,7 +305,7 @@
 	bad_pipe_r,
 	pipe_write,
 	NULL,		/* no readdir */
-	fifo_select,
+	fifo_poll,
 	pipe_ioctl,
 	NULL,		/* mmap */
 	pipe_write_open,
@@ -344,7 +318,7 @@
 	pipe_read,
 	pipe_write,
 	NULL,		/* no readdir */
-	fifo_select,
+	fifo_poll,
 	pipe_ioctl,
 	NULL,		/* mmap */
 	pipe_rdwr_open,
@@ -357,7 +331,7 @@
 	pipe_read,
 	bad_pipe_w,
 	NULL,		/* no readdir */
-	pipe_select,
+	pipe_poll,
 	pipe_ioctl,
 	NULL,		/* no mmap on pipes.. surprise */
 	pipe_read_open,
@@ -370,7 +344,7 @@
 	bad_pipe_r,
 	pipe_write,
 	NULL,		/* no readdir */
-	pipe_select,
+	pipe_poll,
 	pipe_ioctl,
 	NULL,		/* mmap */
 	pipe_write_open,
@@ -383,7 +357,7 @@
 	pipe_read,
 	pipe_write,
 	NULL,		/* no readdir */
-	pipe_select,
+	pipe_poll,
 	pipe_ioctl,
 	NULL,		/* mmap */
 	pipe_rdwr_open,
diff -u --recursive --new-file v2.1.22/linux/fs/proc/Makefile linux/fs/proc/Makefile
--- v2.1.22/linux/fs/proc/Makefile	Thu Jan 18 07:06:17 1996
+++ linux/fs/proc/Makefile	Sun Jan 26 12:07:45 1997
@@ -10,6 +10,14 @@
 O_TARGET := proc.o
 O_OBJS   := inode.o root.o base.o mem.o link.o fd.o array.o kmsg.o net.o scsi.o
 OX_OBJS  := procfs_syms.o
-M_OBJS   := $(O_TARGET)
+M_OBJS   := 
+
+ifeq ($(CONFIG_SUN_OPENPROMFS),y)
+O_OBJS += openpromfs.o
+else
+  ifeq ($(CONFIG_SUN_OPENPROMFS),m)
+  M_OBJS += openpromfs.o
+  endif
+endif
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.22/linux/fs/proc/array.c linux/fs/proc/array.c
--- v2.1.22/linux/fs/proc/array.c	Sun Dec 22 16:37:38 1996
+++ linux/fs/proc/array.c	Sun Jan 26 12:07:45 1997
@@ -46,6 +46,7 @@
 #include <linux/mm.h>
 #include <linux/pagemap.h>
 #include <linux/swap.h>
+#include <linux/slab.h>
 #include <linux/smp.h>
 
 #include <asm/uaccess.h>
@@ -1057,6 +1058,9 @@
 		case PROC_STAT:
 			return get_kstat(page);
 
+		case PROC_SLABINFO:
+			return get_slabinfo(page);
+
 		case PROC_DEVICES:
 			return get_device_list(page);
 
@@ -1180,7 +1184,7 @@
 	array_read,
 	NULL,		/* array_write */
 	NULL,		/* array_readdir */
-	NULL,		/* array_select */
+	NULL,		/* array_poll */
 	NULL,		/* array_ioctl */
 	NULL,		/* mmap */
 	NULL,		/* no special open code */
@@ -1226,7 +1230,7 @@
 	arraylong_read,
 	NULL,		/* array_write */
 	NULL,		/* array_readdir */
-	NULL,		/* array_select */
+	NULL,		/* array_poll */
 	NULL,		/* array_ioctl */
 	NULL,		/* mmap */
 	NULL,		/* no special open code */
diff -u --recursive --new-file v2.1.22/linux/fs/proc/base.c linux/fs/proc/base.c
--- v2.1.22/linux/fs/proc/base.c	Sun Dec 22 16:37:38 1996
+++ linux/fs/proc/base.c	Sun Jan 26 12:07:45 1997
@@ -19,7 +19,7 @@
 	NULL,			/* read - bad */
 	NULL,			/* write - bad */
 	proc_readdir,		/* readdir */
-	NULL,			/* select - default */
+	NULL,			/* poll - default */
 	NULL,			/* ioctl - default */
 	NULL,			/* mmap */
 	NULL,			/* no special open code */
diff -u --recursive --new-file v2.1.22/linux/fs/proc/fd.c linux/fs/proc/fd.c
--- v2.1.22/linux/fs/proc/fd.c	Tue Oct 29 19:58:44 1996
+++ linux/fs/proc/fd.c	Sun Jan 26 12:07:45 1997
@@ -21,7 +21,7 @@
 	NULL,			/* read - bad */
 	NULL,			/* write - bad */
 	proc_readfd,		/* readdir */
-	NULL,			/* select - default */
+	NULL,			/* poll - default */
 	NULL,			/* ioctl - default */
 	NULL,			/* mmap */
 	NULL,			/* no special open code */
diff -u --recursive --new-file v2.1.22/linux/fs/proc/kmsg.c linux/fs/proc/kmsg.c
--- v2.1.22/linux/fs/proc/kmsg.c	Tue Oct 29 19:58:44 1996
+++ linux/fs/proc/kmsg.c	Sat Jan 25 23:46:13 1997
@@ -9,6 +9,7 @@
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
+#include <linux/poll.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -34,13 +35,11 @@
 	return sys_syslog(2,buf,count);
 }
 
-static int kmsg_select(struct inode *inode, struct file *file, int sel_type, select_table * wait)
+static unsigned int kmsg_poll(struct file *file, poll_table * wait)
 {
-	if (sel_type != SEL_IN)
-		return 0;
+	poll_wait(&log_wait, wait);
 	if (log_size)
-		return 1;
-	select_wait(&log_wait, wait);
+		return POLLIN | POLLRDNORM;
 	return 0;
 }
 
@@ -50,7 +49,7 @@
 	kmsg_read,
 	NULL,		/* kmsg_write */
 	NULL,		/* kmsg_readdir */
-	kmsg_select,	/* kmsg_select */
+	kmsg_poll,	/* kmsg_poll */
 	NULL,		/* kmsg_ioctl */
 	NULL,		/* mmap */
 	kmsg_open,
diff -u --recursive --new-file v2.1.22/linux/fs/proc/link.c linux/fs/proc/link.c
--- v2.1.22/linux/fs/proc/link.c	Tue Oct 29 19:58:44 1996
+++ linux/fs/proc/link.c	Sun Jan 26 12:07:45 1997
@@ -33,7 +33,7 @@
 	NULL,			/* read - bad */
 	NULL,			/* write - bad */
 	NULL,			/* readdir - bad */
-	NULL,			/* select - default */
+	NULL,			/* poll - default */
 	NULL,			/* ioctl - default */
 	NULL,			/* mmap */
 	NULL,			/* very special open code */
diff -u --recursive --new-file v2.1.22/linux/fs/proc/mem.c linux/fs/proc/mem.c
--- v2.1.22/linux/fs/proc/mem.c	Tue Oct 29 19:58:44 1996
+++ linux/fs/proc/mem.c	Sun Jan 26 12:07:45 1997
@@ -314,7 +314,7 @@
 	mem_read,
 	mem_write,
 	NULL,		/* mem_readdir */
-	NULL,		/* mem_select */
+	NULL,		/* mem_poll */
 	NULL,		/* mem_ioctl */
 	mem_mmap,	/* mmap */
 	NULL,		/* no special open code */
diff -u --recursive --new-file v2.1.22/linux/fs/proc/net.c linux/fs/proc/net.c
--- v2.1.22/linux/fs/proc/net.c	Tue Oct 29 19:58:44 1996
+++ linux/fs/proc/net.c	Sun Jan 26 12:07:45 1997
@@ -88,7 +88,7 @@
 	proc_readnet,		/* read - bad */
 	NULL,			/* write - bad */
 	NULL,			/* readdir */
-	NULL,			/* select - default */
+	NULL,			/* poll - default */
 	NULL,			/* ioctl - default */
 	NULL,			/* mmap */
 	NULL,			/* no special open code */
diff -u --recursive --new-file v2.1.22/linux/fs/proc/openpromfs.c linux/fs/proc/openpromfs.c
--- v2.1.22/linux/fs/proc/openpromfs.c	Tue Dec 31 21:41:08 1996
+++ linux/fs/proc/openpromfs.c	Sun Jan 26 12:07:45 1997
@@ -1,4 +1,4 @@
-/* $Id: openpromfs.c,v 1.9 1996/12/23 05:54:21 davem Exp $
+/* $Id: openpromfs.c,v 1.12 1997/01/26 07:14:18 davem Exp $
  * openpromfs.c: /proc/openprom handling routines
  *
  * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -9,6 +9,7 @@
 #include <linux/string.h>
 #include <linux/fs.h>
 #include <linux/proc_fs.h>
+#include <linux/init.h>
 
 #include <asm/openprom.h>
 #include <asm/oplib.h>
@@ -462,7 +463,7 @@
 	property_read,		/* read */
 	property_write,		/* write - bad */
 	NULL,			/* readdir */
-	NULL,			/* select - default */
+	NULL,			/* poll - default */
 	NULL,			/* ioctl - default */
 	NULL,			/* mmap */
 	NULL,			/* no special open code */
@@ -495,7 +496,7 @@
 	nodenum_read,		/* read */
 	NULL,			/* write - bad */
 	NULL,			/* readdir */
-	NULL,			/* select - default */
+	NULL,			/* poll - default */
 	NULL,			/* ioctl - default */
 	NULL,			/* mmap */
 	NULL,			/* no special open code */
@@ -528,7 +529,7 @@
 	NULL,			/* read - bad */
 	NULL,			/* write - bad */
 	openpromfs_readdir,	/* readdir */
-	NULL,			/* select - default */
+	NULL,			/* poll - default */
 	NULL,			/* ioctl - default */
 	NULL,			/* mmap */
 	NULL,			/* no special open code */
@@ -909,7 +910,11 @@
 }
 
 /* {{{ init section */
+#ifndef MODULE
+__initfunc(static int check_space (u16 n))
+#else
 static int check_space (u16 n)
+#endif
 {
 	unsigned long pages;
 
@@ -929,7 +934,11 @@
 	return 0;
 }
 
+#ifndef MODULE
+__initfunc(static u16 get_nodes (u16 parent, u32 node))
+#else
 static u16 get_nodes (u16 parent, u32 node)
+#endif
 {
 	char *p;
 	u16 n = last_node++, i;
@@ -1043,8 +1052,11 @@
 
 #ifndef MODULE
 #define RET(x)
-void openpromfs_init (void)
+__initfunc(void openpromfs_init (void))
 #else
+
+EXPORT_NO_SYMBOLS;
+
 #define RET(x) -x
 int init_module (void)
 #endif
@@ -1062,7 +1074,9 @@
 	}
 	nodes[last_node].first_prop = first_prop;
 	proc_openprom_iops = proc_openprom_register (openpromfs_readdir,
-				openpromfs_lookup, openpromfs_use, &devices);
+				                     openpromfs_lookup,
+						     openpromfs_use,
+						     &devices);
 	return RET(0);
 }
 
diff -u --recursive --new-file v2.1.22/linux/fs/proc/root.c linux/fs/proc/root.c
--- v2.1.22/linux/fs/proc/root.c	Sun Dec 22 16:37:38 1996
+++ linux/fs/proc/root.c	Sun Jan 26 12:07:45 1997
@@ -41,7 +41,7 @@
 	NULL,			/* read - bad */
 	NULL,			/* write - bad */
 	proc_readdir,		/* readdir */
-	NULL,			/* select - default */
+	NULL,			/* poll - default */
 	NULL,			/* ioctl - default */
 	NULL,			/* mmap */
 	NULL,			/* no special open code */
@@ -82,7 +82,7 @@
 	NULL,			/* read - bad */
 	NULL,			/* write - bad */
 	proc_root_readdir,	/* readdir */
-	NULL,			/* select - default */
+	NULL,			/* poll - default */
 	NULL,			/* ioctl - default */
 	NULL,			/* mmap */
 	NULL,			/* no special open code */
@@ -255,7 +255,7 @@
 #else
 	NULL,			/* readdir */
 #endif	
-	NULL,			/* select - default */
+	NULL,			/* poll - default */
 	NULL,			/* ioctl - default */
 	NULL,			/* mmap */
 	NULL,			/* no special open code */
@@ -514,6 +514,10 @@
 	PROC_PROFILE, 7, "profile",
 	S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0,
 };
+static struct proc_dir_entry proc_root_slab = {
+	PROC_SLABINFO, 8, "slabinfo",
+	S_IFREG | S_IRUGO, 1, 0, 0,
+};
 
 void proc_root_init(void)
 {
@@ -576,6 +580,8 @@
 	proc_register(&proc_root, &proc_openprom);
 #endif
 		   
+	proc_register(&proc_root, &proc_root_slab);
+
 	if (prof_shift) {
 		proc_register(&proc_root, &proc_root_profile);
 	}
diff -u --recursive --new-file v2.1.22/linux/fs/proc/scsi.c linux/fs/proc/scsi.c
--- v2.1.22/linux/fs/proc/scsi.c	Tue Oct 29 19:58:44 1996
+++ linux/fs/proc/scsi.c	Sun Jan 26 12:07:45 1997
@@ -46,7 +46,7 @@
     proc_readscsi,	/* read	   */
     proc_writescsi,	/* write   */
     proc_readdir,	/* readdir */
-    NULL,		/* select  */
+    NULL,		/* poll    */
     NULL,		/* ioctl   */
     NULL,		/* mmap	   */
     NULL,		/* no special open code	   */
diff -u --recursive --new-file v2.1.22/linux/fs/read_write.c linux/fs/read_write.c
--- v2.1.22/linux/fs/read_write.c	Thu Dec 12 19:37:18 1996
+++ linux/fs/read_write.c	Sun Jan 26 12:07:45 1997
@@ -14,6 +14,8 @@
 #include <linux/mm.h>
 #include <linux/uio.h>
 #include <linux/malloc.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 
@@ -60,6 +62,7 @@
 	struct file * file;
 	struct inode * inode;
 
+	lock_kernel();
 	retval = -EBADF;
 	if (fd >= NR_OPEN ||
 	    !(file = current->files->fd[fd]) ||
@@ -70,6 +73,7 @@
 		goto bad;
 	retval = llseek(inode, file, offset, origin);
 bad:
+	unlock_kernel();
 	return retval;
 }
 
@@ -82,6 +86,7 @@
 	struct inode * inode;
 	long long offset;
 
+	lock_kernel();
 	retval = -EBADF;
 	if (fd >= NR_OPEN ||
 	    !(file = current->files->fd[fd]) ||
@@ -101,8 +106,8 @@
 		if (retval)
 			retval = -EFAULT;
 	}
-
 bad:
+	unlock_kernel();
 	return retval;
 }
 
@@ -113,6 +118,7 @@
 	struct inode * inode;
 	long (*read)(struct inode *, struct file *, char *, unsigned long);
 
+	lock_kernel();
 	error = -EBADF;
 	file = fget(fd);
 	if (!file)
@@ -133,6 +139,7 @@
 out:
 	fput(file, inode);
 bad_file:
+	unlock_kernel();
 	return error;
 }
 
@@ -143,6 +150,7 @@
 	struct inode * inode;
 	long (*write)(struct inode *, struct file *, const char *, unsigned long);
 
+	lock_kernel();
 	error = -EBADF;
 	file = fget(fd);
 	if (!file)
@@ -164,6 +172,7 @@
 out:
 	fput(file, inode);
 bad_file:
+	unlock_kernel();
 	return error;
 }
 
@@ -259,26 +268,34 @@
 {
 	struct file * file;
 	struct inode * inode;
+	long err = -EBADF;
 
-	if (fd >= NR_OPEN || !(file = current->files->fd[fd]) || !(inode = file->f_inode))
-		return -EBADF;
+	lock_kernel();
+	if (fd >= NR_OPEN || !(file = current->files->fd[fd]) || !(inode=file->f_inode))
+		goto out;
 	if (!(file->f_mode & 1))
-		return -EBADF;
-	return do_readv_writev(VERIFY_WRITE, inode, file, vector, count);
+		goto out;
+	err = do_readv_writev(VERIFY_WRITE, inode, file, vector, count);
+out:
+	unlock_kernel();
+	return err;
 }
 
 asmlinkage long sys_writev(unsigned long fd, const struct iovec * vector, unsigned long count)
 {
-	int error;
+	int error = -EBADF;
 	struct file * file;
 	struct inode * inode;
 
-	if (fd >= NR_OPEN || !(file = current->files->fd[fd]) || !(inode = file->f_inode))
-		return -EBADF;
+	lock_kernel();
+	if (fd >= NR_OPEN || !(file = current->files->fd[fd]) || !(inode=file->f_inode))
+		goto out;
 	if (!(file->f_mode & 2))
-		return -EBADF;
+		goto out;
 	down(&inode->i_sem);
 	error = do_readv_writev(VERIFY_READ, inode, file, vector, count);
 	up(&inode->i_sem);
+out:
+	unlock_kernel();
 	return error;
 }
diff -u --recursive --new-file v2.1.22/linux/fs/readdir.c linux/fs/readdir.c
--- v2.1.22/linux/fs/readdir.c	Tue Oct 29 19:58:44 1996
+++ linux/fs/readdir.c	Sun Jan 26 12:07:45 1997
@@ -10,6 +10,8 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 
@@ -55,23 +57,28 @@
 
 asmlinkage int old_readdir(unsigned int fd, void * dirent, unsigned int count)
 {
-	int error;
+	int error = -EBADF;
 	struct file * file;
 	struct readdir_callback buf;
 
+	lock_kernel();
 	if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
-		return -EBADF;
+		goto out;
+	error = -ENOTDIR;
 	if (!file->f_op || !file->f_op->readdir)
-		return -ENOTDIR;
+		goto out;
 	error = verify_area(VERIFY_WRITE, dirent, sizeof(struct old_linux_dirent));
 	if (error)
-		return error;
+		goto out;
 	buf.count = 0;
 	buf.dirent = dirent;
 	error = file->f_op->readdir(file->f_inode, file, &buf, fillonedir);
 	if (error < 0)
-		return error;
-	return buf.count;
+		goto out;
+	error = buf.count;
+out:
+	unlock_kernel();
+	return error;
 }
 
 /*
@@ -121,25 +128,32 @@
 	struct file * file;
 	struct linux_dirent * lastdirent;
 	struct getdents_callback buf;
-	int error;
+	int error = -EBADF;
 
+	lock_kernel();
 	if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
-		return -EBADF;
+		goto out;
+	error = -ENOTDIR;
 	if (!file->f_op || !file->f_op->readdir)
-		return -ENOTDIR;
+		goto out;
 	error = verify_area(VERIFY_WRITE, dirent, count);
 	if (error)
-		return error;
+		goto out;
 	buf.current_dir = (struct linux_dirent *) dirent;
 	buf.previous = NULL;
 	buf.count = count;
 	buf.error = 0;
 	error = file->f_op->readdir(file->f_inode, file, &buf, filldir);
 	if (error < 0)
-		return error;
+		goto out;
 	lastdirent = buf.previous;
-	if (!lastdirent)
-		return buf.error;
-	put_user(file->f_pos, &lastdirent->d_off);
-	return count - buf.count;
+	if (!lastdirent) {
+		error = buf.error;
+	} else {
+		put_user(file->f_pos, &lastdirent->d_off);
+		error = count - buf.count;
+	}
+out:
+	unlock_kernel();
+	return error;
 }
diff -u --recursive --new-file v2.1.22/linux/fs/romfs/inode.c linux/fs/romfs/inode.c
--- v2.1.22/linux/fs/romfs/inode.c	Wed Jan 15 19:45:44 1997
+++ linux/fs/romfs/inode.c	Sun Jan 26 12:07:45 1997
@@ -476,7 +476,7 @@
         generic_file_read,	/* read */
 	NULL,			/* write - bad */
 	NULL,			/* readdir */
-	NULL,			/* select - default */
+	NULL,			/* poll - default */
 	NULL,			/* ioctl */
 	generic_file_mmap,	/* mmap */
 	NULL,			/* open */
@@ -513,7 +513,7 @@
         NULL,			/* read */
 	NULL,			/* write - bad */
 	romfs_readdir,		/* readdir */
-	NULL,			/* select - default */
+	NULL,			/* poll - default */
 	NULL,			/* ioctl */
 	NULL,			/* mmap */
 	NULL,			/* open */
diff -u --recursive --new-file v2.1.22/linux/fs/select.c linux/fs/select.c
--- v2.1.22/linux/fs/select.c	Tue Dec 31 21:41:08 1996
+++ linux/fs/select.c	Sun Jan 26 12:07:45 1997
@@ -1,5 +1,5 @@
 /*
- * This file contains the procedures for the handling of select
+ * This file contains the procedures for the handling of select and poll
  *
  * Created for Linux based loosely upon Mathius Lattner's minix
  * patches by Peter MacDonald. Heavily edited by Linus.
@@ -21,11 +21,16 @@
 #include <linux/errno.h>
 #include <linux/personality.h>
 #include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
+#include <asm/poll.h>
 
 #define ROUND_UP(x,y) (((x)+(y)-1)/(y))
+#define DEFAULT_POLLMASK (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)
 
 /*
  * Ok, Peter made a complicated, but straightforward multiple_wait() function.
@@ -34,20 +39,20 @@
  * understand what I'm doing here, then you understand how the linux
  * sleep/wakeup mechanism works.
  *
- * Two very simple procedures, select_wait() and free_wait() make all the work.
- * select_wait() is an inline-function defined in <linux/sched.h>, as all select
- * functions have to call it to add an entry to the select table.
+ * Two very simple procedures, poll_wait() and free_wait() make all the work.
+ * poll_wait() is an inline-function defined in <linux/sched.h>, as all select/poll
+ * functions have to call it to add an entry to the poll table.
  */
 
 /*
- * I rewrote this again to make the select_table size variable, take some
+ * I rewrote this again to make the poll_table size variable, take some
  * more shortcuts, improve responsiveness, and remove another race that
  * Linus noticed.  -- jrs
  */
 
-static void free_wait(select_table * p)
+static void free_wait(poll_table * p)
 {
-	struct select_table_entry * entry = p->entry + p->nr;
+	struct poll_table_entry * entry = p->entry + p->nr;
 
 	while (p->nr > 0) {
 		p->nr--;
@@ -57,34 +62,6 @@
 }
 
 /*
- * The check function checks the ready status of a file using the vfs layer.
- *
- * If the file was not ready we were added to its wait queue.  But in
- * case it became ready just after the check and just before it called
- * select_wait, we call it again, knowing we are already on its
- * wait queue this time.  The second call is not necessary if the
- * select_table is NULL indicating an earlier file check was ready
- * and we aren't going to sleep on the select_table.  -- jrs
- */
-
-static inline int __check(
-	int (*select) (struct inode *, struct file *, int, select_table *),
-	struct inode *inode,
-	struct file *file,
-	int flag,
-	select_table * wait)
-{
-	return select(inode, file, flag, wait) ||
-		(wait && select(inode, file, flag, NULL));
-}
-
-#define check(flag,wait,file) \
-(((file)->f_op && (file)->f_op->select) ? \
- __check((file)->f_op->select,(file)->f_inode,file,flag,wait) \
- : \
- (flag != SEL_EX))
-
-/*
  * Due to kernel stack usage, we use a _limited_ fd_set type here, and once
  * we really start supporting >256 file descriptors we'll probably have to
  * allocate the kernel fd_set copies dynamically.. (The kernel select routines
@@ -154,11 +131,15 @@
 #define ISSET(i,m)	(((i)&*(m)) != 0)
 #define SET(i,m)	(*(m) |= (i))
 
+#define POLLIN_SET (POLLRDNORM | POLLRDBAND | POLLIN | POLLHUP | POLLERR)
+#define POLLOUT_SET (POLLWRBAND | POLLWRNORM | POLLOUT | POLLERR)
+#define POLLEX_SET (POLLPRI)
+
 static int do_select(int n, fd_set_buffer *fds)
 {
 	int retval;
-	select_table wait_table, *wait;
-	struct select_table_entry *entry;
+	poll_table wait_table, *wait;
+	struct poll_table_entry *entry;
 	int i;
 
 	retval = max_select_fd(n, fds);
@@ -166,7 +147,8 @@
 		goto out;
 	n = retval;
 	retval = -ENOMEM;
-	if(!(entry = (struct select_table_entry*) __get_free_page(GFP_KERNEL)))
+	entry = (struct poll_table_entry *) __get_free_page(GFP_KERNEL);
+	if (!entry)
 		goto out;
 	retval = 0;
 	wait_table.nr = 0;
@@ -178,24 +160,30 @@
 		for (i = 0 ; i < n ; i++,fd++) {
 			unsigned long bit = BIT(i);
 			unsigned long *in = MEM(i,fds->in);
-			struct file * file = *fd;
 
-			if (!file)
-				continue;
-			if (ISSET(bit,__IN(in)) && check(SEL_IN,wait,file)) {
-				SET(bit, __RES_IN(in));
-				retval++;
-				wait = NULL;
-			}
-			if (ISSET(bit,__OUT(in)) && check(SEL_OUT,wait,file)) {
-				SET(bit, __RES_OUT(in));
-				retval++;
-				wait = NULL;
-			}
-			if (ISSET(bit,__EX(in)) && check(SEL_EX,wait,file)) {
-				SET(bit, __RES_EX(in));
-				retval++;
-				wait = NULL;
+			if (bit & BITS(in)) {
+				struct file * file = *fd;
+				unsigned int mask = POLLNVAL;
+				if (file) {
+					mask = DEFAULT_POLLMASK;
+					if (file->f_op && file->f_op->poll)
+						mask = file->f_op->poll(file, wait);
+				}
+				if ((mask & POLLIN_SET) && ISSET(bit, __IN(in))) {
+					SET(bit, __RES_IN(in));
+					retval++;
+					wait = NULL;
+				}
+				if ((mask & POLLOUT_SET) && ISSET(bit, __OUT(in))) {
+					SET(bit, __RES_OUT(in));
+					retval++;
+					wait = NULL;
+				}
+				if ((mask & POLLEX_SET) && ISSET(bit, __EX(in))) {
+					SET(bit, __RES_EX(in));
+					retval++;
+					wait = NULL;
+				}
 			}
 		}
 		wait = NULL;
@@ -288,11 +276,11 @@
  */
 asmlinkage int sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp)
 {
-	int error;
+	int error = -EINVAL;
 	fd_set_buffer fds;
 	unsigned long timeout;
 
-	error = -EINVAL;
+	lock_kernel();
 	if (n < 0)
 		goto out;
 	if (n > NR_OPEN)
@@ -342,5 +330,105 @@
 	set_fd_set(n, outp, &fds.res_out);
 	set_fd_set(n, exp, &fds.res_ex);
 out:
+	unlock_kernel();
 	return error;
+}
+
+static int do_poll(unsigned int nfds, struct pollfd *fds, poll_table *wait)
+{
+	int count;
+	struct file ** fd = current->files->fd;
+
+	count = 0;
+	for (;;) {
+		unsigned int j;
+		struct pollfd * fdpnt;
+
+		current->state = TASK_INTERRUPTIBLE;
+		for (fdpnt = fds, j = 0; j < nfds; j++, fdpnt++) {
+			unsigned int i;
+			unsigned int mask;
+			struct file * file;
+
+			mask = POLLNVAL;
+			i = fdpnt->fd;
+			if (i < NR_OPEN && (file = fd[i]) != NULL) {
+				mask = DEFAULT_POLLMASK;
+				if (file->f_op && file->f_op->poll)
+					mask = file->f_op->poll(file, wait);
+				mask &= fdpnt->events | POLLERR | POLLHUP;
+			}
+			if (mask) {
+				wait = NULL;
+				count++;
+			}
+			fdpnt->revents = mask;
+		}
+
+		wait = NULL;
+		if (count || !current->timeout || (current->signal & ~current->blocked))
+			break;
+		schedule();
+	}
+	current->state = TASK_RUNNING;
+	return count;
+}
+
+asmlinkage int sys_poll(struct pollfd * ufds, unsigned int nfds, int timeout)
+{
+        int i, count, fdcount, err = -EINVAL;
+	struct pollfd * fds, *fds1;
+	poll_table wait_table;
+	struct poll_table_entry *entry;
+
+	lock_kernel();
+	if (nfds > NR_OPEN)
+		goto out;
+
+	err = -ENOMEM;
+	entry = (struct poll_table_entry *) __get_free_page(GFP_KERNEL);
+	if (!entry)
+		goto out;
+	fds = (struct pollfd *) kmalloc(nfds*sizeof(struct pollfd), GFP_KERNEL);
+	if (!fds) {
+		free_page((unsigned long) entry);
+		goto out;
+	}
+
+	err = -EFAULT;
+	if (copy_from_user(fds, ufds, nfds*sizeof(struct pollfd))) {
+		free_page((unsigned long)entry);
+		kfree(fds);
+		goto out;
+	}
+
+	if (timeout < 0)
+		timeout = 0x7fffffff;
+	else if (timeout)
+		timeout = ((unsigned long)timeout*HZ+999)/1000+jiffies+1;
+	current->timeout = timeout;
+
+	count = 0;
+	wait_table.nr = 0;
+	wait_table.entry = entry;
+
+	fdcount = do_poll(nfds, fds, &wait_table);
+	current->timeout = 0;
+
+	free_wait(&wait_table);
+	free_page((unsigned long) entry);
+
+	/* OK, now copy the revents fields back to user space. */
+	fds1 = fds;
+	for(i=0; i < (int)nfds; i++, ufds++, fds++) {
+		__put_user(fds->revents, &ufds->revents);
+	}
+	kfree(fds1);
+	if (!fdcount && (current->signal & ~current->blocked))
+		err = -EINTR;
+	else
+		err = fdcount;
+out:
+	unlock_kernel();
+	return err;
 }
diff -u --recursive --new-file v2.1.22/linux/fs/smbfs/dir.c linux/fs/smbfs/dir.c
--- v2.1.22/linux/fs/smbfs/dir.c	Thu Dec 12 17:02:45 1996
+++ linux/fs/smbfs/dir.c	Sun Jan 26 12:07:45 1997
@@ -56,7 +56,7 @@
 	smb_dir_read,		/* read - bad */
 	NULL,			/* write - bad */
 	smb_readdir,		/* readdir */
-	NULL,			/* select - default */
+	NULL,			/* poll - default */
 	smb_ioctl,		/* ioctl - default */
 	NULL,			/* mmap */
 	NULL,			/* no special open code */
diff -u --recursive --new-file v2.1.22/linux/fs/smbfs/file.c linux/fs/smbfs/file.c
--- v2.1.22/linux/fs/smbfs/file.c	Thu Dec 12 17:02:45 1996
+++ linux/fs/smbfs/file.c	Sun Jan 26 12:07:45 1997
@@ -215,7 +215,7 @@
 	smb_file_read,		/* read */
 	smb_file_write,		/* write */
 	NULL,			/* readdir - bad */
-	NULL,			/* select - default */
+	NULL,			/* poll - default */
 	smb_ioctl,		/* ioctl */
 	smb_mmap,		/* mmap */
 	NULL,			/* open */
diff -u --recursive --new-file v2.1.22/linux/fs/stat.c linux/fs/stat.c
--- v2.1.22/linux/fs/stat.c	Thu Jan  2 15:55:23 1997
+++ linux/fs/stat.c	Sun Jan 26 12:07:45 1997
@@ -11,6 +11,8 @@
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 
@@ -112,11 +114,14 @@
 	struct inode * inode;
 	int error;
 
+	lock_kernel();
 	error = namei(filename,&inode);
 	if (error)
-		return error;
+		goto out;
 	error = cp_old_stat(inode,statbuf);
 	iput(inode);
+out:
+	unlock_kernel();
 	return error;
 }
 #endif
@@ -126,11 +131,14 @@
 	struct inode * inode;
 	int error;
 
+	lock_kernel();
 	error = namei(filename,&inode);
 	if (error)
-		return error;
+		goto out;
 	error = cp_new_stat(inode,statbuf);
 	iput(inode);
+out:
+	unlock_kernel();
 	return error;
 }
 
@@ -145,11 +153,14 @@
 	struct inode * inode;
 	int error;
 
+	lock_kernel();
 	error = lnamei(filename,&inode);
 	if (error)
-		return error;
+		goto out;
 	error = cp_old_stat(inode,statbuf);
 	iput(inode);
+out:
+	unlock_kernel();
 	return error;
 }
 
@@ -160,11 +171,14 @@
 	struct inode * inode;
 	int error;
 
+	lock_kernel();
 	error = lnamei(filename,&inode);
 	if (error)
-		return error;
+		goto out;
 	error = cp_new_stat(inode,statbuf);
 	iput(inode);
+out:
+	unlock_kernel();
 	return error;
 }
 
@@ -178,10 +192,15 @@
 {
 	struct file * f;
 	struct inode * inode;
+	int ret = -EBADF;
 
+	lock_kernel();
 	if (fd >= NR_OPEN || !(f=current->files->fd[fd]) || !(inode=f->f_inode))
-		return -EBADF;
-	return cp_old_stat(inode,statbuf);
+		goto out;
+	ret = cp_old_stat(inode,statbuf);
+out:
+	unlock_kernel();
+	return ret;
 }
 
 #endif
@@ -190,28 +209,38 @@
 {
 	struct file * f;
 	struct inode * inode;
+	int err = -EBADF;
 
+	lock_kernel();
 	if (fd >= NR_OPEN || !(f=current->files->fd[fd]) || !(inode=f->f_inode))
-		return -EBADF;
-	return cp_new_stat(inode,statbuf);
+		goto out;
+	err = cp_new_stat(inode,statbuf);
+out:
+	unlock_kernel();
+	return err;
 }
 
 asmlinkage int sys_readlink(const char * path, char * buf, int bufsiz)
 {
 	struct inode * inode;
-	int error;
+	int error = -EINVAL;
 
+	lock_kernel();
 	if (bufsiz <= 0)
-		return -EINVAL;
+		goto out;
 	error = verify_area(VERIFY_WRITE,buf,bufsiz);
 	if (error)
-		return error;
+		goto out;
 	error = lnamei(path,&inode);
 	if (error)
-		return error;
+		goto out;
+	error = -EINVAL;
 	if (!inode->i_op || !inode->i_op->readlink) {
 		iput(inode);
-		return -EINVAL;
+		goto out;
 	}
-	return inode->i_op->readlink(inode,buf,bufsiz);
+	error = inode->i_op->readlink(inode,buf,bufsiz);
+out:
+	unlock_kernel();
+	return error;
 }
diff -u --recursive --new-file v2.1.22/linux/fs/super.c linux/fs/super.c
--- v2.1.22/linux/fs/super.c	Thu Jan  2 15:55:23 1997
+++ linux/fs/super.c	Sun Jan 26 12:07:45 1997
@@ -30,6 +30,8 @@
 #include <linux/string.h>
 #include <linux/locks.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 #include <linux/fd.h>
 
 #include <asm/system.h>
@@ -246,6 +248,7 @@
 	int retval = -EINVAL;
 	unsigned int index;
 
+	lock_kernel();
 	va_start(args, option);
 	switch (option) {
 		case 1:
@@ -262,6 +265,7 @@
 			break;
 	}
 	va_end(args);
+	unlock_kernel();
 	return retval;
 }
 
@@ -473,13 +477,15 @@
         struct ustat tmp;
         struct statfs sbuf;
         unsigned long old_fs;
+	int err = -EINVAL;
 
+	lock_kernel();
         s = get_super(to_kdev_t(dev));
         if (s == NULL)
-                return -EINVAL;
-
+                goto out;
+	err = -ENOSYS;
         if (!(s->s_op->statfs))
-                return -ENOSYS;
+                goto out;
 
         old_fs = get_fs();
         set_fs(get_ds());
@@ -490,7 +496,10 @@
         tmp.f_tfree = sbuf.f_bfree;
         tmp.f_tinode = sbuf.f_ffree;
 
-        return copy_to_user(ubuf,&tmp,sizeof(struct ustat)) ? -EFAULT : 0;
+        err = copy_to_user(ubuf,&tmp,sizeof(struct ustat)) ? -EFAULT : 0;
+out:
+	unlock_kernel();
+	return err;
 }
 
 static struct super_block * read_super(kdev_t dev,const char *name,int flags,
@@ -625,27 +634,30 @@
 {
 	struct inode * inode;
 	kdev_t dev;
-	int retval;
+	int retval = -EPERM;
 	struct inode dummy_inode;
 
+	lock_kernel();
 	if (!suser())
-		return -EPERM;
+		goto out;
 	retval = namei(name, &inode);
 	if (retval) {
 		retval = lnamei(name, &inode);
 		if (retval)
-			return retval;
+			goto out;
 	}
 	if (S_ISBLK(inode->i_mode)) {
 		dev = inode->i_rdev;
+		retval = -EACCES;
 		if (IS_NODEV(inode)) {
 			iput(inode);
-			return -EACCES;
+			goto out;
 		}
 	} else {
+		retval = -EINVAL;
 		if (!inode->i_sb || inode != inode->i_sb->s_mounted) {
 			iput(inode);
-			return -EINVAL;
+			goto out;
 		}
 		dev = inode->i_sb->s_dev;
 		iput(inode);
@@ -653,9 +665,10 @@
 		dummy_inode.i_rdev = dev;
 		inode = &dummy_inode;
 	}
+	retval = -ENXIO;
 	if (MAJOR(dev) >= MAX_BLKDEV) {
 		iput(inode);
-		return -ENXIO;
+		goto out;
 	}
 	retval = do_umount(dev,0);
 	if (!retval) {
@@ -667,10 +680,11 @@
 	}
 	if (inode != &dummy_inode)
 		iput(inode);
-	if (retval)
-		return retval;
-	fsync_dev(dev);
-	return 0;
+	if (!retval)
+		fsync_dev(dev);
+out:
+	unlock_kernel();
+	return retval;
 }
 
 /*
@@ -814,9 +828,9 @@
  * information (or be NULL).
  *
  * NOTE! As old versions of mount() didn't use this setup, the flags
- * has to have a special 16-bit magic number in the hight word:
+ * have to have a special 16-bit magic number in the high word:
  * 0xC0ED. If this magic word isn't present, the flags and data info
- * isn't used, as the syscall assumes we are talking to an older
+ * aren't used, as the syscall assumes we are talking to an older
  * version that didn't understand them.
  */
 asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
@@ -826,54 +840,60 @@
 	struct inode * inode;
 	struct file_operations * fops;
 	kdev_t dev;
-	int retval;
+	int retval = -EPERM;
 	const char * t;
 	unsigned long flags = 0;
 	unsigned long page = 0;
 
+	lock_kernel();
 	if (!suser())
-		return -EPERM;
+		goto out;
 	if ((new_flags &
 	     (MS_MGC_MSK | MS_REMOUNT)) == (MS_MGC_VAL | MS_REMOUNT)) {
 		retval = copy_mount_options (data, &page);
 		if (retval < 0)
-			return retval;
+			goto out;
 		retval = do_remount(dir_name,
 				    new_flags & ~MS_MGC_MSK & ~MS_REMOUNT,
 				    (char *) page);
 		free_page(page);
-		return retval;
+		goto out;
 	}
 	retval = copy_mount_options (type, &page);
 	if (retval < 0)
-		return retval;
+		goto out;
 	fstype = get_fs_type((char *) page);
 	free_page(page);
+	retval = -ENODEV;
 	if (!fstype)		
-		return -ENODEV;
+		goto out;
 	t = fstype->name;
 	fops = NULL;
 	if (fstype->requires_dev) {
 		retval = namei(dev_name, &inode);
 		if (retval)
-			return retval;
+			goto out;
+		retval = -ENOTBLK;
 		if (!S_ISBLK(inode->i_mode)) {
 			iput(inode);
-			return -ENOTBLK;
+			goto out;
 		}
+		retval = -EACCES;
 		if (IS_NODEV(inode)) {
 			iput(inode);
-			return -EACCES;
+			goto out;
 		}
 		dev = inode->i_rdev;
+		retval = -ENXIO;
 		if (MAJOR(dev) >= MAX_BLKDEV) {
 			iput(inode);
-			return -ENXIO;
+			goto out;
 		}
 		fops = get_blkfops(MAJOR(dev));
+		retval = -ENOTBLK;
 		if (!fops) {
 			iput(inode);
-			return -ENOTBLK;
+			goto out;
 		}
 		if (fops->open) {
 			struct file dummy;	/* allows read-write or read-only flag */
@@ -883,13 +903,14 @@
 			retval = fops->open(inode, &dummy);
 			if (retval) {
 				iput(inode);
-				return retval;
+				goto out;
 			}
 		}
 
 	} else {
+		retval = -EMFILE;
 		if (!(dev = get_unnamed_dev()))
-			return -EMFILE;
+			goto out;
 		inode = NULL;
 	}
 	page = 0;
@@ -899,7 +920,7 @@
 		if (retval < 0) {
 			put_unnamed_dev(dev);
 			iput(inode);
-			return retval;
+			goto out;
 		}
 	}
 	retval = do_mount(dev,dev_name,dir_name,t,flags,(void *) page);
@@ -909,6 +930,8 @@
 		put_unnamed_dev(dev);
 	}
 	iput(inode);
+out:
+	unlock_kernel();
 	return retval;
 }
 
diff -u --recursive --new-file v2.1.22/linux/fs/sysv/dir.c linux/fs/sysv/dir.c
--- v2.1.22/linux/fs/sysv/dir.c	Tue Oct 29 19:58:45 1996
+++ linux/fs/sysv/dir.c	Sun Jan 26 12:07:45 1997
@@ -34,7 +34,7 @@
 	sysv_dir_read,		/* read */
 	NULL,			/* write - bad */
 	sysv_readdir,		/* readdir */
-	NULL,			/* select - default */
+	NULL,			/* poll - default */
 	NULL,			/* ioctl - default */
 	NULL,			/* mmap */
 	NULL,			/* no special open code */
diff -u --recursive --new-file v2.1.22/linux/fs/sysv/file.c linux/fs/sysv/file.c
--- v2.1.22/linux/fs/sysv/file.c	Tue Oct 29 19:58:45 1996
+++ linux/fs/sysv/file.c	Sun Jan 26 12:07:45 1997
@@ -44,7 +44,7 @@
 	sysv_file_read,		/* read */
 	sysv_file_write,	/* write */
 	NULL,			/* readdir - bad */
-	NULL,			/* select - default */
+	NULL,			/* poll - default */
 	NULL,			/* ioctl - default */
 	generic_file_mmap,	/* mmap */
 	NULL,			/* no special open is needed */
diff -u --recursive --new-file v2.1.22/linux/fs/ufs/ufs_dir.c linux/fs/ufs/ufs_dir.c
--- v2.1.22/linux/fs/ufs/ufs_dir.c	Sat Oct  5 16:58:35 1996
+++ linux/fs/ufs/ufs_dir.c	Sun Jan 26 12:07:45 1997
@@ -6,7 +6,7 @@
  * Laboratory for Computer Science Research Computing Facility
  * Rutgers, The State University of New Jersey
  *
- * $Id: ufs_dir.c,v 1.7 1996/05/21 19:01:45 davem Exp $
+ * $Id: ufs_dir.c,v 1.8 1997/01/26 07:14:28 davem Exp $
  *
  */
 
@@ -143,7 +143,7 @@
 	NULL,			/* read */
 	NULL,			/* write */
 	ufs_readdir,		/* readdir */
-	NULL,			/* select */
+	NULL,			/* poll */
 	NULL,			/* ioctl */
 	NULL,			/* mmap */
 	NULL,			/* open */
diff -u --recursive --new-file v2.1.22/linux/fs/ufs/ufs_file.c linux/fs/ufs/ufs_file.c
--- v2.1.22/linux/fs/ufs/ufs_file.c	Sat Oct  5 16:58:35 1996
+++ linux/fs/ufs/ufs_file.c	Sun Jan 26 12:07:45 1997
@@ -6,7 +6,7 @@
  * Laboratory for Computer Science Research Computing Facility
  * Rutgers, The State University of New Jersey
  *
- * $Id: ufs_file.c,v 1.6 1996/05/19 03:55:48 krioles Exp $
+ * $Id: ufs_file.c,v 1.7 1997/01/26 07:14:28 davem Exp $
  *
  */
 
@@ -18,7 +18,7 @@
 	generic_file_read,	/* read */
 	NULL,			/* write */
 	NULL,			/* readdir */
-	NULL,			/* select */
+	NULL,			/* poll */
 	NULL,			/* ioctl */
 	generic_file_mmap,	/* mmap */
 	NULL,			/* open */
diff -u --recursive --new-file v2.1.22/linux/fs/ufs/ufs_super.c linux/fs/ufs/ufs_super.c
--- v2.1.22/linux/fs/ufs/ufs_super.c	Wed Jan 15 19:45:44 1997
+++ linux/fs/ufs/ufs_super.c	Sun Jan 26 12:07:46 1997
@@ -8,7 +8,7 @@
  *
  * Copyright (C) 1996  Eddie C. Dost  (ecd@skynet.be)
  *
- * $Id: ufs_super.c,v 1.21 1996/12/29 20:48:55 davem Exp $
+ * $Id: ufs_super.c,v 1.22 1997/01/16 14:17:41 davem Exp $
  *
  */
 
diff -u --recursive --new-file v2.1.22/linux/fs/ufs/ufs_symlink.c linux/fs/ufs/ufs_symlink.c
--- v2.1.22/linux/fs/ufs/ufs_symlink.c	Wed Dec 18 15:58:52 1996
+++ linux/fs/ufs/ufs_symlink.c	Sun Jan 26 12:07:46 1997
@@ -6,7 +6,7 @@
  * Laboratory for Computer Science Research Computing Facility
  * Rutgers, The State University of New Jersey
  *
- * $Id: ufs_symlink.c,v 1.6 1996/10/30 06:00:36 davem Exp $
+ * $Id: ufs_symlink.c,v 1.7 1997/01/26 07:14:29 davem Exp $
  *
  */
 
@@ -139,7 +139,7 @@
 	NULL,			/* read */
 	NULL,			/* write */
 	NULL,			/* readdir */
-	NULL,			/* select */
+	NULL,			/* poll */
 	NULL,			/* ioctl */
 	NULL,			/* mmap */
 	NULL,			/* open */
diff -u --recursive --new-file v2.1.22/linux/fs/umsdos/dir.c linux/fs/umsdos/dir.c
--- v2.1.22/linux/fs/umsdos/dir.c	Tue Oct 29 19:58:46 1996
+++ linux/fs/umsdos/dir.c	Sun Jan 26 12:07:46 1997
@@ -791,7 +791,7 @@
 	UMSDOS_dir_read,	/* read */
 	NULL,				/* write - bad */
 	UMSDOS_readdir,		/* readdir */
-	NULL,				/* select - default */
+	NULL,				/* poll - default */
 	UMSDOS_ioctl_dir,	/* ioctl - default */
 	NULL,				/* mmap */
 	NULL,				/* no special open code */
diff -u --recursive --new-file v2.1.22/linux/fs/umsdos/file.c linux/fs/umsdos/file.c
--- v2.1.22/linux/fs/umsdos/file.c	Tue Oct 29 19:58:46 1996
+++ linux/fs/umsdos/file.c	Sun Jan 26 12:07:46 1997
@@ -66,7 +66,7 @@
 	UMSDOS_file_read,	/* read */
 	UMSDOS_file_write,	/* write */
 	NULL,				/* readdir - bad */
-	NULL,				/* select - default */
+	NULL,				/* poll - default */
 	NULL,				/* ioctl - default */
 	generic_file_mmap,		/* mmap */
 	NULL,				/* no special open is needed */
@@ -100,7 +100,7 @@
 	UMSDOS_file_read,	/* read */
 	UMSDOS_file_write,	/* write */
 	NULL,				/* readdir - bad */
-	NULL,				/* select - default */
+	NULL,				/* poll - default */
 	NULL,				/* ioctl - default */
 	fat_mmap,			/* mmap */
 	NULL,				/* no special open is needed */
diff -u --recursive --new-file v2.1.22/linux/fs/umsdos/rdir.c linux/fs/umsdos/rdir.c
--- v2.1.22/linux/fs/umsdos/rdir.c	Tue Oct 29 19:58:46 1996
+++ linux/fs/umsdos/rdir.c	Sun Jan 26 12:07:46 1997
@@ -240,7 +240,7 @@
 	UMSDOS_dir_read,	/* read */
 	NULL,				/* write - bad */
 	UMSDOS_rreaddir,	/* readdir */
-	NULL,				/* select - default */
+	NULL,				/* poll - default */
 	UMSDOS_ioctl_dir,	/* ioctl - default */
 	NULL,				/* mmap */
 	NULL,				/* no special open code */
diff -u --recursive --new-file v2.1.22/linux/fs/umsdos/symlink.c linux/fs/umsdos/symlink.c
--- v2.1.22/linux/fs/umsdos/symlink.c	Tue Oct 29 19:58:46 1996
+++ linux/fs/umsdos/symlink.c	Sun Jan 26 12:07:46 1997
@@ -116,7 +116,7 @@
 	NULL,				/* read */
 	NULL,				/* write */
 	NULL,				/* readdir - bad */
-	NULL,				/* select - default */
+	NULL,				/* poll - default */
 	NULL,				/* ioctl - default */
 	NULL,				/* mmap */
 	NULL,				/* no special open is needed */
diff -u --recursive --new-file v2.1.22/linux/include/asm-alpha/cache.h linux/include/asm-alpha/cache.h
--- v2.1.22/linux/include/asm-alpha/cache.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-alpha/cache.h	Sun Jan 26 12:07:46 1997
@@ -0,0 +1,12 @@
+/*
+ * include/asm-alpha/cache.h
+ */
+#ifndef __ARCH_ALPHA_CACHE_H
+#define __ARCH_ALPHA_CACHE_H
+
+/* bytes per L1 cache line */
+#define        L1_CACHE_BYTES  32      /* a guess */
+
+#define        L1_CACHE_ALIGN(x)       (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1))
+
+#endif
diff -u --recursive --new-file v2.1.22/linux/include/asm-alpha/ipsum.h linux/include/asm-alpha/ipsum.h
--- v2.1.22/linux/include/asm-alpha/ipsum.h	Fri Jun  2 13:51:16 1995
+++ linux/include/asm-alpha/ipsum.h	Thu Jan  1 02:00:00 1970
@@ -1,45 +0,0 @@
-#ifndef __ASM_IPSUM_H
-#define __ASM_IPSUM_H
-
-/*
- *	This routine computes a UDP checksum. 
- */
-extern inline unsigned short udp_check(struct udphdr *uh, int len, u32 saddr, u32 daddr)
-{
-	/* uhh.. eventually */
-	return 0;
-}
-
-/*
- *	This routine computes a TCP checksum. 
- */
-extern inline unsigned short tcp_check(struct tcphdr *th, int len, u32 saddr, u32 daddr)
-{     
-	/* uhh.. eventually */
-	return 0;
-}
-
-
-/*
- * This routine does all the checksum computations that don't
- * require anything special (like copying or special headers).
- */
-
-extern inline unsigned short ip_compute_csum(unsigned char * buff, int len)
-{
-	/* uhh.. eventually */
-	return 0;
-}
-
-/*
- *	This is a version of ip_compute_csum() optimized for IP headers, which
- *	always checksum on 4 octet boundaries.
- */
-
-static inline unsigned short ip_fast_csum(unsigned char * buff, int wlen)
-{
-	/* uhh.. eventually */
-	return 0;
-}
-
-#endif
diff -u --recursive --new-file v2.1.22/linux/include/asm-alpha/namei.h linux/include/asm-alpha/namei.h
--- v2.1.22/linux/include/asm-alpha/namei.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-alpha/namei.h	Sun Jan 26 12:07:46 1997
@@ -0,0 +1,21 @@
+/* $Id: namei.h,v 1.1 1996/12/13 14:48:23 jj Exp $
+ * linux/include/asm-alpha/namei.h
+ *
+ * Included from linux/fs/namei.c
+ */
+
+#ifndef __ALPHA_NAMEI_H
+#define __ALPHA_NAMEI_H
+
+/* These dummy routines maybe changed to something useful
+ * for /usr/gnemul/ emulation stuff.
+ * Look at asm-sparc/namei.h for details.
+ */
+
+#define translate_namei(pathname, base, follow_links, res_inode)	\
+	do { } while (0)
+
+#define translate_open_namei(pathname, flag, mode, res_inode, base) \
+	do { } while (0)
+
+#endif /* __ALPHA_NAMEI_H */
diff -u --recursive --new-file v2.1.22/linux/include/asm-alpha/poll.h linux/include/asm-alpha/poll.h
--- v2.1.22/linux/include/asm-alpha/poll.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-alpha/poll.h	Thu Jan 23 21:01:28 1997
@@ -0,0 +1,22 @@
+#ifndef __ALPHA_POLL_H
+#define __ALPHA_POLL_H
+
+#define POLLIN		1
+#define POLLPRI		2
+#define POLLOUT		4
+#define POLLERR		8
+#define POLLHUP		16
+#define POLLNVAL	32
+#define POLLRDNORM	64
+#define POLLRDBAND	128
+#define POLLWRNORM	256
+#define POLLWRBAND	512
+#define POLLMSG		1024
+
+struct pollfd {
+	int fd;
+	short events;
+	short revents;
+};
+
+#endif
diff -u --recursive --new-file v2.1.22/linux/include/asm-alpha/processor.h linux/include/asm-alpha/processor.h
--- v2.1.22/linux/include/asm-alpha/processor.h	Tue Dec 31 21:41:08 1996
+++ linux/include/asm-alpha/processor.h	Sun Jan 26 12:07:46 1997
@@ -58,9 +58,6 @@
 	0 \
 }
 
-#define alloc_kernel_stack()    __get_free_page(GFP_KERNEL)
-#define free_kernel_stack(page) free_page((page))
-
 #include <asm/ptrace.h>
 
 /*
@@ -83,5 +80,14 @@
  * Do necessary setup to start up a newly executed thread.
  */
 extern void start_thread(struct pt_regs *, unsigned long, unsigned long);
+
+/* Free all resources held by a thread. */
+extern void release_thread(struct task_struct *);
+
+/* Allocation and freeing of basic task resources. */
+#define alloc_task_struct()	kmalloc(sizeof(struct task_struct), GFP_KERNEL)
+#define alloc_kernel_stack(p)	__get_free_page(GFP_KERNEL)
+#define free_task_struct(p)	kfree(p)
+#define free_kernel_stack(page) free_page((page))
 
 #endif /* __ASM_ALPHA_PROCESSOR_H */
diff -u --recursive --new-file v2.1.22/linux/include/asm-alpha/smp_lock.h linux/include/asm-alpha/smp_lock.h
--- v2.1.22/linux/include/asm-alpha/smp_lock.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-alpha/smp_lock.h	Sun Jan 26 13:40:46 1997
@@ -0,0 +1,15 @@
+#ifndef __ALPHA_SMPLOCK_H
+#define __ALPHA_SMPLOCK_H
+
+#ifndef __SMP__
+
+#define lock_kernel()		do { } while(0)
+#define unlock_kernel()		do { } while(0)
+
+#else
+
+#error "We do not support SMP on alpha yet"
+
+#endif /* __SMP__ */
+
+#endif /* __ALPHA_SMPLOCK_H */
diff -u --recursive --new-file v2.1.22/linux/include/asm-alpha/uaccess.h linux/include/asm-alpha/uaccess.h
--- v2.1.22/linux/include/asm-alpha/uaccess.h	Wed Jan 15 19:45:44 1997
+++ linux/include/asm-alpha/uaccess.h	Sun Jan 26 12:07:46 1997
@@ -71,6 +71,24 @@
   __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
 #define __get_user(x,ptr) \
   __get_user_nocheck((x),(ptr),sizeof(*(ptr)))
+  
+/*
+ * The "xxx_ret" versions return constant specified in third argument, if
+ * something bad happens. These macros can be optimized for the
+ * case of just returning from the function xxx_ret is used.
+ */
+
+#define put_user_ret(x,ptr,ret) ({ \
+if (put_user(x,ptr)) return ret; })
+
+#define get_user_ret(x,ptr,ret) ({ \
+if (get_user(x,ptr)) return ret; })
+
+#define __put_user_ret(x,ptr,ret) ({ \
+if (__put_user(x,ptr)) return ret; })
+
+#define __get_user_ret(x,ptr,ret) ({ \
+if (__get_user(x,ptr)) return ret; })
 
 /*
  * The "lda %1, 2b-1b(%0)" bits are magic to get the assembler to
@@ -353,6 +371,16 @@
 			: "$1","$2","$3","$4","$5","$28","memory");	    \
 	}								    \
 	__cu_len;							    \
+})
+
+#define copy_to_user_ret(to,from,n,retval) ({ \
+if (copy_to_user(to,from,n)) \
+	return retval; \
+})
+
+#define copy_from_user_ret(to,from,n,retval) ({ \
+if (copy_from_user(to,from,n)) \
+	return retval; \
 })
 
 extern void __clear_user(void);
diff -u --recursive --new-file v2.1.22/linux/include/asm-alpha/unistd.h linux/include/asm-alpha/unistd.h
--- v2.1.22/linux/include/asm-alpha/unistd.h	Mon Dec 30 15:39:14 1996
+++ linux/include/asm-alpha/unistd.h	Thu Jan 23 21:01:28 1997
@@ -1,54 +1,92 @@
 #ifndef _ALPHA_UNISTD_H
 #define _ALPHA_UNISTD_H
 
+#define __NR_osf_syscall	  0	/* not implemented */
 #define __NR_exit		  1
 #define __NR_fork		  2
 #define __NR_read		  3
 #define __NR_write		  4
+#define __NR_osf_old_open	  5	/* not implemented */
 #define __NR_close		  6
 #define __NR_wait4		  7
+#define __NR_osf_old_creat	  8	/* not implemented */
 #define __NR_link		  9
 #define __NR_unlink		 10
+#define __NR_osf_execve		 11	/* not implemented */
 #define __NR_chdir		 12
 #define __NR_fchdir		 13
 #define __NR_mknod		 14
 #define __NR_chmod		 15
 #define __NR_chown		 16
 #define __NR_brk		 17
+#define __NR_osf_getfsstat	 18	/* not implemented */
 #define __NR_lseek		 19
 #define __NR_getxpid		 20
+#define __NR_osf_mount		 21
+#define __NR_osf_umount		 22
 #define __NR_setuid		 23
 #define __NR_getxuid		 24
+#define __NR_exec_with_loader	 25	/* not implemented */
 #define __NR_ptrace		 26
+#define __NR_osf_nrecvmsg	 27	/* not implemented */
+#define __NR_osf_nsendmsg	 28	/* not implemented */
+#define __NR_osf_nrecvfrom	 29	/* not implemented */
+#define __NR_osf_naccept	 30	/* not implemented */
+#define __NR_osf_ngetpeername	 31	/* not implemented */
+#define __NR_osf_ngetsockname	 32	/* not implemented */
 #define __NR_access		 33
+#define __NR_osf_chflags	 34	/* not implemented */
+#define __NR_osf_fchflags	 35	/* not implemented */
 #define __NR_sync		 36
 #define __NR_kill		 37
+#define __NR_osf_old_stat	 38	/* not implemented */
 #define __NR_setpgid		 39
+#define __NR_osf_old_lstat	 40	/* not implemented */
 #define __NR_dup		 41
 #define __NR_pipe		 42
+#define __NR_osf_set_program_attributes	43
+#define __NR_osf_profil		 44	/* not implemented */
 #define __NR_open		 45
+#define __NR_osf_old_sigaction	 46	/* not implemented */
 #define __NR_getxgid		 47
+#define __NR_osf_sigprocmask	 48
+#define __NR_osf_getlogin	 49	/* not implemented */
+#define __NR_osf_setlogin	 50	/* not implemented */
 #define __NR_acct		 51
 #define __NR_sigpending		 52
+
 #define __NR_ioctl		 54
+#define __NR_osf_reboot		 55	/* not implemented */
+#define __NR_osf_revoke		 56	/* not implemented */
 #define __NR_symlink		 57
 #define __NR_readlink		 58
 #define __NR_execve		 59
 #define __NR_umask		 60
 #define __NR_chroot		 61
+#define __NR_osf_old_fstat	 62	/* not implemented */
 #define __NR_getpgrp		 63
 #define __NR_getpagesize	 64
+#define __NR_osf_mremap		 65	/* not implemented */
+#define __NR_osf_vfork		 66
 #define __NR_stat		 67
 #define __NR_lstat		 68
+#define __NR_osf_sbrk		 69	/* not implemented */
+#define __NR_osf_sstk		 70	/* not implemented */
 #define __NR_mmap		 71	/* OSF/1 mmap is superset of Linux */
+#define __NR_osf_old_vadvise	 72	/* not implemented */
 #define __NR_munmap		 73
 #define __NR_mprotect		 74
 #define __NR_madvise		 75
 #define __NR_vhangup		 76
+#define __NR_osf_kmodcall	 77	/* not implemented */
+#define __NR_osf_mincore	 78	/* not implemented */
 #define __NR_getgroups		 79
 #define __NR_setgroups		 80
+#define __NR_osf_old_getpgrp	 81	/* not implemented */
 #define __NR_setpgrp		 82	/* BSD alias for setpgid */
 #define __NR_setitimer		 83
+#define __NR_osf_old_wait	 84	/* not implemented */
+#define __NR_osf_table		 85	/* not implemented */
 #define __NR_getitimer		 86
 #define __NR_gethostname	 87
 #define __NR_sethostname	 88
@@ -57,6 +95,7 @@
 #define __NR_fstat		 91
 #define __NR_fcntl		 92
 #define __NR_select		 93
+#define __NR_poll		 94
 #define __NR_fsync		 95
 #define __NR_setpriority	 96
 #define __NR_socket		 97
@@ -69,12 +108,19 @@
 #define __NR_bind		104
 #define __NR_setsockopt		105
 #define __NR_listen		106
+#define __NR_osf_plock		107	/* not implemented */
+#define __NR_osf_old_sigvec	108	/* not implemented */
+#define __NR_osf_old_sigblock	109	/* not implemented */
+#define __NR_osf_old_sigsetmask	110	/* not implemented */
 #define __NR_sigsuspend		111
+#define __NR_osf_sigstack	112	/* not implemented */
 #define __NR_recvmsg		113
 #define __NR_sendmsg		114
+#define __NR_osf_old_vtrace	115	/* not implemented */
 #define __NR_gettimeofday	116
 #define __NR_getrusage		117
 #define __NR_getsockopt		118
+
 #define __NR_readv		120
 #define __NR_writev		121
 #define __NR_settimeofday	122
@@ -94,14 +140,44 @@
 #define __NR_mkdir		136
 #define __NR_rmdir		137
 #define __NR_utimes		138
+#define __NR_osf_old_sigreturn	139	/* not implemented */
+#define __NR_osf_adjtime	140	/* not implemented */
 #define __NR_getpeername	141
+#define __NR_osf_gethostid	142	/* not implemented */
+#define __NR_osf_sethostid	143	/* not implemented */
 #define __NR_getrlimit		144
 #define __NR_setrlimit		145
+#define __NR_osf_old_killpg	146	/* not implemented */
 #define __NR_setsid		147
 #define __NR_quotactl		148
+#define __NR_osf_oldquota	149	/* not implemented */
 #define __NR_getsockname	150
+
+#define __NR_osf_pid_block	153	/* not implemented */
+#define __NR_osf_pid_unblock	154	/* not implemented */
+
 #define __NR_sigaction		156
+#define __NR_osf_sigwaitprim	157	/* not implemented */
+#define __NR_osf_nfssvc		158	/* not implemented */
+#define __NR_osf_getdirentries	159
+#define __NR_osf_statfs		160
+#define __NR_osf_fstatfs	161
+
+#define __NR_osf_asynch_daemon	163	/* not implemented */
+#define __NR_osf_getfh		164	/* not implemented */	
+#define __NR_osf_getdomainname	165
 #define __NR_setdomainname	166
+
+#define __NR_osf_exportfs	169	/* not implemented */
+
+#define __NR_osf_alt_plock	181	/* not implemented */
+
+#define __NR_osf_getmnt		184	/* not implemented */
+
+#define __NR_osf_alt_sigpending	187	/* not implemented */
+#define __NR_osf_alt_setsid	188	/* not implemented */
+
+#define __NR_osf_swapon		199
 #define __NR_msgctl		200
 #define __NR_msgget		201
 #define __NR_msgrcv		202
@@ -109,16 +185,54 @@
 #define __NR_semctl		204
 #define __NR_semget		205
 #define __NR_semop		206
+#define __NR_osf_utsname	207
+#define __NR_osf_lchown		208	/* not implemented */
+#define __NR_osf_shmat		209
 #define __NR_shmctl		210
 #define __NR_shmdt		211
 #define __NR_shmget		212
-
+#define __NR_osf_mvalid		213	/* not implemented */
+#define __NR_osf_getaddressconf	214	/* not implemented */
+#define __NR_osf_msleep		215	/* not implemented */
+#define __NR_osf_mwakeup	216	/* not implemented */
 #define __NR_msync		217
+#define __NR_osf_signal		218	/* not implemented */
+#define __NR_osf_utc_gettime	219	/* not implemented */
+#define __NR_osf_utc_adjtime	220	/* not implemented */
+
+#define __NR_osf_security	222	/* not implemented */
+#define __NR_osf_kloadcall	223	/* not implemented */
 
 #define __NR_getpgid		233
 #define __NR_getsid		234
+#define __NR_osf_sigaltstack	235	/* not implemented */
+#define __NR_osf_waitid		236	/* not implemented */
+#define __NR_osf_priocntlset	237	/* not implemented */
+#define __NR_osf_sigsendset	238	/* not implemented */
+#define __NR_osf_set_speculative	239	/* not implemented */
+#define __NR_osf_msfs_syscall	240	/* not implemented */
+#define __NR_osf_sysinfo	241
+#define __NR_osf_uadmin		242	/* not implemented */
+#define __NR_osf_fuser		243	/* not implemented */
+#define __NR_osf_proplist_syscall    244
+#define __NR_osf_ntp_adjtime	245	/* not implemented */
+#define __NR_osf_ntp_gettime	246	/* not implemented */
+#define __NR_osf_pathconf	247	/* not implemented */
+#define __NR_osf_fpathconf	248	/* not implemented */
 
+#define __NR_osf_uswitch	250	/* not implemented */
+#define __NR_osf_usleep_thread	251
+#define __NR_osf_audcntl	252	/* not implemented */
+#define __NR_osf_audgen		253	/* not implemented */
 #define __NR_sysfs		254
+#define __NR_osf_subsys_info	255	/* not implemented */
+#define __NR_osf_getsysinfo	256
+#define __NR_osf_setsysinfo	257
+#define __NR_osf_afs_syscall	258	/* not implemented */
+#define __NR_osf_swapctl	259	/* not implemented */
+#define __NR_osf_memcntl	260	/* not implemented */
+#define __NR_osf_fdatasync	261	/* not implemented */
+
 
 /*
  * Linux-specific system calls begin at 300
diff -u --recursive --new-file v2.1.22/linux/include/asm-i386/cache.h linux/include/asm-i386/cache.h
--- v2.1.22/linux/include/asm-i386/cache.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-i386/cache.h	Sun Jan 26 12:07:46 1997
@@ -0,0 +1,16 @@
+/*
+ * include/asm-i386/cache.h
+ */
+#ifndef __ARCH_I386_CACHE_H
+#define __ARCH_I386_CACHE_H
+
+/* bytes per L1 cache line */
+#if    CPU==586 || CPU==686
+#define        L1_CACHE_BYTES  32
+#else
+#define        L1_CACHE_BYTES  16
+#endif
+
+#define        L1_CACHE_ALIGN(x)       (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1))
+
+#endif
diff -u --recursive --new-file v2.1.22/linux/include/asm-i386/irq.h linux/include/asm-i386/irq.h
--- v2.1.22/linux/include/asm-i386/irq.h	Thu Dec 12 19:37:18 1996
+++ linux/include/asm-i386/irq.h	Sun Jan 26 12:07:46 1997
@@ -126,20 +126,6 @@
 
 #ifdef	__SMP__
 
-#ifndef __SMP_PROF__
-#define SMP_PROF_INT_SPINS 
-#define SMP_PROF_IPI_CNT 
-#else
-#define SMP_PROF_INT_SPINS "incl "SYMBOL_NAME_STR(smp_spins)"(,%eax,4)\n\t"
-#define SMP_PROF_IPI_CNT "incl "SYMBOL_NAME_STR(ipi_count)"\n\t" 
-#endif
-
-#define GET_PROCESSOR_ID \
-	"movl "SYMBOL_NAME_STR(apic_reg)", %edx\n\t" \
-	"movl 32(%edx), %eax\n\t" \
-	"shrl $24,%eax\n\t" \
-	"andb $0x0F,%al\n\t"
-
 #define GET_CURRENT \
 	"movl "SYMBOL_NAME_STR(apic_reg)", %ebx\n\t" \
 	"movl 32(%ebx), %ebx\n\t" \
@@ -147,132 +133,15 @@
 	"andl $0x3C,%ebx\n\t" \
 	"movl " SYMBOL_NAME_STR(current_set) "(,%ebx),%ebx\n\t"
 	
-#define	ENTER_KERNEL \
-	"pushl %eax\n\t" \
-	"pushl %edx\n\t" \
-	"pushfl\n\t" \
-	"cli\n\t" \
-	GET_PROCESSOR_ID \
-	"btsl $" STR(SMP_FROM_INT) ","SYMBOL_NAME_STR(smp_proc_in_lock)"(,%eax,4)\n\t" \
-	"1: " \
-	"lock\n\t" \
-	"btsl $0, "SYMBOL_NAME_STR(kernel_flag)"\n\t" \
-	"jnc 3f\n\t" \
-	"cmpb "SYMBOL_NAME_STR(active_kernel_processor)", %al\n\t" \
-	"je 4f\n\t" \
-	"2: " \
-        SMP_PROF_INT_SPINS \
-	"btl %al, "SYMBOL_NAME_STR(smp_invalidate_needed)"\n\t" \
-	"jnc 5f\n\t" \
-	"lock\n\t" \
-	"btrl %al, "SYMBOL_NAME_STR(smp_invalidate_needed)"\n\t" \
-	"jnc 5f\n\t" \
-	"movl %cr3,%edx\n\t" \
-	"movl %edx,%cr3\n" \
-	"5: btl $0, "SYMBOL_NAME_STR(kernel_flag)"\n\t" \
-	"jc 2b\n\t" \
-	"jmp 1b\n\t" \
-	"3: " \
-	"movb %al, "SYMBOL_NAME_STR(active_kernel_processor)"\n\t" \
-	"4: " \
-	"incl "SYMBOL_NAME_STR(kernel_counter)"\n\t" \
-	"popfl\n\t" \
-	"popl %edx\n\t" \
-	"popl %eax\n\t"
+#else
 
-#define	LEAVE_KERNEL \
-	GET_PROCESSOR_ID \
-	"btrl $" STR(SMP_FROM_INT) ","SYMBOL_NAME_STR(smp_proc_in_lock)"(,%eax,4)\n\t" \
-	"pushfl\n\t" \
-	"cli\n\t" \
-	"decl "SYMBOL_NAME_STR(kernel_counter)"\n\t" \
-	"jnz 1f\n\t" \
-	"movb $" STR (NO_PROC_ID) ", "SYMBOL_NAME_STR(active_kernel_processor)"\n\t" \
-	"lock\n\t" \
-	"btrl $0, "SYMBOL_NAME_STR(kernel_flag)"\n\t" \
-	"1: " \
-	"popfl\n\t"
-	
-	
-/*
- *	the syscall count inc is a gross hack because ret_from_syscall is used by both irq and
- *	syscall return paths (urghh).
- */
- 
-#define BUILD_IRQ(chip,nr,mask) \
-asmlinkage void IRQ_NAME(nr); \
-asmlinkage void FAST_IRQ_NAME(nr); \
-asmlinkage void BAD_IRQ_NAME(nr); \
-__asm__( \
-"\n"__ALIGN_STR"\n" \
-SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \
-	"pushl $-"#nr"-2\n\t" \
-	SAVE_ALL \
-	ENTER_KERNEL \
-	ACK_##chip(mask,(nr&7)) \
-	"incl "SYMBOL_NAME_STR(intr_count)"\n\t"\
-	"sti\n\t" \
-	"movl %esp,%eax\n\t" \
-	"pushl %eax\n\t" \
-	"pushl $" #nr "\n\t" \
-	"call "SYMBOL_NAME_STR(do_IRQ)"\n\t" \
-	"addl $8,%esp\n\t" \
-	"cli\n\t" \
-	UNBLK_##chip(mask) \
-	"decl "SYMBOL_NAME_STR(intr_count)"\n\t" \
-	"incl "SYMBOL_NAME_STR(syscall_count)"\n\t" \
-	GET_CURRENT \
-	"jmp ret_from_sys_call\n" \
-"\n"__ALIGN_STR"\n" \
-SYMBOL_NAME_STR(fast_IRQ) #nr "_interrupt:\n\t" \
-	SAVE_MOST \
-	ENTER_KERNEL \
-	ACK_##chip(mask,(nr&7)) \
-	"incl "SYMBOL_NAME_STR(intr_count)"\n\t" \
-	"pushl $" #nr "\n\t" \
-	"call "SYMBOL_NAME_STR(do_fast_IRQ)"\n\t" \
-	"addl $4,%esp\n\t" \
-	"cli\n\t" \
-	UNBLK_##chip(mask) \
-	"decl "SYMBOL_NAME_STR(intr_count)"\n\t" \
-	LEAVE_KERNEL \
-	RESTORE_MOST \
-"\n"__ALIGN_STR"\n" \
-SYMBOL_NAME_STR(bad_IRQ) #nr "_interrupt:\n\t" \
-	SAVE_MOST \
-	ENTER_KERNEL \
-	ACK_##chip(mask,(nr&7)) \
-	LEAVE_KERNEL \
-	RESTORE_MOST);
+#define GET_CURRENT \
+	"movl " SYMBOL_NAME_STR(current_set) ",%ebx\n\t"
 	
- 
-#define BUILD_TIMER_IRQ(chip,nr,mask) \
-asmlinkage void IRQ_NAME(nr); \
-asmlinkage void FAST_IRQ_NAME(nr); \
-asmlinkage void BAD_IRQ_NAME(nr); \
-__asm__( \
-"\n"__ALIGN_STR"\n" \
-SYMBOL_NAME_STR(fast_IRQ) #nr "_interrupt:\n\t" \
-SYMBOL_NAME_STR(bad_IRQ) #nr "_interrupt:\n\t" \
-SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \
-	"pushl $-"#nr"-2\n\t" \
-	SAVE_ALL \
-	ENTER_KERNEL \
-	ACK_##chip(mask,(nr&7)) \
-	"incl "SYMBOL_NAME_STR(intr_count)"\n\t"\
-	"movl %esp,%eax\n\t" \
-	"pushl %eax\n\t" \
-	"pushl $" #nr "\n\t" \
-	"call "SYMBOL_NAME_STR(do_IRQ)"\n\t" \
-	"addl $8,%esp\n\t" \
-	"cli\n\t" \
-	UNBLK_##chip(mask) \
-	"decl "SYMBOL_NAME_STR(intr_count)"\n\t" \
-	"incl "SYMBOL_NAME_STR(syscall_count)"\n\t" \
-	GET_CURRENT \
-	"jmp ret_from_sys_call\n");
+#endif
+
+#ifdef __SMP__
 
-	
 /*
  *	Message pass must be a fast IRQ..
  */
@@ -286,9 +155,7 @@
 SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \
 	"pushl $-"#nr"-2\n\t" \
 	SAVE_ALL \
-	ENTER_KERNEL \
 	ACK_##chip(mask,(nr&7)) \
-	"incl "SYMBOL_NAME_STR(intr_count)"\n\t"\
 	"sti\n\t" \
 	"movl %esp,%eax\n\t" \
 	"pushl %eax\n\t" \
@@ -297,17 +164,11 @@
 	"addl $8,%esp\n\t" \
 	"cli\n\t" \
 	UNBLK_##chip(mask) \
-	GET_PROCESSOR_ID \
-	"btrl $" STR(SMP_FROM_INT) ","SYMBOL_NAME_STR(smp_proc_in_lock)"(,%eax,4)\n\t" \
-	"decl "SYMBOL_NAME_STR(intr_count)"\n\t" \
-	"incl "SYMBOL_NAME_STR(syscall_count)"\n\t" \
-	GET_CURRENT \
 	"jmp ret_from_sys_call\n" \
 "\n"__ALIGN_STR"\n" \
 SYMBOL_NAME_STR(fast_IRQ) #nr "_interrupt:\n\t" \
 	SAVE_MOST \
 	ACK_##chip(mask,(nr&7)) \
-	SMP_PROF_IPI_CNT \
 	"pushl $" #nr "\n\t" \
 	"call "SYMBOL_NAME_STR(do_fast_IRQ)"\n\t" \
 	"addl $4,%esp\n\t" \
@@ -327,8 +188,6 @@
 SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \
 	"pushl $-"#nr"-2\n\t" \
 	SAVE_ALL \
-	ENTER_KERNEL \
-	"incl "SYMBOL_NAME_STR(intr_count)"\n\t"\
 	"sti\n\t" \
 	"movl %esp,%eax\n\t" \
 	"pushl %eax\n\t" \
@@ -336,15 +195,10 @@
 	"call "SYMBOL_NAME_STR(smp_reschedule_irq)"\n\t" \
 	"addl $8,%esp\n\t" \
 	"cli\n\t" \
-	"decl "SYMBOL_NAME_STR(intr_count)"\n\t" \
-	"incl "SYMBOL_NAME_STR(syscall_count)"\n\t" \
-	GET_CURRENT \
 	"jmp ret_from_sys_call\n");
-#else
 
-#define GET_CURRENT \
-	"movl " SYMBOL_NAME_STR(current_set) ",%ebx\n\t"
-	
+#endif /* __SMP__ */
+
 #define BUILD_IRQ(chip,nr,mask) \
 asmlinkage void IRQ_NAME(nr); \
 asmlinkage void FAST_IRQ_NAME(nr); \
@@ -355,7 +209,6 @@
 	"pushl $-"#nr"-2\n\t" \
 	SAVE_ALL \
 	ACK_##chip(mask,(nr&7)) \
-	"incl "SYMBOL_NAME_STR(intr_count)"\n\t"\
 	"sti\n\t" \
 	"movl %esp,%eax\n\t" \
 	"pushl %eax\n\t" \
@@ -364,20 +217,16 @@
 	"addl $8,%esp\n\t" \
 	"cli\n\t" \
 	UNBLK_##chip(mask) \
-	"decl "SYMBOL_NAME_STR(intr_count)"\n\t" \
-	GET_CURRENT \
 	"jmp ret_from_sys_call\n" \
 "\n"__ALIGN_STR"\n" \
 SYMBOL_NAME_STR(fast_IRQ) #nr "_interrupt:\n\t" \
 	SAVE_MOST \
 	ACK_##chip(mask,(nr&7)) \
-	"incl "SYMBOL_NAME_STR(intr_count)"\n\t" \
 	"pushl $" #nr "\n\t" \
 	"call "SYMBOL_NAME_STR(do_fast_IRQ)"\n\t" \
 	"addl $4,%esp\n\t" \
 	"cli\n\t" \
 	UNBLK_##chip(mask) \
-	"decl "SYMBOL_NAME_STR(intr_count)"\n\t" \
 	RESTORE_MOST \
 "\n"__ALIGN_STR"\n" \
 SYMBOL_NAME_STR(bad_IRQ) #nr "_interrupt:\n\t" \
@@ -397,7 +246,6 @@
 	"pushl $-"#nr"-2\n\t" \
 	SAVE_ALL \
 	ACK_##chip(mask,(nr&7)) \
-	"incl "SYMBOL_NAME_STR(intr_count)"\n\t"\
 	"movl %esp,%eax\n\t" \
 	"pushl %eax\n\t" \
 	"pushl $" #nr "\n\t" \
@@ -405,9 +253,6 @@
 	"addl $8,%esp\n\t" \
 	"cli\n\t" \
 	UNBLK_##chip(mask) \
-	"decl "SYMBOL_NAME_STR(intr_count)"\n\t" \
-	GET_CURRENT \
 	"jmp ret_from_sys_call\n");
 
-#endif
-#endif
+#endif /* _ASM_IRQ_H */
diff -u --recursive --new-file v2.1.22/linux/include/asm-i386/namei.h linux/include/asm-i386/namei.h
--- v2.1.22/linux/include/asm-i386/namei.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-i386/namei.h	Sun Jan 26 12:07:46 1997
@@ -0,0 +1,21 @@
+/* $Id: namei.h,v 1.1 1996/12/13 14:48:21 jj Exp $
+ * linux/include/asm-i386/namei.h
+ *
+ * Included from linux/fs/namei.c
+ */
+
+#ifndef __I386_NAMEI_H
+#define __I386_NAMEI_H
+
+/* These dummy routines maybe changed to something useful
+ * for /usr/gnemul/ emulation stuff.
+ * Look at asm-sparc/namei.h for details.
+ */
+
+#define translate_namei(pathname, base, follow_links, res_inode)	\
+	do { } while (0)
+
+#define translate_open_namei(pathname, flag, mode, res_inode, base) \
+	do { } while (0)
+
+#endif /* __I386_NAMEI_H */
diff -u --recursive --new-file v2.1.22/linux/include/asm-i386/poll.h linux/include/asm-i386/poll.h
--- v2.1.22/linux/include/asm-i386/poll.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-i386/poll.h	Thu Jan 23 21:01:28 1997
@@ -0,0 +1,25 @@
+#ifndef __i386_POLL_H
+#define __i386_POLL_H
+
+/* These are specified by iBCS2 */
+#define POLLIN		0x0001
+#define POLLPRI		0x0002
+#define POLLOUT		0x0004
+#define POLLERR		0x0008
+#define POLLHUP		0x0010
+#define POLLNVAL	0x0020
+
+/* The rest seem to be more-or-less nonstandard. Check them! */
+#define POLLRDNORM	0x0040
+#define POLLRDBAND	0x0080
+#define POLLWRNORM	0x0100
+#define POLLWRBAND	0x0200
+#define POLLMSG		0x0400
+
+struct pollfd {
+	int fd;
+	short events;
+	short revents;
+};
+
+#endif
diff -u --recursive --new-file v2.1.22/linux/include/asm-i386/processor.h linux/include/asm-i386/processor.h
--- v2.1.22/linux/include/asm-i386/processor.h	Tue Dec 31 21:41:08 1996
+++ linux/include/asm-i386/processor.h	Sun Jan 26 12:07:46 1997
@@ -140,9 +140,6 @@
 	NULL, 0, 0, 0, 0 /* vm86_info */, \
 }
 
-#define alloc_kernel_stack()    __get_free_page(GFP_KERNEL)
-#define free_kernel_stack(page) free_page((page))
-
 #define start_thread(regs, new_eip, new_esp) do {\
 	unsigned long seg = USER_DS; \
 	__asm__("mov %w0,%%fs ; mov %w0,%%gs":"=r" (seg) :"0" (seg)); \
@@ -155,6 +152,9 @@
 	regs->esp = new_esp; \
 } while (0)
 
+/* Free all resources held by a thread. */
+extern void release_thread(struct task_struct *);
+
 /*
  * Return saved PC of a blocked thread.
  */
@@ -162,5 +162,11 @@
 {
 	return ((unsigned long *)t->esp)[3];
 }
+
+/* Allocation and freeing of basic task resources. */
+#define alloc_task_struct()	kmalloc(sizeof(struct task_struct), GFP_KERNEL)
+#define alloc_kernel_stack(p)	__get_free_page(GFP_KERNEL)
+#define free_task_struct(p)	kfree(p)
+#define free_kernel_stack(page) free_page((page))
 
 #endif /* __ASM_I386_PROCESSOR_H */
diff -u --recursive --new-file v2.1.22/linux/include/asm-i386/smp.h linux/include/asm-i386/smp.h
--- v2.1.22/linux/include/asm-i386/smp.h	Fri Apr 26 10:37:21 1996
+++ linux/include/asm-i386/smp.h	Sun Jan 26 12:21:08 1997
@@ -192,8 +192,6 @@
 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;
-extern volatile unsigned long syscall_count;
 
 /*
  *	General functions that each host system must provide.
@@ -204,7 +202,7 @@
 extern void smp_store_cpu_info(int id);		/* Store per cpu info (like the initial udelay numbers */
 
 extern volatile unsigned long smp_proc_in_lock[NR_CPUS]; /* for computing process time */
-extern volatile unsigned long smp_process_available;
+extern volatile int smp_process_available;
 
 /*
  *	APIC handlers: Note according to the Intel specification update
@@ -233,6 +231,52 @@
 extern __inline int smp_processor_id(void)
 {
 	return GET_APIC_ID(apic_read(APIC_ID));
+}
+
+/* These read/change the "processes available" counter in the scheduler. */
+extern __inline__ __volatile__ void inc_smp_counter(volatile int *ctr)
+{
+	int cpu = smp_processor_id();
+	while(set_bit(31, ctr))
+	{
+		while(test_bit(31,ctr))
+		{
+			if(clear_bit(cpu,&smp_invalidate_needed))
+			{
+				unsigned long tmpreg;
+				__asm__ __volatile__("movl %%cr3,%0\n\tmovl %0,%%cr3"
+						     : "=r" (tmpreg) : : "memory");
+				set_bit(cpu,&cpu_callin_map[0]);
+			}
+		}
+	}
+	*ctr = (*ctr + 1);
+	clear_bit(31, ctr);
+}
+
+extern __inline__ __volatile__ void dec_smp_counter(volatile int *ctr)
+{
+	int cpu = smp_processor_id();
+	while(set_bit(31, ctr))
+	{
+		while(test_bit(31,ctr))
+		{
+			if(clear_bit(cpu,&smp_invalidate_needed))
+			{
+				unsigned long tmpreg;
+				__asm__ __volatile__("movl %%cr3,%0\n\tmovl %0,%%cr3"
+						     : "=r" (tmpreg) : : "memory");
+				set_bit(cpu,&cpu_callin_map[0]);
+			}
+		}
+	}
+	*ctr = (*ctr - 1);
+	clear_bit(31, ctr);
+}
+
+extern __inline__ __volatile__ int read_smp_counter(volatile int *ctr)
+{
+	return (*ctr & 0x7fffffff);
 }
 
 #endif /* !ASSEMBLY */
diff -u --recursive --new-file v2.1.22/linux/include/asm-i386/smp_lock.h linux/include/asm-i386/smp_lock.h
--- v2.1.22/linux/include/asm-i386/smp_lock.h	Wed Apr  3 10:59:32 1996
+++ linux/include/asm-i386/smp_lock.h	Sun Jan 26 12:07:46 1997
@@ -1,69 +1,50 @@
 #ifndef __I386_SMPLOCK_H
 #define __I386_SMPLOCK_H
 
-#ifdef __SMP__
+#ifndef __SMP__
 
-/*
- *	Locking the kernel 
- */
- 
-extern __inline void lock_kernel(void)
+#define lock_kernel()		do { } while(0)
+#define unlock_kernel()		do { } while(0)
+
+#else
+
+/* Locking the kernel */
+extern __inline__ void lock_kernel(void)
 {
-	unsigned long flags;
-	int proc = smp_processor_id();
+	int cpu = smp_processor_id();
 
-	save_flags(flags);
-	cli();
-	/* set_bit works atomic in SMP machines */
-	while(set_bit(0, (void *)&kernel_flag)) 
-	{
-		/*
-		 *	We just start another level if we have the lock 
-		 */
-		if (proc == active_kernel_processor)
-			break;
-		do 
-		{
-#ifdef __SMP_PROF__		
-			smp_spins[smp_processor_id()]++;
-#endif			
-			/*
-			 *	Doing test_bit here doesn't lock the bus 
-			 */
-			if (test_bit(proc, (void *)&smp_invalidate_needed))
-				if (clear_bit(proc, (void *)&smp_invalidate_needed))
-					local_flush_tlb();
-		}
-		while(test_bit(0, (void *)&kernel_flag));
-	}
-	/* 
-	 *	We got the lock, so tell the world we are here and increment
-	 *	the level counter 
-	 */
-	active_kernel_processor = proc;
-	kernel_counter++;
-	restore_flags(flags);
+	__asm__ __volatile__("
+	pushfl
+	cli
+	cmpl	$0, %0
+	jne	0f
+	movl	$0f, %%eax
+	jmp	__lock_kernel
+0:
+	incl	%0
+	popfl
+"	:
+	: "m" (current_set[cpu]->lock_depth), "d" (cpu)
+	: "ax", "memory");
 }
 
-extern __inline void unlock_kernel(void)
+extern __inline__ void unlock_kernel(void)
 {
-	unsigned long flags;
-	save_flags(flags);
-	cli();
-	/*
-	 *	If it's the last level we have in the kernel, then
-	 *	free the lock 
-	 */
-	if (kernel_counter == 0)
-		panic("Kernel counter wrong.\n"); /* FIXME: Why is kernel_counter sometimes 0 here? */
-	
-	if(! --kernel_counter) 
-	{
-		active_kernel_processor = NO_PROC_ID;
-		clear_bit(0, (void *)&kernel_flag);
-	}
-	restore_flags(flags);
+	__asm__ __volatile__("
+	pushfl
+	cli
+	decl	%0
+	jnz	1f
+	movb	%1, active_kernel_processor
+	lock
+	btrl	$0, kernel_flag
+1:
+	popfl
+"	: /* no outputs */
+	: "m" (current->lock_depth), "i" (NO_PROC_ID)
+	: "ax", "memory");
 }
 
-#endif
-#endif
+#endif /* __SMP__ */
+
+#endif /* __I386_SMPLOCK_H */
diff -u --recursive --new-file v2.1.22/linux/include/asm-i386/system.h linux/include/asm-i386/system.h
--- v2.1.22/linux/include/asm-i386/system.h	Tue Sep 24 14:07:21 1996
+++ linux/include/asm-i386/system.h	Sun Jan 26 12:07:46 1997
@@ -74,9 +74,6 @@
 		__asm__ __volatile__("fwait"); \
 		prev->flags&=~PF_USEDFPU;	 \
 	} \
-	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" \
diff -u --recursive --new-file v2.1.22/linux/include/asm-i386/uaccess.h linux/include/asm-i386/uaccess.h
--- v2.1.22/linux/include/asm-i386/uaccess.h	Wed Jan 15 19:45:44 1997
+++ linux/include/asm-i386/uaccess.h	Sun Jan 26 12:21:22 1997
@@ -108,6 +108,25 @@
 #define __put_user(x,ptr) \
   __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
 
+/*
+ * The "xxx_ret" versions return constant specified in third argument, if
+ * something bad happens. These macros can be optimized for the
+ * case of just returning from the function xxx_ret is used.
+ */
+
+#define put_user_ret(x,ptr,ret) ({ \
+if (put_user(x,ptr)) return ret; })
+
+#define get_user_ret(x,ptr,ret) ({ \
+if (get_user(x,ptr)) return ret; })
+
+#define __put_user_ret(x,ptr,ret) ({ \
+if (__put_user(x,ptr)) return ret; })
+
+#define __get_user_ret(x,ptr,ret) ({ \
+if (__get_user(x,ptr)) return ret; })
+
+
 
 extern long __put_user_bad(void);
 
@@ -387,6 +406,15 @@
 	 __constant_copy_from_user((to),(from),(n)) :	\
 	 __generic_copy_from_user((to),(from),(n)))
 
+#define copy_to_user_ret(to,from,n,retval) ({ \
+if (copy_to_user(to,from,n)) \
+	return retval; \
+})
+
+#define copy_from_user_ret(to,from,n,retval) ({ \
+if (copy_from_user(to,from,n)) \
+	return retval; \
+})
 
 #define __copy_to_user(to,from,n)			\
 	(__builtin_constant_p(n) ?			\
diff -u --recursive --new-file v2.1.22/linux/include/asm-i386/unistd.h linux/include/asm-i386/unistd.h
--- v2.1.22/linux/include/asm-i386/unistd.h	Tue Dec 31 21:41:08 1996
+++ linux/include/asm-i386/unistd.h	Thu Jan 23 21:01:28 1997
@@ -173,6 +173,7 @@
 #define __NR_getresuid		165
 #define __NR_vm86		166
 #define __NR_query_module	167
+#define __NR_poll		168
 
 /* user-visible error numbers are in the range -1 - -122: see <asm-i386/errno.h> */
 
diff -u --recursive --new-file v2.1.22/linux/include/asm-m68k/cache.h linux/include/asm-m68k/cache.h
--- v2.1.22/linux/include/asm-m68k/cache.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/cache.h	Sun Jan 26 12:07:46 1997
@@ -0,0 +1,12 @@
+/*
+ * include/asm-m68k/cache.h
+ */
+#ifndef __ARCH_M68K_CACHE_H
+#define __ARCH_M68K_CACHE_H
+
+/* bytes per L1 cache line */
+#define        L1_CACHE_BYTES  32      /* a guess */
+
+#define        L1_CACHE_ALIGN(x)       (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1))
+
+#endif
diff -u --recursive --new-file v2.1.22/linux/include/asm-m68k/processor.h linux/include/asm-m68k/processor.h
--- v2.1.22/linux/include/asm-m68k/processor.h	Tue Dec 31 21:41:08 1996
+++ linux/include/asm-m68k/processor.h	Sun Jan 26 12:07:46 1997
@@ -54,9 +54,6 @@
 	{0, 0}, 0, {0,}, {0, 0, 0}, {0,}, \
 }
 
-#define alloc_kernel_stack()    __get_free_page(GFP_KERNEL)
-#define free_kernel_stack(page) free_page((page))
-
 /*
  * Do necessary setup to start up a newly executed thread.
  */
@@ -78,6 +75,9 @@
 	wrusp(usp);
 }
 
+/* Free all resources held by a thread. */
+extern void release_thread(struct task_struct *);
+
 /*
  * Return saved PC of a blocked thread.
  */
@@ -93,5 +93,11 @@
 	else
 		return sw->retpc;
 }
+
+/* Allocation and freeing of basic task resources. */
+#define alloc_task_struct()	kmalloc(sizeof(struct task_struct), GFP_KERNEL)
+#define alloc_kernel_stack(p)	__get_free_page(GFP_KERNEL)
+#define free_task_struct(p)	kfree(p)
+#define free_kernel_stack(page) free_page((page))
 
 #endif
diff -u --recursive --new-file v2.1.22/linux/include/asm-mips/cache.h linux/include/asm-mips/cache.h
--- v2.1.22/linux/include/asm-mips/cache.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-mips/cache.h	Sun Jan 26 12:07:46 1997
@@ -0,0 +1,12 @@
+/*
+ * include/asm-mips/cache.h
+ */
+#ifndef __ARCH_MIPS_CACHE_H
+#define __ARCH_MIPS_CACHE_H
+
+/* bytes per L1 cache line */
+#define        L1_CACHE_BYTES  32      /* a guess */
+
+#define        L1_CACHE_ALIGN(x)       (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1))
+
+#endif
diff -u --recursive --new-file v2.1.22/linux/include/asm-mips/processor.h linux/include/asm-mips/processor.h
--- v2.1.22/linux/include/asm-mips/processor.h	Tue Dec 31 21:41:09 1996
+++ linux/include/asm-mips/processor.h	Sun Jan 26 12:07:46 1997
@@ -193,6 +193,9 @@
 	regs->reg29 = sp;
 }
 
+/* Free all resources held by a thread. */
+extern void release_thread(struct task_struct *);
+
 #ifdef __KERNEL__
 
 /*
diff -u --recursive --new-file v2.1.22/linux/include/asm-ppc/cache.h linux/include/asm-ppc/cache.h
--- v2.1.22/linux/include/asm-ppc/cache.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-ppc/cache.h	Sun Jan 26 12:07:47 1997
@@ -0,0 +1,12 @@
+/*
+ * include/asm-ppc/cache.h
+ */
+#ifndef __ARCH_PPC_CACHE_H
+#define __ARCH_PPC_CACHE_H
+
+/* bytes per L1 cache line */
+#define        L1_CACHE_BYTES  32      /* a guess */
+
+#define        L1_CACHE_ALIGN(x)       (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1))
+
+#endif
diff -u --recursive --new-file v2.1.22/linux/include/asm-ppc/processor.h linux/include/asm-ppc/processor.h
--- v2.1.22/linux/include/asm-ppc/processor.h	Tue Dec 31 21:41:09 1996
+++ linux/include/asm-ppc/processor.h	Sun Jan 26 12:07:47 1997
@@ -118,15 +118,8 @@
 #define INIT_MMAP { &init_mm, 0, 0x40000000, \
 		      PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC }
 
-#ifdef KERNEL_STACK_BUFFER
-/* give a 1 page buffer below the stack - if change then change ppc_machine.h */
-#define alloc_kernel_stack()  \
-          (memset((void *)__get_free_pages(GFP_KERNEL,1,0),0,KERNEL_STACK_SIZE+PAGE_SIZE)+PAGE_SIZE)
-#define free_kernel_stack(page) free_pages((page)-PAGE_SIZE,1)
-#else
-#define alloc_kernel_stack()    get_free_page(GFP_KERNEL)
-#define free_kernel_stack(page) free_page((page))
-#endif
+/* Free all resources held by a thread. */
+extern void release_thread(struct task_struct *);
 
 /*
  * Return saved PC of a blocked thread. For now, this is the "user" PC
@@ -141,6 +134,20 @@
 #define _PROC_Be       2
 
 int _Processor;
+
+/* Allocation and freeing of basic task resources. */
+#define alloc_task_struct()	kmalloc(sizeof(struct task_struct), GFP_KERNEL)
+#define free_task_struct(p)	kfree(p)
+
+#ifdef KERNEL_STACK_BUFFER
+/* give a 1 page buffer below the stack - if change then change ppc_machine.h */
+#define alloc_kernel_stack()  \
+          (memset((void *)__get_free_pages(GFP_KERNEL,1,0),0,KERNEL_STACK_SIZE+PAGE_SIZE)+PAGE_SIZE)
+#define free_kernel_stack(page) free_pages((page)-PAGE_SIZE,1)
+#else
+#define alloc_kernel_stack()    get_free_page(GFP_KERNEL)
+#define free_kernel_stack(page) free_page((page))
+#endif
 
 #endif /* ASSEMBLY*/
 
diff -u --recursive --new-file v2.1.22/linux/include/asm-sparc/ap1000/DdvReqTable.h linux/include/asm-sparc/ap1000/DdvReqTable.h
--- v2.1.22/linux/include/asm-sparc/ap1000/DdvReqTable.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/ap1000/DdvReqTable.h	Sun Jan 26 12:07:47 1997
@@ -0,0 +1,107 @@
+  /*
+   * Copyright 1996 The Australian National University.
+   * Copyright 1996 Fujitsu Laboratories Limited
+   * 
+   * This software may be distributed under the terms of the Gnu
+   * Public License version 2 or later
+  */
+/*
+ *	Request table size
+ */
+
+#define	TABLE_SIZE	200
+
+/*
+ *	Indirect memory address table size
+ */
+
+#define	MTABLE_SIZE	1000
+
+static inline int INC_T(int a)
+{
+	return (++a == TABLE_SIZE?0:a);
+}
+
+static inline int INC_ML(int a)
+{
+	return (++a == MTABLE_SIZE?0:a);
+}
+
+/*
+ *	Status of requiest table
+ */
+
+#define	DDV_ERROR_RETURN	0
+#define	DDV_NORMAL_RETURN	1
+#define	DDV_REQ_FREE		2
+#define DDV_DISKREAD_REQ	3
+#define	DDV_DISKWRITE_REQ	4
+#define DDV_RAWREAD_REQ		5
+#define	DDV_RAWWRITE_REQ	6
+#define DDV_CACHEPOSTALL_REQ    11
+#define DDV_CACHEFLUSHALL_REQ    12
+#define DDV_CAPACITY_REQ        13
+
+/*
+ *      Specify type of interrupt (set by opiu in PBUF1)
+ */
+
+#define DDV_PRINTK_INTR  1
+#define DDV_MLIST_INTR   2
+#define DDV_READY_INTR   3
+#define DDV_REQCOMP_INTR 4 
+
+struct  RequestInformation {
+	volatile int	status;
+	int rtn;
+	unsigned bnum;
+	int argv[8];
+};
+
+struct DiskInfo {
+  u_long blocks;
+  u_long blk_size;
+  int pad[8];
+  unsigned ptrs[4];
+};
+
+struct RequestTable{
+  volatile unsigned cell_pointer;	/* Cell requiest pointer */
+  volatile unsigned ddv_pointer;	/* DDV operation pointer */
+  struct  RequestInformation async_info[TABLE_SIZE];
+  volatile unsigned start_mtable;
+  volatile unsigned end_mtable;
+  unsigned mtable[MTABLE_SIZE];
+};
+
+#define PRINT_BUFS 32
+
+struct OPrintBuf {
+  char *fmt;
+  int args[6];
+};
+
+struct OPrintBufArray {
+  volatile unsigned option_counter;
+  volatile unsigned cell_counter;
+  struct OPrintBuf bufs[PRINT_BUFS];  
+};
+
+#define ALIGN_SIZE 16
+#define ALIGN_BUFS 128
+#define ALIGN_BUF_SIZE 1024
+
+struct AlignBuf {
+  char *dest;
+  unsigned size;
+  int offset;
+  char buf[ALIGN_BUF_SIZE+2*ALIGN_SIZE];
+};
+
+struct OAlignBufArray {
+  volatile unsigned option_counter;
+  volatile unsigned cell_counter;
+  struct AlignBuf bufs[ALIGN_BUFS];
+};
+
+
diff -u --recursive --new-file v2.1.22/linux/include/asm-sparc/ap1000/apbif.h linux/include/asm-sparc/ap1000/apbif.h
--- v2.1.22/linux/include/asm-sparc/ap1000/apbif.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/ap1000/apbif.h	Sun Jan 26 12:07:47 1997
@@ -0,0 +1,205 @@
+  /*
+   * Copyright 1996 The Australian National University.
+   * Copyright 1996 Fujitsu Laboratories Limited
+   * 
+   * This software may be distributed under the terms of the Gnu
+   * Public License version 2 or later
+  */
+
+/*
+**	BIF data registers (system mode)
+*/
+#define BIF_DATA 	(BIF+0x0000)	/* BIF send and receive data registe	*/
+#define BIF_EDATA  	(BIF+0x0004)	/* BIF end data register 				*/
+/*
+**	BIF data registers (user mode) 
+*/
+#define UBIF_DATA 	(UBIF+0x0000)	/* BIF send and receive data registe	*/
+#define UBIF_EDATA  (UBIF+0x0004)	/* BIF end data register 				*/
+
+/*
+**	BIF scatter and gather parameter register (system mode) 
+*/
+#define BIF_X0SK 	(BIF+0x0010)	/* initial X-skip register 			*/
+#define BIF_XSK 	(BIF+0x0014)	/* X-skip register 					*/
+#define BIF_XSZ 	(BIF+0x0018)	/* X-size register 					*/
+
+#define BIF_Y0SK 	(BIF+0x001c)	/* initial Y-skip register 			*/
+#define BIF_YSK 	(BIF+0x0020)	/* Y-skip register 					*/
+#define BIF_YSZ 	(BIF+0x0024)	/* Y-size register 					*/
+
+#define BIF_CX0SK 	(BIF+0x0028)	/* initial counter of X-skip 		*/
+#define BIF_CXSK 	(BIF+0x002c)	/* X-skip counter 					*/
+#define BIF_CXSZ 	(BIF+0x0030)	/* X-size counter 					*/
+
+#define BIF_CY0SK 	(BIF+0x0034)	/* initial counter of Y-skip 		*/
+#define BIF_CYSK 	(BIF+0x0038)	/* Y-skip counter 					*/
+#define BIF_CYSZ 	(BIF+0x003c)	/* Y-size counter 					*/
+
+#define BIF_TTL 	(BIF+0x0040)	/* number of data transfer register */
+#define BIF_CTTL 	(BIF+0x0044)	/* number of data transfer counter	*/
+
+/*
+**	BIF scatter and gather parameter register (user mode) 
+*/
+#define UBIF_X0SK 	(UBIF+0x0010)	/* initial X-skip register 			*/
+#define UBIF_XSK 	(UBIF+0x0014)	/* X-skip register 					*/
+#define UBIF_XSZ 	(UBIF+0x0018)	/* X-size register 					*/
+
+#define UBIF_Y0SK 	(UBIF+0x001c)	/* initial Y-skip register 			*/
+#define UBIF_YSK 	(UBIF+0x0020)	/* Y-skip register 					*/
+#define UBIF_YSZ 	(UBIF+0x0024)	/* Y-size register 					*/
+
+#define UBIF_CX0SK 	(UBIF+0x0028)	/* initial counter of X-skip 		*/
+#define UBIF_CXSK 	(UBIF+0x002c)	/* X-skip counter 					*/
+#define UBIF_CXSZ 	(UBIF+0x0030)	/* X-size counter 					*/
+
+#define UBIF_CY0SK 	(UBIF+0x0034)	/* initial counter of Y-skip 		*/
+#define UBIF_CYSK 	(UBIF+0x0038)	/* Y-skip counter 					*/
+#define UBIF_CYSZ 	(UBIF+0x003c)	/* Y-size counter 					*/
+
+#define UBIF_TTL 	(UBIF+0x0040)	/* number of data transfer register */
+#define UBIF_CTTL 	(UBIF+0x0044)	/* number of data transfer counter	*/
+
+/*
+**	BIF control registers (system mode)
+*/
+#define BIF_CIDR0 	(BIF+0x0048)	/* cell-id register 0 					*/
+#define BIF_CIDR1 	(BIF+0x004c)	/* cell-id register 1 (for cell mode) 	*/
+#define BIF_CIDR2 	(BIF+0x0050)	/* cell-id register 2 					*/
+#define BIF_CIDR3 	(BIF+0x0054)	/* cell-id register 3 					*/
+#define BIF_HEADER 	(BIF+0x0058)	/* header register 						*/
+#define BIF_INTR 	(BIF+0x006c)	/* BIF interrupt control register 		*/
+#define BIF_SDCSR 	(BIF+0x0070)	/* BIF data control set register 		*/
+#define BIF_RDCSR 	(BIF+0x0074)	/* BIF data control reset reregister	*/
+#define BIF_MHOCR 	(BIF+0x0078)	/* BIF extentional control reregister 	*/
+
+/*
+**	BIF control registers (user mode)
+*/
+#define UBIF_CIDR0 	(UBIF+0x0048)	/* cell-id register 0 					*/
+#define UBIF_CIDR1 	(UBIF+0x004c)	/* cell-id register 1 (for cell mode) 	*/
+#define UBIF_CIDR2 	(UBIF+0x0050)	/* cell-id register 2 					*/
+#define UBIF_CIDR3 	(UBIF+0x0054)	/* cell-id register 3 					*/
+#define UBIF_HEADER (UBIF+0x0058)	/* header register 						*/
+#define UBIF_INTR 	(UBIF+0x006c)	/* BIF interrupt control register 		*/
+#define UBIF_SDCSR 	(UBIF+0x0070)	/* BIF data control set register 		*/
+#define UBIF_RDCSR 	(UBIF+0x0074)	/* BIF data control reset reregister	*/
+#define UBIF_MHOCR 	(UBIF+0x0078)	/* BIF extentional control reregister 	*/
+
+/*
+** bit assignment 
+*/
+#define BIF_HEADER_ID	 0xffff0000	/* cell-id   		*/
+#define BIF_HEADER_BR	 0x00008000	/* broad bit 		*/
+#define BIF_HEADER_IS	 0x00006000	/* ID select		*/
+#define BIF_HEADER_IS_00 0x00000000 
+#define BIF_HEADER_IS_01 0x00002000 
+#define BIF_HEADER_IS_10 0x00004000 
+#define BIF_HEADER_IS_11 0x00006000 
+#define BIF_HEADER_IN	 0x00001000	/* interrupt bit	*/
+#define BIF_HEADER_LS	 0x00000800	/* line send		*/
+#define BIF_HEADER_SC	 0x00000400	/* scatter bit 		*/
+#define BIF_HEADER_HS	 0x00000200	/* header strip		*/
+#define BIF_HEADER_RS	 0x00000100	/* bus release 		*/
+
+#define BIF_HEADER_ID_SHIFT 16
+
+#define BIF_INTR_GS		0x00020000	/* grant interrupt select 		*/
+#define BIF_INTR_GM		0x00010000	/* grant interrupt mask			*/
+#define BIF_INTR_GI		0x00008000	/* grant interrupt request		*/
+#define BIF_INTR_HS		0x00004000	/* header interrupt select		*/
+#define BIF_INTR_HM		0x00002000	/* header interrupt mask		*/
+#define BIF_INTR_HI		0x00001000	/* header interrupt request		*/
+#define BIF_INTR_SS		0x00000800	/* send interrupt select		*/
+#define BIF_INTR_SM		0x00000400	/* send interrupt mask			*/
+#define BIF_INTR_SI		0x00000200	/* send interrupt request		*/
+#define BIF_INTR_RS		0x00000100	/* receive interrupt select		*/
+#define BIF_INTR_RM		0x00000080	/* receive interrupt mask		*/
+#define BIF_INTR_RI		0x00000040	/* receive interrupt request	*/
+#define BIF_INTR_ES		0x00000020	/* error interrupt select 		*/
+#define BIF_INTR_EM		0x00000010	/* error interrupt mask 		*/
+#define BIF_INTR_EI		0x00000008	/* error interrupt request 		*/
+#define BIF_INTR_AS		0x00000004	/* attention interrupt select 	*/
+#define BIF_INTR_AM		0x00000002	/* attention interrupt mask 	*/
+#define BIF_INTR_AI		0x00000001	/* attention interrupt request  */
+
+#define BIF_SDCSR_ER    0x7fffc000  /* error  detected by BIF */
+#define BIF_SDCSR_PE	0x80000000	/* detect parity error in sync			*/
+#define BIF_SDCSR_SP	0x40000000	/* parity error in sync					*/
+#define BIF_SDCSR_LP	0x20000000	/* L-bus parity error					*/
+#define BIF_SDCSR_LR	0x10000000	/* */
+#define BIF_SDCSR_LW	0x08000000	/* */
+#define BIF_SDCSR_AL	0x04000000	/* specify end bit except of end data	*/
+#define BIF_SDCSR_SS	0x02000000	/* request bit but masked by slow sync	*/
+#define BIF_SDCSR_SC	0x01000000	/* clear bit but masked by slow sync	*/
+#define BIF_SDCSR_SY	0x00800000	/* set bit but masked by slow status	*/
+#define BIF_SDCSR_FS	0x00400000	/* request bit but masked by fast sync	*/
+#define BIF_SDCSR_FC	0x00200000	/* clear bit but masked by fast sync	*/
+#define BIF_SDCSR_FY	0x00100000	/* set bit but masked by fast status	*/
+#define BIF_SDCSR_CP	0x00080000	/* parity error in commnad bus			*/
+#define BIF_SDCSR_FP	0x00040000	/* execute scatter or gather but FN=0	*/
+#define BIF_SDCSR_PS	0x00020000	/* header receive error 				*/
+#define BIF_SDCSR_RA	0x00010000	/* change scatter,gather parameter		*/
+#define BIF_SDCSR_PA	0x00008000	/* check if send or receive error		*/
+#define BIF_SDCSR_DL	0x00004000	/* lost data							*/
+#define BIF_SDCSR_BB	0x00002000	/* check if some BIF use command bus	*/
+#define BIF_SDCSR_BG	0x00001000	/* check if command bus got				*/
+#define BIF_SDCSR_BR	0x00000800	/* request command bus					*/
+#define BIF_SDCSR_CN	0x00000400	/* release BIF from command bus			*/
+#define BIF_SDCSR_FN	0x00000200	/* scatter gather enable				*/
+#define BIF_SDCSR_EB	0x00000100	/* send data that have end bit			*/
+#define BIF_SDCSR_TB	0x000000E0	/* data in send FIFO					*/
+#define BIF_SDCSR_TB4	0x00000080
+#define BIF_SDCSR_TB2	0x00000040
+#define BIF_SDCSR_TB1	0x00000020
+#define BIF_SDCSR_RB	0x0000001c	/* data in receive FIFO					*/
+#define BIF_SDCSR_RB4	0x00000010
+#define BIF_SDCSR_RB2	0x00000008	
+#define BIF_SDCSR_RB1	0x00000004	
+#define BIF_SDCSR_DE	0x00000002	/* DMA interface enable bitr			*/
+#define BIF_SDCSR_DR	0x00000001	/* data transfer direction				*/
+
+#define BIF_RDCSR_ER    BIF_SDCSR_ER    /* error  detected by BIF */
+#define BIF_RDCSR_PE	BIF_SDCSR_PE	/* detect parity error in sync		*/
+#define BIF_RDCSR_SP	BIF_SDCSR_SP	/* parity error in sync	  */
+#define BIF_RDCSR_LP	BIF_SDCSR_LP	/* L-bus parity error	  */
+#define BIF_RDCSR_LR	BIF_SDCSR_LR	/* */
+#define BIF_RDCSR_LW	BIF_SDCSR_LW	/* */
+#define BIF_RDCSR_AL	BIF_SDCSR_AL	/* specify end bit except of end data */
+#define BIF_RDCSR_SS	BIF_SDCSR_SS	/* request bit but masked by slow sync	*/
+#define BIF_RDCSR_SC	BIF_SDCSR_SC	/* clear bit but masked by slow sync  */
+#define BIF_RDCSR_SY	BIF_SDCSR_SY	/* set bit but masked by slow status  */
+#define BIF_RDCSR_FS	BIF_SDCSR_FS	/* request bit but masked by fast sync*/
+#define BIF_RDCSR_FC	BIF_SDCSR_FC	/* clear bit but masked by fast sync  */
+#define BIF_RDCSR_FY	BIF_SDCSR_FY	/* set bit but masked by fast status  */
+#define BIF_RDCSR_CP	BIF_SDCSR_CP	/* parity error in commnad bus        */
+#define BIF_RDCSR_FP	BIF_SDCSR_FP	/* execute scatter or gather but FN=0 */
+#define BIF_RDCSR_PS	BIF_SDCSR_PS	/* header receive error 			*/
+#define BIF_RDCSR_RA	BIF_SDCSR_RA	/* change scatter,gather parameter		*/
+#define BIF_RDCSR_DL	BIF_SDCSR_DL	/* lost data					*/
+#define BIF_RDCSR_PA	BIF_SDCSR_PA	/* check if send or receive error	  */
+#define BIF_RDCSR_BB	BIF_SDCSR_BB	/* check if some BIF use command bus  */
+#define BIF_RDCSR_BG	BIF_SDCSR_BG	/* check if command bus got		*/
+#define BIF_RDCSR_BR	BIF_SDCSR_BR	/* request command bus			*/
+#define BIF_RDCSR_CN	BIF_SDCSR_CN	/* release BIF from command bus	*/
+#define BIF_RDCSR_EB	BIF_SDCSR_EB	/* send data that have end bit	*/
+#define BIF_RDCSR_TB	BIF_SDCSR_TB	/* data in send FIFO			*/
+#define BIF_RDCSR_RB	BIF_SDCSR_RB	/* data in receive FIFO			*/
+#define BIF_RDCSR_DE	BIF_SDCSR_DE	/* DMA interface enable bitr	*/
+#define BIF_RDCSR_DR	BIF_SDCSR_DR	/* data transfer direction		*/
+#define BIF_RDCSR_FN	BIF_SDCSR_FN	/* scatter gather enable		*/
+
+#define BIF_MHOCR_RS	0x00000800		/* bif reset						*/
+#define BIF_MHOCR_RC	0x00000400		/* commnad bus circuit reset		*/
+#define BIF_MHOCR_RI	0x00000200		/* remove input buffer data			*/
+#define BIF_MHOCR_RO	0x00000100		/* remove output buffer data		*/
+#define BIF_MHOCR_BA	0x00000008		/* command bus arbitlater reset		*/
+#define BIF_MHOCR_MD	0x00000006		/* command bus mode					*/
+#define BIF_MHOCR_AT	0x00000001		/* command bus attention signal		*/
+
+#define BIF_MHOCR_MD_NORMAL	0x00000006	/* command bus mode [normal]		*/
+#define BIF_MHOCR_MD_BUSWGR	0x00000004	/* command bus mode [bus gather]	*/
+#define BIF_MHOCR_MD_SETCID	0x00000002	/* command bus mode [set cid]		*/
+
+
diff -u --recursive --new-file v2.1.22/linux/include/asm-sparc/ap1000/aplib.h linux/include/asm-sparc/ap1000/aplib.h
--- v2.1.22/linux/include/asm-sparc/ap1000/aplib.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/ap1000/aplib.h	Sun Jan 26 12:07:47 1997
@@ -0,0 +1,119 @@
+  /*
+   * Copyright 1996 The Australian National University.
+   * Copyright 1996 Fujitsu Laboratories Limited
+   * 
+   * This software may be distributed under the terms of the Gnu
+   * Public License version 2 or later
+  */
+
+/* aplib kernel interface definition */
+
+#ifndef _APLIB_H_
+#define _APLIB_H_
+
+struct aplib_struct {
+	unsigned *ringbuf;
+	unsigned write_pointer, read_pointer; /* in words */
+	unsigned ringbuf_size; /* in words */
+	unsigned rbuf_counter; /* read messages */
+	unsigned rbuf_flag1, rbuf_flag2; /* received messages */
+	unsigned *physical_cid; /* logical to physical mapping */
+	unsigned *rel_cid;      /* logical to relative (RTC) mapping */
+	unsigned numcells; /* number of logical cells */
+	unsigned numcells_x; /* number of logical cells in x direction */
+	unsigned numcells_y; /* number of logical cells in y direction */
+	unsigned cid, tid;      /* this cells logical cell ID and task ID */
+	unsigned cidx, cidy;    /* logical cell id in x and y direction */
+	unsigned ack_flag, ack_request;
+	unsigned ok_x, ok_y, ok_xy; /* whether hardware x, y and xy sends are allowed */
+};
+
+
+/*
+ * the system ringbuffer structure
+ * this is also the old way that tasks accessed the MSC hardware
+ */
+struct ringbuf_struct {
+	void *ringbuf; /* pointer to the ringbuf */
+	void *shared; /* pointer to the shared page */
+	int order; /* arg to __get_free_pages */
+	unsigned write_ptr; /* write pointer into the ringbuf */
+	unsigned vaddr; /* base virtual address of ringbuf for task */
+	unsigned frag_count; /* how many words in the frag queue */
+	unsigned frag_len; /* how many words expected in the frag queue */
+	unsigned sq_fragment[16]; /* if the task switches part way through
+				     an op then shove the partial op here */
+};
+
+
+#define APLIB_INIT    1
+#define APLIB_SYNC    2
+#define APLIB_GET     3
+#define APLIB_PUT     4
+#define APLIB_SEND    5
+#define APLIB_PROBE   6
+#define APLIB_POLL    7
+#define APLIB_XSEND   8
+#define APLIB_YSEND   9
+#define APLIB_XYSEND 10
+#define APLIB_XPUT   11
+#define APLIB_YPUT   12
+#define APLIB_XYPUT  13
+
+
+/* message kinds */
+#define RBUF_SYSTEM  0
+#define RBUF_SEND    1
+#define RBUF_X_BRD   2
+#define RBUF_Y_BRD   3
+#define RBUF_XY_BRD  4
+#define RBUF_RPC     5
+#define RBUF_GET     6
+#define RBUF_MPI     7
+#define RBUF_BIGSEND 8
+#define RBUF_SEEN   0xE
+#define RBUF_READ   0xF
+
+#define APLIB_PAGE_BASE 0xd0000000
+#define APLIB_PAGE_LEN  8192
+
+struct aplib_init {
+	unsigned numcells, cid;
+	unsigned numcells_x, numcells_y;
+	unsigned *phys_cells; /* physical cell list */
+	unsigned *ringbuffer;  /* pointer to user supplied ring buffer */
+	unsigned ringbuf_size; /* in words */
+};
+
+
+struct aplib_putget {
+	unsigned cid;
+	unsigned *src_addr, *dest_addr;
+	unsigned size; /* in words */
+	unsigned *dest_flag, *src_flag;
+	unsigned ack;
+};
+
+
+struct aplib_send {
+	/* the ordering here is actually quite important - the parts to be
+	   read by the bigrecv function must be in the first 24 bytes */
+	unsigned src_addr;
+	unsigned size;
+	unsigned info1, info2;
+	unsigned flag_addr;
+	volatile unsigned flag;
+	unsigned type;
+	unsigned tag;
+	unsigned cid;
+};
+
+#ifdef __KERNEL__
+#define MAX_PUT_SIZE (1024*1024 - 1) /* in words */
+#define SMALL_SEND_THRESHOLD 128
+
+
+#endif
+
+#endif /* _APLIB_H_ */
+
diff -u --recursive --new-file v2.1.22/linux/include/asm-sparc/ap1000/apreg.h linux/include/asm-sparc/ap1000/apreg.h
--- v2.1.22/linux/include/asm-sparc/ap1000/apreg.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/ap1000/apreg.h	Sun Jan 26 12:07:47 1997
@@ -0,0 +1,619 @@
+  /*
+   * Copyright 1996 The Australian National University.
+   * Copyright 1996 Fujitsu Laboratories Limited
+   * 
+   * This software may be distributed under the terms of the Gnu
+   * Public License version 2 or later
+  */
+/* ap1000 register definitions needed for Linux/AP+ */
+
+#ifndef _AP1000_APREG_H
+#define _AP1000_APREG_H
+#include <asm/page.h>
+#include <asm/ap1000/apservice.h>
+#include <asm/ap1000/apbif.h>
+#include <linux/tasks.h>
+
+/*
+ * Macros for accessing I/O registers.
+ */
+#define BIF_IN(reg)	(*(volatile unsigned *)(reg))
+#define BIF_OUT(reg,v)	(*(volatile unsigned *)(reg) = (v))
+#define DMA_IN(reg)	(*(volatile unsigned *)(reg))
+#define DMA_OUT(reg,v)	(*(volatile unsigned *)(reg) = (v))
+#define MC_IN(reg)	(*(volatile unsigned *)(reg))
+#define MC_OUT(reg,v)	(*(volatile unsigned *)(reg) = (v))
+#define MSC_IN(reg)	(*(volatile unsigned *)(reg))
+#define MSC_OUT(reg,v)	(*(volatile unsigned *)(reg) = (v))
+#define MSC_IO(reg)	(*(volatile unsigned *)(reg))
+#define RTC_IO(reg)	(*(volatile unsigned *)(reg))
+#define MC_IO(reg)	(*(volatile unsigned *)(reg))
+#define OPT_IO(reg)	(*(volatile unsigned *)(reg))
+
+/*
+ * B-net interface register definitions.
+ */
+#define BIF 	0xfff30000	
+#define BIF_CIDR1 	(BIF+0x004c)	/* cell-id register 1 (for cell mode)*/
+#define BIF_SDCSR 	(BIF+0x0070)	/* BIF data control set register  */
+#define BIF_DATA 	(BIF+0x0000)	/* BIF send and receive data registe	*/
+#define BIF_EDATA  	(BIF+0x0004)	/* BIF end data register 		*/
+#define BIF_INTR 	(BIF+0x006c)	/* BIF interrupt control register 	*/
+
+#define SSTT_SET	(BIF+0xe0)	/* set SSTT 			*/
+#define SSTT_CLR	(BIF+0xe4)	/* clear SSTT 			*/
+#define SSTT_SMSK	(BIF+0xe8)	/* set SSTT mask		*/
+#define SSTT_CMSK	(BIF+0xec)	/* clear SSTT mask		*/
+#define SSTT_SMD	(BIF+0xf0)	/* set SSYN & SSTT mode		*/
+#define SSTT_CMD	(BIF+0xf4)	/* clear SSYN & SSTT mode	*/
+
+/*
+** FSTT registers
+*/
+#define FSTT	BIF	/*	FSTT only system mode	*/
+#define FSTT_SET	(FSTT+0xa0)	/* set FSTT 			  */
+#define FSTT_CLR	(FSTT+0xa4)	/* clear FSTT 			  */
+#define FSTT_SMSK	(FSTT+0xa8)	/* set FSTT mask		  */
+#define FSTT_CMSK	(FSTT+0xac)	/* clear FSTT mask		  */
+#define FSTT_SMD	(FSTT+0xb0)	/* set FSYN & FSTT mode		  */
+#define FSTT_CMD	(FSTT+0xb4)	/* clear FSYN & FSTT mode	  */
+#define FSTT_TIM	(FSTT+0xb8)	/* status timer			  */
+
+
+#define BIF_SDCSR_RB	0x0000001c	/* data in receive FIFO		  */
+#define BIF_SDCSR_EB	0x00000100	/* send data that have end bit	  */
+#define BIF_SDCSR_BG	0x00001000	/* check if command bus got	  */
+#define BIF_SDCSR_BR	0x00000800	/* request command bus		  */
+#define BIF_SDCSR_TB	0x000000E0	/* data in send FIFO		  */
+#define BIF_SDCSR_PE	0x80000000	/* detect parity error in sync	       	*/
+#define BIF_SDCSR_BB    0x00002000      /* check if some BIF use command bus    */
+
+#define BIF_SDCSR_RB_SHIFT 2
+#define BIF_SDCSR_TB_SHIFT 5
+
+#define BIF_INTR_GET_SH       15         /* get bus interrupt */
+#define BIF_INTR_HEADER_SH    12         /* header interrupt */
+#define BIF_INTR_SEND_SH      9          /* send interrupt */
+#define BIF_INTR_RECV_SH      6          /* receive interrupt */
+#define BIF_INTR_ERR_SH       3          /* error interrupt */
+#define BIF_INTR_ATTN_SH      0          /* attention interrupt */
+
+
+#define BIF_HEADER_HS	0x00000200	/* header strip		*/
+#define BIF_HEADER_RS	0x00000100	/* bus release 		*/
+#define BIF_HEADER_IN	0x00001000	/* interrupt bit	*/
+#define BIF_HEADER_BR   0x00008000    /* broad bit    */
+#define BIF_INTR_HS		0x00004000	/* header interrupt select  */
+#define HOST_CID      0x1000
+#define MAKE_HEADER(cid) (BIF_HEADER_IN | \
+			  ((cid)==-1?BIF_HEADER_BR:((cid)<<16) | (1<<13)))
+
+#define BIF_RDCSR 	(BIF+0x0074)	/* BIF data control reset reregister */
+
+/*
+ * Interrupt levels for AP+ devices
+ */
+#define APBIFGET_IRQ	1		/* have acquired B-net */
+#define APOPT0_IRQ	2		/* option interrupt level 0 */
+#define APSYNC_IRQ	3		/* sync (S-net) interrupt */
+#define APDMA_IRQ	4		/* DMA complete interrupt */
+#define APRTC_IRQ	5		/* RTC data transfer interrupt */
+#define APIPORT_IRQ	6		/* Interrupt port interrupt */
+#define APOPT1_IRQ	7		/* option interrupt level 1 */
+#define APBIF_IRQ	8		/* B-net interface interrupt */
+#define APMAS_IRQ	9		/* Send/Recv mem acc. seq. intr */
+#define APTIM1_IRQ	10		/* Timer 1 interrupt */
+#define APMSC_IRQ	11		/* MSC+ ring buf/queue spill etc. */
+#define APLBUS_IRQ	12		/* LBUS error interrupt */
+#define APATTN_IRQ	13		/* Attention interrupt */
+#define APTIM0_IRQ	14		/* Timer 0 interrupt */
+#define APMEM_IRQ	15		/* Memory error interrupt */
+
+/*
+ * LBUS DMA controller register definitions
+ */
+#define DMA     0xfff00000 /* dma controller address */
+#define DMA3    (DMA+0xc0) /* DMA channel 3 */
+#define DMA_DMST    0x04
+#define DMA_MADDR   0x10
+#define DMA_HSKIP   0x08
+#define DMA_HCNT    0x0a
+#define DMA_VSKIP   0x0c
+#define DMA_VCNT    0x0e
+#define DMA_DCMD    0x00
+#define DMA_HDRP    0x28
+#define DMA_DSIZE   0x02
+#define DMA_CSIZE   0x06
+#define DMA_VCNT    0x0e
+
+#define DMA_BIF_BCMD	(DMA+0x120)	/* BIF receive command register	*/
+#define	DMA_BIF_BRST	(DMA+0x124)	/* BIF receive status register */
+#define	DMA_BCMD_SA		0x40000000	/* software abort   */
+#define	DMA_DMST_AC		0x80000000	/* channel active   */
+#define DMA_DMST_RST		0xffe40000  /* reset bits and reqs */
+#define	DMA_DCMD_ST		0x80000000	/* start operation    */
+#define	DMA_DCMD_TYP_AUTO	0x30000000	/* 11: auto  */
+
+#define	DMA_DCMD_TD_MD		0x04000000	/* transfer mem->dev */
+#define	DMA_DCMD_TD_DM		0x00000000	/* transfer direction dev->mem*/
+
+#define DMA_CH2    (DMA+0x80)	/* DMA channel 2	*/
+#define DMA_CH3    (DMA+0xc0)	/* DMA channel 3	*/
+#define DMA2_DMST  (DMA_CH2+0x04)		/* DMA2 status register	  */
+#define DMA3_DMST  (DMA_CH3+0x04)		/* DMA3 status register	  */
+#define DMA2_DCMD   (DMA_CH2+0x00)		/* DMA2 command register  */
+
+#define DMA_INTR_NORMAL_SH     19               /* normal DMA interrupt */
+#define DMA_INTR_ERROR_SH      16               /* error DMA interrupt */
+
+#define	DMA_DCMD_SA		0x40000000	/* software abort     */
+
+
+#define DMA_MAX_TRANS_SIZE		(0xffff<<2)
+#define DMA_TRANS_BLOCK_SIZE	(64<<2)
+
+#define WORD_SIZE 4
+#define B2W(x)    (((x) + WORD_SIZE - 1) / WORD_SIZE)
+#define W2B(x)    ((x) * WORD_SIZE)
+
+#define DMA_GEN		0xfff00180		/* DMA general control reg */
+
+/* AP1000+ Message Controller (MSC+) */
+
+#define MSC_BASE0 0xfa008000
+
+#define MSC_SQCTRL	(MSC_BASE0 + 0x0)	/* Send Queue control */
+
+/* bits in MSC_SQCTRL */
+#define MSC_SQC_STABLE	0x400			/* Send Queue stable */
+#define MSC_SQC_MODE	0x300			/* Send Queue mode: */
+#define MSC_SQC_MODE_BLOCK	0			/* blocking */
+#define MSC_SQC_MODE_THRU	0x100			/* through */
+#define MSC_SQC_MODE_NORMAL	0x200			/* or normal */
+#define MSC_SQC_SPLF_SH		3		/* bit# for spill flags */
+#define MSC_SQC_SPLF_M		0x1f		/* 5 bits wide */
+#define MSC_SQC_REPLYF	0x080			/* Reply queue full */
+#define MSC_SQC_REMRF	0x040			/* Remote reply queue full */
+#define MSC_SQC_USERF	0x020			/* User queue full */
+#define MSC_SQC_REMAF	0x010			/* Remote access queue full */
+#define MSC_SQC_SYSF	0x008			/* System queue full */
+#define MSC_SQC_PAUSE	0x004			/* Send Queue pause */
+#define MSC_SQC_RMODE	0x003			/* Requested mode: */
+#define MSC_SQC_RMODE_BLOCK	0			/* blocking */
+#define MSC_SQC_RMODE_THRU	1			/* through */
+#define MSC_SQC_RMODE_NORMAL	2			/* or normal */
+
+#define MSC_SQPTR0	(MSC_BASE0 + 0x8)	/* Send Queue 0 pointers */
+#define MSC_SQPTR1	(MSC_BASE0 + 0x10)	/* Send Queue 1 pointers */
+#define MSC_SQPTR2	(MSC_BASE0 + 0x18)	/* Send Queue 2 pointers */
+#define MSC_SQPTR3	(MSC_BASE0 + 0x20)	/* Send Queue 3 pointers */
+#define MSC_SQPTR4	(MSC_BASE0 + 0x28)	/* Send Queue 4 pointers */
+
+/* bits in MSC_SQPTR[0-4] */
+#define MSC_SQP_MODE	(1 << 20)		/* 64/32 word queue mode */
+#define MSC_SQP_BP_SH	17			/* bit no. for base ptr */
+#define MSC_SQP_BP_M	7			/* (it's 3 bits wide) */
+#define MSC_SQP_CNT_SH	12			/* bit no. for count */
+#define MSC_SQP_CNT_M	0x1f			/* (it's 5 bits wide) */
+#define MSC_SQP_RP_SH	6			/* bit no. for read ptr */
+#define MSC_SQP_RP_M	0x3f			/* (it's 6 bits wide() */
+#define MSC_SQP_WP_SH	0			/* bit no. for write ptr */
+#define MSC_SQP_WP_M	0x3f			/* (it's 6 bits wide() */
+
+#define MSC_OPTADR	(MSC_BASE0 + 0x30)	/* option memory address */
+
+#define MSC_MASCTRL	(MSC_BASE0 + 0x38)	/* Mem Access Sequencer ctrl */
+
+/* Bits in MSC_MASCTRL */
+#define MSC_MASC_SPAUSE	0x80			/* Send MAS pause */
+#define MSC_MASC_RPAUSE	0x40			/* Recv MAS pause */
+#define MSC_MASC_SFEXIT	0x20			/* Send MAS fault/exit */
+#define MSC_MASC_RFEXIT	0x10			/* Recv MAS fault/exit */
+#define MSC_MASC_SREADY	0x08			/* Send MAS ready */
+#define MSC_MASC_RREADY	0x04			/* Recv MAS ready */
+#define MSC_MASC_SSTOP	0x02			/* Send MAS is stopped */
+#define MSC_MASC_RSTOP	0x01			/* Recv MAS is stopped */
+
+#define MSC_SMASADR	(MSC_BASE0 + 0x40)	/* Send Mem Acc Seq address */
+#define MSC_RMASADR	(MSC_BASE0 + 0x48)	/* Recv Mem Acc Seq address */
+
+#define MSC_PID		(MSC_BASE0 + 0x50)	/* Context number (proc id) */
+
+#define MSC_QWORDCNT	(MSC_BASE0 + 0x60)	/* Queue word counts */
+
+/* Fields in MSC_QWORDCNT */
+#define MSC_QWDC_SYSCNT_SH	24		/* bit# for system count */
+#define MSC_QWDC_SYSCNT_M	0x3f		/* 6 bits wide */
+#define MSC_QWDC_SYSLEN_SH	16		/* bit# for len of sys cmd */
+#define MSC_QWDC_SYSLEN_M	0x3f		/* 6 bits wide */
+#define MSC_QWDC_USRCNT_SH	8		/* bit# for user count */
+#define MSC_QWDC_USRCNT_M	0x3f		/* 6 bits wide */
+#define MSC_QWDC_USRLEN_SH	0		/* bit# for len of user cmd */
+#define MSC_QWDC_USRLEN_M	0x3f		/* 6 bits wide */
+
+#define MSC_INTR	(MSC_BASE0 + 0x70)	/* Interrupt control/status */
+
+/* Bit offsets of interrupt fields in MSC_INTR */
+#define MSC_INTR_QBMFUL_SH	28		/* Queue buffer full intr */
+#define MSC_INTR_SQFILL_SH	24		/* Send queue fill intr */
+#define MSC_INTR_RBMISS_SH	20		/* Ring buffer miss intr */
+#define MSC_INTR_RBFULL_SH	16		/* Ring buffer full intr */
+#define MSC_INTR_RMASF_SH	12		/* Recv MAS fault intr */
+#define MSC_INTR_RMASE_SH	8		/* Recv MAS error intr */
+#define MSC_INTR_SMASF_SH	4		/* Send MAS fault intr */
+#define MSC_INTR_SMASE_SH	0		/* Send MAS error intr */
+
+#define MSC_PPIO	(MSC_BASE0 + 0x1000)	/* PArallel port I/O */
+#define MSC_PACSELECT	(MSC_BASE0 + 0x1008)	/* Performance analyser sel. */
+
+#define MSC_CIDRANGE	(MSC_BASE0 + 0x1010)	/* Rel. Cell-id range limits */
+
+/* Fields in MSC_CIDRANGE */
+#define MSC_CIDR_LRX_SH		24		/* Rel. X lower limit bit# */
+#define MSC_CIDR_LRX_M		0xFF		/* it's 8 bits wide */
+#define MSC_CIDR_HRX_SH		16		/* Rel. X upper limit bit# */
+#define MSC_CIDR_HRX_M		0xFF		/* it's 8 bits wide */
+#define MSC_CIDR_LRY_SH		8		/* Rel. Y lower limit bit# */
+#define MSC_CIDR_LRY_M		0xFF		/* it's 8 bits wide */
+#define MSC_CIDR_HRY_SH		0		/* Rel. Y upper limit bit# */
+#define MSC_CIDR_HRY_M		0xFF		/* it's 8 bits wide */
+
+#define MSC_QBMPTR	(MSC_BASE0 + 0x1018)	/* Queue buffer mgr. ptrs */
+
+/* Fields in MSC_QBMPTR */
+#define MSC_QBMP_LIM_SH		24		/* Pointer limit bit# */
+#define MSC_QBMP_LIM_M		0x3F		/* (6 bits wide) */
+#define MSC_QBMP_BP_SH		16		/* Base pointer bit# */
+#define MSC_QBMP_BP_M		0xFF		/* (8 bits wide) */
+#define MSC_QBMP_WP_SH		0		/* Write pointer bit# */
+#define MSC_QBMP_WP_M		0xFFFF		/* (16 bits wide) */
+
+#define MSC_SMASTWP	(MSC_BASE0 + 0x1030)	/* Send MAS virt page etc. */
+#define MSC_SMASREG	(MSC_BASE0 + 0x1038)	/* Send MAS context etc. */
+#define MSC_RMASTWP	(MSC_BASE0 + 0x1040)	/* Recv MAS virt page etc. */
+#define MSC_RMASREG	(MSC_BASE0 + 0x1048)	/* Recv MAS context etc. */
+
+/* Bits in MSC_[SR]MASREG */
+#define MSC_MASR_CONTEXT_SH	20		/* Context at bit 20 */
+#define MSC_MASR_CONTEXT_M	0xfff		/* 12 bits wide */
+#define MSC_MASR_AVIO		8		/* Address violation bit */
+#define MSC_MASR_CMD		7		/* MAS command bits */
+#define MSC_MASR_CMD_XFER	0		/* transfer data cmd */
+#define MSC_MASR_CMD_FOP	5		/* fetch & operate cmd */
+#define MSC_MASR_CMD_INC	6		/* increment cmd (i.e. flag) */
+#define MSC_MASR_CMD_CSI	7		/* compare & swap cmd */
+
+#define MSC_HDGERRPROC	(MSC_BASE0 + 0x1050)	/* Header gen. error process */
+#define MSC_RHDERRPROC	(MSC_BASE0 + 0x1058)	/* Recv. header decoder err. */
+
+#define MSC_SMASCNT	(MSC_BASE0 + 0x1060)	/* Send MAS counters */
+
+/* Bits in MSC_SMASCNT */
+#define MSC_SMCT_ACCSZ_SH	28		/* Access size at bit 28 */
+#define MSC_SMCT_ACCSZ_M	7		/* 3 bits wide */
+#define MSC_SMCT_MCNT_SH	8		/* M(?) count at bit 8 */
+#define MSC_SMCT_MCNT_M		0xfffff		/* 20 bits wide */
+#define MSC_SMCT_ICNT_SH	0		/* I(?) count at bit 0 */
+#define MSC_SMCT_ICNT_M		0xff		/* 8 bits wide */
+
+#define MSC_IRL		(MSC_BASE0 + 0x1070)	/* highest current int req */
+#define MSC_SIMMCHK	(MSC_BASE0 + 0x1078)	/* DRAM type installed */
+
+#define MSC_SIMMCHK_MASK 0x00000008
+
+#define MSC_SQRAM	(MSC_BASE0 + 0x2000)	/* Send Queue RAM (to +23f8) */
+
+#define MSC_VERSION	(MSC_BASE0 + 0x3000)	/* MSC+ version */
+
+#define MSC_NR_RBUFS 3
+
+#define MSC_RBMBWP0	(MSC_BASE0 + 0x4000)	/* Ring buf 0 base/write ptr */
+#define MSC_RBMMODE0	(MSC_BASE0 + 0x4008)	/* Ring buf 0 mode/context */
+#define MSC_RBMBWP1	(MSC_BASE0 + 0x4010)	/* Ring buf 1 base/write ptr */
+#define MSC_RBMMODE1	(MSC_BASE0 + 0x4018)	/* Ring buf 1 mode/context */
+#define MSC_RBMBWP2	(MSC_BASE0 + 0x4020)	/* Ring buf 2 base/write ptr */
+#define MSC_RBMMODE2	(MSC_BASE0 + 0x4028)	/* Ring buf 2 mode/context */
+
+#define MSC_RBMRP0	(MSC_BASE0 + 0x5000)	/* Ring buf 0 read pointer */
+#define MSC_RBMRP1	(MSC_BASE0 + 0x6000)	/* Ring buf 1 read pointer */
+#define MSC_RBMRP2	(MSC_BASE0 + 0x7000)	/* Ring buf 2 read pointer */
+
+/* locations of queues in virtual memory */
+#define MSC_QUEUE_BASE   0xfa800000
+#define MSC_PUT_QUEUE_S  (MSC_QUEUE_BASE + 0*PAGE_SIZE)
+#define MSC_GET_QUEUE_S  (MSC_QUEUE_BASE + 1*PAGE_SIZE)
+#define MSC_XYG_QUEUE_S  (MSC_QUEUE_BASE + 2*PAGE_SIZE)
+#define MSC_SEND_QUEUE_S  (MSC_QUEUE_BASE + 3*PAGE_SIZE)
+#define MSC_CPUT_QUEUE_S  (MSC_QUEUE_BASE + 4*PAGE_SIZE)
+#define MSC_BSEND_QUEUE_S  (MSC_QUEUE_BASE + 5*PAGE_SIZE)
+#define MSC_CXYG_QUEUE_S  (MSC_QUEUE_BASE + 6*PAGE_SIZE)
+#define MSC_CGET_QUEUE_S  (MSC_QUEUE_BASE + 7*PAGE_SIZE)
+
+/* the 4 interrupt ports - physical addresses (on bus 8) */
+#define MC_INTP_0        0x80004000
+#define MC_INTP_1        0x80005000
+#define MC_INTP_2        0x80006000
+#define MC_INTP_3        0x80007000
+
+/* the address used to send a remote signal - note that 32 pages 
+ are used here - none of them are mapped to anything though */
+#define MSC_REM_SIGNAL          (MSC_QUEUE_BASE + 0x10 * PAGE_SIZE)
+
+#define MSC_PUT_QUEUE   (MSC_QUEUE_BASE + 0x100*PAGE_SIZE)
+#define MSC_GET_QUEUE   (MSC_QUEUE_BASE + 0x101*PAGE_SIZE)
+#define MSC_SEND_QUEUE  (MSC_QUEUE_BASE + 0x102*PAGE_SIZE)
+#define MSC_XY_QUEUE    (MSC_QUEUE_BASE + 0x103*PAGE_SIZE)
+#define MSC_X_QUEUE     (MSC_QUEUE_BASE + 0x104*PAGE_SIZE)
+#define MSC_Y_QUEUE     (MSC_QUEUE_BASE + 0x105*PAGE_SIZE)
+#define MSC_XYG_QUEUE   (MSC_QUEUE_BASE + 0x106*PAGE_SIZE)
+#define MSC_XG_QUEUE    (MSC_QUEUE_BASE + 0x107*PAGE_SIZE)
+#define MSC_YG_QUEUE    (MSC_QUEUE_BASE + 0x108*PAGE_SIZE)
+#define MSC_CSI_QUEUE   (MSC_QUEUE_BASE + 0x109*PAGE_SIZE)
+#define MSC_FOP_QUEUE   (MSC_QUEUE_BASE + 0x10a*PAGE_SIZE)
+
+#define SYSTEM_RINGBUF_BASE    (MSC_QUEUE_BASE + 0x200*PAGE_SIZE)
+#define SYSTEM_RINGBUF_ORDER 5
+#define SYSTEM_RINGBUF_SIZE ((1<<SYSTEM_RINGBUF_ORDER)*PAGE_SIZE)
+
+#define MSC_SYSTEM_DIRECT	(MSC_QUEUE_BASE + 0x700 * PAGE_SIZE)
+#define MSC_USER_DIRECT		(MSC_QUEUE_BASE + 0x701 * PAGE_SIZE)
+#define MSC_REMOTE_DIRECT	(MSC_QUEUE_BASE + 0x702 * PAGE_SIZE)
+#define MSC_REPLY_DIRECT	(MSC_QUEUE_BASE + 0x703 * PAGE_SIZE)
+#define MSC_REMREPLY_DIRECT	(MSC_QUEUE_BASE + 0x704 * PAGE_SIZE)
+
+#define MSC_SYSTEM_DIRECT_END	(MSC_QUEUE_BASE + 0x708 * PAGE_SIZE)
+#define MSC_USER_DIRECT_END	(MSC_QUEUE_BASE + 0x709 * PAGE_SIZE)
+#define MSC_REMOTE_DIRECT_END	(MSC_QUEUE_BASE + 0x70a * PAGE_SIZE)
+#define MSC_REPLY_DIRECT_END	(MSC_QUEUE_BASE + 0x70b * PAGE_SIZE)
+#define MSC_REMREPLY_DIRECT_END	(MSC_QUEUE_BASE + 0x70c * PAGE_SIZE)
+
+/* AP1000+ Memory Controller (MC+) */
+
+#define MC_BASE0	0xfa000000
+
+#define MC_DRAM_CTRL	(MC_BASE0 + 0x0)	/* DRAM control */
+#define MC_DRAM_CHKBIT	(MC_BASE0 + 0x8)	/* DRAM check bits */
+#define MC_DRAM_ERRADR	(MC_BASE0 + 0x10)	/* DRAM error address */
+#define MC_DRAM_ERRSYN	(MC_BASE0 + 0x18)	/* DRAM error syndrome */
+
+#define MC_FREERUN	(MC_BASE0 + 0x20)	/* Free run ctr (12.5MHz) */
+#define MC_ITIMER0	(MC_BASE0 + 0x28)	/* Interval timer 0 */
+#define MC_ITIMER1	(MC_BASE0 + 0x30)	/* Interval timer 1 */
+
+#define MC_INTR		(MC_BASE0 + 0x38)	/* Interrupt control/status */
+
+/* Interrupt control/status fields in MC_INTR */
+#define MC_INTR_ECCD_SH		12		/* ECC double (uncorr.) err */
+#define MC_INTR_ECCS_SH		8		/* ECC single (corr.) error */
+#define MC_INTR_ITIM1_SH	4		/* Interval timer 1 intr */
+#define MC_INTR_ITIM0_SH	0		/* Interval timer 0 intr */
+
+#define MC_CTP		(MC_BASE0 + 0x50)	/* Context table pointer */
+
+#define MC_VBUS_FAST	(MC_BASE0 + 0x60)	/* VBus fast data mode ctrl */
+
+#define MC_INTR_PORT	(MC_BASE0 + 0x68)	/* Interrupt port ctrl/stat */
+
+/* Interrupt control/status fields in MC_INTR_PORT */
+#define MC_INTP_3_SH		12		/* port 0 (880007000) */
+#define MC_INTP_2_SH		8		/* port 1 (880006000) */
+#define MC_INTP_1_SH		4		/* port 1 (880005000) */
+#define MC_INTP_0_SH		0		/* port 1 (880004000) */
+
+#define MC_PAC_COUNT	(MC_BASE0 + 0x1000)	/* Perf. an. counters */
+#define MC_PAC_SELECT	(MC_BASE0 + 0x1008)	/* Perf. an. ctr. select */
+
+#define MC_VERSION	(MC_BASE0 + 0x3000)	/* MC+ version/date */
+
+#define MC_MMU_TLB4K	(MC_BASE0 + 0x6000)	/* MC+ TLB for 4k pages */
+#define MC_MMU_TLB256K	(MC_BASE0 + 0x7000)	/* MC+ TLB for 256k pages */
+#define MC_MMU_TLB4K_SIZE 256
+#define MC_MMU_TLB256K_SIZE 64
+
+
+/*
+ * Bit values for a standard AP1000 3-bit interrupt control/status field.
+ */
+#define AP_INTR_REQ		1	/* interrupt request bit */
+#define AP_INTR_MASK		2	/* interrupt mask bit (1 disables) */
+#define AP_INTR_WENABLE		4	/* enable write to mask/req bits */
+#define AP_CLR_INTR_REQ		4	/* clear req. bit (dismiss intr) */
+#define AP_CLR_INTR_MASK	5	/* clear mask bit (enable ints) */
+#define AP_SET_INTR_REQ		6	/* set request bit */
+#define AP_SET_INTR_MASK	7	/* set mask bit (disable ints) */
+
+/*
+ * Bit field extraction/insertion macros.
+ */
+#define EXTFIELD(val, fld)	(((val) >> fld ## _SH) & fld ## _M)
+#define MKFIELD(val, fld)	(((val) & fld ## _M) << fld ## _SH)
+#define INSFIELD(dst, val, fld)	(((dst) & ~(fld ## _M << fld ## _SH)) \
+				 | MKFIELD(val, fld))
+
+/* 
+ * RTC registers 
+ */
+#define RTC 0xfff10000	/*	RTC system mode	*/
+#define RTC_CSR 	(RTC+0x0010)	/* RTC control	register   */
+#define RTC_STR   	(RTC+0x0020)	/* RTC status register	  */
+#define RTC_ITRR   	(RTC+0x0030)	/* RTC interrupt register  */
+#define RTC_RSTR   	(RTC+0x0070)	/* RTC reset register	   */	 
+#define RTC_RSTR_TR		0x00008000	/* RTC through mode */
+#define RTC_RSTR_TS		0x00004000	/* RTC test mode    */
+#define RTC_RSTR_ED		0x00002000	/* RTC reverse mode    */
+#define RTC_RSTR_AC		0x00001000	/* RTC long mode	*/
+#define RTC_RSTR_SN		0x00000800	/* SOUTH/NORTH direction */
+#define RTC_RSTR_EW		0x00000400	/* EAST/WEST direction	 */
+#define RTC_RSTR_NC		0x00000200	/* get NORTH channel   */
+#define RTC_RSTR_SC		0x00000100	/* get SOUTH channel	*/
+#define RTC_RSTR_WC		0x00000080	/* get WEST channel	*/
+#define RTC_RSTR_EC		0x00000040	/* get EAST channel	*/
+#define RTC_RSTR_BM		0x00000020	/* broad also my cell	*/
+#define RTC_RSTR_RT		0x00000020	/* reset  		*/
+
+
+#define RTC_ITRR_PA		0x00040000	/* parity error for LBUS */
+#define RTC_ITRR_LR		0x00020000	/* MSC read but FIFO is empty*/
+#define RTC_ITRR_LW		0x00010000	/* MSC write but FIFO is full*/
+#define RTC_ITRR_AL		0x00008000	/* specify end data in data transfer */
+#define RTC_ITRR_DN		0x00002000	/* parity error in NORTH channel  */
+#define RTC_ITRR_DS		0x00001000	/* parity error in SOUTH channel		*/
+#define RTC_ITRR_DW		0x00000800	/* parity error in WEST channel			*/
+#define RTC_ITRR_DE		0x00000400	/* parity error in EAST channel			*/
+#define RTC_ITRR_BD		0x00000200	/* receive 2 kind of broad data			*/
+#define RTC_ITRR_EW		0x00000100	/* control to write error bits			*/
+#define RTC_ITRR_EM		0x00000080	/* mask error interrupt request			*/
+#define RTC_ITRR_ER		0x00000040	/* error interrput request				*/
+#define RTC_ITRR_SW		0x00000020	/* control to write SR, SM  */
+#define RTC_ITRR_SM		0x00000010	/* mask send interrupt					*/
+#define RTC_ITRR_SR		0x00000008	/* send interrupt request				*/
+#define RTC_ITRR_RW		0x00000004	/* icontrol to read RR, RM				*/
+#define RTC_ITRR_RM		0x00000002	/* mask read interrupt					*/
+#define RTC_ITRR_RR		0x00000001	/* receive interrupt request			*/
+
+#define RTC_ITRR_RWM (RTC_ITRR_RW|RTC_ITRR_RM)
+#define RTC_ITRR_SWM (RTC_ITRR_SW|RTC_ITRR_SM)
+#define RTC_ITRR_EWM (RTC_ITRR_EW|RTC_ITRR_EM)
+#define RTC_ITRR_RWR (RTC_ITRR_RW|RTC_ITRR_RR)
+#define RTC_ITRR_SWR (RTC_ITRR_SW|RTC_ITRR_SR)
+#define RTC_ITRR_EWR (RTC_ITRR_EW|RTC_ITRR_ER)
+#define RTC_ITRR_RRM (RTC_ITRR_RM|RTC_ITRR_RR)
+#define RTC_ITRR_SRM (RTC_ITRR_SM|RTC_ITRR_SR)
+#define RTC_ITRR_ERM (RTC_ITRR_EM|RTC_ITRR_ER)
+#define RTC_ITRR_RWMR   (RTC_ITRR_RW|RTC_ITRR_RM|RTC_ITRR_RR)
+#define RTC_ITRR_SWMR   (RTC_ITRR_SW|RTC_ITRR_SM|RTC_ITRR_SR)
+#define RTC_ITRR_EWMR   (RTC_ITRR_EW|RTC_ITRR_EM|RTC_ITRR_ER)
+
+#define RTC_ITRR_ALLMSK (RTC_ITRR_RWM|RTC_ITRR_SWM|RTC_ITRR_EWM)
+#define RTC_ITRR_ALLCLR (RTC_ITRR_RW|RTC_ITRR_SW|RTC_ITRR_EW)
+#define RTC_ITRR_ALLWR  (RTC_ITRR_RWMR|RTC_ITRR_SWMR|RTC_ITRR_EWMR)
+#define RTC_ITRR_ALLRD  (RTC_ITRR_RRM|RTC_ITRR_SRM|RTC_ITRR_ERM)
+
+
+/*
+ * macros to manipulate context/task/pid numbers for parallel programs
+ */
+#define MPP_CONTEXT_BASE (AP_NUM_CONTEXTS - (NR_TASKS - MPP_TASK_BASE))
+#define MPP_TASK_TO_CTX(taskid) (((taskid) - MPP_TASK_BASE)+MPP_CONTEXT_BASE)
+#define MPP_CTX_TO_TASK(ctx) (((ctx)-MPP_CONTEXT_BASE)+MPP_TASK_BASE)
+#define MPP_IS_PAR_TASK(taskid) ((taskid) >= MPP_TASK_BASE)
+#define MPP_IS_PAR_CTX(ctx) ((ctx) >= MPP_CONTEXT_BASE)
+
+
+/*
+ * ioctls available on the ring buffer
+ */
+#define CAP_GETINIT 1
+#define CAP_SYNC    2
+#define CAP_SETTASK 3
+#define CAP_SETGANG 4
+#define CAP_MAP     5
+
+/*
+ * the structure shared by the kernel and the parallel tasks in the
+ * front of the cap_shared area
+ */
+#ifndef _ASM_
+#ifdef _APLIB_
+struct _kernel_cap_shared {
+	unsigned rbuf_read_ptr;
+	unsigned dummy[32]; /* for future expansion */
+};
+#endif
+#endif
+
+/*
+ * the mmap'd ringbuffer region is layed out like this:
+
+ shared page - one page
+ queue pages - 11 pages
+ ring buffer - xx pages
+ mirror of ring buffer - xx pages
+ */
+#define RBUF_VBASE 0xd0000000
+#define RBUF_SHARED_PAGE_OFF 0
+#define RBUF_PUT_QUEUE             PAGE_SIZE
+#define RBUF_GET_QUEUE           2*PAGE_SIZE
+#define RBUF_SEND_QUEUE          3*PAGE_SIZE
+#define RBUF_XY_QUEUE            4*PAGE_SIZE
+#define RBUF_X_QUEUE             5*PAGE_SIZE
+#define RBUF_Y_QUEUE             6*PAGE_SIZE
+#define RBUF_XYG_QUEUE           7*PAGE_SIZE
+#define RBUF_XG_QUEUE            8*PAGE_SIZE
+#define RBUF_YG_QUEUE            9*PAGE_SIZE
+#define RBUF_CSI_QUEUE          10*PAGE_SIZE
+#define RBUF_FOP_QUEUE          11*PAGE_SIZE
+#define RBUF_RING_BUFFER_OFFSET 15*PAGE_SIZE
+
+
+/*
+ * number of MMU contexts to use
+ */
+#define AP_NUM_CONTEXTS 1024
+#define SYSTEM_CONTEXT 1
+
+/*
+ * the default gang scheduling factor
+*/
+#define DEF_GANG_FACTOR 15
+
+/*
+ * useful for bypassing the cache
+*/
+#ifdef _APLIB_
+#ifndef _ASM_
+static inline unsigned long phys_8_in(unsigned long paddr)
+{
+	unsigned long word;
+	__asm__ __volatile__("lda [%1] %2, %0\n\t" :
+			     "=r" (word) :
+			     "r" (paddr), "i" (0x28) :
+			     "memory");
+	return word;
+}
+
+/*
+ * useful for bypassing the cache
+*/
+static inline unsigned long phys_9_in(unsigned long paddr)
+{
+	unsigned long word;
+	__asm__ __volatile__("lda [%1] %2, %0\n\t" :
+			     "=r" (word) :
+			     "r" (paddr), "i" (0x29) :
+			     "memory");
+	return word;
+}
+#endif
+#endif
+
+/*
+ * DDV definitions 
+*/
+#define OBASE        (0xfff40010)
+#define OPTION_BASE 0xfc000000
+#define _OPIBUS_BASE (OPTION_BASE + 0x800000)
+#ifdef CAP2_OPTION
+#define OPIBUS_BASE 0
+#else
+#define OPIBUS_BASE _OPIBUS_BASE
+#endif
+#define PBUF0        (OPIBUS_BASE+0x7e0080)
+#define PBUF1        (OPIBUS_BASE+0x7e0084)
+#define PBUF2        (OPIBUS_BASE+0x7e0088)
+#define PBUF3        (OPIBUS_BASE+0x7e008c)
+#define PIRQ         (OPIBUS_BASE+0x7e0090)
+#define PRST         (OPIBUS_BASE+0x7e0094)
+
+#define IRC0         (OPIBUS_BASE+0x7d00a0)
+#define IRC1         (OPIBUS_BASE+0x7d00a4)
+
+#define PRST_IRST    (0x00000001)
+
+#define OPIU_RESET			(0x00000000)
+#define OPIU_OP				(PBUF0)
+
+#define LSTR(s) (_OPIBUS_BASE + (s))
+
+#endif /* _AP1000_APREG_H */
+
diff -u --recursive --new-file v2.1.22/linux/include/asm-sparc/ap1000/apservice.h linux/include/asm-sparc/ap1000/apservice.h
--- v2.1.22/linux/include/asm-sparc/ap1000/apservice.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/ap1000/apservice.h	Sun Jan 26 12:07:47 1997
@@ -0,0 +1,111 @@
+  /*
+   * Copyright 1996 The Australian National University.
+   * Copyright 1996 Fujitsu Laboratories Limited
+   * 
+   * This software may be distributed under the terms of the Gnu
+   * Public License version 2 or later
+  */
+/* this defines service requests that can be made by the cells of the 
+   front end "bootap" server 
+
+   tridge, March 1996
+   */
+#ifndef _APSERVICE_H
+#define _APSERVICE_H
+#ifdef __KERNEL__
+#include <linux/sched.h>
+#endif
+
+#ifndef _ASM_
+
+/* all requests start with this structure */
+struct cap_request {
+  unsigned header; /* for the hardware */
+  int size; /* the total request size in bytes, including this header */
+  int cid; /* the cell it came from */
+  int type; /* the type of request */
+  int data[4]; /* misc data */
+};
+
+/* Initialisation data to be sent to boot cell program */
+struct cap_init {
+  int bootcid;  /* base cid to boot */
+  int numcells; /* number of cells */
+  int physcells; /* physical number of cells */
+  unsigned long baseIP; /* IP address of cell 0 */
+  unsigned long netmask; /* netmask of cells net */
+  int gdbcell; /* what cell is the debugger running on */
+  unsigned init_time; /* time at startup */
+};
+#endif
+
+/* what fake host number to use for the aliased IP device */
+#define AP_ALIAS_IP 2
+
+/* request types */
+#define REQ_WRITE 0
+#define REQ_SHUTDOWN 1
+#define REQ_LOAD_AOUT 2
+#define REQ_PUTCHAR 3
+#define REQ_GETBOOTARGS 4       
+#define REQ_PUTDEBUGCHAR 5      
+#define REQ_GETDEBUGCHAR 6     
+#define REQ_OPENNET 7
+#define REQ_IP 8
+#define REQ_BREAK 9
+#define REQ_INIT 10
+#define REQ_PUTDEBUGSTRING 11
+#define REQ_BREAD 12
+#define REQ_BWRITE 13
+#define REQ_BOPEN 14
+#define REQ_BCLOSE 15
+#define REQ_DDVOPEN 16
+#define REQ_BIF_TOKEN 17
+#define REQ_KILL 18
+#define REQ_SCHEDULE 19
+
+/* the bit used to indicate that the host wants the BIF */
+#define HOST_STATUS_BIT 2
+
+#ifdef __KERNEL__
+/* some prototypes */
+extern int ap_dma_wait(int ch);
+extern int ap_dma_go(unsigned long ch,unsigned int p,int size,unsigned long cmd);
+extern int mpp_cid(void);
+extern void ap_start_debugger(void);
+extern int bif_queue(struct cap_request *req,char *buf,int bufsize);
+extern void write_bif_polled(char *buf1,int len1,char *buf2,int len2);
+extern void read_bif(char *buf,int size);
+extern void ap_wait_request(struct cap_request *req,int type);
+extern void bif_set_poll(int set);
+extern void ap_led(unsigned char d);
+extern void ap_xor_led(unsigned char d);
+extern void ap_set_led(unsigned char d);
+extern void ap_unset_led(unsigned char d);
+extern void bif_toss(int size);
+void ap_msc_init(void);
+void mac_dma_complete(void);
+void ap_dbg_flush(void);
+void bif_queue_flush(void);
+/* void ap_printk(char *msg,int a1,int a2,int a3,int a4,int a5); */
+void show_mapping_ctx(unsigned *ctp,int context,unsigned Vm);
+void async_fault(unsigned long address, int write, int taskid,
+		 void (*callback)(int,unsigned long,int,int));
+void ap_bif_init(void);
+void ap_tnet_init(void);
+int wait_on_int(volatile int *p,int x,int interval);
+void ap_put(int dest_cell,u_long local_addr,int size,
+	    u_long remote_addr,u_long dest_flag,u_long local_flag);
+void ap_bput(u_long local_addr,int size,
+	     u_long remote_addr,u_long dest_flag,u_long local_flag);
+void msc_switch_check(struct task_struct *tsk);
+int bif_queue_nocopy(struct cap_request *req,char *buf,int bufsize);
+void mpp_set_gang_factor(int factor);
+void bif_register_request(int type,void (*fn)(struct cap_request *));
+void bif_add_debug_key(char key,void (*fn)(void),char *description);
+void ap_complete(struct cap_request *creq);
+void ap_reboot(char *bootstr);
+#endif
+
+
+#endif /* _APSERVICE_H */
diff -u --recursive --new-file v2.1.22/linux/include/asm-sparc/ap1000/pgtapmmu.h linux/include/asm-sparc/ap1000/pgtapmmu.h
--- v2.1.22/linux/include/asm-sparc/ap1000/pgtapmmu.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/ap1000/pgtapmmu.h	Sun Jan 26 12:07:47 1997
@@ -0,0 +1,140 @@
+  /*
+   * Copyright 1996 The Australian National University.
+   * Copyright 1996 Fujitsu Laboratories Limited
+   * 
+   * This software may be distributed under the terms of the Gnu
+   * Public License version 2 or later
+  */
+/* 
+ * based on pgtsrmmu.h
+ *
+ */
+
+#ifndef _SPARC_PGTAPMMU_H
+#define _SPARC_PGTAPMMU_H
+
+#include <asm/page.h>
+#include <asm/ap1000/apreg.h>
+
+
+/* PMD_SHIFT determines the size of the area a second-level page table can map */
+#define APMMU_PMD_SHIFT         18
+#define APMMU_PMD_SIZE          (1UL << APMMU_PMD_SHIFT)
+#define APMMU_PMD_MASK          (~(APMMU_PMD_SIZE-1))
+#define APMMU_PMD_ALIGN(addr)   (((addr)+APMMU_PMD_SIZE-1)&APMMU_PMD_MASK)
+
+/* PGDIR_SHIFT determines what a third-level page table entry can map */
+#define APMMU_PGDIR_SHIFT       24
+#define APMMU_PGDIR_SIZE        (1UL << APMMU_PGDIR_SHIFT)
+#define APMMU_PGDIR_MASK        (~(APMMU_PGDIR_SIZE-1))
+#define APMMU_PGDIR_ALIGN(addr) (((addr)+APMMU_PGDIR_SIZE-1)&APMMU_PGDIR_MASK)
+
+#define APMMU_PTRS_PER_PTE      64
+#define APMMU_PTRS_PER_PMD      64
+#define APMMU_PTRS_PER_PGD      256
+
+#define APMMU_PTE_TABLE_SIZE    0x100 /* 64 entries, 4 bytes a piece */
+#define APMMU_PMD_TABLE_SIZE    0x100 /* 64 entries, 4 bytes a piece */
+#define APMMU_PGD_TABLE_SIZE    0x400 /* 256 entries, 4 bytes a piece */
+
+#define APMMU_VMALLOC_START   (0xfe300000)
+
+/* Definition of the values in the ET field of PTD's and PTE's */
+#define APMMU_ET_MASK         0x3
+#define APMMU_ET_INVALID      0x0
+#define APMMU_ET_PTD          0x1
+#define APMMU_ET_PTE          0x2
+#define APMMU_ET_REPTE        0x3 /* AIEEE, SuperSparc II reverse endian page! */
+
+/* Physical page extraction from PTP's and PTE's. */
+#define APMMU_CTX_PMASK    0xfffffff0
+#define APMMU_PTD_PMASK    0xfffffff0
+#define APMMU_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 APMMU_CACHE        0x80
+#define APMMU_DIRTY        0x40
+#define APMMU_REF          0x20
+#define APMMU_EXEC         0x08
+#define APMMU_WRITE        0x04
+#define APMMU_VALID        0x02 /* APMMU_ET_PTE */
+#define APMMU_PRIV         0x1c
+#define APMMU_PRIV_RDONLY  0x18
+
+#define APMMU_CHG_MASK    (0xffffff00 | APMMU_REF | APMMU_DIRTY)
+
+/*
+ * "normal" sun systems have their memory on bus 0. This means the top
+ * 4 bits of 36 bit physical addresses are 0. We use this define to
+ * determine if a piece of memory might be normal memory, or if its
+ * definately some sort of device memory.  
+ *
+ * On the AP+ normal memory is on bus 8. Why? Ask Fujitsu :-)
+*/
+#define MEM_BUS_SPACE 8
+
+/* Some day I will implement true fine grained access bits for
+ * user pages because the APMMU gives us the capabilities to
+ * enforce all the protection levels that vma's can have.
+ * XXX But for now...
+ */
+#define APMMU_PAGE_NONE    __pgprot((MEM_BUS_SPACE<<28) | \
+				    APMMU_VALID | APMMU_CACHE | \
+				    APMMU_PRIV | APMMU_REF)
+#define APMMU_PAGE_SHARED  __pgprot((MEM_BUS_SPACE<<28) | \
+				    APMMU_VALID | APMMU_CACHE | \
+				    APMMU_EXEC | APMMU_WRITE | APMMU_REF)
+#define APMMU_PAGE_COPY    __pgprot((MEM_BUS_SPACE<<28) | \
+				    APMMU_VALID | APMMU_CACHE | \
+				    APMMU_EXEC | APMMU_REF)
+#define APMMU_PAGE_RDONLY  __pgprot((MEM_BUS_SPACE<<28) | \
+				    APMMU_VALID | APMMU_CACHE | \
+				    APMMU_EXEC | APMMU_REF)
+#define APMMU_PAGE_KERNEL  __pgprot((MEM_BUS_SPACE<<28) | \
+				    APMMU_VALID | APMMU_CACHE | APMMU_PRIV | \
+				    APMMU_DIRTY | APMMU_REF)
+
+#define APMMU_CTXTBL_PTR         0x00000100
+#define APMMU_CTX_REG            0x00000200
+
+extern __inline__ unsigned long apmmu_get_ctable_ptr(void)
+{
+	unsigned int retval;
+
+	__asm__ __volatile__("lda [%1] %2, %0\n\t" :
+			     "=r" (retval) :
+			     "r" (APMMU_CTXTBL_PTR),
+			     "i" (ASI_M_MMUREGS));
+	return (retval & APMMU_CTX_PMASK) << 4;
+}
+
+extern __inline__ void apmmu_set_context(int context)
+{
+	__asm__ __volatile__("sta %0, [%1] %2\n\t" : :
+			     "r" (context), "r" (APMMU_CTX_REG),
+			     "i" (ASI_M_MMUREGS) : "memory");
+	/* The AP1000+ message controller also needs to know
+	   the current task's context. */
+	MSC_OUT(MSC_PID, context);
+}
+
+extern __inline__ int apmmu_get_context(void)
+{
+	register int retval;
+	__asm__ __volatile__("lda [%1] %2, %0\n\t" :
+			     "=r" (retval) :
+			     "r" (APMMU_CTX_REG),
+			     "i" (ASI_M_MMUREGS));
+	return retval;
+}
+
+#endif /* !(_SPARC_PGTAPMMU_H) */
+
+
diff -u --recursive --new-file v2.1.22/linux/include/asm-sparc/asmmacro.h linux/include/asm-sparc/asmmacro.h
--- v2.1.22/linux/include/asm-sparc/asmmacro.h	Wed Dec 18 15:59:01 1996
+++ linux/include/asm-sparc/asmmacro.h	Sun Jan 26 12:07:47 1997
@@ -33,168 +33,14 @@
  * lose.  It makes sure the kernel has a proper window so that
  * c-code can be called.
  */
-#ifndef SMP_DEBUG
 #define SAVE_ALL_HEAD \
 	sethi	%hi(trap_setup), %l4; \
 	jmpl	%l4 + %lo(trap_setup), %l6;
 #define SAVE_ALL \
 	SAVE_ALL_HEAD \
 	 nop;
-#else
-#define SAVE_ALL_HEAD \
-	GET_PROCESSOR_ID(l4); \
-	set	C_LABEL(trap_log), %l5; \
-	sll	%l4, 11, %l6; \
-	add	%l5, %l6, %l5; \
-	set	C_LABEL(trap_log_ent), %l6; \
-	sll	%l4, 2, %l4; \
-	add	%l6, %l4, %l6; \
-	ld	[%l6], %l6; \
-	sll	%l6, 3, %l6; \
-	st	%l1, [%l5 + %l6]; \
-	add	%l5, 4, %l5; \
-	st	%l0, [%l5 + %l6]; \
-	set	C_LABEL(trap_log_ent), %l5; \
-	add	%l5, %l4, %l5; \
-	srl	%l6, 3, %l6; \
-	add	%l6, 1, %l6; \
-	and	%l6, 255, %l6; \
-	st	%l6, [%l5]; \
-	sethi	%hi(trap_setup), %l4; \
-	jmpl	%l4 + %lo(trap_setup), %l6;
-#define SAVE_ALL \
-	SAVE_ALL_HEAD \
-	 nop;
-#endif
 
-/* All traps low-level code here must end with this macro.
- * For SMP configurations the ret_trap_entry routine will
- * have to appropriate code to actually release the kernel
- * entry lock.
- */
+/* All traps low-level code here must end with this macro. */
 #define RESTORE_ALL b ret_trap_entry; clr %l6;
-
-#ifndef __SMP__
-
-#define ENTER_SYSCALL
-#define LEAVE_SYSCALL
-#define ENTER_IRQ
-#define LEAVE_IRQ
-
-#else
-
-#define INCREMENT_COUNTER(symbol, tmp1, tmp2) \
-	set	C_LABEL(symbol), %tmp1; \
-	ld	[%tmp1], %tmp2; \
-	add	%tmp2, 1, %tmp2; \
-	st	%tmp2, [%tmp1];
-
-#define DECREMENT_COUNTER(symbol, tmp1, tmp2) \
-	set	C_LABEL(symbol), %tmp1; \
-	ld	[%tmp1], %tmp2; \
-	sub	%tmp2, 1, %tmp2; \
-	st	%tmp2, [%tmp1];
-
-	/* This is so complicated I suggest you don't look at it. */
-#define ENTER_MASK(mask) \
-	GET_PROCESSOR_OFFSET(l4) \
-	set	C_LABEL(smp_proc_in_lock), %l5; \
-	ld	[%l5 + %l4], %l6; \
-	or	%l6, mask, %l6; \
-	st	%l6, [%l5 + %l4]; \
-1: \
-	set	C_LABEL(kernel_flag), %l5; \
-	ldstub	[%l5], %l6; \
-	cmp	%l6, 0; \
-	be	3f; \
-	 nop; \
-	set	C_LABEL(active_kernel_processor), %l5; \
-	GET_PROCESSOR_ID(l4) \
-	ldub	[%l5], %l6; \
-	cmp	%l6, %l4; \
-	be	4f; \
-	 nop; \
-2: \
-	GET_PROCESSOR_MID(l4, l5) \
-	set	C_LABEL(sun4m_interrupts), %l5; \
-	ld	[%l5], %l5; \
-	sll	%l4, 12, %l4; \
-	add	%l5, %l4, %l5; \
-	ld	[%l5], %l4; \
-	sethi	%hi(0x80000000), %l6; \
-	andcc	%l6, %l4, %g0; \
-	be	5f; \
-	 nop; \
-	st	%l6, [%l5 + 4]; \
-	nop; nop; nop; \
-	ld	[%l5], %g0; \
-	nop; nop; nop; \
-	or	%l0, PSR_PIL, %l4; \
-	wr	%l4, 0x0, %psr; \
-	nop; nop; nop; \
-	wr	%l4, PSR_ET, %psr; \
-	nop; nop; nop; \
-	call	C_LABEL(smp_message_irq); \
-       	 nop; \
-	wr	%l0, 0x0, %psr; \
-	nop; nop; nop; \
-5: \
-	set	C_LABEL(kernel_flag), %l5; \
-	ldub	[%l5], %l6; \
-	cmp	%l6, 0; \
-	bne	2b; \
-	 nop; \
-	b	1b; \
-	 nop; \
-3: \
-	GET_PROCESSOR_ID(l4) \
-	set	C_LABEL(active_kernel_processor), %l5; \
-	stb	%l4, [%l5]; \
-	GET_PROCESSOR_MID(l4, l5) \
-	set	C_LABEL(irq_rcvreg), %l5; \
-	ld	[%l5], %l5; \
-	st	%l4, [%l5]; \
-4: \
-
-#define ENTER_SYSCALL \
-	ENTER_MASK(SMP_FROM_SYSCALL) \
-	INCREMENT_COUNTER(kernel_counter, l6, l5) \
-	INCREMENT_COUNTER(syscall_count, l6, l5)
-
-#define ENTER_IRQ \
-	ENTER_MASK(SMP_FROM_INT) \
-	INCREMENT_COUNTER(kernel_counter, l6, l5)
-
-#define LEAVE_MASK(mask) \
-	GET_PROCESSOR_OFFSET(l4) \
-	set	C_LABEL(smp_proc_in_lock), %l5; \
-	ld	[%l5 + %l4], %l6; \
-	andn	%l6, mask, %l6; \
-	st	%l6, [%l5 + %l4];
-
-#define LEAVE_SYSCALL \
-	LEAVE_MASK(SMP_FROM_SYSCALL) \
-	DECREMENT_COUNTER(syscall_count, l6, l5) \
-	set	C_LABEL(kernel_counter), %l6; \
-	ld	[%l6], %l5; \
-	subcc	%l5, 1, %l5; \
-	st	%l5, [%l6]; \
-	bne	1f; \
-	 nop; \
-	set	C_LABEL(active_kernel_processor), %l6; \
-	mov	NO_PROC_ID, %l5; \
-	stb	%l5, [%l6]; \
-	set	C_LABEL(kernel_flag), %l6; \
-	stb	%g0, [%l6]; \
-1:
-
-#define LEAVE_IRQ \
-	LEAVE_MASK(SMP_FROM_INT) \
-	INCREMENT_COUNTER(syscall_count, l6, l5)
-
-
-#define RESTORE_ALL_FASTIRQ b,a	ret_irq_entry;
-
-#endif /* !(__SMP__) */
 
 #endif /* !(_SPARC_ASMMACRO_H) */
diff -u --recursive --new-file v2.1.22/linux/include/asm-sparc/atomic.h linux/include/asm-sparc/atomic.h
--- v2.1.22/linux/include/asm-sparc/atomic.h	Tue Dec 31 21:41:09 1996
+++ linux/include/asm-sparc/atomic.h	Sun Jan 26 12:07:47 1997
@@ -1,4 +1,4 @@
-/* atomic.h: These really suck for now.
+/* atomic.h: These still suck, but the I-cache hit rate is higher.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
  */
@@ -12,8 +12,12 @@
 #include <asm/system.h>
 #include <asm/psr.h>
 
-/*
- * Make sure gcc doesn't try to be clever and move things around
+/* We do the bulk of the actual work out of line in two common
+ * routines in assembler, see arch/sparc/lib/atomic.S for the
+ * "fun" details.
+ */
+
+/* Make sure gcc doesn't try to be clever and move things around
  * on us. We need to use _exactly_ the address the user gave us,
  * not some alias that contains the same information.
  */
@@ -21,118 +25,74 @@
 
 static __inline__ void atomic_add(atomic_t i, atomic_t *v)
 {
+	register atomic_t *ptr asm("g1");
+	register atomic_t increment asm("g2");
+
+	ptr = (atomic_t *) __atomic_fool_gcc(v);
+	increment = i;
+
 	__asm__ __volatile__("
-	rd	%%psr, %%g2
-	andcc	%%g2, %2, %%g0
-	bne	1f
-	 nop
-	wr	%%g2, %2, %%psr
-	nop
-	nop
-	nop
-1:
-	ld	[%0], %%g3
-	add	%%g3, %1, %%g3
-	andcc	%%g2, %2, %%g0
-	st	%%g3, [%0]
-	bne	1f
-	 nop
-	wr	%%g2, 0x0, %%psr
-	nop
-	nop
-	nop
-1:
-"	: /* no outputs */
-	: "r" (__atomic_fool_gcc(v)), "r" (i), "i" (PSR_PIL)
-	: "g2", "g3");
+	mov	%%o7, %%g4
+	call	___atomic_add
+	 add	%%o7, 8, %%o7
+"	: "=&r" (increment)
+	: "0" (increment), "r" (ptr)
+	: "g3", "g4", "g7", "memory");
 }
 
 static __inline__ void atomic_sub(atomic_t i, atomic_t *v)
 {
+	register atomic_t *ptr asm("g1");
+	register atomic_t increment asm("g2");
+
+	ptr = (atomic_t *) __atomic_fool_gcc(v);
+	increment = i;
+
 	__asm__ __volatile__("
-	rd	%%psr, %%g2
-	andcc	%%g2, %2, %%g0
-	bne	1f
-	 nop
-	wr	%%g2, %2, %%psr
-	nop
-	nop
-	nop
-1:
-	ld	[%0], %%g3
-	sub	%%g3, %1, %%g3
-	andcc	%%g2, %2, %%g0
-	st	%%g3, [%0]
-	bne	1f
-	 nop
-	wr	%%g2, 0x0, %%psr
-	nop
-	nop
-	nop
-1:
-"	: /* no outputs */
-	: "r" (__atomic_fool_gcc(v)), "r" (i), "i" (PSR_PIL)
-	: "g2", "g3");
+	mov	%%o7, %%g4
+	call	___atomic_sub
+	 add	%%o7, 8, %%o7
+"	: "=&r" (increment)
+	: "0" (increment), "r" (ptr)
+	: "g3", "g4", "g7", "memory");
 }
 
 static __inline__ int atomic_add_return(atomic_t i, atomic_t *v)
 {
+	register atomic_t *ptr asm("g1");
+	register atomic_t increment asm("g2");
+
+	ptr = (atomic_t *) __atomic_fool_gcc(v);
+	increment = i;
+
 	__asm__ __volatile__("
-	rd	%%psr, %%g2
-	andcc	%%g2, %3, %%g0
-	bne	1f
-	 nop
-	wr	%%g2, %3, %%psr
-	nop
-	nop
-	nop
-1:
-	ld	[%1], %%g3
-	add	%%g3, %2, %0
-	andcc	%%g2, %3, %%g0
-	st	%0, [%1]
-	bne	1f
-	 nop
-	wr	%%g2, 0x0, %%psr
-	nop
-	nop
-	nop
-1:
-"	: "=&r" (i)
-	: "r" (__atomic_fool_gcc(v)), "0" (i), "i" (PSR_PIL)
-	: "g2", "g3");
+	mov	%%o7, %%g4
+	call	___atomic_add
+	 add	%%o7, 8, %%o7
+"	: "=&r" (increment)
+	: "0" (increment), "r" (ptr)
+	: "g3", "g4", "g7", "memory");
 
-	return i;
+	return increment;
 }
 
 static __inline__ int atomic_sub_return(atomic_t i, atomic_t *v)
 {
+	register atomic_t *ptr asm("g1");
+	register atomic_t increment asm("g2");
+
+	ptr = (atomic_t *) __atomic_fool_gcc(v);
+	increment = i;
+
 	__asm__ __volatile__("
-	rd	%%psr, %%g2
-	andcc	%%g2, %3, %%g0
-	bne	1f
-	 nop
-	wr	%%g2, %3, %%psr
-	nop
-	nop
-	nop
-1:
-	ld	[%1], %%g3
-	sub	%%g3, %2, %0
-	andcc	%%g2, %3, %%g0
-	st	%0, [%1]
-	bne	1f
-	 nop
-	wr	%%g2, 0x0, %%psr
-	nop
-	nop
-	nop
-1:
-"	: "=&r" (i)
-	: "r" (__atomic_fool_gcc(v)), "0" (i), "i" (PSR_PIL)
-	: "g2", "g3");
+	mov	%%o7, %%g4
+	call	___atomic_sub
+	 add	%%o7, 8, %%o7
+"	: "=&r" (increment)
+	: "0" (increment), "r" (ptr)
+	: "g3", "g4", "g7", "memory");
 
-	return i;
+	return increment;
 }
 
 #define atomic_dec_return(v) atomic_sub_return(1,(v))
diff -u --recursive --new-file v2.1.22/linux/include/asm-sparc/bitops.h linux/include/asm-sparc/bitops.h
--- v2.1.22/linux/include/asm-sparc/bitops.h	Tue Dec 31 21:41:09 1996
+++ linux/include/asm-sparc/bitops.h	Sun Jan 26 12:07:47 1997
@@ -1,4 +1,4 @@
-/* $Id: bitops.h,v 1.41 1996/12/28 18:14:25 davem Exp $
+/* $Id: bitops.h,v 1.43 1997/01/25 04:42:51 davem Exp $
  * bitops.h: Bit string operations on the Sparc.
  *
  * Copyright 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -97,110 +97,56 @@
 
 extern __inline__ unsigned long set_bit(unsigned long nr, __SMPVOL void *addr)
 {
-	int mask;
-	unsigned long *ADDR = (unsigned long *) addr;
+	register unsigned long mask asm("g2");
+	register unsigned long *ADDR asm("g1");
 
-	ADDR += nr >> 5;
+	ADDR = ((unsigned long *) addr) + (nr >> 5);
 	mask = 1 << (nr & 31);
 	__asm__ __volatile__("
-	rd	%%psr, %%g3
-	andcc	%%g3, %3, %%g0
-	bne	1f
-	 nop
-	wr	%%g3, %3, %%psr
-	nop
-	nop
-	nop
-1:
-	ld	[%0], %%g4
-	or	%%g4, %2, %%g2
-	andcc	%%g3, %3, %%g0
-	st	%%g2, [%0]
-	bne	1f
-	 nop
-	wr	%%g3, 0x0, %%psr
-	nop
-	nop
-	nop
-1:
-	and	%%g4, %2, %0
-"	: "=&r" (ADDR)
-	: "0" (ADDR), "r" (mask), "i" (PSR_PIL)
-	: "g2", "g3", "g4");
+	mov	%%o7, %%g4
+	call	___set_bit
+	 add	%%o7, 8, %%o7
+"	: "=&r" (mask)
+	: "0" (mask), "r" (ADDR)
+	: "g3", "g4", "g5", "g7");
 
-	return (unsigned long) ADDR;
+	return mask;
 }
 
 extern __inline__ unsigned long clear_bit(unsigned long nr, __SMPVOL void *addr)
 {
-	int mask;
-	unsigned long *ADDR = (unsigned long *) addr;
+	register unsigned long mask asm("g2");
+	register unsigned long *ADDR asm("g1");
 
-	ADDR += nr >> 5;
+	ADDR = ((unsigned long *) addr) + (nr >> 5);
 	mask = 1 << (nr & 31);
 	__asm__ __volatile__("
-	rd	%%psr, %%g3
-	andcc	%%g3, %3, %%g0
-	bne	1f
-	 nop
-	wr	%%g3, %3, %%psr
-	nop
-	nop
-	nop
-1:
-	ld	[%0], %%g4
-	andn	%%g4, %2, %%g2
-	andcc	%%g3, %3, %%g0
-	st	%%g2, [%0]
-	bne	1f
-	 nop
-	wr	%%g3, 0x0, %%psr
-	nop
-	nop
-	nop
-1:
-	and	%%g4, %2, %0
-"	: "=&r" (ADDR)
-	: "0" (ADDR), "r" (mask), "i" (PSR_PIL)
-	: "g2", "g3", "g4");
+	mov	%%o7, %%g4
+	call	___clear_bit
+	 add	%%o7, 8, %%o7
+"	: "=&r" (mask)
+	: "0" (mask), "r" (ADDR)
+	: "g3", "g4", "g5", "g7");
 
-	return (unsigned long) ADDR;
+	return mask;
 }
 
 extern __inline__ unsigned long change_bit(unsigned long nr, __SMPVOL void *addr)
 {
-	int mask;
-	unsigned long *ADDR = (unsigned long *) addr;
+	register unsigned long mask asm("g2");
+	register unsigned long *ADDR asm("g1");
 
-	ADDR += nr >> 5;
+	ADDR = ((unsigned long *) addr) + (nr >> 5);
 	mask = 1 << (nr & 31);
 	__asm__ __volatile__("
-	rd	%%psr, %%g3
-	andcc	%%g3, %3, %%g0
-	bne	1f
-	 nop
-	wr	%%g3, %3, %%psr
-	nop
-	nop
-	nop
-1:
-	ld	[%0], %%g4
-	xor	%%g4, %2, %%g2
-	andcc	%%g3, %3, %%g0
-	st	%%g2, [%0]
-	bne	1f
-	 nop
-	wr	%%g3, 0x0, %%psr
-	nop
-	nop
-	nop
-1:
-	and	%%g4, %2, %0
-"	: "=&r" (ADDR)
-	: "0" (ADDR), "r" (mask), "i" (PSR_PIL)
-	: "g2", "g3", "g4");
+	mov	%%o7, %%g4
+	call	___change_bit
+	 add	%%o7, 8, %%o7
+"	: "=&r" (mask)
+	: "0" (mask), "r" (ADDR)
+	: "g3", "g4", "g5", "g7");
 
-	return (unsigned long) ADDR;
+	return mask;
 }
 
 #endif /* __KERNEL__ */
@@ -319,74 +265,38 @@
 
 extern __inline__ int set_le_bit(int nr,void * addr)
 {
-	int		mask;
-	unsigned char	*ADDR = (unsigned char *) addr;
+	register int mask asm("g2");
+	register unsigned char *ADDR asm("g1");
 
-	ADDR += nr >> 3;
+	ADDR = ((unsigned char *) addr) + (nr >> 3);
 	mask = 1 << (nr & 0x07);
 	__asm__ __volatile__("
-	rd	%%psr, %%g3
-	andcc	%%g3, %3, %%g0
-	bne	1f
-	 nop
-	wr	%%g3, %3, %%psr
-	nop
-	nop
-	nop
-1:
-	ldub	[%0], %%g4
-	or	%%g4, %2, %%g2
-	andcc	%%g3, %3, %%g0
-	stb	%%g2, [%0]
-	bne	1f
-	 nop
-	wr	%%g3, 0x0, %%psr
-	nop
-	nop
-	nop
-1:
-	and	%%g4, %2, %0
-"	: "=&r" (ADDR)
-	: "0" (ADDR), "r" (mask), "i" (PSR_PIL)
-	: "g2", "g3", "g4");
+	mov	%%o7, %%g4
+	call	___set_le_bit
+	 add	%%o7, 8, %%o7
+"	: "=&r" (mask)
+	: "0" (mask), "r" (ADDR)
+	: "g3", "g4", "g5", "g7");
 
-	return (int) ADDR;
+	return mask;
 }
 
 extern __inline__ int clear_le_bit(int nr, void * addr)
 {
-	int		mask;
-	unsigned char	*ADDR = (unsigned char *) addr;
+	register int mask asm("g2");
+	register unsigned char *ADDR asm("g1");
 
-	ADDR += nr >> 3;
+	ADDR = ((unsigned char *) addr) + (nr >> 3);
 	mask = 1 << (nr & 0x07);
 	__asm__ __volatile__("
-	rd	%%psr, %%g3
-	andcc	%%g3, %3, %%g0
-	bne	1f
-	 nop
-	wr	%%g3, %3, %%psr
-	nop
-	nop
-	nop
-1:
-	ldub	[%0], %%g4
-	andn	%%g4, %2, %%g2
-	andcc	%%g3, %3, %%g0
-	stb	%%g2, [%0]
-	bne	1f
-	 nop
-	wr	%%g3, 0x0, %%psr
-	nop
-	nop
-	nop
-1:
-	and	%%g4, %2, %0
-"	: "=&r" (ADDR)
-	: "0" (ADDR), "r" (mask), "i" (PSR_PIL)
-	: "g2", "g3", "g4");
+	mov	%%o7, %%g4
+	call	___clear_le_bit
+	 add	%%o7, 8, %%o7
+"	: "=&r" (mask)
+	: "0" (mask), "r" (ADDR)
+	: "g3", "g4", "g5", "g7");
 
-	return (int) ADDR;
+	return mask;
 }
 
 #endif /* __KERNEL__ */
diff -u --recursive --new-file v2.1.22/linux/include/asm-sparc/poll.h linux/include/asm-sparc/poll.h
--- v2.1.22/linux/include/asm-sparc/poll.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/poll.h	Fri Jan 24 08:40:28 1997
@@ -0,0 +1,21 @@
+#ifndef __SPARC_POLL_H
+#define __SPARC_POLL_H
+
+#define POLLIN		  1
+#define POLLPRI		  2
+#define POLLOUT		  4
+#define POLLERR		  8
+#define POLLHUP		 16
+#define POLLNVAL	 32
+#define POLLRDNORM	 64
+#define POLLWRNORM	POLLOUT
+#define POLLRDBAND	128
+#define POLLWRBAND	256
+
+struct pollfd {
+	int fd;
+	short events;
+	short revents;
+};
+
+#endif
diff -u --recursive --new-file v2.1.22/linux/include/asm-sparc/ptrace.h linux/include/asm-sparc/ptrace.h
--- v2.1.22/linux/include/asm-sparc/ptrace.h	Wed Dec 18 15:59:01 1996
+++ linux/include/asm-sparc/ptrace.h	Sun Jan 26 12:07:47 1997
@@ -1,4 +1,4 @@
-/* $Id: ptrace.h,v 1.23 1996/11/25 03:30:24 ecd Exp $ */
+/* $Id: ptrace.h,v 1.24 1997/01/06 06:53:23 davem Exp $ */
 #ifndef _SPARC_PTRACE_H
 #define _SPARC_PTRACE_H
 
@@ -73,7 +73,7 @@
 #define REGWIN_SZ         0x40
 #endif
 
-/* First generic task_struct offsets. sizeof(task_struct)=1552 */
+/* First generic task_struct offsets. sizeof(task_struct)=1568 */
 #define TASK_STATE        0x000
 #define TASK_PRIORITY     0x008
 #define TASK_SIGNAL       0x00c
@@ -81,6 +81,7 @@
 #define TASK_FLAGS        0x014
 #define TASK_SAVED_KSTACK 0x054
 #define TASK_KSTACK_PG    0x058
+#define TASK_LOCK_DEPTH   0x618
 
 /* Thread stuff. */
 #define THREAD_UMASK      0x1e0
@@ -99,10 +100,6 @@
 #define THREAD_FSR        0x530
 #define THREAD_SIGSTK     0x5b8
 #define THREAD_FLAGS      0x5c0
-#define THREAD_EX_COUNT   0x5c8
-#define THREAD_EX_PC      0x5cc
-#define THREAD_EX_EXPC    0x5d0
-#define THREAD_EX_ADDR    0x5d4
 #define THREAD_DS         0x5d8
 #define THREAD_MM         0x608
 #define THREAD_MM_CTX     0x008
diff -u --recursive --new-file v2.1.22/linux/include/asm-sparc/semaphore.h linux/include/asm-sparc/semaphore.h
--- v2.1.22/linux/include/asm-sparc/semaphore.h	Tue Nov 12 15:56:13 1996
+++ linux/include/asm-sparc/semaphore.h	Sun Jan 26 12:07:47 1997
@@ -1,16 +1,13 @@
 #ifndef _SPARC_SEMAPHORE_H
 #define _SPARC_SEMAPHORE_H
 
-/* Dinky, good for nothing, just barely irq safe, Sparc semaphores.
- *
- * I'll write better ones later.
- */
+/* Dinky, good for nothing, just barely irq safe, Sparc semaphores. */
 
 #include <asm/atomic.h>
 
 struct semaphore {
 	atomic_t count;
-	atomic_t waiting;
+	atomic_t waking;
 	struct wait_queue * wait;
 };
 
@@ -18,19 +15,24 @@
 #define MUTEX_LOCKED ((struct semaphore) { 0, 0, NULL })
 
 extern void __down(struct semaphore * sem);
+extern int __down_interruptible(struct semaphore * sem);
 extern void __up(struct semaphore * sem);
 
-/*
- * This isn't quite as clever as the x86 side, but the gp register
- * makes things a bit more complicated on the alpha..
+/* This isn't quite as clever as the x86 side, I'll be fixing this
+ * soon enough.
  */
 extern inline void down(struct semaphore * sem)
 {
-	for (;;) {
-		if (atomic_dec_return(&sem->count) >= 0)
-			break;
+	if (atomic_dec_return(&sem->count) < 0)
 		__down(sem);
-	}
+}
+
+extern inline int down_interruptible(struct semaphore * sem)
+{
+	int ret = 0;
+	if(atomic_dec_return(&sem->count) < 0)
+		ret = __down_interruptible(sem);
+	return ret;
 }
 
 extern inline void up(struct semaphore * sem)
diff -u --recursive --new-file v2.1.22/linux/include/asm-sparc/sigcontext.h linux/include/asm-sparc/sigcontext.h
--- v2.1.22/linux/include/asm-sparc/sigcontext.h	Wed Dec 18 15:59:01 1996
+++ linux/include/asm-sparc/sigcontext.h	Sun Jan 26 12:07:47 1997
@@ -1,4 +1,4 @@
-/* $Id: sigcontext.h,v 1.10 1996/11/27 01:46:51 miguel Exp $ */
+/* $Id: sigcontext.h,v 1.11 1997/01/19 22:32:07 ecd Exp $ */
 #ifndef _ASMsparc_SIGCONTEXT_H
 #define _ASMsparc_SIGCONTEXT_H
 
@@ -38,7 +38,11 @@
 };
 
 typedef struct {
-	struct     pt_regs si_regs;
+	struct pt_regs	si_regs;
+	int		si_mask;
+} __siginfo_t;
+
+typedef struct {
 	unsigned   long si_float_regs [64];
 	unsigned   long si_fsr;
 	unsigned   long si_fpqdepth;
@@ -46,8 +50,7 @@
 		unsigned long *insn_addr;
 		unsigned long insn;
 	} si_fpqueue [16];
-	int si_mask;
-} __siginfo_t;
+} __siginfo_fpu_t;
 
 #endif /* !(__ASSEMBLY__) */
 
diff -u --recursive --new-file v2.1.22/linux/include/asm-sparc/smp.h linux/include/asm-sparc/smp.h
--- v2.1.22/linux/include/asm-sparc/smp.h	Tue Nov 12 15:56:13 1996
+++ linux/include/asm-sparc/smp.h	Sun Jan 26 12:07:47 1997
@@ -15,6 +15,8 @@
 	int prom_node;
 	int mid;
 };
+extern int linux_num_cpus;	/* number of CPUs probed  */
+
 #endif /* !(__ASSEMBLY__) */
 
 #ifdef __SMP__
@@ -31,8 +33,13 @@
 
 extern struct cpuinfo_sparc cpu_data[NR_CPUS];
 
-typedef __volatile__ unsigned char klock_t;
-extern klock_t kernel_flag;
+struct klock_info {
+	unsigned char kernel_flag;
+	unsigned char akp;
+	unsigned char irq_udt;
+};
+
+extern struct klock_info klock_info;
 
 #define KLOCK_HELD       0xff
 #define KLOCK_CLEAR      0x00
@@ -45,12 +52,8 @@
 extern unsigned char boot_cpu_id;
 extern unsigned long cpu_present_map;
 extern __volatile__ unsigned long smp_invalidate_needed[NR_CPUS];
-extern __volatile__ unsigned long kernel_counter;
-extern __volatile__ unsigned char active_kernel_processor;
 extern void smp_message_irq(void);
 extern unsigned long ipi_count;
-extern __volatile__ unsigned long kernel_counter;
-extern __volatile__ unsigned long syscall_count;
 
 extern void print_lock_state(void);
 
@@ -167,6 +170,11 @@
 #define SMP_FROM_INT		1
 #define SMP_FROM_SYSCALL	2
 
+#else /* !(__SMP__) */
+
+#define smp_capture()		do { } while(0)
+#define smp_release()		do { } while(0)
+ 
 #endif /* !(__SMP__) */
 
 #endif /* !(_SPARC_SMP_H) */
diff -u --recursive --new-file v2.1.22/linux/include/asm-sparc/smp_lock.h linux/include/asm-sparc/smp_lock.h
--- v2.1.22/linux/include/asm-sparc/smp_lock.h	Tue Nov 12 15:56:13 1996
+++ linux/include/asm-sparc/smp_lock.h	Sun Jan 26 12:07:47 1997
@@ -1,4 +1,4 @@
-/* smp_lock.h: Locking and unlocking the kernel on the Sparc.
+/* smp_lock.h: SMP locking primitives on Sparc.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
  */
@@ -7,52 +7,142 @@
 #define __SPARC_SMPLOCK_H
 
 #include <asm/smp.h>
-#include <asm/bitops.h>
-#include <asm/atops.h>
-#include <asm/pgtable.h>
+#include <asm/ptrace.h>
 
-#ifdef __SMP__
-
-/*
- *	Locking the kernel 
+#ifndef __SMP__
+#define lock_kernel()		do { } while(0)
+#define unlock_kernel()		do { } while(0)
+
+typedef struct { } spinlock_t;
+#define SPIN_LOCK_UNLOCKED
+
+#define spin_lock_init(lock)	do { } while(0)
+#define spin_lock(lock)		do { } while(0)
+#define spin_trylock(lock)	do { } while(0)
+#define spin_unlock(lock)	do { } while(0)
+
+#define spin_lock_cli(lock)		\
+({	unsigned long flags;		\
+	save_flags(flags); cli();	\
+	return flags;			\
+})
+
+#define spin_unlock_restore(lock, flags)	restore_flags(flags)
+#else
+
+/* The following acquire and release the master kernel global lock,
+ * the idea is that the usage of this mechanmism becomes less and less
+ * as time goes on, to the point where they are no longer needed at all
+ * and can thus disappear.
  */
 
-/* Knock knock... */
+/* Do not fuck with this without consulting arch/sparc/lib/locks.S first! */
 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_flag)) {
-		if(proc == active_kernel_processor)
-			break;
-		do {
-#ifdef __SMP_PROF__		
-			smp_spins[smp_processor_id()]++;
-#endif			
-			barrier();
-		} while(kernel_flag); /* Don't lock the bus more than we have to. */
-	}
-	active_kernel_processor = proc;
-	kernel_counter++;
-	restore_flags(flags);
+	register struct klock_info *klip asm("g1");
+	register int proc asm("g5");
+	klip = &klock_info; proc = smp_processor_id();
+	__asm__ __volatile__("
+	mov	%%o7, %%g4
+	call	___lock_kernel
+	 ld	[%%g6 + %0], %%g2
+"	: : "i" (TASK_LOCK_DEPTH), "r" (klip), "r" (proc)
+	: "g2", "g3", "g4", "g7", "memory");
 }
 
-/* I want out... */
+/* Release kernel global lock. */
 extern __inline__ void unlock_kernel(void)
 {
-	unsigned long flags;
+	register struct klock_info *klip asm("g1");
+	klip = &klock_info;
+	__asm__ __volatile__("
+	mov	%%o7, %%g4
+	call	___unlock_kernel
+	 ld	[%%g6 + %0], %%g2
+"	: : "i" (TASK_LOCK_DEPTH), "r" (klip)
+	: "g2", "g3", "g4", "memory");
+}
 
-	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_flag = KLOCK_CLEAR;
-	}
-	restore_flags(flags);
+/* Simple spin lock operations.  There are two variants, one clears IRQ's
+ * on the local processor, one does not.
+ */
+
+typedef unsigned char spinlock_t;
+#define SPIN_LOCK_UNLOCKED	0
+
+extern __inline__ void spin_lock_init(spinlock_t *lock)
+{
+	*lock = 0;
+}
+
+extern __inline__ void spin_lock(spinlock_t *lock)
+{
+	register spinlock_t *lp asm("g1");
+	lp = lock;
+	__asm__ __volatile__("
+	ldstub	[%%g1], %%g2
+	orcc	%%g2, 0x0, %%g0
+	be	1f
+	 mov	%%o7, %%g4
+	call	___spinlock_waitfor
+	 ldub	[%%g1], %%g2
+1:"	: /* no outputs */
+	: "r" (lp)
+	: "g2", "g4", "memory");
+}
+
+extern __inline__ int spin_trylock(spinlock_t *lock)
+{
+	unsigned int result;
+
+	__asm__ __volatile__("
+	ldstub	[%1], %0
+"	: "=r" (result) : "r" (lock) : "memory");
+
+	return (result == 0);
+}
+
+extern __inline__ void spin_unlock(spinlock_t *lock)
+{
+	__asm__ __volatile__("stb	%%g0, [%0]" : : "r" (lock) : "memory");
+}
+
+/* These variants clear interrupts and return save_flags() style flags
+ * to the caller when acquiring a lock.  To release the lock you must
+ * pass the lock pointer as well as the flags returned from the acquisition
+ * routine when releasing the lock.
+ */
+extern __inline__ unsigned long spin_lock_cli(spinlock_t *lock)
+{
+	register spinlock_t *lp asm("g1");
+	register unsigned long flags asm("g3");
+	lp = lock;
+	__asm__ __volatile__("
+	rd	%%psr, %%g3
+	or	%%g3, %1, %%g4
+	wr	%%g4, 0, %%psr
+	nop; nop; nop;
+	ldstub	[%%g1], %%g2
+	orcc	%%g2, 0x0, %%g0
+	be	1f
+	 mov	%%o7, %%g4
+	call	___spinlock_waitfor
+	 ldub	[%%g1], %%g2
+1:"	: "=r" (flags)
+	: "i" (PSR_PIL), "r" (lp)
+	: "g2", "g4", "memory");
+	return flags;
+}
+
+extern __inline__ void spin_unlock_restore(spinlock_t *lock, unsigned long flags)
+{
+	__asm__ __volatile__("
+	stb	%%g0, [%0]
+	wr	%1, 0, %%psr
+	nop; nop; nop;
+"	: /* no outputs */
+	: "r" (lock), "r" (flags)
+	: "memory");
 }
 
 #endif /* !(__SPARC_SMPLOCK_H) */
diff -u --recursive --new-file v2.1.22/linux/include/asm-sparc/string.h linux/include/asm-sparc/string.h
--- v2.1.22/linux/include/asm-sparc/string.h	Tue Nov 12 15:56:13 1996
+++ linux/include/asm-sparc/string.h	Sun Jan 26 12:07:47 1997
@@ -1,4 +1,4 @@
-/* $Id: string.h,v 1.27 1996/10/27 08:55:50 davem Exp $
+/* $Id: string.h,v 1.28 1997/01/15 16:01:54 jj Exp $
  * string.h: External definitions for optimized assembly string
  *           routines for the Linux Kernel.
  *
@@ -15,8 +15,17 @@
 /* First the mem*() things. */
 #define __HAVE_ARCH_BCOPY
 #define __HAVE_ARCH_MEMMOVE
+extern void __memmove(void *,const void *,__kernel_size_t);
+
+#undef memmove
+#define memmove(_to, _from, _n) \
+({ \
+	__memmove(_to, _from, _n); \
+	_to; \
+})
+
 #define __HAVE_ARCH_MEMCPY
-extern void *__memcpy(void *,const void *,__kernel_size_t);
+extern void __memcpy(void *,const void *,__kernel_size_t);
 
 extern inline void *__constant_memcpy(void *to, const void *from, __kernel_size_t n)
 {
diff -u --recursive --new-file v2.1.22/linux/include/asm-sparc/system.h linux/include/asm-sparc/system.h
--- v2.1.22/linux/include/asm-sparc/system.h	Tue Dec 31 21:41:09 1996
+++ linux/include/asm-sparc/system.h	Sun Jan 26 12:07:47 1997
@@ -1,4 +1,4 @@
-/* $Id: system.h,v 1.47 1996/12/30 00:31:12 davem Exp $ */
+/* $Id: system.h,v 1.51 1997/01/25 01:33:05 davem Exp $ */
 #ifndef __SPARC_SYSTEM_H
 #define __SPARC_SYSTEM_H
 
@@ -55,14 +55,12 @@
 #define SWITCH_ENTER \
 	cli(); \
 	if(prev->flags & PF_USEDFPU) { \
+		put_psr(get_psr() | PSR_EF); \
 		fpsave(&prev->tss.float_regs[0], &prev->tss.fsr, \
 		       &prev->tss.fpqueue[0], &prev->tss.fpqdepth); \
 		prev->flags &= ~PF_USEDFPU; \
 		prev->tss.kregs->psr &= ~PSR_EF; \
-	} \
-	prev->lock_depth = syscall_count; \
-	kernel_counter += (next->lock_depth - prev->lock_depth); \
-	syscall_count = next->lock_depth;
+	}
 
 #define SWITCH_EXIT sti();
 #define SWITCH_DO_LAZY_FPU
@@ -235,33 +233,21 @@
 
 extern __inline__ unsigned long xchg_u32(__volatile__ unsigned long *m, unsigned long val)
 {
+	register unsigned long *ptr asm("g1");
+	register unsigned long ret asm("g2");
+
+	ptr = (unsigned long *) m;
+	ret = val;
+
 	__asm__ __volatile__("
-	rd	%%psr, %%g3
-	andcc	%%g3, %3, %%g0
-	bne	1f
-	 nop
-	wr	%%g3, %3, %%psr
-	nop
-	nop
-	nop
-1:
-	ld	[%1], %%g2
-	andcc	%%g3, %3, %%g0
-	st	%2, [%1]
-	bne	1f
-	 nop
-	wr	%%g3, 0x0, %%psr
-	nop
-	nop
-	nop
-1:
-	mov	%%g2, %0
-	"
-        : "=&r" (val)
-        : "r" (m), "0" (val), "i" (PSR_PIL)
-        : "g2", "g3");
+	mov	%%o7, %%g4
+	call	___xchg32
+	 add	%%o7, 8, %%o7
+"	: "=&r" (ret)
+	: "0" (ret), "r" (ptr)
+	: "g3", "g4", "g7", "memory");
 
-	return val;
+	return ret;
 }
 
 #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
diff -u --recursive --new-file v2.1.22/linux/include/asm-sparc/termios.h linux/include/asm-sparc/termios.h
--- v2.1.22/linux/include/asm-sparc/termios.h	Tue Dec 31 21:41:09 1996
+++ linux/include/asm-sparc/termios.h	Sun Jan 26 12:07:47 1997
@@ -1,4 +1,4 @@
-/* $Id: termios.h,v 1.23 1996/12/30 06:17:03 davem Exp $ */
+/* $Id: termios.h,v 1.24 1996/12/31 22:35:45 davem Exp $ */
 #ifndef _SPARC_TERMIOS_H
 #define _SPARC_TERMIOS_H
 
diff -u --recursive --new-file v2.1.22/linux/include/asm-sparc/uaccess.h linux/include/asm-sparc/uaccess.h
--- v2.1.22/linux/include/asm-sparc/uaccess.h	Wed Jan 15 19:45:45 1997
+++ linux/include/asm-sparc/uaccess.h	Sun Jan 26 12:07:47 1997
@@ -1,4 +1,4 @@
-/* $Id: uaccess.h,v 1.9 1996/12/03 08:44:54 jj Exp $ */
+/* $Id: uaccess.h,v 1.10 1997/01/16 14:19:03 davem Exp $ */
 #ifndef _ASM_UACCESS_H
 #define _ASM_UACCESS_H
 
diff -u --recursive --new-file v2.1.22/linux/include/asm-sparc/unistd.h linux/include/asm-sparc/unistd.h
--- v2.1.22/linux/include/asm-sparc/unistd.h	Tue Dec 31 21:41:09 1996
+++ linux/include/asm-sparc/unistd.h	Sun Jan 26 12:07:47 1997
@@ -1,4 +1,4 @@
-/* $Id: unistd.h,v 1.26 1996/12/29 20:49:14 davem Exp $ */
+/* $Id: unistd.h,v 1.28 1997/01/26 07:12:06 davem Exp $ */
 #ifndef _SPARC_UNISTD_H
 #define _SPARC_UNISTD_H
 
@@ -169,7 +169,7 @@
 #define __NR_getsockname        150 /* SunOS Specific                              */
 #define __NR_getmsg             151 /* SunOS Specific                              */
 #define __NR_putmsg             152 /* SunOS Specific                              */
-#define __NR_poll               153 /* SunOS Specific                              */
+#define __NR_poll               153 /* Common                                      */
 /* #define __NR_ni_syscall      154    ENOSYS under SunOS                          */
 #define __NR_nfssvc             155 /* SunOS Specific                              */
 #define __NR_getdirentries      156 /* SunOS Specific                              */
@@ -286,7 +286,7 @@
 		      : "=r" (__res)\
 		      : "0" (__NR_##name) \
 		      : "g1", "o0"); \
-if (__res >= 0) \
+if (__res < -255 || __res >= 0) \
     return (type) __res; \
 errno = -__res; \
 return -1; \
@@ -306,7 +306,7 @@
 		      : "=r" (__res), "=r" ((long)(arg1)) \
 		      : "0" (__NR_##name),"1" ((long)(arg1)) \
 		      : "g1", "o0"); \
-if (__res >= 0) \
+if (__res < -255 || __res >= 0) \
 	return (type) __res; \
 errno = -__res; \
 return -1; \
@@ -327,7 +327,7 @@
 		      : "=r" (__res), "=r" ((long)(arg1)), "=r" ((long)(arg2)) \
 		      : "0" (__NR_##name),"1" ((long)(arg1)),"2" ((long)(arg2)) \
 		      : "g1", "o0", "o1"); \
-if (__res >= 0) \
+if (__res < -255 || __res >= 0) \
 	return (type) __res; \
 errno = -__res; \
 return -1; \
@@ -351,7 +351,7 @@
 		      : "0" (__NR_##name), "1" ((long)(arg1)), "2" ((long)(arg2)), \
 		        "3" ((long)(arg3)) \
 		      : "g1", "o0", "o1", "o2"); \
-if (__res>=0) \
+if (__res < -255 || __res>=0) \
 	return (type) __res; \
 errno = -__res; \
 return -1; \
@@ -376,7 +376,7 @@
 		      : "0" (__NR_##name),"1" ((long)(arg1)),"2" ((long)(arg2)), \
 		        "3" ((long)(arg3)),"4" ((long)(arg4)) \
 		      : "g1", "o0", "o1", "o2", "o3"); \
-if (__res>=0) \
+if (__res < -255 || __res>=0) \
 	return (type) __res; \
 errno = -__res; \
 return -1; \
@@ -404,7 +404,7 @@
 		        "r" ((long)(arg3)),"r" ((long)(arg4)),"r" ((long)(arg5)), \
 		        "i" (__NR_##name)  \
 		      : "g1", "o0", "o1", "o2", "o3", "o4"); \
-if (__res>=0) \
+if (__res < -255 || __res>=0) \
 	return (type) __res; \
 errno = -__res; \
 return -1; \
diff -u --recursive --new-file v2.1.22/linux/include/asm-sparc64/sigcontext.h linux/include/asm-sparc64/sigcontext.h
--- v2.1.22/linux/include/asm-sparc64/sigcontext.h	Tue Dec 31 21:41:11 1996
+++ linux/include/asm-sparc64/sigcontext.h	Sun Jan 26 12:07:47 1997
@@ -1,4 +1,4 @@
-/* $Id: sigcontext.h,v 1.1 1996/12/26 14:22:36 davem Exp $ */
+/* $Id: sigcontext.h,v 1.2 1997/01/19 22:32:15 ecd Exp $ */
 #ifndef _ASMsparc64_SIGCONTEXT_H
 #define _ASMsparc64_SIGCONTEXT_H
 
@@ -39,19 +39,27 @@
 };
 
 typedef struct {
-	struct     pt_regs32 si_regs;
-	unsigned   int si_float_regs [64];
-	unsigned   int si_fsr;
-	unsigned   int si_fpqdepth;
+	struct pt_regs32	si_regs;
+	int			si_mask;
+} __siginfo32_t;
+
+typedef struct {
+	unsigned int si_float_regs [64];
+	unsigned int si_fsr;
+	unsigned int si_fpqdepth;
 	struct {
 		unsigned int *insn_addr;
 		unsigned int insn;
 	} si_fpqueue [16];
-	int si_mask;
-} __siginfo32_t;
+} __siginfo_fpu32_t;
+
 
 typedef struct {
 	struct     pt_regs si_regs;
+	int si_mask;
+} __siginfo_t;
+
+typedef struct {
 	unsigned   long si_float_regs [64];
 	unsigned   long si_fsr;
 	unsigned   int si_fpqdepth;
@@ -59,8 +67,7 @@
 		unsigned int *insn_addr;
 		unsigned int insn;
 	} si_fpqueue [16];
-	int si_mask;
-} __siginfo_t;
+} __siginfo_fpu_t;
 
 #endif /* !(__ASSEMBLY__) */
 
diff -u --recursive --new-file v2.1.22/linux/include/asm-sparc64/termios.h linux/include/asm-sparc64/termios.h
--- v2.1.22/linux/include/asm-sparc64/termios.h	Tue Dec 31 21:41:11 1996
+++ linux/include/asm-sparc64/termios.h	Sun Jan 26 12:07:47 1997
@@ -1,4 +1,4 @@
-/* $Id: termios.h,v 1.2 1996/12/30 03:31:12 davem Exp $ */
+/* $Id: termios.h,v 1.3 1996/12/31 22:35:49 davem Exp $ */
 #ifndef _SPARC64_TERMIOS_H
 #define _SPARC64_TERMIOS_H
 
diff -u --recursive --new-file v2.1.22/linux/include/asm-sparc64/uaccess.h linux/include/asm-sparc64/uaccess.h
--- v2.1.22/linux/include/asm-sparc64/uaccess.h	Wed Jan 15 19:45:45 1997
+++ linux/include/asm-sparc64/uaccess.h	Sun Jan 26 12:07:47 1997
@@ -1,4 +1,4 @@
-/* $Id: uaccess.h,v 1.2 1996/12/26 15:36:53 davem Exp $ */
+/* $Id: uaccess.h,v 1.3 1997/01/16 14:19:08 davem Exp $ */
 #ifndef _ASM_UACCESS_H
 #define _ASM_UACCESS_H
 
diff -u --recursive --new-file v2.1.22/linux/include/linux/binfmts.h linux/include/linux/binfmts.h
--- v2.1.22/linux/include/linux/binfmts.h	Fri Nov 22 18:28:21 1996
+++ linux/include/linux/binfmts.h	Sun Jan 26 12:07:48 1997
@@ -33,7 +33,7 @@
  */
 struct linux_binfmt {
 	struct linux_binfmt * next;
-	long *use_count;
+	struct module *module;
 	int (*load_binary)(struct linux_binprm *, struct  pt_regs * regs);
 	int (*load_shlib)(int fd);
 	int (*core_dump)(long signr, struct pt_regs * regs);
diff -u --recursive --new-file v2.1.22/linux/include/linux/etherdevice.h linux/include/linux/etherdevice.h
--- v2.1.22/linux/include/linux/etherdevice.h	Thu Dec 12 19:37:18 1996
+++ linux/include/linux/etherdevice.h	Sun Jan 26 12:23:32 1997
@@ -24,7 +24,7 @@
 #ifndef _LINUX_ETHERDEVICE_H
 #define _LINUX_ETHERDEVICE_H
 
-
+#include <linux/config.h>
 #include <linux/if_ether.h>
 
 #ifdef __KERNEL__
@@ -37,9 +37,17 @@
 						unsigned char * haddr);
 extern int		eth_header_cache(struct dst_entry *dst, struct dst_entry *neigh,
 					 struct hh_cache *hh);
+extern struct device	* init_etherdev(struct device *, int);
+
+#ifdef CONFIG_IP_ROUTER
+static void inline eth_copy_and_sum (struct sk_buff *dest, unsigned char *src, int len, int base)
+{
+    memcpy (dest->data, src, len);
+}
+#else
 extern void		eth_copy_and_sum(struct sk_buff *dest,
 				unsigned char *src, int length, int base);
-extern struct device	* init_etherdev(struct device *, int);
+#endif
 
 #endif
 
diff -u --recursive --new-file v2.1.22/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.1.22/linux/include/linux/fs.h	Wed Jan 15 19:45:45 1997
+++ linux/include/linux/fs.h	Sun Jan 26 12:21:08 1997
@@ -463,7 +463,7 @@
 	long (*read) (struct inode *, struct file *, char *, unsigned long);
 	long (*write) (struct inode *, struct file *, const char *, unsigned long);
 	int (*readdir) (struct inode *, struct file *, void *, filldir_t);
-	int (*select) (struct inode *, struct file *, int, select_table *);
+	unsigned int (*poll) (struct file *, poll_table *);
 	int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
 	int (*mmap) (struct inode *, struct file *, struct vm_area_struct *);
 	int (*open) (struct inode *, struct file *);
diff -u --recursive --new-file v2.1.22/linux/include/linux/init.h linux/include/linux/init.h
--- v2.1.22/linux/include/linux/init.h	Thu Jan  1 02:00:00 1970
+++ linux/include/linux/init.h	Sun Jan 26 12:07:48 1997
@@ -0,0 +1,55 @@
+#ifndef _LINUX_INIT_H
+#define _LINUX_INIT_H
+
+/* These macros are used to mark some functions or 
+ * initialized data (doesn't apply to uninitialized data)
+ * as `initialization' functions. The kernel can take this
+ * as hint that the function is used only during the initialization
+ * phase and free up used memory resources after
+ *
+ * Usage:
+ * For functions:
+ * you can surround the whole function declaration 
+ * just before function body into __initfunc() macro, like:
+ *
+ * __initfunc (static void initme(int x, int y))
+ * {
+ *    extern int z; z = x * y;
+ * }
+ *
+ * if the function has a prototype somewhere, you can also add
+ * __init between closing brace of the prototype and semicolon:
+ *
+ * extern int initialize_foobar_device(int, int, int) __init;
+ *
+ * For initialized data:
+ * you should insert __initdata between the variable name and equal
+ * sign followed by value, e.g.:
+ *
+ * static int init_variable __initdata = 0;
+ * static char linux_logo[] __initdata = { 0x32, 0x36, ... };
+ */
+
+#ifndef __init
+#if (defined (__svr4__) || defined (__ELF__)) && !defined (MODULE)
+#define __init __attribute__ ((__section__ (".text.init")))
+#define __initdata __attribute__ ((__section__ (".data.init")))
+#define __initfunc(__arginit) \
+	__arginit __init; \
+	__arginit
+/* For assembly routines */
+#define __INIT		.section	".text.init",#alloc,#execinstr
+#define __FINIT	.previous
+#define __INITDATA	.section	".data.init",#alloc,#write
+#else
+#define	__init
+#define __initdata
+#define __initfunc(__arginit) __arginit
+/* For assembly routines */
+#define __INIT
+#define __FINIT
+#define __INITDATA
+#endif
+#endif
+
+#endif
diff -u --recursive --new-file v2.1.22/linux/include/linux/ioport.h linux/include/linux/ioport.h
--- v2.1.22/linux/include/linux/ioport.h	Sat Dec 30 21:00:41 1995
+++ linux/include/linux/ioport.h	Sun Jan 26 12:07:48 1997
@@ -22,6 +22,11 @@
 extern void release_region(unsigned int from, unsigned int extent);
 extern int get_ioport_list(char *);
 
+#ifdef __sparc__
+extern unsigned int occupy_region(unsigned int base, unsigned int end,
+				  unsigned int num, unsigned int align,
+				  const char *name);
+#endif
 
 #define HAVE_AUTOIRQ
 extern void *irq2dev_map[16];		/* Use only if you own the IRQ. */
diff -u --recursive --new-file v2.1.22/linux/include/linux/locks.h linux/include/linux/locks.h
--- v2.1.22/linux/include/linux/locks.h	Sun Nov 10 20:12:14 1996
+++ linux/include/linux/locks.h	Sun Jan 26 12:21:08 1997
@@ -9,12 +9,6 @@
 #endif
 
 /*
- * Unlocked, temporary IO buffer_heads gets moved to the reuse_list
- * once their page becomes unlocked.  
- */
-extern struct buffer_head *reuse_list;
-
-/*
  * Buffer cache locking - note that interrupts may only unlock, not
  * lock buffers.
  */
diff -u --recursive --new-file v2.1.22/linux/include/linux/mm.h linux/include/linux/mm.h
--- v2.1.22/linux/include/linux/mm.h	Thu Jan  2 15:55:24 1997
+++ linux/include/linux/mm.h	Sun Jan 26 12:21:08 1997
@@ -75,6 +75,7 @@
 
 #define VM_EXECUTABLE	0x1000
 #define VM_LOCKED	0x2000
+#define VM_IO           0x4000  /* Memory mapped I/O or similar */
 
 #define VM_STACK_FLAGS	0x0177
 
@@ -273,6 +274,7 @@
 extern void si_meminfo(struct sysinfo * val);
 
 /* mmap.c */
+extern void vma_init(void);
 extern unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len,
 	unsigned long prot, unsigned long flags, unsigned long off);
 extern void merge_segments(struct mm_struct *, unsigned long, unsigned long);
diff -u --recursive --new-file v2.1.22/linux/include/linux/module.h linux/include/linux/module.h
--- v2.1.22/linux/include/linux/module.h	Thu Jan 23 21:06:51 1997
+++ linux/include/linux/module.h	Sun Jan 26 12:21:20 1997
@@ -7,6 +7,8 @@
 #ifndef _LINUX_MODULE_H
 #define _LINUX_MODULE_H
 
+#include <linux/config.h>
+
 #ifdef __GENKSYMS__
 #  define _set_ver(sym) sym
 #  undef  MODVERSIONS
@@ -22,7 +24,7 @@
 /* Don't need to bring in all of uaccess.h just for this decl.  */
 struct exception_table_entry;
 
-/* Used by get_kernel_syms, which is depreciated.  */
+/* Used by get_kernel_syms, which is obsolete.  */
 struct kernel_sym
 {
 	unsigned long value;
@@ -73,6 +75,7 @@
 	   to examine them.  */
 	const struct module_persist *persist_start;
 	const struct module_persist *persist_end;
+	int (*can_unload)(void);
 };
 
 struct module_info
@@ -80,6 +83,7 @@
   unsigned long addr;
   unsigned long size;
   unsigned long flags;
+	   long usecount;
 };
 
 /* Bits of module.flags.  */
@@ -99,20 +103,27 @@
 #define QM_SYMBOLS	4
 #define QM_INFO		5
 
+/* When struct module is extended, we must test whether the new member
+   is present in the header received from insmod before we can use it.  
+   This function returns true if the member is present.  */
+
+#define mod_member_present(mod,member) 					\
+	((unsigned long)(&((struct module *)0L)->member + 1)		\
+	 <= (mod)->size_of_struct)
+
 /* Backwards compatibility definition.  */
 
 #define GET_USE_COUNT(module)	((module)->usecount)
 
-/* When the struct module is extended, new values must be examined using
-   this macro.  It returns a pointer to the member if available, NULL
-   otherwise. */
-
-#define mod_opt_member(mod,member) 					\
-	({ struct module *_mod = (mod);					\
-	   __typeof__(_mod->member) *_mem = &_mod->member;		\
-	   ((char *)(_mem+1) > (char *)_mod + _mod->size_of_struct	\
-	    ? (__typeof__(_mod->member) *)NULL : _mem);			\
-	})
+/* Poke the use count of a module.  */
+
+#define __MOD_INC_USE_COUNT(mod)					\
+	((mod)->usecount++, (mod)->flags |= MOD_VISITED|MOD_USED_ONCE)
+#define __MOD_DEC_USE_COUNT(mod)					\
+	((mod)->usecount--, (mod)->flags |= MOD_VISITED)
+#define __MOD_IN_USE(mod)						\
+	(mod_member_present((mod), can_unload) && (mod)->can_unload	\
+	 ? (mod)->can_unload() : (mod)->usecount)
 
 /* Indirect stringification.  */
 
@@ -170,13 +181,9 @@
 /* Define the module variable, and usage macros.  */
 extern struct module __this_module;
 
-#define MOD_INC_USE_COUNT 					\
-	(__this_module.usecount++,				\
-	 __this_module.flags |= MOD_VISITED|MOD_USED_ONCE)
-#define MOD_DEC_USE_COUNT					\
-	(__this_module.usecount--, __this_module.flags |= MOD_VISITED)
-#define MOD_IN_USE						\
-	(__this_module.usecount != 0)
+#define MOD_INC_USE_COUNT	__MOD_INC_USE_COUNT(&__this_module)
+#define MOD_DEC_USE_COUNT	__MOD_DEC_USE_COUNT(&__this_module)
+#define MOD_IN_USE		__MOD_IN_USE(&__this_module)
 
 #ifndef __NO_VERSION__
 #include <linux/version.h>
@@ -221,12 +228,6 @@
 
 /* We want the EXPORT_SYMBOL tag left intact for recognition.  */
 
-#elif !defined(EXPORT_SYMTAB) && defined(CONFIG_MODULES)
-
-#define __EXPORT_SYMBOL(sym,str)   error EXPORT_SYMTAB_not_defined
-#define EXPORT_SYMBOL(var)	   error EXPORT_SYMTAB_not_defined
-#define EXPORT_SYMBOL_NOVERS(var)  error EXPORT_SYMTAB_not_defined
-
 #elif !defined(AUTOCONF_INCLUDED)
 
 #define __EXPORT_SYMBOL(sym,str)   error config_must_be_included_before_module
@@ -238,6 +239,14 @@
 #define __EXPORT_SYMBOL(sym,str)
 #define EXPORT_SYMBOL(var)
 #define EXPORT_SYMBOL_NOVERS(var)
+
+#elif !defined(EXPORT_SYMTAB)
+
+/* If things weren't set up in the Makefiles to get EXPORT_SYMTAB defined,
+   then they weren't set up to run genksyms properly so MODVERSIONS breaks.  */
+#define __EXPORT_SYMBOL(sym,str)   error EXPORT_SYMTAB_not_defined
+#define EXPORT_SYMBOL(var)	   error EXPORT_SYMTAB_not_defined
+#define EXPORT_SYMBOL_NOVERS(var)  error EXPORT_SYMTAB_not_defined
 
 #else
 
diff -u --recursive --new-file v2.1.22/linux/include/linux/mpp.h linux/include/linux/mpp.h
--- v2.1.22/linux/include/linux/mpp.h	Thu Jan  1 02:00:00 1970
+++ linux/include/linux/mpp.h	Sun Jan 26 12:07:48 1997
@@ -0,0 +1,18 @@
+#ifndef _LINUX_MPP_H
+#define _LINUX_MPP_H
+
+/*
+ * Definitions related to Massively Parallel Processing support.
+ */
+
+/* All mpp implementations must supply these functions */
+
+extern void mpp_init(void);
+extern void mpp_hw_init(void);
+extern void mpp_procfs_init(void);
+
+extern int mpp_num_cells(void);
+extern int mpp_cid(void);
+extern int get_mppinfo(char *buffer);
+
+#endif
diff -u --recursive --new-file v2.1.22/linux/include/linux/net.h linux/include/linux/net.h
--- v2.1.22/linux/include/linux/net.h	Thu Dec 12 19:37:19 1996
+++ linux/include/linux/net.h	Sat Jan 25 23:49:41 1997
@@ -93,8 +93,7 @@
 			 int flags);
   int	(*getname)	(struct socket *sock, struct sockaddr *uaddr,
 			 int *usockaddr_len, int peer);
-  int	(*select)	(struct socket *sock, int sel_type,
-			 select_table *wait);
+  unsigned int (*poll)	(struct socket *sock, poll_table *wait);
   int	(*ioctl)	(struct socket *sock, unsigned int cmd,
 			 unsigned long arg);
   int	(*listen)	(struct socket *sock, int len);
diff -u --recursive --new-file v2.1.22/linux/include/linux/pci.h linux/include/linux/pci.h
--- v2.1.22/linux/include/linux/pci.h	Thu Jan 23 21:06:51 1997
+++ linux/include/linux/pci.h	Fri Jan 24 20:57:22 1997
@@ -304,6 +304,7 @@
 #define PCI_VENDOR_ID_CT		0x102c
 #define PCI_DEVICE_ID_CT_65545		0x00d8
 #define PCI_DEVICE_ID_CT_65548		0x00dc
+#define PCI_DEVICE_ID_CT_65550		0x00e0
 
 #define PCI_VENDOR_ID_MIRO		0x1031
 #define PCI_DEVICE_ID_MIRO_36050	0x5601
diff -u --recursive --new-file v2.1.22/linux/include/linux/personality.h linux/include/linux/personality.h
--- v2.1.22/linux/include/linux/personality.h	Sun Aug 18 09:57:49 1996
+++ linux/include/linux/personality.h	Sun Jan 26 12:07:48 1997
@@ -37,7 +37,7 @@
 	unsigned char pers_low, pers_high;
 	unsigned long * signal_map;
 	unsigned long * signal_invmap;
-	long *use_count;
+	struct module * module;
 	struct exec_domain *next;
 };
 
diff -u --recursive --new-file v2.1.22/linux/include/linux/poll.h linux/include/linux/poll.h
--- v2.1.22/linux/include/linux/poll.h	Thu Jan  1 02:00:00 1970
+++ linux/include/linux/poll.h	Sat Jan 25 23:46:14 1997
@@ -0,0 +1 @@
+#include <asm/poll.h>
diff -u --recursive --new-file v2.1.22/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- v2.1.22/linux/include/linux/proc_fs.h	Sun Dec 22 16:37:41 1996
+++ linux/include/linux/proc_fs.h	Sun Jan 26 12:21:20 1997
@@ -46,7 +46,8 @@
 	PROC_MD,
 	PROC_RTC,
 	PROC_LOCKS,
-	PROC_ZORRO
+	PROC_ZORRO,
+	PROC_SLABINFO
 };
 
 enum pid_directory_inos {
diff -u --recursive --new-file v2.1.22/linux/include/linux/sched.h linux/include/linux/sched.h
--- v2.1.22/linux/include/linux/sched.h	Tue Dec 31 21:41:12 1996
+++ linux/include/linux/sched.h	Sun Jan 26 13:40:46 1997
@@ -154,7 +154,7 @@
 #define INIT_MM { \
 		1, \
 		swapper_pg_dir, \
-		0, \
+		-1, \
 		0, 0, 0, 0, \
 		0, 0, 0, 0, \
 		0, 0, 0, 0, \
@@ -167,6 +167,7 @@
 	struct sigaction action[32];
 };
 
+
 #define INIT_SIGNALS { \
 		1, \
 		{ {0,}, } }
@@ -245,11 +246,10 @@
 	struct mm_struct *mm;
 /* signal handlers */
 	struct signal_struct *sig;
-#ifdef __SMP__
+/* SMP state */
 	int processor;
 	int last_processor;
 	int lock_depth;		/* Lock depth. We can context switch in and out of holding a syscall kernel lock... */	
-#endif	
 };
 
 /*
@@ -311,6 +311,7 @@
 /* files */	&init_files, \
 /* mm */	&init_mm, \
 /* signals */	&init_signals, \
+/* SMP */	0,0,0, \
 }
 
 extern struct   mm_struct init_mm;
@@ -376,12 +377,10 @@
 extern void exit_fs(struct task_struct *);
 extern void exit_files(struct task_struct *);
 extern void exit_sighand(struct task_struct *);
-extern void release_thread(struct task_struct *);
 
 extern int do_execve(char *, char **, char **, struct pt_regs *);
 extern int do_fork(unsigned long, unsigned long, struct pt_regs *);
 
-
 /* See if we have a valid user level fd.
  * If it makes sense, return the file structure it references.
  * Otherwise return NULL.
@@ -445,13 +444,13 @@
 	restore_flags(flags);
 }
 
-extern inline void select_wait(struct wait_queue ** wait_address, select_table * p)
+extern inline void poll_wait(struct wait_queue ** wait_address, poll_table * p)
 {
-	struct select_table_entry * entry;
+	struct poll_table_entry * entry;
 
 	if (!p || !wait_address)
 		return;
-	if (p->nr >= __MAX_SELECT_TABLE_ENTRIES)
+	if (p->nr >= __MAX_POLL_TABLE_ENTRIES)
 		return;
  	entry = p->entry + p->nr;
 	entry->wait_address = wait_address;
diff -u --recursive --new-file v2.1.22/linux/include/linux/skbuff.h linux/include/linux/skbuff.h
--- v2.1.22/linux/include/linux/skbuff.h	Thu Jan 23 21:06:52 1997
+++ linux/include/linux/skbuff.h	Sun Jan 26 12:21:20 1997
@@ -545,7 +545,7 @@
 
 extern struct sk_buff *		skb_realloc_headroom(struct sk_buff *skb, int newheadroom);
 extern struct sk_buff *		skb_recv_datagram(struct sock *sk,unsigned flags,int noblock, int *err);
-extern int			datagram_select(struct socket *sock, int sel_type, select_table *wait);
+extern unsigned int		datagram_poll(struct socket *sock, poll_table *wait);
 extern int			skb_copy_datagram(struct sk_buff *from, int offset, char *to,int size);
 extern int			skb_copy_datagram_iovec(struct sk_buff *from, int offset, struct iovec *to,int size);
 extern void			skb_free_datagram(struct sock * sk, struct sk_buff *skb);
diff -u --recursive --new-file v2.1.22/linux/include/linux/slab.h linux/include/linux/slab.h
--- v2.1.22/linux/include/linux/slab.h	Thu Jan  1 02:00:00 1970
+++ linux/include/linux/slab.h	Sun Jan 26 12:21:08 1997
@@ -0,0 +1,60 @@
+/*
+ * linux/mm/slab.h
+ * Written by Mark Hemment, 1996.
+ * (markhe@nextd.demon.co.uk)
+ */
+
+#if	!defined(_LINUX_SLAB_H)
+#define	_LINUX_SLAB_H
+
+#if	defined(__KERNEL__)
+
+typedef struct kmem_cache_s kmem_cache_t;
+
+#include	<linux/mm.h>
+
+/* flags for kmem_cache_alloc() */
+#define	SLAB_BUFFER		GFP_BUFFER	/* 0x00 */
+#define	SLAB_ATOMIC		GFP_ATOMIC	/* 0x01 */
+#define	SLAB_USER		GFP_USER	/* 0x02 */
+#define	SLAB_KERNEL		GFP_KERNEL	/* 0x03 */
+#define	SLAB_NOBUFFER		GFP_NOBUFFER	/* 0x04 */
+#define	SLAB_NFS		GFP_NFS		/* 0x05 */
+#define	SLAB_DMA		GFP_DMA		/* 0x08 */
+#define	SLAB_LEVEL_MASK		GFP_LEVEL_MASK	/* 0x0f */
+#define	SLAB_NO_GROW		0x00001000UL	/* don't add another slab during an alloc */
+
+/* flags to pass to kmem_cache_create().
+ * The first 3 are only valid when the allocator has been build
+ * SLAB_DEBUG_SUPPORT.
+ */
+#define	SLAB_DEBUG_FREE		0x00000100UL	/* Peform time consuming ptr checks on free */
+#define	SLAB_DEBUG_INITIAL	0x00000200UL	/* Call constructor, on release, to conform state */
+#define	SLAB_RED_ZONE		0x00000400UL	/* Red zone objs in a cache */
+#define	SLAB_HWCACHE_ALIGN	0x00000800UL	/* align objs on an hw cache line */
+
+/* flags passed to a constructor func */
+#define	SLAB_CTOR_CONSTRUCTOR	0x001UL		/* if not set, then deconstructor */
+#define SLAB_CTOR_ATOMIC	0x002UL		/* tell constructor it can't sleep */
+#define	SLAB_DTOR_ATOMIC	0x002UL		/* tell deconstructor it can't sleep */
+#define	SLAB_CTOR_VERIFY	0x004UL		/* tell constructor it's a verify call */
+
+/* prototypes */
+extern long kmem_cache_init(long, long);
+extern void kmem_cache_sizes_init(void);
+extern struct kmem_cache_s *kmem_cache_create(const char *, unsigned long, unsigned long, unsigned long, void (*)(void *, int, unsigned long), void (*)(void *, int, unsigned long));
+extern int kmem_cache_destroy(struct kmem_cache_s *);
+extern int kmem_cache_shrink(struct kmem_cache_s *, int);
+extern void *kmem_cache_alloc(struct kmem_cache_s *, unsigned long);
+extern void kmem_cache_free(struct kmem_cache_s *, void *);
+extern void *kmem_alloc(unsigned long, unsigned long);
+extern void kmem_free(void *, unsigned long);
+extern int kmem_cache_reap(int, int, int);
+extern int get_slabinfo(char *);
+
+/* System wide slabs. */
+extern kmem_cache_t *vm_area_cachep;
+
+#endif	/* __KERNEL__ */
+
+#endif	/* _LINUX_SLAB_H */
diff -u --recursive --new-file v2.1.22/linux/include/linux/smp_lock.h linux/include/linux/smp_lock.h
--- v2.1.22/linux/include/linux/smp_lock.h	Mon Sep 30 11:21:59 1996
+++ linux/include/linux/smp_lock.h	Sun Jan 26 12:07:48 1997
@@ -1,9 +1,6 @@
 #ifndef __LINUX_SMPLOCK_H
 #define __LINUX_SMPLOCK_H
 
-#ifdef __SMP__
-#include <asm/pgtable.h>
 #include <asm/smp_lock.h>
-#endif
 
 #endif
diff -u --recursive --new-file v2.1.22/linux/include/linux/tasks.h linux/include/linux/tasks.h
--- v2.1.22/linux/include/linux/tasks.h	Mon Oct 30 10:00:21 1995
+++ linux/include/linux/tasks.h	Sun Jan 26 13:40:46 1997
@@ -16,4 +16,10 @@
 #define MAX_TASKS_PER_USER (NR_TASKS/2)
 #define MIN_TASKS_LEFT_FOR_ROOT 4
 
+
+/*
+ * This controls the maximum pid allocated to a process
+ */
+#define PID_MAX 0x8000
+
 #endif
diff -u --recursive --new-file v2.1.22/linux/include/linux/tty_ldisc.h linux/include/linux/tty_ldisc.h
--- v2.1.22/linux/include/linux/tty_ldisc.h	Sun Nov 10 20:12:15 1996
+++ linux/include/linux/tty_ldisc.h	Sun Jan 26 12:21:08 1997
@@ -119,9 +119,7 @@
 	int	(*ioctl)(struct tty_struct * tty, struct file * file,
 			 unsigned int cmd, unsigned long arg);
 	void	(*set_termios)(struct tty_struct *tty, struct termios * old);
-	int	(*select)(struct tty_struct * tty, struct inode * inode,
-			  struct file * file, int sel_type,
-			  struct select_table_struct *wait);
+	unsigned int (*poll)(struct tty_struct *, struct file *, poll_table *);
 	
 	/*
 	 * The following routines are called from below.
diff -u --recursive --new-file v2.1.22/linux/include/linux/wait.h linux/include/linux/wait.h
--- v2.1.22/linux/include/linux/wait.h	Sat Nov 30 12:03:11 1996
+++ linux/include/linux/wait.h	Sat Jan 25 23:46:14 1997
@@ -28,17 +28,17 @@
 	return head && head != WAIT_QUEUE_HEAD(q);
 }
 
-struct select_table_entry {
+struct poll_table_entry {
 	struct wait_queue wait;
 	struct wait_queue ** wait_address;
 };
 
-typedef struct select_table_struct {
+typedef struct poll_table_struct {
 	unsigned int nr;
-	struct select_table_entry * entry;
-} select_table;
+	struct poll_table_entry * entry;
+} poll_table;
 
-#define __MAX_SELECT_TABLE_ENTRIES (PAGE_SIZE / sizeof (struct select_table_entry))
+#define __MAX_POLL_TABLE_ENTRIES (PAGE_SIZE / sizeof (struct poll_table_entry))
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.1.22/linux/include/net/inet_common.h linux/include/net/inet_common.h
--- v2.1.22/linux/include/net/inet_common.h	Thu Dec 12 19:37:20 1996
+++ linux/include/net/inet_common.h	Sat Jan 25 23:46:14 1997
@@ -31,8 +31,7 @@
 					     struct msghdr *msg, 
 					     int size, struct scm_cookie *scm);
 extern int			inet_shutdown(struct socket *sock, int how);
-extern int			inet_select(struct socket *sock, int sel_type,
-					    select_table *wait);
+extern unsigned int		inet_poll(struct socket *sock, poll_table *wait);
 extern int			inet_setsockopt(struct socket *sock, int level,
 						int optname, char *optval, 
 						int optlen);
diff -u --recursive --new-file v2.1.22/linux/include/net/sock.h linux/include/net/sock.h
--- v2.1.22/linux/include/net/sock.h	Thu Jan 23 21:06:52 1997
+++ linux/include/net/sock.h	Sun Jan 26 12:23:35 1997
@@ -531,8 +531,7 @@
 	void			(*write_wakeup)(struct sock *sk);
 	void			(*read_wakeup)(struct sock *sk);
 
-	int			(*select)(struct socket *sock, int which,
-					  select_table *wait);
+	unsigned int		(*poll)(struct socket *sock, poll_table *wait);
 
 	int			(*ioctl)(struct sock *sk, int cmd,
 					 unsigned long arg);
diff -u --recursive --new-file v2.1.22/linux/include/net/tcp.h linux/include/net/tcp.h
--- v2.1.22/linux/include/net/tcp.h	Thu Dec 12 19:37:21 1996
+++ linux/include/net/tcp.h	Sun Jan 26 12:27:04 1997
@@ -265,8 +265,7 @@
 extern void			tcp_close(struct sock *sk, 
 					  unsigned long timeout);
 extern struct sock *		tcp_accept(struct sock *sk, int flags);
-extern int			tcp_select(struct socket *sock, int sel_type, 
-					   select_table *wait);
+extern unsigned int		tcp_poll(struct socket *sock, poll_table *wait);
 extern int			tcp_getsockopt(struct sock *sk, int level, 
 					       int optname, char *optval, 
 					       int *optlen);
diff -u --recursive --new-file v2.1.22/linux/init/main.c linux/init/main.c
--- v2.1.22/linux/init/main.c	Thu Jan 23 21:06:52 1997
+++ linux/init/main.c	Sun Jan 26 13:40:46 1997
@@ -28,6 +28,7 @@
 #include <linux/ioport.h>
 #include <linux/hdreg.h>
 #include <linux/mm.h>
+#include <linux/slab.h>
 #include <linux/major.h>
 #include <linux/blk.h>
 #ifdef CONFIG_ROOT_NFS
@@ -67,6 +68,7 @@
 extern void sock_init(void);
 extern unsigned long pci_init(unsigned long, unsigned long);
 extern long mca_init(long, long);
+extern long sbus_init(long, long);
 extern void sysctl_init(void);
 
 extern void smp_setup(char *str, int *ints);
@@ -200,6 +202,10 @@
 extern void ipc_init(void);
 #endif
 
+#ifdef __sparc__
+extern int serial_console;
+#endif
+
 /*
  * Boot command-line arguments
  */
@@ -607,6 +613,12 @@
 		{ "sonycd",  0x1800 },
 		{ "eza",     0x2800 },
 		{ "bpcd",    0x2900 },
+#if CONFIG_APBLOCK
+		{ "apblock", APBLOCK_MAJOR << 8},
+#endif
+#if CONFIG_DDV
+		{ "ddv", DDV_MAJOR << 8},
+#endif
 		{ NULL, 0 }
 	};
 
@@ -753,45 +765,28 @@
 
 
 
-/*
- *	Called by CPU#0 to activate the rest.
- */
- 
+/* Called by boot processor to activate the rest. */
 static void smp_init(void)
 {
 	int i, j;
+
+	/* Get other processors into their bootup holding patterns. */
 	smp_boot_cpus();
-	
-	/*
-	 *	Create the slave init tasks as sharing pid 0.
-	 *
-	 *	This should only happen if we have virtual CPU numbers
-	 *	higher than 0.
-	 */
 
+	/* Create the slave init tasks as sharing pid 0.  This should only
+	 * happen if we have virtual CPU numbers higher than 0.
+	 */
 	for (i=1; i<smp_num_cpus; i++)
 	{
-		struct task_struct *n, *p;
-
-		j = cpu_logical_map[i];
-		/*
-		 *	We use kernel_thread for the idlers which are
-		 *	unlocked tasks running in kernel space.
+		/* We use kernel_thread for the idlers which are
+		 * unlocked tasks running in kernel space.
 		 */
 		kernel_thread(cpu_idle, NULL, CLONE_PID);
-		/*
-		 *	Don't assume linear processor numbering
-		 */
+
+		/* Don't assume linear processor numbering */
+		j = cpu_logical_map[i];
 		current_set[j]=task[i];
 		current_set[j]->processor=j;
-		cli();
-		n = task[i]->next_run;
-		p = task[i]->prev_run;
-		nr_running--;
-		n->prev_run = p;
-		p->next_run = n;
-		task[i]->next_run = task[i]->prev_run = task[i];
-		sti();
 	}
 }		
 
@@ -859,6 +854,9 @@
 		memory_start += prof_len * sizeof(unsigned int);
 		memset(prof_buffer, 0, prof_len * sizeof(unsigned int));
 	}
+#ifdef CONFIG_SBUS
+	memory_start = sbus_init(memory_start,memory_end);
+#endif
 	memory_start = console_init(memory_start,memory_end);
 #ifdef CONFIG_PCI
 	memory_start = pci_init(memory_start,memory_end);
@@ -867,19 +865,22 @@
 	memory_start = mca_init(memory_start,memory_end);
 #endif
 	memory_start = kmalloc_init(memory_start,memory_end);
+	memory_start = kmem_cache_init(memory_start, memory_end);
 	sti();
 	calibrate_delay();
 	memory_start = inode_init(memory_start,memory_end);
 	memory_start = file_table_init(memory_start,memory_end);
 	memory_start = name_cache_init(memory_start,memory_end);
 #ifdef CONFIG_BLK_DEV_INITRD
-	if (initrd_start && initrd_start < memory_start) {
+	if (initrd_start && !initrd_below_start_ok && initrd_start < memory_start) {
 		printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - "
 		    "disabling it.\n",initrd_start,memory_start);
 		initrd_start = 0;
 	}
 #endif
 	mem_init(memory_start,memory_end);
+	kmem_cache_sizes_init();
+	vma_init();
 	buffer_init();
 	sock_init();
 #if defined(CONFIG_SYSVIPC) || defined(CONFIG_KERNELD)
@@ -943,6 +944,14 @@
 	/* Start the background pageout daemon. */
 	kernel_thread(kswapd, NULL, 0);
 
+#if CONFIG_AP1000
+	/* Start the async paging daemon. */
+	{
+	  extern int asyncd(void *);	 
+	  kernel_thread(asyncd, NULL, 0);
+	}
+#endif
+
 #ifdef CONFIG_BLK_DEV_INITRD
 	real_root_dev = ROOT_DEV;
 	real_root_mountflags = root_mountflags;
@@ -979,8 +988,8 @@
 	root_mountflags = real_root_mountflags;
 	if (mount_initrd && ROOT_DEV != real_root_dev && ROOT_DEV == MKDEV(RAMDISK_MAJOR,0)) {
 		int error;
-		int pid,i;
-		
+		int i, pid;
+
 		pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD);
 		if (pid>0)
 			while (pid != wait(&i));
@@ -992,17 +1001,18 @@
 		}
 	}
 #endif
-	
-	/*
-	 *	This keeps serial console MUCH cleaner, but does assume
-	 *	the console driver checks there really is a video device
-	 *	attached (Sparc effectively does).
-	 */
 
-	if ((open("/dev/tty1",O_RDWR,0) < 0) &&
-	    (open("/dev/ttyS0",O_RDWR,0) < 0))
-		printk("Unable to open an initial console.\n");
-			
+#ifdef __sparc__
+        if (serial_console == 1) {
+                (void) open("/dev/cua0", O_RDWR, 0);
+        } else if (serial_console == 2) {
+                (void) open("/dev/cua1", O_RDWR, 0);
+        } else {
+#endif
+                (void) open("/dev/tty1", O_RDWR, 0);
+#ifdef __sparc__
+        }
+#endif
 	(void) dup(0);
 	(void) dup(0);
 	
@@ -1013,7 +1023,7 @@
 	 * trying to recover a really broken machine.
 	 */
 
-	if (execute_command)
+	if(execute_command)
 		execve(execute_command,argv_init,envp_init);
 	execve("/sbin/init",argv_init,envp_init);
 	execve("/etc/init",argv_init,envp_init);
diff -u --recursive --new-file v2.1.22/linux/ipc/msg.c linux/ipc/msg.c
--- v2.1.22/linux/ipc/msg.c	Tue Oct 29 19:58:47 1996
+++ linux/ipc/msg.c	Sun Jan 26 12:07:48 1997
@@ -15,6 +15,8 @@
 #include <linux/malloc.h>
 #include <linux/kerneld.h>
 #include <linux/interrupt.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 
@@ -393,15 +395,25 @@
 
 asmlinkage int sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg)
 {
+	int ret;
+
 	/* IPC_KERNELD is used as a marker for kernel level calls */
-	return real_msgsnd(msqid, msgp, msgsz, msgflg & ~IPC_KERNELD);
+	lock_kernel();
+	ret = real_msgsnd(msqid, msgp, msgsz, msgflg & ~IPC_KERNELD);
+	unlock_kernel();
+	return ret;
 }
 
 asmlinkage int sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz,
 	long msgtyp, int msgflg)
 {
+	int ret;
+
 	/* IPC_KERNELD is used as a marker for kernel level calls */
-	return real_msgrcv (msqid, msgp, msgsz, msgtyp, msgflg & ~IPC_KERNELD);
+	lock_kernel();
+	ret = real_msgrcv (msqid, msgp, msgsz, msgtyp, msgflg & ~IPC_KERNELD);
+	unlock_kernel();
+	return ret;
 }
 
 static int findkey (key_t key)
@@ -463,51 +475,60 @@
 
 asmlinkage int sys_msgget (key_t key, int msgflg)
 {
-	int id;
+	int id, ret = -EPERM;
 	struct msqid_ds *msq;
 	
 	/*
 	 * If the IPC_KERNELD flag is set, the key is forced to IPC_PRIVATE,
 	 * and a designated kerneld message queue is created/referred to
 	 */
+	lock_kernel();
 	if ((msgflg & IPC_KERNELD)) {
 		int i;
 		if (!suser())
-			return -EPERM;
+			goto out;
 #ifdef NEW_KERNELD_PROTOCOL
 		if ((msgflg & IPC_KERNELD) == OLDIPC_KERNELD) {
 			printk(KERN_ALERT "Please recompile your kerneld daemons!\n");
-			return -EPERM;
+			goto out;
 		}
 #endif
+		ret = -ENOSPC;
 		if ((kerneld_msqid == -1) && (kerneld_msqid =
 				newque(IPC_PRIVATE, msgflg & S_IRWXU)) < 0)
-			return -ENOSPC;
+			goto out;
 		for (i = 0; i < MAX_KERNELDS; ++i) {
 			if (kerneld_arr[i] == 0) {
 				kerneld_arr[i] = current->pid;
 				++n_kernelds;
-				return kerneld_msqid;
+				ret = kerneld_msqid;
+				goto out;
 			}
 		}
-		return -ENOSPC;
+		goto out;
 	}
 	/* else it is a "normal" request */
 	if (key == IPC_PRIVATE) 
-		return newque(key, msgflg);
-	if ((id = findkey (key)) == -1) { /* key not used */
+		ret = newque(key, msgflg);
+	else if ((id = findkey (key)) == -1) { /* key not used */
 		if (!(msgflg & IPC_CREAT))
-			return -ENOENT;
-		return newque(key, msgflg);
-	}
-	if (msgflg & IPC_CREAT && msgflg & IPC_EXCL)
-		return -EEXIST;
-	msq = msgque[id];
-	if (msq == IPC_UNUSED || msq == IPC_NOID)
-		return -EIDRM;
-	if (ipcperms(&msq->msg_perm, msgflg))
-		return -EACCES;
-	return (unsigned int) msq->msg_perm.seq * MSGMNI + id;
+			ret = -ENOENT;
+		else
+			ret = newque(key, msgflg);
+	} else if (msgflg & IPC_CREAT && msgflg & IPC_EXCL) {
+		ret = -EEXIST;
+	} else {
+		msq = msgque[id];
+		if (msq == IPC_UNUSED || msq == IPC_NOID)
+			ret = -EIDRM;
+		else if (ipcperms(&msq->msg_perm, msgflg))
+			ret = -EACCES;
+		else
+			ret = (unsigned int) msq->msg_perm.seq * MSGMNI + id;
+	}
+out:
+	unlock_kernel();
+	return ret;
 } 
 
 static void freeque (int id)
@@ -537,18 +558,20 @@
 
 asmlinkage int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf)
 {
-	int id, err;
+	int id, err = -EINVAL;
 	struct msqid_ds *msq;
 	struct msqid_ds tbuf;
 	struct ipc_perm *ipcp;
 	
+	lock_kernel();
 	if (msqid < 0 || cmd < 0)
-		return -EINVAL;
+		goto out;
+	err = -EFAULT;
 	switch (cmd) {
 	case IPC_INFO: 
 	case MSG_INFO: 
 		if (!buf)
-			return -EFAULT;
+			goto out;
 	{ 
 		struct msginfo msginfo;
 		msginfo.msgmni = MSGMNI;
@@ -566,23 +589,26 @@
 		}
 		err = verify_area (VERIFY_WRITE, buf, sizeof (struct msginfo));
 		if (err)
-			return err;
+			goto out;
 		copy_to_user (buf, &msginfo, sizeof(struct msginfo));
-		return max_msqid;
+		err = max_msqid;
+		goto out;
 	}
 	case MSG_STAT:
 		if (!buf)
-			return -EFAULT;
+			goto out;
 		err = verify_area (VERIFY_WRITE, buf, sizeof (*buf));
 		if (err)
-			return err;
+			goto out;
+		err = -EINVAL;
 		if (msqid > max_msqid)
-			return -EINVAL;
+			goto out;
 		msq = msgque[msqid];
 		if (msq == IPC_UNUSED || msq == IPC_NOID)
-			return -EINVAL;
+			goto out;
+		err = -EACCES;
 		if (ipcperms (&msq->msg_perm, S_IRUGO))
-			return -EACCES;
+			goto out;
 		id = (unsigned int) msq->msg_perm.seq * MSGMNI + msqid;
 		tbuf.msg_perm   = msq->msg_perm;
 		tbuf.msg_stime  = msq->msg_stime;
@@ -594,36 +620,40 @@
 		tbuf.msg_lspid  = msq->msg_lspid;
 		tbuf.msg_lrpid  = msq->msg_lrpid;
 		copy_to_user (buf, &tbuf, sizeof(*buf));
-		return id;
+		err = id;
+		goto out;
 	case IPC_SET:
 		if (!buf)
-			return -EFAULT;
+			goto out;
 		err = verify_area (VERIFY_READ, buf, sizeof (*buf));
 		if (err)
-			return err;
+			goto out;
 		copy_from_user (&tbuf, buf, sizeof (*buf));
 		break;
 	case IPC_STAT:
 		if (!buf)
-			return -EFAULT;
+			goto out;
 		err = verify_area (VERIFY_WRITE, buf, sizeof(*buf));
 		if (err)
-			return err;
+			goto out;
 		break;
 	}
 
 	id = (unsigned int) msqid % MSGMNI;
 	msq = msgque [id];
+	err = -EINVAL;
 	if (msq == IPC_UNUSED || msq == IPC_NOID)
-		return -EINVAL;
+		goto out;
+	err = -EIDRM;
 	if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI)
-		return -EIDRM;
+		goto out;
 	ipcp = &msq->msg_perm;
 
 	switch (cmd) {
 	case IPC_STAT:
+		err = -EACCES;
 		if (ipcperms (ipcp, S_IRUGO))
-			return -EACCES;
+			goto out;
 		tbuf.msg_perm   = msq->msg_perm;
 		tbuf.msg_stime  = msq->msg_stime;
 		tbuf.msg_rtime  = msq->msg_rtime;
@@ -634,24 +664,28 @@
 		tbuf.msg_lspid  = msq->msg_lspid;
 		tbuf.msg_lrpid  = msq->msg_lrpid;
 		copy_to_user (buf, &tbuf, sizeof (*buf));
-		return 0;
+		err = 0;
+		goto out;
 	case IPC_SET:
+		err = -EPERM;
 		if (!suser() && current->euid != ipcp->cuid && 
 		    current->euid != ipcp->uid)
-			return -EPERM;
+			goto out;
 		if (tbuf.msg_qbytes > MSGMNB && !suser())
-			return -EPERM;
+			goto out;
 		msq->msg_qbytes = tbuf.msg_qbytes;
 		ipcp->uid = tbuf.msg_perm.uid;
 		ipcp->gid =  tbuf.msg_perm.gid;
 		ipcp->mode = (ipcp->mode & ~S_IRWXUGO) | 
 			(S_IRWXUGO & tbuf.msg_perm.mode);
 		msq->msg_ctime = CURRENT_TIME;
-		return 0;
+		err = 0;
+		goto out;
 	case IPC_RMID:
+		err = -EPERM;
 		if (!suser() && current->euid != ipcp->cuid && 
 		    current->euid != ipcp->uid)
-			return -EPERM;
+			goto out;
 		/*
 		 * There is only one kerneld message queue,
 		 * mark it as non-existent
@@ -659,10 +693,15 @@
 		if ((kerneld_msqid >= 0) && (msqid == kerneld_msqid))
 			kerneld_msqid = -1;
 		freeque (id); 
-		return 0;
+		err = 0;
+		goto out;
 	default:
-		return -EINVAL;
+		err = -EINVAL;
+		goto out;
 	}
+out:
+	unlock_kernel();
+	return err;
 }
 
 /*
diff -u --recursive --new-file v2.1.22/linux/ipc/sem.c linux/ipc/sem.c
--- v2.1.22/linux/ipc/sem.c	Tue Oct 29 19:58:47 1996
+++ linux/ipc/sem.c	Sun Jan 26 12:07:48 1997
@@ -38,6 +38,8 @@
 #include <linux/ipc.h>
 #include <linux/stat.h>
 #include <linux/malloc.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 
@@ -130,26 +132,33 @@
 
 asmlinkage int sys_semget (key_t key, int nsems, int semflg)
 {
-	int id;
+	int id, err = -EINVAL;
 	struct semid_ds *sma;
 
+	lock_kernel();
 	if (nsems < 0 || nsems > SEMMSL)
-		return -EINVAL;
-	if (key == IPC_PRIVATE)
-		return newary(key, nsems, semflg);
-	if ((id = findkey (key)) == -1) {  /* key not used */
+		goto out;
+	if (key == IPC_PRIVATE) {
+		err = newary(key, nsems, semflg);
+	} else if ((id = findkey (key)) == -1) {  /* key not used */
 		if (!(semflg & IPC_CREAT))
-			return -ENOENT;
-		return newary(key, nsems, semflg);
-	}
-	if (semflg & IPC_CREAT && semflg & IPC_EXCL)
-		return -EEXIST;
-	sma = semary[id];
-	if (nsems > sma->sem_nsems)
-		return -EINVAL;
-	if (ipcperms(&sma->sem_perm, semflg))
-		return -EACCES;
-	return (unsigned int) sma->sem_perm.seq * SEMMNI + id;
+			err = -ENOENT;
+		else
+			err = newary(key, nsems, semflg);
+	} else if (semflg & IPC_CREAT && semflg & IPC_EXCL) {
+		err = -EEXIST;
+	} else {
+		sma = semary[id];
+		if (nsems > sma->sem_nsems)
+			err = -EINVAL;
+		else if (ipcperms(&sma->sem_perm, semflg))
+			err = -EACCES;
+		else
+			err = (int) sma->sem_perm.seq * SEMMNI + id;
+	}
+out:
+	unlock_kernel();
+	return err;
 }
 
 /* Manage the doubly linked list sma->sem_pending as a FIFO:
@@ -368,9 +377,11 @@
 	unsigned int nsems;
 	ushort *array = NULL;
 	ushort sem_io[SEMMSL];
+	int err = -EINVAL;
 
+	lock_kernel();
 	if (semid < 0 || semnum < 0 || cmd < 0)
-		return -EINVAL;
+		goto out;
 
 	switch (cmd) {
 	case IPC_INFO:
@@ -391,42 +402,48 @@
 			seminfo.semusz = used_semids;
 			seminfo.semaem = used_sems;
 		}
-		i = verify_area(VERIFY_WRITE, tmp, sizeof(struct seminfo));
-		if (i)
-			return i;
+		err = verify_area(VERIFY_WRITE, tmp, sizeof(struct seminfo));
+		if (err)
+			goto out;
 		copy_to_user (tmp, &seminfo, sizeof(struct seminfo));
-		return max_semid;
+		err = max_semid;
+		goto out;
 	}
 
 	case SEM_STAT:
 		buf = arg.buf;
-		i = verify_area (VERIFY_WRITE, buf, sizeof (*buf));
-		if (i)
-			return i;
+		err = verify_area (VERIFY_WRITE, buf, sizeof (*buf));
+		if (err)
+			goto out;
+		err = -EINVAL;
 		if (semid > max_semid)
-			return -EINVAL;
+			goto out;
 		sma = semary[semid];
 		if (sma == IPC_UNUSED || sma == IPC_NOID)
-			return -EINVAL;
+			goto out;
+		err = -EACCES;
 		if (ipcperms (&sma->sem_perm, S_IRUGO))
-			return -EACCES;
+			goto out;
 		id = (unsigned int) sma->sem_perm.seq * SEMMNI + semid;
 		tbuf.sem_perm   = sma->sem_perm;
 		tbuf.sem_otime  = sma->sem_otime;
 		tbuf.sem_ctime  = sma->sem_ctime;
 		tbuf.sem_nsems  = sma->sem_nsems;
 		copy_to_user (buf, &tbuf, sizeof(*buf));
-		return id;
+		err = id;
+		goto out;
 	}
 
 	id = (unsigned int) semid % SEMMNI;
 	sma = semary [id];
+	err = -EINVAL;
 	if (sma == IPC_UNUSED || sma == IPC_NOID)
-		return -EINVAL;
+		goto out;
 	ipcp = &sma->sem_perm;
 	nsems = sma->sem_nsems;
+	err = -EIDRM;
 	if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI)
-		return -EIDRM;
+		goto out;
 
 	switch (cmd) {
 	case GETVAL:
@@ -434,8 +451,9 @@
 	case GETNCNT:
 	case GETZCNT:
 	case SETVAL:
+		err = -EINVAL;
 		if (semnum >= nsems)
-			return -EINVAL;
+			goto out;
 		curr = &sma->sem_base[semnum];
 		break;
 	}
@@ -446,8 +464,9 @@
 	case GETNCNT:
 	case GETZCNT:
 	case GETALL:
+		err = -EACCES;
 		if (ipcperms (ipcp, S_IRUGO))
-			return -EACCES;
+			goto out;
 		switch (cmd) {
 		case GETVAL : return curr->semval;
 		case GETPID : return curr->sempid;
@@ -455,60 +474,68 @@
 		case GETZCNT: return count_semzcnt(sma,semnum);
 		case GETALL:
 			array = arg.array;
-			i = verify_area (VERIFY_WRITE, array, nsems*sizeof(ushort));
-			if (i)
-				return i;
+			err = verify_area (VERIFY_WRITE, array, nsems*sizeof(ushort));
+			if (err)
+				goto out;
 		}
 		break;
 	case SETVAL:
 		val = arg.val;
+		err = -ERANGE;
 		if (val > SEMVMX || val < 0)
-			return -ERANGE;
+			goto out;
 		break;
 	case IPC_RMID:
 		if (suser() || current->euid == ipcp->cuid || current->euid == ipcp->uid) {
 			freeary (id);
-			return 0;
+			err = 0;
+			goto out;
 		}
-		return -EPERM;
+		err = -EPERM;
+		goto out;
 	case SETALL: /* arg is a pointer to an array of ushort */
 		array = arg.array;
-		if ((i = verify_area (VERIFY_READ, array, nsems*sizeof(ushort))))
-			return i;
+		if ((err = verify_area (VERIFY_READ, array, nsems*sizeof(ushort))))
+			goto out;
 		copy_from_user (sem_io, array, nsems*sizeof(ushort));
 		for (i = 0; i < nsems; i++)
-			if (sem_io[i] > SEMVMX)
-				return -ERANGE;
+			if (sem_io[i] > SEMVMX) {
+				err = -ERANGE;
+				goto out;
+			}
 		break;
 	case IPC_STAT:
 		buf = arg.buf;
-		if ((i = verify_area (VERIFY_WRITE, buf, sizeof(*buf))))
-			return i;
+		if ((err = verify_area (VERIFY_WRITE, buf, sizeof(*buf))))
+			goto out;
 		break;
 	case IPC_SET:
 		buf = arg.buf;
-		if ((i = verify_area (VERIFY_READ, buf, sizeof (*buf))))
-			return i;
+		if ((err = verify_area (VERIFY_READ, buf, sizeof (*buf))))
+			goto out;
 		copy_from_user (&tbuf, buf, sizeof (*buf));
 		break;
 	}
 
+	err = -EIDRM;
 	if (semary[id] == IPC_UNUSED || semary[id] == IPC_NOID)
-		return -EIDRM;
+		goto out;
 	if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI)
-		return -EIDRM;
+		goto out;
 
 	switch (cmd) {
 	case GETALL:
+		err = -EACCES;
 		if (ipcperms (ipcp, S_IRUGO))
-			return -EACCES;
+			goto out;
 		for (i = 0; i < sma->sem_nsems; i++)
 			sem_io[i] = sma->sem_base[i].semval;
 		copy_to_user (array, sem_io, nsems*sizeof(ushort));
 		break;
 	case SETVAL:
+		err = -EACCES;
 		if (ipcperms (ipcp, S_IWUGO))
-			return -EACCES;
+			goto out;
 		for (un = sma->undo; un; un = un->id_next)
 			un->semadj[semnum] = 0;
 		curr->semval = val;
@@ -523,12 +550,15 @@
 			ipcp->mode = (ipcp->mode & ~S_IRWXUGO)
 				| (tbuf.sem_perm.mode & S_IRWXUGO);
 			sma->sem_ctime = CURRENT_TIME;
-			return 0;
+			err = 0;
+			goto out;
 		}
-		return -EPERM;
+		err = -EPERM;
+		goto out;
 	case IPC_STAT:
+		err = -EACCES;
 		if (ipcperms (ipcp, S_IRUGO))
-			return -EACCES;
+			goto out;
 		tbuf.sem_perm   = sma->sem_perm;
 		tbuf.sem_otime  = sma->sem_otime;
 		tbuf.sem_ctime  = sma->sem_ctime;
@@ -536,8 +566,9 @@
 		copy_to_user (buf, &tbuf, sizeof(*buf));
 		break;
 	case SETALL:
+		err = -EACCES;
 		if (ipcperms (ipcp, S_IWUGO))
-			return -EACCES;
+			goto out;
 		for (i = 0; i < nsems; i++)
 			sma->sem_base[i].semval = sem_io[i];
 		for (un = sma->undo; un; un = un->id_next)
@@ -548,47 +579,58 @@
 		update_queue(sma);
 		break;
 	default:
-		return -EINVAL;
+		err = -EINVAL;
+		goto out;
 	}
-	return 0;
+	err = 0;
+out:
+	unlock_kernel();
+	return err;
 }
 
 asmlinkage int sys_semop (int semid, struct sembuf *tsops, unsigned nsops)
 {
-	int i, id, size, error;
+	int i, id, size, error = -EINVAL;
 	struct semid_ds *sma;
 	struct sembuf sops[SEMOPM], *sop;
 	struct sem_undo *un;
 	int undos = 0, alter = 0;
 
+	lock_kernel();
 	if (nsops < 1 || semid < 0)
-		return -EINVAL;
+		goto out;
+	error = -E2BIG;
 	if (nsops > SEMOPM)
-		return -E2BIG;
+		goto out;
+	error = -EFAULT;
 	if (!tsops)
-		return -EFAULT;
+		goto out;
 	if ((i = verify_area (VERIFY_READ, tsops, nsops * sizeof(*tsops))))
-		return i;
+		goto out;
 	copy_from_user (sops, tsops, nsops * sizeof(*tsops));
 	id = (unsigned int) semid % SEMMNI;
+	error = -EINVAL;
 	if ((sma = semary[id]) == IPC_UNUSED || sma == IPC_NOID)
-		return -EINVAL;
+		goto out;
+	error = -EIDRM;
 	if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI)
-		return -EIDRM;
+		goto out;
 	for (i = 0; i < nsops; i++) {
 		sop = &sops[i];
+		error = -EFBIG;
 		if (sop->sem_num >= sma->sem_nsems)
-			return -EFBIG;
+			goto out;
 		if (sop->sem_flg & SEM_UNDO)
 			undos++;
 		if (sop->sem_op)
 			alter++;
 	}
+	error = -EACCES;
 	if (ipcperms(&sma->sem_perm, alter ? S_IWUGO : S_IRUGO))
-		return -EACCES;
+		goto out;
 	error = try_semop(sma, sops, nsops);
 	if (error < 0)
-		return error;
+		goto out;
 	if (undos) {
 		/* Make sure we have an undo structure
 		 * for this process and this semaphore set.
@@ -599,8 +641,10 @@
 		if (!un) {
 			size = sizeof(struct sem_undo) + sizeof(short)*sma->sem_nsems;
 			un = (struct sem_undo *) kmalloc(size, GFP_ATOMIC);
-			if (!un)
-				return -ENOMEM;
+			if (!un) {
+				error = -ENOMEM;
+				goto out;
+			}
 			memset(un, 0, size);
 			un->semadj = (short *) &un[1];
 			un->semid = semid;
@@ -616,7 +660,7 @@
 		error = do_semop(sma, sops, nsops, un, current->pid);
 		/* maybe some queued-up processes were waiting for this */
 		update_queue(sma);
-		return error;
+		goto out;
 	} else {
 		/* We need to sleep on this operation, so we put the current
 		 * task into the pending queue and go to sleep.
@@ -639,12 +683,15 @@
 		 */
 		if (!queue.prev) {
 			/* operation is finished, update_queue() removed us */
-			return queue.status;
+			error = queue.status;
 		} else {
 			remove_from_queue(sma,&queue);
-			return -EINTR;
+			error = -EINTR;
 		}
 	}
+out:
+	unlock_kernel();
+	return error;
 }
 
 /*
diff -u --recursive --new-file v2.1.22/linux/ipc/shm.c linux/ipc/shm.c
--- v2.1.22/linux/ipc/shm.c	Sun Dec 22 16:37:42 1996
+++ linux/ipc/shm.c	Sun Jan 26 12:07:48 1997
@@ -8,11 +8,14 @@
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
+#include <linux/slab.h>
 #include <linux/ipc.h>
 #include <linux/shm.h>
 #include <linux/stat.h>
 #include <linux/malloc.h>
 #include <linux/swap.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -130,27 +133,33 @@
 asmlinkage int sys_shmget (key_t key, int size, int shmflg)
 {
 	struct shmid_ds *shp;
-	int id = 0;
+	int err, id = 0;
 
-	if (size < 0 || size > SHMMAX)
-		return -EINVAL;
-	if (key == IPC_PRIVATE)
-		return newseg(key, shmflg, size);
-	if ((id = findkey (key)) == -1) {
+	lock_kernel();
+	if (size < 0 || size > SHMMAX) {
+		err = -EINVAL;
+	} else if (key == IPC_PRIVATE) {
+		err = newseg(key, shmflg, size);
+	} else if ((id = findkey (key)) == -1) {
 		if (!(shmflg & IPC_CREAT))
-			return -ENOENT;
-		return newseg(key, shmflg, size);
+			err = -ENOENT;
+		else
+			err = newseg(key, shmflg, size);
+	} else if ((shmflg & IPC_CREAT) && (shmflg & IPC_EXCL)) {
+		err = -EEXIST;
+	} else {
+		shp = shm_segs[id];
+		if (shp->shm_perm.mode & SHM_DEST)
+			err = -EIDRM;
+		else if (size > shp->shm_segsz)
+			err = -EINVAL;
+		else if (ipcperms (&shp->shm_perm, shmflg))
+			err = -EACCES;
+		else
+			err = (int) shp->shm_perm.seq * SHMMNI + id;
 	}
-	if ((shmflg & IPC_CREAT) && (shmflg & IPC_EXCL))
-		return -EEXIST;
-	shp = shm_segs[id];
-	if (shp->shm_perm.mode & SHM_DEST)
-		return -EIDRM;
-	if (size > shp->shm_segsz)
-		return -EINVAL;
-	if (ipcperms (&shp->shm_perm, shmflg))
-		return -EACCES;
-	return (unsigned int) shp->shm_perm.seq * SHMMNI + id;
+	unlock_kernel();
+	return err;
 }
 
 /*
@@ -202,16 +211,18 @@
 	struct shmid_ds tbuf;
 	struct shmid_ds *shp;
 	struct ipc_perm *ipcp;
-	int id, err;
+	int id, err = -EINVAL;
 
+	lock_kernel();
 	if (cmd < 0 || shmid < 0)
-		return -EINVAL;
+		goto out;
 	if (cmd == IPC_SET) {
+		err = -EFAULT;
 		if (!buf)
-			return -EFAULT;
+			goto out;
 		err = verify_area (VERIFY_READ, buf, sizeof (*buf));
 		if (err)
-			return err;
+			goto out;
 		copy_from_user (&tbuf, buf, sizeof (*buf));
 	}
 
@@ -219,8 +230,9 @@
 	case IPC_INFO:
 	{
 		struct shminfo shminfo;
+		err = -EFAULT;
 		if (!buf)
-			return -EFAULT;
+			goto out;
 		shminfo.shmmni = SHMMNI;
 		shminfo.shmmax = SHMMAX;
 		shminfo.shmmin = SHMMIN;
@@ -228,18 +240,20 @@
 		shminfo.shmseg = SHMSEG;
 		err = verify_area (VERIFY_WRITE, buf, sizeof (struct shminfo));
 		if (err)
-			return err;
+			goto out;
 		copy_to_user (buf, &shminfo, sizeof(struct shminfo));
-		return max_shmid;
+		err = max_shmid;
+		goto out;
 	}
 	case SHM_INFO:
 	{
 		struct shm_info shm_info;
+		err = -EFAULT;
 		if (!buf)
-			return -EFAULT;
+			goto out;
 		err = verify_area (VERIFY_WRITE, buf, sizeof (shm_info));
 		if (err)
-			return err;
+			goto out;
 		shm_info.used_ids = used_segs;
 		shm_info.shm_rss = shm_rss;
 		shm_info.shm_tot = shm_tot;
@@ -247,21 +261,24 @@
 		shm_info.swap_attempts = swap_attempts;
 		shm_info.swap_successes = swap_successes;
 		copy_to_user (buf, &shm_info, sizeof(shm_info));
-		return max_shmid;
+		err = max_shmid;
+		goto out;
 	}
 	case SHM_STAT:
+		err = -EFAULT;
 		if (!buf)
-			return -EFAULT;
+			goto out;
 		err = verify_area (VERIFY_WRITE, buf, sizeof (*buf));
 		if (err)
-			return err;
+			goto out;
+		err = -EINVAL;
 		if (shmid > max_shmid)
-			return -EINVAL;
+			goto out;
 		shp = shm_segs[shmid];
 		if (shp == IPC_UNUSED || shp == IPC_NOID)
-			return -EINVAL;
+			goto out;
 		if (ipcperms (&shp->shm_perm, S_IRUGO))
-			return -EACCES;
+			goto out;
 		id = (unsigned int) shp->shm_perm.seq * SHMMNI + shmid;
 		tbuf.shm_perm   = shp->shm_perm;
 		tbuf.shm_segsz  = shp->shm_segsz;
@@ -272,42 +289,51 @@
 		tbuf.shm_lpid   = shp->shm_lpid;
 		tbuf.shm_nattch = shp->shm_nattch;
 		copy_to_user (buf, &tbuf, sizeof(*buf));
-		return id;
+		err = id;
+		goto out;
 	}
 
 	shp = shm_segs[id = (unsigned int) shmid % SHMMNI];
+	err = -EINVAL;
 	if (shp == IPC_UNUSED || shp == IPC_NOID)
-		return -EINVAL;
+		goto out;
+	err = -EIDRM;
 	if (shp->shm_perm.seq != (unsigned int) shmid / SHMMNI)
-		return -EIDRM;
+		goto out;
 	ipcp = &shp->shm_perm;
 
 	switch (cmd) {
 	case SHM_UNLOCK:
+		err = -EPERM;
 		if (!suser())
-			return -EPERM;
+			goto out;
+		err = -EINVAL;
 		if (!(ipcp->mode & SHM_LOCKED))
-			return -EINVAL;
+			goto out;
 		ipcp->mode &= ~SHM_LOCKED;
 		break;
 	case SHM_LOCK:
 /* Allow superuser to lock segment in memory */
 /* Should the pages be faulted in here or leave it to user? */
 /* need to determine interaction with current->swappable */
+		err = -EPERM;
 		if (!suser())
-			return -EPERM;
+			goto out;
+		err = -EINVAL;
 		if (ipcp->mode & SHM_LOCKED)
-			return -EINVAL;
+			goto out;
 		ipcp->mode |= SHM_LOCKED;
 		break;
 	case IPC_STAT:
+		err = -EACCES;
 		if (ipcperms (ipcp, S_IRUGO))
-			return -EACCES;
+			goto out;
+		err = -EFAULT;
 		if (!buf)
-			return -EFAULT;
+			goto out;
 		err = verify_area (VERIFY_WRITE, buf, sizeof (*buf));
 		if (err)
-			return err;
+			goto out;
 		tbuf.shm_perm   = shp->shm_perm;
 		tbuf.shm_segsz  = shp->shm_segsz;
 		tbuf.shm_atime  = shp->shm_atime;
@@ -328,7 +354,8 @@
 			shp->shm_ctime = CURRENT_TIME;
 			break;
 		}
-		return -EPERM;
+		err = -EPERM;
+		goto out;
 	case IPC_RMID:
 		if (suser() || current->euid == shp->shm_perm.uid ||
 		    current->euid == shp->shm_perm.cuid) {
@@ -337,11 +364,16 @@
 				killseg (id);
 			break;
 		}
-		return -EPERM;
+		err = -EPERM;
+		goto out;
 	default:
-		return -EINVAL;
+		err = -EINVAL;
+		goto out;
 	}
-	return 0;
+	err = 0;
+out:
+	unlock_kernel();
+	return err;
 }
 
 /*
@@ -465,39 +497,42 @@
 {
 	struct shmid_ds *shp;
 	struct vm_area_struct *shmd;
-	int err;
+	int err = -EINVAL;
 	unsigned int id;
 	unsigned long addr;
 	unsigned long len;
 
+	lock_kernel();
 	if (shmid < 0) {
 		/* printk("shmat() -> EINVAL because shmid = %d < 0\n",shmid); */
-		return -EINVAL;
+		goto out;
 	}
 
 	shp = shm_segs[id = (unsigned int) shmid % SHMMNI];
 	if (shp == IPC_UNUSED || shp == IPC_NOID) {
 		/* printk("shmat() -> EINVAL because shmid = %d is invalid\n",shmid); */
-		return -EINVAL;
+		goto out;
 	}
 
 	if (!(addr = (ulong) shmaddr)) {
 		if (shmflg & SHM_REMAP)
-			return -EINVAL;
+			goto out;
+		err = -ENOMEM;
 		if (!(addr = get_unmapped_area(0, shp->shm_segsz)))
-			return -ENOMEM;
+			goto out;
 	} else if (addr & (SHMLBA-1)) {
 		if (shmflg & SHM_RND)
 			addr &= ~(SHMLBA-1);       /* round down */
 		else
-			return -EINVAL;
+			goto out;
 	}
 	/*
 	 * Check if addr exceeds TASK_SIZE (from do_mmap)
 	 */
 	len = PAGE_SIZE*shp->shm_npages;
-       if (addr >= TASK_SIZE || len > TASK_SIZE  || addr > TASK_SIZE - len)
-		return -EINVAL;
+	err = -EINVAL;
+	if (addr >= TASK_SIZE || len > TASK_SIZE  || addr > TASK_SIZE - len)
+		goto out;
 	/*
 	 * If shm segment goes below stack, make sure there is some
 	 * space left for the stack to grow (presently 4 pages).
@@ -506,26 +541,30 @@
 	    addr > current->mm->start_stack - PAGE_SIZE*(shp->shm_npages + 4))
 	{
 		/* printk("shmat() -> EINVAL because segment intersects stack\n"); */
-		return -EINVAL;
+		goto out;
 	}
 	if (!(shmflg & SHM_REMAP))
 		if ((shmd = find_vma_intersection(current->mm, addr, addr + shp->shm_segsz))) {
 			/* printk("shmat() -> EINVAL because the interval [0x%lx,0x%lx) intersects an already mapped interval [0x%lx,0x%lx).\n",
 				addr, addr + shp->shm_segsz, shmd->vm_start, shmd->vm_end); */
-			return -EINVAL;
+			goto out;
 		}
 
+	err = -EACCES;
 	if (ipcperms(&shp->shm_perm, shmflg & SHM_RDONLY ? S_IRUGO : S_IRUGO|S_IWUGO))
-		return -EACCES;
+		goto out;
+	err = -EIDRM;
 	if (shp->shm_perm.seq != (unsigned int) shmid / SHMMNI)
-		return -EIDRM;
+		goto out;
 
-	shmd = (struct vm_area_struct *) kmalloc (sizeof(*shmd), GFP_KERNEL);
+	err = -ENOMEM;
+	shmd = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
 	if (!shmd)
-		return -ENOMEM;
+		goto out;
 	if ((shp != shm_segs[id]) || (shp->shm_perm.seq != (unsigned int) shmid / SHMMNI)) {
-		kfree(shmd);
-		return -EIDRM;
+		kmem_cache_free(vm_area_cachep, shmd);
+		err = -EIDRM;
+		goto out;
 	}
 
 	shmd->vm_pte = SWP_ENTRY(SHM_SWP_TYPE, id);
@@ -545,8 +584,8 @@
 	if ((err = shm_map (shmd))) {
 		if (--shp->shm_nattch <= 0 && shp->shm_perm.mode & SHM_DEST)
 			killseg(id);
-		kfree(shmd);
-		return err;
+		kmem_cache_free(vm_area_cachep, shmd);
+		goto out;
 	}
 
 	insert_attach(shp,shmd);  /* insert shmd into shp->attaches */
@@ -555,7 +594,10 @@
 	shp->shm_atime = CURRENT_TIME;
 
 	*raddr = addr;
-	return 0;
+	err = 0;
+out:
+	unlock_kernel();
+	return err;
 }
 
 /* This is called by fork, once for every shm attach. */
diff -u --recursive --new-file v2.1.22/linux/kernel/exec_domain.c linux/kernel/exec_domain.c
--- v2.1.22/linux/kernel/exec_domain.c	Tue Jul 11 07:56:04 1995
+++ linux/kernel/exec_domain.c	Sun Jan 26 12:07:48 1997
@@ -2,6 +2,9 @@
 #include <linux/ptrace.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/module.h>
 
 static asmlinkage void no_lcall7(struct pt_regs * regs);
 
@@ -34,14 +37,14 @@
    * personality set incorrectly.  Check to see whether SVr4 is available,
    * and use it, otherwise give the user a SEGV.
    */
-	if (current->exec_domain && current->exec_domain->use_count)
-		(*current->exec_domain->use_count)--;
+	if (current->exec_domain && current->exec_domain->module)
+		__MOD_DEC_USE_COUNT(current->exec_domain->module);
 
 	current->personality = PER_SVR4;
 	current->exec_domain = lookup_exec_domain(current->personality);
 
-	if (current->exec_domain && current->exec_domain->use_count)
-		(*current->exec_domain->use_count)++;
+	if (current->exec_domain && current->exec_domain->module)
+		__MOD_INC_USE_COUNT(current->exec_domain->module);
 
 	if (current->exec_domain && current->exec_domain->handler
 	&& current->exec_domain->handler != no_lcall7) {
@@ -103,21 +106,27 @@
 {
 	struct exec_domain *it;
 	unsigned long old_personality;
+	int ret;
 
+	lock_kernel();
+	ret = current->personality;
 	if (personality == 0xffffffff)
-		return current->personality;
+		goto out;
 
+	ret = -EINVAL;
 	it = lookup_exec_domain(personality);
 	if (!it)
-		return -EINVAL;
+		goto out;
 
 	old_personality = current->personality;
-	if (current->exec_domain && current->exec_domain->use_count)
-		(*current->exec_domain->use_count)--;
+	if (current->exec_domain && current->exec_domain->module)
+		__MOD_DEC_USE_COUNT(current->exec_domain->module);
 	current->personality = personality;
 	current->exec_domain = it;
-	if (current->exec_domain->use_count)
-		(*current->exec_domain->use_count)++;
-
-	return old_personality;
+	if (current->exec_domain->module)
+		__MOD_INC_USE_COUNT(current->exec_domain->module);
+	ret = old_personality;
+out:
+	unlock_kernel();
+	return ret;
 }
diff -u --recursive --new-file v2.1.22/linux/kernel/exit.c linux/kernel/exit.c
--- v2.1.22/linux/kernel/exit.c	Tue Dec 31 21:41:12 1996
+++ linux/kernel/exit.c	Sun Jan 26 12:07:48 1997
@@ -6,6 +6,7 @@
 
 #undef DEBUG_PROC_TREE
 
+#include <linux/config.h>
 #include <linux/wait.h>
 #include <linux/errno.h>
 #include <linux/signal.h>
@@ -16,6 +17,9 @@
 #include <linux/tty.h>
 #include <linux/malloc.h>
 #include <linux/interrupt.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/module.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -69,7 +73,7 @@
 			wake_up_process(p);
 	}
 }
-		
+
 
 int send_sig(unsigned long sig,struct task_struct * p,int priv)
 {
@@ -131,7 +135,7 @@
 			current->cmin_flt += p->min_flt + p->cmin_flt;
 			current->cmaj_flt += p->maj_flt + p->cmaj_flt;
 			current->cnswap += p->nswap + p->cnswap;
-			kfree(p);
+			free_task_struct(p);
 			return;
 		}
 	panic("trying to release non-existent task");
@@ -153,14 +157,14 @@
 			return 0;
 	return 1;
 }
-	
+
 /*
  * This routine scans the pid tree and makes sure the rep invariant still
  * holds.  Used for debugging only, since it's very slow....
  *
  * It looks a lot scarier than it really is.... we're doing nothing more
- * than verifying the doubly-linked list found in p_ysptr and p_osptr, 
- * and checking it corresponds with the process tree defined by p_cptr and 
+ * than verifying the doubly-linked list found in p_ysptr and p_osptr,
+ * and checking it corresponds with the process tree defined by p_cptr and
  * p_pptr;
  */
 void audit_ptree(void)
@@ -320,8 +324,11 @@
 {
 	int err, retval = 0, count = 0;
 
-	if (!pid)
-		return(kill_pg(current->pgrp,sig,0));
+	lock_kernel();
+	if (!pid) {
+		err = kill_pg(current->pgrp,sig,0);
+		goto out;
+	}
 	if (pid == -1) {
 		struct task_struct * p;
 		for_each_task(p) {
@@ -331,20 +338,26 @@
 					retval = err;
 			}
 		}
-		return(count ? retval : -ESRCH);
+		err = count ? retval : -ESRCH;
+		goto out;
+	}
+	if (pid < 0) {
+		err = kill_pg(-pid,sig,0);
+		goto out;
 	}
-	if (pid < 0) 
-		return(kill_pg(-pid,sig,0));
 	/* Normal kill */
-	return(kill_proc(pid,sig,0));
+	err = kill_proc(pid,sig,0);
+out:
+	unlock_kernel();
+	return err;
 }
 
 /*
  * Determine if a process group is "orphaned", according to the POSIX
  * definition in 2.2.2.52.  Orphaned process groups are not to be affected
- * by terminal-generated stop signals.  Newly orphaned process groups are 
+ * by terminal-generated stop signals.  Newly orphaned process groups are
  * to receive a SIGHUP and a SIGCONT.
- * 
+ *
  * "I ask you, have you ever known what it is to be an orphan?"
  */
 static int will_become_orphaned_pgrp(int pgrp, struct task_struct * ignored_task)
@@ -352,7 +365,7 @@
 	struct task_struct *p;
 
 	for_each_task(p) {
-		if ((p == ignored_task) || (p->pgrp != pgrp) || 
+		if ((p == ignored_task) || (p->pgrp != pgrp) ||
 		    (p->state == TASK_ZOMBIE) ||
 		    (p->p_pptr->pid == 1))
 			continue;
@@ -495,7 +508,7 @@
 	__exit_mm(tsk);
 }
 
-/* 
+/*
  * Send signals to all our closest relatives so that they know
  * to properly mourn us..
  */
@@ -504,7 +517,7 @@
 	struct task_struct * p;
 
 	forget_original_parent(current);
-	/* 
+	/*
 	 * Check to see if any process groups have become orphaned
 	 * as a result of our exiting, and if they have any stopped
 	 * jobs, send them a SIGHUP and then a SIGCONT.  (POSIX 3.2.2.2)
@@ -522,10 +535,10 @@
 	}
 	/* Let father know we died */
 	notify_parent(current);
-	
+
 	/*
 	 * This loop does two things:
-	 * 
+	 *
   	 * A.  Make init inherit all the child processes
 	 * B.  Check to see if any process groups have become orphaned
 	 *	as a result of our exiting, and if they have any stopped
@@ -546,7 +559,7 @@
 			notify_parent(p);
 		/*
 		 * process group orphan check
-		 * Case ii: Our child is in a different pgrp 
+		 * Case ii: Our child is in a different pgrp
 		 * than we are, and it was the only connection
 		 * outside, so the child pgrp is now orphaned.
 		 */
@@ -575,6 +588,9 @@
 	sem_exit();
 	kerneld_exit();
 	__exit_mm(current);
+#if CONFIG_AP1000
+	exit_msc(current);
+#endif
 	__exit_files(current);
 	__exit_fs(current);
 	__exit_sighand(current);
@@ -585,10 +601,10 @@
 #ifdef DEBUG_PROC_TREE
 	audit_ptree();
 #endif
-	if (current->exec_domain && current->exec_domain->use_count)
-		(*current->exec_domain->use_count)--;
-	if (current->binfmt && current->binfmt->use_count)
-		(*current->binfmt->use_count)--;
+	if (current->exec_domain && current->exec_domain->module)
+		__MOD_DEC_USE_COUNT(current->exec_domain->module);
+	if (current->binfmt && current->binfmt->module)
+		__MOD_DEC_USE_COUNT(current->binfmt->module);
 	schedule();
 /*
  * In order to get rid of the "volatile function does return" message
@@ -608,7 +624,9 @@
 
 asmlinkage int sys_exit(int error_code)
 {
+	lock_kernel();
 	do_exit((error_code&0xff)<<8);
+	unlock_kernel();
 }
 
 asmlinkage int sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru)
@@ -617,18 +635,20 @@
 	struct wait_queue wait = { current, NULL };
 	struct task_struct *p;
 
+	lock_kernel();
 	if (stat_addr) {
-		flag = verify_area(VERIFY_WRITE, stat_addr, sizeof(*stat_addr));
-		if (flag)
-			return flag;
+		retval = verify_area(VERIFY_WRITE, stat_addr, sizeof(*stat_addr));
+		if (retval)
+			goto out;
 	}
 	if (ru) {
-		flag = verify_area(VERIFY_WRITE, ru, sizeof(*ru));
-		if (flag)
-			return flag;
+		retval = verify_area(VERIFY_WRITE, ru, sizeof(*ru));
+		if (retval)
+			goto out;
 	}
+	retval = -EINVAL;
 	if (options & ~(WNOHANG|WUNTRACED|__WCLONE))
-	    return -EINVAL;
+	    goto out;
 
 	add_wait_queue(&current->wait_chldexit,&wait);
 repeat:
@@ -699,6 +719,8 @@
 	retval = -ECHILD;
 end_wait4:
 	remove_wait_queue(&current->wait_chldexit,&wait);
+out:
+	unlock_kernel();
 	return retval;
 }
 
@@ -710,7 +732,12 @@
  */
 asmlinkage int sys_waitpid(pid_t pid,unsigned int * stat_addr, int options)
 {
-	return sys_wait4(pid, stat_addr, options, NULL);
+	int ret;
+
+	lock_kernel();
+	ret = sys_wait4(pid, stat_addr, options, NULL);
+	unlock_kernel();
+	return ret;
 }
 
 #endif
diff -u --recursive --new-file v2.1.22/linux/kernel/fork.c linux/kernel/fork.c
--- v2.1.22/linux/kernel/fork.c	Thu Jan  2 15:55:25 1997
+++ linux/kernel/fork.c	Sun Jan 26 13:40:46 1997
@@ -15,10 +15,13 @@
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
+#include <linux/slab.h>
 #include <linux/unistd.h>
 #include <linux/ptrace.h>
 #include <linux/malloc.h>
 #include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/module.h>
 
 #include <asm/system.h>
 #include <asm/pgtable.h>
@@ -84,7 +87,7 @@
 	p = &mm->mmap;
 	flush_cache_mm(current->mm);
 	for (mpnt = current->mm->mmap ; mpnt ; mpnt = mpnt->vm_next) {
-		tmp = (struct vm_area_struct *) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL);
+		tmp = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
 		if (!tmp) {
 			exit_mmap(mm);
 			flush_tlb_mm(current->mm);
@@ -177,7 +180,7 @@
 	tsk->files = newf;
 	if (!newf)
 		return -1;
-			
+
 	newf->count = 1;
 	newf->close_on_exec = oldf->close_on_exec;
 	newf->open_fds = oldf->open_fds;
@@ -221,10 +224,11 @@
 	unsigned long new_stack;
 	struct task_struct *p;
 
-	p = (struct task_struct *) kmalloc(sizeof(*p), GFP_KERNEL);
+	lock_kernel();
+	p = alloc_task_struct();
 	if (!p)
 		goto bad_fork;
-	new_stack = alloc_kernel_stack();
+	new_stack = alloc_kernel_stack(p);
 	if (!new_stack)
 		goto bad_fork_free_p;
 	error = -EAGAIN;
@@ -234,10 +238,10 @@
 
 	*p = *current;
 
-	if (p->exec_domain && p->exec_domain->use_count)
-		(*p->exec_domain->use_count)++;
-	if (p->binfmt && p->binfmt->use_count)
-		(*p->binfmt->use_count)++;
+	if (p->exec_domain && p->exec_domain->module)
+		__MOD_INC_USE_COUNT(p->exec_domain->module);
+	if (p->binfmt && p->binfmt->module)
+		__MOD_INC_USE_COUNT(p->binfmt->module);
 
 	p->did_exec = 0;
 	p->swappable = 0;
@@ -263,8 +267,8 @@
 	p->cutime = p->cstime = 0;
 #ifdef __SMP__
 	p->processor = NO_PROC_ID;
-	p->lock_depth = 1;
 #endif
+	p->lock_depth = 0;
 	p->start_time = jiffies;
 	task[nr] = p;
 	SET_LINKS(p);
@@ -289,9 +293,15 @@
 	p->swappable = 1;
 	p->exit_signal = clone_flags & CSIGNAL;
 	p->counter = current->counter >> 1;
-	wake_up_process(p);			/* do this last, just in case */
+	if(p->pid) {
+		wake_up_process(p);		/* do this last, just in case */
+	} else {
+		p->state = TASK_RUNNING;
+		p->next_run = p->prev_run = p;
+	}
 	++total_forks;
-	return p->pid;
+	error = p->pid;
+	goto fork_out;
 
 bad_fork_cleanup_sighand:
 	exit_sighand(p);
@@ -300,17 +310,19 @@
 bad_fork_cleanup_files:
 	exit_files(p);
 bad_fork_cleanup:
-	if (p->exec_domain && p->exec_domain->use_count)
-		(*p->exec_domain->use_count)--;
-	if (p->binfmt && p->binfmt->use_count)
-		(*p->binfmt->use_count)--;
+	if (p->exec_domain && p->exec_domain->module)
+		__MOD_DEC_USE_COUNT(p->exec_domain->module);
+	if (p->binfmt && p->binfmt->module)
+		__MOD_DEC_USE_COUNT(p->binfmt->module);
 	task[nr] = NULL;
 	REMOVE_LINKS(p);
 	nr_tasks--;
 bad_fork_free_stack:
 	free_kernel_stack(new_stack);
 bad_fork_free_p:
-	kfree(p);
+	free_task_struct(p);
 bad_fork:
+fork_out:
+	unlock_kernel();
 	return error;
 }
diff -u --recursive --new-file v2.1.22/linux/kernel/info.c linux/kernel/info.c
--- v2.1.22/linux/kernel/info.c	Tue Nov 19 15:53:58 1996
+++ linux/kernel/info.c	Sun Jan 26 12:07:49 1997
@@ -12,13 +12,17 @@
 #include <linux/types.h>
 #include <linux/mm.h>
 #include <linux/swap.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 
 asmlinkage int sys_sysinfo(struct sysinfo *info)
 {
 	struct sysinfo val;
+	int err;
 
+	lock_kernel();
 	memset((char *)&val, 0, sizeof(struct sysinfo));
 
 	val.uptime = jiffies / HZ;
@@ -33,6 +37,9 @@
 	si_swapinfo(&val);
 
 	if (copy_to_user(info, &val, sizeof(struct sysinfo)))
-		return -EFAULT;
-	return 0;
+		err = -EFAULT;
+	else
+		err = 0;
+	unlock_kernel();
+	return err;
 }
diff -u --recursive --new-file v2.1.22/linux/kernel/itimer.c linux/kernel/itimer.c
--- v2.1.22/linux/kernel/itimer.c	Tue Nov 19 15:53:58 1996
+++ linux/kernel/itimer.c	Sun Jan 26 12:07:49 1997
@@ -12,6 +12,8 @@
 #include <linux/errno.h>
 #include <linux/time.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 
@@ -80,15 +82,19 @@
 
 asmlinkage int sys_getitimer(int which, struct itimerval *value)
 {
-	int error;
+	int error = -EFAULT;
 	struct itimerval get_buffer;
 
+	lock_kernel();
 	if (!value)
-		return -EFAULT;
+		goto out;
 	error = _getitimer(which, &get_buffer);
 	if (error)
-		return error;
-	return copy_to_user(value, &get_buffer, sizeof(get_buffer)) ? -EFAULT : 0;
+		goto out;
+	error = copy_to_user(value, &get_buffer, sizeof(get_buffer)) ? -EFAULT : 0;
+out:
+	unlock_kernel();
+	return error;
 }
 
 void it_real_fn(unsigned long __data)
@@ -154,21 +160,26 @@
 	int error;
 	struct itimerval set_buffer, get_buffer;
 
+	lock_kernel();
 	if (value) {
 		error = verify_area(VERIFY_READ, value, sizeof(*value));
 		if (error)
-			return error;
+			goto out;
 		error = copy_from_user(&set_buffer, value, sizeof(set_buffer));
-		if (error)
-			return -EFAULT;
+		if (error) {
+			error = -EFAULT;
+			goto out;
+		}
 	} else
 		memset((char *) &set_buffer, 0, sizeof(set_buffer));
 
 	error = _setitimer(which, &set_buffer, ovalue ? &get_buffer : 0);
 	if (error || !ovalue)
-		return error;
+		goto out;
 
 	if (copy_to_user(ovalue, &get_buffer, sizeof(get_buffer)))
 		error = -EFAULT; 
+out:
+	unlock_kernel();
 	return error;
 }
diff -u --recursive --new-file v2.1.22/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.1.22/linux/kernel/ksyms.c	Wed Jan 15 19:45:46 1997
+++ linux/kernel/ksyms.c	Sun Jan 26 12:07:49 1997
@@ -12,7 +12,6 @@
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/smp.h>
 #include <linux/fs.h>
 #include <linux/blkdev.h>
 #include <linux/cdrom.h>
@@ -50,11 +49,12 @@
 #include <linux/swap.h>
 #include <linux/ctype.h>
 
-extern unsigned char aux_device_present, kbd_read_mask;
-#ifdef __i386__
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD)
 extern struct drive_info_struct drive_info;
 #endif
 
+extern unsigned char aux_device_present, kbd_read_mask;
+
 #ifdef CONFIG_PCI
 #include <linux/bios32.h>
 #include <linux/pci.h>
@@ -181,7 +181,7 @@
 EXPORT_SYMBOL(unregister_cdrom);
 EXPORT_SYMBOL(cdrom_fops);
 #endif
- 
+
 /* block device driver support */
 EXPORT_SYMBOL(block_read);
 EXPORT_SYMBOL(block_write);
@@ -201,7 +201,8 @@
 EXPORT_SYMBOL(gendisk_head);
 EXPORT_SYMBOL(resetup_one_dev);
 EXPORT_SYMBOL(unplug_device);
-#ifdef __i386__
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD)
 EXPORT_SYMBOL(drive_info);
 #endif
 
diff -u --recursive --new-file v2.1.22/linux/kernel/module.c linux/kernel/module.c
--- v2.1.22/linux/kernel/module.c	Wed Jan 15 19:45:46 1997
+++ linux/kernel/module.c	Sun Jan 26 12:07:49 1997
@@ -7,6 +7,8 @@
 #include <linux/config.h>
 #include <asm/uaccess.h>
 #include <linux/vmalloc.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 /*
  * Originally by Anonymous (as far as I know...)
@@ -118,6 +120,7 @@
 	long namelen, error;
 	struct module *mod;
 
+	lock_kernel();
 	if (!suser()) {
 		error = -EPERM;
 		goto err0;
@@ -150,11 +153,12 @@
 
 	module_list = mod;	/* link it in */
 
-	return (unsigned long) mod;
-
+	error = (long) mod;
+	goto err0;
 err1:
 	put_mod_name(name);
 err0:
+	unlock_kernel();
 	return error;
 }
 
@@ -167,14 +171,13 @@
 {
 	struct module mod_tmp, *mod;
 	char *name, *n_name;
-	long namelen, n_namelen, i, error;
+	long namelen, n_namelen, i, error = -EPERM;
 	unsigned long mod_user_size;
 	struct module_ref *dep;
 
-	if (!suser()) {
-		error = -EPERM;
+	lock_kernel();
+	if (!suser())
 		goto err0;
-	}
 	if ((namelen = get_mod_name(name_user, &name)) < 0) {
 		error = namelen;
 		goto err0;
@@ -184,14 +187,13 @@
 		goto err1;
 	}
 
-	/* Check for legal module header sizes.  */
+	/* Check module header size.  We allow a bit of slop over the 
+	   size we are familiar with to cope with a version of insmod
+	   for a newer kernel.  But don't over do it. */
 	if ((error = get_user(mod_user_size, &mod_user->size_of_struct)) != 0)
 		goto err1;
-	switch (mod_user_size) {
-	  case sizeof(struct module):
-	  case &((struct module *)0L)->persist_start:
-		break;
-	  default:
+	if (mod_user_size < (unsigned long)&((struct module *)0L)->persist_start
+	    || mod_user_size > sizeof(struct module) + 16*sizeof(void*)) {
 		printk(KERN_ERR "init_module: Invalid module header size.\n"
 		       KERN_ERR "A new version of the modutils is likely "
 				"needed.\n");
@@ -264,6 +266,11 @@
 		goto err2;
 	}
 #endif
+	if (mod_member_present(mod, can_unload)
+	    && mod->can_unload && !bound(mod->can_unload, 0, mod)) {
+		printk(KERN_ERR "init_module: mod->can_unload out of bounds.\n");
+		goto err2;
+	}
 
 #undef bound
 
@@ -279,14 +286,12 @@
 		printk(KERN_ERR "init_module: changed module name to "
 				"`%s' from `%s'\n",
 		       n_name, mod_tmp.name);
-		error = -EINVAL;
 		goto err3;
 	}
 
 	/* Ok, that's about all the sanity we can stomach; copy the rest.  */
 
-	error = copy_from_user(mod+1, mod_user+1, mod->size-sizeof(*mod));
-	if (error) {
+	if (copy_from_user(mod+1, mod_user+1, mod->size-sizeof(*mod))) {
 		error = -EFAULT;
 		goto err3;
 	}
@@ -301,7 +306,6 @@
 		if (d == mod) {
 			printk(KERN_ERR "init_module: self-referential "
 					"dependancy in mod->deps.\n");
-			error = -EINVAL;
 			goto err3;
 		}
 
@@ -310,13 +314,15 @@
 
 		printk(KERN_ERR "init_module: found dependancy that is "
 				"(no longer?) a module.\n");
-		error = -EINVAL;
 		goto err3;
 		
 	found_dep:
 		dep->ref = mod;
 		dep->next_ref = d->refs;
 		d->refs = dep;
+		/* Being referenced by a dependant module counts as a 
+		   use as far as kerneld is concerned.  */
+		d->flags |= MOD_USED_ONCE;
 	}
 
 	/* Free our temporary memory.  */
@@ -327,13 +333,15 @@
 	mod->usecount = 1;
 	if (mod->init && mod->init() != 0) {
 		mod->usecount = 0;
-		return -EBUSY;
+		error = -EBUSY;
+		goto err0;
 	}
 	mod->usecount--;
 
 	/* And set it running.  */
 	mod->flags |= MOD_RUNNING;
-	return 0;
+	error = 0;
+	goto err0;
 
 err3:
 	put_mod_name(n_name);
@@ -342,6 +350,7 @@
 err1:
 	put_mod_name(name);
 err0:
+	unlock_kernel();
 	return error;
 }
 
@@ -350,45 +359,53 @@
 {
 	struct module *mod, *next;
 	char *name;
-	long error;
+	long error = -EPERM;
 
+	lock_kernel();
 	if (!suser())
-		return -EPERM;
+		goto out;
 
 	if (name_user) {
 		if ((error = get_mod_name(name_user, &name)) < 0)
-			return error;
+			goto out;
 		if (error == 0) {
+			error = -EINVAL;
 			put_mod_name(name);
-			return -EINVAL;
+			goto out;
 		}
+		error = -ENOENT;
 		if ((mod = find_module(name)) == NULL) {
 			put_mod_name(name);
-			return -ENOENT;
+			goto out;
 		}
 		put_mod_name(name);
-		if (mod->refs != NULL || mod->usecount != 0)
-			return -EBUSY;
+		error = -EBUSY;
+ 		if (mod->refs != NULL || __MOD_IN_USE(mod))
+			goto out;
 
 		free_module(mod);
-		return 0;
+		error = 0;
+		goto out;
 	}
 
 	/* Do automatic reaping */
 	for (mod = module_list; mod != &kernel_module; mod = next) {
 		next = mod->next;
 		if (mod->refs == NULL &&
-		    mod->usecount == 0 &&
 		    ((mod->flags
 		      & (MOD_AUTOCLEAN|MOD_RUNNING|MOD_DELETED|MOD_USED_ONCE))
-		     == (MOD_AUTOCLEAN|MOD_RUNNING|MOD_USED_ONCE))) {
+		     == (MOD_AUTOCLEAN|MOD_RUNNING|MOD_USED_ONCE)) &&
+		    !__MOD_IN_USE(mod)) {
 			if (mod->flags & MOD_VISITED)
 				mod->flags &= ~MOD_VISITED;
 			else
 				free_module(mod);
 		}
 	}
-	return 0;
+	error = 0;
+out:
+	unlock_kernel();
+	return error;
 }
 
 /* Query various bits about modules.  */
@@ -418,7 +435,8 @@
 		return 0;
 
 calc_space_needed:
-	for (space += len; mod; mod = mod->next)
+	space += len;
+	while ((mod = mod->next) != &kernel_module)
 		space += strlen(mod->name)+1;
 
 	if (put_user(space, ret))
@@ -460,7 +478,8 @@
 		return 0;
 
 calc_space_needed:
-	for (space += len; i < mod->ndeps; ++i)
+	space += len;
+	while (++i < mod->ndeps)
 		space += strlen(mod->deps[i].dep->name)+1;
 
 	if (put_user(space, ret))
@@ -503,7 +522,8 @@
 		return 0;
 
 calc_space_needed:
-	for (space += len; ref; ref = ref->next_ref)
+	space += len;
+	while ((ref = ref->next_ref) != NULL)
 		space += strlen(ref->ref->name)+1;
 
 	if (put_user(space, ret))
@@ -528,15 +548,15 @@
 
 	space = mod->nsyms * 2*sizeof(void *);
 
-	if (!access_ok(VERIFY_WRITE, buf, space))
-		return -EFAULT;
-
 	i = len = 0;
 	s = mod->syms;
 
 	if (space > bufsize)
 		goto calc_space_needed;
 
+	if (!access_ok(VERIFY_WRITE, buf, space))
+		return -EFAULT;
+
 	bufsize -= space;
 	vals = (unsigned long *)buf;
 	strings = buf+space;
@@ -562,8 +582,8 @@
 		return 0;
 
 calc_space_needed:
-	for (space += len; i < mod->nsyms; ++i, ++s)
-		space += strlen(s->name)+1;
+	for (; i < mod->nsyms; ++i, ++s)
+		space += strlen((++s)->name)+1;
 
 	if (put_user(space, ret))
 		return -EFAULT;
@@ -584,6 +604,8 @@
 		info.addr = (unsigned long)mod;
 		info.size = mod->size;
 		info.flags = mod->flags;
+		info.usecount = (mod_member_present(mod, can_unload)
+				 && mod->can_unload ? -1 : mod->usecount);
 
 		if (copy_to_user(buf, &info, sizeof(struct module_info)))
 			return -EFAULT;
@@ -601,20 +623,25 @@
 		 size_t *ret)
 {
 	struct module *mod;
+	int err;
 
+	lock_kernel();
 	if (name_user == NULL)
 		mod = &kernel_module;
 	else {
 		long namelen;
 		char *name;
 
-		if ((namelen = get_mod_name(name_user, &name)) < 0)
-			return namelen;
+		if ((namelen = get_mod_name(name_user, &name)) < 0) {
+			err = namelen;
+			goto out;
+		}
+		err = -ENOENT;
 		if (namelen == 0)
 			mod = &kernel_module;
 		else if ((mod = find_module(name)) == NULL) {
 			put_mod_name(name);
-			return -ENOENT;
+			goto out;
 		}
 		put_mod_name(name);
 	}
@@ -622,28 +649,38 @@
 	switch (which)
 	{
 	case 0:
-		return 0;
+		err = 0;
+		break;
 	case QM_MODULES:
-		return qm_modules(buf, bufsize, ret);
+		err = qm_modules(buf, bufsize, ret);
+		break;
 	case QM_DEPS:
-		return qm_deps(mod, buf, bufsize, ret);
+		err = qm_deps(mod, buf, bufsize, ret);
+		break;
 	case QM_REFS:
-		return qm_refs(mod, buf, bufsize, ret);
+		err = qm_refs(mod, buf, bufsize, ret);
+		break;
 	case QM_SYMBOLS:
-		return qm_symbols(mod, buf, bufsize, ret);
+		err = qm_symbols(mod, buf, bufsize, ret);
+		break;
 	case QM_INFO:
-		return qm_info(mod, buf, bufsize, ret);
+		err = qm_info(mod, buf, bufsize, ret);
+		break;
+	default:
+		err = -EINVAL;
+		break;
 	}
-
-	return -EINVAL;
+out:
+	unlock_kernel();
+	return err;
 }
 
 /*
  * Copy the kernel symbol table to user space.  If the argument is
  * NULL, just return the size of the table.
  *
- * This call is depreciated in favour of query_module+QM_SYMBOLS which
- * does not arbitrarily limit the length of the symbol.
+ * This call is obsolete.  New programs should use query_module+QM_SYMBOLS
+ * which does not arbitrarily limit the length of symbols.
  */
 
 asmlinkage int
@@ -652,13 +689,14 @@
 	struct module *mod;
 	int i;
 
+	lock_kernel();
 	for (mod = module_list, i = 0; mod; mod = mod->next) {
 		/* include the count for the module name! */
 		i += mod->nsyms + 1;
 	}
 
 	if (table == NULL)
-		return i;
+		goto out;
 
 	for (mod = module_list, i = 0; mod; mod = mod->next) {
 		struct kernel_sym ksym;
@@ -675,7 +713,7 @@
 		ksym.name[sizeof(ksym.name)-1] = '\0';
 
 		if (copy_to_user(table, &ksym, sizeof(ksym)) != 0)
-			return i;
+			goto out;
 		++i, ++table;
 
 		if (mod->nsyms == 0)
@@ -687,10 +725,12 @@
 			ksym.name[sizeof(ksym.name)-1] = '\0';
 
 			if (copy_to_user(table, &ksym, sizeof(ksym)) != 0)
-				return i;
+				goto out;
 			++i, ++table;
 		}
 	}
+out:
+	unlock_kernel();
 	return i;
 }
 
@@ -771,15 +811,16 @@
 		long len;
 		const char *q;
 
-#define safe_copystr(str, len)						\
+#define safe_copy_str(str, len)						\
 		do {							\
 			if (left < len)					\
 				goto fini;				\
 			memcpy(p, str, len); p += len, left -= len;	\
 		} while (0)
+#define safe_copy_cstr(str)	safe_copy_str(str, sizeof(str)-1)
 
         	len = strlen(mod->name);
-		safe_copystr(mod->name, len);
+		safe_copy_str(mod->name, len);
 
 		if ((len = 20 - len) > 0) {
 			if (left < len)
@@ -790,47 +831,45 @@
 		}
 
 		len = sprintf(tmpstr, "%8lu", mod->size);
-		safe_copystr(tmpstr, len);
+		safe_copy_str(tmpstr, len);
 
 		if (mod->flags & MOD_RUNNING) {
-			len = sprintf(tmpstr, "%4lu", mod->usecount);
-			safe_copystr(tmpstr, len);
+			len = sprintf(tmpstr, "%4ld",
+				      (mod_member_present(mod, can_unload)
+				       && mod->can_unload
+				       ? -1 : mod->usecount));
+			safe_copy_str(tmpstr, len);
 		}
 
 		if (mod->flags & MOD_DELETED)
-			q = "  (deleted)";
-		else if (mod->flags & MOD_RUNNING)
-			q = "";
-		else
-			q = "  (uninitialized)";
-		len = strlen(q);
-		safe_copystr(q, len);
-
-		safe_copystr("\t", 1);
+			safe_copy_cstr(" (deleted)");
+		else if (mod->flags & MOD_RUNNING) {
+			if (mod->flags & MOD_AUTOCLEAN)
+				safe_copy_cstr(" (autoclean)");
+			if (!(mod->flags & MOD_USED_ONCE))
+				safe_copy_cstr(" (unused)");
+		} else
+			safe_copy_cstr(" (uninitialized)");
 
 		if ((ref = mod->refs) != NULL) {
-			safe_copystr("[", 1);
+			safe_copy_cstr(" [");
 			while (1) {
 				q = ref->ref->name;
 				len = strlen(q);
-				safe_copystr(q, len);
+				safe_copy_str(q, len);
 
 				if ((ref = ref->next_ref) != NULL)
-					safe_copystr(" ", 1);
+					safe_copy_cstr(" ");
 				else
 					break;
 			}
-			safe_copystr("]", 1);
-		}
-
-		if ((mod->flags & (MOD_RUNNING | MOD_AUTOCLEAN))
-		    == (MOD_RUNNING | MOD_AUTOCLEAN)) {
-			safe_copystr(" (autoclean)", 12);
+			safe_copy_cstr("]");
 		}
 
-		safe_copystr("\n", 1);
+		safe_copy_cstr("\n");
 
-#undef safe_copystr
+#undef safe_copy_str
+#undef safe_copy_cstr
 	}
 
 fini:
diff -u --recursive --new-file v2.1.22/linux/kernel/printk.c linux/kernel/printk.c
--- v2.1.22/linux/kernel/printk.c	Sun Dec 22 16:37:42 1996
+++ linux/kernel/printk.c	Sun Jan 26 12:07:49 1997
@@ -21,6 +21,8 @@
 #include <linux/mm.h>
 #include <linux/tty.h>
 #include <linux/tty_driver.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 
@@ -64,87 +66,103 @@
 	unsigned long i, j, count;
 	int do_clear = 0;
 	char c;
-	int error;
+	int error = -EPERM;
 
+	lock_kernel();
 	if ((type != 3) && !suser())
-		return -EPERM;
+		goto out;
+	error = 0;
 	switch (type) {
-		case 0:		/* Close log */
-			return 0;
-		case 1:		/* Open log */
-			return 0;
-		case 2:		/* Read from log */
-			if (!buf || len < 0)
-				return -EINVAL;
-			if (!len)
-				return 0;
-			error = verify_area(VERIFY_WRITE,buf,len);
-			if (error)
-				return error;
-			cli();
-			while (!log_size) {
-				if (current->signal & ~current->blocked) {
-					sti();
-					return -ERESTARTSYS;
-				}
-				interruptible_sleep_on(&log_wait);
-			}
-			i = 0;
-			while (log_size && i < len) {
-				c = *((char *) log_buf+log_start);
-				log_start++;
-				log_size--;
-				log_start &= LOG_BUF_LEN-1;
+	case 0:		/* Close log */
+		break;
+	case 1:		/* Open log */
+		break;
+	case 2:		/* Read from log */
+		error = -EINVAL;
+		if (!buf || len < 0)
+			goto out;
+		error = 0;
+		if (!len)
+			goto out;
+		error = verify_area(VERIFY_WRITE,buf,len);
+		if (error)
+			goto out;
+		cli();
+		error = -ERESTARTSYS;
+		while (!log_size) {
+			if (current->signal & ~current->blocked) {
 				sti();
-				put_user(c,buf);
-				buf++;
-				i++;
-				cli();
+				goto out;
 			}
+			interruptible_sleep_on(&log_wait);
+		}
+		i = 0;
+		while (log_size && i < len) {
+			c = *((char *) log_buf+log_start);
+			log_start++;
+			log_size--;
+			log_start &= LOG_BUF_LEN-1;
 			sti();
-			return i;
-		case 4:		/* Read/clear last kernel messages */
-			do_clear = 1; 
-			/* FALL THRU */
-		case 3:		/* Read last kernel messages */
-			if (!buf || len < 0)
-				return -EINVAL;
-			if (!len)
-				return 0;
-			error = verify_area(VERIFY_WRITE,buf,len);
-			if (error)
-				return error;
-			count = len;
-			if (count > LOG_BUF_LEN)
-				count = LOG_BUF_LEN;
-			if (count > logged_chars)
-				count = logged_chars;
-			j = log_start + log_size - count;
-			for (i = 0; i < count; i++) {
-				c = *((char *) log_buf+(j++ & (LOG_BUF_LEN-1)));
-				put_user(c, buf++);
-			}
-			if (do_clear)
-				logged_chars = 0;
-			return i;
-		case 5:		/* Clear ring buffer */
+			put_user(c,buf);
+			buf++;
+			i++;
+			cli();
+		}
+		sti();
+		error = i;
+		break;
+	case 4:		/* Read/clear last kernel messages */
+		do_clear = 1; 
+		/* FALL THRU */
+	case 3:		/* Read last kernel messages */
+		error = -EINVAL;
+		if (!buf || len < 0)
+			goto out;
+		error = 0;
+		if (!len)
+			goto out;
+		error = verify_area(VERIFY_WRITE,buf,len);
+		if (error)
+			goto out;
+		count = len;
+		if (count > LOG_BUF_LEN)
+			count = LOG_BUF_LEN;
+		if (count > logged_chars)
+			count = logged_chars;
+		j = log_start + log_size - count;
+		for (i = 0; i < count; i++) {
+			c = *((char *) log_buf+(j++ & (LOG_BUF_LEN-1)));
+			put_user(c, buf++);
+		}
+		if (do_clear)
 			logged_chars = 0;
-			return 0;
-		case 6:		/* Disable logging to console */
-			console_loglevel = MINIMUM_CONSOLE_LOGLEVEL;
-			return 0;
-		case 7:		/* Enable logging to console */
-			console_loglevel = DEFAULT_CONSOLE_LOGLEVEL;
-			return 0;
-		case 8:
-			if (len < 1 || len > 8)
-				return -EINVAL;
-			if (len < MINIMUM_CONSOLE_LOGLEVEL)
-				len = MINIMUM_CONSOLE_LOGLEVEL;
-			console_loglevel = len;
-			return 0;
+		error = i;
+		break;
+	case 5:		/* Clear ring buffer */
+		logged_chars = 0;
+		break;
+	case 6:		/* Disable logging to console */
+		console_loglevel = MINIMUM_CONSOLE_LOGLEVEL;
+		break;
+	case 7:		/* Enable logging to console */
+		console_loglevel = DEFAULT_CONSOLE_LOGLEVEL;
+		break;
+	case 8:
+		error = -EINVAL;
+		if (len < 1 || len > 8)
+			goto out;
+		if (len < MINIMUM_CONSOLE_LOGLEVEL)
+			len = MINIMUM_CONSOLE_LOGLEVEL;
+		console_loglevel = len;
+		error = 0;
+		break;
+	default:
+		error = -EINVAL;
+		break;
 	}
-	return -EINVAL;
+out:
+	unlock_kernel();
+	return error;
 }
 
 
diff -u --recursive --new-file v2.1.22/linux/kernel/resource.c linux/kernel/resource.c
--- v2.1.22/linux/kernel/resource.c	Sat Dec 30 21:00:41 1995
+++ linux/kernel/resource.c	Sun Jan 26 12:07:49 1997
@@ -119,6 +119,67 @@
 	return (find_gap(&iolist, from, num) == NULL) ? -EBUSY : 0;
 }
 
+#ifdef __sparc__   /* Why to carry unused code on other architectures? */
+/*
+ * This is for architectures with MMU-managed ports (sparc).
+ */
+unsigned int occupy_region(unsigned int base, unsigned int end,
+			unsigned int num, unsigned int align, const char *name)
+{
+	unsigned int from = 0, till;
+	unsigned long flags;
+	int i;
+	resource_entry_t *p;		/* Scanning ptr */
+	resource_entry_t *p1;		/* === p->next */
+	resource_entry_t *s;		/* Found slot */
+
+	if (base > end-1)
+		return 0;
+	if (num > end - base)
+		return 0;
+
+	for (i = 0; i < IOTABLE_SIZE; i++)
+		if (iotable[i].num == 0)
+			break;
+	if (i == IOTABLE_SIZE) {
+		/* Driver prints a warning typicaly. */
+		return 0;
+	}
+
+	save_flags(flags);
+	cli();
+	/* printk("occupy: search in %08x[%x] ", base, end - base); */
+	s = NULL;
+	for (p = &iolist; p != NULL; p = p1) {
+		p1 = p->next;
+		/* Find window in list */
+		from = (p->from+p->num + align-1) & ~(align-1);
+		till = (p1 == NULL)? (unsigned) (0 - align): p1->from;
+		/* printk(" %08x:%08x", from, till); */
+		/* Clip window with base and end */
+		if (from < base) from = base;
+		if (till > end) till = end;
+		/* See if result is large enougth */
+		if (from < till && from + num < till) {
+			s = p;
+			break;
+		}
+	}
+	/* printk("\r\n"); */
+	restore_flags(flags);
+
+	if (s == NULL)
+		return 0;
+
+	iotable[i].name = name;
+	iotable[i].from = from;
+	iotable[i].num = num;
+	iotable[i].next = s->next;
+	s->next = &iotable[i];
+	return from;
+}
+#endif
+
 /* Called from init/main.c to reserve IO ports. */
 void reserve_setup(char *str, int *ints)
 {
diff -u --recursive --new-file v2.1.22/linux/kernel/sched.c linux/kernel/sched.c
--- v2.1.22/linux/kernel/sched.c	Thu Jan 23 21:06:52 1997
+++ linux/kernel/sched.c	Sun Jan 26 13:40:46 1997
@@ -30,6 +30,7 @@
 #include <linux/resource.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -106,9 +107,6 @@
 
 static inline void add_to_runqueue(struct task_struct * p)
 {
-#ifdef __SMP__
-	int cpu=smp_processor_id();
-#endif	
 #if 1	/* sanity tests */
 	if (p->next_run || p->prev_run) {
 		printk("task already on run-queue\n");
@@ -123,19 +121,7 @@
 	init_task.prev_run = p;
 #ifdef __SMP__
 	/* this is safe only if called with cli()*/
-	while(set_bit(31,&smp_process_available))
-	{
-		while(test_bit(31,&smp_process_available))
-		{
-			if(clear_bit(cpu,&smp_invalidate_needed))
-			{
-				local_flush_tlb();
-				set_bit(cpu,&cpu_callin_map[0]);
-			}
-		}
-	}
-	smp_process_available++;
-	clear_bit(31,&smp_process_available);
+	inc_smp_counter(&smp_process_available);
 	if ((0!=p->pid) && smp_threads_ready)
 	{
 		int i;
@@ -302,14 +288,12 @@
 
 /* check alarm, wake up any interruptible tasks that have got a signal */
 
+	lock_kernel();
 	if (intr_count)
 		goto scheduling_in_interrupt;
 
-	if (bh_active & bh_mask) {
-		intr_count = 1;
+	if (bh_active & bh_mask)
 		do_bottom_half();
-		intr_count = 0;
-	}
 
 	run_task_queue(&tq_scheduler);
 
@@ -401,11 +385,13 @@
 		if (timeout)
 			del_timer(&timer);
 	}
-	return;
+	goto out;
 
 scheduling_in_interrupt:
 	printk("Aiee: scheduling in interrupt %p\n",
 		__builtin_return_address(0));
+out:
+	unlock_kernel();
 }
 
 #ifndef __alpha__
@@ -416,8 +402,10 @@
  */
 asmlinkage int sys_pause(void)
 {
+	lock_kernel();
 	current->state = TASK_INTERRUPTIBLE;
 	schedule();
+	unlock_kernel();
 	return -ERESTARTNOHAND;
 }
 
@@ -1065,6 +1053,7 @@
 				utime = 0;
 				stime = ticks;
 			}
+
 			update_one_process(p, ticks, utime, stime);
 
 			if (p->priority < DEF_PRIORITY)
@@ -1082,14 +1071,17 @@
 			 * Idle processor found, do we have anything
 			 * we could run?
 			 */
-			if (!(0x7fffffff & smp_process_available))
+			if (!(read_smp_counter(&smp_process_available)))
 				continue;
 		}
 		/* Ok, we should reschedule, do the magic */
-		if (i==cpu)
+		cli();
+		if (i==cpu) {
 			need_resched = 1;
-		else
+		} else {
 			smp_message_pass(i, MSG_RESCHEDULE, 0L, 0);
+		}
+		sti();
 	}
 #endif
 }
@@ -1151,6 +1143,7 @@
 	struct itimerval it_new, it_old;
 	unsigned int oldalarm;
 
+	lock_kernel();
 	it_new.it_interval.tv_sec = it_new.it_interval.tv_usec = 0;
 	it_new.it_value.tv_sec = seconds;
 	it_new.it_value.tv_usec = 0;
@@ -1160,6 +1153,7 @@
 	/* And we'd better return too much than too little anyway */
 	if (it_old.it_value.tv_usec)
 		oldalarm++;
+	unlock_kernel();
 	return oldalarm;
 }
 
@@ -1169,32 +1163,62 @@
  */
 asmlinkage int sys_getpid(void)
 {
-	return current->pid;
+	int ret;
+
+	lock_kernel();
+	ret = current->pid;
+	unlock_kernel();
+	return ret;
 }
 
 asmlinkage int sys_getppid(void)
 {
-	return current->p_opptr->pid;
+	int ret;
+
+	lock_kernel();
+	ret = current->p_opptr->pid;
+	unlock_kernel();
+	return ret;
 }
 
 asmlinkage int sys_getuid(void)
 {
-	return current->uid;
+	int ret;
+
+	lock_kernel();
+	ret = current->uid;
+	unlock_kernel();
+	return ret;
 }
 
 asmlinkage int sys_geteuid(void)
 {
-	return current->euid;
+	int ret;
+
+	lock_kernel();
+	ret = current->euid;
+	unlock_kernel();
+	return ret;
 }
 
 asmlinkage int sys_getgid(void)
 {
-	return current->gid;
+	int ret;
+
+	lock_kernel();
+	ret = current->gid;
+	unlock_kernel();
+	return ret;
 }
 
 asmlinkage int sys_getegid(void)
 {
-	return current->egid;
+	int ret;
+
+	lock_kernel();
+	ret = current->egid;
+	unlock_kernel();
+	return ret;
 }
 
 /*
@@ -1206,14 +1230,17 @@
 {
 	unsigned long newprio;
 	int increase = 0;
+	int ret = -EPERM;
 
+	lock_kernel();
 	newprio = increment;
 	if (increment < 0) {
 		if (!suser())
-			return -EPERM;
+			goto out;
 		newprio = -increment;
 		increase = 1;
 	}
+	ret = 0;
 	if (newprio > 40)
 		newprio = 40;
 	/*
@@ -1233,7 +1260,9 @@
 	if (newprio > DEF_PRIORITY*2)
 		newprio = DEF_PRIORITY*2;
 	current->priority = newprio;
-	return 0;
+out:
+	unlock_kernel();
+	return ret;
 }
 
 #endif
@@ -1305,86 +1334,124 @@
 asmlinkage int sys_sched_setscheduler(pid_t pid, int policy, 
 				      struct sched_param *param)
 {
-	return setscheduler(pid, policy, param);
+	int ret;
+
+	lock_kernel();
+	ret = setscheduler(pid, policy, param);
+	unlock_kernel();
+	return ret;
 }
 
 asmlinkage int sys_sched_setparam(pid_t pid, struct sched_param *param)
 {
-	return setscheduler(pid, -1, param);
+	int ret;
+
+	lock_kernel();
+	ret = setscheduler(pid, -1, param);
+	unlock_kernel();
+	return ret;
 }
 
 asmlinkage int sys_sched_getscheduler(pid_t pid)
 {
 	struct task_struct *p;
+	int ret = -EINVAL;
 
+	lock_kernel();
 	if (pid < 0)
-		return -EINVAL;
+		goto out;
 
 	p = find_process_by_pid(pid);
+	ret = -ESRCH;
 	if (!p)
-		return -ESRCH;
+		goto out;
 			
-	return p->policy;
+	ret = p->policy;
+out:
+	unlock_kernel();
+	return ret;
 }
 
 asmlinkage int sys_sched_getparam(pid_t pid, struct sched_param *param)
 {
 	struct task_struct *p;
 	struct sched_param lp;
+	int ret = -EINVAL;
 
+	lock_kernel();
 	if (!param || pid < 0)
-		return -EINVAL;
+		goto out;
 
 	p = find_process_by_pid(pid);
+	ret = -ESRCH;
 	if (!p)
-		return -ESRCH;
+		goto out;
 
 	lp.sched_priority = p->rt_priority;
-	return copy_to_user(param, &lp, sizeof(struct sched_param)) ? -EFAULT : 0;
+	ret = copy_to_user(param, &lp, sizeof(struct sched_param)) ? -EFAULT : 0;
+out:
+	unlock_kernel();
+	return ret;
 }
 
 asmlinkage int sys_sched_yield(void)
 {
+	lock_kernel();
 	cli();
 	move_last_runqueue(current);
 	sti();
+	unlock_kernel();
 	return 0;
 }
 
 asmlinkage int sys_sched_get_priority_max(int policy)
 {
+	int ret = -EINVAL;
+
+	lock_kernel();
 	switch (policy) {
-	      case SCHED_FIFO:
-	      case SCHED_RR:
-		return 99;
-	      case SCHED_OTHER:
-		return 0;
+	case SCHED_FIFO:
+	case SCHED_RR:
+		ret = 99;
+		break;
+	case SCHED_OTHER:
+		ret = 0;
+		break;
 	}
-
-	return -EINVAL;
+	unlock_kernel();
+	return ret;
 }
 
 asmlinkage int sys_sched_get_priority_min(int policy)
 {
+	int ret = -EINVAL;
+
+	lock_kernel();
 	switch (policy) {
-	      case SCHED_FIFO:
-	      case SCHED_RR:
-		return 1;
-	      case SCHED_OTHER:
-		return 0;
+	case SCHED_FIFO:
+	case SCHED_RR:
+		ret = 1;
+		break;
+	case SCHED_OTHER:
+		ret = 0;
 	}
-
-	return -EINVAL;
+	unlock_kernel();
+	return ret;
 }
 
 asmlinkage int sys_sched_rr_get_interval(pid_t pid, struct timespec *interval)
 {
 	struct timespec t;
+	int ret;
 
+	lock_kernel();
 	t.tv_sec = 0;
-	t.tv_nsec = 0;   /* <-- Linus, please fill correct value in here */
-	return -ENOSYS;  /* and then delete this line. Thanks!           */
-	return copy_to_user(interval, &t, sizeof(struct timespec)) ? -EFAULT : 0;
+	t.tv_nsec = 0;            /* <-- Linus, please fill correct value in here */
+	ret = -ENOSYS; goto out;  /* and then delete this line. Thanks!           */
+	ret = copy_to_user(interval, &t, sizeof(struct timespec)) ? -EFAULT : 0;
+out:
+	unlock_kernel();
+	return ret;
 }
 
 /*
@@ -1412,16 +1479,17 @@
 
 asmlinkage int sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp)
 {
-	int error;
+	int error = -EFAULT;
 	struct timespec t;
 	unsigned long expire;
 
-	error = copy_from_user(&t, rqtp, sizeof(struct timespec));
-	if (error)
-		return -EFAULT;	
+	lock_kernel();
+	if(copy_from_user(&t, rqtp, sizeof(struct timespec)))
+		goto out;
 
+	error = -EINVAL;
 	if (t.tv_nsec >= 1000000000L || t.tv_nsec < 0 || t.tv_sec < 0)
-		return -EINVAL;
+		goto out;
 
 	if (t.tv_sec == 0 && t.tv_nsec <= 2000000L &&
 	    current->policy != SCHED_OTHER) {
@@ -1430,7 +1498,8 @@
 		 * high precision by a busy wait for all real-time processes.
 		 */
 		udelay((t.tv_nsec + 999) / 1000);
-		return 0;
+		error = 0;
+		goto out;
 	}
 
 	expire = timespectojiffies(&t) + (t.tv_sec || t.tv_nsec) + jiffies;
@@ -1438,17 +1507,20 @@
 	current->state = TASK_INTERRUPTIBLE;
 	schedule();
 
+	error = 0;
 	if (expire > jiffies) {
 		if (rmtp) {
 			jiffiestotimespec(expire - jiffies -
 					  (expire > jiffies + 1), &t);
+			error = -EFAULT;
 			if (copy_to_user(rmtp, &t, sizeof(struct timespec)))
-				return -EFAULT;	
+				goto out;
 		}
-		return -EINTR;
+		error = -EINTR;
 	}
-
-	return 0;
+out:
+	unlock_kernel();
+	return error;
 }
 
 static void show_task(int nr,struct task_struct * p)
@@ -1516,7 +1588,7 @@
 	 *	process right in SMP mode.
 	 */
 	int cpu=smp_processor_id();
-#ifndef __SMP__	
+#ifndef __SMP__
 	current_set[cpu]=&init_task;
 #else
 	init_task.processor=cpu;
diff -u --recursive --new-file v2.1.22/linux/kernel/signal.c linux/kernel/signal.c
--- v2.1.22/linux/kernel/signal.c	Tue Nov 19 15:53:59 1996
+++ linux/kernel/signal.c	Sun Jan 26 12:07:49 1997
@@ -12,6 +12,8 @@
 #include <linux/ptrace.h>
 #include <linux/unistd.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 
@@ -31,10 +33,11 @@
 	sigset_t new_set, old_set = current->blocked;
 	int error;
 
+	lock_kernel();
 	if (set) {
 		error = get_user(new_set, set);
 		if (error)
-			return error;	
+			goto out;
 		new_set &= _BLOCKABLE;
 		switch (how) {
 		case SIG_BLOCK:
@@ -47,15 +50,19 @@
 			current->blocked = new_set;
 			break;
 		default:
-			return -EINVAL;
+			error = -EINVAL;
+			goto out;
 		}
 	}
 	if (oset) {
 		error = put_user(old_set, oset);
 		if (error)
-			return error;	
+			goto out;
 	}
-	return 0;
+	error = 0;
+out:
+	unlock_kernel();
+	return error;
 }
 
 /*
@@ -63,14 +70,22 @@
  */
 asmlinkage int sys_sgetmask(void)
 {
-	return current->blocked;
+	int ret;
+
+	lock_kernel();
+	ret = current->blocked;
+	unlock_kernel();
+	return ret;
 }
 
 asmlinkage int sys_ssetmask(int newmask)
 {
-	int old=current->blocked;
+	int old;
 
+	lock_kernel();
+	old = current->blocked;
 	current->blocked = newmask & _BLOCKABLE;
+	unlock_kernel();
 	return old;
 }
 
@@ -78,8 +93,13 @@
 
 asmlinkage int sys_sigpending(sigset_t *set)
 {
+	int ret;
+
 	/* fill in "set" with signals pending but blocked. */
-	return put_user(current->blocked & current->signal, set);
+	lock_kernel();
+	ret = put_user(current->blocked & current->signal, set);
+	unlock_kernel();
+	return ret;
 }
 
 /*
@@ -97,7 +117,7 @@
  * isn't actually ignored, but does automatic child reaping, while
  * SIG_DFL is explicitly said by POSIX to force the signal to be ignored..
  */
-static inline void check_pending(int signum)
+inline void check_pending(int signum)
 {
 	struct sigaction *p;
 
@@ -120,17 +140,19 @@
  */
 asmlinkage unsigned long sys_signal(int signum, __sighandler_t handler)
 {
-	int err;
+	unsigned long err;
 	struct sigaction tmp;
 
+	lock_kernel();
+	err = -EINVAL;
 	if (signum<1 || signum>32)
-		return -EINVAL;
+		goto out;
 	if (signum==SIGKILL || signum==SIGSTOP)
-		return -EINVAL;
+		goto out;
 	if (handler != SIG_DFL && handler != SIG_IGN) {
 		err = verify_area(VERIFY_READ, handler, 1);
 		if (err)
-			return err;
+			goto out;
 	}
 	memset(&tmp, 0, sizeof(tmp));
 	tmp.sa_handler = handler;
@@ -138,39 +160,52 @@
 	handler = current->sig->action[signum-1].sa_handler;
 	current->sig->action[signum-1] = tmp;
 	check_pending(signum);
-	return (unsigned long) handler;
+	err = (unsigned long) handler;
+out:
+	unlock_kernel();
+	return err;
 }
 #endif
 
+#ifndef __sparc__
 asmlinkage int sys_sigaction(int signum, const struct sigaction * action,
 	struct sigaction * oldaction)
 {
 	struct sigaction new_sa, *p;
+	int ret = -EINVAL;
 
+	lock_kernel();
 	if (signum<1 || signum>32)
-		return -EINVAL;
+		goto out;
 	p = signum - 1 + current->sig->action;
 	if (action) {
-		int err = verify_area(VERIFY_READ, action, sizeof(*action));
-		if (err)
-			return err;
+		ret = verify_area(VERIFY_READ, action, sizeof(*action));
+		if (ret)
+			goto out;
+		ret = -EINVAL;
 		if (signum==SIGKILL || signum==SIGSTOP)
-			return -EINVAL;
+			goto out;
+		ret = -EFAULT;
 		if (copy_from_user(&new_sa, action, sizeof(struct sigaction)))
-			return -EFAULT;	
+			goto out;
 		if (new_sa.sa_handler != SIG_DFL && new_sa.sa_handler != SIG_IGN) {
-			err = verify_area(VERIFY_READ, new_sa.sa_handler, 1);
-			if (err)
-				return err;
+			ret = verify_area(VERIFY_READ, new_sa.sa_handler, 1);
+			if (ret)
+				goto out;
 		}
 	}
+	ret = -EFAULT;
 	if (oldaction) {
 		if (copy_to_user(oldaction, p, sizeof(struct sigaction)))
-			return -EFAULT;	
+			goto out;	
 	}
 	if (action) {
 		*p = new_sa;
 		check_pending(signum);
 	}
-	return 0;
+	ret = 0;
+out:
+	unlock_kernel();
+	return ret;
 }
+#endif
diff -u --recursive --new-file v2.1.22/linux/kernel/softirq.c linux/kernel/softirq.c
--- v2.1.22/linux/kernel/softirq.c	Mon Apr  1 08:36:26 1996
+++ linux/kernel/softirq.c	Sun Jan 26 12:07:49 1997
@@ -15,6 +15,8 @@
 #include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -35,6 +37,8 @@
 	unsigned long mask, left;
 	void (**bh)(void);
 
+	lock_kernel();
+	intr_count=1;
 	sti();
 	bh = bh_base;
 	active = bh_active & bh_mask;
@@ -48,7 +52,11 @@
 			fn();
 		}
 	}
-	return;
+	goto out;
 bad_bh:
 	printk ("irq.c:bad bottom half entry %08lx\n", mask);
+out:
+	intr_count=0;
+	unlock_kernel();
+	return;
 }
diff -u --recursive --new-file v2.1.22/linux/kernel/sys.c linux/kernel/sys.c
--- v2.1.22/linux/kernel/sys.c	Thu Jan 23 21:06:52 1997
+++ linux/kernel/sys.c	Sun Jan 26 12:07:49 1997
@@ -21,6 +21,8 @@
 #include <linux/fcntl.h>
 #include <linux/acct.h>
 #include <linux/tty.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 #if defined(CONFIG_APM) && defined(CONFIG_APM_POWER_OFF)
 #include <linux/apm_bios.h>
 #endif
@@ -74,13 +76,15 @@
 asmlinkage int sys_setpriority(int which, int who, int niceval)
 {
 	struct task_struct *p;
-	int error = ESRCH;
+	int error = EINVAL;
 	unsigned int priority;
 
+	lock_kernel();
 	if (which > 2 || which < 0)
-		return -EINVAL;
+		goto out;
 
 	/* normalize: avoid signed division (rounding problems) */
+	error = ESRCH;
 	priority = niceval;
 	if (niceval < 0)
 		priority = -niceval;
@@ -109,6 +113,8 @@
 		else
 			p->priority = priority;
 	}
+out:
+	unlock_kernel();
 	return -error;
 }
 
@@ -121,9 +127,11 @@
 {
 	struct task_struct *p;
 	long max_prio = -ESRCH;
+	int ret = -EINVAL;
 
+	lock_kernel();
 	if (which > 2 || which < 0)
-		return -EINVAL;
+		goto out;
 
 	for_each_task (p) {
 		if (!proc_sel(p, which, who))
@@ -135,7 +143,10 @@
 	/* scale the priority from timeslice to 0..40 */
 	if (max_prio > 0)
 		max_prio = (max_prio * 20 + DEF_PRIORITY/2) / DEF_PRIORITY;
-	return max_prio;
+	ret = max_prio;
+out:
+	unlock_kernel();
+	return ret;
 }
 
 #ifndef __alpha__
@@ -194,11 +205,16 @@
  */
 asmlinkage int sys_reboot(int magic, int magic_too, int flag)
 {
+	int error = -EPERM;
+
+	lock_kernel();
 	if (!suser())
-		return -EPERM;
+		goto out;
+	error = -EINVAL;
 	if (magic != 0xfee1dead || 
 	    (magic_too != 672274793 && magic_too != 85072278))
-		return -EINVAL;
+		goto out;
+	error = 0;
 	if (flag == 0x01234567)
 	{
 		notifier_call_chain(&boot_notifier_list, SYS_DOWN, NULL);
@@ -220,8 +236,10 @@
 		notifier_call_chain(&boot_notifier_list, SYS_HALT, NULL);
 		do_exit(0);
 	} else
-		return -EINVAL;
-	return (0);
+		error = -EINVAL;
+out:
+	unlock_kernel();
+	return error;
 }
 
 /*
@@ -260,14 +278,16 @@
 {
 	int old_rgid = current->gid;
 	int old_egid = current->egid;
+	int err = -EPERM;
 
+	lock_kernel();
 	if (rgid != (gid_t) -1) {
 		if ((old_rgid == rgid) ||
 		    (current->egid==rgid) ||
 		    suser())
 			current->gid = rgid;
 		else
-			return(-EPERM);
+			goto out;
 	}
 	if (egid != (gid_t) -1) {
 		if ((old_rgid == egid) ||
@@ -277,7 +297,7 @@
 			current->fsgid = current->egid = egid;
 		else {
 			current->gid = old_rgid;
-			return(-EPERM);
+			goto out;
 		}
 	}
 	if (rgid != (gid_t) -1 ||
@@ -286,7 +306,10 @@
 	current->fsgid = current->egid;
 	if (current->egid != old_egid)
 		current->dumpable = 0;
-	return 0;
+	err = 0;
+out:
+	unlock_kernel();
+	return err;
 }
 
 /*
@@ -295,16 +318,21 @@
 asmlinkage int sys_setgid(gid_t gid)
 {
 	int old_egid = current->egid;
+	int err = -EPERM;
 
+	lock_kernel();
 	if (suser())
 		current->gid = current->egid = current->sgid = current->fsgid = gid;
 	else if ((gid == current->gid) || (gid == current->sgid))
 		current->egid = current->fsgid = gid;
 	else
-		return -EPERM;
+		goto out;
+	err = 0;
 	if (current->egid != old_egid)
 		current->dumpable = 0;
-	return 0;
+out:
+	unlock_kernel();
+	return err;
 }
   
 static char acct_active = 0;
@@ -353,66 +381,70 @@
 
 asmlinkage int sys_acct(const char *name)
 {
-   struct inode *inode = (struct inode *)0;
-   char *tmp;
-   int error;
-
-   if (!suser())
-      return -EPERM;
-
-   if (name == (char *)0) {
-      if (acct_active) {
-         if (acct_file.f_op->release)
-            acct_file.f_op->release(acct_file.f_inode, &acct_file);
-
-         if (acct_file.f_inode != (struct inode *) 0)
-            iput(acct_file.f_inode);
-
-         acct_active = 0;
-      }
-      return 0;
-   } else {
-      if (!acct_active) {
-
-         if ((error = getname(name, &tmp)) != 0)
-            return (error);
-
-         error = open_namei(tmp, O_RDWR, 0600, &inode, 0);
-         putname(tmp);
-
-         if (error)
-            return (error);
-
-         if (!S_ISREG(inode->i_mode)) {
-            iput(inode);
-            return -EACCES;
-         }
-
-         if (!inode->i_op || !inode->i_op->default_file_ops || 
-             !inode->i_op->default_file_ops->write) {
-            iput(inode);
-            return -EIO;
-         }
-
-         acct_file.f_mode = 3;
-         acct_file.f_flags = 0;
-         acct_file.f_count = 1;
-         acct_file.f_inode = inode;
-         acct_file.f_pos = inode->i_size;
-         acct_file.f_reada = 0;
-         acct_file.f_op = inode->i_op->default_file_ops;
-
-         if (acct_file.f_op->open)
-            if (acct_file.f_op->open(acct_file.f_inode, &acct_file)) {
-               iput(inode);
-               return -EIO;
-            }
-
-         acct_active = 1;
-         return 0;
-      } else
-         return -EBUSY;
-   }
+	struct inode *inode = (struct inode *)0;
+	char *tmp;
+	int error = -EPERM;
+
+	lock_kernel();
+	if (!suser())
+		goto out;
+
+	if (name == (char *)0) {
+		if (acct_active) {
+			if (acct_file.f_op->release)
+				acct_file.f_op->release(acct_file.f_inode, &acct_file);
+
+			if (acct_file.f_inode != (struct inode *) 0)
+				iput(acct_file.f_inode);
+
+			acct_active = 0;
+		}
+		error = 0;
+	} else {
+		error = -EBUSY;
+		if (!acct_active) {
+			if ((error = getname(name, &tmp)) != 0)
+				goto out;
+
+			error = open_namei(tmp, O_RDWR, 0600, &inode, 0);
+			putname(tmp);
+			if (error)
+				goto out;
+
+			error = -EACCES;
+			if (!S_ISREG(inode->i_mode)) {
+				iput(inode);
+				goto out;
+			}
+
+			error = -EIO;
+			if (!inode->i_op || !inode->i_op->default_file_ops || 
+			    !inode->i_op->default_file_ops->write) {
+				iput(inode);
+				goto out;
+			}
+
+			acct_file.f_mode = 3;
+			acct_file.f_flags = 0;
+			acct_file.f_count = 1;
+			acct_file.f_inode = inode;
+			acct_file.f_pos = inode->i_size;
+			acct_file.f_reada = 0;
+			acct_file.f_op = inode->i_op->default_file_ops;
+
+			if(acct_file.f_op->open)
+				if(acct_file.f_op->open(acct_file.f_inode, &acct_file)) {
+					iput(inode);
+					goto out;
+				}
+
+			acct_active = 1;
+			error = 0;
+		}
+	}
+out:
+	unlock_kernel();
+	return error;
 }
 
 #ifndef __alpha__
@@ -467,16 +499,20 @@
  */
 asmlinkage int sys_setreuid(uid_t ruid, uid_t euid)
 {
-	int old_ruid = current->uid;
-	int old_euid = current->euid;
+	int old_ruid;
+	int old_euid;
+	int err = -EPERM;
 
+	lock_kernel();
+	old_ruid = current->uid;
+	old_euid = current->euid;
 	if (ruid != (uid_t) -1) {
 		if ((old_ruid == ruid) || 
 		    (current->euid==ruid) ||
 		    suser())
 			current->uid = ruid;
 		else
-			return(-EPERM);
+			goto out;
 	}
 	if (euid != (uid_t) -1) {
 		if ((old_ruid == euid) ||
@@ -486,7 +522,7 @@
 			current->fsuid = current->euid = euid;
 		else {
 			current->uid = old_ruid;
-			return(-EPERM);
+			goto out;
 		}
 	}
 	if (ruid != (uid_t) -1 ||
@@ -495,7 +531,10 @@
 	current->fsuid = current->euid;
 	if (current->euid != old_euid)
 		current->dumpable = 0;
-	return 0;
+	err = 0;
+out:
+	unlock_kernel();
+	return err;
 }
 
 /*
@@ -512,16 +551,22 @@
 asmlinkage int sys_setuid(uid_t uid)
 {
 	int old_euid = current->euid;
+	int retval = 0;
 
+	lock_kernel();
 	if (suser())
 		current->uid = current->euid = current->suid = current->fsuid = uid;
 	else if ((uid == current->uid) || (uid == current->suid))
 		current->fsuid = current->euid = uid;
-	else
-		return -EPERM;
+	else {
+		retval = -EPERM;
+		goto out;
+	}
 	if (current->euid != old_euid)
 		current->dumpable = 0;
-	return(0);
+out:
+	unlock_kernel();
+	return retval;
 }
 
 
@@ -532,36 +577,43 @@
 asmlinkage int sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)
 {
 	uid_t old_ruid, old_euid, old_suid;
+	int err = -EPERM;
 
+	lock_kernel();
 	old_ruid = current->uid;
 	old_euid = current->euid;
 	old_suid = current->suid;
 
 	if ((ruid != (uid_t) -1) && (ruid != current->uid) &&
 	    (ruid != current->euid) && (ruid != current->suid))
-		return -EPERM;
+		goto out;
 	if ((euid != (uid_t) -1) && (euid != current->uid) &&
 	    (euid != current->euid) && (euid != current->suid))
-		return -EPERM;
+		goto out;
 	if ((suid != (uid_t) -1) && (suid != current->uid) &&
 	    (suid != current->euid) && (suid != current->suid))
-		return -EPERM;
+		goto out;
 	if (ruid != (uid_t) -1)
 		current->uid = ruid;
 	if (euid != (uid_t) -1)
 		current->euid = euid;
 	if (suid != (uid_t) -1)
 		current->suid = suid;
-	return 0;
+	err = 0;
+out:
+	unlock_kernel();
+	return err;
 }
 
 asmlinkage int sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
 {
 	int retval;
 
+	lock_kernel();
 	if (!(retval = put_user(current->uid, ruid)) &&
 	    !(retval = put_user(current->euid, euid)))
 		retval = put_user(current->suid, suid);
+	unlock_kernel();
 	return retval;
 }
 
@@ -574,13 +626,16 @@
  */
 asmlinkage int sys_setfsuid(uid_t uid)
 {
-	int old_fsuid = current->fsuid;
+	int old_fsuid;
 
+	lock_kernel();
+	old_fsuid = current->fsuid;
 	if (uid == current->uid || uid == current->euid ||
 	    uid == current->suid || uid == current->fsuid || suser())
 		current->fsuid = uid;
 	if (current->fsuid != old_fsuid)
 		current->dumpable = 0;
+	unlock_kernel();
 	return old_fsuid;
 }
 
@@ -589,19 +644,24 @@
  */
 asmlinkage int sys_setfsgid(gid_t gid)
 {
-	int old_fsgid = current->fsgid;
+	int old_fsgid;
 
+	lock_kernel();
+	old_fsgid = current->fsgid;
 	if (gid == current->gid || gid == current->egid ||
 	    gid == current->sgid || gid == current->fsgid || suser())
 		current->fsgid = gid;
 	if (current->fsgid != old_fsgid)
 		current->dumpable = 0;
+	unlock_kernel();
 	return old_fsgid;
 }
 
 asmlinkage long sys_times(struct tms * tbuf)
 {
 	int error;
+
+	lock_kernel();
 	if (tbuf) {
 		error = put_user(current->utime,&tbuf->tms_utime);
 		if (!error)
@@ -611,9 +671,12 @@
 		if (!error)
 			error =	put_user(current->cstime,&tbuf->tms_cstime);
 		if (error)
-			return error;	
+			goto out;
 	}
-	return jiffies;
+	error = jiffies;
+out:
+	unlock_kernel();
+	return error;
 }
 
 /*
@@ -631,89 +694,127 @@
 asmlinkage int sys_setpgid(pid_t pid, pid_t pgid)
 {
 	struct task_struct * p;
+	int err = -EINVAL;
 
+	lock_kernel();
 	if (!pid)
 		pid = current->pid;
 	if (!pgid)
 		pgid = pid;
 	if (pgid < 0)
-		return -EINVAL;
+		goto out;
 	for_each_task(p) {
 		if (p->pid == pid)
 			goto found_task;
 	}
-	return -ESRCH;
+	err = -ESRCH;
+	goto out;
 
 found_task:
+	err = -ESRCH;
 	if (p->p_pptr == current || p->p_opptr == current) {
+		err = -EPERM;
 		if (p->session != current->session)
-			return -EPERM;
+			goto out;
+		err = -EACCES;
 		if (p->did_exec)
-			return -EACCES;
+			goto out;
 	} else if (p != current)
-		return -ESRCH;
+		goto out;
+	err = -EPERM;
 	if (p->leader)
-		return -EPERM;
+		goto out;
 	if (pgid != pid) {
 		struct task_struct * tmp;
 		for_each_task (tmp) {
 			if (tmp->pgrp == pgid &&
-			 tmp->session == current->session)
+			    tmp->session == current->session)
 				goto ok_pgid;
 		}
-		return -EPERM;
+		goto out;
 	}
 
 ok_pgid:
 	p->pgrp = pgid;
-	return 0;
+	err = 0;
+out:
+	unlock_kernel();
+	return err;
 }
 
 asmlinkage int sys_getpgid(pid_t pid)
 {
 	struct task_struct * p;
+	int ret;
 
-	if (!pid)
-		return current->pgrp;
-	for_each_task(p) {
-		if (p->pid == pid)
-			return p->pgrp;
+	lock_kernel();
+	if (!pid) {
+		ret = current->pgrp;
+	} else {
+		for_each_task(p) {
+			if (p->pid == pid) {
+				ret = p->pgrp;
+				goto out;
+			}
+		}
+		ret = -ESRCH;
 	}
-	return -ESRCH;
+out:
+	unlock_kernel();
+	return ret;
 }
 
 asmlinkage int sys_getpgrp(void)
 {
-	return current->pgrp;
+	int ret;
+
+	lock_kernel();
+	ret = current->pgrp;
+	unlock_kernel();
+	return ret;
 }
 
 asmlinkage int sys_getsid(pid_t pid)
 {
 	struct task_struct * p;
+	int ret;
 
-	if (!pid)
-		return current->session;
-	for_each_task(p) {
-		if (p->pid == pid)
-			return p->session;
+	lock_kernel();
+	if (!pid) {
+		ret = current->session;
+	} else {
+		for_each_task(p) {
+			if (p->pid == pid) {
+				ret = p->session;
+				goto out;
+			}
+		}
+		ret = -ESRCH;
 	}
-	return -ESRCH;
+out:
+	unlock_kernel();
+	return ret;
 }
 
 asmlinkage int sys_setsid(void)
 {
 	struct task_struct * p;
+	int err = -EPERM;
 
+	lock_kernel();
 	for_each_task(p) {
 		if (p->pgrp == current->pid)
-		        return -EPERM;
+		        goto out;
 	}
 
 	current->leader = 1;
 	current->session = current->pgrp = current->pid;
 	current->tty = NULL;
 	current->tty_old_pgrp = 0;
-	return current->pgrp;
+	err = current->pgrp;
+out:
+	unlock_kernel();
+	return err;
 }
 
 /*
@@ -721,34 +822,44 @@
  */
 asmlinkage int sys_getgroups(int gidsetsize, gid_t *grouplist)
 {
-	int i;
+	int i, err = -EINVAL;
 
+	lock_kernel();
 	if (gidsetsize < 0)
-		return -EINVAL;
+		goto out;
 	i = current->ngroups;
 	if (gidsetsize) {
+		err = -EINVAL;
 		if (i > gidsetsize)
-		        return -EINVAL;
+		        goto out;
+		err = -EFAULT;
 		if (copy_to_user(grouplist, current->groups, sizeof(gid_t)*i))
-			return -EFAULT;
+			goto out;
 	}
-	return i;
+	err = i;
+out:
+	unlock_kernel();
+	return err;
 }
 
 asmlinkage int sys_setgroups(int gidsetsize, gid_t *grouplist)
 {
-	int	err;
+	int err = -EPERM;
 
+	lock_kernel();
 	if (!suser())
-		return -EPERM;
+		goto out;
+	err = -EINVAL;
 	if ((unsigned) gidsetsize > NGROUPS)
-		return -EINVAL;
+		goto out;
 	err = copy_from_user(current->groups, grouplist, gidsetsize * sizeof(gid_t));
 	if (err) {
 		gidsetsize = 0;
 		err = -EFAULT;
 	} 
 	current->ngroups = gidsetsize;
+out:
+	unlock_kernel();
 	return err;
 }
 
@@ -773,11 +884,17 @@
 
 asmlinkage int sys_newuname(struct new_utsname * name)
 {
+	int err = -EFAULT;
+
+	lock_kernel();
 	if (!name)
-		return -EFAULT;
+		goto out;
 	if (copy_to_user(name,&system_utsname,sizeof *name))
-		return -EFAULT;
-	return 0;
+		goto out;
+	err = 0;
+out:
+	unlock_kernel();
+	return err;
 }
 
 #ifndef __alpha__
@@ -788,17 +905,22 @@
  */
 asmlinkage int sys_uname(struct old_utsname * name)
 {
-	int error = -EFAULT;;
+	int error = -EFAULT;
+
+	lock_kernel();
 	if (name && !copy_to_user(name, &system_utsname, sizeof (*name)))
 		error = 0;
+	unlock_kernel();
 	return error;
 }
 
 asmlinkage int sys_olduname(struct oldold_utsname * name)
 {
-	int error;
+	int error = -EFAULT;
+
+	lock_kernel();
 	if (!name)
-		return -EFAULT;
+		goto out;
 	error = copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
 	if (!error)
 		error = put_user(0,name->sysname+__OLD_UTS_LEN);
@@ -818,36 +940,49 @@
 		error = copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
 	if (!error)
 		error = put_user(0,name->machine+__OLD_UTS_LEN);
-	return error ? -EFAULT : 0;
+	error = error ? -EFAULT : 0;
+out:
+	unlock_kernel();
+	return error;
 }
 
 #endif
 
 asmlinkage int sys_sethostname(char *name, int len)
 {
-	int error;
+	int error = -EPERM;
 
+	lock_kernel();
 	if (!suser())
-		return -EPERM;
+		goto out;
+	error = -EINVAL;
 	if (len < 0 || len > __NEW_UTS_LEN)
-		return -EINVAL;
+		goto out;
 	error = copy_from_user(system_utsname.nodename, name, len);
-	if (error)
-		return -EFAULT;
+	if (error) {
+		error = -EFAULT;
+		goto out;
+	}
 	system_utsname.nodename[len] = 0;
-	return 0;
+out:
+	unlock_kernel();
+	return error;
 }
 
 asmlinkage int sys_gethostname(char *name, int len)
 {
-	int i;
+	int i, err = -EINVAL;
 
+	lock_kernel();
 	if (len < 0)
-		return -EINVAL;
+		goto out;
 	i = 1+strlen(system_utsname.nodename);
 	if (i > len)
 		i = len;
-	return copy_to_user(name, system_utsname.nodename, i) ? -EFAULT : 0;
+	err = copy_to_user(name, system_utsname.nodename, i) ? -EFAULT : 0;
+out:
+	unlock_kernel();
+	return err;
 }
 
 /*
@@ -856,48 +991,66 @@
  */
 asmlinkage int sys_setdomainname(char *name, int len)
 {
-	int error;
+	int error = -EPERM;
 	
+	lock_kernel();
 	if (!suser())
-		return -EPERM;
+		goto out;
+	error = -EINVAL;
 	if (len < 0 || len > __NEW_UTS_LEN)
-		return -EINVAL;
+		goto out;
 	error = copy_from_user(system_utsname.domainname, name, len);
 	if (error)
-		return -EFAULT;
-	system_utsname.domainname[len] = 0;
-	return 0;
+		error = -EFAULT;
+	else
+		system_utsname.domainname[len] = 0;
+out:
+	unlock_kernel();
+	return error;
 }
 
 asmlinkage int sys_getrlimit(unsigned int resource, struct rlimit *rlim)
 {
+	int error;
+
+	lock_kernel();
 	if (resource >= RLIM_NLIMITS)
-		return -EINVAL;
-	return copy_to_user(rlim, current->rlim + resource, sizeof(*rlim)) 
-			? -EFAULT : 0 ;
+		error = -EINVAL;
+	else
+		error = copy_to_user(rlim, current->rlim + resource, sizeof(*rlim))
+			? -EFAULT : 0;
+	unlock_kernel();
+	return error;
 }
 
 asmlinkage int sys_setrlimit(unsigned int resource, struct rlimit *rlim)
 {
 	struct rlimit new_rlim, *old_rlim;
-	int err;
+	int err = -EINVAL;
 
+	lock_kernel();
 	if (resource >= RLIM_NLIMITS)
-		return -EINVAL;
+		goto out;
 	err = copy_from_user(&new_rlim, rlim, sizeof(*rlim));
-	if (err)
-		return -EFAULT;	
+	if (err) {
+		err = -EFAULT;
+		goto out;
+	}
 	old_rlim = current->rlim + resource;
+	err = -EPERM;
 	if (((new_rlim.rlim_cur > old_rlim->rlim_max) ||
 	     (new_rlim.rlim_max > old_rlim->rlim_max)) &&
 	    !suser())
-		return -EPERM;
+		goto out;
 	if (resource == RLIMIT_NOFILE) {
 		if (new_rlim.rlim_cur > NR_OPEN || new_rlim.rlim_max > NR_OPEN)
-			return -EPERM;
+			goto out;
 	}
 	*old_rlim = new_rlim;
-	return 0;
+	err = 0;
+out:
+	unlock_kernel();
+	return err;
 }
 
 /*
@@ -911,7 +1064,9 @@
 int getrusage(struct task_struct *p, int who, struct rusage *ru)
 {
 	struct rusage r;
+	int err;
 
+	lock_kernel();
 	memset((char *) &r, 0, sizeof(r));
 	switch (who) {
 		case RUSAGE_SELF:
@@ -942,20 +1097,31 @@
 			r.ru_nswap = p->nswap + p->cnswap;
 			break;
 	}
-	return copy_to_user(ru, &r, sizeof(r)) ? -EFAULT : 0;
+	err = copy_to_user(ru, &r, sizeof(r)) ? -EFAULT : 0;
+	unlock_kernel();
+	return err;
 }
 
 asmlinkage int sys_getrusage(int who, struct rusage *ru)
 {
+	int err = -EINVAL;
+
+	lock_kernel();
 	if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN)
-		return -EINVAL;
-	return getrusage(current, who, ru);
+		goto out;
+	err = getrusage(current, who, ru);
+out:
+	unlock_kernel();
+	return err;
 }
 
 asmlinkage int sys_umask(int mask)
 {
-	int old = current->fs->umask;
+	int old;
 
+	lock_kernel();
+	old = current->fs->umask;
 	current->fs->umask = mask & S_IRWXUGO;
+	unlock_kernel();
 	return (old);
 }
diff -u --recursive --new-file v2.1.22/linux/kernel/sysctl.c linux/kernel/sysctl.c
--- v2.1.22/linux/kernel/sysctl.c	Wed Dec 18 15:59:03 1996
+++ linux/kernel/sysctl.c	Sun Jan 26 12:07:49 1997
@@ -20,6 +20,8 @@
 #include <linux/ctype.h>
 #include <linux/utsname.h>
 #include <linux/swapctl.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/bitops.h>
 #include <asm/uaccess.h>
@@ -59,7 +61,7 @@
 	proc_readsys,	/* read	   */
 	proc_writesys,	/* write   */
 	NULL,		/* readdir */
-	NULL,		/* select  */
+	NULL,		/* poll    */
 	NULL,		/* ioctl   */
 	NULL,		/* mmap	   */
 	NULL,		/* no special open code	   */
@@ -226,12 +228,17 @@
 {
 	struct __sysctl_args tmp;
 	int error;
+
+	lock_kernel();
 	error = verify_area(VERIFY_READ, args, sizeof(*args));
 	if (error)
-		return error;
+		goto out;
 	copy_from_user(&tmp, args, sizeof(tmp));
-	return do_sysctl(tmp.name, tmp.nlen, tmp.oldval, tmp.oldlenp, 
-			 tmp.newval, tmp.newlen);
+	error = do_sysctl(tmp.name, tmp.nlen, tmp.oldval, tmp.oldlenp,
+			  tmp.newval, tmp.newlen);
+out:
+	unlock_kernel();
+	return error;
 }
 
 /* Like in_group_p, but testing against egid, not fsgid */
diff -u --recursive --new-file v2.1.22/linux/kernel/time.c linux/kernel/time.c
--- v2.1.22/linux/kernel/time.c	Tue Nov 19 15:53:59 1996
+++ linux/kernel/time.c	Sun Jan 26 12:07:49 1997
@@ -25,6 +25,8 @@
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/timex.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 
@@ -64,11 +66,13 @@
 {
 	int i;
 
+	lock_kernel();
 	i = CURRENT_TIME;
 	if (tloc) {
 		if (put_user(i,tloc))
 			i = -EFAULT;
 	}
+	unlock_kernel();
 	return i;
 }
 
@@ -80,12 +84,14 @@
  */
 asmlinkage int sys_stime(int * tptr)
 {
-	int value;
+	int value = -EPERM;
 
+	lock_kernel();
 	if (!suser())
-		return -EPERM;
+		goto out;
+	value = -EFAULT;
 	if (get_user(value, tptr))
-		return -EFAULT;
+		goto out;
 	cli();
 	xtime.tv_sec = value;
 	xtime.tv_usec = 0;
@@ -93,24 +99,33 @@
 	time_maxerror = MAXPHASE;
 	time_esterror = MAXPHASE;
 	sti();
-	return 0;
+	value = 0;
+out:
+	unlock_kernel();
+	return value;
 }
 
 #endif
 
 asmlinkage int sys_gettimeofday(struct timeval *tv, struct timezone *tz)
 {
+	int err = -EFAULT;
+
+	lock_kernel();
 	if (tv) {
 		struct timeval ktv;
 		do_gettimeofday(&ktv);
 		if (copy_to_user(tv, &ktv, sizeof(ktv)))
-			return -EFAULT;
+			goto out;
 	}
 	if (tz) {
 		if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
-			return -EFAULT;
+			goto out;
 	}
-	return 0;
+	err = 0;
+out:
+	unlock_kernel();
+	return err;
 }
 
 /*
@@ -151,16 +166,19 @@
 	static int	firsttime = 1;
 	struct timeval	new_tv;
 	struct timezone new_tz;
+	int err = -EPERM;
 
+	lock_kernel();
 	if (!suser())
-		return -EPERM;
+		goto out;
+	err = -EFAULT;
 	if (tv) {
 		if (copy_from_user(&new_tv, tv, sizeof(*tv)))
-			return -EFAULT;
+			goto out;
 	}
 	if (tz) {
 		if (copy_from_user(&new_tz, tz, sizeof(*tz)))
-			return -EFAULT;
+			goto out;
 		sys_tz = new_tz;
 		if (firsttime) {
 			firsttime = 0;
@@ -170,7 +188,10 @@
 	}
 	if (tv)
 		do_settimeofday(&new_tv);
-	return 0;
+	err = 0;
+out:
+	unlock_kernel();
+	return err;
 }
 
 long pps_offset = 0;		/* pps time offset (us) */
@@ -197,35 +218,33 @@
 asmlinkage int sys_adjtimex(struct timex *txc_p)
 {
         long ltemp, mtemp, save_adjust;
-	int error;
-
-	/* Local copy of parameter */
-	struct timex txc;
+	int error = -EFAULT;
+	struct timex txc;		/* Local copy of parameter */
 
+	lock_kernel();
 	/* Copy the user data space into the kernel copy
 	 * structure. But bear in mind that the structures
 	 * may change
 	 */
-	error = copy_from_user(&txc, txc_p, sizeof(struct timex));
-	if (error)
-		return -EFAULT;	
+	if(copy_from_user(&txc, txc_p, sizeof(struct timex)))
+		goto out;	
 
 	/* In order to modify anything, you gotta be super-user! */
+	error = -EPERM;
 	if (txc.modes && !suser())
-		return -EPERM;
-
-	/* Now we validate the data before disabling interrupts
-	 */
+		goto out;
 
+	/* Now we validate the data before disabling interrupts */
+	error = -EINVAL;
 	if (txc.modes != ADJ_OFFSET_SINGLESHOT && (txc.modes & ADJ_OFFSET))
 	  /* adjustment Offset limited to +- .512 seconds */
 	  if (txc.offset <= - MAXPHASE || txc.offset >= MAXPHASE )
-	    return -EINVAL;
+	    goto out;
 
 	/* if the quartz is off by more than 10% something is VERY wrong ! */
 	if (txc.modes & ADJ_TICK)
 	  if (txc.tick < 900000/HZ || txc.tick > 1100000/HZ)
-	    return -EINVAL;
+	    goto out;
 
 	cli();
 
@@ -343,5 +362,8 @@
 
 	sti();
 
-	return copy_to_user(txc_p, &txc, sizeof(struct timex)) ? -EFAULT : time_state;
+	error = copy_to_user(txc_p, &txc, sizeof(struct timex)) ? -EFAULT : time_state;
+out:
+	unlock_kernel();
+	return error;
 }
diff -u --recursive --new-file v2.1.22/linux/mm/Makefile linux/mm/Makefile
--- v2.1.22/linux/mm/Makefile	Fri Mar 22 12:56:56 1996
+++ linux/mm/Makefile	Sun Jan 26 12:07:49 1997
@@ -9,7 +9,7 @@
 
 O_TARGET := mm.o
 O_OBJS	 := memory.o mmap.o filemap.o mprotect.o mlock.o mremap.o \
-	    kmalloc.o vmalloc.o \
+	    kmalloc.o vmalloc.o slab.o \
 	    swap.o vmscan.o page_io.o page_alloc.o swap_state.o swapfile.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.22/linux/mm/filemap.c linux/mm/filemap.c
--- v2.1.22/linux/mm/filemap.c	Sun Dec 22 16:37:42 1996
+++ linux/mm/filemap.c	Sun Jan 26 12:07:49 1997
@@ -22,6 +22,8 @@
 #include <linux/locks.h>
 #include <linux/pagemap.h>
 #include <linux/swap.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/system.h>
 #include <asm/pgtable.h>
@@ -1222,18 +1224,20 @@
 {
 	unsigned long end;
 	struct vm_area_struct * vma;
-	int unmapped_error, error;
+	int unmapped_error, error = -EINVAL;
 
+	lock_kernel();
 	if (start & ~PAGE_MASK)
-		return -EINVAL;
+		goto out;
 	len = (len + ~PAGE_MASK) & PAGE_MASK;
 	end = start + len;
 	if (end < start)
-		return -EINVAL;
+		goto out;
 	if (flags & ~(MS_ASYNC | MS_INVALIDATE | MS_SYNC))
-		return -EINVAL;
+		goto out;
+	error = 0;
 	if (end == start)
-		return 0;
+		goto out;
 	/*
 	 * If the interval [start,end) covers some unmapped address ranges,
 	 * just ignore them, but return -EFAULT at the end.
@@ -1242,8 +1246,9 @@
 	unmapped_error = 0;
 	for (;;) {
 		/* Still start < end. */
+		error = -EFAULT;
 		if (!vma)
-			return -EFAULT;
+			goto out;
 		/* Here start < vma->vm_end. */
 		if (start < vma->vm_start) {
 			unmapped_error = -EFAULT;
@@ -1254,15 +1259,19 @@
 			if (start < end) {
 				error = msync_interval(vma, start, end, flags);
 				if (error)
-					return error;
+					goto out;
 			}
-			return unmapped_error;
+			error = unmapped_error;
+			goto out;
 		}
 		/* Here vma->vm_start <= start < vma->vm_end < end. */
 		error = msync_interval(vma, start, vma->vm_end, flags);
 		if (error)
-			return error;
+			goto out;
 		start = vma->vm_end;
 		vma = vma->vm_next;
 	}
+out:
+	unlock_kernel();
+	return error;
 }
diff -u --recursive --new-file v2.1.22/linux/mm/mlock.c linux/mm/mlock.c
--- v2.1.22/linux/mm/mlock.c	Sun Dec 22 16:37:42 1996
+++ linux/mm/mlock.c	Sun Jan 26 12:07:49 1997
@@ -7,11 +7,13 @@
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
+#include <linux/slab.h>
 #include <linux/shm.h>
 #include <linux/errno.h>
 #include <linux/mman.h>
 #include <linux/string.h>
-#include <linux/malloc.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -28,7 +30,7 @@
 {
 	struct vm_area_struct * n;
 
-	n = (struct vm_area_struct *) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL);
+	n = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
 	if (!n)
 		return -EAGAIN;
 	*n = *vma;
@@ -49,7 +51,7 @@
 {
 	struct vm_area_struct * n;
 
-	n = (struct vm_area_struct *) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL);
+	n = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
 	if (!n)
 		return -EAGAIN;
 	*n = *vma;
@@ -70,12 +72,12 @@
 {
 	struct vm_area_struct * left, * right;
 
-	left = (struct vm_area_struct *) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL);
+	left = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
 	if (!left)
 		return -EAGAIN;
-	right = (struct vm_area_struct *) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL);
+	right = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
 	if (!right) {
-		kfree(left);
+		kmem_cache_free(vm_area_cachep, left);
 		return -EAGAIN;
 	}
 	*left = *vma;
@@ -187,7 +189,9 @@
 {
 	unsigned long locked;
 	unsigned long lock_limit;
+	int error = -ENOMEM;
 
+	lock_kernel();
 	len = (len + (start & ~PAGE_MASK) + ~PAGE_MASK) & PAGE_MASK;
 	start &= PAGE_MASK;
 
@@ -199,21 +203,29 @@
 
 	/* check against resource limits */
 	if (locked > lock_limit)
-		return -ENOMEM;
+		goto out;
 
 	/* we may lock at most half of physical memory... */
 	/* (this check is pretty bogus, but doesn't hurt) */
 	if (locked > num_physpages/2)
-		return -ENOMEM;
+		goto out;
 
-	return do_mlock(start, len, 1);
+	error = do_mlock(start, len, 1);
+out:
+	unlock_kernel();
+	return error;
 }
 
 asmlinkage int sys_munlock(unsigned long start, size_t len)
 {
+	int ret;
+
+	lock_kernel();
 	len = (len + (start & ~PAGE_MASK) + ~PAGE_MASK) & PAGE_MASK;
 	start &= PAGE_MASK;
-	return do_mlock(start, len, 0);
+	ret = do_mlock(start, len, 0);
+	unlock_kernel();
+	return ret;
 }
 
 static int do_mlockall(int flags)
@@ -248,25 +260,36 @@
 asmlinkage int sys_mlockall(int flags)
 {
 	unsigned long lock_limit;
+	int ret = -EINVAL;
 
+	lock_kernel();
 	if (!flags || (flags & ~(MCL_CURRENT | MCL_FUTURE)))
-		return -EINVAL;
+		goto out;
 
 	lock_limit = current->rlim[RLIMIT_MEMLOCK].rlim_cur;
 	lock_limit >>= PAGE_SHIFT;
 
+	ret = -ENOMEM;
 	if (current->mm->total_vm > lock_limit)
-		return -ENOMEM;
+		goto out;
 
 	/* we may lock at most half of physical memory... */
 	/* (this check is pretty bogus, but doesn't hurt) */
 	if (current->mm->total_vm > num_physpages/2)
-		return -ENOMEM;
+		goto out;
 
-	return do_mlockall(flags);
+	ret = do_mlockall(flags);
+out:
+	unlock_kernel();
+	return ret;
 }
 
 asmlinkage int sys_munlockall(void)
 {
-	return do_mlockall(0);
+	int ret;
+
+	lock_kernel();
+	ret = do_mlockall(0);
+	unlock_kernel();
+	return ret;
 }
diff -u --recursive --new-file v2.1.22/linux/mm/mmap.c linux/mm/mmap.c
--- v2.1.22/linux/mm/mmap.c	Thu Jan  2 15:55:26 1997
+++ linux/mm/mmap.c	Sun Jan 26 12:07:49 1997
@@ -7,13 +7,15 @@
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
+#include <linux/slab.h>
 #include <linux/shm.h>
 #include <linux/errno.h>
 #include <linux/mman.h>
 #include <linux/string.h>
-#include <linux/malloc.h>
 #include <linux/pagemap.h>
 #include <linux/swap.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -41,6 +43,9 @@
 	__S000, __S001, __S010, __S011, __S100, __S101, __S110, __S111
 };
 
+/* SLAB cache for vm_area_struct's. */
+kmem_cache_t *vm_area_cachep;
+
 /*
  * Check that a process has enough memory to allocate a
  * new virtual mapping.
@@ -64,54 +69,62 @@
 
 asmlinkage unsigned long sys_brk(unsigned long brk)
 {
-	unsigned long rlim;
+	unsigned long rlim, retval;
 	unsigned long newbrk, oldbrk;
 	struct mm_struct *mm = current->mm;
 
+	lock_kernel();
+	retval = mm->brk;
 	if (brk < mm->end_code)
-		return mm->brk;
+		goto out;
 	newbrk = PAGE_ALIGN(brk);
 	oldbrk = PAGE_ALIGN(mm->brk);
-	if (oldbrk == newbrk)
-		return mm->brk = brk;
+	if (oldbrk == newbrk) {
+		retval = mm->brk = brk;
+		goto out;
+	}
 
 	/*
 	 * Always allow shrinking brk
 	 */
 	if (brk <= mm->brk) {
-		mm->brk = brk;
+		retval = mm->brk = brk;
 		do_munmap(newbrk, oldbrk-newbrk);
-		return brk;
+		goto out;
 	}
 	/*
 	 * Check against rlimit and stack..
 	 */
+	retval = mm->brk;
 	rlim = current->rlim[RLIMIT_DATA].rlim_cur;
 	if (rlim >= RLIM_INFINITY)
 		rlim = ~0;
 	if (brk - mm->end_code > rlim)
-		return mm->brk;
+		goto out;
 
 	/*
 	 * Check against existing mmap mappings.
 	 */
 	if (find_vma_intersection(mm, oldbrk, newbrk+PAGE_SIZE))
-		return mm->brk;
+		goto out;
 
 	/*
 	 * Check if we have enough memory..
 	 */
 	if (!vm_enough_memory((newbrk-oldbrk) >> PAGE_SHIFT))
-		return mm->brk;
+		goto out;
 
 	/*
 	 * Ok, looks good - let it rip.
 	 */
 	if(do_mmap(NULL, oldbrk, newbrk-oldbrk,
-		PROT_READ|PROT_WRITE|PROT_EXEC,
-		   MAP_FIXED|MAP_PRIVATE, 0) != oldbrk)
-		return mm->brk;
-	return mm->brk = brk;
+		   PROT_READ|PROT_WRITE|PROT_EXEC,
+		   MAP_FIXED|MAP_PRIVATE, 0) == oldbrk)
+		mm->brk = brk;
+	retval = mm->brk;
+out:
+	unlock_kernel();
+	return retval;
 }
 
 /*
@@ -215,8 +228,7 @@
 	if (file && (!file->f_op || !file->f_op->mmap))
 		return -ENODEV;
 
-	vma = (struct vm_area_struct *)kmalloc(sizeof(struct vm_area_struct),
-		GFP_KERNEL);
+	vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
 	if (!vma)
 		return -ENOMEM;
 
@@ -256,7 +268,7 @@
 	/* Check against address space limit. */
 	if ((mm->total_vm << PAGE_SHIFT) + len
 	    > current->rlim[RLIMIT_AS].rlim_cur) {
-		kfree(vma);
+		kmem_cache_free(vm_area_cachep, vma);
 		return -ENOMEM;
 	}
 
@@ -264,7 +276,7 @@
 	if ((vma->vm_flags & (VM_SHARED | VM_WRITE)) == VM_WRITE) {
 		if (!(flags & MAP_NORESERVE) &&
 		    !vm_enough_memory(len >> PAGE_SHIFT)) {
-			kfree(vma);
+			kmem_cache_free(vm_area_cachep, vma);
 			return -ENOMEM;
 		}
 	}
@@ -273,7 +285,7 @@
 		int error = file->f_op->mmap(file->f_inode, file, vma);
 	
 		if (error) {
-			kfree(vma);
+			kmem_cache_free(vm_area_cachep, vma);
 			return error;
 		}
 	}
@@ -284,7 +296,7 @@
 
 	/* merge_segments might have merged our vma, so we can't use it any more */
 	mm->total_vm += len >> PAGE_SHIFT;
-	if (flags & VM_LOCKED) {
+	if ((flags & VM_LOCKED) && !(flags & VM_IO)) {
 		unsigned long start = addr;
 		mm->locked_vm += len >> PAGE_SHIFT;
 		do {
@@ -751,7 +763,7 @@
 	else {
 	/* Unmapping a hole: area->vm_start < addr <= end < area->vm_end */
 		/* Add end mapping -- leave beginning for below */
-		mpnt = (struct vm_area_struct *)kmalloc(sizeof(*mpnt), GFP_KERNEL);
+		mpnt = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
 
 		if (!mpnt)
 			return;
@@ -767,7 +779,7 @@
 	}
 
 	/* construct whatever mapping is needed */
-	mpnt = (struct vm_area_struct *)kmalloc(sizeof(*mpnt), GFP_KERNEL);
+	mpnt = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
 	if (!mpnt)
 		return;
 	*mpnt = *area;
@@ -782,7 +794,12 @@
 
 asmlinkage int sys_munmap(unsigned long addr, size_t len)
 {
-	return do_munmap(addr, len);
+	int ret;
+
+	lock_kernel();
+	ret = do_munmap(addr, len);
+	unlock_kernel();
+	return ret;
 }
 
 /*
@@ -851,7 +868,7 @@
 		zap_page_range(current->mm, st, size);
 		flush_tlb_range(current->mm, st, end);
 		unmap_fixup(mpnt, st, size);
-		kfree(mpnt);
+		kmem_cache_free(vm_area_cachep, mpnt);
 	} while (free);
 
 	/* we could zap the page tables here too.. */
@@ -896,7 +913,7 @@
 		zap_page_range(mm, start, size);
 		if (mpnt->vm_inode)
 			iput(mpnt->vm_inode);
-		kfree(mpnt);
+		kmem_cache_free(vm_area_cachep, mpnt);
 		mpnt = next;
 	}
 }
@@ -1045,9 +1062,19 @@
 		remove_shared_vm_struct(mpnt);
 		if (mpnt->vm_inode)
 			mpnt->vm_inode->i_count--;
-		kfree_s(mpnt, sizeof(*mpnt));
+		kmem_cache_free(vm_area_cachep, mpnt);
 		mpnt = prev;
 	}
 no_vma:
 	up(&mm->mmap_sem);
+}
+
+void vma_init(void)
+{
+	vm_area_cachep = kmem_cache_create("vm_area_struct",
+					   sizeof(struct vm_area_struct),
+					   sizeof(long)*8, SLAB_HWCACHE_ALIGN,
+					   NULL, NULL);
+	if(!vm_area_cachep)
+		panic("vma_init: Cannot alloc vm_area_struct cache.");
 }
diff -u --recursive --new-file v2.1.22/linux/mm/mprotect.c linux/mm/mprotect.c
--- v2.1.22/linux/mm/mprotect.c	Tue Oct 29 19:58:48 1996
+++ linux/mm/mprotect.c	Sun Jan 26 12:07:49 1997
@@ -7,11 +7,13 @@
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 #include <linux/shm.h>
 #include <linux/errno.h>
 #include <linux/mman.h>
 #include <linux/string.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -99,7 +101,7 @@
 {
 	struct vm_area_struct * n;
 
-	n = (struct vm_area_struct *) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL);
+	n = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
 	if (!n)
 		return -ENOMEM;
 	*n = *vma;
@@ -122,7 +124,7 @@
 {
 	struct vm_area_struct * n;
 
-	n = (struct vm_area_struct *) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL);
+	n = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL);
 	if (!n)
 		return -ENOMEM;
 	*n = *vma;
@@ -145,12 +147,12 @@
 {
 	struct vm_area_struct * left, * right;
 
-	left = (struct vm_area_struct *) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL);
+	left = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
 	if (!left)
 		return -ENOMEM;
-	right = (struct vm_area_struct *) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL);
+	right = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
 	if (!right) {
-		kfree(left);
+		kmem_cache_free(vm_area_cachep, left);
 		return -ENOMEM;
 	}
 	*left = *vma;
@@ -204,21 +206,24 @@
 {
 	unsigned long nstart, end, tmp;
 	struct vm_area_struct * vma, * next;
-	int error;
+	int error = -EINVAL;
 
+	lock_kernel();
 	if (start & ~PAGE_MASK)
-		return -EINVAL;
+		goto out;
 	len = (len + ~PAGE_MASK) & PAGE_MASK;
 	end = start + len;
 	if (end < start)
-		return -EINVAL;
+		goto out;
 	if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC))
-		return -EINVAL;
+		goto out;
+	error = 0;
 	if (end == start)
-		return 0;
+		goto out;
 	vma = find_vma(current->mm, start);
+	error = -EFAULT;
 	if (!vma || vma->vm_start > start)
-		return -EFAULT;
+		goto out;
 
 	for (nstart = start ; ; ) {
 		unsigned int newflags;
@@ -249,5 +254,7 @@
 		}
 	}
 	merge_segments(current->mm, start, end);
+out:
+	unlock_kernel();
 	return error;
 }
diff -u --recursive --new-file v2.1.22/linux/mm/mremap.c linux/mm/mremap.c
--- v2.1.22/linux/mm/mremap.c	Thu Jan  2 15:55:26 1997
+++ linux/mm/mremap.c	Sun Jan 26 12:07:49 1997
@@ -8,11 +8,13 @@
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 #include <linux/shm.h>
 #include <linux/errno.h>
 #include <linux/mman.h>
 #include <linux/string.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/swap.h>
 
 #include <asm/uaccess.h>
@@ -129,8 +131,7 @@
 {
 	struct vm_area_struct * new_vma;
 
-	new_vma = (struct vm_area_struct *)
-		kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL);
+	new_vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
 	if (new_vma) {
 		unsigned long new_addr = get_unmapped_area(addr, new_len);
 
@@ -149,7 +150,7 @@
 			current->mm->total_vm += new_len >> PAGE_SHIFT;
 			return new_addr;
 		}
-		kfree(new_vma);
+		kmem_cache_free(vm_area_cachep, new_vma);
 	}
 	return -ENOMEM;
 }
@@ -163,9 +164,11 @@
 	unsigned long flags)
 {
 	struct vm_area_struct *vma;
+	unsigned long ret = -EINVAL;
 
+	lock_kernel();
 	if (addr & ~PAGE_MASK)
-		return -EINVAL;
+		goto out;
 	old_len = PAGE_ALIGN(old_len);
 	new_len = PAGE_ALIGN(new_len);
 
@@ -173,29 +176,33 @@
 	 * Always allow a shrinking remap: that just unmaps
 	 * the unnecessary pages..
 	 */
+	ret = addr;
 	if (old_len > new_len) {
 		do_munmap(addr+new_len, old_len - new_len);
-		return addr;
+		goto out;
 	}
 
 	/*
 	 * Ok, we need to grow..
 	 */
+	ret = -EFAULT;
 	vma = find_vma(current->mm, addr);
 	if (!vma || vma->vm_start > addr)
-		return -EFAULT;
+		goto out;
 	/* We can't remap across vm area boundaries */
 	if (old_len > vma->vm_end - addr)
-		return -EFAULT;
+		goto out;
 	if (vma->vm_flags & VM_LOCKED) {
 		unsigned long locked = current->mm->locked_vm << PAGE_SHIFT;
 		locked += new_len - old_len;
+		ret = -EAGAIN;
 		if (locked > current->rlim[RLIMIT_MEMLOCK].rlim_cur)
-			return -EAGAIN;
+			goto out;
 	}
+	ret = -ENOMEM;
 	if ((current->mm->total_vm << PAGE_SHIFT) + (new_len - old_len)
 	    > current->rlim[RLIMIT_AS].rlim_cur)
-		return -ENOMEM;
+		goto out;
 
 	/* old_len exactly to the end of the area.. */
 	if (old_len == vma->vm_end - addr &&
@@ -210,7 +217,8 @@
 			current->mm->total_vm += pages;
 			if (vma->vm_flags & VM_LOCKED)
 				current->mm->locked_vm += pages;
-			return addr;
+			ret = addr;
+			goto out;
 		}
 	}
 
@@ -219,6 +227,10 @@
 	 * we need to create a new one and move it..
 	 */
 	if (flags & MREMAP_MAYMOVE)
-		return move_vma(vma, addr, old_len, new_len);
-	return -ENOMEM;
+		ret = move_vma(vma, addr, old_len, new_len);
+	else
+		ret = -ENOMEM;
+out:
+	unlock_kernel();
+	return ret;
 }
diff -u --recursive --new-file v2.1.22/linux/mm/page_alloc.c linux/mm/page_alloc.c
--- v2.1.22/linux/mm/page_alloc.c	Tue Oct 29 19:58:48 1996
+++ linux/mm/page_alloc.c	Sun Jan 26 12:07:49 1997
@@ -5,6 +5,7 @@
  *  Swap reorganised 29.12.95, Stephen Tweedie
  */
 
+#include <linux/config.h>
 #include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/head.h>
@@ -34,7 +35,13 @@
  * of different sizes
  */
 
+#if CONFIG_AP1000
+/* the AP+ needs to allocate 8MB contiguous, aligned chunks of ram
+   for the ring buffers */
+#define NR_MEM_LISTS 12
+#else
 #define NR_MEM_LISTS 6
+#endif
 
 /* The start of this MUST match the start of "struct page" */
 struct free_area_struct {
@@ -239,7 +246,7 @@
 			nr ++;
 		}
 		total += nr * ((PAGE_SIZE>>10) << order);
-		printk("%lu*%lukB ", nr, (PAGE_SIZE>>10) << order);
+		printk("%lu*%lukB ", nr, (unsigned long)((PAGE_SIZE>>10) << order));
 	}
 	restore_flags(flags);
 	printk("= %lukB)\n", total);
diff -u --recursive --new-file v2.1.22/linux/mm/slab.c linux/mm/slab.c
--- v2.1.22/linux/mm/slab.c	Thu Jan  1 02:00:00 1970
+++ linux/mm/slab.c	Sun Jan 26 12:07:49 1997
@@ -0,0 +1,1526 @@
+/*
+ * linux/mm/slab.c
+ * Written by Mark Hemment, 1996.
+ * (markhe@nextd.demon.co.uk)
+ */
+/*
+ * An implementation of the Slab Allocator as described in outline in;
+ *	UNIX Internals: The New Frontiers by Uresh Vahalia
+ *	Pub: Prentice Hall	ISBN 0-13-101908-2
+ * or with a little more detail in;
+ *	The Slab Allocator: An Object-Caching Kernel Memory Allocator
+ *	Jeff Bonwick (Sun Microsystems).
+ *      Presented at: USENIX Summer 1994 Technical Conference
+ */
+
+#include	<linux/slab.h>
+#include	<linux/mm.h>
+#include	<linux/interrupt.h>
+#include	<asm/system.h>
+#include	<asm/cache.h>
+
+/* SLAB_MGMT_CHECKS	- define to enable extra checks in
+ *                        kmem_cache_[create|destroy|shrink].
+ *			  If you're not messing around with these funcs, then undef this.
+ * SLAB_HIGH_PACK	- define to allow 'bufctl's to be stored within objs that do not
+ *			  have a state.  This allows more objs per slab, but removes the
+ *			  ability to sanity check an addr on release (if the addr is
+ *                        within any slab, anywhere, kmem_cache_free() will accept it!).
+ * SLAB_DEBUG_SUPPORT	- when defined, kmem_cache_create() will honour; SLAB_DEBUG_FREE,
+ *			  SLAB_DEBUG_INITIAL and SLAB_RED_ZONE.
+ */
+#define		SLAB_MGMT_CHECKS
+#undef		SLAB_HIGH_PACK
+#define		SLAB_DEBUG_SUPPORT	/* undef this when your cache is stable */
+
+#define	BYTES_PER_WORD	sizeof(void *)
+
+/* legal flag mask for kmem_cache_create() */
+#if	defined(SLAB_DEBUG_SUPPORT)
+#define	SLAB_C_MASK		(SLAB_DEBUG_FREE|SLAB_DEBUG_INITIAL|SLAB_HWCACHE_ALIGN|SLAB_RED_ZONE)
+#else
+#define	SLAB_C_MASK		(SLAB_HWCACHE_ALIGN)
+#endif	/* SLAB_DEBUG_SUPPORT */
+
+/* Magic num for red zoning.
+ * Placed in the first word after the end of an obj
+ */
+#define	SLAB_RED_MAGIC1		0x5A2CF071UL	/* when obj is active */
+#define	SLAB_RED_MAGIC2		0x170FC2A5UL	/* when obj is inactive */
+
+/* Used for linking objs within a slab.  How much of the struct is
+ * used, and where its placed, depends on the packing used in a cache.
+ * Don't mess with the order!
+ */
+typedef struct kmem_bufctl_s {
+	struct kmem_bufctl_s	*buf_nextp;
+	struct kmem_slab_s	*buf_slabp;
+	void 			*buf_objp;	/* start of obj */
+	struct kmem_bufctl_s	*buf_hnextp;
+	struct kmem_bufctl_s	**buf_hashp;
+} kmem_bufctl_t;
+
+/* different portions of the bufctl are used - so need some macros */
+#define	kmem_bufctl_offset(x) ((unsigned long)&((kmem_bufctl_t *)0)->x)
+#define	kmem_bufctl_short_size	(kmem_bufctl_offset(buf_objp))
+#define	kmem_bufctl_very_short_size	(kmem_bufctl_offset(buf_slabp))
+
+/* Slab management struct.
+ * Manages the objs in a slab.  Placed either at the end of mem allocated
+ * for the slab, or from an internal obj cache (SLAB_CFLGS_OFF_SLAB).
+ * Slabs are chain into a partially ordered list.  The linking ptrs must
+ * be first in the struct!
+ * The size of the struct is important(ish);  it should align well on
+ * cache line(s)
+ */
+typedef struct kmem_slab_s {
+	struct kmem_slab_s *s_nextp;
+	struct kmem_slab_s *s_prevp;
+	void		   *s_mem;	/* addr of mem allocated for slab */
+	unsigned long	    s_jiffies;
+	kmem_bufctl_t	   *s_freep;	/* ptr to first inactive obj in slab */
+	unsigned long	    s_flags;
+	unsigned long	    s_magic;
+	unsigned long	    s_inuse;	/* num of objs active in slab */
+} kmem_slab_t;
+
+/* to test for end of slab chain */
+#define	kmem_slab_end(x)	((kmem_slab_t*)&((x)->c_firstp))
+
+/* s_magic */
+#define	SLAB_MAGIC_ALLOC	0xA5C32F2BUL
+#define	SLAB_MAGIC_UNALLOC	0xB2F23C5AUL
+
+/* s_flags */
+#define	SLAB_SFLGS_DMA		0x000001UL	/* slab's mem can do DMA */
+
+/* cache struct - manages a cache.
+ * c_lastp must appear immediately after c_firstp!
+ */
+struct kmem_cache_s {
+	kmem_slab_t		 *c_freep;	/* first slab w. free objs */
+	unsigned long	 	  c_flags;
+	unsigned long		  c_offset;
+	struct kmem_bufctl_s	**c_hashp;	/* ptr for off-slab bufctls */
+	kmem_slab_t		 *c_firstp;	/* first slab in chain */
+	kmem_slab_t		 *c_lastp;	/* last slab in chain */
+	unsigned long		  c_hashbits;
+	unsigned long		  c_num;	/* # of objs per slab */
+	unsigned long		  c_gfporder;	/* order of pgs per slab (2^n) */
+	unsigned long		  c_org_size;
+	unsigned long		  c_magic;
+	unsigned long		  c_inuse;	/* kept at zero */
+	void (*c_ctor)(void *, int, unsigned long); /* constructor func */
+	void (*c_dtor)(void *, int, unsigned long); /* de-constructor func */
+	unsigned long		  c_align;	/* alignment of objs */
+	unsigned long		  c_colour;	/* cache colouring range */
+	unsigned long		  c_colour_next;/* cache colouring */
+	const char		 *c_name;
+	struct kmem_cache_s	 *c_nextp;
+};
+
+/* magic # for c_magic - used to detect out-of-slabs in __kmem_cache_alloc() */
+#define	SLAB_C_MAGIC		0x4F17A36DUL
+
+/* internal c_flags */
+#define	SLAB_CFLGS_OFF_SLAB	0x010000UL	/* slab mgmt in own cache */
+#define	SLAB_CFLGS_BUFCTL	0x020000UL	/* bufctls in own cache */
+#define	SLAB_CFLGS_RELEASED	0x040000UL	/* cache is/being destroyed */
+
+#if	defined(SLAB_HIGH_PACK)
+#define	SLAB_CFLGS_PTR_IN_OBJ	0x080000UL	/* free ptr in obj */
+#endif
+
+#define	SLAB_OFF_SLAB(x)	((x) & SLAB_CFLGS_OFF_SLAB)
+#define	SLAB_BUFCTL(x)		((x) & SLAB_CFLGS_BUFCTL)
+#define	SLAB_RELEASED(x)	((x) & SLAB_CFLGS_RELEASED)
+#if	defined(SLAB_HIGH_PACK)
+#define	SLAB_PTR_IN_OBJ(x)	((x) & SLAB_CFLGS_PTR_IN_OBJ)
+#else
+#define	SLAB_PTR_IN_OBJ(x)	(0)
+#endif
+
+/* maximum size of an obj (in 2^order pages) */
+#define	SLAB_OBJ_MAX_ORDER	5	/* 32 pages */
+
+/* maximum num of pages for a slab (avoids trying to ask for too may contigious pages) */
+#define	SLAB_MAX_GFP_ORDER	5	/* 32 pages */
+
+/* the 'prefered' minimum num of objs per slab - maybe less for large objs */
+#define	SLAB_MIN_OBJS_PER_SLAB	4
+
+/* if the num of objs per slab is <= SLAB_MIN_OBJS_PER_SLAB,
+ * then the page order must be less than this before trying the next order
+ */
+#define	SLAB_BREAK_GFP_ORDER	2
+
+/* size of hash tables for caches which use off-slab bufctls (SLAB_CFLGS_BUFCTL) */
+#define	KMEM_HASH_SIZE	128
+
+/* size description struct for general-caches */
+typedef struct cache_sizes {
+	unsigned long	 cs_size;
+	kmem_cache_t	*cs_cachep;
+} cache_sizes_t;
+
+static cache_sizes_t cache_sizes[] = {
+#if	PAGE_SIZE == 4096
+	{  32,		NULL},
+#endif
+	{  64,		NULL},
+	{ 128,		NULL},
+	{ 256,		NULL},
+	{ 512,		NULL},
+	{1024,		NULL},
+	{2048,		NULL},
+	{4096,		NULL},
+	{8192,		NULL},
+#if	PAGE_SIZE == 8192
+	{16384,		NULL},
+#endif
+	{0,		NULL}
+};
+
+/* Names for the general-caches.
+ * Not placed into the sizes struct for a good reason; the
+ * string ptr is not needed while searching in kmem_alloc()/
+ * kmem_free(), and would 'get-in-the-way' - think about it.
+ */
+static char *cache_sizes_name[] = {
+#if	PAGE_SIZE == 4096
+	"cache-32",
+#endif
+	"cache-64",
+	"cache-128",
+	"cache-256",
+	"cache-512",
+	"cache-1024",
+	"cache-2048",
+	"cache-4096",
+#if	PAGE_SIZE == 4096
+	"cache-8192"
+#elif	PAGE_SIZE == 8192
+	"cache-8192",
+	"cache-16384"
+#else
+#error	Your page size is not supported for the general-caches - please fix
+#endif
+};
+
+static void kmem_hash_ctor(void *ptr, int , unsigned long);	/* fwd ref */
+extern kmem_cache_t	cache_cache;				/* fwd ref */
+
+/* internal cache of hash objs, only used when bufctls are off-slab */
+static	kmem_cache_t	cache_hash = {
+/* freep, flags */		kmem_slab_end(&cache_hash), 0,
+/* offset, hashp */		sizeof(kmem_bufctl_t*)*KMEM_HASH_SIZE, NULL,
+/* firstp, lastp */		kmem_slab_end(&cache_hash), kmem_slab_end(&cache_hash),
+/* hashbits, num, gfporder */	0, 0, 0,
+/* org_size, magic */		sizeof(kmem_bufctl_t*)*KMEM_HASH_SIZE, SLAB_C_MAGIC,
+/* inuse, ctor, dtor, align */	0, kmem_hash_ctor, NULL, L1_CACHE_BYTES,
+/* colour, colour_next */	0, 0,
+/* name, nextp */		"hash_cache", &cache_cache
+};
+
+/* internal cache of freelist mgmnt objs, only use when bufctls are off-slab */
+static	kmem_cache_t	cache_bufctl = {
+/* freep, flags */		kmem_slab_end(&cache_bufctl), 0,
+/* offset, hashp */		sizeof(kmem_bufctl_t), NULL,
+/* firstp, lastp */		kmem_slab_end(&cache_bufctl), kmem_slab_end(&cache_bufctl),
+/* hashbits, num, gfporder */	0, 0, 0,
+/* org_size, magic */		sizeof(kmem_bufctl_t), SLAB_C_MAGIC,
+/* inuse, ctor, dtor, align */	0, NULL, NULL, BYTES_PER_WORD*2,
+/* colour, colour_next */	0, 0,
+/* name, nextp */		"bufctl_cache", &cache_hash
+};
+
+/* internal cache of slab mngmnt objs, only used when slab mgmt is off-slab */
+static	kmem_cache_t	cache_slab = {
+/* freep, flags */		kmem_slab_end(&cache_slab), 0,
+/* offset, hashp */		sizeof(kmem_slab_t), NULL,
+/* firstp, lastp */		kmem_slab_end(&cache_slab), kmem_slab_end(&cache_slab),
+/* hashbits, num, gfporder */	0, 0, 0,
+/* org_size, magic */		sizeof(kmem_slab_t), SLAB_C_MAGIC,
+/* inuse, ctor, dtor, align */	0, NULL, NULL, L1_CACHE_BYTES,
+/* colour, colour_next */	0, 0,
+/* name, nextp */		"slab_cache", &cache_bufctl
+};
+
+/* internal cache of cache description objs */
+static	kmem_cache_t	cache_cache = {
+/* freep, flags */		kmem_slab_end(&cache_cache), 0,
+/* offset, hashp */		sizeof(kmem_cache_t), NULL,
+/* firstp, lastp */		kmem_slab_end(&cache_cache), kmem_slab_end(&cache_cache),
+/* hashbits, num, gfporder */	0, 0, 0,
+/* org_size, magic */		sizeof(kmem_cache_t), SLAB_C_MAGIC,
+/* inuse, ctor, dtor, align */	0, NULL, NULL, L1_CACHE_BYTES,
+/* colour, colour_next */	0, 0,
+/* name */			"kmem_cache",
+/* nextp */			&cache_slab
+};
+
+/* constructor for hash tables */
+static void kmem_hash_ctor(void *ptr, int size, unsigned long flags)
+{
+	memset(ptr, 0, sizeof(kmem_bufctl_t*)*KMEM_HASH_SIZE);
+}
+
+/* place maintainer for reaping */
+static	kmem_cache_t	*clock_searchp = &cache_cache;
+
+/* Init an internal cache */
+static void
+kmem_own_cache_init(kmem_cache_t *cachep)
+{
+	unsigned long	size, i;
+
+	if (cachep->c_inuse || cachep->c_magic != SLAB_C_MAGIC) {
+		panic("Bad init of internal cache %s", cachep->c_name);
+		/* NOTREACHED */
+	}
+	size = cachep->c_offset + kmem_bufctl_short_size;
+	i = size % cachep->c_align;
+	if (i)
+		size += (cachep->c_align-i);
+	cachep->c_offset = size-kmem_bufctl_short_size;
+	
+	i = ((PAGE_SIZE<<cachep->c_gfporder)-sizeof(kmem_slab_t));
+	cachep->c_num = i / size;	/* num of objs per slab */
+
+	/* cache colouring */
+	cachep->c_colour = 1 + (i-(cachep->c_num*size))/cachep->c_align;
+	cachep->c_colour_next = cachep->c_colour;
+}
+
+/* Initialisation - setup all internal caches */
+long
+kmem_cache_init(long start, long end)
+{
+	/* sanity */
+#define	kmem_cache_offset(x) ((unsigned long)&((kmem_cache_t *)0)->x)
+#define	kmem_slab_offset(x) ((unsigned long)&((kmem_slab_t *)0)->x)
+	if (((kmem_cache_offset(c_magic)-kmem_cache_offset(c_firstp)) != kmem_slab_offset(s_magic)) ||
+	    ((kmem_cache_offset(c_inuse)-kmem_cache_offset(c_firstp)) != kmem_slab_offset(s_inuse))) {
+		/* Offsets to the magic are incorrect, either the structures have
+		 * been incorrectly changed, or adjustments are needed for your
+		 * architecture.
+		 */
+		panic("kmem_cache_init(): Offsets are different - been messed with!\n");
+		/* NOTREACHED */
+	}
+#undef	kmem_cache_offset
+#undef	kmem_slab_offset
+
+	kmem_own_cache_init(&cache_cache);
+	kmem_own_cache_init(&cache_slab);
+	kmem_own_cache_init(&cache_bufctl);
+	kmem_own_cache_init(&cache_hash);
+	return start;
+}
+
+/* Initialisation - setup general caches */
+void
+kmem_cache_sizes_init(void)
+{
+	unsigned long	i;
+
+	i = sizeof(cache_sizes)/sizeof(cache_sizes[0])-1;
+	while (i--)
+		cache_sizes[i].cs_cachep = kmem_cache_create(cache_sizes_name[i],
+							     cache_sizes[i].cs_size,
+							     0, 0, NULL, NULL);
+}
+
+/* Interface to system's page allocator.
+ * dma pts to non-zero if all of the mem is suitable for DMA
+ */
+static inline void *
+kmem_getpages(const kmem_cache_t *cachep, unsigned long flags, unsigned int *dma)
+{
+	struct page *page;
+	void	*addr;
+
+	addr = (void*) __get_free_pages(flags & SLAB_LEVEL_MASK, \
+				cachep->c_gfporder, flags & SLAB_DMA); 
+	*dma = 1<<cachep->c_gfporder;
+	if (!(flags & SLAB_DMA) && addr) {
+		/* need to check if can dma */
+		page = mem_map + MAP_NR(addr);
+		while ((*dma)--) {
+			if (!PageDMA(page)) {
+				*dma = 0;
+				break;
+			}
+			page++;
+		}
+	}
+	return addr;
+}
+
+/* Interface to system's page release */
+static inline void
+kmem_freepages(kmem_cache_t *cachep, void *addr)
+{
+	free_pages((unsigned long)addr, cachep->c_gfporder); 
+}
+
+/* Hashing function - used for caches with off-slab bufctls */
+static inline int
+kmem_hash(const kmem_cache_t *cachep, const void *objp)
+{
+	return (((unsigned long)objp >> cachep->c_hashbits) & (KMEM_HASH_SIZE-1));
+}
+
+/* Link bufctl into a hash table - used for caches with off-slab bufctls 
+ * - called with ints disabled
+ */
+static inline void *
+kmem_add_to_hash(kmem_cache_t *cachep, kmem_bufctl_t *bufp)
+{
+	kmem_bufctl_t **bufpp = bufp->buf_hashp;
+
+	bufp->buf_hnextp = *bufpp;
+	return (*bufpp = bufp)->buf_objp;
+}
+
+/* Find bufcntl for given obj addr, and unlink.
+ * - called with ints disabled
+ */
+static inline kmem_bufctl_t *
+kmem_remove_from_hash(kmem_cache_t *cachep, const void *objp)
+{
+	kmem_bufctl_t	*bufp;
+	kmem_bufctl_t	**bufpp = &cachep->c_hashp[kmem_hash(cachep, objp)];
+
+	for (;*bufpp; bufpp = &(*bufpp)->buf_hnextp) {
+		if ((*bufpp)->buf_objp != objp)
+			continue;
+		bufp = *bufpp;
+		*bufpp = bufp->buf_hnextp;
+		return bufp;
+	}
+	return NULL;
+}
+
+/* Three slab chain funcs - all called with ints disabled */
+static inline void
+kmem_slab_unlink(kmem_slab_t *slabp)
+{
+	kmem_slab_t	*prevp = slabp->s_prevp;
+	kmem_slab_t	*nextp = slabp->s_nextp;
+
+	prevp->s_nextp = nextp;
+	nextp->s_prevp = prevp;
+}
+
+static inline void 
+kmem_slab_link_end(kmem_cache_t *cachep, kmem_slab_t *slabp)
+{
+	slabp->s_nextp = kmem_slab_end(cachep);
+	slabp->s_prevp = cachep->c_lastp;
+	kmem_slab_end(cachep)->s_prevp = slabp;
+	slabp->s_prevp->s_nextp = slabp;
+}
+
+static inline void
+kmem_slab_link_free(kmem_cache_t *cachep, kmem_slab_t *slabp)
+{
+	kmem_slab_t	*nextp = cachep->c_freep;
+
+	slabp->s_nextp = nextp;
+	cachep->c_freep = slabp;
+	slabp->s_prevp = nextp->s_prevp;
+	nextp->s_prevp = slabp;
+	slabp->s_prevp->s_nextp = slabp;
+}
+
+/* Cal the num objs, wastage, and bytes left over for a given slab size */
+static int
+kmem_cache_cal_waste(unsigned long gfporder, unsigned long size,
+		     unsigned long extra, unsigned long flags,
+		     unsigned long *left_over, unsigned long *num)
+{
+	unsigned long	wastage;
+
+	wastage = PAGE_SIZE << gfporder;
+	gfporder = 0;
+	if (!SLAB_OFF_SLAB(flags))
+		gfporder = sizeof(kmem_slab_t);
+	wastage -= gfporder;
+	*num = wastage / size;
+	wastage -= (*num * size);
+	*left_over = wastage;
+
+	wastage += (extra * *num);
+	wastage += gfporder;
+
+	return wastage;
+}
+
+/* Create a cache
+ * Returns a ptr to the cache on success, NULL on failure.
+ * Cannot be called within a int, but can be interrupted.
+ * NOTE: The 'name' is assumed to be memory that is _not_  going to disappear.
+ */
+kmem_cache_t *
+kmem_cache_create(const char *name, unsigned long size, unsigned long align,
+		  unsigned long flags, void (*ctor)(void*, int, unsigned long),
+		  void (*dtor)(void*, int, unsigned long))
+{
+	const char *func_nm="kmem_create: ";
+	kmem_cache_t	*searchp, *cachep;
+	unsigned long	words, i;
+	unsigned long	num, left_over;
+
+	/* sanity checks */
+#if	defined(SLAB_MGMT_CHECKS)
+	if (!name) {
+		printk(KERN_ERR "%sNULL ptr\n", func_nm);
+		return NULL;
+	}
+	if (intr_count) {
+		printk(KERN_ERR "%sCalled during int - %s\n", func_nm, name);
+		return NULL;
+	}
+
+	if (size < kmem_bufctl_very_short_size) {
+		printk(KERN_WARNING "%sSize too small %lu - %s\n", func_nm, size, name);
+		size = kmem_bufctl_very_short_size;
+	}
+
+	if (size > ((1<<SLAB_OBJ_MAX_ORDER)*PAGE_SIZE)) {
+		printk(KERN_ERR "%sSize too large %lu - %s\n", func_nm, size, name);
+		return NULL;
+	}
+#endif	/* SLAB_MGMT_CHECKS */
+
+	/* always checks flags, a caller might be expecting debug support which
+	 * isn't available
+	 */
+	if (flags & ~SLAB_C_MASK) {
+		/* Illegal flags */
+		printk(KERN_WARNING "%sIllgl flg %lX - %s\n", func_nm, flags, name);
+		flags &= SLAB_C_MASK;
+	}
+
+#if	defined(SLAB_MGMT_CHECKS)
+	if (align < 0 || align >= size) {
+		printk(KERN_WARNING "%sAlign weired %lu - %s\n", func_nm, align, name);
+		align = 0;
+	}
+
+	if (dtor && !ctor) {
+		/* Descon, but no con - doesn't make sense */
+		printk(KERN_ERR "%sDecon but no con - %s\n", func_nm, name);
+		return NULL;
+	}
+
+	if ((flags & SLAB_DEBUG_INITIAL) && !ctor) {
+		/* No constructor, but inital state check requested */
+		printk(KERN_WARNING "%sNo con, but init state check requested - %s\n",
+		       func_nm, name);
+		flags &= ~SLAB_DEBUG_INITIAL;
+	}
+#endif	/* SLAB_MGMT_CHECKS */
+
+	/* get cache's description obj */
+	cachep = (kmem_cache_t *) kmem_cache_alloc(&cache_cache, SLAB_KERNEL);
+	if (!cachep)
+		goto opps;
+
+	/* remember original size, so can be passed to a constructor or decon.
+	 * Allows the same con/decon to be used for caches of similar objs
+	 * that have a different size data buffer assoicated with them
+	 */
+	cachep->c_org_size = size;
+
+#if	defined(SLAB_DEBUG_SUPPORT)
+	if (flags & SLAB_RED_ZONE)
+		size += BYTES_PER_WORD;		/* word for redzone */
+#endif	/* SLAB_DEBUG_SUPPORT */
+
+	/* Make a guess if slab mngmnt obj and/or bufctls are 'on' or 'off' slab */
+	i = kmem_bufctl_short_size;
+	if (size < (PAGE_SIZE>>3)) {
+		/* Size is small(ish).  Use format where bufctl size per
+		 * obj is low, and slab mngmnt is on-slab
+		 */
+		if (!ctor && !dtor && !(flags & SLAB_RED_ZONE)) {
+			/* the objs in this cache have no state - can store
+			 * store freelist ptr within obj. (redzoning is a state)
+			 */
+#if	defined(SLAB_HIGH_PACK)
+			i=0;
+			flags |= SLAB_CFLGS_PTR_IN_OBJ;
+#else
+			i = kmem_bufctl_very_short_size;
+#endif
+		}
+	} else {
+		/* Size is large, assume best to place the slab mngmnt obj
+		 * off-slab (should allow better packing of objs)
+		 */
+		flags |= SLAB_CFLGS_OFF_SLAB;
+		if (!(size & ~PAGE_MASK) ||
+		    size == (PAGE_SIZE+PAGE_SIZE/2) ||
+		    size == (PAGE_SIZE/2) ||
+		    size == (PAGE_SIZE/4) ||
+		    size == (PAGE_SIZE/8)) {
+			/* to avoid waste the bufctls are off-slab */
+			flags |= SLAB_CFLGS_BUFCTL;
+			/* get hash table for cache */
+			cachep->c_hashp = kmem_cache_alloc(&cache_hash, SLAB_KERNEL);
+			if (cachep->c_hashp == NULL) {
+				kmem_cache_free(&cache_cache, cachep);
+				goto opps;
+			}
+			i = 0;
+			cachep->c_hashbits = PAGE_SHIFT;
+			if (size <= (PAGE_SIZE/2)) {
+				cachep->c_hashbits--;
+				if (size <= (PAGE_SIZE/4)) cachep->c_hashbits--;
+				if (size <= (PAGE_SIZE/8)) cachep->c_hashbits -= 2;
+			}
+		}  /* else slab mngmnt is off-slab, but freelist ptrs are on */
+	}
+	size += i;
+
+	/* Adjust the mem used for objs so they will align correctly.
+	 * Force objs to start on word boundaries, but caller may specify
+	 * h/w cache line boundaries.  This 'alignment' is slightly different
+	 * to the 'align' argument.  Objs may be requested to start on h/w
+	 * lines (as that is how the members of the obj have been organised),
+	 * but the 'align' may be quite high (say 64) as the first 64 bytes
+	 * are commonly accessed/modified within a loop (stops h/w line
+	 * thrashing).  The 'align' is the slab colouring.
+	 */
+	words = BYTES_PER_WORD;
+	if (flags & SLAB_HWCACHE_ALIGN)
+		words = L1_CACHE_BYTES;
+	words--;
+	size += words;
+	size = size & ~words;
+	/* alignment might not be a factor of the boundary alignment - fix-up */
+	align += words;
+	align = align & ~words;
+
+
+	/* Cal size (in pages) of slabs, and the num of objs per slab.
+	 * This could be made much more intelligent. */
+	cachep->c_gfporder=0;
+	do {
+		unsigned long wastage;
+		wastage = kmem_cache_cal_waste(cachep->c_gfporder, size, i,
+					       flags, &left_over, &num);
+		if (!num)
+			goto next;
+		if (SLAB_PTR_IN_OBJ(flags))
+			break;
+		if (cachep->c_gfporder == SLAB_MAX_GFP_ORDER)
+			break;
+		/* large num of objs is good, but v. large slabs are bad for the
+		 * VM sub-system
+		 */
+		if (num <= SLAB_MIN_OBJS_PER_SLAB) {
+			if (cachep->c_gfporder < SLAB_BREAK_GFP_ORDER)
+				goto next;
+		}
+		/* stop caches with small objs having a large num of pages */
+		if (left_over <= sizeof(kmem_slab_t))
+			break;
+		if ((wastage*8) <= (PAGE_SIZE<<cachep->c_gfporder))
+			break;	/* acceptable wastage */
+next:
+		cachep->c_gfporder++;
+	} while (1);
+	cachep->c_num = num;
+
+	/* try with requested alignment, but reduce it if that will
+	 * allow at least some alignment words
+	 */
+	words++;
+	if (left_over < align)
+		align = (left_over / words) * words;
+	else if (!align && words <= left_over) {
+		/* no alignment given, but space enough - give one */
+		align = words;
+		if (words == BYTES_PER_WORD) {
+			if (BYTES_PER_WORD*4 <= left_over)
+				align += align;
+			if (BYTES_PER_WORD*8 <= left_over)
+				align += align;
+		}
+	}
+	cachep->c_align = align;
+
+#if	0
+	printk("Size:%lu Orig:%lu Left:%lu Align %lu Pages:%d - %s\n",
+	       size, cachep->c_org_size, left_over, align, 1<<cachep->c_gfporder, name);
+	if (SLAB_OFF_SLAB(flags)) printk("OFF SLAB\n");
+	if (SLAB_BUFCTL(flags)) printk("BUFCTL PTRS\n");
+#endif
+
+	/* if the bufctl's are on-slab, c_offset does not inc the size of the bufctl */
+	if (!SLAB_BUFCTL(flags))
+		size -= kmem_bufctl_short_size;
+	cachep->c_freep = kmem_slab_end(cachep);
+	cachep->c_flags = flags;
+	cachep->c_offset = size;
+	cachep->c_firstp = kmem_slab_end(cachep);
+	cachep->c_lastp = kmem_slab_end(cachep);
+	cachep->c_ctor = ctor;
+	cachep->c_dtor = dtor;
+	cachep->c_magic = SLAB_C_MAGIC;
+	cachep->c_inuse = 0;		/* always zero */
+	cachep->c_name = name;		/* simply point to the name */
+
+	cachep->c_colour = 1;
+	if (align) 
+		cachep->c_colour += (left_over/align);
+	cachep->c_colour_next = cachep->c_colour;
+
+	/* warn on dup cache names */
+	searchp = &cache_cache;
+	do {
+		if (!strcmp(searchp->c_name, name)) {
+			printk(KERN_WARNING "%sDup name - %s\n", func_nm, name);
+			break;
+		}
+		searchp = searchp->c_nextp;
+	} while (searchp != &cache_cache);
+	cachep->c_nextp = cache_cache.c_nextp;
+	cache_cache.c_nextp = cachep;
+	return cachep;
+opps:
+	printk(KERN_WARNING "%sOut of mem creating cache %s\n", func_nm, name);
+	return NULL;
+}
+
+/* Destroy all the objs in a slab, and release the mem back to the system.
+ * Before calling the slab must have been unlinked
+ */
+static void
+kmem_slab_destroy(kmem_cache_t *cachep, kmem_slab_t *slabp, unsigned long flags)
+{
+	if (cachep->c_dtor || SLAB_BUFCTL(cachep->c_flags)) {
+		kmem_bufctl_t	*bufp = slabp->s_freep;
+
+		/* for each obj in slab... */
+		while (bufp) {
+			kmem_bufctl_t	*freep;
+			if (cachep->c_dtor) {
+				void	*objp = ((void*)bufp)-cachep->c_offset;
+				if (SLAB_BUFCTL(cachep->c_flags))
+					objp = bufp->buf_objp;
+				(cachep->c_dtor)(objp, cachep->c_org_size, flags);
+			}
+			freep = bufp;
+			bufp = bufp->buf_nextp;
+			if (SLAB_BUFCTL(cachep->c_flags))
+				kmem_cache_free(&cache_bufctl, freep);
+		}
+	}
+
+	slabp->s_magic = SLAB_MAGIC_UNALLOC;
+	kmem_freepages(cachep, slabp->s_mem);
+	if (SLAB_OFF_SLAB(cachep->c_flags))
+		kmem_cache_free(&cache_slab, slabp);
+}
+
+/* Destroy (remove) a cache.
+ * All objs in the cache should be inactive
+ */
+int
+kmem_cache_destroy(kmem_cache_t *cachep)
+{
+	kmem_cache_t	**searchp;
+	kmem_slab_t	*slabp;
+	unsigned long	save_flags;
+
+#if	defined(SLAB_MGMT_CHECKS)
+	if (!cachep) {
+		printk(KERN_ERR "kmem_dest: NULL ptr\n");
+		goto err_end;
+	}
+
+	if (intr_count) {
+		printk(KERN_ERR "kmem_dest: Called during int - %s\n", cachep->c_name);
+err_end:
+		return 1;
+	}
+#endif	/* SLAB_MGMT_CHECKS */
+
+	/* unlink the cache from the chain of active caches.
+	 * Note: the chain is never modified during an int
+	 */
+	searchp = &(cache_cache.c_nextp);
+	for (;*searchp != &cache_cache; searchp = &((*searchp)->c_nextp)) {
+		if (*searchp != cachep)
+			continue;
+		goto good_cache;
+	}
+	printk(KERN_ERR "kmem_dest: Invalid cache addr %p\n", cachep);
+	return 1;
+good_cache:
+	/* disable cache so attempts to allocated from an int can
+	 * be caught.
+	 */
+	save_flags(save_flags);
+	cli();
+	if (cachep->c_freep != kmem_slab_end(cachep)) {
+		restore_flags(save_flags);
+		printk(KERN_ERR "kmem_dest: active cache - %s\n", cachep->c_name);
+		return 2;
+	}
+	*searchp = cachep->c_nextp;	/* remove from cache chain */
+	cachep->c_flags |= SLAB_CFLGS_RELEASED;
+	cachep->c_freep = kmem_slab_end(cachep);
+	if (cachep == clock_searchp)
+		clock_searchp = cachep->c_nextp;
+	restore_flags(save_flags);
+
+	while ((slabp = cachep->c_firstp) != kmem_slab_end(cachep)) {
+		kmem_slab_unlink(slabp);
+		kmem_slab_destroy(cachep, slabp, 0);
+	}
+
+	if (SLAB_BUFCTL(cachep->c_flags))
+		kmem_cache_free(&cache_hash, cachep->c_hashp);
+	kmem_cache_free(&cache_cache, cachep);
+	return 0;
+}
+
+/* Shrink a cache, ie. remove _all_ inactive slabs.
+ * Can be called when a user of a cache knows they are not going to be
+ * needing any new objs for a while.
+ * NOTE: This func is probably going to disappear - let me know if you
+ * are using it!
+ */
+int
+kmem_cache_shrink(kmem_cache_t *cachep, int wait)
+{
+	kmem_slab_t	*slabp;
+	unsigned long	dtor_flags;
+	unsigned long	save_flags, num_freed=0;
+
+#if	defined(SLAB_MGMT_CHECKS)
+	if (!cachep) {
+		printk(KERN_ERR "kmem_shrink: NULL ptr\n");
+		goto end;
+	}
+
+	if (intr_count) {
+		printk(KERN_ERR "kmem_shrink: Called during int - %s\n", cachep->c_name);
+		goto end;
+	}
+#endif	/* SLAB_MGMT_CHECKS */
+
+	dtor_flags = 0;
+	if (!wait)	/* not allowed to wait */
+		dtor_flags = SLAB_DTOR_ATOMIC;
+
+	save_flags(save_flags);
+	while (0) {
+		cli();
+		slabp = cachep->c_lastp;
+		if (slabp == kmem_slab_end(cachep) || slabp->s_inuse) {
+			restore_flags(save_flags);
+			goto end;
+		}
+		kmem_slab_unlink(slabp);
+		if (cachep->c_freep == slabp)
+			cachep->c_freep = kmem_slab_end(cachep);
+		restore_flags(save_flags);
+		num_freed++;
+		kmem_slab_destroy(cachep, slabp, dtor_flags);
+	}
+end:
+	return num_freed;
+}
+
+/* Search for a slab whose objs are suitable for DMA.
+ * Note: since testing the first free slab (in __kmem_cache_alloc()),
+ * ints must not have been enabled!
+ */
+static inline kmem_slab_t *
+kmem_cache_search_dma(kmem_cache_t *cachep)
+{
+	kmem_slab_t	*slabp = cachep->c_freep->s_nextp;
+
+	for (; slabp != kmem_slab_end(cachep); slabp = slabp->s_nextp) {
+		if (!(slabp->s_flags & SLAB_SFLGS_DMA))
+			continue;
+		kmem_slab_unlink(slabp);
+		kmem_slab_link_free(cachep, slabp);
+		return slabp;
+	}
+	return NULL;
+}
+
+/* get the mem for a slab mgmt obj */
+static inline kmem_slab_t *
+kmem_cache_slabmgmt(kmem_cache_t *cachep, void *objp, unsigned long local_flags, unsigned long offset)
+{
+	kmem_slab_t	*slabp;
+
+	if (SLAB_OFF_SLAB(cachep->c_flags)) {
+		/* slab mngmnt obj is off-slab */
+		if (!(slabp = kmem_cache_alloc(&cache_slab, local_flags)))
+			return NULL;
+	} else {
+		/* slab mngmnt at end of slab mem */
+		slabp = objp + (PAGE_SIZE << cachep->c_gfporder);
+		slabp--;
+		if (!SLAB_PTR_IN_OBJ(cachep->c_flags)) {
+			/* A bit of extra help for the L1 cache; try to position the slab
+			 * mgmnt struct at different offsets within the gap at the end
+			 * of a slab.  This helps avoid thrashing the h/w cache lines,
+			 * that map to the end of a page, too much...
+			 */
+			unsigned long gap = cachep->c_offset;
+			if (!SLAB_BUFCTL(cachep->c_flags))
+				gap += kmem_bufctl_short_size;
+			gap = (PAGE_SIZE << cachep->c_gfporder)-((gap*cachep->c_num)+offset+sizeof(*slabp));
+			gap /= (sizeof(*slabp)/2); 
+			gap *= (sizeof(*slabp)/2); 
+			slabp = (((void*)slabp)-gap);
+		}
+	}
+
+	slabp->s_flags = slabp->s_inuse = slabp->s_jiffies = 0;
+
+	return slabp;
+}
+
+static inline int
+kmem_cache_init_objs(kmem_cache_t *cachep, kmem_slab_t *slabp, void *objp,
+		     unsigned long local_flags, unsigned long ctor_flags)
+{
+	kmem_bufctl_t	**bufpp = &slabp->s_freep;
+	unsigned long	num = cachep->c_num;
+
+	do {
+		if (SLAB_BUFCTL(cachep->c_flags)) {
+			if (!(*bufpp = kmem_cache_alloc(&cache_bufctl, local_flags))) {
+				kmem_slab_destroy(cachep, slabp, 0);
+				return 1;
+			}
+			(*bufpp)->buf_objp = objp;
+			(*bufpp)->buf_hashp = &cachep->c_hashp[kmem_hash(cachep, objp)];
+		}
+
+		if (cachep->c_ctor)
+			cachep->c_ctor(objp, cachep->c_org_size, ctor_flags);
+
+#if	defined(SLAB_DEBUG_SUPPORT)
+		if (cachep->c_flags & SLAB_RED_ZONE)
+			*((unsigned long*)(objp+cachep->c_org_size)) = SLAB_RED_MAGIC1;
+#endif	/* SLAB_DEBUG_SUPPORT */
+
+		objp += cachep->c_offset;
+		if (!SLAB_BUFCTL(cachep->c_flags)) {
+			*bufpp = objp;
+			objp += kmem_bufctl_short_size;
+		}
+		if (!SLAB_PTR_IN_OBJ(cachep->c_flags))
+			(*bufpp)->buf_slabp = slabp;
+		bufpp = &(*bufpp)->buf_nextp;
+	} while (--num);
+	*bufpp = NULL;
+	return 0;
+}
+
+/* Grow (by 1) the number of slabs within a cache.
+ * This is called by kmem_cache_alloc() when there are no
+ * inactive objs left in a cache
+ */
+static void
+kmem_cache_grow(kmem_cache_t *cachep, unsigned long flags)
+{
+	kmem_slab_t	*slabp;
+	void		*objp;
+	unsigned int	offset, dma;
+	unsigned long	ctor_flags, local_flags, save_flags;
+
+	if (flags & SLAB_NO_GROW)
+		return; /* caller doesn't want us to grow */
+
+	save_flags(save_flags);
+	/* The test for missing atomic flag is performed here, rather than
+	 * the more obvious place, simply to reduce the critical path length
+	 * in kmem_cache_alloc().  If a caller is slightly mis-behaving,
+	 * will eventually be caught here (where it matters)
+	 */
+	if (intr_count && (flags & SLAB_LEVEL_MASK) != SLAB_ATOMIC) {
+		static int count = 0;
+		if (count < 8) {
+			printk(KERN_ERR "kmem_grow: Called nonatomically from "
+			       "int - %s\n", cachep->c_name);
+			count++;
+		}
+		flags &= ~SLAB_LEVEL_MASK;
+		flags |= SLAB_ATOMIC;
+	}
+	local_flags = (flags & SLAB_LEVEL_MASK);
+	ctor_flags = SLAB_CTOR_CONSTRUCTOR;
+	if ((flags & SLAB_LEVEL_MASK) == SLAB_ATOMIC) {
+		/* Not allowed to sleep.
+		 * Need to tell a constructor about this - it
+		 * might need to know....
+		 */
+		ctor_flags |= SLAB_CTOR_ATOMIC;
+	}
+
+	slabp = NULL;
+	/* get mem for the objs */
+	if (!(objp = kmem_getpages(cachep, flags, &dma)))
+		goto opps1;
+
+	/* get colour for the slab, and cal the next value */
+	cli();
+	if (!(offset = --(cachep->c_colour_next)))
+		cachep->c_colour_next = cachep->c_colour;
+	restore_flags(save_flags);
+	offset *= cachep->c_align;
+
+	/* get slab mgmt */
+	if (!(slabp = kmem_cache_slabmgmt(cachep, objp, local_flags, offset)))
+		goto opps2;
+	if (dma)
+		slabp->s_flags = SLAB_SFLGS_DMA;
+	
+	slabp->s_mem = objp;
+	objp += offset;		/* address of first object */
+
+	/* For on-slab bufctls, c_offset is the distance between the start of
+	 * an obj and its related bufctl.  For off-slab bufctls, c_offset is
+	 * the distance between objs in the slab.
+	 * Reason for bufctl at end of obj (when on slab), as opposed to the front;
+	 * if stored within the obj (has no state), and the obj is 'used' after being
+	 * freed then (normally) most activity occurs at the beginning of the obj.
+	 * By keeping the bufctl ptr away from the front, should reduce the chance of
+	 * corruption.  Also, allows easier alignment of objs onto cache lines when
+	 * bufctl is not stored with the objs.
+	 * Downsize; if, while an obj is active, a write is made past its end, then the
+	 * bufctl will be corrupted :(
+	 */
+	if (kmem_cache_init_objs(cachep, slabp, objp, local_flags, ctor_flags))
+		goto no_objs;
+
+	cli();
+	/* make slab active */
+	slabp->s_magic = SLAB_MAGIC_ALLOC;
+	kmem_slab_link_end(cachep, slabp);
+	if (cachep->c_freep == kmem_slab_end(cachep))
+		cachep->c_freep = slabp;
+	restore_flags(save_flags);
+	return;
+no_objs:
+	kmem_freepages(cachep, slabp->s_mem); 
+opps2:
+	kmem_freepages(cachep, objp); 
+opps1:
+	if (slabp && SLAB_OFF_SLAB(cachep->c_flags))
+		kmem_cache_free(&cache_slab, slabp);
+	/* printk("kmem_alloc: Out of mem - %s\n", cachep->c_name); */
+	return;
+}
+
+#if	defined(SLAB_DEBUG_SUPPORT)
+/* Perform extra freeing checks.
+ * Currently, this check is only for caches that use bufctl structures
+ * within the slab.  Those which use bufctl's from the internal cache
+ * have a reasonable check when the address is searched for.
+ */
+static void *
+kmem_extra_free_checks(const kmem_cache_t *cachep, kmem_bufctl_t *search_bufp,
+		       const kmem_bufctl_t *bufp, void * objp)
+{
+	if (SLAB_BUFCTL(cachep->c_flags))
+		goto end;
+
+	/* check slab's freelist to see if this obj is there */
+	for (; search_bufp; search_bufp = search_bufp->buf_nextp) {
+		if (search_bufp != bufp)
+			continue;
+		printk(KERN_ERR "kmem_free: Double free detected during checking "
+		       "%p - %s\n", objp, cachep->c_name);
+		return NULL;
+	}
+end:
+	return objp;
+}
+#endif	/* SLAB_DEBUG_SUPPORT */
+
+static inline void
+kmem_cache_full_free(kmem_cache_t *cachep, kmem_slab_t *slabp)
+{
+	if (!slabp->s_nextp->s_inuse)
+		return;		/* at correct position */
+	slabp->s_jiffies = jiffies;	/* set release time */
+	if (cachep->c_freep == slabp)
+		cachep->c_freep = slabp->s_nextp;
+	kmem_slab_unlink(slabp);
+	kmem_slab_link_end(cachep, slabp);
+
+	return;
+}
+
+static inline void
+kmem_cache_one_free(kmem_cache_t *cachep, kmem_slab_t *slabp)
+{
+	if (slabp->s_nextp->s_inuse != cachep->c_num) {
+		cachep->c_freep = slabp;
+		return;
+	}
+	kmem_slab_unlink(slabp);
+	kmem_slab_link_free(cachep, slabp);
+	return;
+}
+
+/* Returns a ptr to an obj in the given cache.
+ * The obj is in the initial state (if there is one)
+ */
+static inline void *
+__kmem_cache_alloc(kmem_cache_t *cachep, unsigned long flags)
+{
+	kmem_slab_t	*slabp;
+	kmem_bufctl_t	*bufp;
+	void		*objp;
+	unsigned long	save_flags;
+
+	/* sanity check */
+	if (!cachep)
+		goto nul_ptr;
+	save_flags(save_flags);
+	cli();
+	/* get slab alloc is to come from */
+	slabp = cachep->c_freep;
+
+	/* magic is a sanity check _and_ says if we need a new slab */
+	if (slabp->s_magic != SLAB_MAGIC_ALLOC)
+		goto alloc_new_slab;
+try_again:
+	/* DMA allocations are 'rare' - keep out of critical path */
+	if (flags & SLAB_DMA)
+		goto search_dma;
+try_again_dma:
+	slabp->s_inuse++;
+	bufp = slabp->s_freep;
+	slabp->s_freep = bufp->buf_nextp;
+	if (!SLAB_BUFCTL(cachep->c_flags)) {
+		/* Nasty - we want the 'if' to be taken in the common case */
+		if (slabp->s_freep) {
+short_finished:
+			objp = ((void*)bufp) - cachep->c_offset;
+			restore_flags(save_flags);
+#if	defined(SLAB_DEBUG_SUPPORT)
+			if (cachep->c_flags & SLAB_RED_ZONE)
+				goto red_zone;
+#endif	/* SLAB_DEBUG_SUPPORT */
+			return objp;
+		} else {
+			cachep->c_freep = slabp->s_nextp;
+			goto short_finished;
+		}
+	}
+
+	if (!slabp->s_freep)
+		cachep->c_freep = slabp->s_nextp;
+
+	/* link into hash chain */
+	objp = kmem_add_to_hash(cachep, bufp);
+	restore_flags(save_flags);
+#if	defined(SLAB_DEBUG_SUPPORT)
+	if (!(cachep->c_flags & SLAB_RED_ZONE))
+#endif	/* SLAB_DEBUG_SUPPORT */
+		return objp;
+
+#if	defined(SLAB_DEBUG_SUPPORT)
+red_zone:
+	/* set alloc red-zone, and check old one */
+	if (xchg((unsigned long *)(objp+cachep->c_org_size), SLAB_RED_MAGIC2) != SLAB_RED_MAGIC1)
+		printk(KERN_ERR "kmem_alloc: Bad redzone %p - %s\n",
+		       objp, cachep->c_name);
+	return objp;
+#endif	/* SLAB_DEBUG_SUPPORT */
+
+search_dma:
+	if (slabp->s_flags & SLAB_SFLGS_DMA)
+		goto try_again_dma;
+	/* need to search... */
+	if ((slabp = kmem_cache_search_dma(cachep)))
+		goto try_again_dma;
+alloc_new_slab:
+	/* Either out of slabs, or magic number corruption */
+	if (slabp != kmem_slab_end(cachep))
+		goto bad_slab;
+	/* need a new slab */
+	restore_flags(save_flags);
+	if (SLAB_RELEASED(cachep->c_flags)) {
+		printk(KERN_ERR "kmem_alloc: destroyed cache\n");
+		goto end;
+	}
+
+	/* Be lazy and only check for valid flags
+	 * here (keeping it out of the critical path above)
+	 */
+	if (flags & ~(SLAB_DMA|SLAB_LEVEL_MASK|SLAB_NO_GROW)) {
+		printk(KERN_ERR "kmem_alloc: Illegal flgs %lX (correcting) - %s\n",
+		       flags, cachep->c_name);
+		flags &= (SLAB_DMA|SLAB_LEVEL_MASK|SLAB_NO_GROW);
+	}
+
+	kmem_cache_grow(cachep, flags);
+	cli();
+	if ((slabp=cachep->c_freep) != kmem_slab_end(cachep))
+		goto try_again;
+	restore_flags(save_flags);
+end:
+	return NULL;
+bad_slab:
+	/* v. serious error - maybe panic() here? */
+	printk(KERN_ERR "kmem_alloc: Bad slab magic (corruption) - %s\n",
+	       cachep->c_name);
+	goto end;
+nul_ptr:
+	printk(KERN_ERR "kmem_alloc: NULL ptr\n");
+	goto end;
+}
+
+/* Release an obj back to its cache.
+ * If the obj has a constructed state, it should be
+ * in this state _before_ it is released.
+ */
+static inline void
+__kmem_cache_free(kmem_cache_t *cachep, void *objp)
+{
+	kmem_slab_t	*slabp;
+	kmem_bufctl_t	*bufp;
+	unsigned long	save_flags;
+
+	/* basic sanity checks */
+	if (!cachep)
+		goto nul_cache;
+	if (!objp)
+		goto nul_obj;
+
+	save_flags(save_flags);
+#if	defined(SLAB_DEBUG_SUPPORT)
+	if (cachep->c_flags & SLAB_DEBUG_INITIAL)
+		goto init_state_check;
+finished_initial:
+#endif	/* SLAB_DEBUG_SUPPORT */
+
+	if (SLAB_BUFCTL(cachep->c_flags))
+		goto bufctl;
+
+	bufp = (kmem_bufctl_t *)(objp+cachep->c_offset);
+
+	/* get slab for the obj */
+	if (SLAB_PTR_IN_OBJ(cachep->c_flags)) {
+		/* if SLAB_HIGH_PACK is undef, the below is optimised away */		
+		slabp = (kmem_slab_t *)((((unsigned long)objp)&PAGE_MASK)+PAGE_SIZE);
+		slabp--;
+	} else
+		slabp = (kmem_slab_t *) bufp->buf_slabp;
+
+	if (slabp->s_magic != SLAB_MAGIC_ALLOC)		/* sanity check */
+		goto bad_obj;
+	cli();
+
+#if	defined(SLAB_DEBUG_SUPPORT)
+	if (cachep->c_flags & (SLAB_DEBUG_FREE|SLAB_RED_ZONE))
+		goto extra_checks;
+#endif	/* SLAB_DEBUG_SUPPORT */
+
+passed_extra:
+	if (!slabp->s_inuse)			/* sanity check */
+		goto too_many;
+	bufp->buf_nextp = slabp->s_freep;
+	slabp->s_freep = bufp;
+	if (--(slabp->s_inuse)) {
+		if (bufp->buf_nextp) {
+			restore_flags(save_flags);
+			return;
+		}
+		kmem_cache_one_free(cachep, slabp);
+		restore_flags(save_flags);
+		return;
+	}
+	kmem_cache_full_free(cachep, slabp);
+	restore_flags(save_flags);
+	return;
+bufctl:
+	/* Off-slab bufctls.  Need to search hash for bufctl, and hence the slab.
+	 * No 'extra' checks are performed for objs stored this way, finding
+	 * the obj a check enough
+	 */
+	cli();
+	if ((bufp = kmem_remove_from_hash(cachep, objp))) {
+		slabp = (kmem_slab_t *) bufp->buf_slabp;
+#if	defined(SLAB_DEBUG_SUPPORT)
+		if (cachep->c_flags & SLAB_RED_ZONE)
+			goto red_zone;
+#endif	/* SLAB_DEBUG_SUPPORT */
+		goto passed_extra;
+	}
+	restore_flags(save_flags);
+	printk(KERN_ERR "kmem_free: Either bad obj addr or double free: %p - %s\n",
+	       objp, cachep->c_name);
+	return;
+#if	defined(SLAB_DEBUG_SUPPORT)
+red_zone:
+	if (xchg((unsigned long *)(objp+cachep->c_org_size), SLAB_RED_MAGIC1) != SLAB_RED_MAGIC2) {
+		/* Either write past end of the object, or a double free */
+		printk(KERN_ERR "kmem_free: Bad redzone %p - %s\n",
+		       objp, cachep->c_name);
+	}
+	goto passed_extra;
+init_state_check:
+	/* Need to call the slab's constructor so that
+	 * the caller can perform a verify of its state (debugging)
+	 */
+	cachep->c_ctor(objp, cachep->c_org_size, SLAB_CTOR_CONSTRUCTOR|SLAB_CTOR_VERIFY);
+	goto finished_initial;
+extra_checks:
+	if ((cachep->c_flags & SLAB_DEBUG_FREE) &&
+	    (objp != kmem_extra_free_checks(cachep, slabp->s_freep, bufp, objp))) {
+		restore_flags(save_flags);
+		return;
+	}
+	if (cachep->c_flags & SLAB_RED_ZONE)
+		goto red_zone;
+	goto passed_extra;
+#endif	/* SLAB_DEBUG_SUPPORT */
+bad_obj:
+	/* The addr of the slab doesn't contain the correct
+	 * magic num
+	 */
+	if (slabp->s_magic == SLAB_MAGIC_UNALLOC) {
+		/* magic num says this is an unalloc slab */
+		printk(KERN_ERR "kmem_free: obj %p from destroyed slab - %s\n",
+		       objp, cachep->c_name);
+		return;
+	}
+	printk(KERN_ERR "kmem_free: Bad obj %p - %s\n", objp, cachep->c_name);
+	return;
+too_many:
+	/* don't add to freelist */
+	restore_flags(save_flags);
+	printk(KERN_ERR "kmem_free: obj free for slab with no active objs - %s\n",
+	       cachep->c_name);
+	return;
+nul_obj:
+	printk(KERN_ERR "kmem_free: NULL obj - %s\n", cachep->c_name);
+	return;
+nul_cache:
+	printk(KERN_ERR "kmem_free: NULL cache ptr\n");
+	return;
+}
+
+void *
+kmem_cache_alloc(kmem_cache_t *cachep, unsigned long flags)
+{
+	return __kmem_cache_alloc(cachep, flags);
+}
+
+void
+kmem_cache_free(kmem_cache_t *cachep, void *objp)
+{
+	__kmem_cache_free(cachep, objp);
+}
+
+void *
+kmem_alloc(unsigned long size, unsigned long flags)
+{
+	cache_sizes_t	*cachep = cache_sizes;
+
+	for (; cachep->cs_size; cachep++) {
+		if (size > cachep->cs_size)
+			continue;
+		/* should the inline version be used here? */
+		return kmem_cache_alloc(cachep->cs_cachep, flags);
+	}
+	printk(KERN_ERR "kmem_alloc: Size (%lu) too large\n", size);
+	return NULL;
+}
+
+void
+kmem_free(void *objp, unsigned long size)
+{
+	cache_sizes_t	*cachep = cache_sizes;
+
+	for (; cachep->cs_size; cachep++) {
+		if (size > cachep->cs_size)
+			continue;
+		/* should the inline version be used here? */
+		kmem_cache_free(cachep->cs_cachep, objp);
+		return;
+	}
+	printk(KERN_ERR "kmem_free: Size (%lu) too large - strange\n", size);
+}
+
+
+
+/* Called from try_to_free_page().
+ * Ideal solution would have a weight for each cache, based on;
+ *	o num of fully free slabs
+ *	o if the objs have a constructor/deconstructor
+ *	o length of time slabs have been fully free (ie. ageing)
+ * This function _cannot_ be called within a int, but it
+ * can be interrupted.
+ */
+int
+kmem_cache_reap(int pri, int dma, int wait)
+{
+	unsigned long	 dtor_flags = 0;
+	unsigned long	 best_jiffie;
+	unsigned long	 now;
+	int		count = 8;
+	kmem_slab_t	*best_slabp = NULL;
+	kmem_cache_t	*best_cachep = NULL;
+	kmem_slab_t	*slabp;
+	kmem_cache_t	*searchp;
+	unsigned long	save_flags;
+
+	/* 'pri' maps to the number of caches to examine, not the number of slabs.
+	 * This avoids only checking the jiffies for slabs in one cache at the
+	 * expensive spending more cycles
+	 */
+	pri = (9 - pri);
+	if (!wait)	/* not allowed to wait */
+		dtor_flags = SLAB_DTOR_ATOMIC;
+	searchp = clock_searchp;
+	save_flags(save_flags);
+	now = jiffies;
+	best_jiffie = now - (2*HZ);	/* 2secs - avoid heavy thrashing */
+	while (pri--) {
+		kmem_slab_t	*local_slabp;
+		unsigned long	local_jiffie;
+		if (searchp == &cache_cache)
+			goto next;
+
+		/* sanity check for corruption */
+		if (searchp->c_inuse || searchp->c_magic != SLAB_C_MAGIC) {
+			printk(KERN_ERR "kmem_reap: Corrupted cache struct for %s\n",
+			       searchp->c_name);
+			goto next;
+		}
+
+		local_slabp = NULL;
+		local_jiffie = now - (2*HZ);
+		cli();
+		/* As the fully free slabs, within a cache, have no particular
+		 * order, we need to test them all.  Infact, we only check 'count'
+		 * slabs.
+		 */
+		slabp = searchp->c_lastp;
+		for (;count && slabp != kmem_slab_end(searchp) && !slabp->s_inuse; slabp = slabp->s_prevp, count--) {
+			if (slabp->s_jiffies >= local_jiffie)
+				continue;
+
+			/* weight caches with a con/decon */
+			if ((searchp->c_ctor || searchp->c_dtor) && slabp->s_jiffies >= (local_jiffie - (2*HZ)))
+				continue;
+
+			/* weight caches with high page orders.  Avoids stressing the
+			 * VM sub-system by reducing the frequency requests for a large
+			 * num of contigious pages
+			 */
+			if (searchp->c_gfporder > 1 && slabp->s_jiffies >= (local_jiffie - (4*HZ)))
+				continue;
+
+			local_jiffie = slabp->s_jiffies;
+			local_slabp = slabp;
+			if (!searchp->c_gfporder && (now-local_jiffie) >= (300*HZ)) {
+				/* an old, one page slab.  Make a quick get away... */
+				pri = 0;
+				break;
+			}
+		}
+		if (local_slabp) {
+			if (!count || local_jiffie < best_jiffie) {
+				best_slabp = local_slabp;
+				best_jiffie = local_jiffie;
+				best_cachep = searchp;
+				if (!count)
+					break;
+			}
+		}
+		restore_flags(save_flags);
+next:
+		searchp = searchp->c_nextp;
+		if (searchp == clock_searchp)
+			break;
+		count = 8;	/* # of slabs at which we force a reap */
+	}
+
+	/* only move along with we didn't find an over allocated cache */
+	if (count)
+		clock_searchp = clock_searchp->c_nextp;
+
+	if (!best_slabp)
+		return 0;
+
+	cli();
+	if (best_slabp->s_inuse) {
+		/* an object in our selected slab has been
+		 * allocated.  This souldn't happen v. often, so we
+		 * simply fail - which isn't ideal but will do.
+		 * NOTE: No test for the case where an obj has been
+		 * allocated from the slab, and then freed.  While
+		 * this would change our idea of the best slab to
+		 * reap, it's not worth the re-calculation effort.
+		 */
+		restore_flags(save_flags);
+		return 0;
+	}
+
+	if (best_cachep->c_freep == best_slabp)
+		best_cachep->c_freep = best_slabp->s_nextp;
+	kmem_slab_unlink(best_slabp);
+
+	restore_flags(save_flags);
+	kmem_slab_destroy(best_cachep, best_slabp, dtor_flags);
+
+	return 1;
+}
+
+/* /proc/slabinfo
+ *  cache-name num-active-objs total-objs num-active-slabs total-slabs num-pages-per-slab
+ */
+int
+get_slabinfo(char *buf)
+{
+	kmem_cache_t	*cachep;
+	kmem_slab_t	*slabp;
+	unsigned long	active_objs;
+	unsigned long	num_slabs, active_slabs;
+	unsigned long	save_flags;
+	int		len=0;
+
+	/* output format version, so at least we can change it without _too_
+	 * many complaints
+	 */
+	len = sprintf(buf, "slabinfo - version: 1.0\n");
+	save_flags(save_flags);
+	cachep = &cache_cache;
+	do {
+		active_slabs = num_slabs = active_objs = 0;
+		cli();
+		for (slabp = cachep->c_firstp;
+		     slabp != kmem_slab_end(cachep);
+		     slabp = slabp->s_nextp) {
+			num_slabs++;
+			active_objs += slabp->s_inuse;
+			if (slabp->s_inuse)
+				active_slabs++;
+		}
+		restore_flags(save_flags);
+		len += sprintf(buf+len, "%-20s%lu %lu %lu %lu %d\n", cachep->c_name,
+			       active_objs, cachep->c_num*num_slabs,
+			       active_slabs, num_slabs, 1<<cachep->c_gfporder);
+	} while ((cachep = cachep->c_nextp) != &cache_cache);
+	return len;
+}
diff -u --recursive --new-file v2.1.22/linux/mm/swapfile.c linux/mm/swapfile.c
--- v2.1.22/linux/mm/swapfile.c	Wed Dec 18 15:59:03 1996
+++ linux/mm/swapfile.c	Sun Jan 26 12:07:49 1997
@@ -6,6 +6,8 @@
  */
 
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 #include <linux/sched.h>
 #include <linux/head.h>
 #include <linux/kernel.h>
@@ -319,17 +321,18 @@
 
 asmlinkage int sys_swapoff(const char * specialfile)
 {
-	struct swap_info_struct * p;
+	struct swap_info_struct * p = NULL;
 	struct inode * inode;
 	struct file filp;
 	int i, type, prev;
-	int err;
+	int err = -EPERM;
 
+	lock_kernel();
 	if (!suser())
-		return -EPERM;
+		goto out;
 	err = namei(specialfile,&inode);
 	if (err)
-		return err;
+		goto out;
 	prev = -1;
 	for (type = swap_list.head; type >= 0; type = swap_info[type].next) {
 		p = swap_info + type;
@@ -345,9 +348,10 @@
 		}
 		prev = type;
 	}
+	err = -EINVAL;
 	if (type < 0){
 		iput(inode);
-		return -EINVAL;
+		goto out;
 	}
 	if (prev < 0) {
 		swap_list.head = p->next;
@@ -372,7 +376,7 @@
 		else
 			swap_info[prev].next = p - swap_info;
 		p->flags = SWP_WRITEOK;
-		return err;
+		goto out;
 	}
 	if(p->swap_device){
 		memset(&filp, 0, sizeof(filp));		
@@ -396,7 +400,10 @@
 	free_page((long) p->swap_lockmap);
 	p->swap_lockmap = NULL;
 	p->flags = 0;
-	return 0;
+	err = 0;
+out:
+	unlock_kernel();
+	return err;
 }
 
 /*
@@ -410,19 +417,20 @@
 	struct inode * swap_inode;
 	unsigned int type;
 	int i, j, prev;
-	int error;
+	int error = -EPERM;
 	struct file filp;
 	static int least_priority = 0;
 
-	memset(&filp, 0, sizeof(filp));
+	lock_kernel();
 	if (!suser())
-		return -EPERM;
+		goto out;
+	memset(&filp, 0, sizeof(filp));
 	p = swap_info;
 	for (type = 0 ; type < nr_swapfiles ; type++,p++)
 		if (!(p->flags & SWP_USED))
 			break;
 	if (type >= MAX_SWAPFILES)
-		return -EPERM;
+		goto out;
 	if (type >= nr_swapfiles)
 		nr_swapfiles = type+1;
 	p->flags = SWP_USED;
@@ -538,7 +546,8 @@
 	} else {
 		swap_info[prev].next = p - swap_info;
 	}
-	return 0;
+	error = 0;
+	goto out;
 bad_swap:
 	if(filp.f_op && filp.f_op->release)
 		filp.f_op->release(filp.f_inode,&filp);
@@ -551,6 +560,8 @@
 	p->swap_map = NULL;
 	p->swap_lockmap = NULL;
 	p->flags = 0;
+out:
+	unlock_kernel();
 	return error;
 }
 
diff -u --recursive --new-file v2.1.22/linux/mm/vmscan.c linux/mm/vmscan.c
--- v2.1.22/linux/mm/vmscan.c	Wed Dec 18 15:59:14 1996
+++ linux/mm/vmscan.c	Sun Jan 26 12:07:50 1997
@@ -5,7 +5,7 @@
  *
  *  Swap reorganised 29.12.95, Stephen Tweedie.
  *  kswapd added: 7.1.96  sct
- *  Version: $Id: vmscan.c,v 1.4.2.2 1996/01/20 18:22:47 linux Exp $
+ *  Version: $Id: vmscan.c,v 1.21 1997/01/06 06:54:03 davem Exp $
  */
 
 #include <linux/mm.h>
@@ -20,6 +20,7 @@
 #include <linux/fs.h>
 #include <linux/swapctl.h>
 #include <linux/smp_lock.h>
+#include <linux/slab.h>
 
 #include <asm/dma.h>
 #include <asm/system.h> /* for cli()/sti() */
@@ -347,9 +348,13 @@
 				return 1;
 			state = 1;
 		case 1:
-			if (shm_swap(i, dma))
+			if (kmem_cache_reap(i, dma, wait))
 				return 1;
 			state = 2;
+		case 2:
+			if (shm_swap(i, dma))
+				return 1;
+			state = 3;
 		default:
 			if (swap_out(i, dma, wait))
 				return 1;
@@ -368,7 +373,7 @@
 int kswapd(void *unused)
 {
 	int i;
-	char *revision="$Revision: 1.4.2.2 $", *s, *e;
+	char *revision="$Revision: 1.21 $", *s, *e;
 	
 	current->session = 1;
 	current->pgrp = 1;
@@ -380,11 +385,7 @@
 	 *	and other internals and thus be subject to the SMP locking
 	 *	rules. (On a uniprocessor box this does nothing).
 	 */
-	 
-#ifdef __SMP__
 	lock_kernel();
-	syscall_count++;
-#endif
 
 	/* Give kswapd a realtime priority. */
 	current->policy = SCHED_FIFO;
diff -u --recursive --new-file v2.1.22/linux/net/802/Makefile linux/net/802/Makefile
--- v2.1.22/linux/net/802/Makefile	Thu Jan 23 21:06:52 1997
+++ linux/net/802/Makefile	Sun Jan 26 12:07:50 1997
@@ -13,7 +13,7 @@
 ifeq ($(CONFIG_LLC),y)
 SUB_DIRS += transit
 O_OBJS += llc_sendpdu.o llc_utility.o cl2llc.o
-OX_OBJS += llc_macinit.o 
+OX_OBJS += llc_macinit.o
 
 endif
 
diff -u --recursive --new-file v2.1.22/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c
--- v2.1.22/linux/net/appletalk/ddp.c	Thu Jan 23 21:06:53 1997
+++ linux/net/appletalk/ddp.c	Sun Jan 26 12:07:50 1997
@@ -1778,7 +1778,7 @@
 	atalk_socketpair,
 	atalk_accept,
 	atalk_getname,
-	datagram_select,
+	datagram_poll,
 	atalk_ioctl,
 	atalk_listen,
 	atalk_shutdown,
diff -u --recursive --new-file v2.1.22/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c
--- v2.1.22/linux/net/ax25/af_ax25.c	Thu Jan 23 21:06:53 1997
+++ linux/net/ax25/af_ax25.c	Sun Jan 26 12:07:50 1997
@@ -2385,7 +2385,7 @@
 	ax25_socketpair,
 	ax25_accept,
 	ax25_getname,
-	datagram_select,
+	datagram_poll,
 	ax25_ioctl,
 	ax25_listen,
 	ax25_shutdown,
diff -u --recursive --new-file v2.1.22/linux/net/core/datagram.c linux/net/core/datagram.c
--- v2.1.22/linux/net/core/datagram.c	Thu Jan  2 15:55:26 1997
+++ linux/net/core/datagram.c	Sat Jan 25 23:46:14 1997
@@ -3,17 +3,17 @@
  *
  *	Generic datagram handling routines. These are generic for all protocols. Possibly a generic IP version on top
  *	of these would make sense. Not tonight however 8-).
- *	This is used because UDP, RAW, PACKET, DDP, IPX, AX.25 and NetROM layer all have identical select code and mostly
- *	identical recvmsg() code. So we share it here. The select was shared before but buried in udp.c so I moved it.
+ *	This is used because UDP, RAW, PACKET, DDP, IPX, AX.25 and NetROM layer all have identical poll code and mostly
+ *	identical recvmsg() code. So we share it here. The poll was shared before but buried in udp.c so I moved it.
  *
- *	Authors:	Alan Cox <alan@cymru.net>. (datagram_select() from old udp.c code)
+ *	Authors:	Alan Cox <alan@cymru.net>. (datagram_poll() from old udp.c code)
  *
  *	Fixes:
  *		Alan Cox	:	NULL return from skb_peek_copy() understood
  *		Alan Cox	:	Rewrote skb_read_datagram to avoid the skb_peek_copy stuff.
  *		Alan Cox	:	Added support for SOCK_SEQPACKET. IPX can no longer use the SO_TYPE hack but
  *					AX.25 now works right, and SPX is feasible.
- *		Alan Cox	:	Fixed write select of non IP protocol crash.
+ *		Alan Cox	:	Fixed write poll of non IP protocol crash.
  *		Florian  La Roche:	Changed for my new skbuff handling.
  *		Darryl Miles	:	Fixed non-blocking SOCK_SEQPACKET.
  *		Linus Torvalds	:	BSD semantic fixes.
@@ -34,6 +34,8 @@
 #include <linux/sched.h>
 #include <linux/inet.h>
 #include <linux/netdevice.h>
+#include <linux/poll.h>
+
 #include <net/ip.h>
 #include <net/protocol.h>
 #include <net/route.h>
@@ -188,57 +190,48 @@
 }
 
 /*
- *	Datagram select: Again totally generic. This also handles
+ *	Datagram poll: Again totally generic. This also handles
  *	sequenced packet sockets providing the socket receive queue
  *	is only ever holding data ready to receive.
  */
 
-int datagram_select(struct socket *sock, int sel_type, select_table *wait)
+unsigned int datagram_poll(struct socket *sock, poll_table *wait)
 {
 	struct sock *sk = sock->sk;
+	unsigned int mask;
+
+	poll_wait(sk->sleep, wait);
+	mask = 0;
 
+	/* exceptional events? */
 	if (sk->err)
-		return 1;
-	switch(sel_type)
-	{
-		case SEL_IN:
-			if (sk->shutdown & RCV_SHUTDOWN)
-				return 1;
-			if (connection_based(sk) && sk->state==TCP_CLOSE)
-			{
-				/* Connection closed: Wake up */
-				return 1;
-			}
-			if (!skb_queue_empty(&sk->receive_queue))
-			{	/* This appears to be consistent
-				   with other stacks */
-				return 1;
-			}
-			break;
-
-		case SEL_OUT:
-			if (sk->shutdown & SEND_SHUTDOWN)
-				return 1;
-			if (connection_based(sk) && sk->state==TCP_SYN_SENT)
-			{
-				/* Connection still in progress */
-				break;
-			}
-			if (sk->prot && sock_wspace(sk) >= MIN_WRITE_SPACE)
-			{
-				return 1;
-			}
-			if (sk->prot==NULL && sk->sndbuf-sk->wmem_alloc >= MIN_WRITE_SPACE)
-			{
-				return 1;
-			}
-			break;
+		mask |= POLLERR;
+	if (sk->shutdown & RCV_SHUTDOWN)
+		mask |= POLLHUP;
+
+	/* readable? */
+	if (!skb_queue_empty(&sk->receive_queue))
+		mask |= POLLIN | POLLRDNORM;
+
+	/* Connection-based need to check for termination and startup */
+	if (connection_based(sk)) {
+		if (sk->state==TCP_CLOSE)
+			mask |= POLLHUP;
+		/* connection hasn't started yet? */
+		if (sk->state == TCP_SYN_SENT)
+			return mask;
+	}
 
-		case SEL_EX:
-			break;
+	/* writable? */
+	if (!(sk->shutdown & SEND_SHUTDOWN)) {
+		if (sk->prot) {
+			if (sock_wspace(sk) >= MIN_WRITE_SPACE)
+				mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
+		} else {
+			if (sk->sndbuf-sk->wmem_alloc >= MIN_WRITE_SPACE)
+				mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
+		}
 	}
 
-	/* select failed.. */
-	select_wait(sk->sleep, wait);
-	return 0;
+	return mask;
 }
diff -u --recursive --new-file v2.1.22/linux/net/core/scm.c linux/net/core/scm.c
--- v2.1.22/linux/net/core/scm.c	Thu Jan 23 21:06:55 1997
+++ linux/net/core/scm.c	Sun Jan 26 13:40:46 1997
@@ -8,7 +8,6 @@
  *		2 of the License, or (at your option) any later version.
  */
 
-#include <linux/config.h>
 #include <linux/signal.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
diff -u --recursive --new-file v2.1.22/linux/net/core/sock.c linux/net/core/sock.c
--- v2.1.22/linux/net/core/sock.c	Thu Jan 23 21:06:55 1997
+++ linux/net/core/sock.c	Sun Jan 26 12:07:50 1997
@@ -95,6 +95,7 @@
 #include <linux/net.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
+#include <linux/slab.h>
 #include <linux/interrupt.h>
 
 #include <asm/uaccess.h>
@@ -367,6 +368,8 @@
   	return err;
 }
 
+static kmem_cache_t *sk_cachep;
+
 /*
  *	All socket objects are allocated here. This is for future
  *	usage.
@@ -374,16 +377,22 @@
  
 struct sock *sk_alloc(int priority)
 {
-	struct sock *sk=(struct sock *)kmalloc(sizeof(*sk), priority);
-	if(!sk)
-		return NULL;
-	memset(sk, 0, sizeof(*sk));
+	struct sock *sk = kmem_cache_alloc(sk_cachep, priority);
+
+	if(sk)
+		memset(sk, 0, sizeof(struct sock));
 	return sk;
 }
 
 void sk_free(struct sock *sk)
 {
-	kfree_s(sk,sizeof(*sk));
+	kmem_cache_free(sk_cachep, sk);
+}
+
+void sk_init(void)
+{
+	sk_cachep = kmem_cache_create("sock", sizeof(struct sock), 0,
+				      SLAB_HWCACHE_ALIGN, 0, 0);
 }
 
 /*
diff -u --recursive --new-file v2.1.22/linux/net/ethernet/eth.c linux/net/ethernet/eth.c
--- v2.1.22/linux/net/ethernet/eth.c	Thu Dec 12 19:37:25 1996
+++ linux/net/ethernet/eth.c	Sun Jan 26 12:07:50 1997
@@ -300,15 +300,14 @@
 	hh->hh_uptodate = 1;
 }
 
+#ifndef CONFIG_IP_ROUTER
+
 /*
  *	Copy from an ethernet device memory space to an sk_buff while checksumming if IP
  */
  
 void eth_copy_and_sum(struct sk_buff *dest, unsigned char *src, int length, int base)
 {
-#ifdef CONFIG_IP_ROUTER
-	memcpy(dest->data,src,length);
-#else
 	struct ethhdr *eth;
 	struct iphdr *iph;
 	int ip_length;
@@ -337,5 +336,6 @@
 
 	dest->csum=csum_partial_copy(src+sizeof(struct iphdr)+ETH_HLEN,dest->data+sizeof(struct iphdr)+ETH_HLEN,length,base);
 	dest->ip_summed=1;
-#endif	
 }
+
+#endif /* !(CONFIG_IP_ROUTER) */
diff -u --recursive --new-file v2.1.22/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
--- v2.1.22/linux/net/ipv4/af_inet.c	Thu Jan 23 21:06:57 1997
+++ linux/net/ipv4/af_inet.c	Sat Jan 25 23:46:14 1997
@@ -1188,13 +1188,13 @@
 }
 
 
-int inet_select(struct socket *sock, int sel_type, select_table *wait)
+unsigned int inet_poll(struct socket *sock, poll_table *wait)
 {
 	struct sock *sk = sock->sk;
 
-	if (sk->prot->select == NULL)
+	if (sk->prot->poll == NULL)
 		return(0);
-	return sk->prot->select(sock, sel_type, wait);
+	return sk->prot->poll(sock, wait);
 }
 
 /*
@@ -1589,7 +1589,7 @@
 	NULL,
 	inet_accept,
 	inet_getname, 
-	inet_select,
+	inet_poll,
 	inet_ioctl,
 	inet_listen,
 	inet_shutdown,
@@ -1610,7 +1610,7 @@
 	NULL,
 	NULL,
 	inet_getname, 
-	datagram_select,
+	datagram_poll,
 	inet_ioctl,
 	NULL,
 	inet_shutdown,
diff -u --recursive --new-file v2.1.22/linux/net/ipv4/arp.c linux/net/ipv4/arp.c
--- v2.1.22/linux/net/ipv4/arp.c	Thu Jan 23 21:06:57 1997
+++ linux/net/ipv4/arp.c	Sun Jan 26 12:07:50 1997
@@ -1375,7 +1375,7 @@
 	struct rtable *rt;
 	unsigned char *sha, *tha;
 	u32 sip, tip;
-	
+
 /*
  *	The hardware length of the packet should match the hardware length
  *	of the device.  Similarly, the hardware types should match.  The
@@ -1415,7 +1415,18 @@
 	}
 #else
 	if (arp->ar_hln != dev->addr_len    || 
-     		dev->type != ntohs(arp->ar_hrd) || 
+#if CONFIG_AP1000
+	    /*
+	     * ARP from cafe-f was found to use ARPHDR_IEEE802 instead of
+	     * the expected ARPHDR_ETHER.
+	     */
+	    (strcmp(dev->name,"fddi") == 0 && 
+	     arp->ar_hrd != ARPHRD_ETHER && arp->ar_hrd != ARPHRD_IEEE802) ||
+	    (strcmp(dev->name,"fddi") != 0 &&
+	     dev->type != ntohs(arp->ar_hrd)) ||
+#else
+	    dev->type != ntohs(arp->ar_hrd) || 
+#endif
 		dev->flags & IFF_NOARP          ||
 	        skb->pkt_type == PACKET_OTHERHOST ||
 		arp->ar_pln != 4) {
diff -u --recursive --new-file v2.1.22/linux/net/ipv4/ip_fw.c linux/net/ipv4/ip_fw.c
--- v2.1.22/linux/net/ipv4/ip_fw.c	Thu Dec 12 19:37:25 1996
+++ linux/net/ipv4/ip_fw.c	Thu Jan 23 20:31:43 1997
@@ -209,9 +209,9 @@
 int ip_fw_chk(struct iphdr *ip, struct device *rif, __u16 *redirport, struct ip_fw *chain, int policy, int mode)
 {
 	struct ip_fw *f;
-	struct tcphdr		*tcp=(struct tcphdr *)((unsigned long *)ip+ip->ihl);
-	struct udphdr		*udp=(struct udphdr *)((unsigned long *)ip+ip->ihl);
-	struct icmphdr		*icmp=(struct icmphdr *)((unsigned long *)ip+ip->ihl);
+	struct tcphdr		*tcp=(struct tcphdr *)((__u32 *)ip+ip->ihl);
+	struct udphdr		*udp=(struct udphdr *)((__u32 *)ip+ip->ihl);
+	struct icmphdr		*icmp=(struct icmphdr *)((__u32 *)ip+ip->ihl);
 	__u32			src, dst;
 	__u16			src_port=0xFFFF, dst_port=0xFFFF, icmp_type=0xFF;
 	unsigned short		f_prt=0, prt;
diff -u --recursive --new-file v2.1.22/linux/net/ipv4/ip_input.c linux/net/ipv4/ip_input.c
--- v2.1.22/linux/net/ipv4/ip_input.c	Thu Jan 23 21:06:57 1997
+++ linux/net/ipv4/ip_input.c	Sun Jan 26 12:07:50 1997
@@ -422,7 +422,7 @@
 			if (!ipv4_config.source_route) {
 				if (ipv4_config.log_martians)
 					printk(KERN_INFO "source route option %08lx -> %08lx\n",
-				       ntohl(iph->saddr), ntohl(iph->daddr));
+					       ntohl(iph->saddr), ntohl(iph->daddr));
 				goto drop;
 			}
 			if (RT_LOCALADDR(((struct rtable*)skb->dst)->rt_flags) &&
diff -u --recursive --new-file v2.1.22/linux/net/ipv4/ip_sockglue.c linux/net/ipv4/ip_sockglue.c
--- v2.1.22/linux/net/ipv4/ip_sockglue.c	Thu Jan 23 21:06:57 1997
+++ linux/net/ipv4/ip_sockglue.c	Sun Jan 26 12:07:50 1997
@@ -170,7 +170,7 @@
 int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen)
 {
 	int val,err;
-	unsigned char ucval;
+	unsigned char ucval = 0;
 #if defined(CONFIG_IP_FIREWALL) || defined(CONFIG_IP_ACCT)
 	struct ip_fw tmp_fw;
 #endif	
diff -u --recursive --new-file v2.1.22/linux/net/ipv4/packet.c linux/net/ipv4/packet.c
--- v2.1.22/linux/net/ipv4/packet.c	Thu Jan 23 21:06:57 1997
+++ linux/net/ipv4/packet.c	Sat Jan 25 23:46:14 1997
@@ -497,7 +497,7 @@
 	NULL,
 	NULL,
 	NULL,
-	datagram_select,
+	datagram_poll,
 	NULL,			/* No ioctl */
 	packet_init,
 	NULL,
diff -u --recursive --new-file v2.1.22/linux/net/ipv4/raw.c linux/net/ipv4/raw.c
--- v2.1.22/linux/net/ipv4/raw.c	Thu Jan 23 21:06:57 1997
+++ linux/net/ipv4/raw.c	Sat Jan 25 23:46:14 1997
@@ -412,7 +412,7 @@
 	NULL,
 	NULL,
 	NULL,
-	datagram_select,
+	datagram_poll,
 #ifdef CONFIG_IP_MROUTE	
 	ipmr_ioctl,
 #else
diff -u --recursive --new-file v2.1.22/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- v2.1.22/linux/net/ipv4/tcp.c	Thu Jan 23 21:06:58 1997
+++ linux/net/ipv4/tcp.c	Sat Jan 25 23:46:14 1997
@@ -30,7 +30,7 @@
  *					socket was looked up backwards. Nobody
  *					tested any icmp error code obviously.
  *		Alan Cox	:	tcp_err() now handled properly. It
- *					wakes people on errors. select
+ *					wakes people on errors. poll
  *					behaves and the icmp error race
  *					has gone by moving it into sock.c
  *		Alan Cox	:	tcp_send_reset() fixed to work for
@@ -102,12 +102,12 @@
  *		Alan Cox	:	BSD accept semantics.
  *		Alan Cox	:	Reset on closedown bug.
  *	Peter De Schrijver	:	ENOTCONN check missing in tcp_sendto().
- *		Michael Pall	:	Handle select() after URG properly in
+ *		Michael Pall	:	Handle poll() after URG properly in
  *					all cases.
  *		Michael Pall	:	Undo the last fix in tcp_read_urg()
  *					(multi URG PUSH broke rlogin).
  *		Michael Pall	:	Fix the multi URG PUSH problem in
- *					tcp_readable(), select() after URG
+ *					tcp_readable(), poll() after URG
  *					works now.
  *		Michael Pall	:	recv(...,MSG_OOB) never blocks in the
  *					BSD api.
@@ -128,7 +128,7 @@
  *		Alan Cox	:	Reset tracing code.
  *		Alan Cox	:	Spurious resets on shutdown.
  *		Alan Cox	:	Giant 15 minute/60 second timer error
- *		Alan Cox	:	Small whoops in selecting before an
+ *		Alan Cox	:	Small whoops in polling before an
  *					accept.
  *		Alan Cox	:	Kept the state trace facility since
  *					it's handy for debugging.
@@ -162,7 +162,7 @@
  *					generates them.
  *		Alan Cox	:	Cache last socket.
  *		Alan Cox	:	Per route irtt.
- *		Matt Day	:	Select() match BSD precisely on error
+ *		Matt Day	:	poll()->select() match BSD precisely on error
  *		Alan Cox	:	New buffers
  *		Marc Tamsky	:	Various sk->prot->retransmits and
  *					sk->retransmits misupdating fixed.
@@ -419,6 +419,7 @@
 
 #include <linux/types.h>
 #include <linux/fcntl.h>
+#include <linux/poll.h>
 
 #include <net/icmp.h>
 #include <net/tcp.h>
@@ -573,9 +574,9 @@
 		 * though there was normal data available. If we subtract
 		 * the urg data right here, we even get it to work for more
 		 * than one URG PUSH skb without normal data.
-		 * This means that select() finally works now with urg data
+		 * This means that poll() finally works now with urg data
 		 * in the queue.  Note that rlogin was never affected
-		 * because it doesn't use select(); it uses two processes
+		 * because it doesn't use poll(); it uses two processes
 		 * and a blocking read().  And the queue scan in tcp_read()
 		 * was correct.  Mike <pall@rz.uni-karlsruhe.de>
 		 */
@@ -597,81 +598,60 @@
 }
 
 /*
- * LISTEN is a special case for select..
+ * LISTEN is a special case for poll..
  */
-static int tcp_listen_select(struct sock *sk, int sel_type, select_table *wait)
+static unsigned int tcp_listen_poll(struct sock *sk, poll_table *wait)
 {
-	if (sel_type == SEL_IN) {
-		struct open_request *req;
+	struct open_request *req;
 
-		lock_sock(sk);
-		req = tcp_find_established(&sk->tp_pinfo.af_tcp);
-		release_sock(sk);
-		if (req)
-			return 1;
-		select_wait(sk->sleep,wait);
-		return 0;
-	}
+	lock_sock(sk);
+	req = tcp_find_established(&sk->tp_pinfo.af_tcp);
+	release_sock(sk);
+	if (req)
+		return POLLIN | POLLRDNORM;
 	return 0;
 }
 
 /*
  *	Wait for a TCP event.
  *
- *	Note that we don't need to lock the socket, as the upper select layers
+ *	Note that we don't need to lock the socket, as the upper poll layers
  *	take care of normal races (between the test and the event) and we don't
  *	go look at any of the socket buffers directly.
  */
-int tcp_select(struct socket *sock, int sel_type, select_table *wait)
+unsigned int tcp_poll(struct socket *sock, poll_table *wait)
 {
+	unsigned int mask;
 	struct sock *sk = sock->sk;
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 
+	poll_wait(sk->sleep, wait);
 	if (sk->state == TCP_LISTEN)
-		return tcp_listen_select(sk, sel_type, wait);
+		return tcp_listen_poll(sk, wait);
 
-	switch(sel_type) {
-	case SEL_IN:
-		if (sk->err)
-			return 1;
-		if (sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV)
-			break;
+	mask = 0;
+	if (sk->err)
+		mask = POLLERR;
+	/* connected ? */
+	if (sk->state != TCP_SYN_SENT && sk->state != TCP_SYN_RECV) {
 
 		if (sk->shutdown & RCV_SHUTDOWN)
-			return 1;
+			mask |= POLLHUP;
 			
-		if (tp->rcv_nxt == sk->copied_seq)
-			break;
+		if ((tp->rcv_nxt != sk->copied_seq) &&
+		    (sk->urg_seq != sk->copied_seq ||
+		     tp->rcv_nxt != sk->copied_seq+1 ||
+		     sk->urginline || !sk->urg_data))
+			mask |= POLLIN | POLLRDNORM;
+
+		if (!(sk->shutdown & SEND_SHUTDOWN) &&
+		     (sock_wspace(sk) >= sk->mtu+128+sk->prot->max_header))
+			mask |= POLLOUT | POLLWRNORM;
 
-		if (sk->urg_seq != sk->copied_seq ||
-		    tp->rcv_nxt != sk->copied_seq+1 ||
-		    sk->urginline || !sk->urg_data)
-			return 1;
-		break;
-
-	case SEL_OUT:
-		if (sk->err)
-			return 1;
-		if (sk->shutdown & SEND_SHUTDOWN)
-			return 0;
-		if (sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV)
-			break;
-		/*
-		 * This is now right thanks to a small fix
-		 * by Matt Dillon.
-		 */
-
-		if (sock_wspace(sk) < sk->mtu+128+sk->prot->max_header)
-			break;
-		return 1;
-
-	case SEL_EX:
 		if (sk->urg_data)
-			return 1;
-		break;
+			mask |= POLLPRI;
 	}
-	select_wait(sk->sleep, wait);
-	return 0;
+	return mask;
 }
 
 int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
diff -u --recursive --new-file v2.1.22/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c
--- v2.1.22/linux/net/ipv4/tcp_ipv4.c	Wed Dec 18 15:59:14 1996
+++ linux/net/ipv4/tcp_ipv4.c	Sat Jan 25 23:46:14 1997
@@ -1212,7 +1212,7 @@
 	NULL,
 	tcp_write_wakeup,
 	tcp_read_wakeup,
-	tcp_select,
+	tcp_poll,
 	tcp_ioctl,
 	tcp_v4_init_sock,
 	tcp_v4_destroy_sock,
diff -u --recursive --new-file v2.1.22/linux/net/ipv4/udp.c linux/net/ipv4/udp.c
--- v2.1.22/linux/net/ipv4/udp.c	Thu Jan 23 21:06:58 1997
+++ linux/net/ipv4/udp.c	Sat Jan 25 23:46:14 1997
@@ -851,7 +851,7 @@
 	NULL,
 	NULL,
 	NULL,
-	datagram_select,
+	datagram_poll,
 	udp_ioctl,
 	NULL,
 	NULL,
diff -u --recursive --new-file v2.1.22/linux/net/ipv6/af_inet6.c linux/net/ipv6/af_inet6.c
--- v2.1.22/linux/net/ipv6/af_inet6.c	Thu Jan 23 21:06:58 1997
+++ linux/net/ipv6/af_inet6.c	Sun Jan 26 12:07:50 1997
@@ -7,7 +7,7 @@
  *
  *	Adapted from linux/net/ipv4/af_inet.c
  *
- *	$Id: af_inet6.c,v 1.6 1996/12/12 19:22:09 davem Exp $
+ *	$Id: af_inet6.c,v 1.8 1997/01/26 07:14:56 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -727,7 +727,7 @@
 	inet6_socketpair,		/* a do nothing	*/
 	inet_accept,			/* ok		*/
 	inet6_getname, 
-	inet_select,			/* ok		*/
+	inet_poll,			/* ok		*/
 	inet6_ioctl,			/* must change  */
 	inet_listen,			/* ok		*/
 	inet_shutdown,			/* ok		*/
@@ -748,7 +748,7 @@
 	inet6_socketpair,		/* a do nothing	*/
 	inet_accept,			/* ok		*/
 	inet6_getname, 
-	datagram_select,		/* ok		*/
+	datagram_poll,			/* ok		*/
 	inet6_ioctl,			/* must change  */
 	inet_listen,			/* ok		*/
 	inet_shutdown,			/* ok		*/
diff -u --recursive --new-file v2.1.22/linux/net/ipv6/raw.c linux/net/ipv6/raw.c
--- v2.1.22/linux/net/ipv6/raw.c	Thu Jan 23 21:06:58 1997
+++ linux/net/ipv6/raw.c	Sun Jan 26 12:07:50 1997
@@ -7,7 +7,7 @@
  *
  *	Adapted from linux/net/ipv4/raw.c
  *
- *	$Id: raw.c,v 1.5 1996/10/29 22:45:53 roque Exp $
+ *	$Id: raw.c,v 1.7 1997/01/26 07:14:56 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -449,7 +449,7 @@
 	NULL,
 	NULL,
 	NULL,
-	datagram_select,
+	datagram_poll,
 	NULL,
 	rawv6_init_sk,
 	NULL,
diff -u --recursive --new-file v2.1.22/linux/net/ipv6/tcp_ipv6.c linux/net/ipv6/tcp_ipv6.c
--- v2.1.22/linux/net/ipv6/tcp_ipv6.c	Wed Dec 18 15:59:14 1996
+++ linux/net/ipv6/tcp_ipv6.c	Sun Jan 26 12:07:50 1997
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: tcp_ipv6.c,v 1.6 1996/12/12 19:22:18 davem Exp $
+ *	$Id: tcp_ipv6.c,v 1.7 1997/01/26 07:14:57 davem Exp $
  *
  *	Based on: 
  *	linux/net/ipv4/tcp.c
@@ -1236,7 +1236,7 @@
 	NULL,
 	tcp_write_wakeup,
 	tcp_read_wakeup,
-	tcp_select,
+	tcp_poll,
 	tcp_ioctl,
 	tcp_v6_init_sock,
 	tcp_v6_destroy_sock,
diff -u --recursive --new-file v2.1.22/linux/net/ipv6/udp.c linux/net/ipv6/udp.c
--- v2.1.22/linux/net/ipv6/udp.c	Thu Jan 23 21:06:58 1997
+++ linux/net/ipv6/udp.c	Sun Jan 26 12:07:51 1997
@@ -7,7 +7,7 @@
  *
  *	Based on linux/ipv4/udp.c
  *
- *	$Id: udp.c,v 1.6 1996/10/16 18:34:16 roque Exp $
+ *	$Id: udp.c,v 1.7 1997/01/26 07:14:58 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -602,7 +602,7 @@
 	NULL,
 	NULL,
 	NULL,
-	datagram_select,
+	datagram_poll,
 	udp_ioctl,
 	NULL,
 	NULL,
diff -u --recursive --new-file v2.1.22/linux/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c
--- v2.1.22/linux/net/ipx/af_ipx.c	Thu Jan 23 21:06:58 1997
+++ linux/net/ipx/af_ipx.c	Sun Jan 26 12:07:51 1997
@@ -2339,7 +2339,7 @@
 	ipx_socketpair,
 	ipx_accept,
 	ipx_getname,
-	datagram_select,
+	datagram_poll,
 	ipx_ioctl,
 	ipx_listen,
 	ipx_shutdown,
diff -u --recursive --new-file v2.1.22/linux/net/netbeui/netbeui.c linux/net/netbeui/netbeui.c
--- v2.1.22/linux/net/netbeui/netbeui.c	Thu Jan 23 21:06:58 1997
+++ linux/net/netbeui/netbeui.c	Sun Jan 26 12:07:51 1997
@@ -23,6 +23,7 @@
 #include <linux/if_arp.h>
 #include <linux/skbuff.h>
 #include <linux/termios.h>	/* For TIOCOUTQ/INQ */
+#include <linux/poll.h>
 #include <net/datalink.h>
 #include <net/p8022.h>
 #include <net/psnap.h>
@@ -711,11 +712,11 @@
 	return -EOPNOTSUPP;
 }
 
-static int netbeui_select(struct socket *sock , int sel_type, select_table *wait)
+static int netbeui_poll(struct socket *sock, poll_table *wait)
 {
 	netbeui_socket *sk=(netbeui_socket *)sock->data;
 
-	return datagram_select(sk,sel_type,wait);
+	return datagram_poll(sk,wait);
 }
 
 /*
@@ -810,7 +811,7 @@
 	netbeui_socketpair,
 	netbeui_accept,
 	netbeui_getname,
-	netbeui_select,
+	netbeui_poll,
 	netbeui_ioctl,
 	netbeui_listen,
 	netbeui_shutdown,
diff -u --recursive --new-file v2.1.22/linux/net/netlink.c linux/net/netlink.c
--- v2.1.22/linux/net/netlink.c	Thu Dec 12 19:37:31 1996
+++ linux/net/netlink.c	Sat Jan 25 23:46:14 1997
@@ -26,6 +26,7 @@
 
 #include <net/netlink.h>
 
+#include <asm/poll.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -63,19 +64,16 @@
 	return -EINVAL;
 }
 
-static int netlink_select(struct inode *inode, struct file *file, int sel_type, select_table * wait)
+static unsigned int netlink_poll(struct file *file, poll_table * wait)
 {
-	unsigned int minor = MINOR(inode->i_rdev);
-	switch (sel_type) {
-	case SEL_IN:
-		if (skb_peek(&skb_queue_rd[minor])!=NULL)
-			return 1;
-		select_wait(&read_space_wait[minor], wait);
-		break;
-	case SEL_OUT:
-		return 1;
-	}
-	return 0;
+	unsigned int mask;
+	unsigned int minor = MINOR(file->f_inode->i_rdev);
+
+	poll_wait(&read_space_wait[minor], wait);
+	mask = POLLOUT | POLLWRNORM;
+	if (skb_peek(&skb_queue_rd[minor]))
+		mask |= POLLIN | POLLRDNORM;
+	return mask;
 }
 
 /*
@@ -183,7 +181,7 @@
 	netlink_read,
 	netlink_write,
 	NULL,		/* netlink_readdir */
-	netlink_select,
+	netlink_poll,
 	netlink_ioctl,
 	NULL,		/* netlink_mmap */
 	netlink_open,
diff -u --recursive --new-file v2.1.22/linux/net/netrom/af_netrom.c linux/net/netrom/af_netrom.c
--- v2.1.22/linux/net/netrom/af_netrom.c	Thu Jan 23 21:06:58 1997
+++ linux/net/netrom/af_netrom.c	Sun Jan 26 12:07:52 1997
@@ -1365,7 +1365,7 @@
 	nr_socketpair,
 	nr_accept,
 	nr_getname,
-	datagram_select,
+	datagram_poll,
 	nr_ioctl,
 	nr_listen,
 	nr_shutdown,
diff -u --recursive --new-file v2.1.22/linux/net/netsyms.c linux/net/netsyms.c
--- v2.1.22/linux/net/netsyms.c	Thu Jan 23 21:06:58 1997
+++ linux/net/netsyms.c	Sun Jan 26 12:07:52 1997
@@ -14,6 +14,7 @@
 #include <linux/netdevice.h>
 #include <linux/trdevice.h>
 #include <linux/ioport.h>
+#include <net/neighbour.h>
 
 #ifdef CONFIG_INET
 #include <linux/ip.h>
@@ -28,6 +29,7 @@
 #include <net/scm.h>
 #include <net/inet_common.h>
 #include <linux/net_alias.h>
+#include <linux/mroute.h>
 
 extern struct net_proto_family inet_family_ops;
 
@@ -99,7 +101,22 @@
 EXPORT_SYMBOL(skb_copy_datagram);
 EXPORT_SYMBOL(skb_copy_datagram_iovec);
 EXPORT_SYMBOL(skb_realloc_headroom);
-EXPORT_SYMBOL(datagram_select);
+EXPORT_SYMBOL(datagram_poll);
+EXPORT_SYMBOL(sock_init_data);
+EXPORT_SYMBOL(put_cmsg);
+
+EXPORT_SYMBOL(neigh_table_init);
+/* Declared in <net/neighbour.h> but not defined?
+   EXPORT_SYMBOL(neigh_table_destroy);
+   EXPORT_SYMBOL(neigh_table_run_bh);
+*/
+EXPORT_SYMBOL(neigh_alloc);
+EXPORT_SYMBOL(neigh_table_ins);
+EXPORT_SYMBOL(neigh_queue_ins);
+EXPORT_SYMBOL(neigh_unlink);
+EXPORT_SYMBOL(neigh_lookup);
+EXPORT_SYMBOL(ntbl_walk_table);
+EXPORT_SYMBOL(neigh_tbl_run_bh);
 
 /* Needed by smbfs.o */
 EXPORT_SYMBOL(__scm_destroy);
@@ -144,12 +161,11 @@
 EXPORT_SYMBOL(inet_stream_connect);
 EXPORT_SYMBOL(inet_dgram_connect);
 EXPORT_SYMBOL(inet_accept);
-EXPORT_SYMBOL(inet_select);
+EXPORT_SYMBOL(inet_poll);
 EXPORT_SYMBOL(inet_listen);
 EXPORT_SYMBOL(inet_shutdown);
 EXPORT_SYMBOL(inet_setsockopt);
 EXPORT_SYMBOL(inet_getsockopt);
-EXPORT_SYMBOL(inet_fcntl);
 EXPORT_SYMBOL(inet_sendmsg);
 EXPORT_SYMBOL(inet_recvmsg);
 EXPORT_SYMBOL(tcp_sock_array);
@@ -174,7 +190,7 @@
 EXPORT_SYMBOL(tcp_accept);
 EXPORT_SYMBOL(tcp_write_wakeup);
 EXPORT_SYMBOL(tcp_read_wakeup);
-EXPORT_SYMBOL(tcp_select);
+EXPORT_SYMBOL(tcp_poll);
 EXPORT_SYMBOL(tcp_ioctl);
 EXPORT_SYMBOL(tcp_shutdown);
 EXPORT_SYMBOL(tcp_setsockopt);
@@ -228,11 +244,17 @@
 EXPORT_SYMBOL(unregister_trdev);
 EXPORT_SYMBOL(init_trdev);
 #endif
-                          
+                  
 #ifdef CONFIG_NET_ALIAS
 #include <linux/net_alias.h>
 #endif
 
+/* Used by at least ipip.c.  */
+EXPORT_SYMBOL(ipv4_config);
+#ifdef CONFIG_IP_MROUTE
+EXPORT_SYMBOL(ip_mr_find_tunnel);
+#endif
+
 #endif  /* CONFIG_INET */
 
 /* Device callback registration */
@@ -249,6 +271,7 @@
 EXPORT_SYMBOL(register_netdev);
 EXPORT_SYMBOL(unregister_netdev);
 EXPORT_SYMBOL(ether_setup);
+EXPORT_SYMBOL(dev_new_index);
 EXPORT_SYMBOL(eth_type_trans);
 EXPORT_SYMBOL(eth_copy_and_sum);
 EXPORT_SYMBOL(alloc_skb);
@@ -264,10 +287,14 @@
 EXPORT_SYMBOL(dev_get);
 EXPORT_SYMBOL(dev_ioctl);
 EXPORT_SYMBOL(dev_queue_xmit);
+#ifdef CONFIG_IP_ACCT
+EXPORT_SYMBOL(ip_acct_output);
+#endif
 EXPORT_SYMBOL(dev_base);
 EXPORT_SYMBOL(dev_close);
 EXPORT_SYMBOL(dev_mc_add);
 EXPORT_SYMBOL(arp_find);
+EXPORT_SYMBOL(arp_find_1);
 EXPORT_SYMBOL(n_tty_ioctl);
 EXPORT_SYMBOL(tty_register_ldisc);
 EXPORT_SYMBOL(kill_fasync);
diff -u --recursive --new-file v2.1.22/linux/net/rose/af_rose.c linux/net/rose/af_rose.c
--- v2.1.22/linux/net/rose/af_rose.c	Thu Jan 23 21:06:59 1997
+++ linux/net/rose/af_rose.c	Sun Jan 26 12:07:52 1997
@@ -1409,7 +1409,7 @@
 	rose_socketpair,
 	rose_accept,
 	rose_getname,
-	datagram_select,
+	datagram_poll,
 	rose_ioctl,
 	rose_listen,
 	rose_shutdown,
diff -u --recursive --new-file v2.1.22/linux/net/socket.c linux/net/socket.c
--- v2.1.22/linux/net/socket.c	Thu Jan 23 21:06:59 1997
+++ linux/net/socket.c	Sun Jan 26 12:07:52 1997
@@ -61,6 +61,8 @@
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
 #include <linux/stat.h>
@@ -101,7 +103,7 @@
 		       const char *buf, unsigned long size);
 
 static void sock_close(struct inode *inode, struct file *file);
-static int sock_select(struct inode *inode, struct file *file, int which, select_table *seltable);
+static unsigned int sock_poll(struct file *file, poll_table *wait);
 static int sock_ioctl(struct inode *inode, struct file *file,
 		      unsigned int cmd, unsigned long arg);
 static int sock_fasync(struct inode *inode, struct file *filp, int on);
@@ -117,7 +119,7 @@
 	sock_read,
 	sock_write,
 	NULL,			/* readdir */
-	sock_select,
+	sock_poll,
 	sock_ioctl,
 	NULL,			/* mmap */
 	NULL,			/* no special open code... */
@@ -444,19 +446,19 @@
 }
 
 
-static int sock_select(struct inode *inode, struct file *file, int sel_type, select_table * wait)
+static unsigned int sock_poll(struct file *file, poll_table * wait)
 {
 	struct socket *sock;
 
-	sock = socki_lookup(inode);
+	sock = socki_lookup(file->f_inode);
 
 	/*
-	 *	We can't return errors to select, so it's either yes or no. 
+	 *	We can't return errors to poll, so it's either yes or no. 
 	 */
 
-	if (sock->ops->select)
-		return sock->ops->select(sock, sel_type, wait);
-	return(0);
+	if (sock->ops->poll)
+		return sock->ops->poll(sock, wait);
+	return 0;
 }
 
 
@@ -556,16 +558,18 @@
 
 asmlinkage int sys_socket(int family, int type, int protocol)
 {
-	int i, fd;
+	int i, fd, err;
 	struct socket *sock;
 
-	/*
-	 *	Check protocol is in range
-	 */
-	 
-	if(family<0||family>=NPROTO)
-		return -EINVAL;
-		
+	lock_kernel();
+
+ 	/*
+ 	 *	Check protocol is in range
+ 	 */
+	err = -EINVAL;
+ 	if(family<0||family>=NPROTO)
+ 		goto out;
+ 		
 #if defined(CONFIG_KERNELD) && defined(CONFIG_NET)
 	/* Attempt to load a protocol module if the find failed. 
 	 * 
@@ -582,7 +586,7 @@
 #endif
 
 	if (net_families[family]==NULL)
-  		return -EINVAL;
+  		goto out;
 
 /*
  *	Check that this is a type that we know how to manipulate and
@@ -593,7 +597,7 @@
 	if ((type != SOCK_STREAM && type != SOCK_DGRAM &&
 	     type != SOCK_SEQPACKET && type != SOCK_RAW &&
 	     type != SOCK_PACKET) || protocol < 0)
-			return(-EINVAL);
+			goto out;
 
 /*
  *	Allocate the socket and allow the family to set things up. if
@@ -601,10 +605,11 @@
  *	default.
  */
 
+	err = -ENFILE;
 	if (!(sock = sock_alloc())) 
 	{
 		printk(KERN_WARNING "socket: no more sockets\n");
-		return(-ENFILE);	/* Not exactly a match, but its the
+		goto out;	/* Not exactly a match, but its the
 					   closest posix thing */
 	}
 
@@ -613,18 +618,21 @@
 	if ((i = net_families[family]->create(sock, protocol)) < 0) 
 	{
 		sock_release(sock);
-		return(i);
+		err = i;
 	}
-
-	if ((fd = get_fd(sock->inode)) < 0) 
+	else if ((fd = get_fd(sock->inode)) < 0) 
 	{
 		sock_release(sock);
-		return(-EINVAL);
+		err = -EINVAL;
 	}
-
-	sock->file = current->files->fd[fd];
-
-	return(fd);
+	else
+	{
+		sock->file = current->files->fd[fd];
+		err = fd;
+	}
+out:
+	unlock_kernel();
+	return err;
 }
 
 /*
@@ -637,50 +645,59 @@
 	struct socket *sock1, *sock2;
 	int err;
 
+	lock_kernel();
+
 	/*
 	 * Obtain the first socket and check if the underlying protocol
 	 * supports the socketpair call.
 	 */
 
-	if ((fd1 = sys_socket(family, type, protocol)) < 0) 
-		return(fd1);
+	if ((fd1 = sys_socket(family, type, protocol)) < 0) {
+		err = fd1;
+		goto out;
+	}
 
 	sock1 = sockfd_lookup(fd1, &err);
 	if (!sock1)
-		return err;
+		goto out;
+	err = -EOPNOTSUPP;
 	if (!sock1->ops->socketpair) 
 	{
 		sys_close(fd1);
-		return -EOPNOTSUPP;
+		goto out;
 	}
 
 	/*
 	 *	Now grab another socket and try to connect the two together. 
 	 */
-
+	err = -EINVAL;
 	if ((fd2 = sys_socket(family, type, protocol)) < 0) 
 	{
 		sys_close(fd1);
-		return(-EINVAL);
+		goto out;
 	}
 
 	sock2 = sockfd_lookup(fd2,&err);
 	if (!sock2)
-		return err;
+		goto out;
 	if ((i = sock1->ops->socketpair(sock1, sock2)) < 0) 
 	{
 		sys_close(fd1);
 		sys_close(fd2);
-		return(i);
+		err = i;
 	}
-
-	err = put_user(fd1, &usockvec[0]); 
-	if (!err) 
-		err = put_user(fd2, &usockvec[1]);
-	if (err) {
-		sys_close(fd1);
-		sys_close(fd2);
+	else
+	{
+		err = put_user(fd1, &usockvec[0]); 
+		if (!err) 
+			err = put_user(fd2, &usockvec[1]);
+		if (err) {
+			sys_close(fd1);
+			sys_close(fd2);
+		}
 	}
+out:
+	unlock_kernel();
 	return err;
 }
 
@@ -700,15 +717,20 @@
 	char address[MAX_SOCK_ADDR];
 	int err;
 
+	lock_kernel();
 	if (!(sock = sockfd_lookup(fd,&err))) 
-		return err;
+		goto out;
   
 	if((err=move_addr_to_kernel(umyaddr,addrlen,address))<0)
-	  	return err;
+	  	goto out;
   
 	if ((i = sock->ops->bind(sock, (struct sockaddr *)address, addrlen)) < 0) 
-		return(i);
-	return(0);
+		err = i;
+	else
+		err = 0;
+out:
+	unlock_kernel();
+	return err;
 }
 
 
@@ -723,11 +745,14 @@
 	struct socket *sock;
 	int err=-EOPNOTSUPP;
 	
+	lock_kernel();
 	if (!(sock = sockfd_lookup(fd, &err))) 
-		return err;
+		goto out;
 
 	if (sock->ops && sock->ops->listen)
 		err=sock->ops->listen(sock, backlog);
+out:
+	unlock_kernel();
 	return err;
 }
 
@@ -748,45 +773,48 @@
 {
 	struct inode *inode;
 	struct socket *sock, *newsock;
-	int i;
 	int err;
 	char address[MAX_SOCK_ADDR];
 	int len;
 
+	lock_kernel();
   	if (!(sock = sockfd_lookup(fd, &err)))
-		return err;
+		goto out;
+	err = -EOPNOTSUPP;
 	if (!sock->ops->accept)
-		return -EOPNOTSUPP;
+		goto out;
 
+	err = -ENOSR;
 	if (!(newsock = sock_alloc())) 
 	{
 		printk(KERN_WARNING "accept: no more sockets\n");
-		return(-ENOSR);	/* Was: EAGAIN, but we are out of system
+		goto out;	/* Was: EAGAIN, but we are out of system
 				   resources! */
 	}
 
 	inode = newsock->inode;
 	newsock->type = sock->type;
 
-	if ((i = sock->ops->dup(newsock, sock)) < 0) 
+	if ((err = sock->ops->dup(newsock, sock)) < 0) 
 	{
 		sock_release(newsock);
-		return(i);
+		goto out;
 	}
 
-	i = newsock->ops->accept(sock, newsock, current->files->fd[fd]->f_flags);
+	err = newsock->ops->accept(sock, newsock, current->files->fd[fd]->f_flags);
 
-	if (i < 0)
+	if (err < 0)
 	{
 		sock_release(newsock);
-		return(i);
+		goto out;
 	}
 	newsock = socki_lookup(inode);
 
 	if ((fd = get_fd(inode)) < 0) 
 	{
 		sock_release(newsock);
-		return(-EINVAL);
+		err = -EINVAL;
+		goto out;
 	}
 
 	newsock->file = current->files->fd[fd];
@@ -796,7 +824,10 @@
 		newsock->ops->getname(newsock, (struct sockaddr *)address, &len, 1);
 		move_addr_to_user(address,len, upeer_sockaddr, upeer_addrlen);
 	}
-	return fd;
+	err = fd;
+out:
+	unlock_kernel();
+	return err;
 }
 
 
@@ -815,21 +846,23 @@
 asmlinkage int sys_connect(int fd, struct sockaddr *uservaddr, int addrlen)
 {
 	struct socket *sock;
-	int i;
 	char address[MAX_SOCK_ADDR];
 	int err;
 
+	lock_kernel();
 	if (!(sock = sockfd_lookup(fd,&err)))
-		return err;
+		goto out;
 
 	if((err=move_addr_to_kernel(uservaddr,addrlen,address))<0)
-	  	return err;
+	  	goto out;
   
-	i = sock->ops->connect(sock, (struct sockaddr *)address, addrlen,
+	err = sock->ops->connect(sock, (struct sockaddr *)address, addrlen,
 			     current->files->fd[fd]->f_flags);
-	if (i < 0)
-		return(i);
-	return(0);
+	if (err >= 0)
+		err = 0;
+out:
+	unlock_kernel();
+	return err;
 }
 
 /*
@@ -844,15 +877,19 @@
 	int len;
 	int err;
 	
+	lock_kernel();
 	if (!(sock = sockfd_lookup(fd, &err)))
-		return err;
+		goto out;
 
 	err=sock->ops->getname(sock, (struct sockaddr *)address, &len, 0);
 	if(err)
-		return err;
+		goto out;
 	if((err=move_addr_to_user(address,len, usockaddr, usockaddr_len))<0)
-	  	return err;
-	return 0;
+	  	goto out;
+	err = 0;
+out:
+	unlock_kernel();
+	return err;
 }
 
 /*
@@ -867,15 +904,19 @@
 	int len;
 	int err;
 
+	lock_kernel();
 	if (!(sock = sockfd_lookup(fd, &err)))
-		return err;
+		goto out;
 
 	err=sock->ops->getname(sock, (struct sockaddr *)address, &len, 1);
 	if(err)
-	  	return err;
+	  	goto out;
 	if((err=move_addr_to_user(address,len, usockaddr, usockaddr_len))<0)
-	  	return err;
-	return 0;
+	  	goto out;
+	err = 0;
+out:
+	unlock_kernel();
+	return err;
 }
 
 /*
@@ -890,14 +931,16 @@
 	struct msghdr msg;
 	struct iovec iov;
 
+	lock_kernel();
 	if (!(sock = sockfd_lookup(fd, &err))) 
-		return err;
+		goto out;
 
+	err = -EINVAL;
 	if(len<0)
-		return -EINVAL;
+		goto out;
 	err=verify_area(VERIFY_READ, buff, len);
 	if(err)
-		return err;
+		goto out;
 		
 	iov.iov_base=buff;
 	iov.iov_len=len;
@@ -911,7 +954,10 @@
 		flags |= MSG_DONTWAIT;
 	msg.msg_flags=flags;
 
-	return sock_sendmsg(sock, &msg, len);
+	err = sock_sendmsg(sock, &msg, len);
+out:
+	unlock_kernel();
+	return err;
 }
 
 /*
@@ -929,13 +975,14 @@
 	struct msghdr msg;
 	struct iovec iov;
 	
+	lock_kernel();
 	if (!(sock = sockfd_lookup(fd,&err)))
-		return err;
+		goto out;
 
 	err=verify_area(VERIFY_READ,buff,len);
 	if(err)
-	  	return err;
-  	
+	  	goto out;
+
 	iov.iov_base=buff;
 	iov.iov_len=len;
 	msg.msg_name=NULL;
@@ -948,15 +995,18 @@
 	{
 		err=move_addr_to_kernel(addr,addr_len,address);
 		if (err < 0)
-			return err;
+			goto out;
 		msg.msg_name=address;
 	}
-	  	
+
 	if (current->files->fd[fd]->f_flags & O_NONBLOCK)
 		flags |= MSG_DONTWAIT;
 	msg.msg_flags=flags;
 
-	return sock_sendmsg(sock, &msg, len);
+	err = sock_sendmsg(sock, &msg, len);
+out:
+	unlock_kernel();
+	return err;
 }
 
 
@@ -971,15 +1021,17 @@
 	struct socket *sock;
 	int err;
 
+	lock_kernel();
 	if (!(sock = sockfd_lookup(fd, &err))) 
-		return err;
-		
+		goto out;
+
+	err = 0;
 	if(size==0)
-		return 0;
+		goto out;
 	err=verify_area(VERIFY_WRITE, ubuf, size);
 	if(err)
-		return err;
-		
+		goto out;
+
 	msg.msg_name=NULL;
 	msg.msg_iov=&iov;
 	msg.msg_iovlen=1;
@@ -988,8 +1040,12 @@
 	iov.iov_base=ubuf;
 	iov.iov_len=size;
 
-	return sock_recvmsg(sock, &msg, size,
-			    (current->files->fd[fd]->f_flags & O_NONBLOCK) ? flags | MSG_DONTWAIT : flags);
+	err = sock_recvmsg(sock, &msg, size,
+			   (current->files->fd[fd]->f_flags & O_NONBLOCK)
+			   ? flags | MSG_DONTWAIT : flags);
+out:
+	unlock_kernel();
+	return err;
 }
 
 /*
@@ -1007,15 +1063,17 @@
 	char address[MAX_SOCK_ADDR];
 	int err;
 
+	lock_kernel();
 	if (!(sock = sockfd_lookup(fd, &err)))
-	  	return err;
+	  	goto out;
+	err = 0;
 	if (size==0)
-		return 0;
+		goto out;
 
 	err=verify_area(VERIFY_WRITE,ubuf,size);
 	if(err)
-	  	return err;
-  
+	  	goto out;
+
   	msg.msg_control=NULL;
   	msg.msg_controllen=0;
   	msg.msg_iovlen=1;
@@ -1024,17 +1082,20 @@
   	iov.iov_base=ubuf;
   	msg.msg_name=address;
   	msg.msg_namelen=MAX_SOCK_ADDR;
-	err=sock_recvmsg(sock, &msg, size,
-			  (current->files->fd[fd]->f_flags & O_NONBLOCK) ? (flags | MSG_DONTWAIT) : flags);
+	err = sock_recvmsg(sock, &msg, size,
+			   (current->files->fd[fd]->f_flags & O_NONBLOCK)
+			   ? (flags | MSG_DONTWAIT) : flags);
 
 	if(err<0)
-	 	return err;
+	 	goto out;
 	size=err;
-	
-	if(addr!=NULL && (err=move_addr_to_user(address, msg.msg_namelen, addr, addr_len))<0)
-	  	return err;
-	
-	return size;
+	if(addr!=NULL &&
+	   (err=move_addr_to_user(address, msg.msg_namelen, addr, addr_len))<0)
+	  	goto out;
+	err = size;
+out:
+	unlock_kernel();
+	return err;
 }
 
 /*
@@ -1047,16 +1108,19 @@
 	int err;
 	struct socket *sock;
 	
+	lock_kernel();
 	if (!(sock = sockfd_lookup(fd, &err))) 
-		return err;
+		goto out;
 
 	if (level == SOL_SOCKET)
-		return sock_setsockopt(sock,level,optname,optval,optlen);
-
-	if (sock->ops->setsockopt)
-		return sock->ops->setsockopt(sock, level, optname, optval, optlen);
-
-	return -EOPNOTSUPP;
+		err = sock_setsockopt(sock,level,optname,optval,optlen);
+	else if (sock->ops->setsockopt)
+		err = sock->ops->setsockopt(sock, level, optname, optval, optlen);
+	else
+		err = -EOPNOTSUPP;
+out:
+	unlock_kernel();
+	return err;
 }
 
 /*
@@ -1069,16 +1133,19 @@
 	int err;
 	struct socket *sock;
 
+	lock_kernel();
 	if (!(sock = sockfd_lookup(fd, &err)))
-		return err;
+		goto out;
 	    
 	if (level == SOL_SOCKET)
-		return sock_getsockopt(sock,level,optname,optval,optlen);
-
-	if (sock->ops->getsockopt)
-		return sock->ops->getsockopt(sock, level, optname, optval, optlen);
-
-	return -EOPNOTSUPP;
+		err = sock_getsockopt(sock,level,optname,optval,optlen);
+	else if (sock->ops->getsockopt)
+		err = sock->ops->getsockopt(sock, level, optname, optval, optlen);
+	else
+		err = -EOPNOTSUPP;
+out:
+	unlock_kernel();
+	return err;
 }
 
 
@@ -1091,10 +1158,14 @@
 	int err;
 	struct socket *sock;
 
+	lock_kernel();
 	if (!(sock = sockfd_lookup(fd, &err))) 
-		return err;
+		goto out;
 
-	return sock->ops->shutdown(sock, how);
+	err = sock->ops->shutdown(sock, how);
+out:
+	unlock_kernel();
+	return err;
 }
 
 /*
@@ -1111,23 +1182,27 @@
 	int err;
 	int total_len;
 	
+	lock_kernel();
 	if (!(sock = sockfd_lookup(fd,&err)))
-		return err;
+		goto out;
 	
+	err = -EOPNOTSUPP;
 	if (sock->ops->sendmsg==NULL)
-		return -EOPNOTSUPP;
+		goto out;
 
+	err = -EFAULT;
 	if (copy_from_user(&msg_sys,msg,sizeof(struct msghdr)))
-		return -EFAULT; 
+		goto out;
 
 	/* do not move before msg_sys is valid */
+	err = -EINVAL;
 	if (msg_sys.msg_iovlen>UIO_MAXIOV)
-		return -EINVAL;
+		goto out;
 
 	/* This will also move the address data into kernel space */
 	err = verify_iovec(&msg_sys, iov, address, VERIFY_READ);
 	if (err < 0)
-		return err;
+		goto out;
 	total_len=err;
 
 	if (msg_sys.msg_controllen) {
@@ -1159,6 +1234,8 @@
 failed2:
 	if (msg_sys.msg_iov != iov)
 		kfree(msg_sys.msg_iov);
+out:
+	unlock_kernel();
 	return err;
 }
 
@@ -1184,14 +1261,17 @@
 	struct sockaddr *uaddr;
 	int *uaddr_len;
 	
+	lock_kernel();
 	if (!(sock = sockfd_lookup(fd, &err)))
-		return err;
+		goto out;
 
+	err = -EFAULT;
 	if (copy_from_user(&msg_sys,msg,sizeof(struct msghdr)))
-		return -EFAULT; 
+		goto out; 
 
+	err = -EINVAL;
 	if (msg_sys.msg_iovlen>UIO_MAXIOV)
-		return -EINVAL;
+		goto out;
 
 	/*
 	 *	Save the user-mode address (verify_iovec will change the
@@ -1202,7 +1282,7 @@
 	uaddr_len = &msg->msg_namelen;
 	err=verify_iovec(&msg_sys, iov, addr, VERIFY_WRITE);
 	if (err<0)
-		return err;
+		goto out;
 
 	total_len=err;
 
@@ -1214,20 +1294,26 @@
 	len=sock_recvmsg(sock, &msg_sys, total_len, flags);
 	if (msg_sys.msg_iov != iov)
 		kfree(msg_sys.msg_iov);
-	if (len<0)
-		return len;
+	if (len<0) {
+		err = len;
+		goto out;
+	}
 
 	if (uaddr != NULL)
 	{
 		err = move_addr_to_user(addr, msg_sys.msg_namelen, uaddr, uaddr_len);
 		if (err)
-			return err;
+			goto out;
 	}
+	err = -EFAULT;
 	if (put_user(msg_sys.msg_flags, &msg->msg_flags))
-		return -EFAULT;
+		goto out;
 	if (put_user((unsigned long)msg_sys.msg_control-cmsg_ptr, &msg->msg_controllen))
-		return -EFAULT;
-	return len;
+		goto out;
+	err = len;
+out:
+	unlock_kernel();
+	return err;
 }
 
 
@@ -1249,7 +1335,7 @@
 /*
  *	System call vectors. Since I (RIB) want to rewrite sockets as streams,
  *	we have this level of indirection. Not a lot of overhead, since more of
- *	the work is done via read/write/select directly.
+ *	the work is done via read/write/poll directly.
  *
  *	I'm now expanding this up to a higher level to separate the assorted
  *	kernel/user space manipulations and global assumptions from the protocol
@@ -1264,89 +1350,80 @@
 				 4,4,4,6,6,2,5,5,3,3};
 	unsigned long a[6];
 	unsigned long a0,a1;
+	int err = -EINVAL;
 				 
+	lock_kernel();
 	if(call<1||call>SYS_RECVMSG)
-		return -EINVAL;
-		
+		goto out;
+	err = -EFAULT;
 	if ((copy_from_user(a, args, nargs[call] * sizeof(unsigned long))))
-		return -EFAULT;
+		goto out;
 		
 	a0=a[0];
 	a1=a[1];
 	
-		
 	switch(call) 
 	{
 		case SYS_SOCKET:
-			return(sys_socket(a0,a1,a[2]));
+			err = sys_socket(a0,a1,a[2]);
+			break;
 		case SYS_BIND:
-			return(sys_bind(a0,(struct sockaddr *)a1,
-					a[2]));
+			err = sys_bind(a0,(struct sockaddr *)a1, a[2]);
+			break;
 		case SYS_CONNECT:
-			return(sys_connect(a0, (struct sockaddr *)a1,
-					   a[2]));
+			err = sys_connect(a0, (struct sockaddr *)a1, a[2]);
+			break;
 		case SYS_LISTEN:
-			return(sys_listen(a0,a1));
+			err = sys_listen(a0,a1);
+			break;
 		case SYS_ACCEPT:
-			return(sys_accept(a0,(struct sockaddr *)a1,
-					  (int *)a[2]));
+			err = sys_accept(a0,(struct sockaddr *)a1, (int *)a[2]);
+			break;
 		case SYS_GETSOCKNAME:
-			return(sys_getsockname(a0,(struct sockaddr *)a1,
-					       (int *)a[2]));
+			err = sys_getsockname(a0,(struct sockaddr *)a1, (int *)a[2]);
+			break;
 		case SYS_GETPEERNAME:
-			return(sys_getpeername(a0, (struct sockaddr *)a1,
-					       (int *)a[2]));
+			err = sys_getpeername(a0, (struct sockaddr *)a1, (int *)a[2]);
+			break;
 		case SYS_SOCKETPAIR:
-			return(sys_socketpair(a0,a1,
-					      a[2],
-					      (int *)a[3]));
+			err = sys_socketpair(a0,a1, a[2], (int *)a[3]);
+			break;
 		case SYS_SEND:
-			return(sys_send(a0,
-				(void *)a1,
-				a[2],
-				a[3]));
+			err = sys_send(a0, (void *)a1, a[2], a[3]);
+			break;
 		case SYS_SENDTO:
-			return(sys_sendto(a0,(void *)a1,
-				a[2],
-				a[3],
-				(struct sockaddr *)a[4],
-				a[5]));
+			err = sys_sendto(a0,(void *)a1, a[2], a[3],
+					 (struct sockaddr *)a[4], a[5]);
+			break;
 		case SYS_RECV:
-			return(sys_recv(a0,
-				(void *)a1,
-				a[2],
-				a[3]));
+			err = sys_recv(a0, (void *)a1, a[2], a[3]);
+			break;
 		case SYS_RECVFROM:
-			return(sys_recvfrom(a0,
-				(void *)a1,
-				a[2],
-				a[3],
-				(struct sockaddr *)a[4],
-				(int *)a[5]));
+			err = sys_recvfrom(a0, (void *)a1, a[2], a[3],
+					   (struct sockaddr *)a[4], (int *)a[5]);
+			break;
 		case SYS_SHUTDOWN:
-			return(sys_shutdown(a0,a1));
+			err = sys_shutdown(a0,a1);
+			break;
 		case SYS_SETSOCKOPT:
-			return(sys_setsockopt(a0,
-				a1,
-				a[2],
-				(char *)a[3],
-				a[4]));
+			err = sys_setsockopt(a0, a1, a[2], (char *)a[3], a[4]);
+			break;
 		case SYS_GETSOCKOPT:
-			return(sys_getsockopt(a0,
-				a1,
-				a[2],
-				(char *)a[3],
-				(int *)a[4]));
+			err = sys_getsockopt(a0, a1, a[2], (char *)a[3], (int *)a[4]);
+			break;
 		case SYS_SENDMSG:
-				return sys_sendmsg(a0,
-					(struct msghdr *) a1,
-					a[2]);
+			err = sys_sendmsg(a0, (struct msghdr *) a1, a[2]);
+			break;
 		case SYS_RECVMSG:
-				return sys_recvmsg(a0,
-					(struct msghdr *) a1,
-					a[2]);
+			err = sys_recvmsg(a0, (struct msghdr *) a1, a[2]);
+			break;
+		default:
+			err = -EINVAL;
+			break;
 	}
-	return -EINVAL; /* to keep gcc happy */
+out:
+	unlock_kernel();
+	return err;
 }
 
 
@@ -1389,6 +1466,7 @@
 	/* We're all done... */
 }
 
+extern void sk_init(void);
 
 void sock_init(void)
 {
@@ -1401,6 +1479,12 @@
 	 */
 	 
 	for (i = 0; i < NPROTO; i++) net_families[i] = NULL;
+
+	/*
+	 *	Initialize sock SLAB cache.
+	 */
+	 
+	sk_init();
 	
 	/*
 	 *	The netlink device handler may be needed early.
diff -u --recursive --new-file v2.1.22/linux/net/unix/af_unix.c linux/net/unix/af_unix.c
--- v2.1.22/linux/net/unix/af_unix.c	Thu Jan 23 21:06:59 1997
+++ linux/net/unix/af_unix.c	Sat Jan 25 23:46:14 1997
@@ -1429,7 +1429,7 @@
 	unix_socketpair,
 	unix_accept,
 	unix_getname,
-	datagram_select,
+	datagram_poll,
 	unix_ioctl,
 	unix_listen,
 	unix_shutdown,
@@ -1450,7 +1450,7 @@
 	unix_socketpair,
 	NULL,
 	unix_getname,
-	datagram_select,
+	datagram_poll,
 	unix_ioctl,
 	NULL,
 	unix_shutdown,
diff -u --recursive --new-file v2.1.22/linux/net/x25/af_x25.c linux/net/x25/af_x25.c
--- v2.1.22/linux/net/x25/af_x25.c	Thu Jan 23 21:06:59 1997
+++ linux/net/x25/af_x25.c	Sun Jan 26 12:07:52 1997
@@ -1304,7 +1304,7 @@
 	x25_socketpair,
 	x25_accept,
 	x25_getname,
-	datagram_select,
+	datagram_poll,
 	x25_ioctl,
 	x25_listen,
 	x25_shutdown,
diff -u --recursive --new-file v2.1.22/linux/scripts/mkdep.c linux/scripts/mkdep.c
--- v2.1.22/linux/scripts/mkdep.c	Wed Jan 15 19:45:47 1997
+++ linux/scripts/mkdep.c	Sun Jan 26 12:07:52 1997
@@ -126,6 +126,7 @@
 	CASE(' ',preproc);
 	CASE('\t',preproc);
 	CASE('i',i_preproc);
+	CASE('e',e_preproc);
 	GETNEXT
 
 skippreproc:
@@ -137,6 +138,15 @@
 skippreprocslash:
 	GETNEXT;
 	GETNEXT;
+	goto skippreproc;
+
+e_preproc:
+	GETNEXT
+	NOTCASE('l',skippreproc);
+	GETNEXT
+	NOTCASE('i',skippreproc);
+	GETNEXT
+	CASE('f',if_line);
 	goto skippreproc;
 
 i_preproc:
