## Automatically generated incremental diff
## From:   linux-2.4.20-pre4
## To:     linux-2.4.20-pre5
## Robot:  $Id: make-incremental-diff,v 1.11 2002/02/20 02:59:33 hpa Exp $

diff -urN linux-2.4.20-pre4/CREDITS linux-2.4.20-pre5/CREDITS
--- linux-2.4.20-pre4/CREDITS	Wed Aug 28 16:36:45 2002
+++ linux-2.4.20-pre5/CREDITS	Wed Aug 28 16:37:20 2002
@@ -2165,7 +2165,7 @@
 S: South Australia
 
 N. Wolfgang Muees
-E: wmues@nexgo.de
+E: wolfgang@iksw-muees.de
 D: Auerswald USB driver
 
 N: Ian A. Murdock
diff -urN linux-2.4.20-pre4/Documentation/Configure.help linux-2.4.20-pre5/Documentation/Configure.help
--- linux-2.4.20-pre4/Documentation/Configure.help	Wed Aug 28 16:36:45 2002
+++ linux-2.4.20-pre5/Documentation/Configure.help	Wed Aug 28 16:37:20 2002
@@ -3644,6 +3644,16 @@
 
   When in doubt, say N.
 
+ACPI PCI Hotplug driver
+CONFIG_HOTPLUG_PCI_ACPI
+  Say Y here if you have a system that supports PCI Hotplug using
+  ACPI.
+
+  This code 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 acpiphp.o. If you want to compile it
+  as a module, say M here and read <file:Documentation/modules.txt>.
+
 MCA support
 CONFIG_MCA
   MicroChannel Architecture is found in some IBM PS/2 machines and
@@ -10883,6 +10893,48 @@
   say M here and read <file:Documentation/modules.txt>.  This is
   recommended.  The module will be called dl2k.o.
 
+Intel(R) PRO/1000 Gigabit Ethernet support
+CONFIG_E1000
+  This driver supports Intel(R) PRO/1000 gigabit ethernet family of
+  adapters, which includes:
+
+     Controller  Adapter Name                         Board IDs
+     ----------  ------------                         ---------
+     82542       PRO/1000 Gigabit Server Adapter      700262-xxx,
+                                                      717037-xxx
+     82543       PRO/1000 F Server Adapter            738640-xxx,
+                                                      A38888-xxx
+     82543       PRO/1000 T Server Adapter            A19845-xxx,
+                                                      A33948-xxx
+     82544       PRO/1000 XT Server Adapter           A51580-xxx
+     82544       PRO/1000 XF Server Adapter           A50484-xxx
+     82544       PRO/1000 T Desktop Adapter           A62947-xxx
+     82540       PRO/1000 MT Desktop Adapter          A78408-xxx
+     82545       PRO/1000 MT Server Adapter           A92165-xxx
+     82546       PRO/1000 MT Dual Port Server Adapter A92111-xxx
+     82545       PRO/1000 MF Server Adapter           A91622-xxx
+     82545       PRO/1000 MF Server Adapter(LX)       A91624-xxx
+     82546       PRO/1000 MF Dual Port Server Adapter A91620-xxx 
+
+  For more information on how to identify your adapter, go to the
+  Adapter & Driver ID Guide at:
+
+   <http://support.intel.com/support/network/adapter/pro100/21397.htm>
+
+  For general information and support, go to the Intel support
+  website at:
+
+   <http://support.intel.com>
+
+  More specific information on configuring the driver is in 
+  <file:Documentation/networking/e1000.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 e1000.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
 AMD LANCE and PCnet (AT1500 and NE2100) support
 CONFIG_LANCE
   If you have a network (Ethernet) card of this type, say Y and read
@@ -14234,6 +14286,11 @@
   Say Y here to include additional code to support the Sandisk SDDR-09
   SmartMedia reader in the USB Mass Storage driver.
 
+SanDisk SDDR-55 SmartMedia support
+CONFIG_USB_STORAGE_SDDR55
+  Say Y here to include additional code to support the Sandisk SDDR-55
+  SmartMedia reader in the USB Mass Storage driver.
+
 USB Diamond Rio500 support
 CONFIG_USB_RIO500
   Say Y here if you want to connect a USB Rio500 mp3 player to your
@@ -14243,7 +14300,17 @@
   This code 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 rio500.o. If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
+  a module, say M here and read <file:Documenatation/modules.txt>.
+
+USB Auerswald ISDN device support
+CONFIG_USB_AUERSWALD
+  Say Y here if you want to connect an Auerswald USB ISDN Device
+  to your computer's USB port.
+
+  This code 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 auerswald.o. If you want to compile it as
+  a module, say M here and read <file:Documenatation/modules.txt>
 
 CONFIG_USB_TIGL
   If you own a Texas Instruments graphing calculator and use a 
diff -urN linux-2.4.20-pre4/Documentation/DocBook/Makefile linux-2.4.20-pre5/Documentation/DocBook/Makefile
--- linux-2.4.20-pre4/Documentation/DocBook/Makefile	Fri Aug  2 17:39:42 2002
+++ linux-2.4.20-pre5/Documentation/DocBook/Makefile	Wed Aug 28 16:37:20 2002
@@ -1,7 +1,8 @@
 BOOKS	:= wanbook.sgml z8530book.sgml mcabook.sgml videobook.sgml \
 	   kernel-api.sgml parportbook.sgml kernel-hacking.sgml \
 	   kernel-locking.sgml via-audio.sgml mousedrivers.sgml sis900.sgml \
-	   deviceiobook.sgml procfs-guide.sgml tulip-user.sgml
+	   deviceiobook.sgml procfs-guide.sgml tulip-user.sgml \
+	   journal-api.sgml
 
 PS	:=	$(patsubst %.sgml, %.ps, $(BOOKS))
 PDF	:=	$(patsubst %.sgml, %.pdf, $(BOOKS))
@@ -138,6 +139,17 @@
 parportbook.sgml: parportbook.tmpl $(TOPDIR)/drivers/parport/init.c
 	$(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/parport/init.c <$< >$@
 
+
+JBDSOURCES :=  $(TOPDIR)/include/linux/jbd.h \
+	       $(TOPDIR)/fs/jbd/journal.c \
+	       $(TOPDIR)/fs/jbd/recovery.c \
+	       $(TOPDIR)/fs/jbd/transaction.c
+
+journal-api.sgml: journal-api.tmpl $(JBDSOURCES)
+	$(TOPDIR)/scripts/docgen   $(JBDSOURCES) \
+		<journal-api.tmpl >journal-api.sgml
+
+
 DVI	:=	$(patsubst %.sgml, %.dvi, $(BOOKS))
 AUX	:=	$(patsubst %.sgml, %.aux, $(BOOKS))
 TEX	:=	$(patsubst %.sgml, %.tex, $(BOOKS))
diff -urN linux-2.4.20-pre4/Documentation/DocBook/journal-api.tmpl linux-2.4.20-pre5/Documentation/DocBook/journal-api.tmpl
--- linux-2.4.20-pre4/Documentation/DocBook/journal-api.tmpl	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre5/Documentation/DocBook/journal-api.tmpl	Wed Aug 28 16:37:20 2002
@@ -0,0 +1,297 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
+<book id="LinuxJBDAPI">
+ <bookinfo>
+  <title>The Linux Journalling API</title>
+  <authorgroup>
+  <author>
+     <firstname>Roger</firstname>
+     <surname>Gammans</surname>
+     <affiliation>
+     <address>
+      <email>rgammans@computer-surgery.co.uk</email>
+     </address>
+    </affiliation>
+     </author> 
+  </authorgroup>
+  
+  <authorgroup>
+   <author>
+    <firstname>Stephen</firstname>
+    <surname>Tweedie</surname>
+    <affiliation>
+     <address>
+      <email>sct@redhat.com</email>
+     </address>
+    </affiliation>
+   </author>
+  </authorgroup>
+
+  <copyright>
+   <year>2002</year>
+   <holder>Roger Gammans</holder>
+  </copyright>
+
+<legalnotice>
+   <para>
+     This documentation is free software; you can redistribute
+     it and/or modify it under the terms of the GNU General Public
+     License as published by the Free Software Foundation; either
+     version 2 of the License, or (at your option) any later
+     version.
+   </para>
+      
+   <para>
+     This program is distributed in the hope that it will be
+     useful, but WITHOUT ANY WARRANTY; without even the implied
+     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+     See the GNU General Public License for more details.
+   </para>
+      
+   <para>
+     You should have received a copy of the GNU General Public
+     License along with this program; if not, write to the Free
+     Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+     MA 02111-1307 USA
+   </para>
+      
+   <para>
+     For more details see the file COPYING in the source
+     distribution of Linux.
+   </para>
+  </legalnotice>
+ </bookinfo>
+
+<toc></toc>
+
+  <chapter id="Overview">
+     <title>Overview</title>
+  <sect1>
+     <title>Details</title>
+<para>
+The journalling layer is  easy to use. You need to 
+first of all create a journal_t data structure. There are
+two calls to do this dependent on how you decide to allocate the physical
+media on which the journal resides. The journal_init_inode() call 
+is for journals stored in filesystem inodes, or the journal_init_dev()
+call can be use for journal stored on a raw device (in a continuous range 
+of blocks). A journal_t is a typedef for a struct pointer, so when
+you are finally finished make sure you call journal_destroy() on it
+to free up any used kernel memory.
+</para>
+
+<para>
+Once you have got your journal_t object you need to 'mount' or load the journal
+file, unless of course you haven't initialised it yet - in which case you
+need to call journal_create().
+</para>
+
+<para>
+Most of the time however your journal file will already have been created, but
+before you load it you must call journal_wipe() to empty the journal file.
+Hang on, you say , what if the filesystem wasn't cleanly umount()'d . Well, it is the 
+job of the client file system to detect this and skip the call to journal_wipe().
+</para>
+
+<para>
+In either case the next call should be to journal_load() which prepares the
+journal file for use. Note that journal_wipe(..,0) calls journal_skip_recovery() 
+for you if it detects any outstanding transactions in the journal and similarly
+journal_load() will call journal_recover() if necessary.
+I would advise reading fs/ext3/super.c for examples on this stage.
+[RGG: Why is the journal_wipe() call necessary - doesn't this needlessly 
+complicate the API. Or isn't a good idea for the journal layer to hide 
+dirty mounts from the client fs]
+</para>
+
+<para>
+Now you can go ahead and start modifying the underlying 
+filesystem. Almost.
+</para>
+
+
+<para>
+
+You still need to actually journal your filesystem changes, this
+is done by wrapping them into transactions. Additionally you
+also need to wrap the modification of each of the the buffers
+with calls to the journal layer, so it knows what the modifications
+you are actually making are. To do this use  journal_start() which
+returns a transaction handle.
+</para>
+
+<para>
+journal_start()
+and its counterpart journal_stop(), which indicates the end of a transaction
+are nestable calls, so you can reenter a transaction if necessary,
+but remember you must call journal_stop() the same number of times as
+journal_start() before the transaction is completed (or more accurately
+leaves the the update phase). Ext3/VFS makes use of this feature to simplify 
+quota support.
+</para>
+
+<para>
+Inside each transaction you need to wrap the modifications to the
+individual buffers (blocks). Before you start to modify a buffer you
+need to call journal_get_{create,write,undo}_access() as appropriate,
+this allows the journalling layer to copy the unmodified data if it
+needs to. After all the buffer may be part of a previously uncommitted
+transaction. 
+At this point you are at last ready to modify a buffer, and once
+you are have done so you need to call journal_dirty_{meta,}data().
+Or if you've asked for access to a buffer you now know is now longer 
+required to be pushed back on the device you can call journal_forget()
+in much the same way as you might have used bforget() in the past.
+
+</para>
+
+
+
+<para>
+A journal_flush() may be called at any time to commit and checkpoint
+all your transactions.
+</para>
+<para>
+
+Then at umount time , in your put_super() (2.4) or write_super() (2.5)
+you can then call journal_destroy() to clean up your in-core journal object.
+</para>
+
+
+<para>
+Unfortunately there a couple of ways the journal layer can cause a deadlock.
+The first thing to note is that each task can only have
+a single outstanding transaction at any one time, remember nothing
+commits until the outermost journal_stop(). This means
+you must complete the transaction at the end of each file/inode/address
+etc. operation you perform, so that the journalling system isn't re-entered
+on another journal. Since transactions can't be nested/batched 
+across differing journals, and another filesystem other than
+yours (say ext3) may be modified in a later syscall.
+</para>
+<para>
+
+The second case to bear in mind is that journal_start() can 
+block if there isn't enough space in the journal for your transaction 
+(based on the passed nblocks param) - when it blocks it merely(!) needs to
+wait for transactions to complete and be committed from other tasks, 
+so essentially we are waiting for journal_stop(). So to avoid 
+deadlocks you must treat journal_start/stop() as if they
+were semaphores and include them in your semaphore ordering rules to prevent 
+deadlocks. Note that journal_extend() has similar blocking behaviour to
+journal_start() so you can deadlock here just as easily as on journal_start().
+</para>
+<para>
+
+Try to reserve the right number of blocks the first time. ;-).
+</para>
+<para>
+Another wriggle to watch out for is your on-disk block allocation strategy.
+why? Because, if you undo a delete, you need to ensure you haven't reused any
+of the freed blocks in a later transaction. One simple way of doing this
+is make sure any blocks you allocate only have checkpointed transactions
+listed against them. Ext3 does this in ext3_test_allocatable(). 
+</para>
+
+<para>
+Lock is also providing through journal_{un,}lock_updates(),
+ext3 uses this when it wants a window with a clean and stable fs for a moment.
+eg. 
+<programlisting>
+
+	journal_lock_updates() //stop new stuff happening..
+	journal_flush()        // checkpoint everything.
+	..do stuff on stable fs
+	journal_unlock_updates() // carry on with filesystem use.
+</programlisting>
+
+The opportunities for abuse and DOS attacks with this should be obvious,
+if you allow unprivileged userspace to trigger codepaths containing these
+calls.
+
+<para>
+</sect1>
+<sect1>
+<title>Summary</title>
+<para>
+Using the journal is a matter of wrapping the different context changes,
+being each mount, each modification (transaction) and each changed buffer
+to tell the journalling layer about them.
+
+Here is a some pseudo code to give you an idea of how it works, as
+an example.
+<programlisting>
+  journal_t* my_jnrl = journal_create();
+  journal_init_{dev,inode}(jnrl,...)
+  if (clean) journal_wipe();
+  journal_load();
+
+   foreach(transaction) { /*transactions must be 
+                            completed before
+                            a syscall returns to 
+                            userspace*/
+
+          handle_t * xct=journal_start(my_jnrl);
+          foreach(bh) {
+                journal_get_{create,write,undo}_access(xact,bh);
+                if ( myfs_modify(bh) ) { /* returns true 
+                                        if makes changes */
+                           journal_dirty_{meta,}data(xact,bh);
+                } else {
+                           journal_forget(bh);
+                }
+          }
+          journal_stop(xct);
+   }
+   journal_destroy(my_jrnl);
+</programlisting>
+
+</chapter>
+
+  <chapter id="adt">
+     <title>Data Types</title>
+     <para>	
+	The journalling layer uses typedefs to 'hide' the concrete definitions
+	of the structures used. As a client of the JBD layer you can
+	just rely on the using the pointer as a magic cookie  of some sort.
+	
+	Obviously the hiding is not enforced as this is 'C'.
+	</para>
+	<sect1><title>Structures</title>
+!Iinclude/linux/jbd.h
+	</sect1>
+</chapter>
+
+  <chapter id="calls">
+     <title>Functions</title>
+     <para>	
+	The functions here are split into two groups those that
+	affect a journal as a whole, and those which are used to
+	manage transactions
+</para>
+	<sect1><title>Journal Level</title>
+!Efs/jbd/journal.c
+!Efs/jbd/recovery.c
+	</sect1>
+	<sect1><title>Transasction Level</title>
+!Efs/jbd/transaction.c	
+	</sect1>
+</chapter>
+<chapter>
+     <title>See also</title>
+	<para>
+	<citation>
+	   <ulink url="ftp://ftp.uk.linux.org/pub/linux/sct/fs/jfs/journal-design.ps.gz">
+	   	Journaling the Linux ext2fs Filesystem,LinuxExpo 98, Stephen Tweedie
+	   </ulink>
+	   </citation>
+	   </para>
+	   <para>
+	   <citation>
+	   <ulink url="http://olstrans.sourceforge.net/release/OLS2000-ext3/OLS2000-ext3.html">
+	   	Ext3 Journalling FileSystem , OLS 2000, Dr. Stephen Tweedie
+	   </ulink>
+	   </citation>
+	   </para>
+</chapter>
+
+</book>
diff -urN linux-2.4.20-pre4/Documentation/DocBook/parportbook.tmpl linux-2.4.20-pre5/Documentation/DocBook/parportbook.tmpl
--- linux-2.4.20-pre4/Documentation/DocBook/parportbook.tmpl	Thu Oct 25 00:07:40 2001
+++ linux-2.4.20-pre5/Documentation/DocBook/parportbook.tmpl	Wed Aug 28 16:37:20 2002
@@ -595,7 +595,7 @@
    So, the first thing for the device driver to do is tell
    <literal>parport</literal> that it wants to know what parallel
    ports are on the system.  To do this, it uses the
-   <function>parport_register_device</function> function:
+   <function>parport_register_driver</function> function:
   </para>
 
   <funcsynopsis>
diff -urN linux-2.4.20-pre4/Documentation/cdrom/sonycd535 linux-2.4.20-pre5/Documentation/cdrom/sonycd535
--- linux-2.4.20-pre4/Documentation/cdrom/sonycd535	Wed May 20 18:54:34 1998
+++ linux-2.4.20-pre5/Documentation/cdrom/sonycd535	Wed Aug 28 16:37:21 2002
@@ -63,8 +63,8 @@
 Thanks also to Eberhard Moenkeberg (emoenke@gwdg.de) for prodding
 me to place this code into the mainstream Linux source tree
 (as of Linux version 1.1.91), as well as some patches to make
-it a better device citizen.  Further thanks to "S. Joel Katz"
-<stimpson@panix.com> for his MODULE patches (see details below),
+it a better device citizen.  Further thanks to Joel Katz
+<joelkatz@webchat.org> for his MODULE patches (see details below),
 Porfiri Claudio <C.Porfiri@nisms.tei.ericsson.se> for patches
 to make the driver work with the older CDU-510/515 series, and
 Heiko Eissfeldt <heiko@colossus.escape.de> for pointing out that
@@ -79,7 +79,7 @@
 ken@halcyon.com
 
 ------------------------------------------------------------------------------
-(The following is from Joel Katz <Stimpson@Panix.COM>.)
+(The following is from Joel Katz <joelkatz@webchat.org>.)
 
 	To build a version of sony535.o that can be installed as a module,
 use the following command:
@@ -103,7 +103,7 @@
 	I have an external drive, and I usually leave it powered off. I used
 to have to reboot if I needed to use the CDROM drive. Now I don't.
 
-	Even if you have an internal drive, why waste the 268K of memory
+	Even if you have an internal drive, why waste the 96K of memory
 (unswappable) that the driver uses if you use your CD-ROM drive infrequently?
 
 	This driver will not install (whether compiled in or loaded as a
diff -urN linux-2.4.20-pre4/Documentation/filesystems/devfs/README linux-2.4.20-pre5/Documentation/filesystems/devfs/README
--- linux-2.4.20-pre4/Documentation/filesystems/devfs/README	Wed Aug 28 16:36:45 2002
+++ linux-2.4.20-pre5/Documentation/filesystems/devfs/README	Wed Aug 28 16:37:21 2002
@@ -1777,7 +1777,7 @@
 First, remember that no naming scheme will please everybody. You hate
 the scheme, others love it. Who's to say who's right and who's wrong?
 Ultimately, the person who writes the code gets to choose, and what
-exists now is a combination of the the choices made by the
+exists now is a combination of the choices made by the
 devfs author and the
 kernel maintainer (Linus).
 
diff -urN linux-2.4.20-pre4/Documentation/filesystems/proc.txt linux-2.4.20-pre5/Documentation/filesystems/proc.txt
--- linux-2.4.20-pre4/Documentation/filesystems/proc.txt	Wed Nov  7 14:39:36 2001
+++ linux-2.4.20-pre5/Documentation/filesystems/proc.txt	Wed Aug 28 16:37:21 2002
@@ -708,36 +708,26 @@
 used ones  is  far  behind,  you've  encountered  a peak in your usage of file
 handles and you don't need to increase the maximum.
 
-inode-state, inode-nr and inode-max
------------------------------------
-
-As with  file  handles, the kernel allocates the inode structures dynamically,
-but can't free them yet.
-
-The value  in  inode-max  denotes  the  maximum number of inode handlers. This
-value should  be  3 to 4 times larger than the value in file-max, since stdin,
-stdout, and  network  sockets also need an inode struct to handle them. If you
-regularly run out of inodes, you should increase this value.
+inode-state and inode-nr
+------------------------
 
 The file inode-nr contains the first two items from inode-state, so we'll skip
 to that file...
 
-inode-state contains  three  actual numbers and four dummy values. The numbers
-are nr_inodes, nr_free_inodes, and preshrink (in order of appearance).
+inode-state contains  two  actual numbers and five dummy values. The numbers
+are nr_inodes and nr_free_inodes (in order of appearance).
 
 nr_inodes
 ~~~~~~~~~
 
-Denotes the  number  of  inodes the system has allocated. This can be slightly
-more than inode-max because Linux allocates them one pageful at a time.
+Denotes the  number  of  inodes the system has allocated. This number will
+grow and shrink dynamically.
 
 nr_free_inodes
 --------------
 
-Represents the  number  of free inodes and preshrink is nonzero when nr_inodes
-is greater than inode-max and the system needs to prune the inode list instead
-of allocating more.
-
+Represents the  number of free inodes. Ie. The number of inuse inodes is
+(nr_inodes - nr_free_inodes).
 
 super-nr and super-max
 ----------------------
diff -urN linux-2.4.20-pre4/Documentation/initrd.txt linux-2.4.20-pre5/Documentation/initrd.txt
--- linux-2.4.20-pre4/Documentation/initrd.txt	Sun Dec  3 17:48:18 2000
+++ linux-2.4.20-pre5/Documentation/initrd.txt	Wed Aug 28 16:37:21 2002
@@ -115,8 +115,12 @@
  1) make sure loopback block devices are configured into the kernel
  2) create an empty file system of the appropriate size, e.g.
     # dd if=/dev/zero of=initrd bs=300k count=1
-    # mke2fs -F -m0 initrd
+    # mke2fs -F -m0 -b 1024 initrd
     (if space is critical, you may want to use the Minix FS instead of Ext2)
+    (Note that due to a problem elsewhere in the kernel, you _must_ use a
+     1024-byte blocksize when creating your file system.  If any other
+     value is used, the kernel will be unable to mount the initrd at boot
+     time, causing a kernel panic.)
  3) mount the file system, e.g.
     # mount -t ext2 -o loop initrd /mnt
  4) create the console device (not necessary if using devfs, but it can't
diff -urN linux-2.4.20-pre4/Documentation/isapnp.txt linux-2.4.20-pre5/Documentation/isapnp.txt
--- linux-2.4.20-pre4/Documentation/isapnp.txt	Wed Apr 18 11:49:11 2001
+++ linux-2.4.20-pre5/Documentation/isapnp.txt	Wed Aug 28 16:37:21 2002
@@ -29,6 +29,7 @@
 poke <reg> <value>	- poke configuration byte to selected register
 pokew <reg> <value>	- poke configuration word to selected register
 poked <reg> <value>	- poke configuration dword to selected register
+allow_dma0 <value>	- allow dma channel 0 during auto activation: 0=off, 1=on
 
 Explanation:
 	- variable <idx> begins with zero
diff -urN linux-2.4.20-pre4/Documentation/ldm.txt linux-2.4.20-pre5/Documentation/ldm.txt
--- linux-2.4.20-pre4/Documentation/ldm.txt	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre5/Documentation/ldm.txt	Wed Aug 28 16:37:21 2002
@@ -0,0 +1,102 @@
+
+            LDM - Logical Disk Manager (Dynamic Disks)
+            ------------------------------------------
+
+Overview
+--------
+
+Windows 2000 and XP use a new partitioning scheme.  It is a complete
+replacement for the MSDOS style partitions.  It stores its information in a
+1MiB journalled database at the end of the physical disk.  The size of
+partitions is limited only by disk space.  The maximum number of partitions is
+nearly 2000.
+
+Any partitions created under the LDM are called "Dynamic Disks".  There are no
+longer any primary or extended partitions.  Normal MSDOS style partitions are
+now known as Basic Disks.
+
+If you wish to use Spanned, Striped, Mirrored or RAID 5 Volumes, you must use
+Dynamic Disks.  The journalling allows Windows to make changes to these
+partitions and filesystems without the need to reboot.
+
+Once the LDM driver has divided up the disk, you can use the MD driver to
+assemble any multi-partition volumes, e.g.  Stripes, RAID5.
+
+To prevent legacy applications from repartitioning the disk, the LDM creates a
+dummy MSDOS partition containing one disk-sized partition.
+
+
+Example
+-------
+
+Below we have a 50MiB disk, divided into seven partitions.
+N.B.  The missing 1MiB at the end of the disk is where the LDM database is
+      stored.
+
+  Device | Offset Bytes  Sectors  MiB | Size   Bytes  Sectors  MiB
+  -------+----------------------------+---------------------------
+  hda    |            0        0    0 |     52428800   102400   50
+  hda1   |     51380224   100352   49 |      1048576     2048    1
+  hda2   |        16384       32    0 |      6979584    13632    6
+  hda3   |      6995968    13664    6 |     10485760    20480   10
+  hda4   |     17481728    34144   16 |      4194304     8192    4
+  hda5   |     21676032    42336   20 |      5242880    10240    5
+  hda6   |     26918912    52576   25 |     10485760    20480   10
+  hda7   |     37404672    73056   35 |     13959168    27264   13
+
+The LDM Database may not store the partitions in the order that they appear on
+disk, but the driver will sort them.
+
+When Linux boots, you will see something like:
+
+Partition check:
+  hda: [LDM] hda1 hda2 hda3 hda4 hda5 hda6 hda7
+
+
+Compiling LDM Support
+---------------------
+
+To enable LDM, choose the following two options: 
+
+  "Advanced partition selection" CONFIG_PARTITION_ADVANCED
+  "Windows Logical Disk Manager (Dynamic Disk) support" CONFIG_LDM_PARTITION
+
+If you believe the driver isn't working as it should, you can enable the extra
+debugging code.  This will produce a LOT of output.  The option is:
+
+  "Windows LDM extra logging" CONFIG_LDM_DEBUG
+
+N.B. The partition code cannot be compiled as a module.
+
+As with all the partition code, if the driver doesn't see signs of its type of
+partition, it will pass control to another driver, so there is no harm in
+enabling it.
+
+If you have Dynamic Disks but don't enable the driver, then all you will see
+is a dummy MSDOS partition filling the whole disk.  You won't be able to mount
+any of the volumes on the disk.
+
+
+Booting
+-------
+
+If you enable LDM support, then lilo is capable of booting from any of the
+discovered partitions.  However, grub does not understand the LDM partitioning
+and cannot boot from a Dynamic Disk.
+
+
+More Documentation
+------------------
+
+There is an Overview of the LDM online together with complete Technical
+Documentation.  It can also be downloaded in html.
+
+  http://linux-ntfs.sourceforge.net/ldm/index.html
+  http://linux-ntfs.sourceforge.net/downloads.html
+
+If you have any LDM questions that aren't answered on the website, email me.
+
+Cheers,
+    FlatCap - Richard Russon
+    ldm@flatcap.org
+
diff -urN linux-2.4.20-pre4/Documentation/networking/e1000.txt linux-2.4.20-pre5/Documentation/networking/e1000.txt
--- linux-2.4.20-pre4/Documentation/networking/e1000.txt	Wed Aug 28 16:36:45 2002
+++ linux-2.4.20-pre5/Documentation/networking/e1000.txt	Wed Aug 28 16:37:22 2002
@@ -1,7 +1,7 @@
 Linux* Base Driver for the Intel(R) PRO/1000 Family of Adapters
 ===============================================================
 
-June 11, 2002
+August 6, 2002
 
 
 Contents
@@ -20,12 +20,12 @@
 ===============
 
 This file describes the Linux* Base Driver for the Intel(R) PRO/1000 Family
-of Adapters, version 4.2.x.  This driver includes support for 
+of Adapters, version 4.3.x.  This driver includes support for 
 Itanium(TM)-based systems.
 
 This release version includes the following:
 
-   - Support for the ethtool 1.5 interface. A third-party application can use
+   - Support for the ethtool 1.6 interface. A third-party application can use
      the ethtool interface to get and set driver parameters.
 
    - Zero copy. This feature provides faster data throughput. Enabled by
@@ -113,12 +113,12 @@
 Default Value: 0x2F
     This parameter is a bit mask that specifies which speed and duplex
     settings the board advertises. When this parameter is used, the Speed and
-    Duplex parameters must not be specified.
+    Duplex parameters must not be specified.  
 
 Duplex (adapters using copper connections only)
 Valid Range: 0-2 (0=auto-negotiate, 1=half, 2=full)
 Default Value: 0
-    Defines the direction in which data is allowed to flow. Can by either one
+    Defines the direction in which data is allowed to flow. Can by either one 
     or two-directional. If both Duplex and the link partner are set to auto-
     negotiate, the board auto-detects the correct duplex. If the link partner
     is forced (either full or half), Duplex defaults to half-duplex.
@@ -126,45 +126,58 @@
 FlowControl
 Valid Range: 0-3 (0=none, 1=Rx only, 2=Tx only, 3=Rx&Tx)
 Default: Read flow control settings from the EEPROM
-    This parameter controls the automatic generation(Tx) and response(Rx) to
+    This parameter controls the automatic generation(Tx) and response(Rx) to 
     Ethernet PAUSE frames.
 
 RxDescriptors
 Valid Range: 80-256 for 82542 and 82543-based adapters
              80-4096 for 82540, 82544, 82545, and 82546-based adapters
 Default Value: 80
-    This value is the number of receive descriptors allocated by the driver.
-    Increasing this value allows the driver to buffer more incoming packets.
+    This value is the number of receive descriptors allocated by the driver. 
+    Increasing this value allows the driver to buffer more incoming packets. 
     Each descriptor is 16 bytes.  A receive buffer is also allocated for each
-    descriptor and can be either 2048, 4096, 8192, or 16384 bytes, depending
+    descriptor and can be either 2048, 4096, 8192, or 16384 bytes, depending 
     on the MTU setting. The maximum MTU size is 16110.
 
+    NOTE: MTU designates the frame size. It only needs to be set for Jumbo 
+          Frames.
+
 RxIntDelay
 Valid Range: 0-65535 (0=off)
 Default Value: 0 (82542, 82543, and 82544-based adapters)
                128 (82540, 82545, and 82546-based adapters)
-    This value delays the generation of receive interrupts in units of 1.024
-    microseconds.  Receive interrupt reduction can improve CPU efficiency if
-    properly tuned for specific network traffic. Increasing this value adds
-    extra latency to frame reception and can end up decreasing the throughput
-    of TCP traffic. If the system is reporting dropped receives, this value
-    may be set too high, causing the driver to run out of available receive
+    This value delays the generation of receive interrupts in units of 1.024 
+    microseconds.  Receive interrupt reduction can improve CPU efficiency if 
+    properly tuned for specific network traffic. Increasing this value adds 
+    extra latency to frame reception and can end up decreasing the throughput 
+    of TCP traffic. If the system is reporting dropped receives, this value 
+    may be set too high, causing the driver to run out of available receive 
     descriptors.
 
-    CAUTION: When setting RxIntDelay to a value other than 0, adapters based
-             on the Intel 82543 and 82544 LAN controllers may hang (stop
+    CAUTION: When setting RxIntDelay to a value other than 0, adapters based 
+             on the Intel 82543 and 82544 LAN controllers may hang (stop 
              transmitting) under certain network conditions. If this occurs a
-             message is logged in the system event log. In addition, the
-             controller is automatically reset, restoring the network
-             connection. To eliminate the potential for the hang ensure that
+             message is logged in the system event log. In addition, the 
+             controller is automatically reset, restoring the network 
+             connection. To eliminate the potential for the hang ensure that 
              RxIntDelay is set to 0.
 
+RxAbsIntDelay (82540, 82545, and 82546-based adapters only)
+Valid Range: 0-65535 (0=off)
+Default Value: 128
+    This value, in units of 1.024 microseconds, limits the delay in which a 
+    transmit interrupt is generated. Useful only if RxIntDelay is non-zero, 
+    this value ensures that an interrupt is generated after the initial 
+    packet is received within the set amount of time.  Proper tuning,
+    along with RxIntDelay, may improve traffic throughput in specific network
+    conditions.
+
 Speed (adapters using copper connections only)
 Valid Settings: 0, 10, 100, 1000
 Default Value: 0 (auto-negotiate at all supported speeds)
     Speed forces the line speed to the specified value in megabits per second
-    (Mbps). If this parameter is not specified or is set to 0 and the link
-    partner is set to auto-negotiate, the board will auto-detect the correct
+    (Mbps). If this parameter is not specified or is set to 0 and the link 
+    partner is set to auto-negotiate, the board will auto-detect the correct 
     speed. Duplex must also be set when Speed is set to either 10 or 100.
 
 TxDescriptors
@@ -172,9 +185,28 @@
              80-4096 for 82540, 82544, 82545, and 82546-based adapters
 Default Value: 256
     This value is the number of transmit descriptors allocated by the driver.
-    Increasing this value allows the driver to queue more transmits. Each
+    Increasing this value allows the driver to queue more transmits. Each 
     descriptor is 16 bytes.
 
+TxIntDelay
+Valid Range: 0-65535 (0=off)
+Default Value: 64
+    This value delays the generation of transmit interrupts in units of 
+    1.024 microseconds.  Transmit interrupt reduction can improve CPU
+    efficiency if properly tuned for specific network traffic. If the
+    system is reporting dropped transmits, this value may be set too high
+    causing the driver to run out of available transmit descriptors.
+
+TxAbsIntDelay (82540, 82545, and 82546-based adapters only)
+Valid Range: 0-65535 (0=off)
+Default Value: 64
+    This value, in units of 1.024 microseconds, limits the delay in which a 
+    transmit interrupt is generated. Useful only if TxIntDelay is non-zero, 
+    this value ensures that an interrupt is generated after the initial 
+    packet is sent on the wire within the set amount of time.  Proper tuning,
+    along with TxIntDelay, may improve traffic throughput in specific 
+    network conditions.
+
 XsumRX (not available on the PRO/1000 Gigabit Server Adapter)
 Valid Range: 0-1
 Default Value: 1
diff -urN linux-2.4.20-pre4/Documentation/usb/auerswald.txt linux-2.4.20-pre5/Documentation/usb/auerswald.txt
--- linux-2.4.20-pre4/Documentation/usb/auerswald.txt	Fri Aug  2 17:39:42 2002
+++ linux-2.4.20-pre5/Documentation/usb/auerswald.txt	Wed Aug 28 16:37:22 2002
@@ -27,4 +27,4 @@
 ============
 - Connection to ISDN4LINUX (the hisax interface)
 
-The maintainer of this driver is wmues@nexgo.de
+The maintainer of this driver is wolfgang@iksw-muees.de
diff -urN linux-2.4.20-pre4/Documentation/usb/ov511.txt linux-2.4.20-pre5/Documentation/usb/ov511.txt
--- linux-2.4.20-pre4/Documentation/usb/ov511.txt	Mon Feb 25 11:37:52 2002
+++ linux-2.4.20-pre5/Documentation/usb/ov511.txt	Wed Aug 28 16:37:22 2002
@@ -128,16 +128,6 @@
         programs that expect RGB data (e.g. gqcam) to work with this driver. If
         your colors look VERY wrong, you may want to change this.
 
-  NAME: buf_timeout
-  TYPE: integer
-  DEFAULT: 5 (seconds)
-  DESC: Number of seconds before unused frame buffers are deallocated.
-        Previously, memory was allocated upon open() and deallocated upon
-        close(). Deallocation now occurs only if the driver is closed and this
-        timeout is reached. If you are capturing frames less frequently than
-        the default timeout, increase this. This will not make any difference
-        with programs that capture multiple frames during an open/close cycle.
-
   NAME: cams
   TYPE: integer (1-4 for OV511, 1-31 for OV511+)
   DEFAULT: 1
@@ -161,13 +151,6 @@
   DESC: This configures the camera's sensor to transmit a colored test-pattern
         instead of an image. This does not work correctly yet.
 
-  NAME: sensor_gbr (*** TEMPORARILY DISABLED ***)
-  TYPE: integer (Boolean)
-  DEFAULT: 0
-  DESC: This makes the sensor output GBR422 instead of YUV420. This saves the
-        driver the trouble of converting YUV to RGB, but it currently does not
-        work very well (the colors are not quite right)
-
   NAME: dumppix
   TYPE: integer (0-2)
   DEFAULT: 0
@@ -182,9 +165,9 @@
   DEFAULT: 1 (Always on)
   DESC: Controls whether the LED (the little light) on the front of the camera
 	is always off (0), always on (1), or only on when driver is open (2).
-	This is only supported with the OV511+ chipset, and even then only on
-	some cameras (ones that actually have the LED wired to the control pin,
-	and not just hardwired to be on all the time).
+	This is not supported with the OV511, and might only work with certain
+	cameras (ones that actually have the LED wired to the control pin, and
+	not just hard-wired to be on all the time).
 
   NAME: dump_bridge
   TYPE: integer (Boolean)
@@ -259,14 +242,6 @@
 		13  VIDEO_PALETTE_YUV422P   (YUV 4:2:2 Planar)
 		15  VIDEO_PALETTE_YUV420P   (YUV 4:2:0 Planar, same as 10)
 
-  NAME: tuner
-  TYPE: integer
-  DEFAULT: -1 (autodetect)
-  DESC: This sets the exact type of the tuner module in a device. This is set
-	automatically based on the custom ID of the OV511 device. In cases
-	where this fails, you can override this auto-detection. Please see
-	linux/drivers/media/video/tuner.h for a complete list.
-
   NAME: backlight
   TYPE: integer (Boolean)
   DEFAULT: 0 (off)
@@ -293,7 +268,14 @@
 	will compensate for the blocks of corruption that can appear when the
 	camera cannot keep up with the speed of the USB bus (eg. at low frame
 	resolutions). This feature is always enabled when compression is on.
- 
+
+  NAME: mirror
+  TYPE: integer (Boolean)
+  DEFAULT: 0 (off)
+  DESC: Setting this to 1 will reverse ("mirror") the image horizontally. This
+	might be necessary if your camera has a custom lens assembly. This has
+	no effect with video capture devices.
+
 WORKING FEATURES:
  o Color streaming/capture at most widths and heights that are multiples of 8.
  o RGB24, RGB565, YUV420/YUV420P, YUV422/YUYV, and YUV422P color
@@ -304,22 +286,9 @@
  o SAA7111A video capture support at 320x240 and 640x480
  o Compression support
 
-EXPERIMENTAL FEATURES:
- o OV6630 sensor support
- o Banding filter
- o SMP compatibility
-
-TO-DO:
- o V4L2 support (This will be done after the next kernel patch release)
- o Setting of hue not working with OV7620
- o Setting of contrast and hue not working with OV7620AE
- o OV8600 sensor support (Not used in anything yet)
- o OV518/OV518+ support (all that's needed is the decompressor)
- o cams >= 3 not working
-
 HOW TO CONTACT ME:
 
-You can email me at mmcclell@bigfoot.com . Please prefix the subject line
+You can email me at mark@alpha.dyndns.org . Please prefix the subject line
 with "OV511: " so that I am certain to notice your message.
 
 CREDITS:
diff -urN linux-2.4.20-pre4/MAINTAINERS linux-2.4.20-pre5/MAINTAINERS
--- linux-2.4.20-pre4/MAINTAINERS	Wed Aug 28 16:36:45 2002
+++ linux-2.4.20-pre5/MAINTAINERS	Wed Aug 28 16:37:22 2002
@@ -1574,6 +1574,13 @@
 M:	s.doyon@videotron.ca
 S:	Maintained
 
+TIEMAN VOYAGER USB BRAILLE DISPLAY DRIVER
+P:	Stephane Dalton
+M:	sdalton@videotron.ca
+P:	Stéphane Doyon
+M:	s.doyon@videotron.ca
+S:	Maintained
+
 TLAN NETWORK DRIVER
 P:	Samuel Chessman
 M:	chessman@tux.org
@@ -1661,7 +1668,7 @@
 
 USB AUERSWALD DRIVER
 P:	Wolfgang Muees
-M:	wmues@nexgo.de
+M:	wolfgang@iksw-muees.de
 L:	linux-usb-users@lists.sourceforge.net
 L:	linux-usb-devel@lists.sourceforge.net
 S:	Maintained
diff -urN linux-2.4.20-pre4/Makefile linux-2.4.20-pre5/Makefile
--- linux-2.4.20-pre4/Makefile	Wed Aug 28 16:36:45 2002
+++ linux-2.4.20-pre5/Makefile	Wed Aug 28 16:37:22 2002
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 20
-EXTRAVERSION = -pre4
+EXTRAVERSION = -pre5
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
@@ -260,7 +260,7 @@
 # 'kbuild_2_4_nostdinc :=' or -I/usr/include for kernel code and you are not UML
 # then your code is broken!  KAO.
 
-kbuild_2_4_nostdinc	:= -nostdinc $(shell $(CC) -print-search-dirs | sed -ne 's/install: \(.*\)/-I \1include/gp')
+kbuild_2_4_nostdinc	:= -nostdinc -iwithprefix include
 export kbuild_2_4_nostdinc
 
 export	CPPFLAGS CFLAGS CFLAGS_KERNEL AFLAGS AFLAGS_KERNEL
diff -urN linux-2.4.20-pre4/arch/alpha/mm/fault.c linux-2.4.20-pre5/arch/alpha/mm/fault.c
--- linux-2.4.20-pre4/arch/alpha/mm/fault.c	Wed Aug 28 16:36:45 2002
+++ linux-2.4.20-pre5/arch/alpha/mm/fault.c	Wed Aug 28 16:37:22 2002
@@ -151,13 +151,12 @@
 	 * the fault.
 	 */
 	fault = handle_mm_fault(mm, vma, address, cause > 0);
-	up_read(&mm->mmap_sem);
-
 	if (fault < 0)
 		goto out_of_memory;
 	if (fault == 0)
 		goto do_sigbus;
 
+	up_read(&mm->mmap_sem);
 	return;
 
 /*
@@ -206,9 +205,9 @@
 out_of_memory:
 	if (current->pid == 1) {
 		yield();
-		down_read(&mm->mmap_sem);
 		goto survive;
 	}
+	up_read(&mm->mmap_sem);
 	printk(KERN_ALERT "VM: killing process %s(%d)\n",
 	       current->comm, current->pid);
 	if (!user_mode(regs))
@@ -216,6 +215,7 @@
 	do_exit(SIGKILL);
 
 do_sigbus:
+	up_read(&mm->mmap_sem);
 	/*
 	 * Send a sigbus, regardless of whether we were in kernel
 	 * or user mode.
diff -urN linux-2.4.20-pre4/arch/i386/kernel/dmi_scan.c linux-2.4.20-pre5/arch/i386/kernel/dmi_scan.c
--- linux-2.4.20-pre4/arch/i386/kernel/dmi_scan.c	Wed Aug 28 16:36:45 2002
+++ linux-2.4.20-pre5/arch/i386/kernel/dmi_scan.c	Wed Aug 28 16:37:25 2002
@@ -564,6 +564,17 @@
 			MATCH(DMI_BIOS_VERSION, "Version1.01"),
 			NO_MATCH, NO_MATCH,
 			} },
+	{ apm_is_horked, "Intel D850MD", { /* APM crashes */
+			MATCH(DMI_BIOS_VENDOR, "Intel Corp."),
+			MATCH(DMI_BIOS_VERSION, "MV85010A.86A.0016.P07.0201251536"),
+			NO_MATCH, NO_MATCH,
+			} },
+	{ apm_is_horked, "Dell XPS-Z", { /* APM crashes */
+			MATCH(DMI_BIOS_VENDOR, "Intel Corp."),
+			MATCH(DMI_BIOS_VERSION, "A11"),
+			MATCH(DMI_PRODUCT_NAME, "XPS-Z"),
+			NO_MATCH,
+			} },
 	{ apm_is_horked, "Sharp PC-PJ/AX", { /* APM crashes */
 			MATCH(DMI_SYS_VENDOR, "SHARP"),
 			MATCH(DMI_PRODUCT_NAME, "PC-PJ/AX"),
diff -urN linux-2.4.20-pre4/arch/i386/kernel/pci-dma.c linux-2.4.20-pre5/arch/i386/kernel/pci-dma.c
--- linux-2.4.20-pre4/arch/i386/kernel/pci-dma.c	Mon Feb 14 15:34:21 2000
+++ linux-2.4.20-pre5/arch/i386/kernel/pci-dma.c	Wed Aug 28 16:37:25 2002
@@ -19,7 +19,7 @@
 	void *ret;
 	int gfp = GFP_ATOMIC;
 
-	if (hwdev == NULL || hwdev->dma_mask != 0xffffffff)
+	if (hwdev == NULL || ((u32)hwdev->dma_mask != 0xffffffff))
 		gfp |= GFP_DMA;
 	ret = (void *)__get_free_pages(gfp, get_order(size));
 
diff -urN linux-2.4.20-pre4/arch/i386/kernel/pci-i386.c linux-2.4.20-pre5/arch/i386/kernel/pci-i386.c
--- linux-2.4.20-pre4/arch/i386/kernel/pci-i386.c	Wed Aug 28 16:36:45 2002
+++ linux-2.4.20-pre5/arch/i386/kernel/pci-i386.c	Wed Aug 28 16:37:25 2002
@@ -351,7 +351,7 @@
 		lat = pcibios_max_latency;
 	else
 		return;
-	printk("PCI: Setting latency timer of device %s to %d\n", dev->slot_name, lat);
+	printk(KERN_DEBUG "PCI: Setting latency timer of device %s to %d\n", dev->slot_name, lat);
 	pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
 }
 
diff -urN linux-2.4.20-pre4/arch/i386/kernel/pci-pc.c linux-2.4.20-pre5/arch/i386/kernel/pci-pc.c
--- linux-2.4.20-pre4/arch/i386/kernel/pci-pc.c	Wed Aug 28 16:36:45 2002
+++ linux-2.4.20-pre5/arch/i386/kernel/pci-pc.c	Wed Aug 28 16:37:25 2002
@@ -54,11 +54,11 @@
 #define PCI_CONF1_ADDRESS(bus, dev, fn, reg) \
 	(0x80000000 | (BUS2LOCAL(bus) << 16) | (dev << 11) | (fn << 8) | (reg & ~3))
 
-static int pci_conf1_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) /* CONFIG_MULTIQUAD */
+static int pci_conf1_mq_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) /* CONFIG_MULTIQUAD */
 {
 	unsigned long flags;
 
-	if (!value || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255))
+	if (bus > 255 || dev > 31 || fn > 7 || reg > 255)
 		return -EINVAL;
 
 	spin_lock_irqsave(&pci_config_lock, flags);
@@ -82,11 +82,11 @@
 	return 0;
 }
 
-static int pci_conf1_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) /* CONFIG_MULTIQUAD */
+static int pci_conf1_mq_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) /* CONFIG_MULTIQUAD */
 {
 	unsigned long flags;
 
-	if ((bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) 
+	if (bus > 255 || dev > 31 || fn > 7 || reg > 255) 
 		return -EINVAL;
 
 	spin_lock_irqsave(&pci_config_lock, flags);
@@ -110,7 +110,69 @@
 	return 0;
 }
 
-#else /* !CONFIG_MULTIQUAD */
+static int pci_conf1_read_mq_config_byte(struct pci_dev *dev, int where, u8 *value)
+{
+	int result; 
+	u32 data;
+
+	result = pci_conf1_mq_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+		PCI_FUNC(dev->devfn), where, 1, &data);
+
+	*value = (u8)data;
+
+	return result;
+}
+
+static int pci_conf1_read_mq_config_word(struct pci_dev *dev, int where, u16 *value)
+{
+	int result; 
+	u32 data;
+
+	result = pci_conf1_mq_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+		PCI_FUNC(dev->devfn), where, 2, &data);
+
+	*value = (u16)data;
+
+	return result;
+}
+
+static int pci_conf1_read_mq_config_dword(struct pci_dev *dev, int where, u32 *value)
+{
+	if (!value) 
+		return -EINVAL;
+
+	return pci_conf1_mq_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+		PCI_FUNC(dev->devfn), where, 4, value);
+}
+
+static int pci_conf1_write_mq_config_byte(struct pci_dev *dev, int where, u8 value)
+{
+	return pci_conf1_mq_write(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+		PCI_FUNC(dev->devfn), where, 1, value);
+}
+
+static int pci_conf1_write_mq_config_word(struct pci_dev *dev, int where, u16 value)
+{
+	return pci_conf1_mq_write(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+		PCI_FUNC(dev->devfn), where, 2, value);
+}
+
+static int pci_conf1_write_mq_config_dword(struct pci_dev *dev, int where, u32 value)
+{
+	return pci_conf1_mq_write(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+		PCI_FUNC(dev->devfn), where, 4, value);
+}
+
+static struct pci_ops pci_direct_mq_conf1 = {
+	pci_conf1_read_mq_config_byte,
+	pci_conf1_read_mq_config_word,
+	pci_conf1_read_mq_config_dword,
+	pci_conf1_write_mq_config_byte,
+	pci_conf1_write_mq_config_word,
+	pci_conf1_write_mq_config_dword
+};
+
+#endif /* !CONFIG_MULTIQUAD */
 #define PCI_CONF1_ADDRESS(bus, dev, fn, reg) \
 	(0x80000000 | (bus << 16) | (dev << 11) | (fn << 8) | (reg & ~3))
 
@@ -118,7 +180,7 @@
 {
 	unsigned long flags;
 
-	if (!value || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255))
+	if (bus > 255 || dev > 31 || fn > 7 || reg > 255)
 		return -EINVAL;
 
 	spin_lock_irqsave(&pci_config_lock, flags);
@@ -146,7 +208,7 @@
 {
 	unsigned long flags;
 
-	if ((bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) 
+	if ((bus > 255 || dev > 31 || fn > 7 || reg > 255)) 
 		return -EINVAL;
 
 	spin_lock_irqsave(&pci_config_lock, flags);
@@ -170,8 +232,6 @@
 	return 0;
 }
 
-#endif /* CONFIG_MULTIQUAD */
-
 #undef PCI_CONF1_ADDRESS
 
 static int pci_conf1_read_config_byte(struct pci_dev *dev, int where, u8 *value)
@@ -179,9 +239,6 @@
 	int result; 
 	u32 data;
 
-	if (!value) 
-		return -EINVAL;
-
 	result = pci_conf1_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
 		PCI_FUNC(dev->devfn), where, 1, &data);
 
@@ -195,9 +252,6 @@
 	int result; 
 	u32 data;
 
-	if (!value) 
-		return -EINVAL;
-
 	result = pci_conf1_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
 		PCI_FUNC(dev->devfn), where, 2, &data);
 
@@ -208,9 +262,6 @@
 
 static int pci_conf1_read_config_dword(struct pci_dev *dev, int where, u32 *value)
 {
-	if (!value) 
-		return -EINVAL;
-
 	return pci_conf1_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
 		PCI_FUNC(dev->devfn), where, 4, value);
 }
@@ -253,7 +304,7 @@
 {
 	unsigned long flags;
 
-	if (!value || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255))
+	if (bus > 255 || dev > 31 || fn > 7 || reg > 255)
 		return -EINVAL;
 
 	if (dev & 0x10) 
@@ -287,7 +338,7 @@
 {
 	unsigned long flags;
 
-	if ((bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) 
+	if ((bus > 255 || dev > 31 || fn > 7 || reg > 255)) 
 		return -EINVAL;
 
 	if (dev & 0x10) 
@@ -423,6 +474,12 @@
 			__restore_flags(flags);
 			printk(KERN_INFO "PCI: Using configuration type 1\n");
 			request_region(0xCF8, 8, "PCI conf1");
+
+#ifdef CONFIG_MULTIQUAD			
+			/* Multi-Quad has an extended PCI Conf1 */
+			if(clustered_apic_mode)
+				return &pci_direct_mq_conf1;
+#endif				
 			return &pci_direct_conf1;
 		}
 		outl (tmp, 0xCF8);
@@ -640,7 +697,7 @@
 	unsigned long flags;
 	unsigned long bx = ((bus << 8) | (dev << 3) | fn);
 
-	if (!value || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255))
+	if (bus > 255 || dev > 31 || fn > 7 || reg > 255)
 		return -EINVAL;
 
 	spin_lock_irqsave(&pci_config_lock, flags);
@@ -695,7 +752,7 @@
 	unsigned long flags;
 	unsigned long bx = ((bus << 8) | (dev << 3) | fn);
 
-	if ((bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) 
+	if ((bus > 255 || dev > 31 || fn > 7 || reg > 255)) 
 		return -EINVAL;
 
 	spin_lock_irqsave(&pci_config_lock, flags);
@@ -750,7 +807,7 @@
 	u32 data;
 
 	if (!value) 
-		return -EINVAL;
+		BUG();
 
 	result = pci_bios_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
 		PCI_FUNC(dev->devfn), where, 1, &data);
@@ -766,7 +823,7 @@
 	u32 data;
 
 	if (!value) 
-		return -EINVAL;
+		BUG();
 
 	result = pci_bios_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
 		PCI_FUNC(dev->devfn), where, 2, &data);
@@ -779,7 +836,7 @@
 static int pci_bios_read_config_dword(struct pci_dev *dev, int where, u32 *value)
 {
 	if (!value) 
-		return -EINVAL;
+		BUG();
 	
 	return pci_bios_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
 		PCI_FUNC(dev->devfn), where, 4, value);
@@ -1227,6 +1284,11 @@
 	pci_read_config_byte(d, PCI_REVISION_ID, &revision);
 	
 	if (d->device == PCI_DEVICE_ID_VIA_8367_0) {
+		/* fix pci bus latency issues resulted by NB bios error
+		   it appears on bug free^Wreduced kt266x's bios forces
+		   NB latency to zero */
+		pci_write_config_byte(d, PCI_LATENCY_TIMER, 0);
+
 		where = 0x95; /* the memory write queue timer register is 
 				 different for the KT266x's: 0x95 not 0x55 */
 	} else if (d->device == PCI_DEVICE_ID_VIA_8363_0 &&
@@ -1281,6 +1343,11 @@
 	 * both PCI BIOS and direct access, with a preference for direct.
 	 */
 
+#ifdef CONFIG_PCI_DIRECT
+	struct pci_ops *tmp = NULL;
+#endif
+
+
 #ifdef CONFIG_PCI_BIOS
 	if ((pci_probe & PCI_PROBE_BIOS) 
 		&& ((pci_root_ops = pci_find_bios()))) {
@@ -1293,7 +1360,8 @@
 
 #ifdef CONFIG_PCI_DIRECT
 	if ((pci_probe & (PCI_PROBE_CONF1 | PCI_PROBE_CONF2)) 
-		&& (pci_root_ops = pci_check_direct())) {
+		&& (tmp = pci_check_direct())) {
+		pci_root_ops = tmp;
 		if (pci_root_ops == &pci_direct_conf1) {
 			pci_config_read = pci_conf1_read;
 			pci_config_write = pci_conf1_write;
diff -urN linux-2.4.20-pre4/arch/i386/lib/checksum.S linux-2.4.20-pre5/arch/i386/lib/checksum.S
--- linux-2.4.20-pre4/arch/i386/lib/checksum.S	Tue Sep  5 14:01:35 2000
+++ linux-2.4.20-pre5/arch/i386/lib/checksum.S	Wed Aug 28 16:37:25 2002
@@ -149,6 +149,8 @@
 30:	subl $2, %ecx          
 	ja 20b                 
 	je 32f
+	addl $2, %ecx
+	jz 80f
 	movzbl (%esi),%ebx	# csumming 1 byte, 2-aligned
 	addl %ebx, %eax
 	adcl $0, %eax
diff -urN linux-2.4.20-pre4/arch/i386/mm/fault.c linux-2.4.20-pre5/arch/i386/mm/fault.c
--- linux-2.4.20-pre4/arch/i386/mm/fault.c	Wed Aug 28 16:36:45 2002
+++ linux-2.4.20-pre5/arch/i386/mm/fault.c	Wed Aug 28 16:37:25 2002
@@ -333,12 +333,11 @@
  * us unable to handle the page fault gracefully.
  */
 out_of_memory:
-	up_read(&mm->mmap_sem);
 	if (tsk->pid == 1) {
 		yield();
-		down_read(&mm->mmap_sem);
 		goto survive;
 	}
+	up_read(&mm->mmap_sem);
 	printk("VM: killing process %s\n", tsk->comm);
 	if (error_code & 4)
 		do_exit(SIGKILL);
diff -urN linux-2.4.20-pre4/arch/ia64/mm/fault.c linux-2.4.20-pre5/arch/ia64/mm/fault.c
--- linux-2.4.20-pre4/arch/ia64/mm/fault.c	Wed Aug 28 16:36:45 2002
+++ linux-2.4.20-pre5/arch/ia64/mm/fault.c	Wed Aug 28 16:37:25 2002
@@ -194,12 +194,11 @@
 	return;
 
   out_of_memory:
-	up_read(&mm->mmap_sem);
 	if (current->pid == 1) {
 		yield();
-		down_read(&mm->mmap_sem);
 		goto survive;
 	}
+	up_read(&mm->mmap_sem);
 	printk("VM: killing process %s\n", current->comm);
 	if (user_mode(regs))
 		do_exit(SIGKILL);
diff -urN linux-2.4.20-pre4/arch/m68k/mm/fault.c linux-2.4.20-pre5/arch/m68k/mm/fault.c
--- linux-2.4.20-pre4/arch/m68k/mm/fault.c	Wed Aug 28 16:36:45 2002
+++ linux-2.4.20-pre5/arch/m68k/mm/fault.c	Wed Aug 28 16:37:26 2002
@@ -179,13 +179,12 @@
  * us unable to handle the page fault gracefully.
  */
 out_of_memory:
-	up_read(&mm->mmap_sem);
 	if (current->pid == 1) {
 		yield();
-		down_read(&mm->mmap_sem);
 		goto survive;
 	}
-	
+
+	up_read(&mm->mmap_sem);
 	printk("VM: killing process %s\n", current->comm);
 	if (user_mode(regs))
 		do_exit(SIGKILL);
diff -urN linux-2.4.20-pre4/arch/mips/mm/fault.c linux-2.4.20-pre5/arch/mips/mm/fault.c
--- linux-2.4.20-pre4/arch/mips/mm/fault.c	Wed Aug 28 16:36:45 2002
+++ linux-2.4.20-pre5/arch/mips/mm/fault.c	Wed Aug 28 16:37:26 2002
@@ -211,12 +211,11 @@
  * us unable to handle the page fault gracefully.
  */
 out_of_memory:
-	up_read(&mm->mmap_sem);
 	if (tsk->pid == 1) {
 		yield();
-		down_read(&mm->mmap_sem);
 		goto survive;
 	}
+	up_read(&mm->mmap_sem);
 	printk(KERN_NOTICE "VM: killing process %s\n", tsk->comm);
 	if (user_mode(regs))
 		do_exit(SIGKILL);
diff -urN linux-2.4.20-pre4/arch/mips64/mm/fault.c linux-2.4.20-pre5/arch/mips64/mm/fault.c
--- linux-2.4.20-pre4/arch/mips64/mm/fault.c	Wed Aug 28 16:36:45 2002
+++ linux-2.4.20-pre5/arch/mips64/mm/fault.c	Wed Aug 28 16:37:26 2002
@@ -236,12 +236,11 @@
  * us unable to handle the page fault gracefully.
  */
 out_of_memory:
-	up_read(&mm->mmap_sem);
 	if (tsk->pid == 1) {
 		yield();
-		down_read(&mm->mmap_sem);
 		goto survive;
 	}
+	up_read(&mm->mmap_sem);
 	printk(KERN_NOTICE "VM: killing process %s\n", tsk->comm);
 	if (user_mode(regs))
 		do_exit(SIGKILL);
diff -urN linux-2.4.20-pre4/arch/parisc/config.in linux-2.4.20-pre5/arch/parisc/config.in
--- linux-2.4.20-pre4/arch/parisc/config.in	Wed Aug 28 16:36:45 2002
+++ linux-2.4.20-pre5/arch/parisc/config.in	Wed Aug 28 16:37:26 2002
@@ -16,98 +16,106 @@
 endmenu
 
 mainmenu_option next_comment
+comment 'Loadable module support'
+bool 'Enable loadable module support' CONFIG_MODULES
+if [ "$CONFIG_MODULES" = "y" ] ; then
+  bool 'Set version information on all module symbols' CONFIG_MODVERSIONS
+  bool 'Kernel module loader' CONFIG_KMOD
+fi
+endmenu
+
+mainmenu_option next_comment
+comment 'Processor type'
+choice 'Processor family' \
+	"PA7000/PA7100		CONFIG_PA7100 \
+	 PA7200			CONFIG_PA7200 \
+	 PA7100LC/PA7300LC	CONFIG_PA7100LC \
+	 PA8x00			CONFIG_PA8X00" PA7000
+
+if [ "$CONFIG_PA8X00" = "y" ] ; then
+   define_bool CONFIG_PA20 y
+   bool '64-bit kernel' CONFIG_PARISC64
+   dep_bool '32-bit PDC' CONFIG_PDC_NARROW $CONFIG_PARISC64
+else
+   define_bool CONFIG_PA11 y
+fi
+endmenu
+
+mainmenu_option next_comment
 comment 'General options'
 
-# bool 'Symmetric multi-processing support' CONFIG_SMP
-define_bool CONFIG_SMP n
+bool 'Symmetric multi-processing support' CONFIG_SMP
+bool 'Chassis LCD and LED support' CONFIG_CHASSIS_LCD_LED
 
 bool 'Kernel Debugger support' CONFIG_KWDB
 # define_bool CONFIG_KWDB n
 
-# bool 'GSC/Gecko bus support' CONFIG_GSC y
-define_bool CONFIG_GSC y
-
-bool 'U2/Uturn I/O MMU' CONFIG_IOMMU_CCIO y
-bool 'LASI I/O support' CONFIG_GSC_LASI y
-
-bool 'PCI bus support' CONFIG_PCI y
+bool 'U2/Uturn I/O MMU' CONFIG_IOMMU_CCIO
+bool 'VSC/GSC/HSC bus support' CONFIG_GSC
+dep_bool '  Lasi I/O support' CONFIG_GSC_LASI $CONFIG_GSC
+dep_bool '  Wax I/O support' CONFIG_GSC_WAX $CONFIG_GSC
+
+dep_bool 'EISA support' CONFIG_EISA $CONFIG_GSC
+define_bool CONFIG_ISA $CONFIG_EISA
+bool 'PCI support' CONFIG_PCI
 
 if [ "$CONFIG_PCI" = "y" ]; then
-	bool 'GSCtoPCI/DINO PCI support' CONFIG_GSC_DINO y
-	bool 'LBA/Elroy PCI support' CONFIG_PCI_LBA n
-fi 
+   dep_bool '  GSCtoPCI/Dino PCI support' CONFIG_GSC_DINO $CONFIG_GSC
+   bool '  LBA/Elroy PCI support' CONFIG_PCI_LBA
+   define_bool CONFIG_IOSAPIC $CONFIG_PCI_LBA
+   define_bool CONFIG_IOMMU_SBA $CONFIG_PCI_LBA
 
-if [ "$CONFIG_PCI_LBA" = "y" ]; then
-	define_bool CONFIG_IOSAPIC y
-	define_bool CONFIG_IOMMU_SBA y
-fi
+#   bool '  EPIC PCI support' CONFIG_PCI_EPIC n
+   bool '  SuperIO support' CONFIG_SUPERIO
+fi 
 
-#
-# if [ "$CONFIG_PCI_EPIC" = "y" ]; then...
-#
+source drivers/pci/Config.in
 
 endmenu
 
 mainmenu_option next_comment
-comment 'Loadable module support'
-bool 'Enable loadable module support' CONFIG_MODULES
-if [ "$CONFIG_MODULES" = "y" ]; then
-  bool 'Set version information on all module symbols' CONFIG_MODVERSIONS
-  bool 'Kernel module loader' CONFIG_KMOD
-fi
-endmenu
-
-mainmenu_option next_comment
 comment 'General setup'
 
+bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG
+
 bool 'Networking support' CONFIG_NET
 
 bool 'System V IPC' CONFIG_SYSVIPC
 bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
 bool 'Sysctl support' CONFIG_SYSCTL
-tristate 'Kernel support for SOM binaries' CONFIG_BINFMT_SOM
+define_bool CONFIG_KCORE_ELF y
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
+tristate 'Kernel support for SOM binaries' CONFIG_BINFMT_SOM
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  tristate 'Kernel support for JAVA binaries (obsolete)' CONFIG_BINFMT_JAVA
-fi
+
+# anyone want to get ACPI working on PA/RISC?
+define_bool CONFIG_PM n
 
 endmenu
 
-##source drivers/parport/Config.in
-mainmenu_option next_comment
-comment 'Parallel port support'
+source drivers/parport/Config.in
 
-tristate 'Parallel port support' CONFIG_PARPORT
-if [ "$CONFIG_PARPORT" != "n" ]; then
-   if [ "$CONFIG_PCI" = "y" ]; then
-     dep_tristate '  PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT
-     if [ "$CONFIG_PARPORT_PC" != "n" ]; then
-        bool '    Use FIFO/DMA if available' CONFIG_PARPORT_PC_FIFO
-        if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-           bool '    SuperIO chipset support (EXPERIMENTAL)' CONFIG_PARPORT_PC_SUPERIO
-        fi
-     fi
-   fi
-   if [ "$CONFIG_GSC_LASI" = "y" ]; then
-      dep_tristate '  LASI/ASP builtin parallel-port' CONFIG_PARPORT_GSC $CONFIG_PARPORT
-   else
-      define_tristate CONFIG_PARPORT_GSC n
-   fi
+source drivers/block/Config.in
 
-   # If exactly one hardware type is selected then parport will optimise away
-   # support for loading any others.  Defeat this if the user is keen.
-   bool '  Support foreign hardware' CONFIG_PARPORT_OTHER
+source drivers/md/Config.in
 
-   bool '  IEEE 1284 transfer modes' CONFIG_PARPORT_1284
+if [ "$CONFIG_NET" = "y" ]; then
+   source net/Config.in
 fi
-endmenu
 
+if [ "$CONFIG_SUPERIO" = "y" ]; then
+    mainmenu_option next_comment
+    comment 'ATA/IDE/MFM/RLL support'
 
-source drivers/block/Config.in
+    tristate 'ATA/IDE/MFM/RLL support' CONFIG_IDE
 
-if [ "$CONFIG_NET" = "y" ]; then
-  source net/Config.in
+    if [ "$CONFIG_IDE" != "n" ]; then
+      source drivers/ide/Config.in
+    else
+      define_bool CONFIG_BLK_DEV_IDE_MODES n
+      define_bool CONFIG_BLK_DEV_HD n
+    fi
+    endmenu
 fi
 
 mainmenu_option next_comment
@@ -116,90 +124,70 @@
 tristate 'SCSI support' CONFIG_SCSI
 
 if [ "$CONFIG_SCSI" != "n" ]; then
-  comment 'SCSI support type (disk, tape, CDrom)'
-
-  dep_tristate 'SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI
-  if [ "$CONFIG_BLK_DEV_SD" != "n" ]; then
-    int  'Maximum number of SCSI disks that can be loaded as modules' CONFIG_SD_EXTRA_DEVS 40
-  fi
-
-  dep_tristate 'SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI
-  dep_tristate 'SCSI CDROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI
-  if [ "$CONFIG_BLK_DEV_SR" != "n" ]; then
-    bool '  Enable vendor-specific extensions (for SCSI CDROM)' CONFIG_BLK_DEV_SR_VENDOR
-    int  'Maximum number of CDROM devices that can be loaded as modules' CONFIG_SR_EXTRA_DEVS 2
-  fi
-  dep_tristate 'SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI
-
-  comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs'
-  bool 'Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN
-  bool 'Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS
-
-  mainmenu_option next_comment
-  comment 'SCSI low-level drivers'
-  if [ "$CONFIG_GSC_LASI" = "y" ]; then
-    dep_tristate 'Lasi SCSI support' CONFIG_SCSI_LASI $CONFIG_SCSI
-    dep_tristate 'Zalon SCSI support' CONFIG_SCSI_ZALON $CONFIG_SCSI
-  fi
-  if [ "$CONFIG_PCI" = "y" ]; then
-    dep_tristate 'SYM53C8XX SCSI support' CONFIG_SCSI_SYM53C8XX $CONFIG_SCSI
-  fi
-  if [ "$CONFIG_SCSI_ZALON" != "n" -o "$CONFIG_SCSI_SYM53C8XX" != "n" ]; then
-    int  '  default tagged command queue depth' CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS 8
-    int  '  maximum number of queued commands' CONFIG_SCSI_NCR53C8XX_MAX_TAGS 32
-    int  '  synchronous transfers frequency in MHz' CONFIG_SCSI_NCR53C8XX_SYNC 20
-    bool '  enable profiling' CONFIG_SCSI_NCR53C8XX_PROFILE
-    bool '  use normal IO' CONFIG_SCSI_NCR53C8XX_IOMAPPED
-  fi
-  endmenu
+   source drivers/scsi/Config.in
 fi
 endmenu
 
 if [ "$CONFIG_NET" = "y" ]; then
-  mainmenu_option next_comment
-  comment 'Network device support'
+   mainmenu_option next_comment
+   comment 'Network device support'
 
-  bool 'Network device support' CONFIG_NETDEVICES
+   bool 'Network device support' CONFIG_NETDEVICES
 
-  if [ "$CONFIG_NETDEVICES" = "y" ]; then
-    if [ "$CONFIG_GSC_LASI" = "y" ]; then
-      tristate 'Lasi ethernet' CONFIG_LASI_82596
-    fi
-    source drivers/net/Config.in
-  fi
-  endmenu
+   if [ "$CONFIG_NETDEVICES" = "y" ]; then
+      source drivers/net/Config.in
+      if [ "$CONFIG_ATM" = "y" ]; then
+         source drivers/atm/Config.in
+      fi
+   fi
+   endmenu
 fi
 
+#
+# input before char - char/joystick depends on it. As does USB.
+#
+source drivers/input/Config.in
 source drivers/char/Config.in
+source drivers/hil/Config.in
+
+source drivers/media/Config.in
 
 source fs/Config.in
 
+if [ "$CONFIG_VT" = "y" ]; then
+   mainmenu_option next_comment
+   comment 'Console drivers'
+   source drivers/video/Config.in
+
+   bool 'STI console' CONFIG_STI_CONSOLE
+   if [ "$CONFIG_GSC_PS2" = "y" ]; then
+      define_bool CONFIG_DUMMY_CONSOLE y
+   fi
+   if [ "$CONFIG_STI_CONSOLE" = "y" ]; then
+      define_bool CONFIG_DUMMY_CONSOLE y
+      define_bool CONFIG_FBCON y
+      define_bool CONFIG_FBCON_FONT y
+#      define_bool CONFIG_FBCON_FONTWIDTH8_ONLY n
+      define_bool CONFIG_FONT_8x8 y
+      define_bool CONFIG_FONT_8x16 y
+      define_bool CONFIG_FONT_6x11 y
+      define_bool CONFIG_FONT_SUN12x22 y
+   fi
+   endmenu
+fi
+
 mainmenu_option next_comment
-comment 'Sound Drivers'
+comment 'Sound'
+
 tristate 'Sound card support' CONFIG_SOUND
 if [ "$CONFIG_SOUND" != "n" ]; then
    source drivers/sound/Config.in
 fi
 endmenu
 
-if [ "$CONFIG_VT" = "y" ]; then
-  mainmenu_option next_comment
-  comment 'Console drivers'
-  source drivers/video/Config.in
-
-#  bool 'IODC console' CONFIG_IODC_CONSOLE
-  bool 'STI console' CONFIG_STI_CONSOLE
-  if [ "$CONFIG_IODC_CONSOLE" = "n" ]; then
-    if [ "$CONFIG_GSC_PS2" = "y" ]; then
-      define_bool CONFIG_DUMMY_CONSOLE y
-    fi
-  fi
-  if [ "$CONFIG_STI_CONSOLE" = "y" ]; then
-    define_bool CONFIG_DUMMY_CONSOLE y
-  fi
-  endmenu
+if [ "$CONFIG_SUPERIO" = "y" ]; then
+    source drivers/usb/Config.in
 fi
-# endmenu
 
 mainmenu_option next_comment
 comment 'Kernel hacking'
diff -urN linux-2.4.20-pre4/arch/ppc/Makefile linux-2.4.20-pre5/arch/ppc/Makefile
--- linux-2.4.20-pre4/arch/ppc/Makefile	Wed Aug 28 16:36:45 2002
+++ linux-2.4.20-pre5/arch/ppc/Makefile	Wed Aug 28 16:37:27 2002
@@ -42,6 +42,11 @@
 CFLAGS := $(CFLAGS) -Wa,-mppc64bridge
 endif
 
+ifdef CONFIG_MORE_COMPILE_OPTIONS
+# Use sed to remove the quotes.
+  CFLAGS += $(shell echo $(CONFIG_COMPILE_OPTIONS) | sed -e 's/"//g')
+endif
+
 ifdef CONFIG_4xx
   HEAD := arch/ppc/kernel/head_4xx.o
 else
diff -urN linux-2.4.20-pre4/arch/ppc/amiga/amiints.c linux-2.4.20-pre5/arch/ppc/amiga/amiints.c
--- linux-2.4.20-pre4/arch/ppc/amiga/amiints.c	Mon May 21 17:04:46 2001
+++ linux-2.4.20-pre5/arch/ppc/amiga/amiints.c	Wed Aug 28 16:37:27 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.amiints.c 1.8 05/21/01 00:48:24 cort
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  * linux/arch/m68k/amiga/amiints.c -- Amiga Linux interrupt handling code
@@ -42,6 +42,8 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/kernel_stat.h>
 #include <linux/init.h>
 
@@ -63,9 +65,6 @@
 extern void cia_init_IRQ(struct ciabase *base);
 extern int cia_get_irq_list(struct ciabase *base, char *buf);
 
-/* irq node variables for amiga interrupt sources */
-static irq_node_t *ami_irq_list[AMI_STD_IRQS];
-
 unsigned short ami_intena_vals[AMI_STD_IRQS] = {
 	IF_VERTB, IF_COPER, IF_AUD0, IF_AUD1, IF_AUD2, IF_AUD3, IF_BLIT,
 	IF_DSKSYN, IF_DSKBLK, IF_RBF, IF_TBE, IF_SOFT, IF_PORTS, IF_EXTER
@@ -78,7 +77,7 @@
 
 static void ami_badint(int irq, void *dev_id, struct pt_regs *fp)
 {
-	num_spurious += 1;
+/*	num_spurious += 1;*/
 }
 
 /*
@@ -97,25 +96,12 @@
 {
 	int i;
 
-	/* initialize handlers */
-	for (i = 0; i < AMI_STD_IRQS; i++) {
-		if (ami_servers[i]) {
-			ami_irq_list[i] = NULL;
-		} else {
-			ami_irq_list[i] = new_irq_node();
-			ami_irq_list[i]->handler = ami_badint;
-			ami_irq_list[i]->flags   = 0;
-			ami_irq_list[i]->dev_id  = NULL;
-			ami_irq_list[i]->devname = NULL;
-			ami_irq_list[i]->next    = NULL;
-		}
-	}
 	for (i = 0; i < AMI_IRQS; i++)
 		ami_ablecount[i] = 0;
 
 	/* turn off PCMCIA interrupts */
 	if (AMIGAHW_PRESENT(PCMCIA))
-		pcmcia_disable_irq();
+		gayle.inten = GAYLE_IRQ_IDE;
 
 	/* turn off all interrupts... */
 	custom.intena = 0x7fff;
@@ -138,152 +124,6 @@
 	cia_init_IRQ(&ciab_base);
 }
 
-static inline int amiga_insert_irq(irq_node_t **list, irq_node_t *node)
-{
-	unsigned long flags;
-	irq_node_t *cur;
-
-	if (!node->dev_id)
-		printk("%s: Warning: dev_id of %s is zero\n",
-		       __FUNCTION__, node->devname);
-
-	save_flags(flags);
-	cli();
-
-	cur = *list;
-
-	if (node->flags & SA_INTERRUPT) {
-		if (node->flags & SA_SHIRQ)
-			return -EBUSY;
-		/*
-		 * There should never be more than one
-		 */
-		while (cur && cur->flags & SA_INTERRUPT) {
-			list = &cur->next;
-			cur = cur->next;
-		}
-	} else {
-		while (cur) {
-			list = &cur->next;
-			cur = cur->next;
-		}
-	}
-
-	node->next = cur;
-	*list = node;
-
-	restore_flags(flags);
-	return 0;
-}
-
-static inline void amiga_delete_irq(irq_node_t **list, void *dev_id)
-{
-	unsigned long flags;
-	irq_node_t *node;
-
-	save_flags(flags);
-	cli();
-
-	for (node = *list; node; list = &node->next, node = *list) {
-		if (node->dev_id == dev_id) {
-			*list = node->next;
-			/* Mark it as free. */
-			node->handler = NULL;
-			restore_flags(flags);
-			return;
-		}
-	}
-	restore_flags(flags);
-	printk ("%s: tried to remove invalid irq\n", __FUNCTION__);
-}
-
-/*
- * amiga_request_irq : add an interrupt service routine for a particular
- *                     machine specific interrupt source.
- *                     If the addition was successful, it returns 0.
- */
-
-int amiga_request_irq(unsigned int irq,
-		      void (*handler)(int, void *, struct pt_regs *),
-                      unsigned long flags, const char *devname, void *dev_id)
-{
-	irq_node_t *node;
-	int error = 0;
-
-	if (irq >= AMI_IRQS) {
-		printk ("%s: Unknown IRQ %d from %s\n", __FUNCTION__,
-			irq, devname);
-		return -ENXIO;
-	}
-
-	if (irq >= IRQ_AMIGA_AUTO)
-		return sys_request_irq(irq - IRQ_AMIGA_AUTO, handler,
-		                       flags, devname, dev_id);
-
-	if (irq >= IRQ_AMIGA_CIAA)
-		return cia_request_irq(irq, handler, flags, devname, dev_id);
-
-	/*
-	 * IRQ_AMIGA_PORTS & IRQ_AMIGA_EXTER defaults to shared,
-	 * we could add a check here for the SA_SHIRQ flag but all drivers
-	 * should be aware of sharing anyway.
-	 */
-	if (ami_servers[irq]) {
-		if (!(node = new_irq_node()))
-			return -ENOMEM;
-		node->handler = handler;
-		node->flags   = flags;
-		node->dev_id  = dev_id;
-		node->devname = devname;
-		node->next    = NULL;
-		error = amiga_insert_irq(&ami_irq_list[irq], node);
-	} else {
-		ami_irq_list[irq]->handler = handler;
-		ami_irq_list[irq]->flags   = flags;
-		ami_irq_list[irq]->dev_id  = dev_id;
-		ami_irq_list[irq]->devname = devname;
-	}
-
-	/* enable the interrupt */
-	if (irq < IRQ_AMIGA_PORTS && !ami_ablecount[irq])
-		custom.intena = IF_SETCLR | ami_intena_vals[irq];
-
-	return error;
-}
-
-void amiga_free_irq(unsigned int irq, void *dev_id)
-{
-	if (irq >= AMI_IRQS) {
-		printk ("%s: Unknown IRQ %d\n", __FUNCTION__, irq);
-		return;
-	}
-
-	if (irq >= IRQ_AMIGA_AUTO) {
-		sys_free_irq(irq - IRQ_AMIGA_AUTO, dev_id);
-		return;
-	}
-	if (irq >= IRQ_AMIGA_CIAA) {
-		cia_free_irq(irq, dev_id);
-		return;
-	}
-
-	if (ami_servers[irq]) {
-		amiga_delete_irq(&ami_irq_list[irq], dev_id);
-		/* if server list empty, disable the interrupt */
-		if (!ami_irq_list[irq] && irq < IRQ_AMIGA_PORTS)
-			custom.intena = ami_intena_vals[irq];
-	} else {
-		if (ami_irq_list[irq]->dev_id != dev_id)
-			printk("%s: removing probably wrong IRQ %d from %s\n",
-			       __FUNCTION__, irq, ami_irq_list[irq]->devname);
-		ami_irq_list[irq]->handler = ami_badint;
-		ami_irq_list[irq]->flags   = 0;
-		ami_irq_list[irq]->dev_id  = NULL;
-		ami_irq_list[irq]->devname = NULL;
-		custom.intena = ami_intena_vals[irq];
-	}
-}
-
 /*
  * Enable/disable a particular machine specific interrupt source.
  * Note that this may affect other interrupts in case of a shared interrupt.
@@ -350,20 +190,24 @@
 
 inline void amiga_do_irq(int irq, struct pt_regs *fp)
 {
-	kstat.irqs[0][SYS_IRQS + irq]++;
-	ami_irq_list[irq]->handler(irq, ami_irq_list[irq]->dev_id, fp);
+	irq_desc_t *desc = irq_desc + irq;
+	struct irqaction *action = desc->action;
+
+	kstat.irqs[0][irq]++;
+	action->handler(irq, action->dev_id, fp);
 }
 
 void amiga_do_irq_list(int irq, struct pt_regs *fp)
 {
-	irq_node_t *node;
+	irq_desc_t *desc = irq_desc + irq;
+	struct irqaction *action;
 
-	kstat.irqs[0][SYS_IRQS + irq]++;
+	kstat.irqs[0][irq]++;
 
 	custom.intreq = ami_intena_vals[irq];
 
-	for (node = ami_irq_list[irq]; node; node = node->next)
-		node->handler(irq, node->dev_id, fp);
+	for (action = desc->action; action; action = action->next)
+		action->handler(irq, action->dev_id, fp);
 }
 
 /*
@@ -469,9 +313,15 @@
 /* The PPC irq handling links all handlers requested on the same vector
    and executes them in a loop. Having ami_badint at the end of the chain
    is a bad idea. */
-void (*amiga_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = {
-	NULL, ami_int1, NULL, ami_int3,
-	ami_int4, ami_int5, NULL, ami_int7
+struct irqaction amiga_sys_irqaction[AUTO_IRQS] = {
+	{ handler: ami_badint, name: "spurious int" },
+	{ handler: ami_int1, name: "int1 handler" },
+	{ 0, /* CIAA */ },
+	{ handler: ami_int3, name: "int3 handler" },
+	{ handler: ami_int4, name: "int4 handler" },
+	{ handler: ami_int5, name: "int5 handler" },
+	{ 0, /* CIAB */ },
+	{ handler: ami_int7, name: "int7 handler" },
 };
 #else
 void (*amiga_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = {
@@ -479,29 +329,3 @@
 	ami_int4, ami_int5, ami_badint, ami_int7
 };
 #endif
-
-int amiga_get_irq_list(char *buf)
-{
-	int i, len = 0;
-	irq_node_t *node;
-
-	for (i = 0; i < AMI_STD_IRQS; i++) {
-		if (!(node = ami_irq_list[i]))
-			continue;
-		len += sprintf(buf+len, "ami  %2d: %10u ", i,
-		               kstat.irqs[0][SYS_IRQS + i]);
-		do {
-			if (node->flags & SA_INTERRUPT)
-				len += sprintf(buf+len, "F ");
-			else
-				len += sprintf(buf+len, "  ");
-			len += sprintf(buf+len, "%s\n", node->devname);
-			if ((node = node->next))
-				len += sprintf(buf+len, "                    ");
-		} while (node);
-	}
-
-	len += cia_get_irq_list(&ciaa_base, buf+len);
-	len += cia_get_irq_list(&ciab_base, buf+len);
-	return len;
-}
diff -urN linux-2.4.20-pre4/arch/ppc/amiga/cia.c linux-2.4.20-pre5/arch/ppc/amiga/cia.c
--- linux-2.4.20-pre4/arch/ppc/amiga/cia.c	Mon May 21 17:04:46 2001
+++ linux-2.4.20-pre5/arch/ppc/amiga/cia.c	Wed Aug 28 16:37:27 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.cia.c 1.7 05/21/01 00:48:24 cort
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  *  linux/arch/m68k/amiga/cia.c - CIA support
@@ -16,7 +16,8 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
-#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/kernel_stat.h>
 #include <linux/init.h>
 
@@ -30,7 +31,6 @@
 	u_short int_mask;
 	int handler_irq, cia_irq, server_irq;
 	char *name;
-	irq_handler_t irq_list[CIA_IRQS];
 } ciaa_base = {
 	&ciaa, 0, 0, IF_PORTS,
 	IRQ_AMIGA_AUTO_2, IRQ_AMIGA_CIAA,
@@ -99,15 +99,13 @@
 }
 
 /*
- *  Enable or disable CIA interrupts, return old interrupt mask,
- *  interrupts will only be enabled if a handler exists
+ *  Enable or disable CIA interrupts, return old interrupt mask.
  */
 
 static unsigned char cia_able_irq_private(struct ciabase *base,
 					  unsigned char mask)
 {
-	u_char old, tmp;
-	int i;
+	u_char old;
 
 	old = base->icr_mask;
 	base->icr_data |= base->cia->icr;
@@ -117,12 +115,7 @@
 	else
 		base->icr_mask &= ~mask;
 	base->icr_mask &= CIA_ICR_ALL;
-	for (i = 0, tmp = 1; i < CIA_IRQS; i++, tmp <<= 1) {
-		if ((tmp & base->icr_mask) && !base->irq_list[i].handler) {
-			base->icr_mask &= ~tmp;
-			base->cia->icr = tmp;
-		}
-	}
+
 	if (base->icr_data & base->icr_mask)
 		custom.intreq = IF_SETCLR | base->int_mask;
 	return old;
@@ -144,94 +137,45 @@
 	return cia_able_irq_private(base, mask);
 }
 
-int cia_request_irq(unsigned int irq,
-                    void (*handler)(int, void *, struct pt_regs *),
-                    unsigned long flags, const char *devname, void *dev_id)
-{
-	u_char mask;
-	struct ciabase *base;
-
-	CIA_SET_BASE_ADJUST_IRQ(base, irq);
-
-	base->irq_list[irq].handler = handler;
-	base->irq_list[irq].flags   = flags;
-	base->irq_list[irq].dev_id  = dev_id;
-	base->irq_list[irq].devname = devname;
-
-	/* enable the interrupt */
-	mask = 1 << irq;
-	cia_set_irq_private(base, mask);
-	cia_able_irq_private(base, CIA_ICR_SETCLR | mask);
-	return 0;
-}
-
-void cia_free_irq(unsigned int irq, void *dev_id)
-{
-	struct ciabase *base;
-
-	CIA_SET_BASE_ADJUST_IRQ(base, irq);
-
-	if (base->irq_list[irq].dev_id != dev_id)
-		printk("%s: removing probably wrong IRQ %i from %s\n",
-		       __FUNCTION__, base->cia_irq + irq,
-		       base->irq_list[irq].devname);
-
-	base->irq_list[irq].handler = NULL;
-	base->irq_list[irq].flags   = 0;
-
-	cia_able_irq_private(base, 1 << irq);
-}
-
 static void cia_handler(int irq, void *dev_id, struct pt_regs *fp)
 {
 	struct ciabase *base = (struct ciabase *)dev_id;
-	int mach_irq, i;
+	irq_desc_t *desc;
+	struct irqaction *action;
+	int i;
 	unsigned char ints;
 
-	mach_irq = base->cia_irq;
-	irq = SYS_IRQS + mach_irq;
+	irq = base->cia_irq;
+	desc = irq_desc + irq;
 	ints = cia_set_irq_private(base, CIA_ICR_ALL);
 	custom.intreq = base->int_mask;
-	for (i = 0; i < CIA_IRQS; i++, irq++, mach_irq++) {
+	for (i = 0; i < CIA_IRQS; i++, irq++) {
 		if (ints & 1) {
 			kstat.irqs[0][irq]++;
-			base->irq_list[i].handler(mach_irq, base->irq_list[i].dev_id, fp);
+			action = desc->action;
+			action->handler(irq, action->dev_id, fp);
 		}
 		ints >>= 1;
+		desc++;
 	}
 	amiga_do_irq_list(base->server_irq, fp);
 }
 
 void __init cia_init_IRQ(struct ciabase *base)
 {
-	int i;
-
-	/* init isr handlers */
-	for (i = 0; i < CIA_IRQS; i++) {
-		base->irq_list[i].handler = NULL;
-		base->irq_list[i].flags   = 0;
-	}
+	extern struct irqaction amiga_sys_irqaction[AUTO_IRQS];
+	struct irqaction *action;
 
 	/* clear any pending interrupt and turn off all interrupts */
 	cia_set_irq_private(base, CIA_ICR_ALL);
 	cia_able_irq_private(base, CIA_ICR_ALL);
 
 	/* install CIA handler */
-	request_irq(base->handler_irq, cia_handler, 0, base->name, base);
+	action = &amiga_sys_irqaction[base->handler_irq-IRQ_AMIGA_AUTO];
+	action->handler = cia_handler;
+	action->dev_id = base;
+	action->name = base->name;
+	setup_irq(base->handler_irq, &amiga_sys_irqaction[base->handler_irq-IRQ_AMIGA_AUTO]);
 
 	custom.intena = IF_SETCLR | base->int_mask;
 }
-
-int cia_get_irq_list(struct ciabase *base, char *buf)
-{
-	int i, j, len = 0;
-
-	j = base->cia_irq;
-	for (i = 0; i < CIA_IRQS; i++) {
-		len += sprintf(buf+len, "cia  %2d: %10d ", j + i,
-			       kstat.irqs[0][SYS_IRQS + j + i]);
-			len += sprintf(buf+len, "  ");
-		len += sprintf(buf+len, "%s\n", base->irq_list[i].devname);
-	}
-	return len;
-}
diff -urN linux-2.4.20-pre4/arch/ppc/amiga/config.c linux-2.4.20-pre5/arch/ppc/amiga/config.c
--- linux-2.4.20-pre4/arch/ppc/amiga/config.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc/amiga/config.c	Wed Aug 28 16:37:27 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.config.c 1.12 09/18/01 11:19:06 paulus
+ * BK Id: %F% %I% %G% %U% %#%
  */
 #define m68k_debug_device debug_device
 
@@ -411,16 +411,16 @@
   mach_keyb_init       = amiga_keyb_init;
   mach_kbdrate         = amiga_kbdrate;
   mach_init_IRQ        = amiga_init_IRQ;
-  mach_default_handler = &amiga_default_handler;
 #ifndef CONFIG_APUS
+  mach_default_handler = &amiga_default_handler;
   mach_request_irq     = amiga_request_irq;
   mach_free_irq        = amiga_free_irq;
   enable_irq           = amiga_enable_irq;
   disable_irq          = amiga_disable_irq;
+  mach_get_irq_list    = amiga_get_irq_list;
 #endif
   mach_get_model       = amiga_get_model;
   mach_get_hardware_list = amiga_get_hardware_list;
-  mach_get_irq_list    = amiga_get_irq_list;
   mach_gettimeoffset   = amiga_gettimeoffset;
   if (AMIGAHW_PRESENT(A3000_CLK)){
     mach_gettod  = a3000_gettod;
diff -urN linux-2.4.20-pre4/arch/ppc/boot/Makefile linux-2.4.20-pre5/arch/ppc/boot/Makefile
--- linux-2.4.20-pre4/arch/ppc/boot/Makefile	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc/boot/Makefile	Wed Aug 28 16:37:27 2002
@@ -31,6 +31,7 @@
 subdir-$(CONFIG_ALL_PPC)	:= chrp pmac prep
 tools-$(CONFIG_ALL_PPC)		:= addnote mknote hack-coff mkprep
 tools-$(CONFIG_4xx)		:= mktree
+tools-$(CONFIG_SPRUCE)		:= mktree
 
 # These are dirs we don't want to go into on BOOT_TARGETS.  We have them for
 # the 'depend' stage.
diff -urN linux-2.4.20-pre4/arch/ppc/boot/simple/Makefile linux-2.4.20-pre5/arch/ppc/boot/simple/Makefile
--- linux-2.4.20-pre4/arch/ppc/boot/simple/Makefile	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc/boot/simple/Makefile	Wed Aug 28 16:37:28 2002
@@ -3,11 +3,16 @@
 #
 # Author: Tom Rini <trini@mvista.com>
 #
-# Copyright 2001 MontaVista Software Inc.
+# Copyright 2001-2002 MontaVista Software Inc.
 #
-# Notes: For machine targets which produce more than one image, define
+# Notes:
+# (1) For machine targets which produce more than one image, define
 # ZNETBOOT and ZNETBOOTRD to the image which should be available for
 # 'znetboot' and 'znetboot.initrd`
+# (2) For machine targets which use the mktree program, define END to be
+# the machine name you want in the image, and you can optionally set
+# ENTRYPOINT which the image should be loaded at.  The optimal setting
+# for ENTRYPOINT is the link address.
 #
 # This program is free software; you can redistribute  it and/or modify it
 # under  the terms of  the GNU General  Public License as published by the
@@ -28,9 +33,24 @@
 ifeq ($(CONFIG_GEMINI),y)
 ZIMAGE				:= zImage-SMON
 ZIMAGEINITRD			:= zImage.initrd-SMON
-HEADHELP			:= direct.o
+EXTRA				:= direct.o
 TFTPIMAGE			:= /tftpboot/zImage.gemini
 endif
+ifeq ($(CONFIG_PAL4),y)
+ZIMAGE				:= zImage-PAL4
+ZIMAGEINITRD			:= zImage.initrd-PAL4
+EXTRA				:= direct.o
+TFTPIMAGE			:= /tftpboot/zImage.pal4
+endif
+ifeq ($(CONFIG_SPRUCE),y)
+ZIMAGE				:= zImage-TREE
+ZIMAGEINITRD			:= zImage.initrd-TREE
+EXTRA				:= direct.o
+ENTRYPOINT			:= 0x00800000
+MISC				:= misc-spruce.o
+END				:= spruce
+TFTPIMAGE			:= /tftpboot/zImage.$(END)
+endif
 ifeq ($(CONFIG_SMP),y)
 TFTPIMAGE			+= .smp
 endif
@@ -46,7 +66,7 @@
 OBJCOPY_ARGS			:= -O elf32-powerpc
 
 # head.o and ../common/relocate.o must be at the start.
-obj-y				:= head.o ../common/relocate.o $(HEADHELP) \
+obj-y				:= head.o ../common/relocate.o $(EXTRA) \
 				$(MISC) ../common/misc-common.o \
 				../common/string.o ../common/util.o
 obj-$(CONFIG_4xx)		+= embed_config.o
@@ -69,10 +89,6 @@
 MKPREP				:= ../utils/mkprep
 MKTREE				:= ../utils/mktree
 
-AFLAGS_head.o			+= -I$(TOPDIR)/arch/$(ARCH)/kernel
-AFLAGS_../common/util.o		+= -I$(TOPDIR)/arch/$(ARCH)/kernel
-AFLAGS_../common/relocate.o	+= -I$(TOPDIR)/arch/$(ARCH)/kernel
-
 zvmlinux: $(obj-y) $(LIBS) ../ld.script ../images/vmlinux.gz ../common/dummy.o
 	$(OBJCOPY) $(OBJCOPY_ARGS) \
 		--add-section=.image=../images/vmlinux.gz \
@@ -120,6 +136,12 @@
 zImage.initrd-EMBEDDED: zvmlinux.initrd
 	mv zvmlinux.initrd ../images/zImage.initrd.embedded
 
+zImage-PAL4: zvmlinux
+	cp zvmlinux ../images/zImage.pal4
+
+zImage.initrd-PAL4: zvmlinux.initrd
+	cp zvmlinux.initrd ../images/zImage.initrd.pal4
+
 zImage-SMON: zvmlinux
 	dd if=zvmlinux of=../images/zImage.gemini skip=64 bs=1k
 
@@ -127,9 +149,9 @@
 	dd if=zvmlinux.initrd of=../images/zImage.initrd.gemini skip=64 bs=1k
 
 zImage-TREE: zvmlinux
-	$(MKTREE) zvmlinux ../images/zImage.treeboot
+	$(MKTREE) zvmlinux ../images/zImage.$(END) $(ENTRYPOINT)
 
 zImage.initrd-TREE: zvmlinux.initrd
-	$(MKTREE) zvmlinux.initrd ../images/zImage.initrd.treeboot
+	$(MKTREE) zvmlinux.initrd ../images/zImage.initrd.$(END) $(ENTRYPOINT)
 
 include $(TOPDIR)/Rules.make
diff -urN linux-2.4.20-pre4/arch/ppc/boot/simple/misc-spruce.c linux-2.4.20-pre5/arch/ppc/boot/simple/misc-spruce.c
--- linux-2.4.20-pre4/arch/ppc/boot/simple/misc-spruce.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre5/arch/ppc/boot/simple/misc-spruce.c	Wed Aug 28 16:37:28 2002
@@ -0,0 +1,440 @@
+/*
+ * arch/ppc/boot/spruce/misc.c
+ *
+ * Misc. bootloader code for IBM Spruce reference platform
+ *
+ * Authors: Johnnie Peters <jpeters@mvista.com>
+ *	    Matt Porter <mporter@mvista.com>
+ *
+ * Derived from arch/ppc/boot/prep/misc.c
+ *
+ * Copyright 2000-2001 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED
+ * WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ * NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ * USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the  GNU General Public License along
+ * with this program; if not, write  to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/types.h>
+#include <linux/elf.h>
+#include <linux/config.h>
+#include <linux/pci.h>
+
+#include <asm/page.h>
+#include <asm/processor.h>
+#include <asm/mmu.h>
+#include <asm/bootinfo.h>
+
+#include "zlib.h"
+
+/* Define some important locations of the Spruce. */
+#define SPRUCE_PCI_CONFIG_ADDR	0xfec00000
+#define SPRUCE_PCI_CONFIG_DATA	0xfec00004
+#define SPRUCE_ISA_IO_BASE	0xf8000000
+
+unsigned long com_port;
+
+char *avail_ram;
+char *end_avail;
+
+/* The linker tells us where the image is. */
+extern char __image_begin, __image_end;
+extern char __ramdisk_begin, __ramdisk_end;
+extern char _end[];
+
+#ifdef CONFIG_CMDLINE
+#define CMDLINE CONFIG_CMDLINE
+#else
+#define CMDLINE ""
+#endif
+char cmd_preset[] = CMDLINE;
+char cmd_buf[256];
+char *cmd_line = cmd_buf;
+
+unsigned long initrd_size = 0;
+
+char *zimage_start;
+int zimage_size;
+
+extern void udelay(long);
+extern void puts(const char *);
+extern void putc(const char c);
+extern void puthex(unsigned long val);
+extern int getc(void);
+extern int tstc(void);
+extern void gunzip(void *, int, unsigned char *, int *);
+
+extern unsigned long serial_init(int chan, void *ignored);
+
+/* PCI configuration space access routines. */
+unsigned int *pci_config_address = (unsigned int *)SPRUCE_PCI_CONFIG_ADDR;
+unsigned char *pci_config_data   = (unsigned char *)SPRUCE_PCI_CONFIG_DATA;
+
+void cpc700_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+			     unsigned char offset, unsigned char *val)
+{
+	out_le32(pci_config_address,
+		 (((bus & 0xff)<<16) | (dev_fn<<8) | (offset&0xfc) | 0x80000000));
+
+	*val= (in_le32((unsigned *)pci_config_data) >> (8 * (offset & 3))) & 0xff;
+}
+
+void cpc700_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+			     unsigned char offset, unsigned char val)
+{
+	out_le32(pci_config_address,
+		 (((bus & 0xff)<<16) | (dev_fn<<8) | (offset&0xfc) | 0x80000000));
+
+	out_8(pci_config_data + (offset&3), val);
+}
+
+void cpc700_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+			     unsigned char offset, unsigned short *val)
+{
+	out_le32(pci_config_address,
+		 (((bus & 0xff)<<16) | (dev_fn<<8) | (offset&0xfc) | 0x80000000));
+
+	*val= in_le16((unsigned short *)(pci_config_data + (offset&3)));
+}
+
+void cpc700_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+			     unsigned char offset, unsigned short val)
+{
+	out_le32(pci_config_address,
+		 (((bus & 0xff)<<16) | (dev_fn<<8) | (offset&0xfc) | 0x80000000));
+
+	out_le16((unsigned short *)(pci_config_data + (offset&3)), val);
+}
+
+void cpc700_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+			     unsigned char offset, unsigned int *val)
+{
+	out_le32(pci_config_address,
+		 (((bus & 0xff)<<16) | (dev_fn<<8) | (offset&0xfc) | 0x80000000));
+
+	*val= in_le32((unsigned *)pci_config_data);
+}
+
+void cpc700_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+			     unsigned char offset, unsigned int val)
+{
+	out_le32(pci_config_address,
+		 (((bus & 0xff)<<16) | (dev_fn<<8) | (offset&0xfc) | 0x80000000));
+
+	out_le32((unsigned *)pci_config_data, val);
+}
+
+unsigned long isa_io_base = SPRUCE_ISA_IO_BASE;
+
+#define PCNET32_WIO_RDP		0x10
+#define PCNET32_WIO_RAP		0x12
+#define PCNET32_WIO_RESET	0x14
+
+#define PCNET32_DWIO_RDP	0x10
+#define PCNET32_DWIO_RAP	0x14
+#define PCNET32_DWIO_RESET	0x18
+
+/* Processor interface config register access */
+#define PIFCFGADDR 0xff500000
+#define PIFCFGDATA 0xff500004
+
+#define PLBMIFOPT 0x18 /* PLB Master Interface Options */
+
+#define MEM_MBEN	0x24
+#define MEM_TYPE	0x28
+#define MEM_B1SA	0x3c
+#define MEM_B1EA	0x5c
+#define MEM_B2SA	0x40
+#define MEM_B2EA	0x60
+
+unsigned long
+decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum)
+{
+	int timer = 0;
+	char *cp, ch;
+
+	int loop;
+	int csr0;
+	int csr_id;
+	int *mem_addr = (int *)0xff500008;
+	int *mem_data = (int *)0xff50000c;
+	int mem_size = 0;
+	unsigned long mem_mben;
+	unsigned long mem_type;
+	unsigned long mem_start;
+	unsigned long mem_end;
+	int *pif_addr = (int *)0xff500000;
+	int *pif_data = (int *)0xff500004;
+	int pci_devfn;
+	int found_multi = 0;
+	unsigned short vendor;
+	unsigned short device;
+	unsigned short command;
+	unsigned char header_type;
+	unsigned int bar0;
+
+#ifdef CONFIG_SERIAL_CONSOLE
+	/* Initialize the serial console port */
+	com_port = serial_init(0, NULL);
+#endif
+
+	/*
+	 * Gah, these firmware guys need to learn that hardware
+	 * byte swapping is evil! Disable all hardware byte
+	 * swapping so it doesn't hurt anyone.
+	 */
+	*pif_addr = PLBMIFOPT;
+	asm("sync");
+	*pif_data = 0x00000000;
+	asm("sync");
+
+	/* Get the size of memory from the memory controller. */
+	*mem_addr = MEM_MBEN;
+	asm("sync");
+	mem_mben = *mem_data;
+	asm("sync");
+	for(loop = 0; loop < 1000; loop++);
+
+	*mem_addr = MEM_TYPE;
+	asm("sync");
+	mem_type = *mem_data;
+	asm("sync");
+	for(loop = 0; loop < 1000; loop++);
+
+	*mem_addr = MEM_TYPE;
+	/* Confirm bank 1 has DRAM memory */
+	if ((mem_mben & 0x40000000) &&
+				((mem_type & 0x30000000) == 0x10000000)) {
+		*mem_addr = MEM_B1SA;
+		asm("sync");
+		mem_start = *mem_data;
+		asm("sync");
+		for(loop = 0; loop < 1000; loop++);
+
+		*mem_addr = MEM_B1EA;
+		asm("sync");
+		mem_end = *mem_data;
+		asm("sync");
+		for(loop = 0; loop < 1000; loop++);
+
+		mem_size = mem_end - mem_start + 0x100000;
+	}
+
+	/* Confirm bank 2 has DRAM memory */
+	if ((mem_mben & 0x20000000) &&
+				((mem_type & 0xc000000) == 0x4000000)) {
+		*mem_addr = MEM_B2SA;
+		asm("sync");
+		mem_start = *mem_data;
+		asm("sync");
+		for(loop = 0; loop < 1000; loop++);
+
+		*mem_addr = MEM_B2EA;
+		asm("sync");
+		mem_end = *mem_data;
+		asm("sync");
+		for(loop = 0; loop < 1000; loop++);
+
+		mem_size += mem_end - mem_start + 0x100000;
+	}
+
+	/* Search out and turn off the PcNet ethernet boot device. */
+	for (pci_devfn = 1; pci_devfn < 0xff; pci_devfn++) {
+		if (PCI_FUNC(pci_devfn) && !found_multi)
+			continue;
+
+		cpc700_pcibios_read_config_byte(0, pci_devfn,
+				PCI_HEADER_TYPE, &header_type);
+
+		if (!PCI_FUNC(pci_devfn))
+			found_multi = header_type & 0x80;
+
+		cpc700_pcibios_read_config_word(0, pci_devfn, PCI_VENDOR_ID,
+				&vendor);
+
+		if (vendor != 0xffff) {
+			cpc700_pcibios_read_config_word(0, pci_devfn,
+						PCI_DEVICE_ID, &device);
+
+			/* If this PCI device is the Lance PCNet board then turn it off */
+			if ((vendor == PCI_VENDOR_ID_AMD) &&
+					(device == PCI_DEVICE_ID_AMD_LANCE)) {
+
+				/* Turn on I/O Space on the board. */
+				cpc700_pcibios_read_config_word(0, pci_devfn,
+						PCI_COMMAND, &command);
+				command |= 0x1;
+				cpc700_pcibios_write_config_word(0, pci_devfn,
+						PCI_COMMAND, command);
+
+				/* Get the I/O space address */
+				cpc700_pcibios_read_config_dword(0, pci_devfn,
+						PCI_BASE_ADDRESS_0, &bar0);
+				bar0 &= 0xfffffffe;
+
+				/* Reset the PCNet Board */
+				inl (bar0+PCNET32_DWIO_RESET);
+				inw (bar0+PCNET32_WIO_RESET);
+
+				/* First do a work oriented read of csr0.  If the value is
+				 * 4 then this is the correct mode to access the board.
+				 * If not try a double word ortiented read.
+				 */
+				outw(0, bar0 + PCNET32_WIO_RAP);
+				csr0 = inw(bar0 + PCNET32_WIO_RDP);
+
+				if (csr0 == 4) {
+					/* Check the Chip id register */
+					outw(88, bar0 + PCNET32_WIO_RAP);
+					csr_id = inw(bar0 + PCNET32_WIO_RDP);
+
+					if (csr_id) {
+						/* This is the valid mode - set the stop bit */
+						outw(0, bar0 + PCNET32_WIO_RAP);
+						outw(csr0, bar0 + PCNET32_WIO_RDP);
+					}
+				} else {
+					outl(0, bar0 + PCNET32_DWIO_RAP);
+					csr0 = inl(bar0 + PCNET32_DWIO_RDP);
+					if (csr0 == 4) {
+						/* Check the Chip id register */
+						outl(88, bar0 + PCNET32_WIO_RAP);
+						csr_id = inl(bar0 + PCNET32_WIO_RDP);
+
+						if (csr_id) {
+							/* This is the valid mode  - set the stop bit*/
+							outl(0, bar0 + PCNET32_WIO_RAP);
+							outl(csr0, bar0 + PCNET32_WIO_RDP);
+						}
+					}
+				}
+			}
+		}
+	}
+
+	/* assume the chunk below 8M is free */
+	end_avail = (char *)0x00800000;
+
+	/*
+	 * We link ourself to 0x00800000.  When we run, we relocate
+	 * ourselves there.  So we just need __image_begin for the
+	 * start. -- Tom
+	 */
+	zimage_start = (char *)(unsigned long)(&__image_begin);
+	zimage_size = (unsigned long)(&__image_end) -
+			(unsigned long)(&__image_begin);
+
+	initrd_size = (unsigned long)(&__ramdisk_end) -
+		(unsigned long)(&__ramdisk_begin);
+
+	/*
+	 * The zImage and initrd will be between start and _end, so they've
+	 * already been moved once.  We're good to go now. -- Tom
+	 */
+	avail_ram = (char *)PAGE_ALIGN((unsigned long)_end);
+	puts("zimage at:     "); puthex((unsigned long)zimage_start);
+	puts(" "); puthex((unsigned long)(zimage_size+zimage_start));
+	puts("\n");
+
+	if ( initrd_size ) {
+		puts("initrd at:     ");
+		puthex((unsigned long)(&__ramdisk_begin));
+		puts(" "); puthex((unsigned long)(&__ramdisk_end));puts("\n");
+	}
+
+	avail_ram = (char *)0x00400000;
+	end_avail = (char *)0x00800000;
+	puts("avail ram:     "); puthex((unsigned long)avail_ram); puts(" ");
+	puthex((unsigned long)end_avail); puts("\n");
+
+	/* Display standard Linux/PPC boot prompt for kernel args */
+	puts("\nLinux/PPC load: ");
+	cp = cmd_line;
+	memcpy (cmd_line, cmd_preset, sizeof(cmd_preset));
+	while ( *cp ) putc(*cp++);
+	while (timer++ < 5*1000) {
+		if (tstc()) {
+			while ((ch = getc()) != '\n' && ch != '\r') {
+				if (ch == '\b') {
+					if (cp != cmd_line) {
+						cp--;
+						puts("\b \b");
+					}
+				} else {
+					*cp++ = ch;
+					putc(ch);
+				}
+			}
+			break;  /* Exit 'timer' loop */
+		}
+		udelay(1000);  /* 1 msec */
+	}
+	*cp = 0;
+	puts("\n");
+
+	puts("Uncompressing Linux...");
+
+	gunzip(0, 0x400000, zimage_start, &zimage_size);
+
+	puts("done.\n");
+
+	{
+		struct bi_record *rec;
+
+		rec = (struct bi_record *)_ALIGN((ulong)zimage_size +
+							(1<<20)-1,(1<<20));
+
+		rec->tag = BI_FIRST;
+        	rec->size = sizeof(struct bi_record);
+        	rec = (struct bi_record *)((unsigned long)rec + rec->size);
+
+        	rec->tag = BI_BOOTLOADER_ID;
+        	memcpy( (void *)rec->data, "spruceboot", 11);
+        	rec->size = sizeof(struct bi_record) + 10 + 1;
+        	rec = (struct bi_record *)((unsigned long)rec + rec->size);
+
+        	rec->tag = BI_MEMSIZE;
+        	rec->data[0] = mem_size;
+        	rec->size = sizeof(struct bi_record) + sizeof(unsigned long);
+        	rec = (struct bi_record *)((unsigned long)rec + rec->size);
+
+        	rec->tag = BI_CMD_LINE;
+        	memcpy( (char *)rec->data, cmd_line, strlen(cmd_line)+1);
+        	rec->size = sizeof(struct bi_record) + strlen(cmd_line) + 1;
+        	rec = (struct bi_record *)((ulong)rec + rec->size);
+
+		if ( initrd_size ) {
+			rec->tag = BI_INITRD;
+			rec->data[0] = (unsigned long)(&__ramdisk_begin);
+			rec->data[1] = initrd_size;
+			rec->size = sizeof(struct bi_record) + 2 *
+				sizeof(unsigned long);
+			rec = (struct bi_record *)((unsigned long)rec +
+					rec->size);
+		}
+
+        	rec->tag = BI_LAST;
+        	rec->size = sizeof(struct bi_record);
+        	rec = (struct bi_record *)((unsigned long)rec + rec->size);
+	}
+
+	puts("Now booting the kernel\n");
+
+	return 0;
+}
diff -urN linux-2.4.20-pre4/arch/ppc/config.in linux-2.4.20-pre5/arch/ppc/config.in
--- linux-2.4.20-pre4/arch/ppc/config.in	Wed Aug 28 16:36:45 2002
+++ linux-2.4.20-pre5/arch/ppc/config.in	Wed Aug 28 16:37:28 2002
@@ -97,6 +97,7 @@
   choice 'Machine Type'		\
 	"CHRP/PowerMac/PReP	CONFIG_ALL_PPC		\
   	 Amiga-APUS		CONFIG_APUS		\
+	 IBM-Spruce		CONFIG_SPRUCE		\
 	 Synergy-Gemini        	CONFIG_GEMINI"		CHRP/PowerMac/PReP
 fi
 
@@ -403,4 +404,12 @@
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
 bool 'Include kgdb kernel debugger' CONFIG_KGDB
 bool 'Include xmon kernel debugger' CONFIG_XMON
+bool 'Include BDI-2000 user context switcher' CONFIG_BDI_SWITCH
+if [ "$CONFIG_KGDB" = "y" -o "$CONFIG_XMON" = "y" \
+	-o "$CONFIG_BDI_SWITCH" = "y" ]; then
+  bool 'Add any additional compile options' CONFIG_MORE_COMPILE_OPTIONS
+  if [ "$CONFIG_MORE_COMPILE_OPTIONS" = "y" ]; then
+    string 'Additional compile arguments' CONFIG_COMPILE_OPTIONS "-g -ggdb"
+  fi
+fi
 endmenu
diff -urN linux-2.4.20-pre4/arch/ppc/configs/pal4_defconfig linux-2.4.20-pre5/arch/ppc/configs/pal4_defconfig
--- linux-2.4.20-pre4/arch/ppc/configs/pal4_defconfig	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre5/arch/ppc/configs/pal4_defconfig	Wed Aug 28 16:37:28 2002
@@ -0,0 +1,569 @@
+#
+# Automatically generated make config: don't edit
+#
+# CONFIG_UID16 is not set
+# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_HAVE_DEC_LOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+CONFIG_KMOD=y
+
+#
+# Platform support
+#
+CONFIG_PPC=y
+CONFIG_PPC32=y
+CONFIG_6xx=y
+# CONFIG_4xx is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8xx is not set
+# CONFIG_8260 is not set
+CONFIG_PPC_STD_MMU=y
+# CONFIG_ALL_PPC is not set
+# CONFIG_APUS is not set
+# CONFIG_SPRUCE is not set
+CONFIG_PAL4=y
+# CONFIG_GEMINI is not set
+# CONFIG_SMP is not set
+# CONFIG_ALTIVEC is not set
+# CONFIG_TAU is not set
+
+#
+# General setup
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+CONFIG_PCI=y
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_KCORE_ELF=y
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+CONFIG_BINFMT_MISC=m
+CONFIG_PCI_NAMES=y
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+# CONFIG_PPC_RTC is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="ip=on"
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_STATS is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+# CONFIG_NETLINK_DEV is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_FILTER=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+CONFIG_SYN_COOKIES=y
+
+#
+#   IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+# CONFIG_IP_NF_QUEUE is not set
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_LIMIT=m
+CONFIG_IP_NF_MATCH_MAC=m
+CONFIG_IP_NF_MATCH_PKTTYPE=m
+CONFIG_IP_NF_MATCH_MARK=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_LENGTH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_TCPMSS=m
+CONFIG_IP_NF_MATCH_HELPER=m
+CONFIG_IP_NF_MATCH_STATE=m
+CONFIG_IP_NF_MATCH_CONNTRACK=m
+CONFIG_IP_NF_MATCH_UNCLEAN=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_MIRROR=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+# CONFIG_IP_NF_NAT_LOCAL is not set
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+# CONFIG_IP_NF_MANGLE is not set
+# CONFIG_IP_NF_TARGET_LOG is not set
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_COMPAT_IPCHAINS=m
+CONFIG_IP_NF_NAT_NEEDED=y
+# CONFIG_IP_NF_COMPAT_IPFWADM is not set
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_MACE is not set
+# CONFIG_BMAC is not set
+# CONFIG_GMAC is not set
+# CONFIG_SUNLANCE is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNBMAC is not set
+# CONFIG_SUNQE is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+# CONFIG_TULIP is not set
+# CONFIG_DE4X5 is not set
+# CONFIG_DGRS is not set
+# CONFIG_DM9102 is not set
+CONFIG_EEPRO100=y
+# CONFIG_E100 is not set
+# CONFIG_LNE390 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_NE3210 is not set
+# CONFIG_ES3210 is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_8139TOO_PIO is not set
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_8139TOO_8129 is not set
+# CONFIG_8139_OLD_RX_RESET is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_TC35815 is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_VIA_RHINE_MMIO is not set
+# CONFIG_WINBOND_840 is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+# CONFIG_STRIP is not set
+# CONFIG_WAVELAN is not set
+# CONFIG_ARLAN is not set
+# CONFIG_AIRONET4500 is not set
+# CONFIG_AIRONET4500_NONCS is not set
+# CONFIG_AIRONET4500_PROC is not set
+# CONFIG_AIRO is not set
+CONFIG_HERMES=m
+# CONFIG_PLX_HERMES is not set
+# CONFIG_PCI_HERMES is not set
+CONFIG_NET_WIRELESS=y
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Console drivers
+#
+# CONFIG_VGA_CONSOLE is not set
+
+#
+# Frame-buffer support
+#
+# CONFIG_FB is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
+# Macintosh device drivers
+#
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+
+#
+# I2C support
+#
+CONFIG_I2C=m
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+CONFIG_I2C_CHARDEV=m
+CONFIG_I2C_PROC=m
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+
+#
+# Input core support is needed for gameports
+#
+
+#
+# Input core support is needed for joysticks
+#
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BEFS_DEBUG is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+CONFIG_TMPFS=y
+CONFIG_RAMFS=y
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_DEVFS_FS=y
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_SMB_NLS is not set
+# CONFIG_NLS is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_KGDB is not set
+# CONFIG_XMON is not set
+CONFIG_BDI_SWITCH=y
+# CONFIG_MORE_COMPILE_OPTIONS is not set
diff -urN linux-2.4.20-pre4/arch/ppc/configs/spruce_defconfig linux-2.4.20-pre5/arch/ppc/configs/spruce_defconfig
--- linux-2.4.20-pre4/arch/ppc/configs/spruce_defconfig	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre5/arch/ppc/configs/spruce_defconfig	Wed Aug 28 16:37:28 2002
@@ -0,0 +1,531 @@
+#
+# Automatically generated by make menuconfig: don't edit
+#
+# CONFIG_UID16 is not set
+# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# Platform support
+#
+CONFIG_PPC=y
+CONFIG_PPC32=y
+CONFIG_6xx=y
+# CONFIG_40x is not set
+# CONFIG_POWER3 is not set
+# CONFIG_8xx is not set
+# CONFIG_PPC_ISERIES is not set
+# CONFIG_8260 is not set
+CONFIG_PPC_STD_MMU=y
+# CONFIG_ALL_PPC is not set
+# CONFIG_APUS is not set
+CONFIG_SPRUCE=y
+# CONFIG_PCORE is not set
+# CONFIG_POWERPMC250 is not set
+# CONFIG_MENF1 is not set
+# CONFIG_LOPEC is not set
+# CONFIG_MCPN765 is not set
+# CONFIG_MVME5100 is not set
+# CONFIG_PRPMC750 is not set
+# CONFIG_PRPMC800 is not set
+# CONFIG_SANDPOINT is not set
+# CONFIG_ADIR is not set
+# CONFIG_K2 is not set
+# CONFIG_GEMINI is not set
+# CONFIG_WILLOW is not set
+# CONFIG_ZX4500 is not set
+# CONFIG_SPRUCE_BAUD_33M is not set
+# CONFIG_SMP is not set
+# CONFIG_ALTIVEC is not set
+# CONFIG_TAU is not set
+
+#
+# General setup
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+CONFIG_PCI=y
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_KCORE_ELF=y
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_PCI_NAMES is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+CONFIG_PPC_RTC=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="ip=on"
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_NETLINK=y
+# CONFIG_RTNETLINK is not set
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_MACE is not set
+# CONFIG_BMAC is not set
+# CONFIG_GMAC is not set
+# CONFIG_SUNLANCE is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNBMAC is not set
+# CONFIG_SUNQE is not set
+# CONFIG_SUNLANCE is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_PCI=y
+CONFIG_PCNET32=y
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+# CONFIG_TULIP is not set
+# CONFIG_DE4X5 is not set
+# CONFIG_DGRS is not set
+# CONFIG_DM9102 is not set
+# CONFIG_EEPRO100 is not set
+# CONFIG_LNE390 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_NE3210 is not set
+# CONFIG_ES3210 is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_8139TOO_PIO is not set
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_8139TOO_8129 is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_WINBOND_840 is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Console drivers
+#
+# CONFIG_VGA_CONSOLE is not set
+
+#
+# Frame-buffer support
+#
+# CONFIG_FB is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
+# Macintosh device drivers
+#
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+CONFIG_MOUSE=y
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_INTEL_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_TMPFS is not set
+# CONFIG_RAMFS is not set
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+# CONFIG_ZLIB_FS_INFLATE is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_SMB_NLS is not set
+# CONFIG_NLS is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+# CONFIG_USB_UHCI is not set
+# CONFIG_USB_UHCI_ALT is not set
+# CONFIG_USB_OHCI is not set
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_BLUETOOTH is not set
+# CONFIG_USB_STORAGE is not set
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_HP8200e is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_DC2XX is not set
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_SCANNER is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_HPUSBSCSI is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_CDCETHER is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_USB_USS720 is not set
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+# CONFIG_USB_SERIAL_GENERIC is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB_RIO500 is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_KGDB is not set
+# CONFIG_XMON is not set
+# CONFIG_BDI_SWITCH is not set
diff -urN linux-2.4.20-pre4/arch/ppc/kernel/Makefile linux-2.4.20-pre5/arch/ppc/kernel/Makefile
--- linux-2.4.20-pre4/arch/ppc/kernel/Makefile	Wed Aug 28 16:36:45 2002
+++ linux-2.4.20-pre5/arch/ppc/kernel/Makefile	Wed Aug 28 16:37:28 2002
@@ -56,6 +56,8 @@
 obj-$(CONFIG_ALL_PPC)		+= prom_init.o prom.o open_pic.o \
 					indirect_pci.o i8259.o prep_nvram.o
 obj-$(CONFIG_GEMINI)		+= open_pic.o
+obj-$(CONFIG_PAL4)		+= indirect_pci.o pci_auto.o todc_time.o
+obj-$(CONFIG_SPRUCE)		+= indirect_pci.o pci_auto.o todc_time.o
 obj-$(CONFIG_8260)		+= m8260_setup.o ppc8260_pic.o
 obj-$(CONFIG_BOOTX_TEXT)	+= btext.o
 
diff -urN linux-2.4.20-pre4/arch/ppc/kernel/head.S linux-2.4.20-pre5/arch/ppc/kernel/head.S
--- linux-2.4.20-pre4/arch/ppc/kernel/head.S	Wed Aug 28 16:36:45 2002
+++ linux-2.4.20-pre5/arch/ppc/kernel/head.S	Wed Aug 28 16:37:29 2002
@@ -1633,6 +1633,21 @@
 	TLBSYNC			/* ... on all CPUs */
 
 	bl	load_up_mmu
+
+#ifdef CONFIG_BDI_SWITCH
+	/* Add helper information for the Abatron bdiGDB debugger.
+	 * We do this here because we know the mmu is disabled, and
+	 * will be enabled for real in just a few instructions.
+	 */
+	lis	r5, abatron_pteptrs@h
+	ori	r5, r5, abatron_pteptrs@l
+	stw	r5, 0xf0(r0)	/* This much match your Abatron config */
+	lis	r6, swapper_pg_dir@h
+	ori	r6, r6, swapper_pg_dir@l
+	tophys(r5, r5)
+	stw	r6, 0(r5)
+#endif
+
 /* Now turn on the MMU for real! */
 	li	r4,MSR_KERNEL
 	FIX_SRR1(r4,r5)
@@ -1652,6 +1667,16 @@
 	addis	r3,r3,0x6000	/* Set Ks, Ku bits */
 	li	r0,NUM_USER_SEGMENTS
 	mtctr	r0
+
+#ifdef CONFIG_BDI_SWITCH
+	/* Context switch the PTE pointer for the Abatron BDI2000.
+	 * The PGDIR is passed as second argument.
+	 */
+	lis	r5, KERNELBASE@h
+	lwz	r5, 0xf0(r5)
+	stw	r4, 0x4(r5)
+#endif
+
 	li	r4,0
 BEGIN_FTR_SECTION
 	DSSALL
@@ -1870,3 +1895,11 @@
 	.long 0, 0, 0, 0, 0, 0, 0, 0
 	.long 0, 0, 0, 0, 0, 0, 0, 0
 	.long 0, 0, 0, 0, 0, 0, 0, 0
+
+#ifdef CONFIG_BDI_SWITCH
+/* Room for two PTE pointers, usually the kernel and current user pointers
+ * to their respective root page table.
+ */
+abatron_pteptrs:
+	.space	8
+#endif
diff -urN linux-2.4.20-pre4/arch/ppc/kernel/head_8xx.S linux-2.4.20-pre5/arch/ppc/kernel/head_8xx.S
--- linux-2.4.20-pre4/arch/ppc/kernel/head_8xx.S	Wed Aug 28 16:36:45 2002
+++ linux-2.4.20-pre5/arch/ppc/kernel/head_8xx.S	Wed Aug 28 16:37:29 2002
@@ -777,14 +777,18 @@
 	sync			/* wait for tlbia/tlbie to finish */
 	TLBSYNC			/* ... on all CPUs */
 
-	/* set up the PTE pointers for the Abatron bdiGDB.
-	*/
+#ifdef CONFIG_BDI_SWITCH
+	/* Add helper information for the Abatron bdiGDB debugger.
+	 * We do this here because we know the mmu is disabled, and
+	 * will be enabled for real in just a few instructions.
+	 */
 	tovirt(r6,r6)
 	lis	r5, abatron_pteptrs@h
 	ori	r5, r5, abatron_pteptrs@l
 	stw	r5, 0xf0(r0)	/* Must match your Abatron config file */
 	tophys(r5,r5)
 	stw	r6, 0(r5)
+#endif
 
 /* Now turn on the MMU for real! */
 	li	r4,MSR_KERNEL
@@ -948,15 +952,16 @@
 cmd_line:
 	.space	512
 
+#ifdef CONFIG_BDI_SWITCH
 /* Room for two PTE table poiners, usually the kernel and current user
  * pointer to their respective root page table (pgdir).
  */
 abatron_pteptrs:
 	.space	8
+#endif
 
 #ifdef CONFIG_8xx_CPU6
 	.globl	cpu6_errata_word
 cpu6_errata_word:
 	.space	16
 #endif
-
diff -urN linux-2.4.20-pre4/arch/ppc/kernel/irq.c linux-2.4.20-pre5/arch/ppc/kernel/irq.c
--- linux-2.4.20-pre4/arch/ppc/kernel/irq.c	Wed Aug 28 16:36:45 2002
+++ linux-2.4.20-pre5/arch/ppc/kernel/irq.c	Wed Aug 28 16:37:29 2002
@@ -50,19 +50,16 @@
 
 #include <asm/uaccess.h>
 #include <asm/bitops.h>
-#include <asm/hydra.h>
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/irq.h>
-#include <asm/gg2.h>
 #include <asm/cache.h>
 #include <asm/prom.h>
-#include <asm/amigaints.h>
-#include <asm/amigahw.h>
-#include <asm/amigappc.h>
 #include <asm/ptrace.h>
 
+#define NR_MASK_WORDS	((NR_IRQS + 31) / 32)
+
 extern atomic_t ipi_recv;
 extern atomic_t ipi_sent;
 void enable_irq(unsigned int irq_nr);
@@ -187,9 +184,6 @@
  * now, this is what I need. -- Dan
  */
 #define request_irq	request_8xxirq
-#elif defined(CONFIG_APUS)
-#define request_irq	request_sysirq
-#define free_irq	sys_free_irq
 #endif
 
 void free_irq(unsigned int irq, void* dev_id)
@@ -371,9 +365,6 @@
 
 int get_irq_list(char *buf)
 {
-#ifdef CONFIG_APUS
-	return apus_get_irq_list (buf);
-#else
 	int i, len = 0, j;
 	struct irqaction * action;
 
@@ -421,7 +412,6 @@
 #endif		
 	len += sprintf(buf+len, "BAD: %10u\n", ppc_spurious_interrupts);
 	return len;
-#endif /* CONFIG_APUS */
 }
 
 static inline void
diff -urN linux-2.4.20-pre4/arch/ppc/kernel/pci.c linux-2.4.20-pre5/arch/ppc/kernel/pci.c
--- linux-2.4.20-pre4/arch/ppc/kernel/pci.c	Wed Aug 28 16:36:45 2002
+++ linux-2.4.20-pre5/arch/ppc/kernel/pci.c	Wed Aug 28 16:37:29 2002
@@ -180,6 +180,10 @@
 #endif
 		}
 	}
+
+	/* Call machine specific resource fixup */
+	if (ppc_md.pcibios_fixup_resources)
+		ppc_md.pcibios_fixup_resources(dev);
 }
 
 #ifdef CONFIG_ALL_PPC
@@ -821,6 +825,10 @@
 	if (pci_assign_all_busses && have_of)
 		pcibios_make_OF_bus_map();
 
+	/* Do machine dependent PCI interrupt routing */
+	if (ppc_md.pci_swizzle && ppc_md.pci_map_irq)
+		pci_fixup_irqs(ppc_md.pci_swizzle, ppc_md.pci_map_irq);
+
 	/* Call machine dependant fixup */
 	if (ppc_md.pcibios_fixup)
 		ppc_md.pcibios_fixup();
@@ -836,6 +844,25 @@
 		ppc_md.pcibios_after_init();
 }
 
+unsigned char __init
+common_swizzle(struct pci_dev *dev, unsigned char *pinp)
+{
+	struct pci_controller *hose = dev->sysdata;
+
+	if (dev->bus->number != hose->first_busno) {
+		u8 pin = *pinp;
+		do {
+			pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn));
+			/* Move up the chain of bridges. */
+			dev = dev->bus->self;
+		} while (dev->bus->self);
+		*pinp = pin;
+
+		/* The slot is the idsel of the last bridge. */
+	}
+	return PCI_SLOT(dev->devfn);
+}
+
 void __init
 pcibios_fixup_pbus_ranges(struct pci_bus * bus, struct pbus_set_ranges_data * ranges)
 {
@@ -1231,6 +1258,19 @@
 	return result;
 }
 
+void __init
+pci_init_resource(struct resource *res, unsigned long start, unsigned long end,
+		  int flags, char *name)
+{
+	res->start = start;
+	res->end = end;
+	res->flags = flags;
+	res->name = name;
+	res->parent = NULL;
+	res->sibling = NULL;
+	res->child = NULL;
+}
+
 /*
  * Null PCI config access functions, for the case when we can't
  * find a hose.
diff -urN linux-2.4.20-pre4/arch/ppc/kernel/pci_auto.c linux-2.4.20-pre5/arch/ppc/kernel/pci_auto.c
--- linux-2.4.20-pre4/arch/ppc/kernel/pci_auto.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre5/arch/ppc/kernel/pci_auto.c	Wed Aug 28 16:37:29 2002
@@ -0,0 +1,519 @@
+/*
+ * arch/ppc/kernel/pci_auto.c
+ * 
+ * PCI autoconfiguration library
+ *
+ * Author: Matt Porter <mporter@mvista.com>
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+/*
+ * The CardBus support is very preliminary.  Preallocating space is
+ * the way to go but will require some change in card services to
+ * make it useful.  Eventually this will ensure that we can put
+ * multiple CB bridges behind multiple P2P bridges.  For now, at
+ * least it ensures that we place the CB bridge BAR and assigned
+ * initial bus numbers.  I definitely need to do something about
+ * the lack of 16-bit I/O support. -MDP
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#include <asm/pci-bridge.h>
+
+#define	PCIAUTO_IDE_MODE_MASK		0x05
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif /* DEBUG */
+
+static int pciauto_upper_iospc;
+static int pciauto_upper_memspc;
+
+void __init pciauto_setup_bars(struct pci_controller *hose,
+		int current_bus,
+		int pci_devfn,
+		int bar_limit)
+{
+	int bar_response, bar_size, bar_value;
+	int bar, addr_mask;
+	int * upper_limit;
+	int found_mem64 = 0;
+
+	DBG("PCI Autoconfig: Found Bus %d, Device %d, Function %d\n",
+		current_bus, PCI_SLOT(pci_devfn), PCI_FUNC(pci_devfn) );
+
+	for (bar = PCI_BASE_ADDRESS_0; bar <= bar_limit; bar+=4) {
+		/* Tickle the BAR and get the response */
+		early_write_config_dword(hose,
+				current_bus,
+				pci_devfn,
+				bar,
+				0xffffffff);
+		early_read_config_dword(hose,
+				current_bus,
+				pci_devfn,
+				bar,
+				&bar_response);
+
+		/* If BAR is not implemented go to the next BAR */
+		if (!bar_response)
+			continue;
+
+		/* Check the BAR type and set our address mask */
+		if (bar_response & PCI_BASE_ADDRESS_SPACE) {
+			addr_mask = PCI_BASE_ADDRESS_IO_MASK;
+			upper_limit = &pciauto_upper_iospc;
+			DBG("PCI Autoconfig: BAR 0x%x, I/O, ", bar);
+		} else {
+			if ( (bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) ==
+			PCI_BASE_ADDRESS_MEM_TYPE_64)
+				found_mem64 = 1;
+
+			addr_mask = PCI_BASE_ADDRESS_MEM_MASK;		
+			upper_limit = &pciauto_upper_memspc;
+			DBG("PCI Autoconfig: BAR 0x%x, Mem ", bar);
+		}
+
+		/* Calculate requested size */
+		bar_size = ~(bar_response & addr_mask) + 1;
+
+		/* Allocate a base address */
+		bar_value = (*upper_limit - bar_size) & ~(bar_size - 1);
+
+		/* Write it out and update our limit */
+		early_write_config_dword(hose,
+				current_bus,
+				pci_devfn,
+				bar,
+				bar_value);
+
+		*upper_limit = bar_value;
+
+		/*
+		 * If we are a 64-bit decoder then increment to the
+		 * upper 32 bits of the bar and force it to locate
+		 * in the lower 4GB of memory.
+		 */ 
+		if (found_mem64) {
+			bar += 4;
+			early_write_config_dword(hose,
+					current_bus,
+					pci_devfn,
+					bar,
+					0x00000000);
+			found_mem64 = 0;
+		}
+
+		DBG("size=0x%x, address=0x%x\n",
+			bar_size, bar_value);
+	}
+
+}
+
+void __init pciauto_prescan_setup_bridge(struct pci_controller *hose,
+		int current_bus,
+		int pci_devfn,
+		int sub_bus,
+		int *iosave,
+		int *memsave)
+{
+	/* Configure bus number registers */
+	early_write_config_byte(hose,
+			current_bus,
+			pci_devfn,
+			PCI_PRIMARY_BUS,
+			current_bus);
+	early_write_config_byte(hose,
+			current_bus,
+			pci_devfn,
+			PCI_SECONDARY_BUS,
+			sub_bus + 1);
+	early_write_config_byte(hose,
+			current_bus,
+			pci_devfn,
+			PCI_SUBORDINATE_BUS,
+			0xff);
+
+	/* Round memory allocator to 1MB boundary */
+	pciauto_upper_memspc &= ~(0x100000 - 1);
+	*memsave = pciauto_upper_memspc;
+
+	/* Round I/O allocator to 4KB boundary */
+	pciauto_upper_iospc &= ~(0x1000 - 1);
+	*iosave = pciauto_upper_iospc;
+
+	/* Set up memory and I/O filter limits, assume 32-bit I/O space */
+	early_write_config_word(hose,
+			current_bus,
+			pci_devfn,
+			PCI_MEMORY_LIMIT,
+			((pciauto_upper_memspc - 1) & 0xfff00000) >> 16);
+	early_write_config_byte(hose,
+			current_bus,
+			pci_devfn,
+			PCI_IO_LIMIT,
+			((pciauto_upper_iospc - 1) & 0x0000f000) >> 8);
+	early_write_config_word(hose,
+			current_bus,
+			pci_devfn,
+			PCI_IO_LIMIT_UPPER16,
+			((pciauto_upper_iospc - 1) & 0xffff0000) >> 16);
+
+	/* Zero upper 32 bits of prefetchable base/limit */
+	early_write_config_dword(hose,
+			current_bus,
+			pci_devfn,
+			PCI_PREF_BASE_UPPER32,
+			0);
+	early_write_config_dword(hose,
+			current_bus,
+			pci_devfn,
+			PCI_PREF_LIMIT_UPPER32,
+			0);
+}
+
+void __init pciauto_postscan_setup_bridge(struct pci_controller *hose,
+		int current_bus,
+		int pci_devfn,
+		int sub_bus,
+		int *iosave,
+		int *memsave)
+{
+	int cmdstat;
+
+	/* Configure bus number registers */
+	early_write_config_byte(hose,
+			current_bus,
+			pci_devfn,
+			PCI_SUBORDINATE_BUS,
+			sub_bus);
+
+	/*
+	 * Round memory allocator to 1MB boundary.
+	 * If no space used, allocate minimum.
+	 */
+	pciauto_upper_memspc &= ~(0x100000 - 1);
+	if (*memsave == pciauto_upper_memspc)
+		pciauto_upper_memspc -= 0x00100000;
+
+	early_write_config_word(hose,
+			current_bus,
+			pci_devfn,
+			PCI_MEMORY_BASE,
+			pciauto_upper_memspc >> 16);
+
+	/* Allocate 1MB for pre-fretch */
+	early_write_config_word(hose,
+			current_bus,
+			pci_devfn,
+			PCI_PREF_MEMORY_LIMIT,
+			((pciauto_upper_memspc - 1) & 0xfff00000) >> 16);
+
+	pciauto_upper_memspc -= 0x100000;
+
+	early_write_config_word(hose,
+			current_bus,
+			pci_devfn,
+			PCI_PREF_MEMORY_BASE,
+			pciauto_upper_memspc >> 16);
+
+	/* Round I/O allocator to 4KB boundary */
+	pciauto_upper_iospc &= ~(0x1000 - 1);
+	if (*iosave == pciauto_upper_iospc)
+		pciauto_upper_iospc -= 0x1000;
+
+	early_write_config_byte(hose,
+			current_bus,
+			pci_devfn,
+			PCI_IO_BASE,
+			(pciauto_upper_iospc & 0x0000f000) >> 8);
+	early_write_config_word(hose,
+			current_bus,
+			pci_devfn,
+			PCI_IO_BASE_UPPER16,
+			pciauto_upper_iospc >> 16);
+	
+	/* Enable memory and I/O accesses, enable bus master */
+	early_read_config_dword(hose,
+			current_bus,
+			pci_devfn,
+			PCI_COMMAND,
+			&cmdstat);
+	early_write_config_dword(hose,
+			current_bus,
+			pci_devfn,
+			PCI_COMMAND,
+			cmdstat |
+			PCI_COMMAND_IO |
+			PCI_COMMAND_MEMORY |
+			PCI_COMMAND_MASTER);
+}
+
+void __init pciauto_prescan_setup_cardbus_bridge(struct pci_controller *hose,
+		int current_bus,
+		int pci_devfn,
+		int sub_bus,
+		int *iosave,
+		int *memsave)
+{
+	/* Configure bus number registers */
+	early_write_config_byte(hose,
+			current_bus,
+			pci_devfn,
+			PCI_PRIMARY_BUS,
+			current_bus);
+	early_write_config_byte(hose,
+			current_bus,
+			pci_devfn,
+			PCI_SECONDARY_BUS,
+			sub_bus + 1);
+	early_write_config_byte(hose,
+			current_bus,
+			pci_devfn,
+			PCI_SUBORDINATE_BUS,
+			0xff);
+
+	/* Round memory allocator to 4KB boundary */
+	pciauto_upper_memspc &= ~(0x1000 - 1);
+	*memsave = pciauto_upper_memspc;
+
+	/* Round I/O allocator to 4 byte boundary */
+	pciauto_upper_iospc &= ~(0x4 - 1);
+	*iosave = pciauto_upper_iospc;
+
+	/* Set up memory and I/O filter limits, assume 32-bit I/O space */
+	early_write_config_dword(hose,
+			current_bus,
+			pci_devfn,
+			0x20,
+			pciauto_upper_memspc - 1);
+	early_write_config_dword(hose,
+			current_bus,
+			pci_devfn,
+			0x30,
+			pciauto_upper_iospc - 1);
+}
+
+void __init pciauto_postscan_setup_cardbus_bridge(struct pci_controller *hose,
+		int current_bus,
+		int pci_devfn,
+		int sub_bus,
+		int *iosave,
+		int *memsave)
+{
+	int cmdstat;
+
+	/*
+	 * Configure subordinate bus number.  The PCI subsystem
+	 * bus scan will renumber buses (reserving three additional
+	 * for this PCI<->CardBus bridge for the case where a CardBus
+	 * adapter contains a P2P or CB2CB bridge.
+	 */
+	early_write_config_byte(hose,
+			current_bus,
+			pci_devfn,
+			PCI_SUBORDINATE_BUS,
+			sub_bus);
+
+	/*
+	 * Reserve an additional 4MB for mem space and 16KB for
+	 * I/O space.  This should cover any additional space
+	 * requirement of unusual CardBus devices with 
+	 * additional bridges that can consume more address space.
+	 * 
+	 * Although pcmcia-cs currently will reprogram bridge
+	 * windows, the goal is to add an option to leave them
+	 * alone and use the bridge window ranges as the regions
+	 * that are searched for free resources upon hot-insertion
+	 * of a device.  This will allow a PCI<->CardBus bridge
+	 * configured by this routine to happily live behind a
+	 * P2P bridge in a system.
+	 */
+	pciauto_upper_memspc -= 0x00400000;
+	pciauto_upper_iospc -= 0x00004000;
+
+	/* Round memory allocator to 4KB boundary */
+	pciauto_upper_memspc &= ~(0x1000 - 1);
+
+	early_write_config_dword(hose,
+			current_bus,
+			pci_devfn,
+			0x1c,
+			pciauto_upper_memspc);
+
+	/* Round I/O allocator to 4 byte boundary */
+	pciauto_upper_iospc &= ~(0x4 - 1);
+	early_write_config_dword(hose,
+			current_bus,
+			pci_devfn,
+			0x2c,
+			pciauto_upper_iospc);
+	
+	/* Enable memory and I/O accesses, enable bus master */
+	early_read_config_dword(hose,
+			current_bus,
+			pci_devfn,
+			PCI_COMMAND,
+			&cmdstat);
+	early_write_config_dword(hose,
+			current_bus,
+			pci_devfn,
+			PCI_COMMAND,
+			cmdstat |
+			PCI_COMMAND_IO |
+			PCI_COMMAND_MEMORY |
+			PCI_COMMAND_MASTER);
+}
+
+int __init pciauto_bus_scan(struct pci_controller *hose, int current_bus)
+{
+	int sub_bus, pci_devfn, pci_class, cmdstat, found_multi = 0;
+	unsigned short vid;
+	unsigned char header_type;
+
+	/*
+	 * Fetch our I/O and memory space upper boundaries used
+	 * to allocated base addresses on this hose.
+	 */
+	if (current_bus == hose->first_busno) {
+		pciauto_upper_iospc = hose->io_space.end + 1;
+		pciauto_upper_memspc = hose->mem_space.end + 1;
+	}
+
+	sub_bus = current_bus;
+
+	for (pci_devfn = 0; pci_devfn < 0xff; pci_devfn++) {
+		/* Skip our host bridge */
+		if ( (current_bus == hose->first_busno) && (pci_devfn == 0) )
+			continue;
+
+		if (PCI_FUNC(pci_devfn) && !found_multi)
+			continue;
+
+		/* If config space read fails from this device, move on */
+		if (early_read_config_byte(hose,
+				current_bus,
+				pci_devfn,
+				PCI_HEADER_TYPE,
+				&header_type))
+			continue;
+
+		if (!PCI_FUNC(pci_devfn))
+			found_multi = header_type & 0x80;
+
+		early_read_config_word(hose,
+				current_bus,
+				pci_devfn,
+				PCI_VENDOR_ID,
+				&vid);
+
+		if (vid != 0xffff) {
+			early_read_config_dword(hose,
+					current_bus,
+					pci_devfn,
+					PCI_CLASS_REVISION, &pci_class);
+			if ( (pci_class >> 16) == PCI_CLASS_BRIDGE_PCI ) {
+				int iosave, memsave;
+
+				DBG("PCI Autoconfig: Found P2P bridge, device %d\n", PCI_SLOT(pci_devfn));
+				/* Allocate PCI I/O and/or memory space */
+				pciauto_setup_bars(hose,
+						current_bus,
+						pci_devfn,
+						PCI_BASE_ADDRESS_1);
+
+				pciauto_prescan_setup_bridge(hose,
+						current_bus,
+						pci_devfn,
+						sub_bus,
+						&iosave,
+						&memsave);
+				sub_bus = pciauto_bus_scan(hose, sub_bus+1);
+				pciauto_postscan_setup_bridge(hose,
+						current_bus,
+						pci_devfn,
+						sub_bus,
+						&iosave,
+						&memsave);
+			} else if ((pci_class >> 16) == PCI_CLASS_BRIDGE_CARDBUS) {
+				int iosave, memsave;
+
+				DBG("PCI Autoconfig: Found CardBus bridge, device %d function %d\n", PCI_SLOT(pci_devfn), PCI_FUNC(pci_devfn));
+				/* Place CardBus Socket/ExCA registers */
+				pciauto_setup_bars(hose,
+						current_bus,
+						pci_devfn,
+						PCI_BASE_ADDRESS_0);
+
+				pciauto_prescan_setup_cardbus_bridge(hose,
+						current_bus,
+						pci_devfn,
+						sub_bus,
+						&iosave,
+						&memsave);
+				sub_bus = pciauto_bus_scan(hose, sub_bus+1);
+				pciauto_postscan_setup_cardbus_bridge(hose,
+						current_bus,
+						pci_devfn,
+						sub_bus,
+						&iosave,
+						&memsave);
+			} else {
+				if ((pci_class >> 16) == PCI_CLASS_STORAGE_IDE) {
+					unsigned char prg_iface;
+
+					early_read_config_byte(hose,
+							current_bus,
+							pci_devfn,
+							PCI_CLASS_PROG,
+							&prg_iface);
+					if (!(prg_iface & PCIAUTO_IDE_MODE_MASK)) {
+						DBG("PCI Autoconfig: Skipping legacy mode IDE controller\n");
+						continue;
+					}
+				}
+				/* Allocate PCI I/O and/or memory space */
+				pciauto_setup_bars(hose,
+						current_bus,
+						pci_devfn,
+						PCI_BASE_ADDRESS_5);
+
+				/*
+				 * Enable some standard settings
+				 */
+				early_read_config_dword(hose,
+						current_bus,
+						pci_devfn,
+						PCI_COMMAND,
+						&cmdstat);
+				early_write_config_dword(hose,
+						current_bus,
+						pci_devfn,
+						PCI_COMMAND,
+						cmdstat |
+						PCI_COMMAND_IO |
+						PCI_COMMAND_MEMORY |
+						PCI_COMMAND_MASTER);
+				early_write_config_byte(hose,
+						current_bus,
+						pci_devfn,
+						PCI_LATENCY_TIMER,
+						0x80);
+			}
+		}
+	}
+	return sub_bus;
+}
diff -urN linux-2.4.20-pre4/arch/ppc/kernel/setup.c linux-2.4.20-pre5/arch/ppc/kernel/setup.c
--- linux-2.4.20-pre4/arch/ppc/kernel/setup.c	Wed Aug 28 16:36:45 2002
+++ linux-2.4.20-pre5/arch/ppc/kernel/setup.c	Wed Aug 28 16:37:30 2002
@@ -57,9 +57,7 @@
 
 /* Used with the BI_MEMSIZE bootinfo parameter to store the memory
    size value reported by the boot loader. */ 
-unsigned int boot_mem_size;
-
-int parse_bootinfo(void);
+unsigned long boot_mem_size;
 
 unsigned long ISA_DMA_THRESHOLD;
 unsigned long DMA_MODE_READ, DMA_MODE_WRITE;
@@ -339,6 +337,8 @@
 	}
 #endif	
 
+	parse_bootinfo(find_bootinfo());
+
 	/* if we didn't get any bootinfo telling us what we are... */
 	if (_machine == 0) {
 		/* prep boot loader tells us if we're prep or not */
@@ -428,7 +428,7 @@
 }
 #endif /* CONFIG_ALL_PPC */
 
-int parse_bootinfo(void)
+struct bi_record *find_bootinfo(void)
 {
 	struct bi_record *rec;
 	extern char __bss_start[];
@@ -442,11 +442,16 @@
 		 */
 		rec = (struct bi_record *)_ALIGN((ulong)__bss_start+0x10000+(1<<20)-1,(1<<20));
 		if ( rec->tag != BI_FIRST )
-			return -1;
+			return NULL;
 	}
-	for ( ; rec->tag != BI_LAST ;
-	      rec = (struct bi_record *)((ulong)rec + rec->size) )
-	{
+	return rec;
+}
+
+void parse_bootinfo(struct bi_record *rec)
+{
+	if (rec == NULL || rec->tag != BI_FIRST)
+		return;
+	while (rec->tag != BI_LAST) {
 		ulong *data = rec->data;
 		switch (rec->tag) {
 		case BI_CMD_LINE:
@@ -472,9 +477,8 @@
 			boot_mem_size = data[0];
 			break;
 		}
+		rec = (struct bi_record *)((ulong)rec + rec->size);
 	}
-
-	return 0;
 }
 
 /*
@@ -491,8 +495,6 @@
 	strcpy(cmd_line, CONFIG_CMDLINE);
 #endif /* CONFIG_CMDLINE */
 
-	parse_bootinfo();
-
 	platform_init(r3, r4, r5, r6, r7);
 
 	if (ppc_md.progress)
diff -urN linux-2.4.20-pre4/arch/ppc/kernel/todc_time.c linux-2.4.20-pre5/arch/ppc/kernel/todc_time.c
--- linux-2.4.20-pre4/arch/ppc/kernel/todc_time.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre5/arch/ppc/kernel/todc_time.c	Wed Aug 28 16:37:30 2002
@@ -0,0 +1,505 @@
+/*
+ * arch/ppc/kernel/todc_time.c
+ * 
+ * Time of Day Clock support for the M48T35, M48T37, M48T59, and MC146818
+ * Real Time Clocks/Timekeepers.
+ *
+ * Author: Mark A. Greer
+ *         mgreer@mvista.com
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/time.h>
+#include <linux/timex.h>
+
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/time.h>
+#include <asm/todc.h>
+
+/*
+ * Depending on the hardware on your board and your board design, the
+ * RTC/NVRAM may be accessed either directly (like normal memory) or via
+ * address/data registers.  If your board uses the direct method, set
+ * 'nvram_data' to the base address of your nvram and leave 'nvram_as0' and
+ * 'nvram_as1' NULL.  If your board uses address/data regs to access nvram,
+ * set 'nvram_as0' to the address of the lower byte, set 'nvram_as1' to the
+ * address of the upper byte (leave NULL if using mv146818), and set
+ * 'nvram_data' to the address of the 8-bit data register.
+ *
+ * You also need to set 'ppc_md.nvram_read_val' and 'ppc_md.nvram_write_val' to
+ * the proper routines.  There are standard ones defined further down in
+ * this file that you can use.
+ *
+ * There is a built in assumption that the RTC and NVRAM are accessed by the
+ * same mechanism (i.e., ppc_md.nvram_read_val, etc works for both).
+ *
+ * Note: Even though the documentation for the various RTC chips say that it
+ * 	 take up to a second before it starts updating once the 'R' bit is
+ * 	 cleared, they always seem to update even though we bang on it many
+ * 	 times a second.  This is true, except for the Dallas Semi 1746/1747
+ * 	 (possibly others).  Those chips seem to have a real problem whenever
+ * 	 we set the 'R' bit before reading them, they basically stop counting.
+ * 	 					--MAG
+ */
+
+extern spinlock_t	rtc_lock;
+
+/*
+ * 'todc_info' should be initialized in your *_setup.c file to
+ * point to a fully initialized 'todc_info_t' structure.
+ * This structure holds all the register offsets for your particular
+ * TODC/RTC chip.
+ * TODC_ALLOC()/TODC_INIT() will allocate and initialize this table for you.
+ */
+
+#ifdef	RTC_FREQ_SELECT
+#undef	RTC_FREQ_SELECT
+#define	RTC_FREQ_SELECT		control_b	/* Register A */
+#endif
+
+#ifdef	RTC_CONTROL
+#undef	RTC_CONTROL
+#define	RTC_CONTROL		control_a	/* Register B */
+#endif
+
+#ifdef	RTC_INTR_FLAGS
+#undef	RTC_INTR_FLAGS
+#define	RTC_INTR_FLAGS		watchdog	/* Register C */
+#endif
+
+#ifdef	RTC_VALID
+#undef	RTC_VALID
+#define	RTC_VALID		interrupts	/* Register D */
+#endif
+
+/* Access routines when RTC accessed directly (like normal memory) */
+u_char
+todc_direct_read_val(int addr)
+{
+	return readb(todc_info->nvram_data + addr);
+}
+  
+void
+todc_direct_write_val(int addr, unsigned char val)
+{
+	writeb(val, todc_info->nvram_data + addr);
+	return;
+}
+
+/* Access routines for accessing m48txx type chips via addr/data regs */
+u_char
+todc_m48txx_read_val(int addr)
+{
+	outb(addr, todc_info->nvram_as0);
+	outb(addr>>todc_info->as0_bits, todc_info->nvram_as1);
+	return inb(todc_info->nvram_data);
+}
+  
+void
+todc_m48txx_write_val(int addr, unsigned char val)
+{
+	outb(addr, todc_info->nvram_as0);
+	outb(addr>>todc_info->as0_bits, todc_info->nvram_as1);
+   	outb(val, todc_info->nvram_data);
+	return;
+}
+
+/* Access routines for accessing mc146818 type chips via addr/data regs */
+u_char
+todc_mc146818_read_val(int addr)
+{
+	outb(addr, todc_info->nvram_as0);
+	return inb(todc_info->nvram_data);
+}
+  
+void
+todc_mc146818_write_val(int addr, unsigned char val)
+{
+	outb(addr, todc_info->nvram_as0);
+   	outb(val, todc_info->nvram_data);
+	return;
+}
+
+
+/*
+ * Routines to make RTC chips with NVRAM buried behind an addr/data pair
+ * have the NVRAM and clock regs appear at the same level.
+ * The NVRAM will appear to start at addr 0 and the clock regs will appear
+ * to start immediately after the NVRAM (actually, start at offset
+ * todc_info->nvram_size).
+ */
+static inline u_char
+todc_read_val(int addr)
+{
+	u_char	val;
+
+	if (todc_info->sw_flags & TODC_FLAG_2_LEVEL_NVRAM) {
+		if (addr < todc_info->nvram_size) { /* NVRAM */
+			ppc_md.nvram_write_val(todc_info->nvram_addr_reg, addr);
+			val = ppc_md.nvram_read_val(todc_info->nvram_data_reg);
+		}
+		else { /* Clock Reg */
+			addr -= todc_info->nvram_size;
+			val = ppc_md.nvram_read_val(addr);
+		}
+	}
+	else {
+		val = ppc_md.nvram_read_val(addr);
+	}
+
+	return val;
+}
+
+static inline void
+todc_write_val(int addr, u_char val)
+{
+	if (todc_info->sw_flags & TODC_FLAG_2_LEVEL_NVRAM) {
+		if (addr < todc_info->nvram_size) { /* NVRAM */
+			ppc_md.nvram_write_val(todc_info->nvram_addr_reg, addr);
+			ppc_md.nvram_write_val(todc_info->nvram_data_reg, val);
+		}
+		else { /* Clock Reg */
+			addr -= todc_info->nvram_size;
+			ppc_md.nvram_write_val(addr, val);
+		}
+	}
+	else {
+		ppc_md.nvram_write_val(addr, val);
+	}
+}
+
+/*
+ * TODC routines
+ *
+ * There is some ugly stuff in that there are assumptions for the mc146818.
+ *
+ * Assumptions:
+ *	- todc_info->control_a has the offset as mc146818 Register B reg
+ *	- todc_info->control_b has the offset as mc146818 Register A reg
+ *	- m48txx control reg's write enable or 'W' bit is same as
+ *	  mc146818 Register B 'SET' bit (i.e., 0x80)
+ *
+ * These assumptions were made to make the code simpler.
+ */
+long __init
+todc_time_init(void)
+{
+	static u_char	not_initialized = 1;
+
+	/* Make sure clocks are running */
+	if (not_initialized) {
+		u_char	cntl_b;
+
+		cntl_b = todc_read_val(todc_info->control_b);
+
+		if (todc_info->rtc_type == TODC_TYPE_MC146818) {
+			if ((cntl_b & 0x70) != 0x20) {
+				printk(KERN_INFO "TODC %s %s\n",
+					"real-time-clock was stopped.",
+					"Now starting...");
+				cntl_b &= ~0x70;
+				cntl_b |= 0x20;
+			}
+
+			todc_write_val(todc_info->control_b, cntl_b);
+		}
+		else if (todc_info->rtc_type == TODC_TYPE_DS1501) {
+			u_char	month;
+
+			todc_info->enable_read = TODC_DS1501_CNTL_B_TE;
+			todc_info->enable_write = TODC_DS1501_CNTL_B_TE;
+
+			month = todc_read_val(todc_info->month);
+
+			if ((month & 0x80) == 0x80) {
+				printk(KERN_INFO "TODC %s %s\n",
+					"real-time-clock was stopped.",
+					"Now starting...");
+				month &= ~0x80;
+				todc_write_val(todc_info->month, month);
+			}
+
+			cntl_b &= ~TODC_DS1501_CNTL_B_TE;
+			todc_write_val(todc_info->control_b, cntl_b);
+		}
+		else { /* must be a m48txx type */
+			u_char	cntl_a;
+
+			todc_info->enable_read = TODC_MK48TXX_CNTL_A_R;
+			todc_info->enable_write = TODC_MK48TXX_CNTL_A_W;
+
+			cntl_a = todc_read_val(todc_info->control_a);
+
+			/* Check & clear STOP bit in control B register */
+			if (cntl_b & TODC_MK48TXX_DAY_CB) {
+				printk(KERN_INFO "TODC %s %s\n",
+					"real-time-clock was stopped.",
+					"Now starting...");
+
+				cntl_a |= todc_info->enable_write;
+				cntl_b &= ~TODC_MK48TXX_DAY_CB;/* Start Oscil */
+
+				todc_write_val(todc_info->control_a, cntl_a);
+				todc_write_val(todc_info->control_b, cntl_b);
+			}
+
+			/* Make sure READ & WRITE bits are cleared. */
+			cntl_a &= ~(todc_info->enable_write |
+				    todc_info->enable_read);
+			todc_write_val(todc_info->control_a, cntl_a);
+		}
+
+		not_initialized = 0;
+	}
+
+
+	return 0;
+}
+
+/*
+ * There is some ugly stuff in that there are assumptions that for a mc146818,
+ * the todc_info->control_a has the offset of the mc146818 Register B reg and
+ * that the register'ss 'SET' bit is the same as the m48txx's write enable
+ * bit in the control register of the m48txx (i.e., 0x80).
+ *
+ * It was done to make the code look simpler.
+ */
+ulong
+todc_get_rtc_time(void)
+{
+	uint	year, mon, day, hour, min, sec;
+	uint	limit, i;
+	u_char	save_control, uip;
+
+	spin_lock(&rtc_lock);
+	save_control = todc_read_val(todc_info->control_a);
+
+	if (todc_info->rtc_type != TODC_TYPE_MC146818) {
+		limit = 1;
+
+		switch (todc_info->rtc_type) {
+			case TODC_TYPE_DS1557:
+			case TODC_TYPE_DS1743:
+			case TODC_TYPE_DS1746:	/* XXXX BAD HACK -> FIX */
+			case TODC_TYPE_DS1747:
+				break;
+			default:
+				todc_write_val(todc_info->control_a,
+				       (save_control | todc_info->enable_read));
+		}
+	}
+	else {
+		limit = 100000000;
+	}
+
+	for (i=0; i<limit; i++) {
+		if (todc_info->rtc_type == TODC_TYPE_MC146818) {
+			uip = todc_read_val(todc_info->RTC_FREQ_SELECT);
+		}
+
+		sec = todc_read_val(todc_info->seconds) & 0x7f;
+		min = todc_read_val(todc_info->minutes) & 0x7f;
+		hour = todc_read_val(todc_info->hours) & 0x3f;
+		day = todc_read_val(todc_info->day_of_month) & 0x3f;
+		mon = todc_read_val(todc_info->month) & 0x1f;
+		year = todc_read_val(todc_info->year) & 0xff;
+
+		if (todc_info->rtc_type == TODC_TYPE_MC146818) {
+			uip |= todc_read_val(todc_info->RTC_FREQ_SELECT);
+			if ((uip & RTC_UIP) == 0) break;
+		}
+	}
+
+	if (todc_info->rtc_type != TODC_TYPE_MC146818) {
+		switch (todc_info->rtc_type) {
+			case TODC_TYPE_DS1557:
+			case TODC_TYPE_DS1743:
+			case TODC_TYPE_DS1746:	/* XXXX BAD HACK -> FIX */
+			case TODC_TYPE_DS1747:
+				break;
+			default:
+				save_control &= ~(todc_info->enable_read);
+				todc_write_val(todc_info->control_a,
+						       save_control);
+		}
+	}
+	spin_unlock(&rtc_lock);
+
+	if ((todc_info->rtc_type != TODC_TYPE_MC146818) ||
+	    ((save_control & RTC_DM_BINARY) == 0) ||
+	    RTC_ALWAYS_BCD) {
+
+		BCD_TO_BIN(sec);
+		BCD_TO_BIN(min);
+		BCD_TO_BIN(hour);
+		BCD_TO_BIN(day);
+		BCD_TO_BIN(mon);
+		BCD_TO_BIN(year);
+	}
+
+	year = year + 1900;
+	if (year < 1970) {
+		year += 100;
+	}
+
+	return mktime(year, mon, day, hour, min, sec);
+}
+
+int
+todc_set_rtc_time(unsigned long nowtime)
+{
+	struct rtc_time	tm;
+	u_char		save_control, save_freq_select;
+
+	spin_lock(&rtc_lock);
+	to_tm(nowtime, &tm);
+
+	save_control = todc_read_val(todc_info->control_a);
+
+	/* Assuming MK48T59_RTC_CA_WRITE & RTC_SET are equal */
+	todc_write_val(todc_info->control_a,
+			       (save_control | todc_info->enable_write));
+	save_control &= ~(todc_info->enable_write); /* in case it was set */
+
+	if (todc_info->rtc_type == TODC_TYPE_MC146818) {
+		save_freq_select = todc_read_val(todc_info->RTC_FREQ_SELECT);
+		todc_write_val(todc_info->RTC_FREQ_SELECT,
+				       save_freq_select | RTC_DIV_RESET2);
+	}
+
+
+        tm.tm_year = (tm.tm_year - 1900) % 100;
+
+	if ((todc_info->rtc_type != TODC_TYPE_MC146818) ||
+	    ((save_control & RTC_DM_BINARY) == 0) ||
+	    RTC_ALWAYS_BCD) {
+
+		BIN_TO_BCD(tm.tm_sec);
+		BIN_TO_BCD(tm.tm_min);
+		BIN_TO_BCD(tm.tm_hour);
+		BIN_TO_BCD(tm.tm_mon);
+		BIN_TO_BCD(tm.tm_mday);
+		BIN_TO_BCD(tm.tm_year);
+	}
+
+	todc_write_val(todc_info->seconds,      tm.tm_sec);
+	todc_write_val(todc_info->minutes,      tm.tm_min);
+	todc_write_val(todc_info->hours,        tm.tm_hour);
+	todc_write_val(todc_info->month,        tm.tm_mon);
+	todc_write_val(todc_info->day_of_month, tm.tm_mday);
+	todc_write_val(todc_info->year,         tm.tm_year);
+	
+	todc_write_val(todc_info->control_a, save_control);
+
+	if (todc_info->rtc_type == TODC_TYPE_MC146818) {
+		todc_write_val(todc_info->RTC_FREQ_SELECT, save_freq_select);
+	}
+	spin_unlock(&rtc_lock);
+
+	return 0;
+}
+
+/*
+ * Manipulates read bit to reliably read seconds at a high rate.
+ */
+static unsigned char __init todc_read_timereg(int addr)
+{
+	unsigned char save_control, val;
+
+	switch (todc_info->rtc_type) {
+		case TODC_TYPE_DS1557:
+		case TODC_TYPE_DS1746:	/* XXXX BAD HACK -> FIX */
+		case TODC_TYPE_DS1747:
+		case TODC_TYPE_MC146818:
+			break;
+		default:
+			save_control = todc_read_val(todc_info->control_a);
+			todc_write_val(todc_info->control_a,
+				       (save_control | todc_info->enable_read));
+	}
+	val = todc_read_val(addr);
+
+	switch (todc_info->rtc_type) {
+		case TODC_TYPE_DS1557:
+		case TODC_TYPE_DS1746:	/* XXXX BAD HACK -> FIX */
+		case TODC_TYPE_DS1747:
+		case TODC_TYPE_MC146818:
+			break;
+		default:
+			save_control &= ~(todc_info->enable_read);
+			todc_write_val(todc_info->control_a, save_control);
+	}
+
+	return val;
+} 
+
+/*
+ * This was taken from prep_setup.c
+ * Use the NVRAM RTC to time a second to calibrate the decrementer.
+ */
+void __init
+todc_calibrate_decr(void)
+{
+	ulong	freq;
+	ulong	tbl, tbu;
+        long	i, loop_count;
+        u_char	sec;
+ 
+	todc_time_init();
+
+	/*
+	 * Actually this is bad for precision, we should have a loop in
+	 * which we only read the seconds counter. todc_read_val writes
+	 * the address bytes on every call and this takes a lot of time.
+	 * Perhaps an nvram_wait_change method returning a time
+	 * stamp with a loop count as parameter would be the solution.
+	 */
+	/*
+	 * Need to make sure the tbl doesn't roll over so if tbu increments
+	 * during this test, we need to do it again.
+	 */
+	loop_count = 0;
+
+	sec = todc_read_timereg(todc_info->seconds) & 0x7f;
+
+	do {
+		tbu = get_tbu();
+
+		for (i = 0 ; i < 10000000 ; i++) {/* may take up to 1 second */
+		   tbl = get_tbl();
+
+		   if ((todc_read_timereg(todc_info->seconds) & 0x7f) != sec) {
+		      break;
+		   }
+		}
+
+		sec = todc_read_timereg(todc_info->seconds) & 0x7f;
+
+		for (i = 0 ; i < 10000000 ; i++) { /* Should take 1 second */
+		   freq = get_tbl();
+
+		   if ((todc_read_timereg(todc_info->seconds) & 0x7f) != sec) {
+		      break;
+		   }
+		}
+
+		freq -= tbl;
+	} while ((get_tbu() != tbu) && (++loop_count < 2));
+
+	printk("time_init: decrementer frequency = %lu.%.6lu MHz\n",
+	       freq/1000000, freq%1000000);
+
+	tb_ticks_per_jiffy = freq / HZ;
+	tb_to_us = mulhwu_scale_factor(freq, 1000000);
+
+	return;
+}
diff -urN linux-2.4.20-pre4/arch/ppc/mm/fault.c linux-2.4.20-pre5/arch/ppc/mm/fault.c
--- linux-2.4.20-pre4/arch/ppc/mm/fault.c	Wed Aug 28 16:36:45 2002
+++ linux-2.4.20-pre5/arch/ppc/mm/fault.c	Wed Aug 28 16:37:30 2002
@@ -195,12 +195,11 @@
  * us unable to handle the page fault gracefully.
  */
 out_of_memory:
-	up_read(&mm->mmap_sem);
 	if (current->pid == 1) {
 		yield();
-		down_read(&mm->mmap_sem);
 		goto survive;
 	}
+	up_read(&mm->mmap_sem);
 	printk("VM: killing process %s\n", current->comm);
 	if (user_mode(regs))
 		do_exit(SIGKILL);
diff -urN linux-2.4.20-pre4/arch/ppc/platforms/Makefile linux-2.4.20-pre5/arch/ppc/platforms/Makefile
--- linux-2.4.20-pre4/arch/ppc/platforms/Makefile	Wed Aug 28 16:36:45 2002
+++ linux-2.4.20-pre5/arch/ppc/platforms/Makefile	Wed Aug 28 16:37:30 2002
@@ -21,6 +21,10 @@
 # Extra CFLAGS so we don't have to do relative includes
 CFLAGS_pmac_setup.o	+= -I$(TOPDIR)/drivers/scsi -I$(TOPDIR)/fs/partitions \
 				-I$(TOPDIR)/arch/$(ARCH)/mm
+CFLAGS_spruce_setup.o	+= -I$(TOPDIR)/arch/ppc/kernel
+CFLAGS_spruce_pci.o	+= -I$(TOPDIR)/arch/ppc/kernel
+CFLAGS_pal4_setup.o	+= -I$(TOPDIR)/arch/ppc/kernel
+CFLAGS_pal4_pci.o	+= -I$(TOPDIR)/arch/ppc/kernel
 
 O_TARGET := platform.o
 
@@ -45,6 +49,8 @@
 obj-$(CONFIG_PPC_RTAS)		+= error_log.o proc_rtas.o
 obj-$(CONFIG_PREP_RESIDUAL)	+= residual.o
 obj-$(CONFIG_GEMINI)		+= gemini_pci.o gemini_setup.o gemini_prom.o
+obj-$(CONFIG_PAL4)		+= pal4_setup.o pal4_pci.o cpc700_pic.o
+obj-$(CONFIG_SPRUCE)		+= spruce_setup.o spruce_pci.o cpc700_pic.o
 
 ifeq ($(CONFIG_SMP),y)
 obj-$(CONFIG_ALL_PPC)		+= pmac_smp.o chrp_smp.o
diff -urN linux-2.4.20-pre4/arch/ppc/platforms/apus_pci.c linux-2.4.20-pre5/arch/ppc/platforms/apus_pci.c
--- linux-2.4.20-pre4/arch/ppc/platforms/apus_pci.c	Wed Aug 28 16:36:45 2002
+++ linux-2.4.20-pre5/arch/ppc/platforms/apus_pci.c	Wed Aug 28 16:37:30 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.apus_pci.c 1.5 09/08/01 15:47:42 paulus
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  * Copyright (C) Michel Dänzer <michdaen@iiic.ethz.ch>
@@ -20,6 +20,7 @@
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/string.h>
+#include <linux/init.h>
 
 #include <asm/io.h>
 #include <asm/pci-bridge.h>
diff -urN linux-2.4.20-pre4/arch/ppc/platforms/apus_setup.c linux-2.4.20-pre5/arch/ppc/platforms/apus_setup.c
--- linux-2.4.20-pre4/arch/ppc/platforms/apus_setup.c	Wed Aug 28 16:36:45 2002
+++ linux-2.4.20-pre5/arch/ppc/platforms/apus_setup.c	Wed Aug 28 16:37:30 2002
@@ -141,7 +141,7 @@
 {
 #ifdef CONFIG_APUS
 	extern unsigned long m68k_get_rtc_time(void);
-	
+
 	return m68k_get_rtc_time ();
 #else
 	return 0;
@@ -222,7 +222,7 @@
 		    if ((q = strchr( debug_device, ' ' ))) *q = 0;
 		    i = 1;
 	    } else if (!strncmp( p, "60nsram", 7 )) {
-		    APUS_WRITE (APUS_REG_WAITSTATE, 
+		    APUS_WRITE (APUS_REG_WAITSTATE,
 				REGWAITSTATE_SETRESET
 				|REGWAITSTATE_PPCR
 				|REGWAITSTATE_PPCW);
@@ -286,7 +286,7 @@
 			  "  bne   1b     \n\t"
 			  "  stw   4,0(%0)\n\t"
 			  "  stw   5,4(%0)\n\t"
-			  : 
+			  :
 			  : "r" (time)
 			  : "r4", "r5", "r6");
 }
@@ -395,7 +395,7 @@
 
 /*********************************************************** FLOPPY */
 #if defined(CONFIG_AMIGA_FLOPPY)
-__init 
+__init
 void floppy_setup(char *str, int *ints)
 {
 	if (mach_floppy_setup)
@@ -416,7 +416,7 @@
 	pte_t *pte = 0;
 
 	va &= PAGE_MASK;
-	
+
 	dir = pgd_offset( mm, va );
 	if (dir)
 	{
@@ -447,11 +447,11 @@
 		flags = (_PAGE_NO_CACHE | _PAGE_GUARDED);
 		break;
 	default:
-		panic ("kernel_set_cachemode() doesn't support mode %d\n", 
+		panic ("kernel_set_cachemode() doesn't support mode %d\n",
 		       cmode);
 		break;
 	}
-	
+
 	size /= PAGE_SIZE;
 	address &= PAGE_MASK;
 	while (size--)
@@ -491,7 +491,7 @@
 				goto exit;
 			}
 		}
-		
+
 		ret = (unsigned long) __va(paddr);
 	}
 exit:
@@ -543,7 +543,7 @@
 	       "icbi 0,%0 \n\t"
 	       "isync \n\t"
 	       : : "r" (addr));
-	
+
 	addr += L1_CACHE_BYTES;
 	length -= L1_CACHE_BYTES;
 
@@ -570,11 +570,11 @@
 {
 	cli();
 
-	APUS_WRITE(APUS_REG_LOCK, 
+	APUS_WRITE(APUS_REG_LOCK,
 		   REGLOCK_BLACKMAGICK1|REGLOCK_BLACKMAGICK2);
-	APUS_WRITE(APUS_REG_LOCK, 
+	APUS_WRITE(APUS_REG_LOCK,
 		   REGLOCK_BLACKMAGICK1|REGLOCK_BLACKMAGICK3);
-	APUS_WRITE(APUS_REG_LOCK, 
+	APUS_WRITE(APUS_REG_LOCK,
 		   REGLOCK_BLACKMAGICK2|REGLOCK_BLACKMAGICK3);
 	APUS_WRITE(APUS_REG_SHADOW, REGSHADOW_SELFRESET);
 	APUS_WRITE(APUS_REG_RESET, REGRESET_AMIGARESET);
@@ -657,116 +657,47 @@
 #endif
 /****************************************************** IRQ stuff */
 
-static unsigned int apus_irq_cannonicalize(unsigned int irq)
-{
-	return irq;
-}
-
-int apus_get_irq_list(char *buf)
-{
-#ifdef CONFIG_APUS
-	extern int amiga_get_irq_list(char *buf);
-	
-	return amiga_get_irq_list (buf);
-#else
-	return 0;
-#endif
-}
+static unsigned char last_ipl[8];
 
-/* IPL must be between 0 and 7 */
-static inline void apus_set_IPL(unsigned long ipl)
-{
-	APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_DISABLEINT);
-	APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK);
-	APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | ((~ipl) & IPLEMU_IPLMASK));
-	APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT);
-}
-
-static inline unsigned long apus_get_IPL(void)
-{
-	/* This returns the present IPL emulation level. */
-	unsigned long __f;
-	APUS_READ(APUS_IPL_EMU, __f);
-	return ((~__f) & IPLEMU_IPLMASK);
-}
-
-static inline unsigned long apus_get_prev_IPL(struct pt_regs* regs)
-{
-	/* The value saved in mq is the IPL_EMU value at the time of
-	   interrupt. The lower bits are the current interrupt level,
-	   the upper bits the requested level. Thus, to restore the
-	   IPL level to the post-interrupt state, we will need to use
-	   the lower bits. */
-	unsigned long __f = regs->mq;
-	return ((~__f) & IPLEMU_IPLMASK);
-}
-
-
-#ifdef CONFIG_APUS
-void free_irq(unsigned int irq, void *dev_id)
-{
-	extern void amiga_free_irq(unsigned int irq, void *dev_id);
-
-	amiga_free_irq (irq, dev_id);
-}
-
-int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
-	unsigned long irqflags, const char * devname, void *dev_id)
+int apus_get_irq(struct pt_regs* regs)
 {
-	extern int  amiga_request_irq(unsigned int irq, 
-				      void (*handler)(int, void *, 
-						      struct pt_regs *),
-				      unsigned long flags, 
-				      const char *devname, 
-				      void *dev_id);
+	unsigned char ipl_emu, mask;
+	unsigned int level;
 
-	return amiga_request_irq (irq, handler, irqflags, devname, dev_id);
-}
-
-/* In Linux/m68k the sys_request_irq deals with vectors 0-7. That's what
-   callers expect - but on Linux/APUS we actually use the IRQ_AMIGA_AUTO
-   vectors (24-31), so we put this dummy function in between to adjust
-   the vector argument (rather have cruft here than in the generic irq.c). */
-int sys_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
-		    unsigned long irqflags, const char * devname, void *dev_id)
-{
-	extern int request_sysirq(unsigned int irq, 
-				  void (*handler)(int, void *, 
-						  struct pt_regs *),
-				  unsigned long irqflags,
-				  const char * devname, void *dev_id);
-	return request_sysirq(irq+IRQ_AMIGA_AUTO, handler, irqflags, 
-			      devname, dev_id);
-}
-#endif
+	APUS_READ(APUS_IPL_EMU, ipl_emu);
+	level = (ipl_emu >> 3) & IPLEMU_IPLMASK;
+	mask = IPLEMU_SETRESET|IPLEMU_DISABLEINT|level;
+	level ^= 7;
+
+	/* Save previous IPL value */
+	if (last_ipl[level])
+		return -2;
+	last_ipl[level] = ipl_emu;
+
+	/* Set to current IPL value */
+	APUS_WRITE(APUS_IPL_EMU, mask);
+	APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT|level);
 
-int apus_get_irq(struct pt_regs* regs)
-{
-#ifdef CONFIG_APUS
-	int level = apus_get_IPL();
 
 #ifdef __INTERRUPT_DEBUG
-	printk("<%d:%d>", level, apus_get_prev_IPL(regs));
+	printk("<%d:%d>", level, ~ipl_emu & IPLEMU_IPLMASK);
 #endif
-
-	if (0 == level)
-		return -8;
-	if (7 == level)
-		return -9;
-
 	return level + IRQ_AMIGA_AUTO;
-#else
-	return 0;
-#endif
 }
 
-void apus_post_irq(struct pt_regs* regs, int level)
+void apus_end_irq(unsigned int irq)
 {
+	unsigned char ipl_emu;
+	unsigned int level = irq - IRQ_AMIGA_AUTO;
 #ifdef __INTERRUPT_DEBUG
-	printk("{%d}", apus_get_prev_IPL(regs));
+	printk("{%d}", ~last_ipl[level] & IPLEMU_IPLMASK);
 #endif
 	/* Restore IPL to the previous value */
-	apus_set_IPL(apus_get_prev_IPL(regs));
+	ipl_emu = last_ipl[level] & IPLEMU_IPLMASK;
+	APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET|IPLEMU_DISABLEINT|ipl_emu);
+	last_ipl[level] = 0;
+	ipl_emu ^= 7;
+	APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT|ipl_emu);
 }
 
 /****************************************************** keyboard */
@@ -851,9 +782,9 @@
 }
 
 int __debug_serinit( void )
-{	
+{
 	unsigned long flags;
-	
+
 	save_flags (flags);
 	cli();
 
@@ -871,7 +802,7 @@
 	 */
 	ciab.ddra |= (SER_DTR | SER_RTS);   /* outputs */
 	ciab.ddra &= ~(SER_DCD | SER_CTS | SER_DSR);  /* inputs */
-	
+
 #ifdef CONFIG_KGDB
 	/* turn Rx interrupts on for GDB */
 	custom.intena = IF_SETCLR | IF_RBF;
@@ -913,40 +844,21 @@
 /* The number of spurious interrupts */
 volatile unsigned int num_spurious;
 
-#define NUM_IRQ_NODES 100
-static irq_node_t nodes[NUM_IRQ_NODES];
+extern struct irqaction amiga_sys_irqaction[AUTO_IRQS];
 
-extern void (*amiga_default_handler[AUTO_IRQS])(int, void *, struct pt_regs *);
-
-static const char *default_names[SYS_IRQS] = {
-	"spurious int", "int1 handler", "int2 handler", "int3 handler",
-	"int4 handler", "int5 handler", "int6 handler", "int7 handler"
-};
-
-irq_node_t *new_irq_node(void)
-{
-	irq_node_t *node;
-	short i;
-
-	for (node = nodes, i = NUM_IRQ_NODES-1; i >= 0; node++, i--)
-		if (!node->handler)
-			return node;
-
-	printk ("new_irq_node: out of nodes\n");
-	return NULL;
-}
 
 extern void amiga_enable_irq(unsigned int irq);
 extern void amiga_disable_irq(unsigned int irq);
 
+struct hw_interrupt_type amiga_sys_irqctrl = {
+	typename: "Amiga IPL",
+	end: apus_end_irq,
+};
+
 struct hw_interrupt_type amiga_irqctrl = {
-	" Amiga  ",
-	NULL,
-	NULL,
-	amiga_enable_irq,
-	amiga_disable_irq,
-	0,
-	0
+	typename: "Amiga    ",
+	enable: amiga_enable_irq,
+	disable: amiga_disable_irq,
 };
 
 #define HARDWARE_MAPPED_SIZE (512*1024)
@@ -1015,18 +927,23 @@
 __init
 void apus_init_IRQ(void)
 {
+	struct irqaction *action;
 	int i;
 
-	for ( i = 0 ; i < NR_IRQS ; i++ )
-		irq_desc[i].handler = &amiga_irqctrl;
-
-	for (i = 0; i < NUM_IRQ_NODES; i++)
-		nodes[i].handler = NULL;
+#ifdef CONFIG_PCI
+        apus_setup_pci_ptrs();
+#endif
 
-	for (i = 0; i < AUTO_IRQS; i++) {
-		if (amiga_default_handler[i] != NULL)
-			sys_request_irq(i, amiga_default_handler[i],
-					0, default_names[i], NULL);
+	for ( i = 0 ; i < AMI_IRQS; i++ ) {
+		irq_desc[i].status = IRQ_LEVEL;
+		if (i < IRQ_AMIGA_AUTO) {
+			irq_desc[i].handler = &amiga_irqctrl;
+		} else {
+			irq_desc[i].handler = &amiga_sys_irqctrl;
+			action = &amiga_sys_irqaction[i-IRQ_AMIGA_AUTO];
+			if (action->name)
+				setup_irq(i, action);
+		}
 	}
 
 	amiga_init_IRQ();
@@ -1039,7 +956,7 @@
 {
 	extern int parse_bootinfo(const struct bi_record *);
 	extern char _end[];
-	
+
 	/* Parse bootinfo. The bootinfo is located right after
            the kernel bss */
 	parse_bootinfo((const struct bi_record *)&_end);
@@ -1049,7 +966,7 @@
 	   registers when kernel is booted via a PPC reset. */
 	if ( ramdisk.addr ) {
 		initrd_start = (unsigned long) __va(ramdisk.addr);
-		initrd_end = (unsigned long) 
+		initrd_end = (unsigned long)
 			__va(ramdisk.size + ramdisk.addr);
 	}
 #endif /* CONFIG_BLK_DEV_INITRD */
@@ -1058,13 +975,9 @@
 
 	ppc_md.setup_arch     = apus_setup_arch;
 	ppc_md.show_cpuinfo   = apus_show_cpuinfo;
-	ppc_md.irq_cannonicalize = apus_irq_cannonicalize;
 	ppc_md.init_IRQ       = apus_init_IRQ;
 	ppc_md.get_irq        = apus_get_irq;
-	
-#error Should use the ->end() member of irq_desc[x]. -- Cort
-	/*ppc_md.post_irq       = apus_post_irq;*/
-	
+
 #ifdef CONFIG_HEARTBEAT
 	ppc_md.heartbeat      = apus_heartbeat;
 	ppc_md.heartbeat_count = 1;
diff -urN linux-2.4.20-pre4/arch/ppc/platforms/cpc700.h linux-2.4.20-pre5/arch/ppc/platforms/cpc700.h
--- linux-2.4.20-pre4/arch/ppc/platforms/cpc700.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre5/arch/ppc/platforms/cpc700.h	Wed Aug 28 16:37:30 2002
@@ -0,0 +1,109 @@
+/*
+ * include/asm-ppc/cpc700.h
+ * 
+ * Header file for IBM CPC700 Host Bridge, et. al.
+ *
+ * Author: Mark A. Greer
+ *         mgreer@mvista.com
+ *
+ * Copyright 2000-2002 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED
+ * WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ * NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ * USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the  GNU General Public License along
+ * with this program; if not, write  to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * This file contains the defines and macros for the IBM CPC700 host bridge,
+ * memory controller, PIC, UARTs, IIC, and Timers.
+ */
+
+#ifndef	_ASMPPC_CPC700_H
+#define	_ASMPPC_CPC700_H
+
+#include <linux/stddef.h>
+#include <linux/types.h>
+#include <linux/init.h>
+
+#define CPC700_OUT_32(a,d)  (*(u_int *)a = d)
+#define CPC700_IN_32(a)     (*(u_int *)a)
+
+/*
+ * PCI Section
+ */
+#define CPC700_PCI_CONFIG_ADDR          0xfec00000
+#define CPC700_PCI_CONFIG_DATA          0xfec00004
+
+#define CPC700_PMM0_LOCAL		0xff400000
+#define CPC700_PMM0_MASK_ATTR		0xff400004
+#define CPC700_PMM0_PCI_LOW		0xff400008
+#define CPC700_PMM0_PCI_HIGH		0xff40000c
+#define CPC700_PMM1_LOCAL		0xff400010
+#define CPC700_PMM1_MASK_ATTR		0xff400014
+#define CPC700_PMM1_PCI_LOW		0xff400018
+#define CPC700_PMM1_PCI_HIGH		0xff40001c
+#define CPC700_PMM2_LOCAL		0xff400020
+#define CPC700_PMM2_MASK_ATTR		0xff400024
+#define CPC700_PMM2_PCI_LOW		0xff400028
+#define CPC700_PMM2_PCI_HIGH		0xff40002c
+#define CPC700_PTM1_MEMSIZE		0xff400030
+#define CPC700_PTM1_LOCAL		0xff400034
+#define CPC700_PTM2_MEMSIZE		0xff400038
+#define CPC700_PTM2_LOCAL		0xff40003c
+
+/*
+ * PIC Section
+ *
+ * IBM calls the CPC700's programmable interrupt controller the Universal
+ * Interrupt Controller or UIC.
+ */
+
+/*
+ * UIC Register Addresses.
+ */
+#define	CPC700_UIC_UICSR		0xff500880	/* Status Reg (Rd/Clr)*/
+#define	CPC700_UIC_UICSRS		0xff500884	/* Status Reg (Set) */
+#define	CPC700_UIC_UICER		0xff500888	/* Enable Reg */
+#define	CPC700_UIC_UICCR		0xff50088c	/* Critical Reg */
+#define	CPC700_UIC_UICPR		0xff500890	/* Polarity Reg */
+#define	CPC700_UIC_UICTR		0xff500894	/* Trigger Reg */
+#define	CPC700_UIC_UICMSR		0xff500898	/* Masked Status Reg */
+#define	CPC700_UIC_UICVR		0xff50089c	/* Vector Reg */
+#define	CPC700_UIC_UICVCR		0xff5008a0	/* Vector Config Reg */
+
+#define	CPC700_UIC_UICER_ENABLE		0x00000001	/* Enable an IRQ */
+
+#define	CPC700_UIC_UICVCR_31_HI		0x00000000	/* IRQ 31 hi priority */
+#define	CPC700_UIC_UICVCR_0_HI		0x00000001	/* IRQ 0 hi priority */
+#define CPC700_UIC_UICVCR_BASE_MASK	0xfffffffc
+#define CPC700_UIC_UICVCR_ORDER_MASK	0x00000001
+
+/* Specify value of a bit for an IRQ. */
+#define	CPC700_UIC_IRQ_BIT(i)		((0x00000001) << (31 - (i)))
+
+/*
+ * UIC Exports...
+ */
+extern struct hw_interrupt_type cpc700_pic;
+extern unsigned int cpc700_irq_assigns[32][2];
+ 
+extern void __init cpc700_init_IRQ(void);
+extern int cpc700_get_irq(struct pt_regs *);
+
+#endif	/* _ASMPPC_CPC700_H */
diff -urN linux-2.4.20-pre4/arch/ppc/platforms/cpc700_pic.c linux-2.4.20-pre5/arch/ppc/platforms/cpc700_pic.c
--- linux-2.4.20-pre4/arch/ppc/platforms/cpc700_pic.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre5/arch/ppc/platforms/cpc700_pic.c	Wed Aug 28 16:37:30 2002
@@ -0,0 +1,205 @@
+/*
+ * arch/ppc/platforms/cpc700_pic.c
+ * 
+ * Interrupt controller support for IBM Spruce
+ *
+ * Authors: Mark Greer, Matt Porter, and Johnnie Peters
+ *	    mgreer@mvista.com
+ *          mporter@mvista.com
+ *          jpeters@mvista.com
+ *
+ * Copyright 2001-2002 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED
+ * WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ * NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ * USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the  GNU General Public License along
+ * with this program; if not, write  to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/irq.h>
+
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+
+#include "cpc700.h"
+
+static void
+cpc700_unmask_irq(unsigned int irq)
+{
+	unsigned int tr_bits;
+
+	/*
+	 * IRQ 31 is largest IRQ supported.
+	 * IRQs 17-19 are reserved.
+	 */
+	if ((irq <= 31) && ((irq < 17) || (irq > 19))) {
+		tr_bits = CPC700_IN_32(CPC700_UIC_UICTR);
+
+		if ((tr_bits & (1 << (31 - irq))) == 0) {
+			/* level trigger interrupt, clear bit in status
+			 * register */
+			CPC700_OUT_32(CPC700_UIC_UICSR, 1 << (31 - irq));
+		}
+
+		/* Know IRQ fits in entry 0 of ppc_cached_irq_mask[] */
+		ppc_cached_irq_mask[0] |= CPC700_UIC_IRQ_BIT(irq);
+		
+		CPC700_OUT_32(CPC700_UIC_UICER, ppc_cached_irq_mask[0]);
+	}
+	return;
+}
+
+static void
+cpc700_mask_irq(unsigned int irq)
+{
+	/*
+	 * IRQ 31 is largest IRQ supported.
+	 * IRQs 17-19 are reserved.
+	 */
+	if ((irq <= 31) && ((irq < 17) || (irq > 19))) {
+		/* Know IRQ fits in entry 0 of ppc_cached_irq_mask[] */
+		ppc_cached_irq_mask[0] &=
+			~CPC700_UIC_IRQ_BIT(irq);
+
+		CPC700_OUT_32(CPC700_UIC_UICER, ppc_cached_irq_mask[0]);
+	}
+	return;
+}
+
+static void
+cpc700_mask_and_ack_irq(unsigned int irq)
+{
+	u_int	bit;
+
+	/*
+	 * IRQ 31 is largest IRQ supported.
+	 * IRQs 17-19 are reserved.
+	 */
+	if ((irq <= 31) && ((irq < 17) || (irq > 19))) {
+		/* Know IRQ fits in entry 0 of ppc_cached_irq_mask[] */
+		bit = CPC700_UIC_IRQ_BIT(irq);
+
+		ppc_cached_irq_mask[0] &= ~bit;
+		CPC700_OUT_32(CPC700_UIC_UICER, ppc_cached_irq_mask[0]);
+		CPC700_OUT_32(CPC700_UIC_UICSR, bit); /* Write 1 clears IRQ */
+	}
+	return;
+}
+
+static struct hw_interrupt_type cpc700_pic = {
+	"CPC700 PIC",
+	NULL,
+	NULL,
+	cpc700_unmask_irq,
+	cpc700_mask_irq,
+	cpc700_mask_and_ack_irq,
+	NULL,
+	NULL
+};
+
+__init static void
+cpc700_pic_init_irq(unsigned int irq)
+{
+	unsigned int tmp;
+
+	/* Set interrupt sense */
+	tmp = CPC700_IN_32(CPC700_UIC_UICTR);
+	if (cpc700_irq_assigns[irq][0] == 0) {
+		tmp &= ~CPC700_UIC_IRQ_BIT(irq);
+	} else {
+		tmp |= CPC700_UIC_IRQ_BIT(irq);
+	}
+	CPC700_OUT_32(CPC700_UIC_UICTR, tmp);
+
+	/* Set interrupt polarity */
+	tmp = CPC700_IN_32(CPC700_UIC_UICPR);
+	if (cpc700_irq_assigns[irq][1]) {
+		tmp |= CPC700_UIC_IRQ_BIT(irq);
+	} else {
+		tmp &= ~CPC700_UIC_IRQ_BIT(irq);
+	}
+	CPC700_OUT_32(CPC700_UIC_UICPR, tmp);
+
+	/* Set interrupt critical */
+	tmp = CPC700_IN_32(CPC700_UIC_UICCR);
+	tmp |= CPC700_UIC_IRQ_BIT(irq);
+	CPC700_OUT_32(CPC700_UIC_UICCR, tmp);
+			
+	return;
+}
+	
+__init void
+cpc700_init_IRQ(void)
+{
+	int i;
+
+	ppc_cached_irq_mask[0] = 0;
+	CPC700_OUT_32(CPC700_UIC_UICER, 0x00000000);    /* Disable all irq's */
+	CPC700_OUT_32(CPC700_UIC_UICSR, 0xffffffff);    /* Clear cur intrs */
+	CPC700_OUT_32(CPC700_UIC_UICCR, 0xffffffff);    /* Gen INT not MCP */
+	CPC700_OUT_32(CPC700_UIC_UICPR, 0x00000000);    /* Active low */
+	CPC700_OUT_32(CPC700_UIC_UICTR, 0x00000000);    /* Level Sensitive */
+	CPC700_OUT_32(CPC700_UIC_UICVR, CPC700_UIC_UICVCR_0_HI);
+						        /* IRQ 0 is highest */
+
+	for (i = 0; i < 17; i++) {
+		irq_desc[i].handler = &cpc700_pic;
+		cpc700_pic_init_irq(i);
+	}
+
+	for (i = 20; i < 32; i++) {
+		irq_desc[i].handler = &cpc700_pic;
+		cpc700_pic_init_irq(i);
+	}
+
+	return;
+}
+
+
+
+/*
+ * Find the highest IRQ that generating an interrupt, if any.
+ */
+int
+cpc700_get_irq(struct pt_regs *regs)
+{
+	int irq = 0;
+	u_int irq_status, irq_test = 1;
+
+	irq_status = CPC700_IN_32(CPC700_UIC_UICMSR);
+
+	do
+	{
+		if (irq_status & irq_test)
+			break;
+		irq++;
+		irq_test <<= 1;
+	} while (irq < NR_IRQS);
+		
+
+	if (irq == NR_IRQS)
+	    irq = 33;
+
+	return (31 - irq);
+}
diff -urN linux-2.4.20-pre4/arch/ppc/platforms/gemini_setup.c linux-2.4.20-pre5/arch/ppc/platforms/gemini_setup.c
--- linux-2.4.20-pre4/arch/ppc/platforms/gemini_setup.c	Wed Aug 28 16:36:45 2002
+++ linux-2.4.20-pre5/arch/ppc/platforms/gemini_setup.c	Wed Aug 28 16:37:30 2002
@@ -534,6 +534,8 @@
 {
 	int i;
 
+	parse_bootinfo(find_bootinfo());
+
 	for(i = 0; i < GEMINI_LEDS; i++)
 		gemini_led_off(i);
 
diff -urN linux-2.4.20-pre4/arch/ppc/platforms/oak_setup.c linux-2.4.20-pre5/arch/ppc/platforms/oak_setup.c
--- linux-2.4.20-pre4/arch/ppc/platforms/oak_setup.c	Wed Aug 28 16:36:45 2002
+++ linux-2.4.20-pre5/arch/ppc/platforms/oak_setup.c	Wed Aug 28 16:37:30 2002
@@ -72,6 +72,8 @@
 platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
 	      unsigned long r6, unsigned long r7)
 {
+	parse_bootinfo(find_bootinfo());
+
 	/*
 	 * If we were passed in a board information, copy it into the
 	 * residual data area.
diff -urN linux-2.4.20-pre4/arch/ppc/platforms/pal4.h linux-2.4.20-pre5/arch/ppc/platforms/pal4.h
--- linux-2.4.20-pre4/arch/ppc/platforms/pal4.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre5/arch/ppc/platforms/pal4.h	Wed Aug 28 16:37:30 2002
@@ -0,0 +1,68 @@
+/*
+ * arch/ppc/platforms/pal4.h
+ * 
+ * Definitions for SBS Palomar IV board
+ *
+ * Author: Dan Cox
+ *
+ * Copyright 2002 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __PPC_PLATFORMS_PAL4_H
+#define __PPC_PLATFORMS_PAL4_H
+
+#include <asm/io.h>
+
+#define CPC700_MEM_CFGADDR    0xff500008
+#define CPC700_MEM_CFGDATA    0xff50000c
+
+#define CPC700_MB0SA            0x38
+#define CPC700_MB0EA            0x58
+#define CPC700_MB1SA            0x3c
+#define CPC700_MB1EA            0x5c
+#define CPC700_MB2SA            0x40
+#define CPC700_MB2EA            0x60
+#define CPC700_MB3SA            0x44
+#define CPC700_MB3EA            0x64
+#define CPC700_MB4SA            0x48
+#define CPC700_MB4EA            0x68
+
+extern inline long
+cpc700_read_memreg(int reg)
+{
+	out_be32((volatile unsigned int *) CPC700_MEM_CFGADDR, reg);
+	return in_be32((volatile unsigned int *) CPC700_MEM_CFGDATA);
+}
+
+
+#define PAL4_NVRAM             0xfffc0000
+#define PAL4_NVRAM_SIZE        0x8000
+
+#define PAL4_DRAM              0xfff80000
+#define  PAL4_DRAM_BR_MASK     0xc0
+#define  PAL4_DRAM_BR_SHIFT    6
+#define  PAL4_DRAM_RESET       0x10
+#define  PAL4_DRAM_EREADY      0x40
+
+#define PAL4_MISC              0xfff80004
+#define  PAL4_MISC_FB_MASK     0xc0
+#define  PAL4_MISC_FLASH       0x40  /* StratFlash mapping: 1->0xff80, 0->0xfff0 */
+#define  PAL4_MISC_MISC        0x08
+#define  PAL4_MISC_BITF        0x02
+#define  PAL4_MISC_NVKS        0x01
+
+#define PAL4_L2                0xfff80008
+#define  PAL4_L2_MASK          0x07
+
+#define PAL4_PLDR              0xfff8000c
+
+/* Only two Ethernet devices on the board... */
+#define PAL4_ETH               31
+#define PAL4_INTA              20
+
+#endif /* __PPC_PLATFORMS_PAL4_H */
diff -urN linux-2.4.20-pre4/arch/ppc/platforms/pal4_pci.c linux-2.4.20-pre5/arch/ppc/platforms/pal4_pci.c
--- linux-2.4.20-pre4/arch/ppc/platforms/pal4_pci.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre5/arch/ppc/platforms/pal4_pci.c	Wed Aug 28 16:37:30 2002
@@ -0,0 +1,78 @@
+/*
+ * arch/ppc/platforms/pal4_pci.c
+ * 
+ * PCI support for SBS Palomar IV
+ *
+ * Author: Dan Cox 
+ *
+ * Copyright 2002 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#include <asm/byteorder.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/pci-bridge.h>
+#include <asm/uaccess.h>
+
+#include "cpc700.h"
+#include "pal4.h"
+
+/* not much to this.... */
+static inline int __init
+pal4_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+	if (idsel == 9)
+		return PAL4_ETH;
+	else
+		return PAL4_INTA + (idsel - 3);
+}
+
+void __init
+pal4_find_bridges(void)
+{
+	struct pci_controller *hose;
+
+	hose = pcibios_alloc_controller();
+	if (!hose)
+		return;
+
+	hose->first_busno = 0;
+	hose->last_busno = 0xff;
+	hose->pci_mem_offset = 0;
+
+	/* Could snatch these from the CPC700.... */
+	pci_init_resource(&hose->io_resource,
+			  0x0, 
+			  0x03ffffff,
+			  IORESOURCE_IO,
+			  "PCI host bridge");
+
+	pci_init_resource(&hose->mem_resources[0],
+			  0x90000000,
+			  0x9fffffff,
+			  IORESOURCE_MEM,
+			  "PCI host bridge");
+
+	hose->io_space.start = 0x00800000;
+	hose->io_space.end = 0x03ffffff;
+	hose->mem_space.start = 0x90000000;
+	hose->mem_space.end = 0x9fffffff;
+	hose->io_base_virt = (void *) 0xf8000000;
+	
+	setup_indirect_pci(hose, CPC700_PCI_CONFIG_ADDR,
+			   CPC700_PCI_CONFIG_DATA);
+	
+	hose->last_busno = pciauto_bus_scan(hose, hose->first_busno);
+
+	ppc_md.pci_swizzle = common_swizzle;
+	ppc_md.pci_map_irq = pal4_map_irq;
+}
diff -urN linux-2.4.20-pre4/arch/ppc/platforms/pal4_serial.h linux-2.4.20-pre5/arch/ppc/platforms/pal4_serial.h
--- linux-2.4.20-pre4/arch/ppc/platforms/pal4_serial.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre5/arch/ppc/platforms/pal4_serial.h	Wed Aug 28 16:37:30 2002
@@ -0,0 +1,41 @@
+/*
+ * arch/ppc/platforms/pal4_serial.h
+ * 
+ * Definitions for SBS PalomarIV serial support 
+ *
+ * Author: Dan Cox
+ *
+ * Copyright 2002 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __PPC_PAL4_SERIAL_H
+#define __PPC_PAL4_SERIAL_H
+
+#define CPC700_SERIAL_1       0xff600300
+#define CPC700_SERIAL_2       0xff600400
+
+#define RS_TABLE_SIZE     2
+#define BASE_BAUD         (33333333 / 4 / 16)
+
+#ifdef CONFIG_SERIAL_DETECT_IRQ
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ)
+#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_AUTO_IRQ)
+#else
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST)
+#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF)
+#endif
+
+#define SERIAL_PORT_DFNS \
+      {0, BASE_BAUD, CPC700_SERIAL_1, 3, STD_COM_FLAGS, \
+       iomem_base: (unsigned char *) CPC700_SERIAL_1, \
+       io_type: SERIAL_IO_MEM},   /* ttyS0 */ \
+      {0, BASE_BAUD, CPC700_SERIAL_2, 4, STD_COM_FLAGS, \
+       iomem_base: (unsigned char *) CPC700_SERIAL_2, \
+       io_type: SERIAL_IO_MEM}
+
+#endif
diff -urN linux-2.4.20-pre4/arch/ppc/platforms/pal4_setup.c linux-2.4.20-pre5/arch/ppc/platforms/pal4_setup.c
--- linux-2.4.20-pre4/arch/ppc/platforms/pal4_setup.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre5/arch/ppc/platforms/pal4_setup.c	Wed Aug 28 16:37:30 2002
@@ -0,0 +1,199 @@
+/*
+ * arch/ppc/platforms/pal4_setup.c
+ *
+ * Board setup routines for the SBS PalomarIV.
+ *
+ * Author: Dan Cox
+ *
+ * Copyright 2002 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/reboot.h>
+#include <linux/time.h>
+#include <linux/irq.h>
+#include <linux/kdev_t.h>
+#include <linux/blk.h>
+#include <linux/console.h>
+#include <linux/seq_file.h>
+
+#include <asm/todc.h>
+#include <asm/bootinfo.h>
+
+#include "cpc700.h"
+#include "pal4.h"
+
+extern void pal4_find_bridges(void);
+
+unsigned int cpc700_irq_assigns[][2] = {
+        {1, 1},    /* IRQ 0: ECC correctable error */
+        {1, 1},    /* IRQ 1: PCI write to memory range */
+        {0, 1},    /* IRQ 2: PCI write to command register */
+        {0, 1},    /* IRQ 3: UART 0 */
+        {0, 1},    /* IRQ 4: UART 1 */
+        {0, 1},    /* IRQ 5: ICC 0 */
+        {0, 1},    /* IRQ 6: ICC 1 */
+        {0, 1},    /* IRQ 7: GPT compare 0 */
+        {0, 1},    /* IRQ 8: GPT compare 1 */
+        {0, 1},    /* IRQ 9: GPT compare 2 */
+        {0, 1},    /* IRQ 10: GPT compare 3 */
+        {0, 1},    /* IRQ 11: GPT compare 4 */
+        {0, 1},    /* IRQ 12: GPT capture 0 */
+        {0, 1},    /* IRQ 13: GPT capture 1 */
+        {0, 1},    /* IRQ 14: GPT capture 2 */
+        {0, 1},    /* IRQ 15: GPT capture 3 */
+        {0, 1},    /* IRQ 16: GPT capture 4 */
+        {0, 0},    /* IRQ 17: reserved */
+        {0, 0},    /* IRQ 18: reserved */
+        {0, 0},    /* IRQ 19: reserved */
+        {0, 0},    /* IRQ 20: reserved */
+        {0, 1},    /* IRQ 21: Ethernet */
+        {0, 0},    /* IRQ 22: reserved */
+        {0, 0},    /* IRQ 23: reserved */
+        {0, 0},    /* IRQ 24: resreved */
+        {0, 0},    /* IRQ 25: reserved */
+        {0, 0},    /* IRQ 26: reserved */
+        {0, 0},    /* IRQ 27: reserved */
+        {0, 0},    /* IRQ 28: reserved */
+        {0, 0},    /* IRQ 29: reserved */
+        {0, 0},    /* IRQ 30: reserved */
+        {0, 0},    /* IRQ 31: reserved */
+};
+
+static int
+pal4_show_cpuinfo(struct seq_file *m)
+{
+        seq_printf(m, "board\t\t: SBS Palomar IV\n");
+
+        return 0;
+}
+
+static void
+pal4_restart(char *cmd)
+{
+        __cli();
+        __asm__ __volatile__("lis  3,0xfff0\n \
+                              ori  3,3,0x100\n \
+                              mtspr 26,3\n \
+                              li   3,0\n \
+                              mtspr 27,3\n \
+                              rfi");
+
+        for(;;);
+}
+
+static void
+pal4_power_off(void)
+{
+	__cli();
+	for(;;);
+}
+
+static void
+pal4_halt(void)
+{
+	pal4_power_off();
+}
+
+static unsigned long __init
+pal4_find_end_of_memory(void)
+{
+	int i;
+	unsigned long len, amt, batu, batl;
+
+        __asm__ __volatile__("lis  %0,0xf000\n \
+                              ori  %1,%0,0x002a\n \
+                              ori  %0,%0,0x1ffe\n \
+                              mtspr 0x21e,%0\n \
+                              mtspr 0x21f,%1\n \
+                              isync\n \
+                              sync" : "=r" (batu), "=r" (batl));
+
+	for(len = 0, i = CPC700_MB1EA; i <= CPC700_MB4EA; i+=4) {
+		amt = cpc700_read_memreg(i);
+		if (amt == 0)
+			break;
+		len = amt;
+	}
+
+	return len;
+}
+
+TODC_ALLOC();
+
+static void __init
+pal4_setup_arch(void)
+{
+	unsigned long l2;
+
+	TODC_INIT(TODC_TYPE_MK48T37, 0, 0, 
+		  ioremap(PAL4_NVRAM, PAL4_NVRAM_SIZE), 8);
+
+	pal4_find_bridges();
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (initrd_start)
+		ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
+	else
+#endif
+		ROOT_DEV = to_kdev_t(0x00ff);
+
+	/* The L2 gets disabled in the bootloader, but all the proper
+	   bits should be present from the fw, so just re-enable it */
+	l2 = _get_L2CR();
+	if (!(l2 & L2CR_L2E)) {
+		/* presume that it was initially set if the size is
+		   still present. */
+		if (l2 ^ L2CR_L2SIZ_MASK)
+			_set_L2CR(l2 | L2CR_L2E);
+		else
+			printk("L2 not set by firmware; left disabled.\n");
+	}
+}
+
+static void __init
+pal4_map_io(void)
+{
+	io_block_mapping(0xf0000000, 0xf0000000, 0x10000000, _PAGE_IO);
+}
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+	      unsigned long r6, unsigned long r7)
+{
+	parse_bootinfo(find_bootinfo());
+
+	isa_io_base = 0 /*PAL4_ISA_IO_BASE*/;
+	pci_dram_offset = 0 /*PAL4_PCI_SYS_MEM_BASE*/;
+	
+	ppc_md.setup_arch = pal4_setup_arch;
+	ppc_md.show_cpuinfo = pal4_show_cpuinfo;
+	
+	ppc_md.find_end_of_memory = pal4_find_end_of_memory;
+	ppc_md.setup_io_mappings = pal4_map_io;
+
+	ppc_md.init_IRQ = cpc700_init_IRQ;
+	ppc_md.get_irq = cpc700_get_irq;
+
+	ppc_md.restart = pal4_restart;
+	ppc_md.halt = pal4_halt;
+	ppc_md.power_off = pal4_power_off;
+
+	ppc_md.time_init = todc_time_init;
+	ppc_md.set_rtc_time = todc_set_rtc_time;
+	ppc_md.get_rtc_time = todc_get_rtc_time;
+	ppc_md.calibrate_decr = todc_calibrate_decr;
+
+	ppc_md.nvram_read_val = todc_direct_read_val;
+	ppc_md.nvram_write_val = todc_direct_write_val;
+}
+
diff -urN linux-2.4.20-pre4/arch/ppc/platforms/spruce.h linux-2.4.20-pre5/arch/ppc/platforms/spruce.h
--- linux-2.4.20-pre4/arch/ppc/platforms/spruce.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre5/arch/ppc/platforms/spruce.h	Wed Aug 28 16:37:30 2002
@@ -0,0 +1,99 @@
+/*
+ * include/asm-ppc/platforms/spruce.h
+ * 
+ * Definitions for IBM Spruce reference board support
+ *
+ * Authors: Matt Porter and Johnnie Peters
+ *          mporter@mvista.com
+ *          jpeters@mvista.com
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED
+ * WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ * NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ * USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the  GNU General Public License along
+ * with this program; if not, write  to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_SPRUCE_H__
+#define __ASM_SPRUCE_H__
+
+#define SPRUCE_PCI_CONFIG_ADDR	0xfec00000
+#define SPRUCE_PCI_CONFIG_DATA	0xfec00004
+
+#define SPRUCE_PCI_PHY_IO_BASE	0xf8000000
+#define SPRUCE_PCI_IO_BASE	SPRUCE_PCI_PHY_IO_BASE
+
+#define SPRUCE_PCI_SYS_MEM_BASE	0x00000000
+
+#define SPRUCE_PCI_LOWER_MEM	0x80000000
+#define SPRUCE_PCI_UPPER_MEM	0x9fffffff
+#define SPRUCE_PCI_LOWER_IO	0x00000000
+#define SPRUCE_PCI_UPPER_IO	0x03ffffff
+
+#define	SPRUCE_ISA_IO_BASE	SPRUCE_PCI_IO_BASE
+
+#define SPRUCE_MEM_SIZE		0x04000000
+#define SPRUCE_BUS_SPEED	66666667
+
+#define SPRUCE_NVRAM_BASE_ADDR	0xff800000
+#define SPRUCE_RTC_BASE_ADDR	SPRUCE_NVRAM_BASE_ADDR
+
+#define KEYBOARD_IRQ    22
+#define AUX_IRQ 	21
+
+unsigned char spruce_read_keyb_data(void);
+unsigned char spruce_read_keyb_status(void);
+
+#define kbd_read_input  spruce_read_keyb_data
+#define kbd_read_status spruce_read_keyb_status
+#define kbd_write_output(val) *((unsigned char *)0xff810000) = (char)val
+#define kbd_write_command(val) *((unsigned char *)0xff810001) = (char)val
+
+/*
+ * Serial port defines
+ */ 
+#define SPRUCE_FPGA_REG_A	0xff820000
+#define SPRUCE_UARTCLK_33M	0x02
+#define SPRUCE_UARTCLK_IS_33M(reg)	(reg & SPRUCE_UARTCLK_33M)
+
+#define UART0_IO_BASE	0xff600300
+#define UART1_IO_BASE	0xff600400
+
+#define RS_TABLE_SIZE	2
+
+#define SPRUCE_BAUD_33M	33000000/64
+#define SPRUCE_BAUD_30M	30000000/64
+#define BASE_BAUD	SPRUCE_BAUD_33M
+
+#define UART0_INT	3
+#define UART1_INT	4
+
+#define STD_UART_OP(num)					\
+	{ 0, BASE_BAUD, 0, UART##num##_INT,			\
+		(ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST),	\
+		iomem_base: UART##num##_IO_BASE,		\
+		io_type: SERIAL_IO_MEM},
+
+#define SERIAL_PORT_DFNS	\
+	STD_UART_OP(0)		\
+	STD_UART_OP(1)
+
+#endif /* __ASM_SPRUCE_H__ */
+#endif /* __KERNEL__ */
diff -urN linux-2.4.20-pre4/arch/ppc/platforms/spruce_pci.c linux-2.4.20-pre5/arch/ppc/platforms/spruce_pci.c
--- linux-2.4.20-pre4/arch/ppc/platforms/spruce_pci.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre5/arch/ppc/platforms/spruce_pci.c	Wed Aug 28 16:37:30 2002
@@ -0,0 +1,104 @@
+/*
+ * arch/ppc/platforms/spruce_pci.c
+ * 
+ * PCI support for IBM Spruce
+ *
+ * Author: Johnnie Peters
+ *         jpeters@mvista.com
+ *
+ * Copyright 2000 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED
+ * WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ * NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ * USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the  GNU General Public License along
+ * with this program; if not, write  to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+#include <platforms/spruce.h>
+
+#include "cpc700.h"
+
+static inline int
+spruce_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+	static char pci_irq_table[][4] =
+		/*
+		 * 	PCI IDSEL/INTPIN->INTLINE 
+		 * 	A	B	C	D
+		 */
+	{
+		{23, 24, 25, 26},	/* IDSEL 1 - PCI slot 3 */
+		{24, 25, 26, 23},	/* IDSEL 2 - PCI slot 2 */
+		{25, 26, 23, 24},	/* IDSEL 3 - PCI slot 1 */
+		{26, 23, 24, 25},	/* IDSEL 4 - PCI slot 0 */
+	};
+
+	const long min_idsel = 1, max_idsel = 4, irqs_per_slot = 4;
+	return PCI_IRQ_TABLE_LOOKUP;
+}
+
+void __init
+spruce_setup_hose(void)
+{
+	struct pci_controller *hose;
+
+	/* Setup hose */
+	hose = pcibios_alloc_controller();
+	if (!hose) 
+		return;
+
+	hose->first_busno = 0;
+	hose->last_busno = 0xff;
+
+	pci_init_resource(&hose->io_resource,
+			SPRUCE_PCI_LOWER_IO,
+			SPRUCE_PCI_UPPER_IO,
+			IORESOURCE_IO,
+			"PCI host bridge");
+
+	pci_init_resource(&hose->mem_resources[0],
+			SPRUCE_PCI_LOWER_MEM,
+			SPRUCE_PCI_UPPER_MEM,
+			IORESOURCE_MEM,
+			"PCI host bridge");
+
+	hose->io_space.start = SPRUCE_PCI_LOWER_IO;
+	hose->io_space.end = SPRUCE_PCI_UPPER_IO;
+	hose->mem_space.start = SPRUCE_PCI_LOWER_MEM;
+	hose->mem_space.end = SPRUCE_PCI_UPPER_MEM;
+	hose->io_base_virt = (void *)SPRUCE_ISA_IO_BASE;
+
+	setup_indirect_pci(hose,
+			SPRUCE_PCI_CONFIG_ADDR,
+			SPRUCE_PCI_CONFIG_DATA);
+
+	hose->last_busno = pciauto_bus_scan(hose, hose->first_busno);
+
+	ppc_md.pci_swizzle = common_swizzle;
+	ppc_md.pci_map_irq = spruce_map_irq;
+}
diff -urN linux-2.4.20-pre4/arch/ppc/platforms/spruce_setup.c linux-2.4.20-pre5/arch/ppc/platforms/spruce_setup.c
--- linux-2.4.20-pre4/arch/ppc/platforms/spruce_setup.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre5/arch/ppc/platforms/spruce_setup.c	Wed Aug 28 16:37:30 2002
@@ -0,0 +1,327 @@
+/*
+ * arch/ppc/platforms/spruce_setup.c
+ *
+ * Board setup routines for IBM Spruce
+ *
+ * Authors: Johnnie Peters <jpeters@mvista.com>
+ *          Matt Porter <mporter@mvista.com>
+ *
+ * Copyright 2001-2002 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED
+ * WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ * NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ * USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the  GNU General Public License along
+ * with this program; if not, write  to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/reboot.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/types.h>
+#include <linux/major.h>
+#include <linux/blk.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include <linux/ide.h>
+#include <linux/serial.h>
+
+#include <asm/keyboard.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/time.h>
+#include <platforms/spruce.h>
+#include <asm/todc.h>
+#include <asm/bootinfo.h>
+
+#include "cpc700.h"
+
+extern void spruce_init_IRQ(void);
+extern int spruce_get_irq(struct pt_regs *);
+extern void spruce_setup_hose(void);
+
+extern int pckbd_setkeycode(unsigned int, unsigned int);
+extern int pckbd_getkeycode(unsigned int);
+extern int pckbd_translate(unsigned char, unsigned char *, char);
+extern char pckbd_unexpected_up(unsigned char);
+extern void pckbd_leds(unsigned char);
+extern void pckbd_init_hw(void);
+extern unsigned char pckbd_sysrq_xlate[128];
+extern char cmd_line[];
+
+/*
+ * CPC700 PIC interrupt programming table
+ *
+ * First entry is the sensitivity (level/edge), second is the polarity.
+ */
+unsigned int cpc700_irq_assigns[32][2] = {
+	{ 1, 1 },       /* IRQ  0: ECC Correctable Error - rising edge */
+	{ 1, 1 },       /* IRQ  1: PCI Write Mem Range   - rising edge */
+	{ 0, 1 },       /* IRQ  2: PCI Write Command Reg - active high */
+	{ 0, 1 },       /* IRQ  3: UART 0                - active high */
+	{ 0, 1 },       /* IRQ  4: UART 1                - active high */
+	{ 0, 1 },       /* IRQ  5: ICC 0                 - active high */
+	{ 0, 1 },       /* IRQ  6: ICC 1                 - active high */
+	{ 0, 1 },       /* IRQ  7: GPT Compare 0         - active high */
+	{ 0, 1 },       /* IRQ  8: GPT Compare 1         - active high */
+	{ 0, 1 },       /* IRQ  9: GPT Compare 2         - active high */
+	{ 0, 1 },       /* IRQ 10: GPT Compare 3         - active high */
+	{ 0, 1 },       /* IRQ 11: GPT Compare 4         - active high */
+	{ 0, 1 },       /* IRQ 12: GPT Capture 0         - active high */
+	{ 0, 1 },       /* IRQ 13: GPT Capture 1         - active high */
+	{ 0, 1 },       /* IRQ 14: GPT Capture 2         - active high */
+	{ 0, 1 },       /* IRQ 15: GPT Capture 3         - active high */
+	{ 0, 1 },       /* IRQ 16: GPT Capture 4         - active high */
+	{ 0, 0 },       /* IRQ 17: Reserved */
+	{ 0, 0 },       /* IRQ 18: Reserved */
+	{ 0, 0 },       /* IRQ 19: Reserved */
+	{ 0, 1 },       /* IRQ 20: FPGA EXT_IRQ0         - active high */
+	{ 1, 1 },       /* IRQ 21: Mouse                 - rising edge */
+	{ 1, 1 },       /* IRQ 22: Keyboard              - rising edge */
+	{ 0, 0 },       /* IRQ 23: PCI Slot 3            - active low */
+	{ 0, 0 },       /* IRQ 24: PCI Slot 2            - active low */
+	{ 0, 0 },       /* IRQ 25: PCI Slot 1            - active low */
+	{ 0, 0 },       /* IRQ 26: PCI Slot 0            - active low */
+};
+
+static void __init
+spruce_calibrate_decr(void)
+{
+	int freq, divisor = 4;
+
+	/* determine processor bus speed */
+	freq = SPRUCE_BUS_SPEED;
+	tb_ticks_per_jiffy = freq / HZ / divisor;
+	tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000);
+}
+
+static int
+spruce_show_cpuinfo(struct seq_file *m)
+{
+	seq_printf(m, "vendor\t\t: IBM\n");
+	seq_printf(m, "machine\t\t: Spruce\n");
+
+	return 0;
+}
+
+TODC_ALLOC();
+
+static void __init
+spruce_setup_arch(void)
+{
+	u32 baud_base;
+	struct serial_struct serial_req;
+
+	/* Setup TODC access */
+	TODC_INIT(TODC_TYPE_DS1643, 0, 0, SPRUCE_RTC_BASE_ADDR, 8);
+
+	/* init to some ~sane value until calibrate_delay() runs */
+	loops_per_jiffy = 50000000 / HZ;
+
+	/* Setup PCI host bridge */
+	spruce_setup_hose();
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (initrd_start)
+		ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); /* /dev/ram */
+	else
+#endif
+#ifdef CONFIG_ROOT_NFS
+		ROOT_DEV = to_kdev_t(0x00FF);	/* /dev/nfs pseudo device */
+#else
+		ROOT_DEV = to_kdev_t(0x0801);	/* /dev/sda1 */
+#endif
+
+#ifdef CONFIG_DUMMY_CONSOLE
+	conswitchp = &dummy_con;
+#endif
+
+	if (SPRUCE_UARTCLK_IS_33M(readb(SPRUCE_FPGA_REG_A)))	
+		baud_base = SPRUCE_BAUD_33M;
+	else
+		baud_base = SPRUCE_BAUD_30M;
+
+	/* Setup serial port access */
+	memset(&serial_req, 0, sizeof(serial_req));
+	serial_req.baud_base = baud_base;
+	serial_req.line = 0;
+	serial_req.port = 0;
+	serial_req.irq = 3;
+	serial_req.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
+	serial_req.io_type = SERIAL_IO_MEM;
+	serial_req.iomem_base = UART0_IO_BASE;
+	serial_req.iomem_reg_shift = 0;
+
+	if (early_serial_setup(&serial_req) != 0) {
+		printk("Early serial init of port 0 failed\n");
+	}
+
+	/* Assume early_serial_setup() doesn't modify serial_req */
+	serial_req.line = 1;
+	serial_req.port = 1;
+	serial_req.irq = 4; 
+	serial_req.iomem_base = UART1_IO_BASE;
+
+	if (early_serial_setup(&serial_req) != 0) {
+		printk("Early serial init of port 1 failed\n");
+	}
+
+	/* Identify the system */
+	printk("System Identification: IBM Spruce\n");
+	printk("IBM Spruce port (C) 2001 MontaVista Software, Inc. (source@mvista.com)\n");
+}
+
+static void
+spruce_restart(char *cmd)
+{
+	__cli();
+
+	/* SRR0 has system reset vector, SRR1 has default MSR value */
+	/* rfi restores MSR from SRR1 and sets the PC to the SRR0 value */
+	__asm__ __volatile__
+	("\n\
+	lis	3,0xfff0
+	ori	3,3,0x0100
+	mtspr	26,3
+	li	3,0
+	mtspr	27,3
+	rfi
+	");
+	for(;;);
+}
+
+static void
+spruce_power_off(void)
+{
+	for(;;);
+}
+
+static void
+spruce_halt(void)
+{
+	spruce_restart(NULL);
+}
+
+static unsigned long __init
+spruce_find_end_of_memory(void)
+{
+	return boot_mem_size;
+}
+
+static void __init
+spruce_map_io(void)
+{
+	io_block_mapping(SPRUCE_PCI_IO_BASE, SPRUCE_PCI_PHY_IO_BASE,
+			 0x08000000, _PAGE_IO);
+}
+
+unsigned char spruce_read_keyb_status(void)
+{
+	unsigned long kbd_status;
+
+	__raw_writel(0x00000088, 0xff500008);
+	eieio();
+
+	__raw_writel(0x03000000, 0xff50000c);
+	eieio();
+
+	asm volatile("	lis	7,0xff88	\n
+			ori	7,7,0x8		\n
+			lswi	6,7,0x8		\n
+			mr	%0,6		\n"
+			: "=r" (kbd_status) :: "6", "7");
+
+	__raw_writel(0x00000000, 0xff50000c);
+	eieio();
+
+	return (unsigned char)(kbd_status >> 24);
+}
+
+unsigned char spruce_read_keyb_data(void)
+{
+	unsigned long kbd_data;
+
+	__raw_writel(0x00000088, 0xff500008);
+	eieio();
+
+	__raw_writel(0x03000000, 0xff50000c);
+	eieio();
+
+	asm volatile("	lis	7,0xff88	\n
+			lswi	6,7,0x8		\n
+			mr	%0,6		\n"
+			: "=r" (kbd_data) :: "6", "7");
+
+	__raw_writel(0x00000000, 0xff50000c);
+	eieio();
+
+	return (unsigned char)(kbd_data >> 24);
+}
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+	      unsigned long r6, unsigned long r7)
+{
+	parse_bootinfo(find_bootinfo());
+
+	isa_io_base = SPRUCE_ISA_IO_BASE;
+	pci_dram_offset = SPRUCE_PCI_SYS_MEM_BASE;
+
+	ppc_md.setup_arch = spruce_setup_arch;
+	ppc_md.show_cpuinfo = spruce_show_cpuinfo;
+	ppc_md.init_IRQ = cpc700_init_IRQ;
+	ppc_md.get_irq = cpc700_get_irq;
+
+	ppc_md.find_end_of_memory = spruce_find_end_of_memory;
+	ppc_md.setup_io_mappings = spruce_map_io;
+
+	ppc_md.restart = spruce_restart;
+	ppc_md.power_off = spruce_power_off;
+	ppc_md.halt = spruce_halt;
+
+	ppc_md.time_init = todc_time_init;
+	ppc_md.set_rtc_time = todc_set_rtc_time;
+	ppc_md.get_rtc_time = todc_get_rtc_time;
+	ppc_md.calibrate_decr = spruce_calibrate_decr;
+
+	ppc_md.nvram_read_val = todc_direct_read_val;
+	ppc_md.nvram_write_val = todc_direct_write_val;
+
+#ifdef CONFIG_VT
+	/* Spruce has a PS2 style keyboard */
+	ppc_md.kbd_setkeycode = pckbd_setkeycode;
+	ppc_md.kbd_getkeycode = pckbd_getkeycode;
+	ppc_md.kbd_translate = pckbd_translate;
+	ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
+	ppc_md.kbd_leds = pckbd_leds;
+	ppc_md.kbd_init_hw = pckbd_init_hw;
+#ifdef CONFIG_MAGIC_SYSRQ
+	ppc_md.kbd_sysrq_xlate = pckbd_sysrq_xlate;
+	SYSRQ_KEY = 0x54;
+#endif
+#endif
+}
diff -urN linux-2.4.20-pre4/arch/ppc64/Makefile linux-2.4.20-pre5/arch/ppc64/Makefile
--- linux-2.4.20-pre4/arch/ppc64/Makefile	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/Makefile	Wed Aug 28 16:37:30 2002
@@ -22,7 +22,8 @@
 LINKFLAGS	= -T arch/ppc64/vmlinux.lds -Bstatic \
 		-e $(KERNELLOAD) -Ttext $(KERNELLOAD)
 CFLAGS		:= $(CFLAGS) -fsigned-char -msoft-float -pipe \
-		-Wno-uninitialized -mminimal-toc -fno-builtin
+		-Wno-uninitialized -mminimal-toc -fno-builtin \
+		-mtraceback=full
 CPP		= $(CC) -E $(CFLAGS)
 
 
diff -urN linux-2.4.20-pre4/arch/ppc64/boot/addRamDisk.c linux-2.4.20-pre5/arch/ppc64/boot/addRamDisk.c
--- linux-2.4.20-pre4/arch/ppc64/boot/addRamDisk.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/boot/addRamDisk.c	Wed Aug 28 16:37:30 2002
@@ -25,7 +25,7 @@
 
 void death(const char *msg, FILE *fdesc, const char *fname) 
 {
-	printf(msg);
+	fprintf(stderr, msg);
 	fclose(fdesc);
 	unlink(fname);
 	exit(1);
@@ -66,47 +66,47 @@
   
   
 	if (argc < 2) {
-		printf("Name of RAM disk file missing.\n");
+		fprintf(stderr, "Name of RAM disk file missing.\n");
 		exit(1);
 	}
 
 	if (argc < 3) {
-		printf("Name of System Map input file is missing.\n");
+		fprintf(stderr, "Name of System Map input file is missing.\n");
 		exit(1);
 	}
   
 	if (argc < 4) {
-		printf("Name of vmlinux file missing.\n");
+		fprintf(stderr, "Name of vmlinux file missing.\n");
 		exit(1);
 	}
 
 	if (argc < 5) {
-		printf("Name of vmlinux output file missing.\n");
+		fprintf(stderr, "Name of vmlinux output file missing.\n");
 		exit(1);
 	}
 
 
 	ramDisk = fopen(argv[1], "r");
 	if ( ! ramDisk ) {
-		printf("RAM disk file \"%s\" failed to open.\n", argv[1]);
+		fprintf(stderr, "RAM disk file \"%s\" failed to open.\n", argv[1]);
 		exit(1);
 	}
 
 	sysmap = fopen(argv[2], "r");
 	if ( ! sysmap ) {
-		printf("System Map file \"%s\" failed to open.\n", argv[2]);
+		fprintf(stderr, "System Map file \"%s\" failed to open.\n", argv[2]);
 		exit(1);
 	}
   
 	inputVmlinux = fopen(argv[3], "r");
 	if ( ! inputVmlinux ) {
-		printf("vmlinux file \"%s\" failed to open.\n", argv[3]);
+		fprintf(stderr, "vmlinux file \"%s\" failed to open.\n", argv[3]);
 		exit(1);
 	}
   
 	outputVmlinux = fopen(argv[4], "w+");
 	if ( ! outputVmlinux ) {
-		printf("output vmlinux file \"%s\" failed to open.\n", argv[4]);
+		fprintf(stderr, "output vmlinux file \"%s\" failed to open.\n", argv[4]);
 		exit(1);
 	}
   
@@ -118,7 +118,7 @@
 	fseek(inputVmlinux, 0, SEEK_SET);
 	printf("kernel file size = %d\n", kernelLen);
 	if ( kernelLen == 0 ) {
-		printf("You must have a linux kernel specified as argv[3]\n");
+		fprintf(stderr, "You must have a linux kernel specified as argv[3]\n");
 		exit(1);
 	}
 
@@ -160,9 +160,9 @@
 	/* search for _end in the last page of the system map */
 	ptr_end = strstr(inbuf, " _end");
 	if (!ptr_end) {
-		printf("Unable to find _end in the sysmap file \n");
-		printf("inbuf: \n");
-		printf("%s \n", inbuf);
+		fprintf(stderr, "Unable to find _end in the sysmap file \n");
+		fprintf(stderr, "inbuf: \n");
+		fprintf(stderr, "%s \n", inbuf);
 		exit(1);
 	}
 	printf("Found _end in the last page of the sysmap - backing up 10 characters it looks like %s", ptr_end-10);
diff -urN linux-2.4.20-pre4/arch/ppc64/boot/addSystemMap.c linux-2.4.20-pre5/arch/ppc64/boot/addSystemMap.c
--- linux-2.4.20-pre4/arch/ppc64/boot/addSystemMap.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/boot/addSystemMap.c	Wed Aug 28 16:37:30 2002
@@ -64,38 +64,38 @@
 	long padPages = 0;
 	if ( argc < 2 )
 	{
-		printf("Name of System Map file missing.\n");
+		fprintf(stderr, "Name of System Map file missing.\n");
 		exit(1);
 	}
 
 	if ( argc < 3 )
 	{
-		printf("Name of vmlinux file missing.\n");
+		fprintf(stderr, "Name of vmlinux file missing.\n");
 		exit(1);
 	}
 
 	if ( argc < 4 )
 	{
-		printf("Name of vmlinux output file missing.\n");
+		fprintf(stderr, "Name of vmlinux output file missing.\n");
 		exit(1);
 	}
 
 	sysmap = fopen(argv[1], "r");
 	if ( ! sysmap )
 	{
-		printf("System Map file \"%s\" failed to open.\n", argv[1]);
+		fprintf(stderr, "System Map file \"%s\" failed to open.\n", argv[1]);
 		exit(1);
 	}
 	inputVmlinux = fopen(argv[2], "r");
 	if ( ! inputVmlinux )
 	{
-		printf("vmlinux file \"%s\" failed to open.\n", argv[2]);
+		fprintf(stderr, "vmlinux file \"%s\" failed to open.\n", argv[2]);
 		exit(1);
 	}
 	outputVmlinux = fopen(argv[3], "w");
 	if ( ! outputVmlinux )
 	{
-		printf("output vmlinux file \"%s\" failed to open.\n", argv[3]);
+		fprintf(stderr, "output vmlinux file \"%s\" failed to open.\n", argv[3]);
 		exit(1);
 	}
 
@@ -107,7 +107,7 @@
 	printf("kernel file size = %ld\n", kernelLen);
 	if ( kernelLen == 0 )
 	{
-		printf("You must have a linux kernel specified as argv[2]\n");
+		fprintf(stderr, "You must have a linux kernel specified as argv[2]\n");
 		exit(1);
 	}
 
@@ -154,9 +154,9 @@
 	ptr_end = strstr(inbuf, " _end");
 	if (!ptr_end)
 	{
-		printf("Unable to find _end in the sysmap file \n");
-		printf("inbuf: \n");
-		printf("%s \n", inbuf);
+		fprintf(stderr, "Unable to find _end in the sysmap file \n");
+		fprintf(stderr, "inbuf: \n");
+		fprintf(stderr, "%s \n", inbuf);
 		exit(1);
 	}
 	printf("Found _end in the last page of the sysmap - backing up 10 characters it looks like %s", ptr_end-10);
diff -urN linux-2.4.20-pre4/arch/ppc64/boot/zImage.c linux-2.4.20-pre5/arch/ppc64/boot/zImage.c
--- linux-2.4.20-pre4/arch/ppc64/boot/zImage.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/boot/zImage.c	Wed Aug 28 16:37:30 2002
@@ -225,7 +225,7 @@
 
 	rec = bi_rec_alloc(rec, 2);
 	rec->tag = BI_MACHTYPE;
-	rec->data[0] = _MACH_pSeries;
+	rec->data[0] = PLATFORM_PSERIES;
 	rec->data[1] = 1;
 
 	if ( initrd.size > 0 ) {
diff -urN linux-2.4.20-pre4/arch/ppc64/config.in linux-2.4.20-pre5/arch/ppc64/config.in
--- linux-2.4.20-pre4/arch/ppc64/config.in	Wed Aug 28 16:36:45 2002
+++ linux-2.4.20-pre5/arch/ppc64/config.in	Wed Aug 28 16:37:30 2002
@@ -37,6 +37,7 @@
    define_bool CONFIG_MSCHUNKS y
 else
 bool 'MsChunks Physical to Absolute address translation support' CONFIG_MSCHUNKS
+tristate 'Firmware flash interface' CONFIG_RTAS_FLASH
 fi
 
 
@@ -59,6 +60,7 @@
 define_bool CONFIG_MCA n
 define_bool CONFIG_EISA n
 define_bool CONFIG_PCI y
+define_bool CONFIG_PCMCIA n
 
 bool 'Networking support' CONFIG_NET
 bool 'Sysctl support' CONFIG_SYSCTL
@@ -70,9 +72,9 @@
    define_bool CONFIG_KCORE_ELF y
 fi
 
-bool 'Kernel support for 64-bit ELF binaries' CONFIG_BINFMT_ELF
+bool 'Kernel support for 64 bit ELF binaries' CONFIG_BINFMT_ELF
 
-tristate 'Kernel support for 32-bit ELF binaries' CONFIG_BINFMT_ELF32
+tristate 'Kernel support for 32 bit ELF binaries' CONFIG_BINFMT_ELF32
 
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 
@@ -80,12 +82,6 @@
 
 bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG
 
-if [ "$CONFIG_HOTPLUG" = "y" ]; then
-   source drivers/pcmcia/Config.in
-else
-   define_bool CONFIG_PCMCIA n
-fi
-
 source drivers/parport/Config.in
 
 if [ "$CONFIG_PPC_ISERIES" != "y" ]; then
@@ -93,12 +89,15 @@
    bool 'Support for frame buffer devices' CONFIG_FB
 
    bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE
+
+   bool 'Default bootloader kernel arguments' CONFIG_CMDLINE_BOOL
+   if [ "$CONFIG_CMDLINE_BOOL" = "y" ] ; then
+     string 'Initial kernel command string' CONFIG_CMDLINE "console=ttyS0,9600 console=tty0 root=/dev/sda2"
+   fi
 fi
 
 endmenu
 
-source drivers/mtd/Config.in
-source drivers/pnp/Config.in
 source drivers/block/Config.in
 source drivers/md/Config.in
 
@@ -145,8 +144,6 @@
 
 source net/ax25/Config.in
 
-source net/irda/Config.in
-
 mainmenu_option next_comment
 comment 'ISDN subsystem'
 
@@ -165,12 +162,14 @@
 fi
 endmenu
 
+if [ "$CONFIG_PPC_ISERIES" != "y" ]; then
 mainmenu_option next_comment
 comment 'Console drivers'
 source drivers/video/Config.in
 endmenu
 
 source drivers/input/Config.in
+fi
 
 if [ "$CONFIG_PPC_ISERIES" = "y" ]; then
 mainmenu_option next_comment
@@ -214,6 +213,7 @@
 source drivers/char/Config.in
 source fs/Config.in
 
+if [ "$CONFIG_PPC_ISERIES" != "y" ]; then
 mainmenu_option next_comment
 comment 'Sound'
 tristate 'Sound card support' CONFIG_SOUND
@@ -224,7 +224,9 @@
 
 endmenu
 
+source drivers/media/Config.in
 source drivers/usb/Config.in
+fi
 
 mainmenu_option next_comment
 comment 'Kernel hacking'
@@ -232,10 +234,21 @@
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
 bool 'Include kgdb kernel debugger' CONFIG_KGDB
 bool 'Include xmon kernel debugger' CONFIG_XMON
-#bool 'Include kdb kernel debugger' CONFIG_KDB
-#if [ "$CONFIG_KDB" = "y" ]; then
-#  bool '  KDB off by default' CONFIG_KDB_OFF
-#  define_bool CONFIG_KALLSYMS y
-#fi
+bool 'Include kdb kernel debugger' CONFIG_KDB
+if [ "$CONFIG_KDB" = "y" ]; then
+  bool '  KDB off by default' CONFIG_KDB_OFF
+  define_bool CONFIG_KALLSYMS y
+  define_bool CONFIG_XMON n
+fi
+if [ "$CONFIG_XMON" = "y" ]; then
+  define_bool CONFIG_KDB n
+  define_bool CONFIG_KALLSYMS n
+fi
 bool 'Include PPCDBG realtime debugging' CONFIG_PPCDBG
+
+tristate 'Linux Kernel Crash Dump (LKCD) Support' CONFIG_DUMP
+if [ "$CONFIG_DUMP" = "y" -o "$CONFIG_DUMP" = "m" ]; then
+   dep_bool '  LKCD RLE compression' CONFIG_DUMP_COMPRESS_RLE $CONFIG_DUMP
+   dep_bool '  LKCD GZIP compression' CONFIG_DUMP_COMPRESS_GZIP $CONFIG_DUMP
+fi
 endmenu
diff -urN linux-2.4.20-pre4/arch/ppc64/configs/iSeries_devfs_defconfig linux-2.4.20-pre5/arch/ppc64/configs/iSeries_devfs_defconfig
--- linux-2.4.20-pre4/arch/ppc64/configs/iSeries_devfs_defconfig	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/configs/iSeries_devfs_defconfig	Wed Aug 28 16:37:30 2002
@@ -696,4 +696,10 @@
 # CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_KGDB is not set
 # CONFIG_XMON is not set
+# CONFIG_KDB is not set
+# CONFIG_KDB_OFF is not set
+# CONFIG_KALLSYMS is not set
 # CONFIG_PPCDBG is not set
+CONFIG_DUMP=y
+CONFIG_DUMP_COMPRESS_RLE=y
+CONFIG_DUMP_COMPRESS_GZIP=y
diff -urN linux-2.4.20-pre4/arch/ppc64/configs/iSeries_nodevfs_ideemul_defconfig linux-2.4.20-pre5/arch/ppc64/configs/iSeries_nodevfs_ideemul_defconfig
--- linux-2.4.20-pre4/arch/ppc64/configs/iSeries_nodevfs_ideemul_defconfig	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/configs/iSeries_nodevfs_ideemul_defconfig	Wed Aug 28 16:37:30 2002
@@ -67,7 +67,6 @@
 #
 # CONFIG_PNP is not set
 # CONFIG_ISAPNP is not set
-# CONFIG_PNPBIOS is not set
 
 #
 # Block devices
@@ -77,6 +76,7 @@
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_NBD is not set
@@ -101,8 +101,6 @@
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK=y
-CONFIG_RTNETLINK=y
 # CONFIG_NETLINK_DEV is not set
 # CONFIG_NETFILTER is not set
 CONFIG_FILTER=y
@@ -110,8 +108,6 @@
 CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
 CONFIG_IP_ADVANCED_ROUTER=y
-CONFIG_RTNETLINK=y
-CONFIG_NETLINK=y
 CONFIG_IP_MULTIPLE_TABLES=y
 CONFIG_IP_ROUTE_NAT=y
 CONFIG_IP_ROUTE_MULTIPATH=y
@@ -134,12 +130,18 @@
 # CONFIG_IPV6 is not set
 # CONFIG_KHTTPD is not set
 # CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
 
 #
 #  
 #
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -155,6 +157,16 @@
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
 # CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
@@ -192,6 +204,7 @@
 # CONFIG_SCSI_AHA152X is not set
 # CONFIG_SCSI_AHA1542 is not set
 # CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AACRAID is not set
 # CONFIG_SCSI_AIC7XXX is not set
 # CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_DPT_I2O is not set
@@ -213,6 +226,7 @@
 # CONFIG_SCSI_INIA100 is not set
 # CONFIG_SCSI_NCR53C406A is not set
 # CONFIG_SCSI_NCR53C7xx is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
 # CONFIG_SCSI_NCR53C8XX is not set
 # CONFIG_SCSI_SYM53C8XX is not set
 # CONFIG_SCSI_PAS16 is not set
@@ -229,8 +243,6 @@
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
 # CONFIG_SCSI_DEBUG is not set
-# CONFIG_SCSI_MESH is not set
-# CONFIG_SCSI_MAC53C94 is not set
 
 #
 # IEEE 1394 (FireWire) support (EXPERIMENTAL)
@@ -259,12 +271,10 @@
 # CONFIG_MACE is not set
 # CONFIG_BMAC is not set
 # CONFIG_GMAC is not set
-# CONFIG_OAKNET is not set
 # CONFIG_SUNLANCE is not set
 # CONFIG_HAPPYMEAL is not set
 # CONFIG_SUNBMAC is not set
 # CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
 # CONFIG_SUNGEM is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
@@ -278,6 +288,7 @@
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
 # CONFIG_TULIP is not set
+# CONFIG_TC35815 is not set
 # CONFIG_DE4X5 is not set
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
@@ -293,11 +304,13 @@
 # CONFIG_8139TOO_PIO is not set
 # CONFIG_8139TOO_TUNE_TWISTER is not set
 # CONFIG_8139TOO_8129 is not set
+# CONFIG_8139_NEW_RX_RESET is not set
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
 # CONFIG_TLAN is not set
 # CONFIG_VIA_RHINE is not set
+# CONFIG_VIA_RHINE_MMIO is not set
 # CONFIG_WINBOND_840 is not set
 # CONFIG_NET_POCKET is not set
 
@@ -312,6 +325,7 @@
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 # CONFIG_PLIP is not set
@@ -329,6 +343,7 @@
 CONFIG_TR=y
 CONFIG_IBMOL=m
 # CONFIG_IBMLS is not set
+# CONFIG_3C359 is not set
 # CONFIG_TMS380TR is not set
 # CONFIG_NET_FC is not set
 # CONFIG_RCPCI is not set
@@ -380,6 +395,15 @@
 # CONFIG_FB is not set
 
 #
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
 # iSeries device drivers
 #
 CONFIG_VIOCONS=y
@@ -435,43 +459,20 @@
 # Joysticks
 #
 # CONFIG_INPUT_GAMEPORT is not set
-# CONFIG_INPUT_NS558 is not set
-# CONFIG_INPUT_LIGHTNING is not set
-# CONFIG_INPUT_PCIGAME is not set
-# CONFIG_INPUT_CS461X is not set
-# CONFIG_INPUT_EMU10K1 is not set
-# CONFIG_INPUT_SERIO is not set
-# CONFIG_INPUT_SERPORT is not set
 
 #
-# Joysticks
+# Input core support is needed for gameports
+#
+
+#
+# Input core support is needed for joysticks
 #
-# CONFIG_INPUT_ANALOG is not set
-# CONFIG_INPUT_A3D is not set
-# CONFIG_INPUT_ADI is not set
-# CONFIG_INPUT_COBRA is not set
-# CONFIG_INPUT_GF2K is not set
-# CONFIG_INPUT_GRIP is not set
-# CONFIG_INPUT_INTERACT is not set
-# CONFIG_INPUT_TMDC is not set
-# CONFIG_INPUT_SIDEWINDER is not set
-# CONFIG_INPUT_IFORCE_USB is not set
-# CONFIG_INPUT_IFORCE_232 is not set
-# CONFIG_INPUT_WARRIOR is not set
-# CONFIG_INPUT_MAGELLAN is not set
-# CONFIG_INPUT_SPACEORB is not set
-# CONFIG_INPUT_SPACEBALL is not set
-# CONFIG_INPUT_STINGER is not set
-# CONFIG_INPUT_DB9 is not set
-# CONFIG_INPUT_GAMECON is not set
-# CONFIG_INPUT_TURBOGRAFX is not set
 # CONFIG_QIC02_TAPE is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -484,7 +485,6 @@
 # CONFIG_FTAPE is not set
 # CONFIG_AGP is not set
 # CONFIG_DRM is not set
-# CONFIG_MWAVE is not set
 
 #
 # File systems
@@ -494,11 +494,15 @@
 CONFIG_AUTOFS4_FS=y
 CONFIG_REISERFS_FS=y
 # CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
 # CONFIG_ADFS_FS is not set
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
 # CONFIG_BFS_FS is not set
+CONFIG_EXT3_FS=y
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
 # CONFIG_FAT_FS is not set
 # CONFIG_MSDOS_FS is not set
 # CONFIG_UMSDOS_FS is not set
@@ -511,8 +515,10 @@
 CONFIG_RAMFS=y
 CONFIG_ISO9660_FS=y
 CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
 # CONFIG_NTFS_RW is not set
@@ -536,6 +542,7 @@
 # Network File Systems
 #
 # CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
 # CONFIG_ROOT_NFS is not set
@@ -555,6 +562,8 @@
 CONFIG_NCPFS_SMALLDOS=y
 CONFIG_NCPFS_NLS=y
 CONFIG_NCPFS_EXTRAS=y
+# CONFIG_ZISOFS_FS is not set
+# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -589,6 +598,7 @@
 # CONFIG_NLS_CODEPAGE_949 is not set
 # CONFIG_NLS_CODEPAGE_874 is not set
 # CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
 CONFIG_NLS_ISO8859_1=y
 # CONFIG_NLS_ISO8859_2 is not set
@@ -616,109 +626,15 @@
 # CONFIG_USB is not set
 
 #
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-# CONFIG_USB_HID is not set
-# CONFIG_USB_HIDDEV is not set
-# CONFIG_USB_KBD is not set
-# CONFIG_USB_MOUSE is not set
-# CONFIG_USB_WACOM is not set
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-# CONFIG_USB_IBMCAM is not set
-# CONFIG_USB_OV511 is not set
-# CONFIG_USB_PWC is not set
-# CONFIG_USB_SE401 is not set
-# CONFIG_USB_DSBR is not set
-# CONFIG_USB_DABUSB is not set
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
 # Kernel hacking
 #
 CONFIG_MAGIC_SYSRQ=y
 # CONFIG_KGDB is not set
 # CONFIG_XMON is not set
+# CONFIG_KDB is not set
+# CONFIG_KDB_OFF is not set
+# CONFIG_KALLSYMS is not set
 # CONFIG_PPCDBG is not set
+CONFIG_DUMP=y
+CONFIG_DUMP_COMPRESS_RLE=y
+CONFIG_DUMP_COMPRESS_GZIP=y
diff -urN linux-2.4.20-pre4/arch/ppc64/configs/pSeries_defconfig linux-2.4.20-pre5/arch/ppc64/configs/pSeries_defconfig
--- linux-2.4.20-pre4/arch/ppc64/configs/pSeries_defconfig	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/configs/pSeries_defconfig	Wed Aug 28 16:37:30 2002
@@ -25,6 +25,7 @@
 CONFIG_IRQ_ALL_CPUS=y
 # CONFIG_HMT is not set
 # CONFIG_MSCHUNKS is not set
+CONFIG_RTAS_FLASH=m
 
 #
 # Loadable module support
@@ -61,6 +62,9 @@
 CONFIG_FB=y
 CONFIG_PROC_DEVICETREE=y
 
+CONFIG_CMDLINE_BOOL=n
+CONFIG_CMDLINE="console=ttyS0,9600 console=tty0 root=/dev/sda2"
+
 #
 # Memory Technology Devices (MTD)
 #
@@ -80,7 +84,9 @@
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_NBD=y
 CONFIG_BLK_DEV_RAM=y
@@ -128,6 +134,11 @@
 #
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -145,6 +156,11 @@
 # CONFIG_NET_SCHED is not set
 
 #
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
 # ATA/IDE/MFM/RLL support
 #
 CONFIG_IDE=y
@@ -161,6 +177,7 @@
 # CONFIG_BLK_DEV_HD is not set
 # CONFIG_BLK_DEV_IDEDISK is not set
 # CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_IDEDISK_STROKE is not set
 # CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
 # CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
 # CONFIG_BLK_DEV_IDEDISK_IBM is not set
@@ -175,6 +192,7 @@
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
 # CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
 
 #
 # IDE chipset support/bugfixes
@@ -186,12 +204,15 @@
 CONFIG_BLK_DEV_IDEPCI=y
 # CONFIG_IDEPCI_SHARE_IRQ is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
-CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
 # CONFIG_IDEDMA_PCI_AUTO is not set
+# CONFIG_IDEDMA_ONLYDISK is not set
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_PCI_WIP is not set
+# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
+CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_AEC62XX_TUNING is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
@@ -199,6 +220,7 @@
 # CONFIG_BLK_DEV_AMD74XX is not set
 # CONFIG_AMD74XX_OVERRIDE is not set
 # CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_CMD680 is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
 # CONFIG_BLK_DEV_CS5530 is not set
 # CONFIG_BLK_DEV_HPT34X is not set
@@ -349,6 +371,7 @@
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
 # CONFIG_TULIP is not set
+# CONFIG_TC35815 is not set
 # CONFIG_DE4X5 is not set
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
@@ -380,12 +403,12 @@
 CONFIG_ACENIC=y
 # CONFIG_ACENIC_OMIT_TIGON_I is not set
 # CONFIG_DL2K is not set
-CONFIG_E1000=y
 # CONFIG_MYRI_SBUS is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 # CONFIG_PLIP is not set
@@ -403,6 +426,7 @@
 CONFIG_TR=y
 CONFIG_IBMOL=y
 # CONFIG_IBMLS is not set
+# CONFIG_3C359 is not set
 # CONFIG_TMS380TR is not set
 # CONFIG_NET_FC is not set
 # CONFIG_RCPCI is not set
@@ -445,6 +469,7 @@
 # CONFIG_FB_RIVA is not set
 # CONFIG_FB_CLGEN is not set
 # CONFIG_FB_PM2 is not set
+# CONFIG_FB_PM3 is not set
 # CONFIG_FB_CYBER2000 is not set
 CONFIG_FB_OF=y
 # CONFIG_FB_CONTROL is not set
@@ -464,6 +489,7 @@
 # CONFIG_FB_RADEON is not set
 # CONFIG_FB_ATY128 is not set
 # CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
 # CONFIG_FB_3DFX is not set
 # CONFIG_FB_VOODOO1 is not set
 # CONFIG_FB_TRIDENT is not set
@@ -517,6 +543,7 @@
 CONFIG_PSMOUSE=y
 # CONFIG_82C710_MOUSE is not set
 # CONFIG_PC110_PAD is not set
+# CONFIG_MK712_MOUSE is not set
 
 #
 # Joysticks
@@ -536,7 +563,6 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_RTC is not set
@@ -577,7 +603,7 @@
 # CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 # CONFIG_TMPFS is not set
-# CONFIG_RAMFS is not set
+CONFIG_RAMFS=y
 CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
 # CONFIG_ZISOFS is not set
@@ -691,112 +717,16 @@
 # CONFIG_USB is not set
 
 #
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-# CONFIG_USB_IBMCAM is not set
-# CONFIG_USB_OV511 is not set
-# CONFIG_USB_PWC is not set
-# CONFIG_USB_SE401 is not set
-# CONFIG_USB_STV680 is not set
-# CONFIG_USB_VICAM is not set
-# CONFIG_USB_DSBR is not set
-# CONFIG_USB_DABUSB is not set
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IPAQ is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_KLSI is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
 # Kernel hacking
 #
 CONFIG_MAGIC_SYSRQ=y
 # CONFIG_KGDB is not set
-CONFIG_XMON=y
+# CONFIG_XMON is not set
+CONFIG_KDB=y
+# CONFIG_KDB_OFF is not set
+# CONFIG_KALLSYMS is not set
 CONFIG_PPCDBG=y
+
+CONFIG_DUMP=y
+CONFIG_DUMP_COMPRESS_RLE=y
+CONFIG_DUMP_COMPRESS_GZIP=y
diff -urN linux-2.4.20-pre4/arch/ppc64/defconfig linux-2.4.20-pre5/arch/ppc64/defconfig
--- linux-2.4.20-pre4/arch/ppc64/defconfig	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/defconfig	Wed Aug 28 16:37:30 2002
@@ -25,6 +25,7 @@
 CONFIG_IRQ_ALL_CPUS=y
 # CONFIG_HMT is not set
 # CONFIG_MSCHUNKS is not set
+CONFIG_RTAS_FLASH=m
 
 #
 # Loadable module support
@@ -61,6 +62,9 @@
 CONFIG_FB=y
 CONFIG_PROC_DEVICETREE=y
 
+CONFIG_CMDLINE_BOOL=n
+CONFIG_CMDLINE="console=ttyS0,9600 console=tty0 root=/dev/sda2"
+
 #
 # Memory Technology Devices (MTD)
 #
@@ -80,7 +84,9 @@
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_NBD=y
 CONFIG_BLK_DEV_RAM=y
@@ -128,6 +134,11 @@
 #
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -145,6 +156,11 @@
 # CONFIG_NET_SCHED is not set
 
 #
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
 # ATA/IDE/MFM/RLL support
 #
 CONFIG_IDE=y
@@ -161,6 +177,7 @@
 # CONFIG_BLK_DEV_HD is not set
 # CONFIG_BLK_DEV_IDEDISK is not set
 # CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_IDEDISK_STROKE is not set
 # CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
 # CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
 # CONFIG_BLK_DEV_IDEDISK_IBM is not set
@@ -175,6 +192,7 @@
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
 # CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
 
 #
 # IDE chipset support/bugfixes
@@ -186,12 +204,15 @@
 CONFIG_BLK_DEV_IDEPCI=y
 # CONFIG_IDEPCI_SHARE_IRQ is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
-CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
 # CONFIG_IDEDMA_PCI_AUTO is not set
+# CONFIG_IDEDMA_ONLYDISK is not set
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_PCI_WIP is not set
+# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
+CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_AEC62XX_TUNING is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
@@ -199,6 +220,7 @@
 # CONFIG_BLK_DEV_AMD74XX is not set
 # CONFIG_AMD74XX_OVERRIDE is not set
 # CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_CMD680 is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
 # CONFIG_BLK_DEV_CS5530 is not set
 # CONFIG_BLK_DEV_HPT34X is not set
@@ -349,6 +371,7 @@
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
 # CONFIG_TULIP is not set
+# CONFIG_TC35815 is not set
 # CONFIG_DE4X5 is not set
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
@@ -378,14 +401,14 @@
 # Ethernet (1000 Mbit)
 #
 CONFIG_ACENIC=y
-# CONFIG_ACENIC_OMIT_TIGON_I is not set
+CONFIG_ACENIC_OMIT_TIGON_I=y
 # CONFIG_DL2K is not set
-CONFIG_E1000=y
 # CONFIG_MYRI_SBUS is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 # CONFIG_PLIP is not set
@@ -403,6 +426,7 @@
 CONFIG_TR=y
 CONFIG_IBMOL=y
 # CONFIG_IBMLS is not set
+# CONFIG_3C359 is not set
 # CONFIG_TMS380TR is not set
 # CONFIG_NET_FC is not set
 # CONFIG_RCPCI is not set
@@ -445,6 +469,7 @@
 # CONFIG_FB_RIVA is not set
 # CONFIG_FB_CLGEN is not set
 # CONFIG_FB_PM2 is not set
+# CONFIG_FB_PM3 is not set
 # CONFIG_FB_CYBER2000 is not set
 CONFIG_FB_OF=y
 # CONFIG_FB_CONTROL is not set
@@ -464,6 +489,7 @@
 # CONFIG_FB_RADEON is not set
 # CONFIG_FB_ATY128 is not set
 # CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
 # CONFIG_FB_3DFX is not set
 # CONFIG_FB_VOODOO1 is not set
 # CONFIG_FB_TRIDENT is not set
@@ -517,6 +543,7 @@
 CONFIG_PSMOUSE=y
 # CONFIG_82C710_MOUSE is not set
 # CONFIG_PC110_PAD is not set
+# CONFIG_MK712_MOUSE is not set
 
 #
 # Joysticks
@@ -536,7 +563,6 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_RTC is not set
@@ -577,7 +603,7 @@
 # CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 # CONFIG_TMPFS is not set
-# CONFIG_RAMFS is not set
+CONFIG_RAMFS=y
 CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
 # CONFIG_ZISOFS is not set
@@ -691,112 +717,16 @@
 # CONFIG_USB is not set
 
 #
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-# CONFIG_USB_IBMCAM is not set
-# CONFIG_USB_OV511 is not set
-# CONFIG_USB_PWC is not set
-# CONFIG_USB_SE401 is not set
-# CONFIG_USB_STV680 is not set
-# CONFIG_USB_VICAM is not set
-# CONFIG_USB_DSBR is not set
-# CONFIG_USB_DABUSB is not set
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IPAQ is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_KLSI is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
 # Kernel hacking
 #
 CONFIG_MAGIC_SYSRQ=y
 # CONFIG_KGDB is not set
-CONFIG_XMON=y
+# CONFIG_XMON is not set
+CONFIG_KDB=y
+# CONFIG_KDB_OFF is not set
+# CONFIG_KALLSYMS is not set
 CONFIG_PPCDBG=y
+
+CONFIG_DUMP=y
+CONFIG_DUMP_COMPRESS_RLE=y
+CONFIG_DUMP_COMPRESS_GZIP=y
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/LparData.c linux-2.4.20-pre5/arch/ppc64/kernel/LparData.c
--- linux-2.4.20-pre4/arch/ppc64/kernel/LparData.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/LparData.c	Wed Aug 28 16:37:30 2002
@@ -6,14 +6,12 @@
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  */
-#define __KERNEL__ 1
 #include <asm/types.h>
 #include <asm/page.h>
 #include <stddef.h>
 #include <linux/threads.h>
 #include <asm/processor.h>
 #include <asm/ptrace.h>
-#include <asm/init.h>
 #include <asm/naca.h>
 #include <asm/abs_addr.h>
 #include <asm/bitops.h>
@@ -25,6 +23,7 @@
 #include <asm/iSeries/LparMap.h>
 #include <asm/iSeries/ItVpdAreas.h>
 #include <asm/iSeries/ItIplParmsReal.h>
+#include <asm/iSeries/ItExtVpdPanel.h>
 #include <asm/iSeries/ItLpQueue.h>
 #include <asm/iSeries/IoHriProcessorVpd.h>
 #include <asm/iSeries/ItSpCommArea.h>
@@ -144,6 +143,8 @@
 
 struct ItIplParmsReal xItIplParmsReal = {};
 
+struct ItExtVpdPanel xItExtVpdPanel = {};
+
 #define maxPhysicalProcessors 32
 
 struct IoHriProcessorVpd xIoHriProcessorVpd[maxPhysicalProcessors] = {
@@ -185,7 +186,8 @@
 	{0},		/* DMA lengths */
 	{0},		/* DMA tokens */
 	{		/* VPD lengths */
-		0,0,0,0,		/*  0 -  3 */
+	        0,0,0,		        /*  0 - 2 */
+		sizeof(xItExtVpdPanel), /*       3 Extended VPD   */
 		sizeof(struct paca_struct),	/*       4 length of Paca  */
 		0,			/*       5 */
 		sizeof(struct ItIplParmsReal),/* 6 length of IPL parms */
@@ -202,7 +204,8 @@
 		0,0			/* 24 - 25 */
 		},
 	{			/* VPD addresses */
-		0,0,0,0,		/*	 0 -  3 */
+		0,0,0,  		/*	 0 -  2 */
+		&xItExtVpdPanel,        /*       3 Extended VPD */
 		&paca[0],		/*       4 first Paca */
 		0,			/*       5 */
 		&xItIplParmsReal,	/*	 6 IPL parms */
@@ -244,7 +247,3 @@
 
 	return mem;
 }
-
-
-
-
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/Makefile linux-2.4.20-pre5/arch/ppc64/kernel/Makefile
--- linux-2.4.20-pre4/arch/ppc64/kernel/Makefile	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/Makefile	Wed Aug 28 16:37:30 2002
@@ -27,19 +27,21 @@
 			pmc.o mf_proc.o proc_pmc.o proc_pcifr.o iSeries_setup.o \
 			ItLpQueue.o hvCall.o mf.o HvLpEvent.o ras.o \
 			iSeries_proc.o HvCall.o flight_recorder.o HvLpConfig.o \
-			rtc.o
+			rtc.o perfmon.o
 
-obj-$(CONFIG_PCI) +=  pci.o pci_dn.o pci_dma.o
+obj-$(CONFIG_PCI) +=  pci.o pci_dn.o pci_dma.o pSeries_lpar.o pSeries_hvCall.o
 
 ifeq ($(CONFIG_PPC_ISERIES),y)
 obj-$(CONFIG_PCI) += iSeries_pci.o iSeries_pci_reset.o iSeries_IoMmTable.o iSeries_irq.o iSeries_VpdInfo.o XmPciLpEvent.o 
 endif
 ifeq ($(CONFIG_PPC_PSERIES),y)
-obj-$(CONFIG_PCI) += pSeries_pci.o pSeries_lpar.o pSeries_hvCall.o eeh.o
+obj-$(CONFIG_PCI) += pSeries_pci.o eeh.o
 
 obj-y += rtasd.o nvram.o
 endif
 
+obj-$(CONFIG_RTAS_FLASH) += rtas_flash.o
+
 obj-$(CONFIG_KGDB) += ppc-stub.o
 
 obj-$(CONFIG_SMP) += smp.o
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/XmPciLpEvent.c linux-2.4.20-pre5/arch/ppc64/kernel/XmPciLpEvent.c
--- linux-2.4.20-pre4/arch/ppc64/kernel/XmPciLpEvent.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/XmPciLpEvent.c	Wed Aug 28 16:37:30 2002
@@ -14,22 +14,32 @@
 #include <linux/bootmem.h>
 #include <linux/blk.h>
 #include <linux/ide.h>
+#include <linux/rtc.h>
+#include <linux/time.h>
 
 #include <asm/iSeries/HvTypes.h>
 #include <asm/iSeries/HvLpEvent.h>
 #include <asm/iSeries/HvCallPci.h>
 #include <asm/iSeries/XmPciLpEvent.h>
 #include <asm/ppcdebug.h>
+#include <asm/time.h>
+#include <asm/flight_recorder.h>
+
+extern struct flightRecorder* PciFr;
+
 
 long Pci_Interrupt_Count = 0;
 long Pci_Event_Count     = 0;
 
 enum XmPciLpEvent_Subtype {
 	XmPciLpEvent_BusCreated	   = 0,		// PHB has been created
-	XmPciLpEvent_BusFailed	   = 1,		// PHB has failed
-	XmPciLpEvent_BusRecovered  = 12,	// PHB has been recovered
+	XmPciLpEvent_BusError	   = 1,		// PHB has failed
+	XmPciLpEvent_BusFailed	   = 2,		// Msg to Seconday, Primary failed bus
 	XmPciLpEvent_NodeFailed	   = 4,		// Multi-adapter bridge has failed
 	XmPciLpEvent_NodeRecovered = 5,		// Multi-adapter bridge has recovered
+	XmPciLpEvent_BusRecovered  = 12,	// PHB has been recovered
+	XmPciLpEvent_UnQuiesceBus  = 18,	// Secondary bus unqiescing
+	XmPciLpEvent_BridgeError   = 21,	// Bridge Error
 	XmPciLpEvent_SlotInterrupt = 22		// Slot interrupt
 };
 
@@ -69,6 +79,7 @@
 };
 
 static void intReceived(struct XmPciLpEvent* eventParm, struct pt_regs* regsParm);
+static void logXmEvent( char* ErrorText, int busNumber);
 
 static void XmPciLpEvent_handler( struct HvLpEvent* eventParm, struct pt_regs* regsParm)
 {
@@ -81,10 +92,10 @@
 			intReceived( (struct XmPciLpEvent*)eventParm, regsParm );
 			break;
 		case HvLpEvent_Function_Ack:
-			printk(KERN_ERR "XmPciLpEvent.c: unexpected ack received\n");
+			printk(KERN_ERR "XmPciLpEvent.c: Unexpected ack received\n");
 			break;
 		default:
-			printk(KERN_ERR "XmPciLpEvent.c: unexpected event function %d\n",(int)eventParm->xFlags.xFunction);
+			printk(KERN_ERR "XmPciLpEvent.c: Unexpected event function %d\n",(int)eventParm->xFlags.xFunction);
 			break;
 		}
 	}
@@ -114,23 +125,25 @@
 		break;
 		/* Ignore error recovery events for now */
 	case XmPciLpEvent_BusCreated:
-		printk(KERN_INFO "XmPciLpEvent.c: system bus %d created\n", eventParm->eventData.busCreated.busNumber);
+	        logXmEvent("System bus created.",eventParm->eventData.busCreated.busNumber);
 		break;
+	case XmPciLpEvent_BusError:
 	case XmPciLpEvent_BusFailed:
-		printk(KERN_INFO "XmPciLpEvent.c: system bus %d failed\n", eventParm->eventData.busFailed.busNumber);
+		logXmEvent("System bus failed.", eventParm->eventData.busFailed.busNumber);
 		break;
 	case XmPciLpEvent_BusRecovered:
-		printk(KERN_INFO "XmPciLpEvent.c: system bus %d recovered\n", eventParm->eventData.busRecovered.busNumber);
+	case XmPciLpEvent_UnQuiesceBus:
+		logXmEvent("System bus recovered.",eventParm->eventData.busRecovered.busNumber);
 		break;
 	case XmPciLpEvent_NodeFailed:
-		printk(KERN_INFO "XmPciLpEvent.c: multi-adapter bridge %d/%d/%d failed\n", eventParm->eventData.nodeFailed.busNumber, eventParm->eventData.nodeFailed.subBusNumber, eventParm->eventData.nodeFailed.deviceId);
-		break;
+	case XmPciLpEvent_BridgeError:
+	        logXmEvent("Multi-adapter bridge failed.",eventParm->eventData.nodeFailed.busNumber);
+	        break;
 	case XmPciLpEvent_NodeRecovered:
-		printk(KERN_INFO "XmPciLpEvent.c: multi-adapter bridge %d/%d/%d recovered\n", eventParm->eventData.nodeRecovered.busNumber, eventParm->eventData.nodeRecovered.subBusNumber, eventParm->eventData.nodeRecovered.deviceId);
+		logXmEvent("Multi-adapter bridge recovered",eventParm->eventData.nodeRecovered.busNumber);
 		break;
 	default:
-		printk(KERN_ERR "XmPciLpEvent.c: unrecognized event subtype 0x%x\n",
-		       eventParm->hvLpEvent.xSubtype);
+	        logXmEvent("Unrecognized event subtype.",eventParm->hvLpEvent.xSubtype);
 		break;
 	};
 }
@@ -154,4 +167,25 @@
     	}
     return xRc;
 }
+/***********************************************************************/
+/* printk                                                              */
+/*   XmPciLpEvent: System bus failed, bus 0x4A. Time:128-16.10.44      */
+/* pcifr                                                               */
+/*  0045. XmPciLpEvent: System bus failed, bus 0x4A. Time:128-16.10.44 */
+/***********************************************************************/
+static void logXmEvent( char* ErrorText, int busNumber) {
+	struct  timeval  TimeClock;
+	struct  rtc_time CurTime;
+
+	do_gettimeofday(&TimeClock);
+	to_tm(TimeClock.tv_sec, &CurTime);
+	char    EventLog[128];
+
+	sprintf(EventLog,"XmPciLpEvent: %s, Bus:0x%03X.  Time:%02d.%02d.%02d",
+		ErrorText,busNumber,
+		CurTime.tm_hour,CurTime.tm_min,CurTime.tm_sec);
+
+	fr_Log_Entry(PciFr,EventLog);
+	printk(KERN_INFO "%s\n",EventLog);
+}
 
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/align.c linux-2.4.20-pre5/arch/ppc64/kernel/align.c
--- linux-2.4.20-pre4/arch/ppc64/kernel/align.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/align.c	Wed Aug 28 16:37:30 2002
@@ -238,7 +238,7 @@
 	dsisr = regs->dsisr;
 
 	/* Power4 doesn't set DSISR for an alignment interrupt */
-	if (__is_processor(PV_POWER4))
+	if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p))
 		dsisr = make_dsisr( *((unsigned *)regs->nip) );
 
 	/* extract the operation and registers from the dsisr */
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/chrp_setup.c linux-2.4.20-pre5/arch/ppc64/kernel/chrp_setup.c
--- linux-2.4.20-pre4/arch/ppc64/kernel/chrp_setup.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/chrp_setup.c	Wed Aug 28 16:37:30 2002
@@ -102,6 +102,8 @@
 extern int probingmem;
 extern unsigned long loops_per_jiffy;
 
+extern unsigned long ppc_proc_freq;
+extern unsigned long ppc_tb_freq;
 #ifdef CONFIG_BLK_DEV_RAM
 extern int rd_doload;		/* 1 = load ramdisk, 0 = don't load */
 extern int rd_prompt;		/* 1 = prompt for ramdisk, 0 = don't prompt */
@@ -114,6 +116,8 @@
 	struct device_node *root;
 	const char *model = "";
 
+	seq_printf(m, "timebase\t: %lu\n", ppc_tb_freq);
+
 	root = find_path_device("/");
 	if (root)
 		model = get_property(root, "model", NULL);
@@ -174,7 +178,6 @@
 		for (openpic = 0; n > 0; --n)
 			openpic = (openpic << 32) + *opprop++;
 		printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic);
-		udbg_printf("OpenPIC addr: %lx\n", openpic);
 		OpenPIC_Addr = __ioremap(openpic, 0x40000, _PAGE_NO_CACHE);
 	}
 
@@ -191,7 +194,9 @@
 	 * -- tibit
 	 */
 	chrp_request_regions();
-	ppc_md.progress(UTS_RELEASE, 0x7777);
+	/* Manually leave the kernel version on the panel. */
+	ppc_md.progress("Linux ppc64\n", 0);
+	ppc_md.progress(UTS_RELEASE, 0);
 }
 
 /* Initialize firmware assisted non-maskable interrupts if
@@ -259,11 +264,9 @@
 	if(naca->interrupt_controller == IC_OPEN_PIC) {
 		ppc_md.init_IRQ       = openpic_init_IRQ; 
 		ppc_md.get_irq        = openpic_get_irq;
-		ppc_md.post_irq	      = NULL;
 	} else {
 		ppc_md.init_IRQ       = xics_init_IRQ;
 		ppc_md.get_irq        = xics_get_irq;
-		ppc_md.post_irq	      = NULL;
 	}
 	ppc_md.init_ras_IRQ = init_ras_IRQ;
 
@@ -301,8 +304,6 @@
 	SYSRQ_KEY = 0x63;	/* Print Screen */
 #endif
 #endif
-	
-	ppc_md.progress("Linux ppc64\n", 0x0);
 }
 
 void __chrp
@@ -314,10 +315,7 @@
 	static int display_character, set_indicator;
 	static int max_width;
 
-	if (hex)
-		udbg_printf("<chrp_progress> %s\n", s);
-
-	if (!rtas.base || (naca->platform != PLATFORM_PSERIES))
+	if (!rtas.base)
 		return;
 
 	if (max_width == 0) {
@@ -363,9 +361,6 @@
 
 extern void setup_default_decr(void);
 
-extern unsigned long ppc_proc_freq;
-extern unsigned long ppc_tb_freq;
-
 void __init pSeries_calibrate_decr(void)
 {
 	struct device_node *cpu;
@@ -401,7 +396,6 @@
 	tb_ticks_per_jiffy = freq / HZ;
 	tb_ticks_per_sec = tb_ticks_per_jiffy * HZ;
 	tb_ticks_per_usec = freq / 1000000;
-	tb_to_us = mulhwu_scale_factor(freq, 1000000);
 	div128_by_32( 1024*1024, 0, tb_ticks_per_sec, &divres );
 	tb_to_xs = divres.result_low;
 
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/eeh.c linux-2.4.20-pre5/arch/ppc64/kernel/eeh.c
--- linux-2.4.20-pre4/arch/ppc64/kernel/eeh.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/eeh.c	Wed Aug 28 16:37:30 2002
@@ -59,15 +59,14 @@
 	return ((IO_UNMAPPED_REGION_ID << 60) | (phb << 48UL) | ((bus & 0xff) << 40UL) | (devfn << 32UL) | (offset & 0xffffffff));
 }
 
-
-
-int eeh_get_state(unsigned long ea) {
+int eeh_get_state(unsigned long ea)
+{
 	return 0;
 }
 
-
 /* Check for an eeh failure at the given token address.
- * The given value has been read and it should be 1's (0xff, 0xffff or 0xffffffff).
+ * The given value has been read and it should be 1's (0xff, 0xffff or
+ * 0xffffffff).
  *
  * Probe to determine if an error actually occurred.  If not return val.
  * Otherwise panic.
@@ -113,7 +112,8 @@
 	return val;	/* good case */
 }
 
-void eeh_init(void) {
+void eeh_init(void)
+{
 	extern char cmd_line[];	/* Very early cmd line parse.  Cheap, but works. */
 	char *eeh_force_off = strstr(cmd_line, "eeh-force-off");
 	char *eeh_force_on = strstr(cmd_line, "eeh-force-on");
@@ -334,6 +334,7 @@
 {
 	return eeh_parm(str, 0);
 }
+
 static int __init eehon_parm(char *str)
 {
 	return eeh_parm(str, 1);
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/entry.S linux-2.4.20-pre5/arch/ppc64/kernel/entry.S
--- linux-2.4.20-pre4/arch/ppc64/kernel/entry.S	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/entry.S	Wed Aug 28 16:37:30 2002
@@ -305,9 +305,7 @@
 	cmpdi	0,r5,0
 	beq	4f
 irq_recheck:
-	/*
-	 * Check for pending interrupts (iSeries)
-	 */
+	/* Check for pending interrupts (iSeries) */
 	CHECKANYINT(r3,r4)
 	beq+	4f	/* skip do_IRQ if no interrupts */
 
@@ -346,6 +344,7 @@
 	mtlr	r0
 	ld	r3,_XER(r1)
 	mtspr	XER,r3
+
 	REST_8GPRS(5, r1)
 	REST_10GPRS(14, r1)
 	REST_8GPRS(24, r1)
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/head.S linux-2.4.20-pre5/arch/ppc64/kernel/head.S
--- linux-2.4.20-pre4/arch/ppc64/kernel/head.S	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/head.S	Wed Aug 28 16:37:30 2002
@@ -31,7 +31,7 @@
 #include <asm/page.h>
 #include <linux/config.h>
 #include <asm/mmu.h>
-// #include <asm/paca.h>
+#include <asm/perfmon.h>
 
 #ifdef CONFIG_PPC_ISERIES
 #define DO_SOFT_DISABLE
@@ -154,12 +154,13 @@
  */
 
 /*
- * We make as much of the exception code common between native Pseries
- * and Iseries LPAR implementations as possible.
+ * We make as much of the exception code common between native
+ * exception handlers (including pSeries LPAR) and iSeries LPAR
+ * implementations as possible.
  */
 
 /*
- * This is the start of the interrupt handlers for Pseries
+ * This is the start of the interrupt handlers for pSeries
  * This code runs with relocation off.
  */
 #define EX_SRR0		0
@@ -200,13 +201,13 @@
 	rfid
 
 /*
- * This is the start of the interrupt handlers for i_series
+ * This is the start of the interrupt handlers for iSeries
  * This code runs with relocation on.
  */
 #define EXCEPTION_PROLOG_ISERIES(n)	                                      \
 	mtspr	SPRG2,r20;		    /* use SPRG2 as scratch reg    */ \
 	mtspr   SPRG1,r21;                  /* save r21                    */ \
-	mfspr	r20,SPRG3;		    /* get Paca                    */ \
+	mfspr	r20,SPRG3;		    /* get paca                    */ \
 	ld      r21,PACAEXCSP(r20);         /* get exception stack ptr     */ \
 	addi    r21,r21,EXC_FRAME_SIZE;     /* make exception frame        */ \
 	std	r22,EX_R22(r21);	    /* save r22 on exception frame */ \
@@ -302,9 +303,9 @@
 	.globl label##_Iseries;			\
 label##_Iseries:				\
 	EXCEPTION_PROLOG_ISERIES( n );		\
-	lbz	r22,PACAPROFENABLED(r20);	\
-	cmpi	0,r22,0;			\
-	bne-	label##_Iseries_profile;	\
+	lbz	r22,PACAPROFMODE(r20);		\
+	cmpi	0,r22,PMC_STATE_DECR_PROFILE;	\
+	beq-	label##_Iseries_profile;	\
 label##_Iseries_prof_ret:			\
 	lbz	r22,PACAPROCENABLED(r20);	\
 	cmpi	0,r22,0;			\
@@ -359,7 +360,7 @@
 
 	/* Space for the naca.  Architected to be located at real address
 	 * 0x4000.  Various tools rely on this location being fixed.
-	 * The first dword of the Naca is required by iSeries LPAR to
+	 * The first dword of the naca is required by iSeries LPAR to
 	 * point to itVpdAreas.  On pSeries native, this value is not used.
 	 */
 	. = 0x4000
@@ -430,7 +431,7 @@
 	STD_EXCEPTION_ISERIES( 0xc00, SystemCall )
 	STD_EXCEPTION_ISERIES( 0xd00, SingleStep )
 	STD_EXCEPTION_ISERIES( 0xe00, Trap_0e )
-	STD_EXCEPTION_ISERIES( 0xf00, PerformanceMonitor )
+	MASKABLE_EXCEPTION_ISERIES( 0xf00, PerformanceMonitor )
 
 	.globl SystemReset_Iseries
 SystemReset_Iseries:
@@ -484,6 +485,12 @@
 HardwareInterrupt_Iseries_masked:
 	b	maskable_exception_exit
 
+	.globl PerformanceMonitor_Iseries_masked
+PerformanceMonitor_Iseries_masked:
+	li	r22,1
+	stb	r22,PACALPPACA+LPPACAPDCINT(r20)
+	b	maskable_exception_exit
+
 	.globl Decrementer_Iseries_masked
 Decrementer_Iseries_masked:
 	li	r22,1
@@ -529,7 +536,6 @@
 	STD_EXCEPTION_COMMON( 0xb00, Trap_0b, .UnknownException )
 	STD_EXCEPTION_COMMON( 0xd00, SingleStep, .SingleStepException )
 	STD_EXCEPTION_COMMON( 0xe00, Trap_0e, .UnknownException )
-	STD_EXCEPTION_COMMON( 0xf00, PerformanceMonitor, .PerformanceMonitorException )
 	STD_EXCEPTION_COMMON(0x1300, InstructionBreakpoint, .InstructionBreakpointException )
 
 /*
@@ -583,7 +589,8 @@
 	bl	.do_stab_SI
 	b	1f
 
-2:	bl	.do_hash_page_DSI 	/* Try to handle as hpte fault */
+2:	li	r5,0x300
+	bl	.do_hash_page_DSI 	/* Try to handle as hpte fault */
 1:
 	ld      r4,_DAR(r1)
 	ld      r5,_DSISR(r1)
@@ -668,7 +675,7 @@
 #else
 	rldicl	r20,r23,49,63   	/* copy EE bit from saved MSR */
 #endif
-	li	r6,0x380
+	li	r6,0x480
 	bl      .save_remaining_regs
 	bl      .do_page_fault
 	b       .ret_from_except
@@ -787,6 +794,150 @@
 	bl      .DoSyscall
 	b       .ret_from_except
 
+	.globl PerformanceMonitor_common
+PerformanceMonitor_common:	
+	EXCEPTION_PROLOG_COMMON
+	bl	.PerformanceMonitorException
+	b	fast_exception_return
+	
+_GLOBAL(PerformanceMonitorException)
+	mfspr	r7,SPRG3
+	lbz	r8,PACAPROFMODE(r7)
+	cmpi	0,r8,PMC_STATE_PROFILE_KERN
+	beq 	5f
+	cmpi	0,r8,PMC_STATE_TRACE_KERN
+	beq 	6f
+	cmpi	0,r8,PMC_STATE_TRACE_USER
+	beq 	9f
+	blr
+
+	/* PMC Profile Kernel */
+5:	mfspr   r9,SIAR	
+	srdi    r8,r9,60
+	cmpi    0,r8,0xc
+	beq     3f
+	li	r9,0xc
+	sldi	r9,r9,60
+3:      ld	r8,PACAPROFSTEXT(r7)	/* _stext */
+	subf	r9,r8,r9		/* offset into kernel */
+	lwz	r8,PACAPROFSHIFT(r7)
+	srd	r9,r9,r8
+	lwz	r8,PACAPROFLEN(r7)	/* length of profile table (-1) */
+	srdi	r8,r8,2
+	cmpd	r9,r8		/* off end? */
+	ble	1f
+	mr	r9,r8			/* force into last entry */
+	srdi	r9,r9,2
+1:	sldi	r9,r9,2		/* convert to offset into buffer */
+	ld	r8,PACAPROFBUFFER(r7)	/* profile buffer */
+	add	r8,r8,r9
+2:	lwarx	r9,0,r8		/* atomically increment */
+	addi	r9,r9,1
+	stwcx.	r9,0,r8
+	bne-	2b
+	addi	r10,r7,PACAPMC1
+	addi	r7,r7,PACAPMCC1
+	b	7f
+
+	/* PMC Trace Kernel */
+6:	LOADADDR(r11, perfmon_base)
+  	addi	r8,r11,32
+	ld	r12,24(r11)
+	subi	r12,r12,1
+8:	ldarx	r10,0,r8
+	addi	r9,r10,16
+	and	r9,r9,r12
+	stdcx.	r9,0,r8
+	bne-	8b
+	ld	r9,16(r11)	/* profile buffer */
+	add	r8,r9,r10
+  	mfspr   r9,SIAR	
+	std	r9,0(r8)
+	mfspr   r9,SDAR	
+	std	r9,8(r8)
+	addi	r10,r7,PACAPMC1
+	addi	r7,r7,PACAPMCC1
+	b	7f
+
+	/* PMC Trace User */
+9:	LOADADDR(r11, perfmon_base)
+#if 0
+  	addi	r8,r11,32
+	ld	r12,24(r11)
+	subi	r12,r12,1
+8:	ldarx	r10,0,r8
+	addi	r9,r10,16
+	and	r9,r9,r12
+	stdcx.	r9,0,r8
+	bne-	8b
+	ld	r9,16(r11)	/* profile buffer */
+	add	r8,r9,r10
+  	mfspr   r9,SIAR	
+	std	r9,0(r8)
+	mfspr   r9,SDAR	
+	std	r9,8(r8)
+	addi	r10,r13,THREAD+THREAD_PMC1
+	addi	r7,r13,THREAD+THREAD_PMCC1
+#endif
+	/* Accumulate counter values for kernel traces */
+7:	ld	r9,0(r7)
+	mfspr   r8,PMC1	
+	add	r9,r9,r8
+	std	r9,0(r7)
+	ld	r9,8(r7)
+	mfspr	r8,PMC2
+	add	r9,r9,r8
+	std	r9,8(r7)
+	ld	r9,16(r7)
+	mfspr	r8,PMC3
+	add	r9,r9,r8
+	std	r9,16(r7)
+	ld	r9,24(r7)
+	mfspr	r8,PMC4
+	add	r9,r9,r8
+	std	r9,24(r7)
+	ld	r9,32(r7)
+	mfspr	r8,PMC5
+	add	r9,r9,r8
+	std	r9,32(r7)
+	ld	r9,40(r7)
+	mfspr	r8,PMC6
+	add	r9,r9,r8
+	std	r9,40(r7)
+	ld	r9,48(r7)
+	mfspr	r8,PMC7
+	add	r9,r9,r8
+	std	r9,48(r7)
+	ld	r9,56(r7)
+	mfspr	r8,PMC8
+	add	r9,r9,r8
+	std	r9,56(r7)
+
+	/* Reset all counters for kernel traces */
+	lwz	r9,0(r10)
+	mtspr	PMC1,r9
+	lwz	r9,4(r10)
+	mtspr	PMC2,r9
+	lwz	r9,8(r10)
+	mtspr	PMC3,r9
+	lwz	r9,12(r10)
+	mtspr	PMC4,r9
+	lwz	r9,16(r10)
+	mtspr	PMC5,r9
+	lwz	r9,20(r10)
+	mtspr	PMC6,r9
+	lwz	r9,24(r10)
+	mtspr	PMC7,r9
+	lwz	r9,28(r10)
+	mtspr	PMC8,r9
+	lwz	r9,32(r10)
+	mtspr	MMCR0,r9
+	lwz	r9,36(r10)
+	mtspr	MMCR1,r9
+	lwz	r9,40(r10)
+	mtspr	MMCRA,r9
+	blr
+
 _GLOBAL(do_hash_page_ISI)
 	li	r4,0
 _GLOBAL(do_hash_page_DSI)
@@ -812,6 +963,7 @@
 	/*
 	 * r3 contains the faulting address
 	 * r4 contains the required access permissions
+	 * r5 contains the trap number
 	 *
 	 * at return r3 = 0 for success
 	 */
@@ -1029,6 +1181,13 @@
 	ori	r20,r20,256    /* map kernel region with large ptes */
 #endif
 	
+	/* Invalidate the old entry */
+	slbmfee	r21,r22
+	lis	r23,-2049
+	ori	r23,r23,65535
+	and	r21,r21,r23
+	slbie	r21
+
 	/* Put together the esid portion of the entry. */
 	mfspr	r21,DAR        /* Get the new esid                     */
 	rldicl  r21,r21,36,28  /* Permits a full 36b of ESID           */
@@ -1104,7 +1263,7 @@
 
 	/*
 	 * Indicate that r1 contains the kernel stack and
-	 * get the Kernel TOC and CURRENT pointers from the Paca
+	 * get the Kernel TOC and CURRENT pointers from the paca
 	 */
 	mfspr	r23,SPRG3		/* Get PACA */
 	std	r22,PACAKSAVE(r23)	/* r1 is now kernel sp */
@@ -1129,7 +1288,9 @@
 	mtmsrd  r22
 	blr
 
-
+/*
+ * Kernel profiling with soft disable on iSeries
+ */
 do_profile:
 	ld	r22,8(r21)		/* Get SRR1 */
 	andi.	r22,r22,MSR_PR		/* Test if in kernel */
@@ -1163,7 +1324,7 @@
 	bl	.enable_64b_mode
 	isync
 
-	/* Set up a Paca value for this processor. */
+	/* Set up a paca value for this processor. */
 	LOADADDR(r24, paca) 		 /* Get base vaddr of Paca array  */
 	mulli	r25,r3,PACA_SIZE	 /* Calculate vaddr of right Paca */
 	add	r25,r25,r24              /* for this processor.           */
@@ -1208,7 +1369,7 @@
 	std	r4,0(r9)		/* set the naca pointer */
 
 	/* Get the pointer to the segment table */
-	ld	r6,PACA(r4)             /* Get the base Paca pointer       */
+	ld	r6,PACA(r4)             /* Get the base paca pointer       */
 	ld	r4,PACASTABVIRT(r6)
 
 	bl      .iSeries_fixup_klimit
@@ -1316,17 +1477,10 @@
 					/* executed here.                 */
 
         LOADADDR(r0, 4f)                /* Jump to the copy of this code  */
-	mtctr	r0			/* that we just made              */
+	mtctr	r0			/* that we just made/relocated    */
 	bctr
 
-4:	LOADADDR(r9,rtas)
-	sub	r9,r9,r26
-	ld	r5,RTASBASE(r9)		/* get the value of rtas->base */
-	ld	r9,RTASSIZE(r9)		/* get the value of rtas->size */
-	bl	.copy_and_flush		/* copy upto rtas->base */
-	add     r6,r6,r9		/* then skip over rtas->size bytes */
-
-	LOADADDR(r5,klimit)
+4:	LOADADDR(r5,klimit)
 	sub	r5,r5,r26
 	ld	r5,0(r5)		/* get the value of klimit */
 	sub	r5,r5,r27
@@ -1470,15 +1624,15 @@
 /*
  * This function is called after the master CPU has released the
  * secondary processors.  The execution environment is relocation off.
- * The Paca for this processor has the following fields initialized at
+ * The paca for this processor has the following fields initialized at
  * this point:
  *   1. Processor number
  *   2. Segment table pointer (virtual address)
  * On entry the following are set:
  *   r1    = stack pointer.  vaddr for iSeries, raddr (temp stack) for pSeries
  *   r24   = cpu# (in Linux terms)
- *   r25   = Paca virtual address
- *   SPRG3 = Paca virtual address
+ *   r25   = paca virtual address
+ *   SPRG3 = paca virtual address
  */
 _GLOBAL(__secondary_start)
 
@@ -1523,15 +1677,19 @@
 	sc				/* HvCall_setASR */
 #else
 	/* set the ASR */
-	addi  r3,0,0x4000     /* r3 = ptr to naca */
-	lhz   r3,PLATFORM(r3) /* r3 = platform flags */
-	cmpldi r3,PLATFORM_PSERIES_LPAR
-	bne   98f
-	li	r3,H_SET_ASR  /* hcall = H_SET_ASR */
-	HSC     			    /* Invoking hcall */
-	b     99f
-98:             /* This is not a hypervisor machine */
-	mtasr	r4			/* set the stab location            */
+	addi	r3,0,0x4000     /* r3 = ptr to naca */
+	lhz   	r3,PLATFORM(r3) /* r3 = platform flags */
+	cmpldi 	r3,PLATFORM_PSERIES_LPAR
+	bne   	98f
+	mfspr	r3,PVR
+	srwi	r3,r3,16
+	cmpwi	r3,0x37         /* SStar */
+	bne	98f
+	li	r3,H_SET_ASR    /* hcall = H_SET_ASR */
+	HSC     		/* Invoking hcall */
+	b	99f
+98:                             /* !(rpa hypervisor) || !(sstar) */
+	mtasr	r4	        /* set the stab location         */
 99:
 #endif
 	li	r7,0
@@ -1651,9 +1809,6 @@
 	addi    r2,r2,0x4000
 	sub	r2,r2,r26
 
-	/* Init naca->debug_switch so it can be used in stab & htab init.  */
-	bl	.ppcdbg_initialize
-
 	/* Get the pointer to the segment table which is used by           */
 	/* stab_initialize                                                 */
 	li	r27,0x4000
@@ -1662,15 +1817,19 @@
 	mtspr	SPRG3,r6		/* PPPBBB: Temp... -Peter */
 	ld	r3,PACASTABREAL(r6)
 	ori	r4,r3,1			/* turn on valid bit                */
-	
+
 	/* set the ASR */
-	addi  r3,0,0x4000     /* r3 = ptr to naca */
-	lhz   r3,PLATFORM(r3) /* r3 = platform flags */
-	cmpldi r3,PLATFORM_PSERIES_LPAR
-	bne   98f
-	li	r3,H_SET_ASR  /* hcall = H_SET_ASR */
-	HSC     			    /* Invoking hcall */
-	b     99f
+	addi	r3,0,0x4000     /* r3 = ptr to naca */
+	lhz   	r3,PLATFORM(r3) /* r3 = platform flags */
+	cmpldi 	r3,PLATFORM_PSERIES_LPAR
+	bne   	98f
+	mfspr	r3,PVR
+	srwi	r3,r3,16
+	cmpwi	r3,0x37         /* SStar */
+	bne	98f
+	li	r3,H_SET_ASR    /* hcall = H_SET_ASR */
+	HSC     	        /* Invoking hcall */
+	b     	99f
 98:                 /* This is not a hypervisor machine */
 	mtasr	r4			/* set the stab location            */
 99:
@@ -1681,11 +1840,15 @@
 	bl	.stab_initialize
 	bl	.htab_initialize
 
-	LOADADDR(r6,_SDR1)
+	addi  r3,0,0x4000     /* r3 = ptr to naca */
+	lhz   r3,PLATFORM(r3) /* r3 = platform flags */
+	cmpldi r3,PLATFORM_PSERIES
+	bne    98f
+	LOADADDR(r6,_SDR1)		/* Only if NOT LPAR */
 	sub	r6,r6,r26
 	ld	r6,0(r6)		/* get the value of _SDR1 */
 	mtspr	SDR1,r6			/* set the htab location  */
-
+98: 
 	LOADADDR(r3,.start_here_common)
 	SET_REG_TO_CONST(r4, MSR_KERNEL)
 	mtspr	SRR0,r3
@@ -1735,9 +1898,9 @@
 	addi	r8,r8,0x4000
 	std	r8,0(r9)		/* set the value of the naca ptr  */
 
-	LOADADDR(r4,naca)               /* Get Naca ptr address           */
+	LOADADDR(r4,naca)               /* Get naca ptr address           */
 	ld	r4,0(r4)                /* Get the location of the naca   */
-	ld	r4,PACA(r4)             /* Get the base Paca pointer      */
+	ld	r4,PACA(r4)             /* Get the base paca pointer      */
 	mtspr	SPRG3,r4
 
 	/* ptr to current */
@@ -1887,11 +2050,3 @@
 	.globl	stab_array
 stab_array:
         .space	4096 * (48 - 1)
-	
-/*
- * This space gets a copy of optional info passed to us by the bootstrap
- * Used to pass parameters into the kernel like root=/dev/sda1, etc.
- */
-	.globl	cmd_line
-cmd_line:
-	.space	512
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/htab.c linux-2.4.20-pre5/arch/ppc64/kernel/htab.c
--- linux-2.4.20-pre4/arch/ppc64/kernel/htab.c	Wed Aug 28 16:36:45 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/htab.c	Wed Aug 28 16:37:30 2002
@@ -1,10 +1,11 @@
 /*
- * 
- *
  * PowerPC64 port by Mike Corrigan and Dave Engebretsen
  *   {mikejc|engebret}@us.ibm.com
  *
  *    Copyright (c) 2000 Mike Corrigan <mikejc@us.ibm.com>
+ *
+ * SMP scalability work:
+ *    Copyright (C) 2001 Anton Blanchard <anton@au.ibm.com>, IBM
  * 
  *    Module name: htab.c
  *
@@ -18,17 +19,7 @@
  */
 
 #include <linux/config.h>
-#include <asm/processor.h>
-#include <asm/pgtable.h>
-#include <asm/mmu.h>
-#include <asm/mmu_context.h>
-#include <asm/page.h>
-#include <asm/types.h>
-#include <asm/init.h>
-#include <asm/system.h>
-#include <asm/iSeries/LparData.h>
 #include <linux/spinlock.h>
-#include <asm/ppcdebug.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/proc_fs.h>
@@ -36,61 +27,74 @@
 #include <linux/sysctl.h>
 #include <linux/ctype.h>
 #include <linux/cache.h>
+
+#include <asm/ppcdebug.h>
+#include <asm/processor.h>
+#include <asm/pgtable.h>
+#include <asm/mmu.h>
+#include <asm/mmu_context.h>
+#include <asm/page.h>
+#include <asm/types.h>
 #include <asm/uaccess.h>
 #include <asm/naca.h>
 #include <asm/pmc.h>
 #include <asm/machdep.h>
 #include <asm/lmb.h>
+#include <asm/abs_addr.h>
+#include <asm/io.h>
 #include <asm/eeh.h>
-
-/* For iSeries */
+#include <asm/hvcall.h>
+#include <asm/iSeries/LparData.h>
 #include <asm/iSeries/HvCallHpt.h>
 
-/* Note:  pte   --> Linux PTE
+/*
+ * Note:  pte   --> Linux PTE
  *        HPTE  --> PowerPC Hashed Page Table Entry
+ *
+ * Execution context:
+ *   htab_initialize is called with the MMU off (of course), but
+ *   the kernel has been copied down to zero so it can directly
+ *   reference global data.  At this point it is very difficult
+ *   to print debug info.
+ *
  */
 
 HTAB htab_data = {NULL, 0, 0, 0, 0};
 
-int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
-		   void *buffer, size_t *lenp);
-
-void htab_initialize(void);
-void make_pte_LPAR(HPTE *htab,
-	      unsigned long va, unsigned long pa, int mode,
-	      unsigned long hash_mask, int large);
-
-extern unsigned long reloc_offset(void);
-extern unsigned long get_kernel_vsid( unsigned long ea );
-extern void cacheable_memzero( void *, unsigned int );
-
 extern unsigned long _SDR1;
 extern unsigned long klimit;
 
-extern unsigned long _ASR;
-extern inline void make_ste(unsigned long stab,
-			    unsigned long esid, unsigned long vsid);
-
-extern char _stext[], _etext[], __start_naca[], __end_stab[];
-
-static spinlock_t hash_table_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
-
-#define PTRRELOC(x)	((typeof(x))((unsigned long)(x) - offset))
-#define PTRUNRELOC(x)	((typeof(x))((unsigned long)(x) + offset))
-#define RELOC(x)	(*PTRRELOC(&(x)))
-
-extern unsigned long htab_size( unsigned long );
-unsigned long hpte_getword0_iSeries( unsigned long slot );
+void make_pte(HPTE *htab, unsigned long va, unsigned long pa,
+	      int mode, unsigned long hash_mask, int large);
+long plpar_pte_enter(unsigned long flags,
+		     unsigned long ptex,
+		     unsigned long new_pteh, unsigned long new_ptel,
+		     unsigned long *old_pteh_ret, unsigned long *old_ptel_ret);
+static long hpte_remove(unsigned long hpte_group);
+static long rpa_lpar_hpte_remove(unsigned long hpte_group);
+static long iSeries_hpte_remove(unsigned long hpte_group);
+
+static spinlock_t pSeries_tlbie_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t pSeries_lpar_tlbie_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t hash_table_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 
 #define KB (1024)
 #define MB (1024*KB)
+
+static inline void
+loop_forever(void)
+{
+	volatile unsigned long x = 1;
+	for(;x;x|=1)
+		;
+}
+
 static inline void
 create_pte_mapping(unsigned long start, unsigned long end,
 		   unsigned long mode, unsigned long mask, int large)
 {
-	unsigned long addr, offset = reloc_offset();
-	HTAB *_htab_data = PTRRELOC(&htab_data);
-	HPTE  *htab  = (HPTE *)__v2a(_htab_data->htab);
+	unsigned long addr;
+	HPTE *htab = (HPTE *)__v2a(htab_data.htab);
 	unsigned int step;
 
 	if (large)
@@ -101,8 +105,8 @@
 	for (addr = start; addr < end; addr += step) {
 		unsigned long vsid = get_kernel_vsid(addr);
 		unsigned long va = (vsid << 28) | (addr & 0xfffffff);
-		make_pte(htab, va, (unsigned long)__v2a(addr), mode, mask,
-				large);
+		make_pte(htab, va, (unsigned long)__v2a(addr), 
+			 mode, mask, large);
 	}
 }
 
@@ -111,16 +115,21 @@
 {
 	unsigned long table, htab_size_bytes;
 	unsigned long pteg_count;
-	unsigned long mode_ro, mode_rw, mask;
-	unsigned long offset = reloc_offset();
-	struct naca_struct *_naca = RELOC(naca);
-	HTAB *_htab_data = PTRRELOC(&htab_data);
+	unsigned long mode_rw, mask;
 
+#if 0
+	/* Can't really do the call below since it calls the normal RTAS
+	 * entry point and we're still relocate off at the moment.
+	 * Temporarily diabling until it can call through the relocate off
+	 * RTAS entry point.  -Peter
+	 */
+	ppc64_boot_msg(0x05, "htab init");
+#endif
 	/*
 	 * Calculate the required size of the htab.  We want the number of
 	 * PTEGs to equal one half the number of real pages.
 	 */ 
-	htab_size_bytes = 1UL << _naca->pftSize;
+	htab_size_bytes = 1UL << naca->pftSize;
 	pteg_count = htab_size_bytes >> 7;
 
 	/* For debug, make the HTAB 1/8 as big as it normally would be. */
@@ -129,335 +138,499 @@
 		htab_size_bytes = pteg_count << 7;
 	}
 
-	_htab_data->htab_num_ptegs = pteg_count;
-	_htab_data->htab_hash_mask = pteg_count - 1;
+	htab_data.htab_num_ptegs = pteg_count;
+	htab_data.htab_hash_mask = pteg_count - 1;
 
-	if(_naca->platform == PLATFORM_PSERIES) {
+	if(naca->platform == PLATFORM_PSERIES) {
 		/* Find storage for the HPT.  Must be contiguous in
 		 * the absolute address space.
 		 */
 		table = lmb_alloc(htab_size_bytes, htab_size_bytes);
-		if ( !table )
-			panic("ERROR, cannot find space for HPTE\n");
-		_htab_data->htab = (HPTE *)__a2v(table);
+		if ( !table ) {
+			ppc64_terminate_msg(0x20, "hpt space");
+			loop_forever();
+		}
+		htab_data.htab = (HPTE *)__a2v(table);
 
 		/* htab absolute addr + encoded htabsize */
-		RELOC(_SDR1) = table + __ilog2(pteg_count) - 11;
+		_SDR1 = table + __ilog2(pteg_count) - 11;
 
 		/* Initialize the HPT with no entries */
-		cacheable_memzero((void *)table, htab_size_bytes);
+		memset((void *)table, 0, htab_size_bytes);
 	} else {
-		_htab_data->htab = NULL;
-		RELOC(_SDR1) = 0; 
+		/* Using a hypervisor which owns the htab */
+		htab_data.htab = NULL;
+		_SDR1 = 0; 
 	}
 
-	mode_ro = _PAGE_ACCESSED | _PAGE_COHERENT | PP_RXRX;
 	mode_rw = _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX;
 	mask = pteg_count-1;
 
-	/* Create PTE's for the kernel text and data sections plus
-	 * the HPT and HPTX arrays.  Make the assumption that
-	 * (addr & KERNELBASE) == 0 (ie they are disjoint).
-	 * We also assume that the va is <= 64 bits.
-	 */
-#if 0
-	create_pte_mapping((unsigned long)_stext,       (unsigned long)__start_naca,                 mode_ro, mask);
-	create_pte_mapping((unsigned long)__start_naca, (unsigned long)__end_stab,                   mode_rw, mask);
-	create_pte_mapping((unsigned long)__end_stab,   (unsigned long)_etext,                       mode_ro, mask);
-	create_pte_mapping((unsigned long)_etext,       RELOC(klimit),                               mode_rw, mask);
-	create_pte_mapping((unsigned long)__a2v(table), (unsigned long)__a2v(table+htab_size_bytes), mode_rw, mask);
-#else
-#ifndef CONFIG_PPC_ISERIES
-	if (__is_processor(PV_POWER4) && _naca->physicalMemorySize > 256*MB) {
+	/* XXX we currently map kernel text rw, should fix this */
+	if ((naca->platform & PLATFORM_PSERIES) &&
+	   cpu_has_largepage() && (naca->physicalMemorySize > 256*MB)) {
 		create_pte_mapping((unsigned long)KERNELBASE, 
 				   KERNELBASE + 256*MB, mode_rw, mask, 0);
 		create_pte_mapping((unsigned long)KERNELBASE + 256*MB, 
-				   KERNELBASE + (_naca->physicalMemorySize), 
+				   KERNELBASE + (naca->physicalMemorySize), 
 				   mode_rw, mask, 1);
-		return;
+	} else {
+		create_pte_mapping((unsigned long)KERNELBASE, 
+				   KERNELBASE+(naca->physicalMemorySize), 
+				   mode_rw, mask, 0);
 	}
-#endif
-	create_pte_mapping((unsigned long)KERNELBASE, 
-			   KERNELBASE+(_naca->physicalMemorySize), 
-			   mode_rw, mask, 0);
+#if 0
+	/* Can't really do the call below since it calls the normal RTAS
+	 * entry point and we're still relocate off at the moment.
+	 * Temporarily diabling until it can call through the relocate off
+	 * RTAS entry point.  -Peter
+	 */
+	ppc64_boot_msg(0x06, "htab done");
 #endif
 }
 #undef KB
 #undef MB
 
 /*
- * Create a pte.  Used during initialization only.
+ * Create a pte. Used during initialization only.
  * We assume the PTE will fit in the primary PTEG.
  */
-void make_pte(HPTE *htab,
-	      unsigned long va, unsigned long pa, int mode,
-	      unsigned long hash_mask, int large)
+void make_pte(HPTE *htab, unsigned long va, unsigned long pa,
+	      int mode, unsigned long hash_mask, int large)
 {
-	HPTE  *hptep;
-	unsigned long hash, i;
-	volatile unsigned long x = 1;
-	unsigned long vpn;
-
-#ifdef CONFIG_PPC_PSERIES
-	if(naca->platform == PLATFORM_PSERIES_LPAR) {
-		make_pte_LPAR(htab, va, pa, mode, hash_mask, large); 
-		return;
-	}
-#endif
+	HPTE *hptep, local_hpte, rhpte;
+	unsigned long hash, vpn, flags, lpar_rc;
+	unsigned long i, dummy1, dummy2;
+	long slot;
 
 	if (large)
-		vpn = va >> 24;
+		vpn = va >> LARGE_PAGE_SHIFT;
 	else
-		vpn = va >> 12;
+		vpn = va >> PAGE_SHIFT;
 
 	hash = hpt_hash(vpn, large);
 
-	hptep  = htab +  ((hash & hash_mask)*HPTES_PER_GROUP);
-
-	for (i = 0; i < 8; ++i, ++hptep) {
-		if ( hptep->dw0.dw0.v == 0 ) {		/* !valid */
-			hptep->dw1.dword1 = pa | mode;
-			hptep->dw0.dword0 = 0;
-			hptep->dw0.dw0.avpn = va >> 23;
-			hptep->dw0.dw0.bolted = 1;	/* bolted */
-			hptep->dw0.dw0.v = 1;		/* make valid */
-			return;
+	local_hpte.dw1.dword1 = pa | mode;
+	local_hpte.dw0.dword0 = 0;
+	local_hpte.dw0.dw0.avpn = va >> 23;
+	local_hpte.dw0.dw0.bolted = 1;		/* bolted */
+	if (large) {
+		local_hpte.dw0.dw0.l = 1;	/* large page */
+		local_hpte.dw0.dw0.avpn &= ~0x1UL;
+	}
+	local_hpte.dw0.dw0.v = 1;
+
+	if (naca->platform == PLATFORM_PSERIES) {
+		hptep  = htab + ((hash & hash_mask)*HPTES_PER_GROUP);
+
+		for (i = 0; i < 8; ++i, ++hptep) {
+			if (hptep->dw0.dw0.v == 0) {		/* !valid */
+				*hptep = local_hpte;
+				return;
+			}
 		}
+	} else if (naca->platform == PLATFORM_PSERIES_LPAR) {
+		slot = ((hash & hash_mask)*HPTES_PER_GROUP);
+		
+		/* Set CEC cookie to 0                   */
+		/* Zero page = 0                         */
+		/* I-cache Invalidate = 0                */
+		/* I-cache synchronize = 0               */
+		/* Exact = 0 - modify any entry in group */
+		flags = 0;
+		
+		lpar_rc =  plpar_pte_enter(flags, slot, local_hpte.dw0.dword0,
+					   local_hpte.dw1.dword1, 
+					   &dummy1, &dummy2);
+		if (lpar_rc != H_Success) {
+			ppc64_terminate_msg(0x21, "hpte enter");
+			loop_forever();
+		}
+		return;
+	} else if (naca->platform == PLATFORM_ISERIES_LPAR) {
+		slot = HvCallHpt_findValid(&rhpte, vpn);
+		if (slot < 0) {
+			/* Must find space in primary group */
+			panic("hash_page: hpte already exists\n");
+		}
+		HvCallHpt_addValidate(slot, 0, (HPTE *)&local_hpte );
+		return;
 	}
 
 	/* We should _never_ get here and too early to call xmon. */
-	for(;x;x|=1);
+	ppc64_terminate_msg(0x22, "hpte platform");
+	loop_forever();
+}
+
+/*
+ * find_linux_pte returns the address of a linux pte for a given 
+ * effective address and directory.  If not found, it returns zero.
+ */
+pte_t *find_linux_pte(pgd_t *pgdir, unsigned long ea)
+{
+	pgd_t *pg;
+	pmd_t *pm;
+	pte_t *pt = NULL;
+	pte_t pte;
+
+	pg = pgdir + pgd_index(ea);
+	if (!pgd_none(*pg)) {
+		pm = pmd_offset(pg, ea);
+		if (!pmd_none(*pm)) { 
+			pt = pte_offset(pm, ea);
+			pte = *pt;
+			if (!pte_present(pte))
+				pt = NULL;
+		}
+	}
+
+	return pt;
 }
 
-/* Functions to invalidate a HPTE */
-static void hpte_invalidate_iSeries( unsigned long slot )
+static inline unsigned long computeHptePP(unsigned long pte)
 {
-	HvCallHpt_invalidateSetSwBitsGet( slot, 0, 0 );
+	return (pte & _PAGE_USER) |
+		(((pte & _PAGE_USER) >> 1) &
+		 ((~((pte >> 2) &	/* _PAGE_RW */
+		     (pte >> 7))) &	/* _PAGE_DIRTY */
+		  1));
 }
 
-static void hpte_invalidate_pSeries( unsigned long slot )
+/*
+ * Handle a fault by adding an HPTE. If the address can't be determined
+ * to be valid via Linux page tables, return 1. If handled return 0
+ */
+int __hash_page(unsigned long ea, unsigned long access, 
+		unsigned long vsid, pte_t *ptep)
 {
-	/* Local copy of the first doubleword of the HPTE */
-	union {
-		unsigned long d;
-		Hpte_dword0   h;
-	} hpte_dw0;
+	unsigned long va, vpn;
+	unsigned long newpp, prpn;
+	unsigned long hpteflags;
+	long slot;
+	pte_t old_pte, new_pte;
 
-	/* Locate the HPTE */
-	HPTE  * hptep  = htab_data.htab  + slot;
+	/* Search the Linux page table for a match with va */
+	va = (vsid << 28) | (ea & 0x0fffffff);
+	vpn = va >> PAGE_SHIFT;
 
-	/* Get the first doubleword of the HPTE */
-	hpte_dw0.d = hptep->dw0.dword0;
+	/* Acquire the hash table lock to guarantee that the linux
+	 * pte we fetch will not change
+	 */
+	spin_lock( &hash_table_lock );
+	
+	/* 
+	 * Check the user's access rights to the page.  If access should be
+	 * prevented then send the problem up to do_page_fault.
+	 */
+	access |= _PAGE_PRESENT;
+	if (unlikely(access & ~(pte_val(*ptep)))) {
+		spin_unlock( &hash_table_lock );
+		return 1;
+	}
 
-	/* Invalidate the hpte */
-	hptep->dw0.dword0 = 0;
+	/* 
+	 * We have found a pte (which was present).
+	 * The spinlocks prevent this status from changing
+	 * The hash_table_lock prevents the _PAGE_HASHPTE status
+	 * from changing (RPN, DIRTY and ACCESSED too)
+	 * The page_table_lock prevents the pte from being 
+	 * invalidated or modified
+	 */
 
-	/* Invalidate the tlb   */
-	{
-		unsigned long vsid, group, pi, pi_high;
-
-		vsid = hpte_dw0.h.avpn >> 5;
-		group = slot >> 3;
-		if(hpte_dw0.h.h) {
-			group = ~group;
-		} 
-		pi = (vsid ^ group) & 0x7ff;
-		pi_high = (hpte_dw0.h.avpn & 0x1f) << 11;
-		pi |= pi_high;
-		_tlbie(pi << 12);
-	}
-}
+	/*
+	 * At this point, we have a pte (old_pte) which can be used to build
+	 * or update an HPTE. There are 2 cases:
+	 *
+	 * 1. There is a valid (present) pte with no associated HPTE (this is 
+	 *	the most common case)
+	 * 2. There is a valid (present) pte with an associated HPTE. The
+	 *	current values of the pp bits in the HPTE prevent access
+	 *	because we are doing software DIRTY bit management and the
+	 *	page is currently not DIRTY. 
+	 */
 
+	old_pte = *ptep;
+	new_pte = old_pte;
 
-/* Select an available HPT slot for a new HPTE
- *   return slot index (if in primary group)
- *   return -slot index (if in secondary group) 
- */
-static long hpte_selectslot_iSeries( unsigned long vpn )
-{
-	HPTE hpte;
-	long ret_slot, orig_slot;
-	unsigned long primary_hash;
-	unsigned long hpteg_slot;
-	unsigned long slot;
-	unsigned i, k;
-	union {
-		unsigned long	d;
-		Hpte_dword0	h;
-	} hpte_dw0;
+	/* If the attempted access was a store */
+	if (access & _PAGE_RW)
+		pte_val(new_pte) |= _PAGE_ACCESSED | _PAGE_DIRTY;
+	else
+		pte_val(new_pte) |= _PAGE_ACCESSED;
+
+	newpp = computeHptePP(pte_val(new_pte));
+	
+	/* Check if pte already has an hpte (case 2) */
+	if (unlikely(pte_val(old_pte) & _PAGE_HASHPTE)) {
+		/* There MIGHT be an HPTE for this pte */
+		unsigned long hash, slot, secondary;
+
+		/* XXX fix large pte flag */
+		hash = hpt_hash(vpn, 0);
+		secondary = (pte_val(old_pte) & _PAGE_SECONDARY) >> 15;
+		if (secondary)
+			hash = ~hash;
+		slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP;
+		slot += (pte_val(old_pte) & _PAGE_GROUP_IX) >> 12;
 
-	ret_slot = orig_slot = HvCallHpt_findValid( &hpte, vpn );
-	if ( hpte.dw0.dw0.v ) {		/* If valid ...what do we do now? */
-		udbg_printf( "hpte_selectslot_iSeries: vpn 0x%016lx already valid at slot 0x%016lx\n", vpn, ret_slot );
-		udbg_printf( "hpte_selectslot_iSeries: returned hpte 0x%016lx 0x%016lx\n", hpte.dw0.dword0, hpte.dw1.dword1 );
-
-		return (0x8000000000000000); 
-		/*			panic("select_hpte_slot found entry already valid\n"); */
-	}
-	if ( ret_slot == -1 ) {		/* -1 indicates no available slots */
-
-		/* No available entry found in secondary group */
-
-		PMC_SW_SYSTEM(htab_capacity_castouts);
-
-		primary_hash = hpt_hash(vpn, 0);
-		hpteg_slot = ( primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP;
-		k = htab_data.next_round_robin++ & 0x7;
-
-		for ( i=0; i<HPTES_PER_GROUP; ++i ) {
-			if ( k == HPTES_PER_GROUP )
-				k = 0;
-			slot = hpteg_slot + k;
-			hpte_dw0.d = hpte_getword0_iSeries( slot );
-			if ( !hpte_dw0.h.bolted ) {
-				hpte_invalidate_iSeries( slot );
-				ret_slot = slot;
+		/* XXX fix large pte flag */
+		if (ppc_md.hpte_updatepp(slot, secondary, 
+					 newpp, va, 0) == -1) {
+			pte_val(old_pte) &= ~_PAGE_HPTEFLAGS;
+		} else {
+			if (!pte_same(old_pte, new_pte)) {
+				*ptep = new_pte;
 			}
-			++k;
-		}
-	} else {
-		if ( ret_slot < 0 ) {
-			PMC_SW_SYSTEM(htab_primary_overflows);
-			ret_slot &= 0x7fffffffffffffff;
-			ret_slot = -ret_slot;
 		}
 	}
-	if ( ret_slot == -1 ) {
-		/* No non-bolted entry found in primary group - time to panic */
-        	udbg_printf("hpte_selectslot_pSeries - No non-bolted HPTE in group 0x%lx! \n", hpteg_slot/HPTES_PER_GROUP);
-        	panic("No non-bolted HPTE in group %lx", (unsigned long)hpteg_slot/HPTES_PER_GROUP);
+
+	if (likely(!(pte_val(old_pte) & _PAGE_HASHPTE))) {
+		/* Update the linux pte with the HPTE slot */
+		pte_val(new_pte) &= ~_PAGE_HPTEFLAGS;
+		pte_val(new_pte) |= _PAGE_HASHPTE;
+		prpn = pte_val(old_pte) >> PTE_SHIFT;
+
+		/* copy appropriate flags from linux pte */
+		hpteflags = (pte_val(new_pte) & 0x1f8) | newpp;
+
+		slot = ppc_md.hpte_insert(vpn, prpn, hpteflags, 0, 0);
+
+		pte_val(new_pte) |= ((slot<<12) & 
+				     (_PAGE_GROUP_IX | _PAGE_SECONDARY));
+
+		*ptep = new_pte;
 	}
-	PPCDBG(PPCDBG_MM, "hpte_selectslot_iSeries: vpn=0x%016lx, orig_slot=0x%016lx, ret_slot=0x%016lx \n",
-	       vpn, orig_slot, ret_slot );	
-	return ret_slot;
+
+	spin_unlock(&hash_table_lock);
+
+	return 0;
 }
 
-static long hpte_selectslot_pSeries(unsigned long vpn)
+/*
+ * Handle a fault by adding an HPTE. If the address can't be determined
+ * to be valid via Linux page tables, return 1. If handled return 0
+ */
+int hash_page(unsigned long ea, unsigned long access)
 {
-	HPTE * hptep;
-	unsigned long primary_hash;
-	unsigned long hpteg_slot;
-	unsigned i, k;
+	void *pgdir;
+	unsigned long vsid;
+	struct mm_struct *mm;
+	pte_t *ptep;
+	int ret;
 
-	/* Search the primary group for an available slot */
+	/* Check for invalid addresses. */
+	if (!IS_VALID_EA(ea)) return 1;
 
-	primary_hash = hpt_hash(vpn, 0);
-	hpteg_slot = ( primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP;
-	hptep = htab_data.htab + hpteg_slot;
-	
-	for (i=0; i<HPTES_PER_GROUP; ++i) {
-		if ( hptep->dw0.dw0.v == 0 ) {
-			/* If an available slot found, return it */
-			return hpteg_slot + i;
-		}
-		hptep++;
+ 	switch (REGION_ID(ea)) {
+	case USER_REGION_ID:
+		mm = current->mm;
+		if (mm == NULL) return 1;
+		vsid = get_vsid(mm->context, ea);
+		break;
+	case IO_REGION_ID:
+		mm = &ioremap_mm;
+		vsid = get_kernel_vsid(ea);
+		break;
+	case VMALLOC_REGION_ID:
+		mm = &init_mm;
+		vsid = get_kernel_vsid(ea);
+		break;
+	case IO_UNMAPPED_REGION_ID:
+		udbg_printf("EEH Error ea = 0x%lx\n", ea);
+		PPCDBG_ENTER_DEBUGGER();
+		panic("EEH Error ea = 0x%lx\n", ea);
+		break;
+	case KERNEL_REGION_ID:
+		/*
+		 * As htab_initialize is now, we shouldn't ever get here since
+		 * we're bolting the entire 0xC0... region.
+		 */
+		udbg_printf("Little faulted on kernel address 0x%lx\n", ea);
+		PPCDBG_ENTER_DEBUGGER();
+		panic("Little faulted on kernel address 0x%lx\n", ea);
+		break;
+	default:
+		/* Not a valid range, send the problem up to do_page_fault */
+		return 1;
+		break;
 	}
 
-	/* No available entry found in primary group */
-
-	PMC_SW_SYSTEM(htab_primary_overflows);
-
-	/* Search the secondary group */
+	pgdir = mm->pgd;
+	if (pgdir == NULL) return 1;
 
-	hpteg_slot = ( ~primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP;
-	hptep = htab_data.htab + hpteg_slot;
+	/*
+	 * Lock the Linux page table to prevent mmap and kswapd
+	 * from modifying entries while we search and update
+	 */
+	spin_lock(&mm->page_table_lock);
 
-	for (i=0; i<HPTES_PER_GROUP; ++i) {
-		if ( hptep->dw0.dw0.v == 0 ) {
-			/* If an available slot found, return it */
-			return -(hpteg_slot + i);
-		}
-		hptep++;
+	ptep = find_linux_pte(pgdir, ea);
+	/*
+	 * If no pte found or not present, send the problem up to
+	 * do_page_fault
+	 */
+	if (ptep && pte_present(*ptep)) {
+		ret = __hash_page(ea, access, vsid, ptep);
+	} else {	
+		/* If no pte, send the problem up to do_page_fault */
+		ret = 1;
 	}
 
-	/* No available entry found in secondary group */
+	spin_unlock(&mm->page_table_lock);
+
+	return ret;
+}
 
-	PMC_SW_SYSTEM(htab_capacity_castouts);
+void flush_hash_page(unsigned long context, unsigned long ea, pte_t *ptep)
+{
+	unsigned long vsid, vpn, va, hash, secondary, slot, flags;
+	unsigned long large = 0, local = 0;
+	pte_t pte;
 
-	/* Select an entry in the primary group to replace */
+	if ((ea >= USER_START) && (ea <= USER_END))
+		vsid = get_vsid(context, ea);
+	else
+		vsid = get_kernel_vsid(ea);
 
-	hpteg_slot = ( primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP;
-	hptep = htab_data.htab + hpteg_slot;
-	k = htab_data.next_round_robin++ & 0x7;
+	va = (vsid << 28) | (ea & 0x0fffffff);
+	if (large)
+		vpn = va >> LARGE_PAGE_SHIFT;
+	else
+		vpn = va >> PAGE_SHIFT;
+	hash = hpt_hash(vpn, large);
 
-	for (i=0; i<HPTES_PER_GROUP; ++i) {
-		if (k == HPTES_PER_GROUP)
-			k = 0;
+	spin_lock_irqsave( &hash_table_lock, flags);
 
-		if (!hptep[k].dw0.dw0.bolted) {
-			hpteg_slot += k;
-			/* Invalidate the current entry */
-			ppc_md.hpte_invalidate(hpteg_slot); 
-			return hpteg_slot;
-		}
-		++k;
+	pte = __pte(pte_update(ptep, _PAGE_HPTEFLAGS, 0));
+	secondary = (pte_val(pte) & _PAGE_SECONDARY) >> 15;
+	if (secondary) hash = ~hash;
+	slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP;
+	slot += (pte_val(pte) & _PAGE_GROUP_IX) >> 12;
+	
+	if (pte_val(pte) & _PAGE_HASHPTE) {
+		ppc_md.hpte_invalidate(slot, secondary, va, large, local);
 	}
 
-	/* No non-bolted entry found in primary group - time to panic */
-        udbg_printf("hpte_selectslot_pSeries - No non-bolted HPTE in group 0x%lx! \n", hpteg_slot/HPTES_PER_GROUP);
-	/*      xmon(0); */
-        panic("No non-bolted HPTE in group %lx", (unsigned long)hpteg_slot/HPTES_PER_GROUP);
+	spin_unlock_irqrestore( &hash_table_lock, flags );
+}
 
-	/* keep the compiler happy */
-	return 0;
+long plpar_pte_enter(unsigned long flags,
+		     unsigned long ptex,
+		     unsigned long new_pteh, unsigned long new_ptel,
+		     unsigned long *old_pteh_ret, unsigned long *old_ptel_ret)
+{
+	unsigned long dummy, ret;
+	ret = plpar_hcall(H_ENTER, flags, ptex, new_pteh, new_ptel,
+			   old_pteh_ret, old_ptel_ret, &dummy);
+	return(ret);
 }
 
-unsigned long hpte_getword0_iSeries( unsigned long slot )
+long plpar_pte_remove(unsigned long flags,
+		      unsigned long ptex,
+		      unsigned long avpn,
+		      unsigned long *old_pteh_ret, unsigned long *old_ptel_ret)
 {
-	unsigned long dword0;
+	unsigned long dummy;
+	return plpar_hcall(H_REMOVE, flags, ptex, avpn, 0,
+			   old_pteh_ret, old_ptel_ret, &dummy);
+}
 
-	HPTE hpte;
-	HvCallHpt_get( &hpte, slot );
-	dword0 = hpte.dw0.dword0;
+long plpar_pte_read(unsigned long flags,
+		    unsigned long ptex,
+		    unsigned long *old_pteh_ret, unsigned long *old_ptel_ret)
+{
+	unsigned long dummy;
+	return plpar_hcall(H_READ, flags, ptex, 0, 0,
+			   old_pteh_ret, old_ptel_ret, &dummy);
+}
 
-	return dword0;
+long plpar_pte_protect(unsigned long flags,
+		       unsigned long ptex,
+		       unsigned long avpn)
+{
+	return plpar_hcall_norets(H_PROTECT, flags, ptex, avpn);
+}
+
+static __inline__ void set_pp_bit(unsigned long pp, HPTE *addr)
+{
+	unsigned long old;
+	unsigned long *p = &addr->dw1.dword1;
+
+	__asm__ __volatile__(
+        "1:	ldarx	%0,0,%3\n\
+                rldimi  %0,%2,0,62\n\
+                stdcx.	%0,0,%3\n\
+            	bne	1b"
+        : "=&r" (old), "=m" (*p)
+        : "r" (pp), "r" (p), "m" (*p)
+        : "cc");
 }
 
-unsigned long hpte_getword0_pSeries( unsigned long slot )
+/*
+ * Functions used to retrieve word 0 of a given page table entry.
+ *
+ * Input : slot : PTE index within the page table of the entry to retrieve 
+ * Output: Contents of word 0 of the specified entry
+ */
+static unsigned long rpa_lpar_hpte_getword0(unsigned long slot)
 {
 	unsigned long dword0;
-	HPTE * hptep = htab_data.htab + slot;
+	unsigned long lpar_rc;
+	unsigned long dummy_word1;
+	unsigned long flags;
+
+	/* Read 1 pte at a time                        */
+	/* Do not need RPN to logical page translation */
+	/* No cross CEC PFT access                     */
+	flags = 0;
+	
+	lpar_rc = plpar_pte_read(flags, slot, &dword0, &dummy_word1);
+
+	if (lpar_rc != H_Success)
+		panic("Error on pte read in get_hpte0 rc = %lx\n", lpar_rc);
 
-	dword0 = hptep->dw0.dword0;
 	return dword0;
 }
 
-static long hpte_find_iSeries(unsigned long vpn)
+unsigned long iSeries_hpte_getword0(unsigned long slot)
 {
+	unsigned long dword0;
+
 	HPTE hpte;
-	long slot;
+	HvCallHpt_get(&hpte, slot);
+	dword0 = hpte.dw0.dword0;
 
-	slot = HvCallHpt_findValid( &hpte, vpn );
-	if ( hpte.dw0.dw0.v ) {
-		if ( slot < 0 ) {
-			slot &= 0x7fffffffffffffff;
-			slot = -slot;
-		}
-	} else
-		slot = -1;
-	return slot;
+	return dword0;
 }
 
-static long hpte_find_pSeries(unsigned long vpn)
+/*
+ * Functions used to find the PTE for a particular virtual address. 
+ * Only used during boot when bolting pages.
+ *
+ * Input : vpn      : virtual page number
+ * Output: PTE index within the page table of the entry
+ *         -1 on failure
+ */
+static long hpte_find(unsigned long vpn)
 {
-	union {
-		unsigned long d;
-		Hpte_dword0   h;
-	} hpte_dw0;
-	long slot;
+	HPTE *hptep;
 	unsigned long hash;
-	unsigned long i,j;
+	unsigned long i, j;
+	long slot;
+	Hpte_dword0 dw0;
 
 	hash = hpt_hash(vpn, 0);
-	for ( j=0; j<2; ++j ) {
+
+	for (j = 0; j < 2; j++) {
 		slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP;
-		for ( i=0; i<HPTES_PER_GROUP; ++i ) {
-			hpte_dw0.d = hpte_getword0_pSeries( slot );
-			if ( ( hpte_dw0.h.avpn == ( vpn >> 11 ) ) &&
-			     ( hpte_dw0.h.v ) &&
-			     ( hpte_dw0.h.h == j ) ) {
+		for (i = 0; i < HPTES_PER_GROUP; i++) {
+			hptep = htab_data.htab + slot;
+			dw0 = hptep->dw0.dw0;
+
+			if ((dw0.avpn == (vpn >> 11)) && dw0.v &&
+			    (dw0.h == j)) {
 				/* HPTE matches */
-				if ( j )
+				if (j)
 					slot = -slot;
 				return slot;
 			}
@@ -465,247 +638,320 @@
 		}
 		hash = ~hash;
 	}
+
 	return -1;
-} 
+}
 
-/* This function is called by iSeries setup when initializing the hpt */
-void build_valid_hpte( unsigned long vsid, unsigned long ea, unsigned long pa,
-		       pte_t * ptep, unsigned hpteflags, unsigned bolted )
-{
-	unsigned long vpn, flags;
-	long hpte_slot;
-	unsigned hash;
-	pte_t pte;
+static long rpa_lpar_hpte_find(unsigned long vpn)
+{
+	unsigned long hash;
+	unsigned long i, j;
+	long slot;
+	union {
+		unsigned long dword0;
+		Hpte_dword0 dw0;
+	} hpte_dw0;
+	Hpte_dword0 dw0;
 
-	vpn = ((vsid << 28) | ( ea & 0xffff000 )) >> 12;
+	hash = hpt_hash(vpn, 0);
 
-	spin_lock_irqsave( &hash_table_lock, flags );
+	for (j = 0; j < 2; j++) {
+		slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP;
+		for (i = 0; i < HPTES_PER_GROUP; i++) {
+			hpte_dw0.dword0 = rpa_lpar_hpte_getword0(slot);
+			dw0 = hpte_dw0.dw0;
 
-	hpte_slot = ppc_md.hpte_selectslot( vpn );
-	hash = 0;
-	if ( hpte_slot < 0 ) {
-		if ( hpte_slot == 0x8000000000000000 ) {
-			udbg_printf("hash_page: ptep    = 0x%016lx\n", 
-				    (unsigned long)ptep );
-			udbg_printf("hash_page: ea      = 0x%016lx\n", ea );
-			udbg_printf("hash_page: vpn     = 0x%016lx\n", vpn );
-               
-			panic("hash_page: hpte already exists\n");
+			if ((dw0.avpn == (vpn >> 11)) && dw0.v &&
+			    (dw0.h == j)) {
+				/* HPTE matches */
+				if (j)
+					slot = -slot;
+				return slot;
+			}
+			++slot;
 		}
-		hash = 1;
-		hpte_slot = -hpte_slot;
+		hash = ~hash;
 	}
-	ppc_md.hpte_create_valid( hpte_slot, vpn, pa >> 12, hash, ptep,
-				  hpteflags, bolted );
-
-	if ( ptep ) {
-		/* Get existing pte flags */
-		pte = *ptep;
-		pte_val(pte) &= ~_PAGE_HPTEFLAGS;
-
-		/* Add in the has hpte flag */
-		pte_val(pte) |= _PAGE_HASHPTE;
-
-		/* Add in the _PAGE_SECONDARY flag */
-		pte_val(pte) |= hash << 15;
-
-		/* Add in the hpte slot */
-		pte_val(pte) |= (hpte_slot << 12) & _PAGE_GROUP_IX;
-               
-		/* Save the new pte.  */
-		*ptep = pte;
-               
-	}
-	spin_unlock_irqrestore( &hash_table_lock, flags );
-}
 
+	return -1;
+} 
 
-/* Create an HPTE and validate it
- *   It is assumed that the HPT slot currently is invalid.
- *   The HPTE is set with the vpn, rpn (converted to absolute)
- *   and flags
- */
-static void hpte_create_valid_iSeries(unsigned long slot, unsigned long vpn,
-				      unsigned long prpn, unsigned hash, 
-				      void * ptep, unsigned hpteflags, 
-				      unsigned bolted )
-{
-	/* Local copy of HPTE */
-	struct {
-		/* Local copy of first doubleword of HPTE */
-		union {
-			unsigned long d;
-			Hpte_dword0   h;
-		} dw0;
-		/* Local copy of second doubleword of HPTE */
-		union {
-			unsigned long     d;
-			Hpte_dword1       h;
-			Hpte_dword1_flags f;
-		} dw1;
-	} lhpte;
-	
-	unsigned long avpn = vpn >> 11;
-	unsigned long arpn = physRpn_to_absRpn( prpn );
+static long iSeries_hpte_find(unsigned long vpn)
+{
+	HPTE hpte;
+	long slot;
 
-	/* Fill in the local HPTE with absolute rpn, avpn and flags */
-	lhpte.dw1.d        = 0;
-	lhpte.dw1.h.rpn    = arpn;
-	lhpte.dw1.f.flags  = hpteflags;
-
-	lhpte.dw0.d        = 0;
-	lhpte.dw0.h.avpn   = avpn;
-	lhpte.dw0.h.h      = hash;
-	lhpte.dw0.h.bolted = bolted;
-	lhpte.dw0.h.v      = 1;
+	/*
+	 * The HvCallHpt_findValid interface is as follows:
+	 * 0xffffffffffffffff : No entry found.
+	 * 0x00000000xxxxxxxx : Entry found in primary group, slot x
+	 * 0x80000000xxxxxxxx : Entry found in secondary group, slot x
+	 */
+	slot = HvCallHpt_findValid(&hpte, vpn); 
+	if (hpte.dw0.dw0.v) {
+		if (slot < 0) {
+			slot &= 0x7fffffffffffffff;
+			slot = -slot;
+		}
+	} else {
+		slot = -1;
+	}
 
-	/* Now fill in the actual HPTE */
-	HvCallHpt_addValidate( slot, hash, (HPTE *)&lhpte );
+	return slot;
 }
 
-static void hpte_create_valid_pSeries(unsigned long slot, unsigned long vpn,
-				      unsigned long prpn, unsigned hash, 
-				      void * ptep, unsigned hpteflags, 
-				      unsigned bolted)
-{
-	/* Local copy of HPTE */
-	struct {
-		/* Local copy of first doubleword of HPTE */
-		union {
-			unsigned long d;
-			Hpte_dword0   h;
-		} dw0;
-		/* Local copy of second doubleword of HPTE */
-		union {
-			unsigned long     d;
-			Hpte_dword1       h;
-			Hpte_dword1_flags f;
-		} dw1;
-	} lhpte;
-	
-	unsigned long avpn = vpn >> 11;
-	unsigned long arpn = physRpn_to_absRpn( prpn );
+/*
+ * Functions used to invalidate a page table entry from the page table
+ * and tlb.
+ *
+ * Input : slot  : PTE index within the page table of the entry to invalidated
+ *         va    : Virtual address of the entry being invalidated
+ *         large : 1 = large page (16M)
+ *         local : 1 = Use tlbiel to only invalidate the local tlb 
+ */
+static void hpte_invalidate(unsigned long slot, 
+			    unsigned long secondary,
+			    unsigned long va,
+			    int large, int local)
+{
+	HPTE *hptep = htab_data.htab + slot;
+	Hpte_dword0 dw0;
+	unsigned long vpn, avpn;
+	unsigned long flags;
 
-	HPTE *hptep;
+	if (large)
+		vpn = va >> LARGE_PAGE_SHIFT;
+	else
+		vpn = va >> PAGE_SHIFT;
 
-	/* Fill in the local HPTE with absolute rpn, avpn and flags */
-	lhpte.dw1.d        = 0;
-	lhpte.dw1.h.rpn    = arpn;
-	lhpte.dw1.f.flags  = hpteflags;
-
-	lhpte.dw0.d        = 0;
-	lhpte.dw0.h.avpn   = avpn;
-	lhpte.dw0.h.h      = hash;
-	lhpte.dw0.h.bolted = bolted;
-	lhpte.dw0.h.v      = 1;
+	avpn = vpn >> 11;
 
-	/* Now fill in the actual HPTE */
-	hptep  = htab_data.htab  + slot;
+	dw0 = hptep->dw0.dw0;
 
-	/* Set the second dword first so that the valid bit
-	 * is the last thing set
+	/*
+	 * Do not remove bolted entries.  Alternatively, we could check
+	 * the AVPN, hash group, and valid bits.  By doing it this way,
+	 * it is common with the pSeries LPAR optimal path.
 	 */
-	
-	hptep->dw1.dword1 = lhpte.dw1.d;
+	if (dw0.bolted) return;
 
-	/* Guarantee the second dword is visible before
-	 * the valid bit
+	/* Invalidate the hpte. */
+	hptep->dw0.dword0 = 0;
+
+	/* Invalidate the tlb */
+	spin_lock_irqsave(&pSeries_tlbie_lock, flags);
+	_tlbie(va, large);
+	spin_unlock_irqrestore(&pSeries_tlbie_lock, flags);
+}
+
+static void rpa_lpar_hpte_invalidate(unsigned long slot, 
+				     unsigned long secondary,
+				     unsigned long va,
+				     int large, int local)
+{
+	unsigned long lpar_rc;
+	unsigned long dummy1, dummy2;
+
+	/* 
+	 * Don't remove a bolted entry.  This case can occur when we bolt
+	 * pages dynamically after initial boot.
 	 */
-	
-	__asm__ __volatile__ ("eieio" : : : "memory");
+	lpar_rc = plpar_pte_remove(H_ANDCOND, slot, (0x1UL << 4), 
+				   &dummy1, &dummy2);
+
+	if (lpar_rc != H_Success)
+		panic("Bad return code from invalidate rc = %lx\n", lpar_rc);
+}
 
-	/* Now set the first dword including the valid bit */
-	hptep->dw0.dword0 = lhpte.dw0.d;
+static void iSeries_hpte_invalidate(unsigned long slot, 
+				    unsigned long secondary,
+				    unsigned long va,
+				    int large, int local)
+{
+	HPTE lhpte;
+	unsigned long vpn, avpn;
 
-	__asm__ __volatile__ ("ptesync" : : : "memory");
+	if (large)
+		vpn = va >> LARGE_PAGE_SHIFT;
+	else
+		vpn = va >> PAGE_SHIFT;
+
+	avpn = vpn >> 11;
+
+	lhpte.dw0.dword0 = iSeries_hpte_getword0(slot);
+	
+	if ((lhpte.dw0.dw0.avpn == avpn) && 
+	    (lhpte.dw0.dw0.v) &&
+	    (lhpte.dw0.dw0.h == secondary)) {
+		HvCallHpt_invalidateSetSwBitsGet(slot, 0, 0);
+	}
 }
 
-/* find_linux_pte returns the address of a linux pte for a given 
- * effective address and directory.  If not found, it returns zero.
+/*
+ * Functions used to update page protection bits.
+ *
+ * Input : slot  : PTE index within the page table of the entry to update
+ *         newpp : new page protection bits
+ *         va    : Virtual address of the entry being updated
+ *         large : 1 = large page (16M)
+ * Output: 0 on success, -1 on failure
  */
+static long hpte_updatepp(unsigned long slot, 
+			  unsigned long secondary,
+			  unsigned long newpp,
+			  unsigned long va, int large)
+{
+	HPTE *hptep = htab_data.htab + slot;
+	Hpte_dword0 dw0;
+	Hpte_dword1 dw1;
+	unsigned long vpn, avpn;
+	unsigned long flags;
 
-pte_t  * find_linux_pte( pgd_t * pgdir, unsigned long ea )
-{
-	pgd_t *pg;
-	pmd_t *pm;
-	pte_t *pt = NULL;
-	pte_t pte;
-	pg = pgdir + pgd_index( ea );
-	if ( ! pgd_none( *pg ) ) {
+	if (large)
+		vpn = va >> LARGE_PAGE_SHIFT;
+	else
+		vpn = va >> PAGE_SHIFT;
 
-		pm = pmd_offset( pg, ea );
-		if ( ! pmd_none( *pm ) ) { 
-			pt = pte_offset( pm, ea );
-			pte = *pt;
-			if ( ! pte_present( pte ) )
-				pt = NULL;
-		}
-	}
+	avpn = vpn >> 11;
 
-	return pt;
+	dw0 = hptep->dw0.dw0;
+	if ((dw0.avpn == avpn) && 
+	    (dw0.v) && (dw0.h == secondary)) {
+		/* Turn off valid bit in HPTE */
+		dw0.v = 0;
+		hptep->dw0.dw0 = dw0;
+		
+		/* Ensure it is out of the tlb too */
+		spin_lock_irqsave(&pSeries_tlbie_lock, flags);
+		_tlbie(va, large);
+		spin_unlock_irqrestore(&pSeries_tlbie_lock, flags);
+		
+		/* Insert the new pp bits into the HPTE */
+		dw1 = hptep->dw1.dw1;
+		dw1.pp = newpp;
+		hptep->dw1.dw1 = dw1;
+		
+		/* Ensure it is visible before validating */
+		__asm__ __volatile__ ("eieio" : : : "memory");
+		
+		/* Turn the valid bit back on in HPTE */
+		dw0.v = 1;
+		hptep->dw0.dw0 = dw0;
+		
+		__asm__ __volatile__ ("ptesync" : : : "memory");
+		
+		return 0;
+	}
 
+	return -1;
 }
 
-static inline unsigned long computeHptePP( unsigned long pte )
-{
-	return (     pte & _PAGE_USER )           |
-		( ( ( pte & _PAGE_USER )    >> 1 ) &
-		  ( ( ~( ( pte >> 2 ) &		/* _PAGE_RW */
-		         ( pte >> 7 ) ) ) &     /* _PAGE_DIRTY */
-			 1 ) );
+static long rpa_lpar_hpte_updatepp(unsigned long slot, 
+				   unsigned long secondary,
+				   unsigned long newpp,
+				   unsigned long va, int large)
+{
+	unsigned long lpar_rc;
+	unsigned long flags = (newpp & 7);
+	unsigned long avpn = va >> 23;
+	HPTE hpte;
+
+	lpar_rc = plpar_pte_read(0, slot, &hpte.dw0.dword0, &hpte.dw1.dword1);
+
+	if ((hpte.dw0.dw0.avpn == avpn) &&
+	    (hpte.dw0.dw0.v) && 
+	    (hpte.dw0.dw0.h == secondary)) {
+		lpar_rc = plpar_pte_protect(flags, slot, 0);
+		if (lpar_rc != H_Success)
+			panic("bad return code from pte protect rc = %lx\n", 
+			      lpar_rc);
+		return 0;
+	}
+
+	return -1;
 }
 
-static void hpte_updatepp_iSeries(long slot, unsigned long newpp, unsigned long va)
+static long iSeries_hpte_updatepp(unsigned long slot, 
+				  unsigned long secondary,
+				  unsigned long newpp, 
+				  unsigned long va, int large)
 {
-	HvCallHpt_setPp( slot, newpp );
+	unsigned long vpn, avpn;
+	HPTE hpte;
+
+	if (large)
+		vpn = va >> LARGE_PAGE_SHIFT;
+	else
+		vpn = va >> PAGE_SHIFT;
+
+	avpn = vpn >> 11;
+
+	HvCallHpt_get(&hpte, slot);
+	if ((hpte.dw0.dw0.avpn == avpn) && 
+	    (hpte.dw0.dw0.v) &&
+	    (hpte.dw0.dw0.h == secondary)) {
+		HvCallHpt_setPp(slot, newpp);
+		return 0;
+	}
+	return -1;
 }
 
-static void hpte_updatepp_pSeries(long slot, unsigned long newpp, unsigned long va)
+/*
+ * Functions used to update the page protection bits. Intended to be used 
+ * to create guard pages for kernel data structures on pages which are bolted
+ * in the HPT. Assumes pages being operated on will not be stolen.
+ * Does not work on large pages. No need to lock here because we are the 
+ * only user.
+ * 
+ * Input : newpp : page protection flags
+ *         ea    : effective kernel address to bolt.
+ */
+static void hpte_updateboltedpp(unsigned long newpp, unsigned long ea)
 {
-	/* Local copy of first doubleword of HPTE */
-	union {
-		unsigned long d;
-		Hpte_dword0   h;
-	} hpte_dw0;
-	
-	/* Local copy of second doubleword of HPTE */
-	union {
-		unsigned long     d;
-		Hpte_dword1       h;
-		Hpte_dword1_flags f;
-	} hpte_dw1;	
-
-	HPTE *  hptep  = htab_data.htab  + slot;
-
-	/* Turn off valid bit in HPTE */
-	hpte_dw0.d = hptep->dw0.dword0;
-	hpte_dw0.h.v = 0;
-	hptep->dw0.dword0 = hpte_dw0.d;
+	unsigned long vsid, va, vpn, flags;
+	long slot;
+	HPTE *hptep;
+
+	vsid = get_kernel_vsid(ea);
+	va = (vsid << 28) | (ea & 0x0fffffff);
+	vpn = va >> PAGE_SHIFT;
+
+	slot = hpte_find(vpn);
+	if (slot == -1)
+		panic("could not find page to bolt\n");
+	hptep = htab_data.htab + slot;
+
+	set_pp_bit(newpp, hptep);
 
 	/* Ensure it is out of the tlb too */
-	_tlbie( va );
+	spin_lock_irqsave(&pSeries_tlbie_lock, flags);
+	_tlbie(va, 0);
+	spin_unlock_irqrestore(&pSeries_tlbie_lock, flags);
+}
 
-	/* Insert the new pp bits into the HPTE */
-	hpte_dw1.d = hptep->dw1.dword1;
-	hpte_dw1.h.pp = newpp;
-	hptep->dw1.dword1 = hpte_dw1.d;
+static void rpa_lpar_hpte_updateboltedpp(unsigned long newpp, unsigned long ea)
+{
+	unsigned long lpar_rc;
+	unsigned long vsid, va, vpn, flags;
+	long slot;
 
-	/* Ensure it is visible before validating */
-	__asm__ __volatile__ ("eieio" : : : "memory");
+	vsid = get_kernel_vsid(ea);
+	va = (vsid << 28) | (ea & 0x0fffffff);
+	vpn = va >> PAGE_SHIFT;
 
-	/* Turn the valid bit back on in HPTE */
-	hpte_dw0.h.v = 1;
-	hptep->dw0.dword0 = hpte_dw0.d;
+	slot = rpa_lpar_hpte_find(vpn);
+	if (slot == -1)
+		panic("updateboltedpp: Could not find page to bolt\n");
 
-	__asm__ __volatile__ ("ptesync" : : : "memory");
+	flags = newpp & 3;
+	lpar_rc = plpar_pte_protect(flags, slot, 0);
+
+	if (lpar_rc != H_Success)
+		panic("Bad return code from pte bolted protect rc = %lx\n",
+		      lpar_rc); 
 }
 
-/*
- * Update the page protection bits.  Intended to be used to create
- * guard pages for kernel data structures on pages which are bolted
- * in the HPT.  Assumes pages being operated on will not be stolen. 
- */
-void hpte_updateboltedpp_iSeries(unsigned long newpp, unsigned long ea )
+void iSeries_hpte_updateboltedpp(unsigned long newpp, unsigned long ea)
 {
 	unsigned long vsid,va,vpn;
 	long slot;
@@ -714,518 +960,408 @@
 	va = ( vsid << 28 ) | ( ea & 0x0fffffff );
 	vpn = va >> PAGE_SHIFT;
 
-	slot = ppc_md.hpte_find( vpn );
-	HvCallHpt_setPp( slot, newpp );
-}
+	slot = iSeries_hpte_find(vpn); 
+	if (slot == -1)
+		panic("updateboltedpp: Could not find page to bolt\n");
 
-
-static __inline__ void set_pp_bit(unsigned long  pp, HPTE *addr)
-{
-	unsigned long old;
-	unsigned long *p = (unsigned long *)(&(addr->dw1));
-
-	__asm__ __volatile__(
-        "1:	ldarx	%0,0,%3\n\
-                rldimi  %0,%2,0,62\n\
-                stdcx.	%0,0,%3\n\
-            	bne	1b"
-        : "=&r" (old), "=m" (*p)
-        : "r" (pp), "r" (p), "m" (*p)
-        : "cc");
+	HvCallHpt_setPp(slot, newpp);
 }
 
 /*
- * Update the page protection bits.  Intended to be used to create
- * guard pages for kernel data structures on pages which are bolted
- * in the HPT.  Assumes pages being operated on will not be stolen. 
+ * Functions used to insert new hardware page table entries.
+ * Will castout non-bolted entries as necessary using a random
+ * algorithm.
+ *
+ * Input : vpn      : virtual page number
+ *         prpn     : real page number in absolute space
+ *         hpteflags: page protection flags
+ *         bolted   : 1 = bolt the page
+ *         large    : 1 = large page (16M)
+ * Output: hsss, where h = hash group, sss = slot within that group
  */
-void hpte_updateboltedpp_pSeries(unsigned long newpp, unsigned long ea)
+static long hpte_insert(unsigned long vpn, unsigned long prpn,
+			unsigned long hpteflags, int bolted, int large)
 {
-	unsigned long vsid,va,vpn,flags;
-	long slot;
 	HPTE *hptep;
+	Hpte_dword0 dw0;
+	HPTE lhpte;
+	int i, secondary;
+	unsigned long hash = hpt_hash(vpn, 0);
+	unsigned long avpn = vpn >> 11;
+	unsigned long arpn = physRpn_to_absRpn(prpn);
+	unsigned long hpte_group;
 
-	vsid = get_kernel_vsid( ea );
-	va = ( vsid << 28 ) | ( ea & 0x0fffffff );
-	vpn = va >> PAGE_SHIFT;
+repeat:
+	secondary = 0;
+	hpte_group = ((hash & htab_data.htab_hash_mask) *
+		      HPTES_PER_GROUP) & ~0x7UL;
+	hptep = htab_data.htab + hpte_group;
+
+	for (i = 0; i < HPTES_PER_GROUP; i++) {
+		dw0 = hptep->dw0.dw0;
+		if (!dw0.v) {
+			/* retry with lock held */
+			dw0 = hptep->dw0.dw0;
+			if (!dw0.v)
+				break;
+		}
+		hptep++;
+	}
 
-	slot = ppc_md.hpte_find( vpn );
-	hptep = htab_data.htab  + slot;
+	if (i == HPTES_PER_GROUP) {
+		secondary = 1;
+		hpte_group = ((~hash & htab_data.htab_hash_mask) *
+			      HPTES_PER_GROUP) & ~0x7UL;
+		hptep = htab_data.htab + hpte_group;
+
+		for (i = 0; i < HPTES_PER_GROUP; i++) {
+			dw0 = hptep->dw0.dw0;
+			if (!dw0.v) {
+				/* retry with lock held */
+				dw0 = hptep->dw0.dw0;
+				if (!dw0.v)
+					break;
+			}
+			hptep++;
+		}
+		if (i == HPTES_PER_GROUP) {
+			if (mftb() & 0x1)
+				hpte_group=((hash & htab_data.htab_hash_mask)* 
+					    HPTES_PER_GROUP) & ~0x7UL;
+			
+			hpte_remove(hpte_group);
+			goto repeat;
+		}
+	}
 
-	set_pp_bit(newpp , hptep);
+	lhpte.dw1.dword1      = 0;
+	lhpte.dw1.dw1.rpn     = arpn;
+	lhpte.dw1.flags.flags = hpteflags;
 
-	/* Ensure it is out of the tlb too */
-	spin_lock_irqsave( &hash_table_lock, flags );
-	_tlbie( va );
-	spin_unlock_irqrestore( &hash_table_lock, flags );
-}
+	lhpte.dw0.dword0      = 0;
+	lhpte.dw0.dw0.avpn    = avpn;
+	lhpte.dw0.dw0.h       = secondary;
+	lhpte.dw0.dw0.bolted  = bolted;
+	lhpte.dw0.dw0.v       = 1;
 
+	if (large) lhpte.dw0.dw0.l = 1;
 
+	hptep->dw1.dword1 = lhpte.dw1.dword1;
 
-/* This is called very early. */
-void hpte_init_iSeries(void)
-{
-	ppc_md.hpte_invalidate   = hpte_invalidate_iSeries;
-	ppc_md.hpte_updatepp     = hpte_updatepp_iSeries;
-	ppc_md.hpte_updateboltedpp = hpte_updateboltedpp_iSeries;
-	ppc_md.hpte_getword0     = hpte_getword0_iSeries;
-	ppc_md.hpte_selectslot   = hpte_selectslot_iSeries;
-	ppc_md.hpte_create_valid = hpte_create_valid_iSeries;
-	ppc_md.hpte_find	 = hpte_find_iSeries;
+	/* Guarantee the second dword is visible before the valid bit */
+	__asm__ __volatile__ ("eieio" : : : "memory");
+
+	/*
+	 * Now set the first dword including the valid bit
+	 * NOTE: this also unlocks the hpte
+	 */
+	hptep->dw0.dword0 = lhpte.dw0.dword0;
+
+	__asm__ __volatile__ ("ptesync" : : : "memory");
+
+	return ((secondary << 3) | i);
 }
-void hpte_init_pSeries(void)
+
+static long rpa_lpar_hpte_insert(unsigned long vpn, unsigned long prpn,
+				 unsigned long hpteflags,
+				 int bolted, int large)
 {
-	ppc_md.hpte_invalidate   = hpte_invalidate_pSeries;
-	ppc_md.hpte_updatepp     = hpte_updatepp_pSeries;
-	ppc_md.hpte_updateboltedpp = hpte_updateboltedpp_pSeries;
-	ppc_md.hpte_getword0     = hpte_getword0_pSeries;
-	ppc_md.hpte_selectslot   = hpte_selectslot_pSeries;
-	ppc_md.hpte_create_valid = hpte_create_valid_pSeries;
-	ppc_md.hpte_find	 = hpte_find_pSeries;
+	/* XXX fix for large page */
+	unsigned long lpar_rc;
+	unsigned long flags;
+	unsigned long slot;
+	HPTE lhpte;
+	int secondary;
+	unsigned long hash = hpt_hash(vpn, 0);
+	unsigned long avpn = vpn >> 11;
+	unsigned long arpn = physRpn_to_absRpn(prpn);
+	unsigned long hpte_group;
+
+	/* Fill in the local HPTE with absolute rpn, avpn and flags */
+	lhpte.dw1.dword1      = 0;
+	lhpte.dw1.dw1.rpn     = arpn;
+	lhpte.dw1.flags.flags = hpteflags;
+
+	lhpte.dw0.dword0      = 0;
+	lhpte.dw0.dw0.avpn    = avpn;
+	lhpte.dw0.dw0.bolted  = bolted;
+	lhpte.dw0.dw0.v       = 1;
+
+	if (large) lhpte.dw0.dw0.l = 1;
+
+	/* Now fill in the actual HPTE */
+	/* Set CEC cookie to 0         */
+	/* Large page = 0              */
+	/* Zero page = 0               */
+	/* I-cache Invalidate = 0      */
+	/* I-cache synchronize = 0     */
+	/* Exact = 0                   */
+	flags = 0;
+
+	/* XXX why is this here? - Anton */
+	/*   -- Because at one point we hit a case where non cachable
+	 *      pages where marked coherent & this is rejected by the HV.
+	 *      Perhaps it is no longer an issue ... DRENG.
+	 */ 
+	if (hpteflags & (_PAGE_GUARDED|_PAGE_NO_CACHE))
+		lhpte.dw1.flags.flags &= ~_PAGE_COHERENT;
+
+repeat:
+	secondary = 0;
+	lhpte.dw0.dw0.h = secondary;
+	hpte_group = ((hash & htab_data.htab_hash_mask) *
+		      HPTES_PER_GROUP) & ~0x7UL;
+
+	__asm__ __volatile__ (
+		H_ENTER_r3
+		"mr    4, %2\n"
+                "mr    5, %3\n"
+                "mr    6, %4\n"
+                "mr    7, %5\n"
+                HSC    
+                "mr    %0, 3\n"
+                "mr    %1, 4\n"
+		: "=r" (lpar_rc), "=r" (slot)
+		: "r" (flags), "r" (hpte_group), "r" (lhpte.dw0.dword0),
+		"r" (lhpte.dw1.dword1)
+		: "r0", "r3", "r4", "r5", "r6", "r7", 
+		  "r8", "r9", "r10", "r11", "r12", "cc");
+
+	if (lpar_rc == H_PTEG_Full) {
+		secondary = 1;
+		lhpte.dw0.dw0.h = secondary;
+		hpte_group = ((~hash & htab_data.htab_hash_mask) *
+			      HPTES_PER_GROUP) & ~0x7UL;
+
+		__asm__ __volatile__ (
+			      H_ENTER_r3
+			      "mr    4, %2\n"
+			      "mr    5, %3\n"
+			      "mr    6, %4\n"
+			      "mr    7, %5\n"
+			      HSC    
+			      "mr    %0, 3\n"
+			      "mr    %1, 4\n"
+			      : "=r" (lpar_rc), "=r" (slot)
+			      : "r" (flags), "r" (hpte_group), "r" (lhpte.dw0.dword0),
+			      "r" (lhpte.dw1.dword1)
+			      : "r0", "r3", "r4", "r5", "r6", "r7",
+			        "r8", "r9", "r10", "r11", "r12", "cc");
+		if (lpar_rc == H_PTEG_Full) {
+			if (mftb() & 0x1)
+				hpte_group=((hash & htab_data.htab_hash_mask)* 
+					    HPTES_PER_GROUP) & ~0x7UL;
+			
+			rpa_lpar_hpte_remove(hpte_group);
+			goto repeat;
+		}
+	}
+
+	if (lpar_rc != H_Success)
+		panic("Bad return code from pte enter rc = %lx\n", lpar_rc);
+
+	return ((secondary << 3) | (slot & 0x7));
 }
 
-/* Handle a fault by adding an HPTE 
- * If the address can't be determined to be valid
- * via Linux page tables, return 1.  If handled
- * return 0
- */
-int hash_page( unsigned long ea, unsigned long access )
+static long iSeries_hpte_insert(unsigned long vpn, unsigned long prpn,
+				unsigned long hpteflags,
+				int bolted, int large)
 {
-	int rc = 1;
-	void * pgdir = NULL;
-	unsigned long va, vsid, vpn;
-	unsigned long newpp, hash_ind, prpn;
-	unsigned long hpteflags, regionid;
+	HPTE lhpte;
+	unsigned long hash, hpte_group;
+	unsigned long avpn = vpn >> 11;
+	unsigned long arpn = physRpn_to_absRpn( prpn );
+	int secondary = 0;
 	long slot;
-	struct mm_struct * mm;
-	pte_t old_pte, new_pte, *ptep;
 
-	/* Check for invalid addresses. */
-	if (!IS_VALID_EA(ea)) {
-		return 1;
+	hash = hpt_hash(vpn, 0);
+
+repeat:
+	slot = HvCallHpt_findValid(&lhpte, vpn);
+	if (lhpte.dw0.dw0.v) {
+		panic("select_hpte_slot found entry already valid\n");
 	}
 
-	regionid =  REGION_ID(ea);
-	switch ( regionid ) {
-	case USER_REGION_ID:
-		mm = current->mm;
-		if ( mm == NULL ) {
-			PPCDBG(PPCDBG_MM, "hash_page returning; mm = 0\n"); 
-			return 1;
+	if (slot == -1) { /* No available entry found in either group */
+		if (mftb() & 0x1) {
+			hpte_group=((hash & htab_data.htab_hash_mask)* 
+				    HPTES_PER_GROUP) & ~0x7UL;
+		} else {
+			hpte_group=((~hash & htab_data.htab_hash_mask)* 
+				    HPTES_PER_GROUP) & ~0x7UL;
 		}
-		vsid = get_vsid(mm->context, ea );
-		break;
-	case IO_REGION_ID:
-		mm = &ioremap_mm;
-		vsid = get_kernel_vsid( ea );
-		break;
-	case VMALLOC_REGION_ID:
-		mm = &init_mm;
-		vsid = get_kernel_vsid( ea );
-		break;
-	case IO_UNMAPPED_REGION_ID:
-		udbg_printf("EEH Error ea = 0x%lx\n", ea);
- 		PPCDBG_ENTER_DEBUGGER();
-		panic("EEH Error ea = 0x%lx\n", ea);
-		break;
-	case KERNEL_REGION_ID:
-		/* As htab_initialize is now, we shouldn't ever get here since
-		 * we're bolting the entire 0xC0... region.
-		 */
-		udbg_printf("Little faulted on kernel address 0x%lx\n", ea);
- 		PPCDBG_ENTER_DEBUGGER();
-		panic("Little faulted on kernel address 0x%lx\n", ea);
-		break;
-	default:
-		/* Not a valid range, send the problem up to do_page_fault */
-		return 1;
-		break;
-	}
 
-	/* Search the Linux page table for a match with va */
-        va = ( vsid << 28 ) | ( ea & 0x0fffffff );
-	vpn = va >> PAGE_SHIFT;
-	pgdir = mm->pgd;
-	PPCDBG(PPCDBG_MM, "hash_page ea = 0x%16.16lx, va = 0x%16.16lx\n          current = 0x%16.16lx, access = %lx\n", ea, va, current, access); 
-                if ( pgdir == NULL ) {
-                return 1;
-	}
-	
-	/* Lock the Linux page table to prevent mmap and kswapd
-	 * from modifying entries while we search and update
-	 */
-	
-	spin_lock( &mm->page_table_lock );
-	
-	ptep = find_linux_pte( pgdir, ea );
-	/* If no pte found, send the problem up to do_page_fault */
-	if ( ! ptep ) {
-	  spin_unlock( &mm->page_table_lock );
-	  return 1;
-	}
-	
-	/* Acquire the hash table lock to guarantee that the linux
-	 * pte we fetch will not change
-	 */
-	spin_lock( &hash_table_lock );
-	
-	old_pte = *ptep;
-	
-	/* If the pte is not "present" (valid), send the problem
-	 * up to do_page_fault.
-	 */
-	if ( ! pte_present( old_pte ) ) {
-	  spin_unlock( &hash_table_lock );
-	  spin_unlock( &mm->page_table_lock );
-	  return 1;
-	}
-	
-	/* At this point we have found a pte (which was present).
-	 * The spinlocks prevent this status from changing
-	 * The hash_table_lock prevents the _PAGE_HASHPTE status
-	 * from changing (RPN, DIRTY and ACCESSED too)
-	 * The page_table_lock prevents the pte from being 
-	 * invalidated or modified
-	 */
+		hash = hpt_hash(vpn, 0);
+		iSeries_hpte_remove(hpte_group);
+		goto repeat;
+	} else if (slot < 0) {
+		slot &= 0x7fffffffffffffff;
+		secondary = 1;
+	}
+
+	/* Create the HPTE */
+	lhpte.dw1.dword1      = 0;
+	lhpte.dw1.dw1.rpn     = arpn;
+	lhpte.dw1.flags.flags = hpteflags;
+
+	lhpte.dw0.dword0     = 0;
+	lhpte.dw0.dw0.avpn   = avpn;
+	lhpte.dw0.dw0.h      = secondary;
+	lhpte.dw0.dw0.bolted = bolted;
+	lhpte.dw0.dw0.v      = 1;
 
-/* At this point, we have a pte (old_pte) which can be used to build or update
- * an HPTE.   There are 5 cases:
- *
- * 1. There is a valid (present) pte with no associated HPTE (this is 
- *	the most common case)
- * 2. There is a valid (present) pte with an associated HPTE.  The
- *	current values of the pp bits in the HPTE prevent access because the
- *	user doesn't have appropriate access rights.
- * 3. There is a valid (present) pte with an associated HPTE.  The
- *	current values of the pp bits in the HPTE prevent access because we are
- *	doing software DIRTY bit management and the page is currently not DIRTY. 
- * 4. This is a Kernel address (0xC---) for which there is no page directory.
- *	There is an HPTE for this page, but the pp bits prevent access.
- *      Since we always set up kernel pages with R/W access for the kernel
- *	this case only comes about for users trying to access the kernel.
- *	This case is always an error and is not dealt with further here.
- * 5. This is a Kernel address (0xC---) for which there is no page directory.
- *	There is no HPTE for this page.
+	/* Now fill in the actual HPTE */
+	HvCallHpt_addValidate(slot, secondary, (HPTE *)&lhpte);
+	return ((secondary << 3) | (slot & 0x7));
+}
 
- * Check the user's access rights to the page.  If access should be prevented
- * then send the problem up to do_page_fault.
+/*
+ * Functions used to remove hardware page table entries.
+ *
+ * Input : hpte_group: PTE index of the first entry in a group
+ * Output: offset within the group of the entry removed or
+ *         -1 on failure
  */
-
-	access |= _PAGE_PRESENT;
-	if ( 0 == ( access & ~(pte_val(old_pte)) ) ) {
-		/*
-		 * Check if pte might have an hpte, but we have
-		 * no slot information
-		 */
-		if ( pte_val(old_pte) & _PAGE_HPTENOIX ) {
-			unsigned long slot;	
-			pte_val(old_pte) &= ~_PAGE_HPTEFLAGS;
-			slot = ppc_md.hpte_find( vpn );
-			if ( slot != -1 ) {
-				if ( slot < 0 ) {
-					pte_val(old_pte) |= _PAGE_SECONDARY;
-					slot = -slot;
-				}
-				pte_val(old_pte) |= ((slot << 12) & _PAGE_GROUP_IX) | _PAGE_HASHPTE;
-				
-			}
+static long hpte_remove(unsigned long hpte_group)
+{
+	HPTE *hptep;
+	Hpte_dword0 dw0;
+	int i;
+	int slot_offset;
+	unsigned long vsid, group, pi, pi_high;
+	unsigned long slot;
+	unsigned long flags;
+	int large;
+	unsigned long va;
+
+	/* pick a random slot to start at */
+	slot_offset = mftb() & 0x7;
+
+	for (i = 0; i < HPTES_PER_GROUP; i++) {
+		hptep = htab_data.htab + hpte_group + slot_offset;
+		dw0 = hptep->dw0.dw0;
+
+		if (dw0.v && !dw0.bolted) {
+			/* retry with lock held */
+			dw0 = hptep->dw0.dw0;
+			if (dw0.v && !dw0.bolted)
+				break;
 		}
 
-		/* User has appropriate access rights. */
-		new_pte = old_pte;
-		/* If the attempted access was a store */
-		if ( access & _PAGE_RW )
-			pte_val(new_pte) |= _PAGE_ACCESSED |
-				_PAGE_DIRTY;
-		else
-			pte_val(new_pte) |= _PAGE_ACCESSED;
-
-		/* Only cases 1, 3 and 5 still in play */
-
-		newpp = computeHptePP( pte_val(new_pte) );
-
-		/* Check if pte already has an hpte (case 3) */
-		if ( pte_val(old_pte) & _PAGE_HASHPTE ) {
-			/* There MIGHT be an HPTE for this pte */
-			unsigned long hash, slot, secondary;
-			/* Local copy of first doubleword of HPTE */
-			union {
-				unsigned long d;
-				Hpte_dword0   h;
-			} hpte_dw0;
-			hash = hpt_hash(vpn, 0);
-			secondary = (pte_val(old_pte) & _PAGE_SECONDARY) >> 15;
-			if ( secondary )
-				hash = ~hash;
-			slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP;
-			slot += (pte_val(old_pte) & _PAGE_GROUP_IX) >> 12;
-			/* If there is an HPTE for this page it is indexed by slot */
-			hpte_dw0.d = ppc_md.hpte_getword0( slot );
-			if ( (hpte_dw0.h.avpn == (vpn >> 11) ) &&
-			     (hpte_dw0.h.v) && 
-			     (hpte_dw0.h.h == secondary ) ){
-				/* HPTE matches */
-				ppc_md.hpte_updatepp( slot, newpp, va );
-				if ( !pte_same( old_pte, new_pte ) )
-					*ptep = new_pte;
-			}
-			else {
-				/* HPTE is not for this pte */
-				pte_val(old_pte) &= ~_PAGE_HPTEFLAGS;
-			}
-		}
-		if ( !( pte_val(old_pte) & _PAGE_HASHPTE ) ) {
-			/* Cases 1 and 5 */
-			/* For these cases we need to create a new
-			 * HPTE and update the linux pte (for
-			 * case 1).  For case 5 there is no linux pte.
-			 *
-			 * Find an available HPTE slot
- 			 */
-			slot = ppc_md.hpte_selectslot( vpn );
-
-			/* If hpte_selectslot returns 0x8000000000000000 that means
-			 * that there was already an entry in the HPT even though
-			 * the linux PTE said there couldn't be. 
-			 */
-			/* Debug code */
-			if ( slot == 0x8000000000000000 ) {
-				unsigned long xold_pte = pte_val(old_pte);
-				unsigned long xnew_pte = pte_val(new_pte);
-				
-				udbg_printf("hash_page: ptep    = 0x%016lx\n", (unsigned long)ptep );
-				udbg_printf("hash_page: old_pte = 0x%016lx\n", xold_pte );
-				udbg_printf("hash_page: new_pte = 0x%016lx\n", xnew_pte );
-				udbg_printf("hash_page: ea      = 0x%016lx\n", ea );
-				udbg_printf("hash_page: va      = 0x%016lx\n", va );
-				udbg_printf("hash_page: access  = 0x%016lx\n", access );
-			
-				panic("hash_page: hpte already exists\n");
-			}
-			hash_ind = 0;
-			if ( slot < 0 ) {
-				slot = -slot;
-				hash_ind = 1;
-			}
+		slot_offset++;
+		slot_offset &= 0x7;
+	}
 
-			/* Set the physical address */
-			prpn = pte_val(old_pte) >> PTE_SHIFT;
-			
-			if ( ptep ) {
-				/* Update the linux pte with the HPTE slot */
-				pte_val(new_pte) &= ~_PAGE_HPTEFLAGS;
-				pte_val(new_pte) |= hash_ind << 15;
-				pte_val(new_pte) |= (slot<<12) & _PAGE_GROUP_IX;
-				pte_val(new_pte) |= _PAGE_HASHPTE;
-				/* No need to use ldarx/stdcx here because all
-				 * who might be updating the pte will hold the page_table_lock
-				 * or the hash_table_lock (we hold both)
-				 */
-				*ptep = new_pte;
-			}
+	if (i == HPTES_PER_GROUP)
+		return -1;
 
-			/* copy appropriate flags from linux pte */
-			hpteflags = (pte_val(new_pte) & 0x1f8) | newpp;
+	large = dw0.l;
 
-			/* Create the HPTE */
-			ppc_md.hpte_create_valid( slot, vpn, prpn, hash_ind, ptep, hpteflags, 0 ); 
+	/* Invalidate the hpte. NOTE: this also unlocks it */
+	hptep->dw0.dword0 = 0;
 
-		}
+	/* Invalidate the tlb */
+	vsid = dw0.avpn >> 5;
+	slot = hptep - htab_data.htab;
+	group = slot >> 3;
+	if (dw0.h)
+		group = ~group;
+	pi = (vsid ^ group) & 0x7ff;
+	pi_high = (dw0.avpn & 0x1f) << 11;
+	pi |= pi_high;
 
-		/* Indicate success */
-		rc = 0;
-	}		
-	
-	spin_unlock( &hash_table_lock );
-	if (ptep)
-		spin_unlock( &mm->page_table_lock );
+	if (large)
+		va = pi << LARGE_PAGE_SHIFT;
+	else
+		va = pi << PAGE_SHIFT;
+
+	spin_lock_irqsave(&pSeries_tlbie_lock, flags);
+	_tlbie(va, large);
+	spin_unlock_irqrestore(&pSeries_tlbie_lock, flags);
 
-	return rc;
+	return i;
 }
 
-void flush_hash_page( unsigned long context, unsigned long ea, pte_t *ptep )
+static long rpa_lpar_hpte_remove(unsigned long hpte_group)
 {
-	unsigned long vsid, vpn, va, hash, secondary, slot, flags;
-	/* Local copy of first doubleword of HPTE */
-	union {
-		unsigned long d;
-		Hpte_dword0   h;
-	} hpte_dw0;
-	pte_t pte;
+	unsigned long slot_offset;
+	unsigned long lpar_rc;
+	int i;
+	unsigned long dummy1, dummy2;
 
-	if ( (ea >= USER_START ) && ( ea <= USER_END ) )
-		vsid = get_vsid( context, ea );
-	else
-		vsid = get_kernel_vsid( ea );
-	va = (vsid << 28) | (ea & 0x0fffffff);
-	vpn = va >> PAGE_SHIFT;
-	hash = hpt_hash(vpn, 0);
+	/* pick a random slot to start at */
+	slot_offset = mftb() & 0x7;
 
-	spin_lock_irqsave( &hash_table_lock, flags);
-	pte = __pte(pte_update(ptep, _PAGE_HPTEFLAGS, 0));
-	if ( pte_val(pte) & _PAGE_HASHPTE ) {
-		secondary = (pte_val(pte) & _PAGE_SECONDARY) >> 15;
-		if ( secondary )
-			hash = ~hash;
-		slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP;
-		slot += (pte_val(pte) & _PAGE_GROUP_IX) >> 12;
-		/* If there is an HPTE for this page it is indexed by slot */
+	for (i = 0; i < HPTES_PER_GROUP; i++) {
 
-		hpte_dw0.d = ppc_md.hpte_getword0( slot );
-		if ( (hpte_dw0.h.avpn == (vpn >> 11) ) &&
-		     (hpte_dw0.h.v) && 
-		     (hpte_dw0.h.h == secondary ) ){
-			/* HPTE matches */
-			ppc_md.hpte_invalidate( slot );	
-		}
-		else {
-			unsigned k;
-			/* Temporarily lets check for the hpte in all possible slots */
-			for ( secondary = 0; secondary < 2; ++secondary ) {
-				hash = hpt_hash(vpn, 0);
-				if ( secondary )
-					hash = ~hash;
-				slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP;
-				for ( k=0; k<8; ++k ) {
-					hpte_dw0.d = ppc_md.hpte_getword0( slot+k );
-					if ( ( hpte_dw0.h.avpn == (vpn >> 11) ) &&
-					     ( hpte_dw0.h.v ) &&
-					     ( hpte_dw0.h.h == secondary ) ) {
-						while (1) ;
-					}
-				}
-			}
-		}
+		/* Don't remove a bolted entry */
+		lpar_rc = plpar_pte_remove(H_ANDCOND, hpte_group + slot_offset,
+					   (0x1UL << 4), &dummy1, &dummy2);
+
+		if (lpar_rc == H_Success)
+			return i;
+
+		if (lpar_rc != H_Not_Found)
+			panic("Bad return code from pte remove rc = %lx\n",
+			      lpar_rc);
+
+		slot_offset++;
+		slot_offset &= 0x7;
 	}
-	spin_unlock_irqrestore( &hash_table_lock, flags );
+
+	return -1;
 }
 
-int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
-		   void *buffer, size_t *lenp)
+static long iSeries_hpte_remove(unsigned long hpte_group)
 {
-	int vleft, first=1, len, left, val;
-#define TMPBUFLEN 256
-	char buf[TMPBUFLEN], *p;
-	static const char *sizestrings[4] = {
-		"2MB", "256KB", "512KB", "1MB"
-	};
-	static const char *clockstrings[8] = {
-		"clock disabled", "+1 clock", "+1.5 clock", "reserved(3)",
-		"+2 clock", "+2.5 clock", "+3 clock", "reserved(7)"
-	};
-	static const char *typestrings[4] = {
-		"flow-through burst SRAM", "reserved SRAM",
-		"pipelined burst SRAM", "pipelined late-write SRAM"
-	};
-	static const char *holdstrings[4] = {
-		"0.5", "1.0", "(reserved2)", "(reserved3)"
-	};
-
-	if ( ((_get_PVR() >> 16) != 8) && ((_get_PVR() >> 16) != 12))
-		return -EFAULT;
-	
-	if ( /*!table->maxlen ||*/ (filp->f_pos && !write)) {
-		*lenp = 0;
-		return 0;
-	}
-	
-	vleft = table->maxlen / sizeof(int);
-	left = *lenp;
-	
-	for (; left /*&& vleft--*/; first=0) {
-		if (write) {
-			while (left) {
-				char c;
-				if(get_user(c,(char *) buffer))
-					return -EFAULT;
-				if (!isspace(c))
-					break;
-				left--;
-				((char *) buffer)++;
-			}
-			if (!left)
-				break;
-			len = left;
-			if (len > TMPBUFLEN-1)
-				len = TMPBUFLEN-1;
-			if(copy_from_user(buf, buffer, len))
-				return -EFAULT;
-			buf[len] = 0;
-			p = buf;
-			if (*p < '0' || *p > '9')
-				break;
-			val = simple_strtoul(p, &p, 0);
-			len = p-buf;
-			if ((len < left) && *p && !isspace(*p))
-				break;
-			buffer += len;
-			left -= len;
-#if 0
-			/* DRENG need a def */
-			_set_L2CR(0);
-			_set_L2CR(val);
-			while ( _get_L2CR() & 0x1 )
-				/* wait for invalidate to finish */;
-#endif
-			  
-		} else {
-			p = buf;
-			if (!first)
-				*p++ = '\t';
-#if 0
-			/* DRENG need a def */
-			val = _get_L2CR();
-#endif
-			p += sprintf(p, "0x%08x: ", val);
-			p += sprintf(p, " %s", (val >> 31) & 1 ? "enabled" :
-				     "disabled");
-			p += sprintf(p, ", %sparity", (val>>30)&1 ? "" : "no ");
-			p += sprintf(p, ", %s", sizestrings[(val >> 28) & 3]);
-			p += sprintf(p, ", %s", clockstrings[(val >> 25) & 7]);
-			p += sprintf(p, ", %s", typestrings[(val >> 23) & 2]);
-			p += sprintf(p, "%s", (val>>22)&1 ? ", data only" : "");
-			p += sprintf(p, "%s", (val>>20)&1 ? ", ZZ enabled": "");
-			p += sprintf(p, ", %s", (val>>19)&1 ? "write-through" :
-				     "copy-back");
-			p += sprintf(p, "%s", (val>>18)&1 ? ", testing" : "");
-			p += sprintf(p, ", %sns hold",holdstrings[(val>>16)&3]);
-			p += sprintf(p, "%s", (val>>15)&1 ? ", DLL slow" : "");
-			p += sprintf(p, "%s", (val>>14)&1 ? ", diff clock" :"");
-			p += sprintf(p, "%s", (val>>13)&1 ? ", DLL bypass" :"");
-			
-			p += sprintf(p,"\n");
-			
-			len = strlen(buf);
-			if (len > left)
-				len = left;
-			if(copy_to_user(buffer, buf, len))
-				return -EFAULT;
-			left -= len;
-			buffer += len;
-			break;
+	unsigned long slot_offset;
+	int i;
+	HPTE lhpte;
+
+	/* Pick a random slot to start at */
+	slot_offset = mftb() & 0x7;
+
+	for (i = 0; i < HPTES_PER_GROUP; i++) {
+		lhpte.dw0.dword0 = 
+			iSeries_hpte_getword0(hpte_group + slot_offset);
+
+		if (!lhpte.dw0.dw0.bolted) {
+			HvCallHpt_invalidateSetSwBitsGet(hpte_group + 
+							 slot_offset, 0, 0);
+			return i;
 		}
-	}
 
-	if (!write && !first && left) {
-		if(put_user('\n', (char *) buffer))
-			return -EFAULT;
-		left--, buffer++;
-	}
-	if (write) {
-		p = (char *) buffer;
-		while (left) {
-			char c;
-			if(get_user(c, p++))
-				return -EFAULT;
-			if (!isspace(c))
-				break;
-			left--;
-		}
+		slot_offset++;
+		slot_offset &= 0x7;
 	}
-	if (write && first)
-		return -EINVAL;
-	*lenp -= left;
-	filp->f_pos += *lenp;
-	return 0;
+
+	return -1;
+}
+
+void hpte_init_pSeries(void)
+{
+	ppc_md.hpte_invalidate     = hpte_invalidate;
+	ppc_md.hpte_updatepp       = hpte_updatepp;
+	ppc_md.hpte_updateboltedpp = hpte_updateboltedpp;
+	ppc_md.hpte_insert	   = hpte_insert;
+	ppc_md.hpte_remove	   = hpte_remove;
+}
+
+void pSeries_lpar_mm_init(void)
+{
+	ppc_md.hpte_invalidate     = rpa_lpar_hpte_invalidate;
+	ppc_md.hpte_updatepp       = rpa_lpar_hpte_updatepp;
+	ppc_md.hpte_updateboltedpp = rpa_lpar_hpte_updateboltedpp;
+	ppc_md.hpte_insert         = rpa_lpar_hpte_insert;
+	ppc_md.hpte_remove         = rpa_lpar_hpte_remove;
+}
+
+void hpte_init_iSeries(void)
+{
+	ppc_md.hpte_invalidate     = iSeries_hpte_invalidate;
+	ppc_md.hpte_updatepp       = iSeries_hpte_updatepp;
+	ppc_md.hpte_updateboltedpp = iSeries_hpte_updateboltedpp;
+	ppc_md.hpte_insert         = iSeries_hpte_insert;
+	ppc_md.hpte_remove         = iSeries_hpte_remove;
 }
 
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/iSeries_IoMmTable.c linux-2.4.20-pre5/arch/ppc64/kernel/iSeries_IoMmTable.c
--- linux-2.4.20-pre4/arch/ppc64/kernel/iSeries_IoMmTable.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/iSeries_IoMmTable.c	Wed Aug 28 16:37:30 2002
@@ -130,7 +130,7 @@
 /*   The HvCallPci_getBarParms is used to get the size of the BAR  */
 /*   space.  It calls iSeries_IoMmTable_AllocateEntry to allocate  */
 /*   each entry.                                                   */
-/* - Loops through The Bar resourses(0 - 5) including the the ROM  */
+/* - Loops through The Bar resourses(0 - 5) including the ROM      */
 /*   is resource(6).                                               */
 /*******************************************************************/
 void iSeries_allocateDeviceBars(struct pci_dev* PciDev)
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/iSeries_pci.c linux-2.4.20-pre5/arch/ppc64/kernel/iSeries_pci.c
--- linux-2.4.20-pre4/arch/ppc64/kernel/iSeries_pci.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/iSeries_pci.c	Wed Aug 28 16:37:30 2002
@@ -4,7 +4,7 @@
  * Copyright (C) 2001 Allan Trautman, IBM Corporation
  *
  * iSeries specific routines for PCI.
- * 
+ * /
  * Based on code from pci.c and iSeries_pci.c 32bit
  *
  * This program is free software; you can redistribute it and/or modify
@@ -28,6 +28,8 @@
 #include <linux/init.h>
 #include <linux/ide.h>
 #include <linux/pci.h>
+#include <linux/rtc.h>
+#include <linux/time.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -37,6 +39,8 @@
 #include <asm/ppcdebug.h>
 #include <asm/naca.h>
 #include <asm/flight_recorder.h>
+#include <asm/hardirq.h>
+#include <asm/time.h>
 #include <asm/pci_dma.h>
 
 #include <asm/iSeries/HvCallPci.h>
@@ -76,9 +80,6 @@
 extern int    Pci_Error_Flag;
 extern int    Pci_Trace_Flag;
 
-extern void iSeries_MmIoTest(void);
-
-
 /*******************************************************************
  * Forward declares of prototypes. 
  *******************************************************************/
@@ -379,7 +380,10 @@
 			if(DevInfo->deviceType == HvCallPci_NodeDevice) {
 				iSeries_Scan_EADs_Bridge(Bus, SubBus, IdSel);
 			}
-			else printk("PCI: Invalid System Configuration(0x%02X.\n",DevInfo->deviceType);
+			else {
+				printk("PCI: Invalid System Configuration(0x%02X).\n",DevInfo->deviceType);
+				PCIFR(      "Invalid System Configuration(0x%02X).",  DevInfo->deviceType);
+			}
 		}
 		else pci_Log_Error("getDeviceInfo",Bus, SubBus, IdSel,HvRc);
 	}
@@ -511,7 +515,7 @@
 /* I/0 Memory copy MUST use mmio commands on iSeries                    */
 /* To do; For performance, include the hv call directly                 */
 /************************************************************************/
-void* iSeries_memset(void* dest, char c, size_t Count)
+void* iSeries_memset_io(void* dest, char c, size_t Count)
 {
 	u8    ByteValue     = c;
 	long  NumberOfBytes = Count;
@@ -580,6 +584,18 @@
 	}
 	return Node;
 }
+/******************************************************************/
+/* Set and reset Device Node Lock                                 */
+/******************************************************************/
+#define setIoLock() \
+    unsigned long IrqFlags; \
+    spin_lock_irqsave(&DevNode->IoLock, IrqFlags ); 
+
+#define resetIoLock() \
+    int RtnCode = DevNode->ReturnCode; \
+    spin_unlock_irqrestore( &DevNode->IoLock, IrqFlags ); \
+    return RtnCode;
+
 /**********************************************************************************
  *
  * Read PCI Config Space Code 
@@ -588,8 +604,8 @@
 /** BYTE  *************************************************************************/
 int iSeries_Node_read_config_byte(struct iSeries_Device_Node* DevNode, int Offset, u8* ReadValue)
 {
-	u8  ReadData; 
-	if(DevNode == NULL) { return 0x301; } 
+	u8  ReadData;
+	setIoLock();
 	++Pci_Cfg_Read_Count;
 	DevNode->ReturnCode = HvCallPci_configLoad8(ISERIES_BUS(DevNode),ISERIES_SUBBUS(DevNode),0x10,
 	                                                Offset,&ReadData);
@@ -600,14 +616,14 @@
 		printk("PCI: RCB: 0x%04X.%02X  Error: 0x%04X\n",ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode);
 		PCIFR(      "RCB: 0x%04X.%02X  Error: 0x%04X",  ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode);
 	}
-	*ReadValue = ReadData; 
- 	return DevNode->ReturnCode;
+	*ReadValue = ReadData;
+	resetIoLock();
 }
 /** WORD  *************************************************************************/
 int iSeries_Node_read_config_word(struct iSeries_Device_Node* DevNode, int Offset, u16* ReadValue)
 {
 	u16  ReadData; 
-	if(DevNode == NULL) { return 0x301; } 
+	setIoLock();
 	++Pci_Cfg_Read_Count;
 	DevNode->ReturnCode = HvCallPci_configLoad16(ISERIES_BUS(DevNode),ISERIES_SUBBUS(DevNode),0x10,
 	                                                Offset,&ReadData);
@@ -619,14 +635,14 @@
 		PCIFR(      "RCW: 0x%04X.%02X  Error: 0x%04X",  ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode);
 
 	}
-	*ReadValue = ReadData; 
- 	return DevNode->ReturnCode;
+	*ReadValue = ReadData;
+	resetIoLock();
 }
 /** DWORD *************************************************************************/
 int iSeries_Node_read_config_dword(struct iSeries_Device_Node* DevNode, int Offset, u32* ReadValue)
 {
  	u32  ReadData; 
-	if(DevNode == NULL) { return 0x301; } 
+	setIoLock();
 	++Pci_Cfg_Read_Count;
 	DevNode->ReturnCode = HvCallPci_configLoad32(ISERIES_BUS(DevNode),ISERIES_SUBBUS(DevNode),0x10,
 	                                                Offset,&ReadData);
@@ -637,8 +653,8 @@
 		printk("PCI: RCL: 0x%04X.%02X  Error: 0x%04X\n",ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode);
 		PCIFR(      "RCL: 0x%04X.%02X  Error: 0x%04X",  ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode);
 	}
-	*ReadValue = ReadData; 
- 	return DevNode->ReturnCode;
+	*ReadValue = ReadData;
+	resetIoLock();
 }
 int iSeries_pci_read_config_byte(struct pci_dev* PciDev, int Offset, u8* ReadValue) { 
 	struct iSeries_Device_Node* DevNode = get_Device_Node(PciDev);
@@ -662,6 +678,7 @@
 /** BYTE  *************************************************************************/
 int iSeries_Node_write_config_byte(struct iSeries_Device_Node* DevNode, int Offset, u8 WriteData)
 {
+	setIoLock();
 	++Pci_Cfg_Write_Count;
 	DevNode->ReturnCode = HvCallPci_configStore8(ISERIES_BUS(DevNode),ISERIES_SUBBUS(DevNode),0x10,
 	                                                  Offset,WriteData);
@@ -672,11 +689,12 @@
 		printk("PCI: WCB: 0x%04X.%02X  Error: 0x%04X\n",ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode);
 		PCIFR(      "WCB: 0x%04X.%02X  Error: 0x%04X",  ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode);
 	}
- 	return DevNode->ReturnCode;
+	resetIoLock();
 }
 /** WORD  *************************************************************************/
 int iSeries_Node_write_config_word(struct iSeries_Device_Node* DevNode, int Offset, u16 WriteData)
 {
+	setIoLock();
 	++Pci_Cfg_Write_Count;
 	DevNode->ReturnCode = HvCallPci_configStore16(ISERIES_BUS(DevNode),ISERIES_SUBBUS(DevNode),0x10,
 	                                                  Offset,WriteData);
@@ -687,11 +705,12 @@
 		printk("PCI: WCW: 0x%04X.%02X  Error: 0x%04X\n",ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode);
 		PCIFR(      "WCW: 0x%04X.%02X  Error: 0x%04X",  ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode);
 	}
- 	return DevNode->ReturnCode;
+	resetIoLock();
 }
 /** DWORD *************************************************************************/
 int iSeries_Node_write_config_dword(struct iSeries_Device_Node* DevNode, int Offset, u32 WriteData)
 {
+	setIoLock();
 	++Pci_Cfg_Write_Count;
 	DevNode->ReturnCode = HvCallPci_configStore32(ISERIES_BUS(DevNode),ISERIES_SUBBUS(DevNode),0x10,
 	                                                  Offset,WriteData);
@@ -702,7 +721,7 @@
 		printk("PCI: WCL: 0x%04X.%02X  Error: 0x%04X\n",ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode);
 		PCIFR(      "WCL: 0x%04X.%02X  Error: 0x%04X",  ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode);
 	}
-	return DevNode->ReturnCode;
+	resetIoLock();
 }
 int iSeries_pci_write_config_byte( struct pci_dev* PciDev,int Offset, u8 WriteValue)
 {
@@ -736,69 +755,93 @@
 };
 
 /************************************************************************
- * Check Return Code
+ * Log Pci Error and check Retry Count 
  * -> On Failure, print and log information.
  *    Increment Retry Count, if exceeds max, panic partition.
- * -> If in retry, print and log success 
- ************************************************************************
- * PCI: Device 23.90 ReadL I/O Error( 0): 0x1234
- * PCI: Device 23.90 ReadL Retry( 1)
- * PCI: Device 23.90 ReadL Retry Successful(1)
+ * -> If in retry, print and log success
  ************************************************************************/
-int  CheckReturnCode(char* TextHdr, struct iSeries_Device_Node* DevNode, u64 RtnCode)
+void logPciError(char* ErrorTxt, void* IoAddress, struct iSeries_Device_Node* DevNode, u64 RtnCode)
 {
-	if(RtnCode != 0)  {
-		++Pci_Error_Count;
-		++DevNode->IoRetry;
-		PCIFR(      "%s: Device 0x%04X:%02X  I/O Error(%2d): 0x%04X",
-			    TextHdr,ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->IoRetry,(int)RtnCode);
-		printk("PCI: %s: Device 0x%04X:%02X  I/O Error(%2d): 0x%04X\n",
-		            TextHdr,ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->IoRetry,(int)RtnCode);
-		/*******************************************************/
-		/* Bump the retry and check for retry count exceeded.  */
-		/* If, Exceeded, panic the system.                     */           
-		/*******************************************************/
-		if(DevNode->IoRetry > Pci_Retry_Max && Pci_Error_Flag > 0 ) {
-			mf_displaySrc(0xB6000103);
-			panic_timeout = 0; 
-			panic("PCI: Hardware I/O Error, SRC B6000103, Automatic Reboot Disabled.\n");
-		}
-		return -1;	/* Retry Try */
-	}
-	/********************************************************************
-	* If retry was in progress, log success and rest retry count        *
-	*********************************************************************/
-	else if(DevNode->IoRetry > 0) {
-		PCIFR("%s: Device 0x%04X:%02X Retry Successful(%2d).",
-		      TextHdr,ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->IoRetry);
-		DevNode->IoRetry = 0;
-		return 0; 
+	++DevNode->IoRetry;
+	++Pci_Error_Count;
+
+	PCIFR("%s: I/O Error(%1d/%1d):0x%04X  IoAddress:0x%p  Device:0x%04X:%02X",  
+	      ErrorTxt, DevNode->IoRetry, in_interrupt(), RtnCode, IoAddress, ISERIES_BUS(DevNode),DevNode->AgentId);
+	/*******************************************************/
+	/* Filter out EADs freeze and alignment errors         */
+	/*******************************************************/
+	if(RtnCode == 0x0102) {
+		PCIFR("EADS Freeze error.......Panic........");
+		mf_displaySrc(0xB6000103);
+		panic_timeout = 0; 
+		panic("PCI: EADs Freeze error SRC B6000103\n");
+	}
+	else if(RtnCode == 0x0241) {
+		PCIFR("MMIO Alignment error: 0x%p",IoAddress);
+		mf_displaySrc(0xB6000103);
+		panic_timeout = 0; 
+		panic("PCI: MMIO Alignment error. SRC B6000103\n");
+	}
+	/*******************************************************/
+	/* Bump the retry and check for retry count exceeded.  */
+	/* If, Exceeded, panic the system.                     */           
+	/*******************************************************/
+	if(DevNode->IoRetry > Pci_Retry_Max && Pci_Error_Flag != 0 ) {
+		mf_displaySrc(0xB6000103);
+		panic_timeout = 0; 
+		panic("PCI: Hardware I/O Error, SRC B6000103, Automatic Reboot Disabled.\n");
+	}
+	/**************************************************************/
+	/* Wait x ms before retrying I/O to give I/O time to recover. */
+	/* Retry wait delay logic.                                    */
+	/* - On first retry, no delay, maybe just glitch.             */
+	/* - On successify retries, vary the delay to avoid being in a*/
+        /*   repetitive timing window.                                */ 
+	/**************************************************************/
+	if(DevNode->IoRetry > 0) {
+		udelay(DevNode->IoRetry * 50);
 	}
-	return 0; 
 }
+
+/************************************************************************
+ * Retry was successful
+ ************************************************************************/
+void  pciRetrySuccessful(struct iSeries_Device_Node* DevNode)
+{
+	struct  timeval  TimeClock;
+	struct  rtc_time CurTime;
+	do_gettimeofday(&TimeClock);
+	to_tm(TimeClock.tv_sec, &CurTime);
+
+	PCIFR("Retry Successful(%2d) on Device 0x%04X:%02X at %02d.%02d.%02d",
+	      DevNode->IoRetry,ISERIES_BUS(DevNode),DevNode->AgentId,
+	      CurTime.tm_hour,CurTime.tm_min,CurTime.tm_sec);
+
+	DevNode->IoRetry = 0;
+}
+
 /************************************************************************/
 /* Translate the I/O Address into a device node, bar, and bar offset.   */
 /* Note: Make sure the passed variable end up on the stack to avoid     */
 /* the exposure of being device global.                                 */
+/* The Device Node is Lock to block other I/O to device.                */
 /************************************************************************/
-static inline struct iSeries_Device_Node* xlateIoMmAddress(void* IoAddress,
-							    union HvDsaMap* DsaPtr,
-							   u64* BarOffsetPtr) {
-
-	unsigned long BaseIoAddr = (unsigned long)IoAddress-iSeries_Base_Io_Memory;
-	long          TableIndex = BaseIoAddr/iSeries_IoMmTable_Entry_Size;
-	struct iSeries_Device_Node* DevNode = *(iSeries_IoMmTable +TableIndex);
-	if(DevNode != NULL) {
-		DsaPtr->DsaAddr       = ISERIES_DSA(DevNode);
-		DsaPtr->Dsa.barNumber = *(iSeries_IoBarTable+TableIndex);
-		*BarOffsetPtr         = BaseIoAddr % iSeries_IoMmTable_Entry_Size;
-	}
-	else {
-		panic("PCI: Invalid PCI IoAddress detected!\n");
-	}
-	return DevNode;
-}
-
+#define setUpMmIo(IoAddress,Type) \
+unsigned long   IrqFlags; \
+struct HvCallPci_LoadReturn Return; \
+union HvDsaMap  DsaData;  \
+u64             BarOffset;\
+unsigned long BaseIoAddr = (unsigned long)IoAddress-iSeries_Base_Io_Memory; \
+long          TableIndex = (BaseIoAddr/iSeries_IoMmTable_Entry_Size);       \
+struct iSeries_Device_Node* DevNode = *(iSeries_IoMmTable+TableIndex);      \
+if(DevNode != NULL) { \
+    DsaData.DsaAddr       = ISERIES_DSA(DevNode); \
+    DsaData.Dsa.barNumber = *(iSeries_IoBarTable+TableIndex); \
+    BarOffset             = BaseIoAddr % iSeries_IoMmTable_Entry_Size; \
+    ++Pci_Io_##Type##_Count; \
+    spin_lock_irqsave(&DevNode->IoLock, IrqFlags ); \
+} \
+else panic("PCI: Invalid PCI IoAddress detected 0x%p!\n",IoAddress);
 /************************************************************************/
 /* Read MM I/O Instructions for the iSeries                             */
 /* On MM I/O error, all ones are returned and iSeries_pci_IoError is cal*/
@@ -810,47 +853,53 @@
 /************************************************************************/
 u8  iSeries_Read_Byte(void* IoAddress)
 {
-	u64    BarOffset;
-	union  HvDsaMap DsaData;
-	struct HvCallPci_LoadReturn Return;
-	struct iSeries_Device_Node* DevNode = xlateIoMmAddress(IoAddress,&DsaData,&BarOffset);
-
+	setUpMmIo(IoAddress,Read);
 	do {
-		++Pci_Io_Read_Count;
 		HvCall3Ret16(HvCallPciBarLoad8, &Return, DsaData.DsaAddr,BarOffset, 0);
-	} while (CheckReturnCode("RDB",DevNode, Return.rc) != 0);
-
-	if(Pci_Trace_Flag == 1)	PCIFR("RDB: IoAddress 0x%p = 0x%02X",IoAddress, (u8)Return.value); 
+		if(Return.rc != 0 ) {
+			logPciError("RDB",IoAddress, DevNode, Return.rc);
+		}
+		else if ( DevNode->IoRetry > 0) {
+			pciRetrySuccessful(DevNode);
+		}
+	} while (Return.rc != 0);
+	spin_unlock_irqrestore(&DevNode->IoLock, IrqFlags ); 
+	if(Pci_Trace_Flag == 1 ) PCIFR("RDB: IoAddress 0x%p = 0x%02X",IoAddress, (u8)Return.value);
 	return (u8)Return.value;
 }
+int Retry_Test = 0;
 u16  iSeries_Read_Word(void* IoAddress)
 {
-	u64    BarOffset;
-	union  HvDsaMap DsaData;
-	struct HvCallPci_LoadReturn Return;
-	struct iSeries_Device_Node* DevNode = xlateIoMmAddress(IoAddress,&DsaData,&BarOffset);
-
+	setUpMmIo(IoAddress,Read);
 	do {
-		++Pci_Io_Read_Count;
 		HvCall3Ret16(HvCallPciBarLoad16,&Return, DsaData.DsaAddr,BarOffset, 0);
-	} while (CheckReturnCode("RDW",DevNode, Return.rc) != 0);
 
-	if(Pci_Trace_Flag == 1) PCIFR("RDW: IoAddress 0x%p = 0x%04X",IoAddress, swab16((u16)Return.value));
+		if(Return.rc != 0 ) {
+			logPciError("RDW",IoAddress, DevNode, Return.rc);
+		}
+		else if ( DevNode->IoRetry > 0) {
+			pciRetrySuccessful(DevNode);
+		}
+	} while (Return.rc != 0);
+	spin_unlock_irqrestore(&DevNode->IoLock, IrqFlags ); 
+	if(Pci_Trace_Flag == 1 ) PCIFR("RDW: IoAddress 0x%p = 0x%04X",IoAddress, (u16)Return.value);
 	return swab16((u16)Return.value);
 }
 u32  iSeries_Read_Long(void* IoAddress)
 {
-	u64    BarOffset;
-	union  HvDsaMap DsaData;
-	struct HvCallPci_LoadReturn Return;
-	struct iSeries_Device_Node* DevNode = xlateIoMmAddress(IoAddress,&DsaData,&BarOffset);
-
+	setUpMmIo(IoAddress,Read);
 	do {
-		++Pci_Io_Read_Count;
 		HvCall3Ret16(HvCallPciBarLoad32,&Return, DsaData.DsaAddr,BarOffset, 0);
-	} while (CheckReturnCode("RDL",DevNode, Return.rc) != 0);
 
-	if(Pci_Trace_Flag == 1) PCIFR("RDL: IoAddress 0x%p = 0x%04X",IoAddress, swab32((u32)Return.value));
+		if(Return.rc != 0 ) {
+			logPciError("RDL",IoAddress, DevNode, Return.rc);
+		}
+		else if ( DevNode->IoRetry > 0) {
+			pciRetrySuccessful(DevNode);
+		}
+	} while (Return.rc != 0);
+	spin_unlock_irqrestore(&DevNode->IoLock, IrqFlags ); 
+	if(Pci_Trace_Flag == 1 ) PCIFR("RDL: IoAddress 0x%p = 0x%08X",IoAddress, swab32((u32)Return.value));
 	return swab32((u32)Return.value);
 }
 /************************************************************************/
@@ -862,41 +911,47 @@
 /************************************************************************/
 void iSeries_Write_Byte(u8 Data, void* IoAddress)
 {
-	u64    BarOffset;
-	union  HvDsaMap DsaData;
-	struct HvCallPci_LoadReturn Return;
-	struct iSeries_Device_Node* DevNode = xlateIoMmAddress(IoAddress,&DsaData,&BarOffset);
-
+	setUpMmIo(IoAddress,Write);
 	do {
-		++Pci_Io_Write_Count;
 		Return.rc = HvCall4(HvCallPciBarStore8, DsaData.DsaAddr,BarOffset, Data, 0);
-	} while (CheckReturnCode("WWB",DevNode, Return.rc) != 0);
+		if(Return.rc != 0 ) {
+			logPciError("WWB",IoAddress, DevNode, Return.rc);
+		}
+		else if ( DevNode->IoRetry > 0) {
+			pciRetrySuccessful(DevNode);
+		}
+	} while (Return.rc != 0);
+	spin_unlock_irqrestore(&DevNode->IoLock, IrqFlags ); 
 	if(Pci_Trace_Flag == 1) PCIFR("WWB: IoAddress 0x%p = 0x%02X",IoAddress,Data);
 }
 void iSeries_Write_Word(u16 Data, void* IoAddress)
 {
-	u64    BarOffset;
-	union  HvDsaMap DsaData;
-	struct HvCallPci_LoadReturn Return;
-	struct iSeries_Device_Node* DevNode = xlateIoMmAddress(IoAddress,&DsaData,&BarOffset);
-
+	setUpMmIo(IoAddress,Write);
 	do {
-		++Pci_Io_Write_Count;
 		Return.rc = HvCall4(HvCallPciBarStore16,DsaData.DsaAddr,BarOffset, swab16(Data), 0);
-	} while (CheckReturnCode("WWW",DevNode, Return.rc) != 0);
+		if(Return.rc != 0 ) {
+			logPciError("WWW",IoAddress, DevNode, Return.rc);
+		}
+		else if ( DevNode->IoRetry > 0) {
+			pciRetrySuccessful(DevNode);
+		}
+	} while (Return.rc != 0);
+	spin_unlock_irqrestore(&DevNode->IoLock, IrqFlags ); 
 	if(Pci_Trace_Flag == 1) PCIFR("WWW: IoAddress 0x%p = 0x%04X",IoAddress,Data);
 }
 void iSeries_Write_Long(u32 Data, void* IoAddress)
 {
-	u64    BarOffset;
-	union  HvDsaMap DsaData;
-	struct HvCallPci_LoadReturn Return;
-	struct iSeries_Device_Node* DevNode = xlateIoMmAddress(IoAddress,&DsaData,&BarOffset);
-
+	setUpMmIo(IoAddress,Write);
 	do {
-		++Pci_Io_Write_Count;
 		Return.rc = HvCall4(HvCallPciBarStore32,DsaData.DsaAddr,BarOffset, swab32(Data), 0);
-	} while (CheckReturnCode("WWL",DevNode, Return.rc) != 0);
+		if(Return.rc != 0 ) {
+			logPciError("WWL",IoAddress, DevNode, Return.rc);
+		}
+		else if ( DevNode->IoRetry > 0) {
+			pciRetrySuccessful(DevNode);
+		}
+	} while (Return.rc != 0);
+	spin_unlock_irqrestore(&DevNode->IoLock, IrqFlags ); 
 	if(Pci_Trace_Flag == 1) PCIFR("WWL: IoAddress 0x%p = 0x%08X",IoAddress, Data);
 }
 /*
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/iSeries_pci_reset.c linux-2.4.20-pre5/arch/ppc64/kernel/iSeries_pci_reset.c
--- linux-2.4.20-pre4/arch/ppc64/kernel/iSeries_pci_reset.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/iSeries_pci_reset.c	Wed Aug 28 16:37:30 2002
@@ -78,7 +78,7 @@
 		schedule_timeout(WaitDelay);
 	}
 	if (DeviceNode->ReturnCode == 0) {
-		PCIFR("Slot 0x%04X.%02 Reset\n",ISERIES_BUS(DeviceNode),DeviceNode->AgentId );
+		PCIFR("Slot 0x%04X.%02X Reset\n",ISERIES_BUS(DeviceNode),DeviceNode->AgentId );
 	} 
 	else {
 		printk("PCI: Slot 0x%04X.%02X Reset Failed, RCode: %04X\n",ISERIES_BUS(DeviceNode),DeviceNode->AgentId,DeviceNode->ReturnCode);
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/iSeries_setup.c linux-2.4.20-pre5/arch/ppc64/kernel/iSeries_setup.c
--- linux-2.4.20-pre4/arch/ppc64/kernel/iSeries_setup.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/iSeries_setup.c	Wed Aug 28 16:37:30 2002
@@ -49,6 +49,7 @@
 #include <asm/iSeries/IoHriMainStore.h>
 #include <asm/iSeries/iSeries_proc.h>
 #include <asm/proc_pmc.h>
+#include <asm/perfmon.h>
 #include <asm/iSeries/mf.h>
 
 /* Function Prototypes */
@@ -59,13 +60,10 @@
 static void setup_iSeries_cache_sizes( void );
 static void iSeries_bolt_kernel(unsigned long saddr, unsigned long eaddr);
 #endif
-void build_valid_hpte( unsigned long vsid, unsigned long ea, unsigned long pa,
-		       pte_t * ptep, unsigned hpteflags, unsigned bolted );
 extern void ppcdbg_initialize(void);
 extern void iSeries_pcibios_init(void);
 extern void iSeries_pcibios_fixup(void);
 extern void iSeries_pcibios_fixup_bus(int);
-static void iSeries_setup_dprofile(void);
 
 /* Global Variables */
 
@@ -77,10 +75,6 @@
 static unsigned long tbFreqMhz = 0;
 static unsigned long tbFreqMhzHundreths = 0;
 
-unsigned long dprof_shift = 0;
-unsigned long dprof_len = 0;
-unsigned int * dprof_buffer = NULL;
-
 int piranha_simulator = 0;
 
 extern char _end[];
@@ -257,7 +251,7 @@
 {
 	unsigned long i;
 	unsigned long mem_blocks = 0;
-	if ( __is_processor( PV_POWER4 ) )
+	if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p))
 		mem_blocks = iSeries_process_Regatta_mainstore_vpd( mb_array, max_entries );
 	else
 		mem_blocks = iSeries_process_Condor_mainstore_vpd( mb_array, max_entries );
@@ -283,8 +277,6 @@
 iSeries_init_early(void)
 {
 #ifdef CONFIG_PPC_ISERIES
-	ppcdbg_initialize();
-	
 #if defined(CONFIG_BLK_DEV_INITRD)
 	/*
 	 * If the init RAM disk has been configured and there is
@@ -397,28 +389,6 @@
 			*(p+1) = 0;
 	}
 
-        if (strstr(cmd_line, "dprofile=")) {
-                char *p, *q;
-
-                for (q = cmd_line; (p = strstr(q, "dprofile=")) != 0; ) {
-			unsigned long size, new_klimit;
-                        q = p + 9;
-                        if (p > cmd_line && p[-1] != ' ')
-                                continue;
-                        dprof_shift = simple_strtoul(q, &q, 0);
-			dprof_len = (unsigned long)&_etext - (unsigned long)&_stext;
-			dprof_len >>= dprof_shift;
-			size = ((dprof_len * sizeof(unsigned int)) + (PAGE_SIZE-1)) & PAGE_MASK;
-			dprof_buffer = (unsigned int *)((klimit + (PAGE_SIZE-1)) & PAGE_MASK);
-			new_klimit = ((unsigned long)dprof_buffer) + size;
-			lmb_reserve( __pa(klimit), (new_klimit-klimit));
-			klimit = new_klimit;
-			memset( dprof_buffer, 0, size );
-                }
-        }
-
-	iSeries_setup_dprofile();
-
 	iSeries_proc_early_init();	
 	mf_init();
 	mf_initialized = 1;
@@ -631,7 +601,6 @@
 /*
  * Bolt the kernel addr space into the HPT
  */
-
 static void __init iSeries_bolt_kernel(unsigned long saddr, unsigned long eaddr)
 {
 	unsigned long pa;
@@ -644,12 +613,13 @@
 		unsigned long va = ( vsid << 28 ) | ( pa & 0xfffffff );
 		unsigned long vpn = va >> PAGE_SHIFT;
 		unsigned long slot = HvCallHpt_findValid( &hpte, vpn );
-		if ( hpte.dw0.dw0.v ) {
+		if (hpte.dw0.dw0.v) {
 			/* HPTE exists, so just bolt it */
-			HvCallHpt_setSwBits( slot, 0x10, 0 );
+			HvCallHpt_setSwBits(slot, 0x10, 0);
 		} else {
 			/* No HPTE exists, so create a new bolted one */
-			build_valid_hpte(vsid, ea, pa, NULL, mode_rw, 1);
+			make_pte(NULL, va, (unsigned long)__v2a(ea), 
+				 mode_rw, 0, 0);
 		}
 	}
 }
@@ -852,7 +822,6 @@
 	 */
 	tb_ticks_per_sec   = tb_ticks_per_jiffy * HZ;
 	tb_ticks_per_usec = cyclesPerUsec;
-	tb_to_us = mulhwu_scale_factor(ppc_tb_freq, 1000000);
 	div128_by_32( 1024*1024, 0, tb_ticks_per_sec, &divres );
 	tb_to_xs = divres.result_low;
 	setup_default_decr();
@@ -884,17 +853,3 @@
 	}
 }
 
-static void iSeries_setup_dprofile(void)
-{
-	if ( dprof_buffer ) {
-		unsigned i;
-		for (i=0; i<MAX_PACAS; ++i) {
-			paca[i].prof_shift = dprof_shift;
-			paca[i].prof_len = dprof_len-1;
-			paca[i].prof_buffer = dprof_buffer;
-			paca[i].prof_stext = (unsigned *)&_stext;
-			mb();
-			paca[i].prof_enabled = 1;
-		}
-	}
-}
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/ioctl32.c linux-2.4.20-pre5/arch/ppc64/kernel/ioctl32.c
--- linux-2.4.20-pre4/arch/ppc64/kernel/ioctl32.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/ioctl32.c	Wed Aug 28 16:37:31 2002
@@ -44,6 +44,7 @@
 #include <linux/ppp_defs.h>
 #include <linux/if_ppp.h>
 #include <linux/if_pppox.h>
+#include <linux/if_tun.h>
 #include <linux/mtio.h>
 #include <linux/cdrom.h>
 #include <linux/loop.h>
@@ -102,6 +103,7 @@
 #include <linux/usb.h>
 #include <linux/usbdevice_fs.h>
 #include <linux/nbd.h>
+#include <linux/random.h>
 #include <asm/ppc32.h>
 #include <asm/ppcdebug.h>
 
@@ -469,6 +471,7 @@
 		return -ENODEV;
 
 	strcpy(ifr32.ifr_name, dev->name);
+	dev_put(dev);
 
 	err = copy_to_user((struct ifreq32 *)arg, &ifr32, sizeof(struct ifreq32));
 	return (err ? -EFAULT : 0);
@@ -1157,6 +1160,234 @@
 	return err;
 }
 
+typedef struct sg_io_hdr32 {
+	s32 interface_id;	/* [i] 'S' for SCSI generic (required) */
+	s32 dxfer_direction;	/* [i] data transfer direction  */
+	u8  cmd_len;		/* [i] SCSI command length ( <= 16 bytes) */
+	u8  mx_sb_len;		/* [i] max length to write to sbp */
+	u16 iovec_count;	/* [i] 0 implies no scatter gather */
+	u32 dxfer_len;		/* [i] byte count of data transfer */
+	u32 dxferp;		/* [i], [*io] points to data transfer memory
+					      or scatter gather list */
+	u32 cmdp;		/* [i], [*i] points to command to perform */
+	u32 sbp;		/* [i], [*o] points to sense_buffer memory */
+	u32 timeout;		/* [i] MAX_UINT->no timeout (unit: millisec) */
+	u32 flags;		/* [i] 0 -> default, see SG_FLAG... */
+	s32 pack_id;		/* [i->o] unused internally (normally) */
+	u32 usr_ptr;		/* [i->o] unused internally */
+	u8  status;		/* [o] scsi status */
+	u8  masked_status;	/* [o] shifted, masked scsi status */
+	u8  msg_status;		/* [o] messaging level data (optional) */
+	u8  sb_len_wr;		/* [o] byte count actually written to sbp */
+	u16 host_status;	/* [o] errors from host adapter */
+	u16 driver_status;	/* [o] errors from software driver */
+	s32 resid;		/* [o] dxfer_len - actual_transferred */
+	u32 duration;		/* [o] time taken by cmd (unit: millisec) */
+	u32 info;		/* [o] auxiliary information */
+} sg_io_hdr32_t;  /* 64 bytes long (on sparc32) */
+
+typedef struct sg_iovec32 {
+	u32 iov_base;
+	u32 iov_len;
+} sg_iovec32_t;
+
+static int alloc_sg_iovec(sg_io_hdr_t *sgp, u32 uptr32)
+{
+	sg_iovec32_t *uiov = (sg_iovec32_t *) A(uptr32);
+	sg_iovec_t *kiov;
+	int i;
+
+	sgp->dxferp = kmalloc(sgp->iovec_count *
+			      sizeof(sg_iovec_t), GFP_KERNEL);
+	if (!sgp->dxferp)
+		return -ENOMEM;
+	memset(sgp->dxferp, 0,
+	       sgp->iovec_count * sizeof(sg_iovec_t));
+
+	kiov = (sg_iovec_t *) sgp->dxferp;
+	for (i = 0; i < sgp->iovec_count; i++) {
+		u32 iov_base32;
+		if (__get_user(iov_base32, &uiov->iov_base) ||
+		    __get_user(kiov->iov_len, &uiov->iov_len))
+			return -EFAULT;
+
+		kiov->iov_base = kmalloc(kiov->iov_len, GFP_KERNEL);
+		if (!kiov->iov_base)
+			return -ENOMEM;
+		if (copy_from_user(kiov->iov_base,
+				   (void *) A(iov_base32),
+				   kiov->iov_len))
+			return -EFAULT;
+
+		uiov++;
+		kiov++;
+	}
+
+	return 0;
+}
+
+static int copy_back_sg_iovec(sg_io_hdr_t *sgp, u32 uptr32)
+{
+	sg_iovec32_t *uiov = (sg_iovec32_t *) A(uptr32);
+	sg_iovec_t *kiov = (sg_iovec_t *) sgp->dxferp;
+	int i;
+
+	for (i = 0; i < sgp->iovec_count; i++) {
+		u32 iov_base32;
+
+		if (__get_user(iov_base32, &uiov->iov_base))
+			return -EFAULT;
+
+		if (copy_to_user((void *) A(iov_base32),
+				 kiov->iov_base,
+				 kiov->iov_len))
+			return -EFAULT;
+
+		uiov++;
+		kiov++;
+	}
+
+	return 0;
+}
+
+static void free_sg_iovec(sg_io_hdr_t *sgp)
+{
+	sg_iovec_t *kiov = (sg_iovec_t *) sgp->dxferp;
+	int i;
+
+	for (i = 0; i < sgp->iovec_count; i++) {
+		if (kiov->iov_base) {
+			kfree(kiov->iov_base);
+			kiov->iov_base = NULL;
+		}
+		kiov++;
+	}
+	kfree(sgp->dxferp);
+	sgp->dxferp = NULL;
+}
+
+static int sg_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	sg_io_hdr32_t *sg_io32;
+	sg_io_hdr_t sg_io64;
+	u32 dxferp32, cmdp32, sbp32;
+	mm_segment_t old_fs;
+	int err = 0;
+
+	sg_io32 = (sg_io_hdr32_t *)arg;
+	err = __get_user(sg_io64.interface_id, &sg_io32->interface_id);
+	err |= __get_user(sg_io64.dxfer_direction, &sg_io32->dxfer_direction);
+	err |= __get_user(sg_io64.cmd_len, &sg_io32->cmd_len);
+	err |= __get_user(sg_io64.mx_sb_len, &sg_io32->mx_sb_len);
+	err |= __get_user(sg_io64.iovec_count, &sg_io32->iovec_count);
+	err |= __get_user(sg_io64.dxfer_len, &sg_io32->dxfer_len);
+	err |= __get_user(sg_io64.timeout, &sg_io32->timeout);
+	err |= __get_user(sg_io64.flags, &sg_io32->flags);
+	err |= __get_user(sg_io64.pack_id, &sg_io32->pack_id);
+
+	sg_io64.dxferp = NULL;
+	sg_io64.cmdp = NULL;
+	sg_io64.sbp = NULL;
+
+	err |= __get_user(cmdp32, &sg_io32->cmdp);
+	sg_io64.cmdp = kmalloc(sg_io64.cmd_len, GFP_KERNEL);
+	if (!sg_io64.cmdp) {
+		err = -ENOMEM;
+		goto out;
+	}
+	if (copy_from_user(sg_io64.cmdp,
+			   (void *) A(cmdp32),
+			   sg_io64.cmd_len)) {
+		err = -EFAULT;
+		goto out;
+	}
+
+	err |= __get_user(sbp32, &sg_io32->sbp);
+	sg_io64.sbp = kmalloc(sg_io64.mx_sb_len, GFP_KERNEL);
+	if (!sg_io64.sbp) {
+		err = -ENOMEM;
+		goto out;
+	}
+	if (copy_from_user(sg_io64.sbp,
+			   (void *) A(sbp32),
+			   sg_io64.mx_sb_len)) {
+		err = -EFAULT;
+		goto out;
+	}
+
+	err |= __get_user(dxferp32, &sg_io32->dxferp);
+	if (sg_io64.iovec_count) {
+		int ret;
+
+		if ((ret = alloc_sg_iovec(&sg_io64, dxferp32))) {
+			err = ret;
+			goto out;
+		}
+	} else {
+		sg_io64.dxferp = kmalloc(sg_io64.dxfer_len, GFP_KERNEL);
+		if (!sg_io64.dxferp) {
+			err = -ENOMEM;
+			goto out;
+		}
+		if (copy_from_user(sg_io64.dxferp,
+				   (void *) A(dxferp32),
+				   sg_io64.dxfer_len)) {
+			err = -EFAULT;
+			goto out;
+		}
+	}
+
+	/* Unused internally, do not even bother to copy it over. */
+	sg_io64.usr_ptr = NULL;
+
+	if (err)
+		return -EFAULT;
+
+	old_fs = get_fs();
+	set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, cmd, (unsigned long) &sg_io64);
+	set_fs (old_fs);
+
+	if (err < 0)
+		goto out;
+
+	err = __put_user(sg_io64.pack_id, &sg_io32->pack_id);
+	err |= __put_user(sg_io64.status, &sg_io32->status);
+	err |= __put_user(sg_io64.masked_status, &sg_io32->masked_status);
+	err |= __put_user(sg_io64.msg_status, &sg_io32->msg_status);
+	err |= __put_user(sg_io64.sb_len_wr, &sg_io32->sb_len_wr);
+	err |= __put_user(sg_io64.host_status, &sg_io32->host_status);
+	err |= __put_user(sg_io64.driver_status, &sg_io32->driver_status);
+	err |= __put_user(sg_io64.resid, &sg_io32->resid);
+	err |= __put_user(sg_io64.duration, &sg_io32->duration);
+	err |= __put_user(sg_io64.info, &sg_io32->info);
+	err |= copy_to_user((void *)A(sbp32), sg_io64.sbp, sg_io64.mx_sb_len);
+	if (sg_io64.dxferp) {
+		if (sg_io64.iovec_count)
+			err |= copy_back_sg_iovec(&sg_io64, dxferp32);
+		else
+			err |= copy_to_user((void *)A(dxferp32),
+					    sg_io64.dxferp,
+					    sg_io64.dxfer_len);
+	}
+	if (err)
+		err = -EFAULT;
+
+out:
+	if (sg_io64.cmdp)
+		kfree(sg_io64.cmdp);
+	if (sg_io64.sbp)
+		kfree(sg_io64.sbp);
+	if (sg_io64.dxferp) {
+		if (sg_io64.iovec_count) {
+			free_sg_iovec(&sg_io64);
+		} else {
+			kfree(sg_io64.dxferp);
+		}
+	}
+	return err;
+}
+
 struct ppp_option_data32 {
 	__kernel_caddr_t32	ptr;
 	__u32			length;
@@ -2161,12 +2392,11 @@
 		if (l->lv_block_exception) {
 			lbe32 = (lv_block_exception32_t *)A(ptr2);
 			memset(lbe, 0, size);
-                       for (i = 0; i < l->lv_remap_end; i++, lbe++, lbe32++) {
-                               err |= get_user(lbe->rsector_org, &lbe32->rsector_org);
-                               err |= __get_user(lbe->rdev_org, &lbe32->rdev_org);
-                               err |= __get_user(lbe->rsector_new, &lbe32->rsector_new);
-                               err |= __get_user(lbe->rdev_new, &lbe32->rdev_new);
-
+			for (i = 0; i < l->lv_remap_end; i++, lbe++, lbe32++) {
+				err |= get_user(lbe->rsector_org, &lbe32->rsector_org);
+				err |= __get_user(lbe->rdev_org, &lbe32->rdev_org);
+				err |= __get_user(lbe->rsector_new, &lbe32->rsector_new);
+				err |= __get_user(lbe->rdev_new, &lbe32->rdev_new);
 			}
 		}
 	}
@@ -2222,16 +2452,17 @@
 	switch (cmd) {
 	case VG_STATUS:
 		v = kmalloc(sizeof(vg_t), GFP_KERNEL);
-		if (!v) return -ENOMEM;
+		if (!v)
+			return -ENOMEM;
 		karg = v;
 		break;
 
 	case VG_CREATE_OLD:
 	case VG_CREATE:
 		v = kmalloc(sizeof(vg_t), GFP_KERNEL);
-		if (!v) return -ENOMEM;
-		if (copy_from_user(v, (void *)arg, (long)&((vg32_t *)0)->proc) ||
-		    __get_user(v->proc, &((vg32_t *)arg)->proc)) {
+		if (!v)
+			return -ENOMEM;
+		if (copy_from_user(v, (void *)arg, (long)&((vg32_t *)0)->proc)) {
 			kfree(v);
 			return -EFAULT;
 		}
@@ -2248,39 +2479,46 @@
 			return -EPERM;
 		for (i = 0; i < v->pv_max; i++) {
 			err = __get_user(ptr, &((vg32_t *)arg)->pv[i]);
-			if (err) break;
+			if (err)
+				break;
 			if (ptr) {
 				v->pv[i] = kmalloc(sizeof(pv_t), GFP_KERNEL);
 				if (!v->pv[i]) {
 					err = -ENOMEM;
 					break;
 				}
-				err = copy_from_user(v->pv[i], (void *)A(ptr), sizeof(pv32_t) - 8 - UUID_LEN+1);
+				err = copy_from_user(v->pv[i], (void *)A(ptr),
+						     sizeof(pv32_t) - 8 - UUID_LEN+1);
 				if (err) {
 					err = -EFAULT;
 					break;
 				}
-				err = copy_from_user(v->pv[i]->pv_uuid, ((pv32_t *)A(ptr))->pv_uuid, UUID_LEN+1);
+				err = copy_from_user(v->pv[i]->pv_uuid,
+						     ((pv32_t *)A(ptr))->pv_uuid,
+						     UUID_LEN+1);
 				if (err) {
 				        err = -EFAULT;
 					break;
 				}
 
-				
-				v->pv[i]->pe = NULL; v->pv[i]->inode = NULL;
+				v->pv[i]->pe = NULL;
+				v->pv[i]->bd = NULL;
 			}
 		}
 		if (!err) {
 			for (i = 0; i < v->lv_max; i++) {
 				err = __get_user(ptr, &((vg32_t *)arg)->lv[i]);
-				if (err) break;
+				if (err)
+					break;
 				if (ptr) {
 					v->lv[i] = get_lv_t(ptr, &err);
-					if (err) break;
+					if (err)
+						break;
 				}
 			}
 		}
 		break;
+
 	case LV_CREATE:
 	case LV_EXTEND:
 	case LV_REDUCE:
@@ -2288,54 +2526,70 @@
 	case LV_RENAME:
 	case LV_STATUS_BYNAME:
 	        err = copy_from_user(&u.pv_status, arg, sizeof(u.pv_status.pv_name));
-		if (err) return -EFAULT;
+		if (err)
+			return -EFAULT;
 		if (cmd != LV_REMOVE) {
 			err = __get_user(ptr, &((lv_req32_t *)arg)->lv);
-			if (err) return err;
+			if (err)
+				return err;
 			u.lv_req.lv = get_lv_t(ptr, &err);
 		} else
 			u.lv_req.lv = NULL;
 		break;
 
-
 	case LV_STATUS_BYINDEX:
-		err = get_user(u.lv_byindex.lv_index, &((lv_status_byindex_req32_t *)arg)->lv_index);
+		err = get_user(u.lv_byindex.lv_index,
+			       &((lv_status_byindex_req32_t *)arg)->lv_index);
 		err |= __get_user(ptr, &((lv_status_byindex_req32_t *)arg)->lv);
-		if (err) return err;
+		if (err)
+			return err;
 		u.lv_byindex.lv = get_lv_t(ptr, &err);
 		break;
+
 	case LV_STATUS_BYDEV:
 	        err = get_user(u.lv_bydev.dev, &((lv_status_bydev_req32_t *)arg)->dev);
+		err |= __get_user(ptr, &((lv_status_bydev_req32_t *)arg)->lv);
+		if (err)
+			return err;
 		u.lv_bydev.lv = get_lv_t(ptr, &err);
-		if (err) return err;
-		u.lv_bydev.lv = &p;
-		p.pe = NULL; p.inode = NULL;		
-		break;		
+		break;
+
 	case VG_EXTEND:
 		err = copy_from_user(&p, (void *)arg, sizeof(pv32_t) - 8 - UUID_LEN+1);
-		if (err) return -EFAULT;
+		if (err)
+			return -EFAULT;
 		err = copy_from_user(p.pv_uuid, ((pv32_t *)arg)->pv_uuid, UUID_LEN+1);
-		if (err) return -EFAULT;
-		p.pe = NULL; p.inode = NULL;
+		if (err)
+			return -EFAULT;
+		p.pe = NULL;
+		p.bd = NULL;
 		karg = &p;
 		break;
+
 	case PV_CHANGE:
 	case PV_STATUS:
 		err = copy_from_user(&u.pv_status, arg, sizeof(u.lv_req.lv_name));
-		if (err) return -EFAULT;
+		if (err)
+			return -EFAULT;
 		err = __get_user(ptr, &((pv_status_req32_t *)arg)->pv);
-		if (err) return err;
+		if (err)
+			return err;
 		u.pv_status.pv = &p;
 		if (cmd == PV_CHANGE) {
-			err = copy_from_user(&p, (void *)A(ptr), sizeof(pv32_t) - 8 - UUID_LEN+1);
-			if (err) return -EFAULT;
-			p.pe = NULL; p.inode = NULL;
+			err = copy_from_user(&p, (void *)A(ptr),
+					     sizeof(pv32_t) - 8 - UUID_LEN+1);
+			if (err)
+				return -EFAULT;
+			p.pe = NULL;
+			p.bd = NULL;
 		}
 		break;
-	}
+	};
+
         old_fs = get_fs(); set_fs (KERNEL_DS);
         err = sys_ioctl (fd, cmd, (unsigned long)karg);
         set_fs (old_fs);
+
 	switch (cmd) {
 	case VG_STATUS:
 		if (!err) {
@@ -2361,17 +2615,23 @@
 		}
 		kfree(v);
 		break;
+
 	case LV_STATUS_BYNAME:
-		if (!err && u.lv_req.lv) err = copy_lv_t(ptr, u.lv_req.lv);
+		if (!err && u.lv_req.lv)
+			err = copy_lv_t(ptr, u.lv_req.lv);
 		/* Fall through */
+
         case LV_CREATE:
 	case LV_EXTEND:
 	case LV_REDUCE:
-		if (u.lv_req.lv) put_lv_t(u.lv_req.lv);
+		if (u.lv_req.lv)
+			put_lv_t(u.lv_req.lv);
 		break;
+
 	case LV_STATUS_BYINDEX:
 		if (u.lv_byindex.lv) {
-			if (!err) err = copy_lv_t(ptr, u.lv_byindex.lv);
+			if (!err)
+				err = copy_lv_t(ptr, u.lv_byindex.lv);
 			put_lv_t(u.lv_byindex.lv);
 		}
 		break;
@@ -2387,9 +2647,11 @@
 	case PV_STATUS:
 		if (!err) {
 			err = copy_to_user((void *)A(ptr), &p, sizeof(pv32_t) - 8 - UUID_LEN+1);
-			if (err) return -EFAULT;
+			if (err)
+				return -EFAULT;
 			err = copy_to_user(((pv_t *)A(ptr))->pv_uuid, p.pv_uuid, UUID_LEN + 1);
-			if (err) return -EFAULT;
+			if (err)
+				return -EFAULT;
 		}
 		break;
 	};
@@ -2977,6 +3239,7 @@
 		set_fs (KERNEL_DS);
 		err = sys_ioctl(fd, cmd, (unsigned long)&a);
 		set_fs (old_fs);
+		break;
 	default:
 		return -EINVAL;
 	}                                        
@@ -3435,119 +3698,6 @@
 	return ((0 == ret) ? 0 : -EFAULT);
 }	
 
-struct sg_io_hdr_32
-{
-	int interface_id;
-	int dxfer_direction;
-	unsigned char cmd_len;
-	unsigned char mx_sb_len;
-	unsigned short iovec_count;
-	unsigned int dxfer_len;
-	u32 dxferp;
-	u32 cmdp;
-	u32 sbp;
-	unsigned int timeout;
-	unsigned int flags;
-	int pack_id;
-	u32 usr_ptr;
-	unsigned char status;
-	unsigned char masked_status;
-	unsigned char msg_status;
-	unsigned char sb_len_wr;
-	unsigned short host_status;
-	unsigned short driver_status;
-	int resid;
-	unsigned int duration;
-	unsigned int info;
-};
-
-static int do_sg_io(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	struct sg_io_hdr *sg = kmalloc(sizeof(struct sg_io_hdr), GFP_KERNEL);
-	struct sg_io_hdr_32 *sg_32 = (struct sg_io_hdr_32 *)arg;
-	u32 dxferp_32;
-	u32 cmdp_32;
-	u32 sbp_32;
-	u32 usr_ptr_32;
-	int ret = -EFAULT;
-	int err;
-	mm_segment_t old_fs = get_fs();
-
-	if (!sg)
-		return -ENOMEM;
-
-	memset(sg, 0, sizeof(*sg));
-
-	err = copy_from_user(sg, sg_32, offsetof(struct sg_io_hdr, dxferp));
-	err |= __get_user(dxferp_32, &sg_32->dxferp);
-	err |= __get_user(cmdp_32, &sg_32->cmdp);
-	err |= __get_user(sbp_32, &sg_32->sbp);
-
-	if (err)
-		goto error;
-
-	sg->dxferp = (void *)A(dxferp_32);
-	sg->cmdp = (void *)A(cmdp_32);
-	sg->sbp = (void *)A(sbp_32);
-
-	err = __copy_from_user(&sg->timeout, &sg_32->timeout,
-			       (long)&sg->usr_ptr - (long)&sg->timeout);
-
-	err |= __get_user(usr_ptr_32, &sg_32->usr_ptr);
-
-	if (err)
-		goto error;
-
-	sg->usr_ptr = (void *)A(usr_ptr_32);
-
-	err = __copy_from_user(&sg->status, &sg_32->status,
-			       sizeof(struct sg_io_hdr) -
-			       offsetof(struct sg_io_hdr, status));
-
-	if (err)
-		goto error;
-
-	set_fs(KERNEL_DS);
-	ret = sys_ioctl(fd, cmd, (unsigned long)sg);
-	set_fs(old_fs);
-
-	err = copy_to_user(sg_32, sg, offsetof(struct sg_io_hdr, dxferp));
-
-	dxferp_32 = (unsigned long)sg->dxferp;
-	cmdp_32 = (unsigned long)sg->cmdp;
-	sbp_32 = (unsigned long)sg->sbp;
-	err |= __put_user(dxferp_32, &sg_32->dxferp);
-	err |= __put_user(cmdp_32, &sg_32->cmdp);
-	err |= __put_user(sbp_32, &sg_32->sbp);
-
-	if (err) {
-		ret = -EFAULT;
-		goto error;
-	}
-
-	err = __copy_to_user(&sg_32->timeout, &sg->timeout,
-			     (long)&sg->usr_ptr - (long)&sg->timeout);
-
-	usr_ptr_32 = (unsigned long)sg->usr_ptr;
-	err |= __put_user(usr_ptr_32, &sg_32->usr_ptr);
-
-	if (err) {
-		ret = -EFAULT;
-		goto error;
-	}
-
-	err = __copy_to_user(&sg_32->status, &sg->status,
-			      sizeof(struct sg_io_hdr) -
-			      offsetof(struct sg_io_hdr, status));
-
-	if (err)
-		ret = -EFAULT;
-
-error:
-	kfree(sg);
-	return ret;
-}
-
 struct ioctl_trans {
 	unsigned long cmd;
 	unsigned long handler;
@@ -3736,6 +3886,12 @@
 COMPATIBLE_IOCTL(SCSI_IOCTL_TAGGED_DISABLE),
 COMPATIBLE_IOCTL(SCSI_IOCTL_GET_BUS_NUMBER),
 COMPATIBLE_IOCTL(SCSI_IOCTL_SEND_COMMAND),
+/* Big T */
+COMPATIBLE_IOCTL(TUNSETNOCSUM),
+COMPATIBLE_IOCTL(TUNSETDEBUG),
+COMPATIBLE_IOCTL(TUNSETIFF),
+COMPATIBLE_IOCTL(TUNSETPERSIST),
+COMPATIBLE_IOCTL(TUNSETOWNER),
 /* Big V */
 COMPATIBLE_IOCTL(VT_SETMODE),
 COMPATIBLE_IOCTL(VT_GETMODE),
@@ -3812,6 +3968,8 @@
 COMPATIBLE_IOCTL(SIOCDRARP),
 COMPATIBLE_IOCTL(SIOCADDDLCI),
 COMPATIBLE_IOCTL(SIOCDELDLCI),
+COMPATIBLE_IOCTL(SIOCGIFVLAN),
+COMPATIBLE_IOCTL(SIOCSIFVLAN),
 /* SG stuff */
 COMPATIBLE_IOCTL(SG_SET_TIMEOUT),
 COMPATIBLE_IOCTL(SG_GET_TIMEOUT),
@@ -4145,10 +4303,19 @@
 COMPATIBLE_IOCTL(WDIOC_GETTEMP),
 COMPATIBLE_IOCTL(WDIOC_SETOPTIONS),
 COMPATIBLE_IOCTL(WDIOC_KEEPALIVE),
+/* Big R */
+COMPATIBLE_IOCTL(RNDGETENTCNT),
+COMPATIBLE_IOCTL(RNDADDTOENTCNT),
+COMPATIBLE_IOCTL(RNDGETPOOL),
+COMPATIBLE_IOCTL(RNDADDENTROPY),
+COMPATIBLE_IOCTL(RNDZAPENTCNT),
+COMPATIBLE_IOCTL(RNDCLEARPOOL),
 /* Bluetooth ioctls */
 COMPATIBLE_IOCTL(HCIDEVUP),
 COMPATIBLE_IOCTL(HCIDEVDOWN),
 COMPATIBLE_IOCTL(HCIDEVRESET),
+COMPATIBLE_IOCTL(HCIDEVRESTAT),
+COMPATIBLE_IOCTL(HCIGETDEVINFO),
 COMPATIBLE_IOCTL(HCIGETDEVLIST),
 COMPATIBLE_IOCTL(HCISETRAW),
 COMPATIBLE_IOCTL(HCISETSCAN),
@@ -4264,6 +4431,7 @@
 HANDLE_IOCTL(FDPOLLDRVSTAT32, fd_ioctl_trans),
 HANDLE_IOCTL(FDGETFDCSTAT32, fd_ioctl_trans),
 HANDLE_IOCTL(FDWERRORGET32, fd_ioctl_trans),
+HANDLE_IOCTL(SG_IO,sg_ioctl_trans),
 HANDLE_IOCTL(PPPIOCGIDLE32, ppp_ioctl_trans),
 HANDLE_IOCTL(PPPIOCSCOMPRESS32, ppp_ioctl_trans),
 HANDLE_IOCTL(MTIOCGET32, mt_ioctl_trans),
@@ -4358,7 +4526,6 @@
 HANDLE_IOCTL(USBDEVFS_REAPURB32, do_usbdevfs_reapurb),
 HANDLE_IOCTL(USBDEVFS_REAPURBNDELAY32, do_usbdevfs_reapurb),
 HANDLE_IOCTL(USBDEVFS_DISCSIGNAL32, do_usbdevfs_discsignal),
-HANDLE_IOCTL(SG_IO, do_sg_io),
 };
 
 unsigned long ioctl32_hash_table[1024];
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/irq.c linux-2.4.20-pre5/arch/ppc64/kernel/irq.c
--- linux-2.4.20-pre4/arch/ppc64/kernel/irq.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/irq.c	Wed Aug 28 16:37:31 2002
@@ -1,6 +1,4 @@
 /*
- * 
- *
  *  arch/ppc/kernel/irq.c
  *
  *  Derived from arch/i386/kernel/irq.c
@@ -25,7 +23,6 @@
  * should be easier.
  */
 
-
 #include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/threads.h>
@@ -42,6 +39,7 @@
 #include <linux/delay.h>
 #include <linux/irq.h>
 #include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 #include <linux/random.h>
 
 #include <asm/uaccess.h>
@@ -56,6 +54,7 @@
 #include <asm/iSeries/LparData.h>
 #include <asm/machdep.h>
 #include <asm/paca.h>
+#include <asm/perfmon.h>
 
 #include "local_irq.h"
 
@@ -99,7 +98,7 @@
  * this needs to be removed.
  * -- Cort
  */
-#define IRQ_KMALLOC_ENTRIES 8
+#define IRQ_KMALLOC_ENTRIES 16
 static int cache_bitmask = 0;
 static struct irqaction malloc_cache[IRQ_KMALLOC_ENTRIES];
 extern int mem_init_done;
@@ -554,58 +553,61 @@
 	spin_unlock(&desc->lock);
 }
 
-int do_IRQ(struct pt_regs *regs, int isfake)
+int do_IRQ(struct pt_regs *regs)
 {
 	int cpu = smp_processor_id();
-	int irq;
+	int irq, first = 1;
+#ifdef CONFIG_PPC_ISERIES
 	struct paca_struct *lpaca;
-	struct ItLpQueue * lpq;
-
-	/* if(cpu) udbg_printf("Entering do_IRQ\n");  */
-
-        irq_enter(cpu);
+	struct ItLpQueue *lpq;
+#endif
 
-	if (naca->platform != PLATFORM_ISERIES_LPAR) {
-	
-		/* every arch is required to have a get_irq -- Cort */
-		irq = ppc_md.get_irq( regs );
+	irq_enter(cpu);
 
-		if ( irq >= 0 ) {
-			ppc_irq_dispatch_handler( regs, irq );
-			if (ppc_md.post_irq)
-				ppc_md.post_irq( regs, irq );
-		} else {
-			/* -2 means ignore, already handled */
-			if (irq != -2) {
-				printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
-					irq, regs->nip);
-				ppc_spurious_interrupts++;
-			}
-		}
-	}
-	/* if on iSeries partition */
-	else {
-		lpaca = get_paca();
+#ifdef CONFIG_PPC_ISERIES
+	lpaca = get_paca();
 #ifdef CONFIG_SMP
-		if ( lpaca->xLpPaca.xIntDword.xFields.xIpiCnt ) {
-			lpaca->xLpPaca.xIntDword.xFields.xIpiCnt = 0;
-			iSeries_smp_message_recv( regs );
-		}
-#endif /* CONFIG_SMP */
-		lpq = lpaca->lpQueuePtr;
-		if ( lpq && ItLpQueue_isLpIntPending( lpq ) )
-			lpEvent_count += ItLpQueue_process( lpq, regs );
+	if (lpaca->xLpPaca.xIntDword.xFields.xIpiCnt) {
+		lpaca->xLpPaca.xIntDword.xFields.xIpiCnt = 0;
+		iSeries_smp_message_recv(regs);
 	}
-		
+#endif /* CONFIG_SMP */
+	lpq = lpaca->lpQueuePtr;
+	if (lpq && ItLpQueue_isLpIntPending(lpq))
+		lpEvent_count += ItLpQueue_process(lpq, regs);
+#else
+	/*
+	 * Every arch is required to implement ppc_md.get_irq.
+	 * This function will either return an irq number or -1 to
+	 * indicate there are no more pending.  But the first time
+	 * through the loop this means there wasn't an IRQ pending.
+	 * The value -2 is for buggy hardware and means that this IRQ
+	 * has already been handled. -- Tom
+	 */
+	while ((irq = ppc_md.get_irq(regs)) >= 0) {
+		ppc_irq_dispatch_handler(regs, irq);
+		first = 0;
+	}
+	if (irq != -2 && first)
+		/* That's not SMP safe ... but who cares ? */
+		ppc_spurious_interrupts++;
+#endif
+
         irq_exit(cpu);
 
-	if (naca->platform == PLATFORM_ISERIES_LPAR) {
-		if ( lpaca->xLpPaca.xIntDword.xFields.xDecrInt ) {
-			lpaca->xLpPaca.xIntDword.xFields.xDecrInt = 0;
-			/* Signal a fake decrementer interrupt */
-			timer_interrupt( regs );
-		}
+#ifdef CONFIG_PPC_ISERIES
+	if (lpaca->xLpPaca.xIntDword.xFields.xDecrInt) {
+		lpaca->xLpPaca.xIntDword.xFields.xDecrInt = 0;
+		/* Signal a fake decrementer interrupt */
+		timer_interrupt(regs);
+	}
+
+	if (lpaca->xLpPaca.xIntDword.xFields.xPdcInt) {
+		lpaca->xLpPaca.xIntDword.xFields.xPdcInt = 0;
+		/* Signal a fake PMC interrupt */
+		PerformanceMonitorException();
 	}
+#endif
 
 	if (softirq_pending(cpu))
 		do_softirq();
@@ -902,9 +904,11 @@
 		unsigned i;
 		for (i=0; i<MAX_PACAS; ++i) {
 			if ( paca[i].prof_buffer && (new_value & 1) )
-				paca[i].prof_enabled = 1;
-			else
-				paca[i].prof_enabled = 0;
+				paca[i].prof_mode = PMC_STATE_DECR_PROFILE;
+			else {
+				if(paca[i].prof_mode != PMC_STATE_INITIAL) 
+					paca[i].prof_mode = PMC_STATE_READY;
+			}
 			new_value >>= 1;
 		}
 	}
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/lmb.c linux-2.4.20-pre5/arch/ppc64/kernel/lmb.c
--- linux-2.4.20-pre4/arch/ppc64/kernel/lmb.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/lmb.c	Wed Aug 28 16:37:31 2002
@@ -12,6 +12,7 @@
  */
 
 #include <linux/config.h>
+#include <linux/kernel.h>
 #include <asm/types.h>
 #include <asm/page.h>
 #include <asm/prom.h>
@@ -27,7 +28,7 @@
 static long lmb_add_region(struct lmb_region *, unsigned long, unsigned long, unsigned long);
 
 struct lmb lmb = {
-	0,
+	0, 0,
 	{0,0,0,0,{{0,0,0}}},
 	{0,0,0,0,{{0,0,0}}}
 };
@@ -135,6 +136,10 @@
 	struct lmb *_lmb = PTRRELOC(&lmb);
 	struct lmb_region *_rgn = &(_lmb->memory);
 
+	/* On pSeries LPAR systems, the first LMB is our RMO region. */
+	if ( base == 0 )
+		_lmb->rmo_size = size;
+
 	return lmb_add_region(_rgn, base, size, LMB_MEMORY_AREA);
 
 }
@@ -242,12 +247,17 @@
 	return (i < rgn->cnt) ? i : -1;
 }
 
-
 unsigned long
 lmb_alloc(unsigned long size, unsigned long align)
 {
+	return lmb_alloc_base(size, align, LMB_ALLOC_ANYWHERE);
+}
+
+unsigned long
+lmb_alloc_base(unsigned long size, unsigned long align, unsigned long max_addr)
+{
 	long i, j;
-	unsigned long base;
+	unsigned long base = 0;
 	unsigned long offset = reloc_offset();
 	struct lmb *_lmb = PTRRELOC(&lmb);
 	struct lmb_region *_mem = &(_lmb->memory);
@@ -261,7 +271,12 @@
 		if ( lmbtype != LMB_MEMORY_AREA )
 			continue;
 
-		base = _ALIGN_DOWN(lmbbase+lmbsize-size, align);
+		if ( max_addr == LMB_ALLOC_ANYWHERE )
+			base = _ALIGN_DOWN(lmbbase+lmbsize-size, align);
+		else if ( lmbbase < max_addr )
+			base = _ALIGN_DOWN(min(lmbbase+lmbsize,max_addr)-size, align);
+		else
+			continue;
 
 		while ( (lmbbase <= base) &&
 			((j = lmb_overlaps_region(_rsv,base,size)) >= 0) ) {
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/mf.c linux-2.4.20-pre5/arch/ppc64/kernel/mf.c
--- linux-2.4.20-pre4/arch/ppc64/kernel/mf.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/mf.c	Wed Aug 28 16:37:31 2002
@@ -410,7 +410,7 @@
 		mf_powerOff();
 	}
 	else
-		printk( KERN_ALERT "mf.c: init has been successfully notified to proceed with shutdown\n" );
+		printk( KERN_INFO "mf.c: init has been successfully notified to proceed with shutdown\n" );
 
 	return rc;
 }
@@ -436,7 +436,7 @@
 		case 0x5B:	/* power control notification */
 			if ( (event->xUnion.xCEMsgData.xCEMsg[5]&0x20) != 0 )
 			{
-				printk( KERN_ALERT "mf.c: Commencing partition shutdown\n" );
+				printk( KERN_INFO "mf.c: Commencing partition shutdown\n" );
 				if ( shutdown() == 0 )
 					signalCEMsg( "\x00\x00\x00\xDB\x00\x00\x00\x00\x00\x00\x00\x00", NULL );
 			}
@@ -479,7 +479,7 @@
 			signalEvent( NULL );
 		break;
 	case 1:	/* IT sys shutdown */
-		printk( KERN_ALERT "mf.c: Commencing system shutdown\n" );
+		printk( KERN_INFO "mf.c: Commencing system shutdown\n" );
 		shutdown();
 		break;
 	}
@@ -666,7 +666,7 @@
  */
 void mf_powerOff( void )
 {
-	printk( KERN_ALERT "mf.c: Down it goes...\n" );
+	printk( KERN_INFO "mf.c: Down it goes...\n" );
 	signalCEMsg( "\x00\x00\x00\x4D\x00\x00\x00\x00\x00\x00\x00\x00", NULL );
 	for (;;);
 }
@@ -677,7 +677,7 @@
  */
 void mf_reboot( void )
 {
-	printk( KERN_ALERT "mf.c: Preparing to bounce...\n" );
+	printk( KERN_INFO "mf.c: Preparing to bounce...\n" );
 	signalCEMsg( "\x00\x00\x00\x4E\x00\x00\x00\x00\x00\x00\x00\x00", NULL );
 	for (;;);
 }
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/misc.S linux-2.4.20-pre5/arch/ppc64/kernel/misc.S
--- linux-2.4.20-pre4/arch/ppc64/kernel/misc.S	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/misc.S	Wed Aug 28 16:37:31 2002
@@ -745,7 +745,8 @@
 	.llong .sys_fremovexattr	/* 220 */
 	.llong .sys_futex
 #endif
-	.rept NR_syscalls-221
+	.llong .sys_perfmonctl   /* Put this here for now ... */
+	.rept NR_syscalls-222
 		.llong .sys_ni_syscall
 	.endr
 #endif
@@ -975,6 +976,7 @@
 	.llong .sys_fremovexattr	/* 220 */
 	.llong .sys_futex
 #endif
-	.rept NR_syscalls-221
+	.llong .sys_perfmonctl   /* Put this here for now ... */
+	.rept NR_syscalls-222
 	.llong .sys_ni_syscall
 	.endr
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/mk_defs.c linux-2.4.20-pre5/arch/ppc64/kernel/mk_defs.c
--- linux-2.4.20-pre4/arch/ppc64/kernel/mk_defs.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/mk_defs.c	Wed Aug 28 16:37:31 2002
@@ -79,11 +79,33 @@
 	DEFINE(PACAPROCENABLED, offsetof(struct paca_struct, xProcEnabled));
 	DEFINE(PACAHRDWINTCOUNT, offsetof(struct paca_struct, xHrdIntCount));
 	DEFINE(PACADEFAULTDECR, offsetof(struct paca_struct, default_decr));
-	DEFINE(PACAPROFENABLED, offsetof(struct paca_struct, prof_enabled));
+
+	DEFINE(PACAPROFMODE, offsetof(struct paca_struct, prof_mode));
 	DEFINE(PACAPROFLEN, offsetof(struct paca_struct, prof_len));
 	DEFINE(PACAPROFSHIFT, offsetof(struct paca_struct, prof_shift));
 	DEFINE(PACAPROFBUFFER, offsetof(struct paca_struct, prof_buffer));
 	DEFINE(PACAPROFSTEXT, offsetof(struct paca_struct, prof_stext));
+	DEFINE(PACAPROFETEXT, offsetof(struct paca_struct, prof_etext));
+	DEFINE(PACAPMC1, offsetof(struct paca_struct, pmc[0]));
+	DEFINE(PACAPMC2, offsetof(struct paca_struct, pmc[1]));
+	DEFINE(PACAPMC3, offsetof(struct paca_struct, pmc[2]));
+	DEFINE(PACAPMC4, offsetof(struct paca_struct, pmc[3]));
+	DEFINE(PACAPMC5, offsetof(struct paca_struct, pmc[4]));
+	DEFINE(PACAPMC6, offsetof(struct paca_struct, pmc[5]));
+	DEFINE(PACAPMC7, offsetof(struct paca_struct, pmc[6]));
+	DEFINE(PACAPMC8, offsetof(struct paca_struct, pmc[7]));
+	DEFINE(PACAMMCR0, offsetof(struct paca_struct, pmc[8]));
+	DEFINE(PACAMMCR1, offsetof(struct paca_struct, pmc[9]));
+	DEFINE(PACAMMCRA, offsetof(struct paca_struct, pmc[10]));
+	DEFINE(PACAPMCC1, offsetof(struct paca_struct, pmcc[0]));
+	DEFINE(PACAPMCC2, offsetof(struct paca_struct, pmcc[1]));
+	DEFINE(PACAPMCC3, offsetof(struct paca_struct, pmcc[2]));
+	DEFINE(PACAPMCC4, offsetof(struct paca_struct, pmcc[3]));
+	DEFINE(PACAPMCC5, offsetof(struct paca_struct, pmcc[4]));
+	DEFINE(PACAPMCC6, offsetof(struct paca_struct, pmcc[5]));
+	DEFINE(PACAPMCC7, offsetof(struct paca_struct, pmcc[6]));
+	DEFINE(PACAPMCC8, offsetof(struct paca_struct, pmcc[7]));
+
 	DEFINE(PACALPPACA, offsetof(struct paca_struct, xLpPaca));
         DEFINE(LPPACA, offsetof(struct paca_struct, xLpPaca));
         DEFINE(PACAREGSAV, offsetof(struct paca_struct, xRegSav));
@@ -93,6 +115,7 @@
         DEFINE(LPPACASRR1, offsetof(struct ItLpPaca, xSavedSrr1));
 	DEFINE(LPPACAANYINT, offsetof(struct ItLpPaca, xIntDword.xAnyInt));
 	DEFINE(LPPACADECRINT, offsetof(struct ItLpPaca, xIntDword.xFields.xDecrInt));
+	DEFINE(LPPACAPDCINT, offsetof(struct ItLpPaca, xIntDword.xFields.xPdcInt));
         DEFINE(LPQCUREVENTPTR, offsetof(struct ItLpQueue, xSlicCurEventPtr));
         DEFINE(LPQOVERFLOW, offsetof(struct ItLpQueue, xPlicOverflowIntPending));
         DEFINE(LPEVENTFLAGS, offsetof(struct HvLpEvent, xFlags));
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/open_pic.c linux-2.4.20-pre5/arch/ppc64/kernel/open_pic.c
--- linux-2.4.20-pre4/arch/ppc64/kernel/open_pic.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/open_pic.c	Wed Aug 28 16:37:31 2002
@@ -33,7 +33,6 @@
 static volatile struct OpenPIC *OpenPIC = NULL;
 u_int OpenPIC_NumInitSenses __initdata = 0;
 u_char *OpenPIC_InitSenses __initdata = NULL;
-extern int use_of_interrupt_tree;
 
 void find_ISUs(void);
 
@@ -47,7 +46,6 @@
 OpenPIC_SourcePtr ISU[OPENPIC_MAX_ISU];
 
 static void openpic_end_irq(unsigned int irq_nr);
-static void openpic_ack_irq(unsigned int irq_nr);
 static void openpic_set_affinity(unsigned int irq_nr, unsigned long cpumask);
 
 struct hw_interrupt_type open_pic = {
@@ -56,14 +54,13 @@
 	NULL,
 	openpic_enable_irq,
 	openpic_disable_irq,
-	openpic_ack_irq,
+	NULL,
 	openpic_end_irq,
 	openpic_set_affinity
 };
 
 #ifdef CONFIG_SMP
 static void openpic_end_ipi(unsigned int irq_nr);
-static void openpic_ack_ipi(unsigned int irq_nr);
 static void openpic_enable_ipi(unsigned int irq_nr);
 static void openpic_disable_ipi(unsigned int irq_nr);
 
@@ -73,9 +70,9 @@
 	NULL,
 	openpic_enable_ipi,
 	openpic_disable_ipi,
-	openpic_ack_ipi,
+	NULL,
 	openpic_end_ipi,
-	0
+	NULL
 };
 #endif /* CONFIG_SMP */
 
@@ -293,7 +290,7 @@
 	}
 	OpenPIC = (volatile struct OpenPIC *)OpenPIC_Addr;
 
-	ppc_md.progress("openpic enter",0x122);
+	ppc64_boot_msg(0x20, "OpenPic Init");
 
 	t = openpic_read(&OpenPIC->Global.Feature_Reporting0);
 	switch (t & OPENPIC_FEATURE_VERSION_MASK) {
@@ -330,7 +327,7 @@
 	find_ISUs();
 
 	/* Initialize timer interrupts */
-	ppc_md.progress("openpic timer",0x3ba);
+	ppc64_boot_msg(0x21, "OpenPic Timer");
 	for (i = 0; i < OPENPIC_NUM_TIMERS; i++) {
 		/* Disabled, Priority 0 */
 		openpic_inittimer(i, 0, openpic_vec_timer+i);
@@ -340,7 +337,7 @@
 
 #ifdef CONFIG_SMP
 	/* Initialize IPI interrupts */
-	ppc_md.progress("openpic ipi",0x3bb);
+	ppc64_boot_msg(0x22, "OpenPic IPI");
 	openpic_test_broken_IPI();
 	for (i = 0; i < OPENPIC_NUM_IPI; i++) {
 		/* Disabled, Priority 10..13 */
@@ -352,7 +349,7 @@
 #endif
 
 	/* Initialize external interrupts */
-	ppc_md.progress("openpic ext",0x3bc);
+	ppc64_boot_msg(0x23, "OpenPic Ext");
 
 	openpic_set_priority(0xf);
 
@@ -385,7 +382,7 @@
 		irq_desc[i].handler = &open_pic;
 
 	/* Initialize the spurious interrupt */
-	ppc_md.progress("openpic spurious",0x3bd);
+	ppc64_boot_msg(0x24, "OpenPic Spurious");
 	openpic_set_spurious(openpic_vec_spurious);
 
 	/* Initialize the cascade */
@@ -397,7 +394,7 @@
 	openpic_set_priority(0);
 	openpic_disable_8259_pass_through();
 
-	ppc_md.progress("openpic exit",0x222);
+	ppc64_boot_msg(0x25, "OpenPic Done");
 }
 
 void openpic_setup_ISU(int isu_num, unsigned long addr)
@@ -756,13 +753,6 @@
 				(sense ? OPENPIC_SENSE_LEVEL : 0));
 }
 
-/* No spinlocks, should not be necessary with the OpenPIC
- * (1 register = 1 interrupt and we have the desc lock).
- */
-static void openpic_ack_irq(unsigned int irq_nr)
-{
-}
-
 static void openpic_end_irq(unsigned int irq_nr)
 {
 	if ((irq_desc[irq_nr].status & IRQ_LEVEL) != 0)
@@ -775,10 +765,6 @@
 }
 
 #ifdef CONFIG_SMP
-static void openpic_ack_ipi(unsigned int irq_nr)
-{
-}
-
 static void openpic_end_ipi(unsigned int irq_nr)
 {
 	/* IPIs are marked IRQ_PER_CPU. This has the side effect of
@@ -825,4 +811,3 @@
 		irq = -1;
 	return irq;
 }
-
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/pSeries_lpar.c linux-2.4.20-pre5/arch/ppc64/kernel/pSeries_lpar.c
--- linux-2.4.20-pre4/arch/ppc64/kernel/pSeries_lpar.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/pSeries_lpar.c	Wed Aug 28 16:37:31 2002
@@ -21,6 +21,7 @@
 
 #include <linux/config.h>
 #include <linux/kernel.h>
+#include <linux/fs.h>
 #include <asm/processor.h>
 #include <asm/semaphore.h>
 #include <asm/mmu.h>
@@ -33,128 +34,7 @@
 #include <asm/pci_dma.h>
 #include <linux/pci.h>
 #include <asm/naca.h>
-
-/* Status return values */
-#define H_Success	0
-#define H_Busy		1	/* Hardware busy -- retry later */
-#define H_Hardware	-1	/* Hardware error */
-#define H_Function	-2	/* Function not supported */
-#define H_Privilege	-3	/* Caller not privileged */
-#define H_Parameter	-4	/* Parameter invalid, out-of-range or conflicting */
-#define H_Bad_Mode	-5	/* Illegal msr value */
-#define H_PTEG_Full	-6	/* PTEG is full */
-#define H_Not_Found	-7	/* PTE was not found" */
-#define H_Reserved_DABR	-8	/* DABR address is reserved by the hypervisor on this processor" */
-
-/* Flags */
-#define H_LARGE_PAGE		(1UL<<(63-16))
-#define H_EXACT		    (1UL<<(63-24))	/* Use exact PTE or return H_PTEG_FULL */
-#define H_R_XLATE		(1UL<<(63-25))	/* include a valid logical page num in the pte if the valid bit is set */
-#define H_READ_4		(1UL<<(63-26))	/* Return 4 PTEs */
-#define H_AVPN			(1UL<<(63-32))	/* An avpn is provided as a sanity test */
-#define H_ICACHE_INVALIDATE	(1UL<<(63-40))	/* icbi, etc.  (ignored for IO pages) */
-#define H_ICACHE_SYNCHRONIZE	(1UL<<(63-41))	/* dcbst, icbi, etc (ignored for IO pages */
-#define H_ZERO_PAGE		(1UL<<(63-48))	/* zero the page before mapping (ignored for IO pages) */
-#define H_COPY_PAGE		(1UL<<(63-49))
-#define H_N			(1UL<<(63-61))
-#define H_PP1			(1UL<<(63-62))
-#define H_PP2			(1UL<<(63-63))
-
-
-
-/* pSeries hypervisor opcodes */
-#define H_REMOVE		0x04
-#define H_ENTER			0x08
-#define H_READ			0x0c
-#define H_CLEAR_MOD		0x10
-#define H_CLEAR_REF		0x14
-#define H_PROTECT		0x18
-#define H_GET_TCE		0x1c
-#define H_PUT_TCE		0x20
-#define H_SET_SPRG0		0x24
-#define H_SET_DABR		0x28
-#define H_PAGE_INIT		0x2c
-#define H_SET_ASR		0x30
-#define H_ASR_ON		0x34
-#define H_ASR_OFF		0x38
-#define H_LOGICAL_CI_LOAD	0x3c
-#define H_LOGICAL_CI_STORE	0x40
-#define H_LOGICAL_CACHE_LOAD	0x44
-#define H_LOGICAL_CACHE_STORE	0x48
-#define H_LOGICAL_ICBI		0x4c
-#define H_LOGICAL_DCBF		0x50
-#define H_GET_TERM_CHAR		0x54
-#define H_PUT_TERM_CHAR		0x58
-#define H_REAL_TO_LOGICAL	0x5c
-#define H_HYPERVISOR_DATA	0x60
-#define H_EOI			0x64
-#define H_CPPR			0x68
-#define H_IPI			0x6c
-#define H_IPOLL			0x70
-#define H_XIRR			0x74
-
-#define HSC			".long 0x44000022\n"
-#define H_ENTER_r3		"li	3, 0x08\n"
-
-/* plpar_hcall() -- Generic call interface using above opcodes
- *
- * The actual call interface is a hypervisor call instruction with
- * the opcode in R3 and input args in R4-R7.
- * Status is returned in R3 with variable output values in R4-R11.
- * Only H_PTE_READ with H_READ_4 uses R6-R11 so we ignore it for now
- * and return only two out args which MUST ALWAYS BE PROVIDED.
- */
-long plpar_hcall(unsigned long opcode,
-		 unsigned long arg1,
-		 unsigned long arg2,
-		 unsigned long arg3,
-		 unsigned long arg4,
-		 unsigned long *out1,
-		 unsigned long *out2,
-		 unsigned long *out3);
-
-/* Same as plpar_hcall but for those opcodes that return no values
- * other than status.  Slightly more efficient.
- */
-long plpar_hcall_norets(unsigned long opcode, ...);
-
-
-long plpar_pte_enter(unsigned long flags,
-		     unsigned long ptex,
-		     unsigned long new_pteh, unsigned long new_ptel,
-		     unsigned long *old_pteh_ret, unsigned long *old_ptel_ret)
-{
-	unsigned long dummy, ret;
-	ret = plpar_hcall(H_ENTER, flags, ptex, new_pteh, new_ptel,
-			   old_pteh_ret, old_ptel_ret, &dummy);
-	return(ret);
-}
-
-long plpar_pte_remove(unsigned long flags,
-		      unsigned long ptex,
-		      unsigned long avpn,
-		      unsigned long *old_pteh_ret, unsigned long *old_ptel_ret)
-{
-	unsigned long dummy;
-	return plpar_hcall(H_REMOVE, flags, ptex, avpn, 0,
-			   old_pteh_ret, old_ptel_ret, &dummy);
-}
-
-long plpar_pte_read(unsigned long flags,
-		    unsigned long ptex,
-		    unsigned long *old_pteh_ret, unsigned long *old_ptel_ret)
-{
-	unsigned long dummy;
-	return plpar_hcall(H_READ, flags, ptex, 0, 0,
-			   old_pteh_ret, old_ptel_ret, &dummy);
-}
-
-long plpar_pte_protect(unsigned long flags,
-		       unsigned long ptex,
-		       unsigned long avpn)
-{
-	return plpar_hcall_norets(H_PROTECT, flags, ptex);
-}
+#include <asm/hvcall.h>
 
 long plpar_tce_get(unsigned long liobn,
 		   unsigned long ioba,
@@ -222,357 +102,6 @@
 			   xirr_ret, mfrr_ret, &dummy);
 }
 
-/*
- * The following section contains code that ultimately should
- * be put in the relavent file (htab.c, xics.c, etc).  It has
- * been put here for the time being in order to ease maintainence
- * of the pSeries LPAR code until it can all be put into CVS.
- */
-static void hpte_invalidate_pSeriesLP(unsigned long slot)
-{
-	HPTE old_pte;
-	unsigned long lpar_rc;
-	unsigned long flags = 0;
-			
-	lpar_rc = plpar_pte_remove(flags,
-				   slot,
-				   0,
-				   &old_pte.dw0.dword0, 
-				   &old_pte.dw1.dword1);
-	if (lpar_rc != H_Success) BUG();
-}
-
-/* NOTE: for updatepp ops we are fortunate that the linux "newpp" bits and
- * the low 3 bits of flags happen to line up.  So no transform is needed.
- * We can probably optimize here and assume the high bits of newpp are
- * already zero.  For now I am paranoid.
- */
-static void hpte_updatepp_pSeriesLP(long slot, unsigned long newpp, unsigned long va)
-{
-	unsigned long lpar_rc;
-	unsigned long flags;
-	flags =   newpp & 3;
-	lpar_rc = plpar_pte_protect( flags,
-				     slot,
-				     0);
-	if (lpar_rc != H_Success) {
-		udbg_printf( " bad return code from pte protect rc = %lx \n", lpar_rc); 
-		for (;;);
-	}
-}
-
-static void hpte_updateboltedpp_pSeriesLP(unsigned long newpp, unsigned long ea)
-{
-	unsigned long lpar_rc;
-	unsigned long vsid,va,vpn,flags;
-	long slot;
-
-	vsid = get_kernel_vsid( ea );
-	va = ( vsid << 28 ) | ( ea & 0x0fffffff );
-	vpn = va >> PAGE_SHIFT;
-
-	slot = ppc_md.hpte_find( vpn );
-	flags =   newpp & 3;
-	lpar_rc = plpar_pte_protect( flags,
-				     slot,
-				     0);
-	if (lpar_rc != H_Success) {
-		udbg_printf( " bad return code from pte bolted protect rc = %lx \n", lpar_rc); 
-		for (;;);
-	}
-}
-
-
-static unsigned long hpte_getword0_pSeriesLP(unsigned long slot)
-{
-	unsigned long dword0;
-	unsigned long lpar_rc;
-	unsigned long dummy_word1;
-	unsigned long flags;
-	/* Read 1 pte at a time                        */
-	/* Do not need RPN to logical page translation */
-	/* No cross CEC PFT access                     */
-	flags = 0;
-	
-	lpar_rc = plpar_pte_read(flags,
-				 slot,
-				 &dword0, &dummy_word1);
-	if (lpar_rc != H_Success) {
-		udbg_printf(" error on pte read in get_hpte0 rc = %lx \n", lpar_rc);
-		for (;;);
-	}
-
-	return(dword0);
-}
-
-static long hpte_selectslot_pSeriesLP(unsigned long vpn)
-{
-	unsigned long primary_hash;
-	unsigned long hpteg_slot;
-	unsigned i, k;
-	unsigned long flags;
-	HPTE  pte_read;
-	unsigned long lpar_rc;
-
-	/* Search the primary group for an available slot */
-	primary_hash = hpt_hash(vpn, 0);
-
-	hpteg_slot = ( primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP;
-
-	/* Read 1 pte at a time                        */
-	/* Do not need RPN to logical page translation */
-	/* No cross CEC PFT access                     */
-	flags = 0;
-	for (i=0; i<HPTES_PER_GROUP; ++i) {
-		/* read the hpte entry from the slot */
-		lpar_rc = plpar_pte_read(flags,
-					 hpteg_slot + i,
-					 &pte_read.dw0.dword0, &pte_read.dw1.dword1);
-		if (lpar_rc != H_Success) {
-			udbg_printf(" read of hardware page table failed rc = %lx \n", lpar_rc); 
-			for (;;);
-		}
-		if ( pte_read.dw0.dw0.v == 0 ) {
-			/* If an available slot found, return it */
-			return hpteg_slot + i;
-		}
-
-	}
-
-
-	/* Search the secondary group for an available slot */
-	hpteg_slot = ( ~primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP;
-
-
-	for (i=0; i<HPTES_PER_GROUP; ++i) {
-		/* read the hpte entry from the slot */
-		lpar_rc = plpar_pte_read(flags,
-					 hpteg_slot + i,
-					 &pte_read.dw0.dword0, &pte_read.dw1.dword1);
-		if (lpar_rc != H_Success) {
-			udbg_printf(" read of hardware page table failed2 rc = %lx  \n", lpar_rc); 
-			for (;;);
-		}
-		if ( pte_read.dw0.dw0.v == 0 ) {
-			/* If an available slot found, return it */
-			return hpteg_slot + i;
-		}
-
-	}
-
-	/* No available entry found in secondary group */
-
-
-	/* Select an entry in the primary group to replace */
-
-	hpteg_slot = ( primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP;
-
-	k = htab_data.next_round_robin++ & 0x7;
-
-	for (i=0; i<HPTES_PER_GROUP; ++i) {
-		if (k == HPTES_PER_GROUP)
-			k = 0;
-
-		lpar_rc = plpar_pte_read(flags,
-					 hpteg_slot + k,
-					 &pte_read.dw0.dword0, &pte_read.dw1.dword1);
-		if (lpar_rc != H_Success) {
-			udbg_printf( " pte read failed - rc = %lx", lpar_rc); 
-			for (;;);
-		}
-		if (  ! pte_read.dw0.dw0.bolted)
-		{
-			hpteg_slot += k;
-			/* Invalidate the current entry */
-			ppc_md.hpte_invalidate(hpteg_slot); 
-			return hpteg_slot;
-		}
-		++k;
-	}
-
-	/* No non-bolted entry found in primary group - time to panic */
-	udbg_printf("select_hpte_slot - No non-bolted HPTE in group 0x%lx! \n", hpteg_slot/HPTES_PER_GROUP);
-	udbg_printf("No non-bolted HPTE in group %lx", (unsigned long)hpteg_slot/HPTES_PER_GROUP);
-	for (;;);
-
-	/* never executes - avoid compiler errors */
-	return 0;
-}
-
-
-static void hpte_create_valid_pSeriesLP(unsigned long slot, unsigned long vpn,
-					unsigned long prpn, unsigned hash, 
-					void *ptep, unsigned hpteflags, 
-					unsigned bolted)
-{
-	/* Local copy of HPTE */
-	struct {
-		/* Local copy of first doubleword of HPTE */
-		union {
-			unsigned long d;
-			Hpte_dword0   h;
-		} dw0;
-		/* Local copy of second doubleword of HPTE */
-		union {
-			unsigned long     d;
-			Hpte_dword1       h;
-			Hpte_dword1_flags f;
-		} dw1;
-	} lhpte;
-	
-	unsigned long avpn = vpn >> 11;
-	unsigned long arpn = physRpn_to_absRpn( prpn );
-
-	unsigned long lpar_rc;
-	unsigned long flags;
-	HPTE ret_hpte;
-
-	/* Fill in the local HPTE with absolute rpn, avpn and flags */
-	lhpte.dw1.d        = 0;
-	lhpte.dw1.h.rpn    = arpn;
-	lhpte.dw1.f.flags  = hpteflags;
-
-	lhpte.dw0.d        = 0;
-	lhpte.dw0.h.avpn   = avpn;
-	lhpte.dw0.h.h      = hash;
-	lhpte.dw0.h.bolted = bolted;
-	lhpte.dw0.h.v      = 1;
-
-	/* Now fill in the actual HPTE */
-	/* Set CEC cookie to 0                  */
-	/* Large page = 0                       */
-	/* Zero page = 0                        */
-	/* I-cache Invalidate = 0               */
-	/* I-cache synchronize = 0              */
-	/* Exact = 1 - only modify exact entry  */
-	flags = H_EXACT;
-
-	if (hpteflags & (_PAGE_GUARDED|_PAGE_NO_CACHE))
-		lhpte.dw1.f.flags &= ~_PAGE_COHERENT;
-#if 1
-	__asm__ __volatile__ (
-		 H_ENTER_r3
-		 "mr	4, %1\n"
-		 "mr	5, %2\n"
-		 "mr	6, %3\n"
-		 "mr	7, %4\n"
-		 HSC
-		 "mr	%0, 3\n"
-		 : "=r" (lpar_rc)
-		 : "r" (flags), "r" (slot), "r" (lhpte.dw0.d), "r" (lhpte.dw1.d)
-		 : "r3", "r4", "r5", "r6", "r7", "cc");
-#else
-	lpar_rc =  plpar_pte_enter(flags,
-				   slot,
-				   lhpte.dw0.d,
-				   lhpte.dw1.d,
-				   &ret_hpte.dw0.dword0,
-				   &ret_hpte.dw1.dword1);
-#endif
-	if (lpar_rc != H_Success) {
-		udbg_printf("error on pte enter lapar rc = %ld\n",lpar_rc);
-		udbg_printf("ent: s=%lx, dw0=%lx, dw1=%lx\n", slot, lhpte.dw0.d, lhpte.dw1.d);
-		/* xmon_backtrace("backtrace"); */
-		for (;;);
-	}
-}
-
-static long hpte_find_pSeriesLP(unsigned long vpn)
-{
-	union {
-		unsigned long d;
-		Hpte_dword0   h;
-	} hpte_dw0;
-	long slot;
-	unsigned long hash;
-	unsigned long i,j;
-
-	hash = hpt_hash(vpn, 0);
-	for ( j=0; j<2; ++j ) {
-		slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP;
-		for ( i=0; i<HPTES_PER_GROUP; ++i ) {
-			hpte_dw0.d = hpte_getword0_pSeriesLP( slot );
-			if ( ( hpte_dw0.h.avpn == ( vpn >> 11 ) ) &&
-			     ( hpte_dw0.h.v ) &&
-			     ( hpte_dw0.h.h == j ) ) {
-				/* HPTE matches */
-				if ( j )
-					slot = -slot;
-				return slot;
-			}
-			++slot;
-		}
-		hash = ~hash;
-	}
-	return -1;
-} 
-
-/*
- * Create a pte - LPAR .  Used during initialization only.
- * We assume the PTE will fit in the primary PTEG.
- */
-void make_pte_LPAR(HPTE *htab,
-		   unsigned long va, unsigned long pa, int mode,
-		   unsigned long hash_mask, int large)
-{
-	HPTE  local_hpte, ret_hpte;
-	unsigned long hash, slot, flags,lpar_rc, vpn;
-
-	if (large)
-		vpn = va >> 24;
-	else
-		vpn = va >> 12;
-
-	hash = hpt_hash(vpn, large);
-
-	slot = ((hash & hash_mask)*HPTES_PER_GROUP);
-
-	local_hpte.dw1.dword1 = pa | mode;
-	local_hpte.dw0.dword0 = 0;
-	local_hpte.dw0.dw0.avpn = va >> 23;
-	local_hpte.dw0.dw0.bolted = 1;				/* bolted */
-	if (large)
-		local_hpte.dw0.dw0.l = 1;  /* large page */
-	local_hpte.dw0.dw0.v = 1;
-
-	/* Set CEC cookie to 0                   */
-	/* Zero page = 0                         */
-	/* I-cache Invalidate = 0                */
-	/* I-cache synchronize = 0               */
-	/* Exact = 0 - modify any entry in group */
-	flags = 0;
-#if 1
-	__asm__ __volatile__ (
-		 H_ENTER_r3
-		 "mr	4, %1\n"
-		 "mr	5, %2\n"
-		 "mr	6, %3\n"
-		 "mr	7, %4\n"
-		 HSC
-		 "mr	%0, 3\n"
-		 : "=r" (lpar_rc)
-		 : "r" (flags), "r" (slot), "r" (local_hpte.dw0.dword0), "r" (local_hpte.dw1.dword1)
-		 : "r3", "r4", "r5", "r6", "r7", "cc");
-#else
-	lpar_rc =  plpar_pte_enter(flags,
-				   slot,
-				   local_hpte.dw0.dword0,
-				   local_hpte.dw1.dword1,
-				   &ret_hpte.dw0.dword0,
-				   &ret_hpte.dw1.dword1);
-#endif
-#if 0 /* NOTE: we explicitly do not check return status here because it is
-       * "normal" for early boot code to map io regions for which a partition
-       * has no access.  However, we will die if we actually fault on these
-       * "permission denied" pages.
-       */
-	if (lpar_rc != H_Success) {
-		/* pSeriesLP_init_early(); */
-		udbg_printf("flags=%lx, slot=%lx, dword0=%lx, dword1=%lx, rc=%d\n", flags, slot, local_hpte.dw0.dword0,local_hpte.dw1.dword1, lpar_rc);
-		BUG();
-	}
-#endif
-}
 
 static void tce_build_pSeriesLP(struct TceTable *tbl, long tcenum, 
 				unsigned long uaddr, int direction )
@@ -746,55 +275,6 @@
 }
 
 
-/* This is called early in setup.c.
- * Use it to setup page table ppc_md stuff as well as udbg.
- */
-void pSeriesLP_init_early(void)
-{
-	ppc_md.hpte_invalidate   = hpte_invalidate_pSeriesLP;
-	ppc_md.hpte_updatepp     = hpte_updatepp_pSeriesLP;
-	ppc_md.hpte_updateboltedpp  = hpte_updateboltedpp_pSeriesLP;
-	ppc_md.hpte_getword0     = hpte_getword0_pSeriesLP;
-	ppc_md.hpte_selectslot   = hpte_selectslot_pSeriesLP;
-	ppc_md.hpte_create_valid = hpte_create_valid_pSeriesLP;
-	ppc_md.hpte_find	 = hpte_find_pSeriesLP;
-
-	ppc_md.tce_build	 = tce_build_pSeriesLP;
-	ppc_md.tce_free_one	 = tce_free_one_pSeriesLP;
-
-#ifdef CONFIG_SMP
-	smp_init_pSeries();
-#endif
-	pSeries_pcibios_init_early();
-
-	/* The keyboard is not useful in the LPAR environment.
-	 * Leave all the interfaces NULL.
-	 */
-
-	if (naca->serialPortAddr) {
-		void *comport = (void *)__ioremap(naca->serialPortAddr, 16, _PAGE_NO_CACHE);
-		udbg_init_uart(comport);
-		ppc_md.udbg_putc = udbg_putc;
-		ppc_md.udbg_getc = udbg_getc;
-		ppc_md.udbg_getc_poll = udbg_getc_poll;
-	} else {
-		/* lookup the first virtual terminal number in case we don't have a com port.
-		 * Zero is probably correct in case someone calls udbg before the init.
-		 * The property is a pair of numbers.  The first is the starting termno (the
-		 * one we use) and the second is the number of terminals.
-		 */
-		u32 *termno;
-		struct device_node *np = find_path_device("/rtas");
-		if (np) {
-			termno = (u32 *)get_property(np, "ibm,termno", 0);
-			if (termno)
-				vtermno = termno[0];
-		}
-		ppc_md.udbg_putc = udbg_putcLP;
-		ppc_md.udbg_getc = udbg_getcLP;
-		ppc_md.udbg_getc_poll = udbg_getc_pollLP;
-	}
-}
 
 /* Code for hvc_console.  Should move it back eventually. */
 
@@ -853,3 +333,43 @@
 	}
 	return 0;
 }
+
+#ifndef CONFIG_PPC_ISERIES
+void pSeries_lpar_mm_init(void);
+
+/* This is called early in setup.c.
+ * Use it to setup page table ppc_md stuff as well as udbg.
+ */
+void pSeriesLP_init_early(void)
+{
+	pSeries_lpar_mm_init();
+
+	ppc_md.tce_build	 = tce_build_pSeriesLP;
+	ppc_md.tce_free_one	 = tce_free_one_pSeriesLP;
+
+#ifdef CONFIG_SMP
+	smp_init_pSeries();
+#endif
+	pSeries_pcibios_init_early();
+
+	/* The keyboard is not useful in the LPAR environment.
+	 * Leave all the interfaces NULL.
+	 */
+
+	/* lookup the first virtual terminal number in case we don't have a com port.
+	 * Zero is probably correct in case someone calls udbg before the init.
+	 * The property is a pair of numbers.  The first is the starting termno (the
+	 * one we use) and the second is the number of terminals.
+	 */
+	u32 *termno;
+	struct device_node *np = find_path_device("/rtas");
+	if (np) {
+		termno = (u32 *)get_property(np, "ibm,termno", 0);
+		if (termno)
+			vtermno = termno[0];
+	}
+	ppc_md.udbg_putc = udbg_putcLP;
+	ppc_md.udbg_getc = udbg_getcLP;
+	ppc_md.udbg_getc_poll = udbg_getc_pollLP;
+}
+#endif
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/pSeries_pci.c linux-2.4.20-pre5/arch/ppc64/kernel/pSeries_pci.c
--- linux-2.4.20-pre4/arch/ppc64/kernel/pSeries_pci.c	Wed Aug 28 16:36:45 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/pSeries_pci.c	Wed Aug 28 16:37:31 2002
@@ -22,13 +22,11 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/string.h>
 #include <linux/init.h>
-#include <linux/ide.h>
 #include <linux/bootmem.h>
 
 #include <asm/io.h>
@@ -80,14 +78,12 @@
 	 \
 	if (dn == NULL) { \
 		ret = -2; \
-	} else if (dn->status) { \
-		ret = -1; \
 	} else { \
 		addr = (dn->busno << 16) | (dn->devfn << 8) | offset; \
 		buid = dn->phb->buid; \
 		if (buid) { \
 			ret = rtas_call(ibm_read_pci_config, 4, 2, &returnval, addr, buid >> 32, buid & 0xffffffff, nbytes); \
-                        if (ret < 0) \
+                        if (ret < 0 || (returnval == 0xffffffff)) \
                                ret = rtas_fake_read(dn, offset, nbytes, &returnval); \
 		} else { \
 			ret = rtas_call(read_pci_config, 2, 2, &returnval, addr, nbytes); \
@@ -113,8 +109,6 @@
 	 \
 	if (dn == NULL) { \
 		ret = -2; \
-	} else if (dn->status) { \
-		ret = -1; \
 	} else { \
 		buid = dn->phb->buid; \
 		addr = (dn->busno << 16) | (dn->devfn << 8) | offset; \
@@ -659,13 +653,20 @@
 			continue;
 		}
 
+		if (dev->resource[i].start > dev->resource[i].end) {
+			/* Bogus resource.  Just clear it out. */
+			dev->resource[i].start = dev->resource[i].end = 0;
+			continue;
+		}
+
+
 		if (dev->resource[i].flags & IORESOURCE_IO) {
 			if (is_eeh_implemented()) {
 				unsigned int busno = dev->bus ? dev->bus->number : 0;
 				unsigned long size = dev->resource[i].end - dev->resource[i].start;
 				unsigned long addr = (unsigned long)__ioremap(dev->resource[i].start + phb->io_base_phys, size, _PAGE_NO_CACHE);
 				if (!addr)
-					panic("fixup_resources: ioremap failed!\n");
+					panic("fixup_resources: io ioremap failed!\n");
 				dev->resource[i].start = eeh_token(phb->global_number, busno, dev->devfn, addr) | eeh_disable_bit;
 				dev->resource[i].end = dev->resource[i].start + size;
 			} else {
@@ -685,7 +686,7 @@
 					unsigned long size = dev->resource[i].end - dev->resource[i].start;
 					unsigned long addr = (unsigned long)__ioremap(dev->resource[i].start + phb->pci_mem_offset, size, _PAGE_NO_CACHE);
 					if (!addr)
-						panic("fixup_resources: ioremap failed!\n");
+						panic("fixup_resources: mem ioremap failed!\n");
 					dev->resource[i].start = eeh_token(phb->global_number, busno, dev->devfn, addr) | eeh_disable_bit;
 					dev->resource[i].end = dev->resource[i].start + size;
 				} else {
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/pacaData.c linux-2.4.20-pre5/arch/ppc64/kernel/pacaData.c
--- linux-2.4.20-pre4/arch/ppc64/kernel/pacaData.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/pacaData.c	Wed Aug 28 16:37:31 2002
@@ -7,7 +7,6 @@
  *      2 of the License, or (at your option) any later version.
  */
 
-#define __KERNEL__
 #include <asm/types.h>
 #include <asm/page.h>
 #include <stddef.h>
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/pci.c linux-2.4.20-pre5/arch/ppc64/kernel/pci.c
--- linux-2.4.20-pre4/arch/ppc64/kernel/pci.c	Wed Aug 28 16:36:45 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/pci.c	Wed Aug 28 16:37:31 2002
@@ -74,7 +74,7 @@
 long   Pci_Cfg_Write_Count= 0;
 long   Pci_Error_Count    = 0;
 
-int    Pci_Retry_Max      = 3;	/* Only retry 3 times  */	
+int    Pci_Retry_Max      = 7;	/* Retry set to 7 times  */	
 int    Pci_Error_Flag     = 1;	/* Set Retry Error on. */
 int    Pci_Trace_Flag     = 0;
 
@@ -373,6 +373,8 @@
 	pci_read_config_word(dev, PCI_COMMAND, &cmd);
 	old_cmd = cmd;
 	for(idx=0; idx<6; idx++) {
+		if(!(mask & (1<<idx)))
+			continue;
 		r = &dev->resource[idx];
 		if (!r->start && r->end) {
 			printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name);
@@ -452,9 +454,9 @@
 	iSeries_pcibios_init(); 
 #endif
 
+	ppc64_boot_msg(0x40, "PCI Probe");
 	printk("PCI: Probing PCI hardware\n");
 	PPCDBG(PPCDBG_BUSWALK,"PCI: Probing PCI hardware\n");
-				
 
 	/* Scan all of the recorded PCI controllers.  */
 	for (next_busno = 0, hose = hose_head; hose; hose = hose->next) {
@@ -489,11 +491,13 @@
 #endif
 
 	/* Cache the location of the ISA bridge (if we have one) */
-	if (ppc64_isabridge_dev = pci_find_class(PCI_CLASS_BRIDGE_ISA << 8, NULL))
+	ppc64_isabridge_dev = pci_find_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
+	if (ppc64_isabridge_dev != NULL )
 		printk("ISA bridge at %s\n", ppc64_isabridge_dev->slot_name);
 
 	printk("PCI: Probing PCI hardware done\n");
 	PPCDBG(PPCDBG_BUSWALK,"PCI: Probing PCI hardware done.\n");
+	ppc64_boot_msg(0x41, "PCI Done");
 
 }
 
@@ -511,11 +515,11 @@
 
 void __init pcibios_fixup_bus(struct pci_bus *bus)
 {
+#ifndef CONFIG_PPC_ISERIES
 	struct pci_controller *phb = PCI_GET_PHB_PTR(bus);
 	struct resource *res;
 	int i;
 
-#ifndef CONFIG_PPC_ISERIES
 	if (bus->parent == NULL) {
 		/* This is a host bridge - fill in its resources */
 		phb->bus = bus;
@@ -573,7 +577,7 @@
 	return str;
 }
 
-int pcibios_enable_device(struct pci_dev *dev)
+int pcibios_enable_device(struct pci_dev *dev, int mask)
 {
 	u16 cmd, old_cmd;
 	int idx;
@@ -587,8 +591,6 @@
 	pci_read_config_word(dev, PCI_COMMAND, &cmd);
 	old_cmd = cmd;
 	for (idx=0; idx<6; idx++) {
-		if(!(mask & (1<<idx)))
-			continue;
 		r = &dev->resource[idx];
 		if (!r->start && r->end) {
 			printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name);
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/pci_dma.c linux-2.4.20-pre5/arch/ppc64/kernel/pci_dma.c
--- linux-2.4.20-pre4/arch/ppc64/kernel/pci_dma.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/pci_dma.c	Wed Aug 28 16:37:31 2002
@@ -1389,10 +1389,11 @@
 	PPCDBG(PPCDBG_TCE, "pci_unmap_sg:\n");
 	PPCDBG(PPCDBG_TCE, "\thwdev = 0x%16.16lx, sg = 0x%16.16lx, direction = 0x%16.16lx, nelms = 0x%16.16lx\n", hwdev, sg, direction, nelms);	
 
-	if ( direction == PCI_DMA_NONE )
+	if ( direction == PCI_DMA_NONE || nelms == 0 )
 		BUG();
 
 	dma_start_page = sg->dma_address & PAGE_MASK;
+ 	dma_end_page   = 0;
 	for ( i=nelms; i>0; --i ) {
 		unsigned k = i - 1;
 		if ( sg[k].dma_length ) {
@@ -1408,6 +1409,7 @@
  	/* Client asked for way to much space.  This is checked later anyway */
 	/* It is easier to debug here for the drivers than in the tce tables.*/
  	if(order >= NUM_TCE_LEVELS) {
+		printk("PCI_DMA: dma_start_page:0x%lx  dma_end_page:0x%lx\n",dma_start_page,dma_end_page);
 		printk("PCI_DMA: pci_unmap_sg size to large: 0x%x \n",(numTces << PAGE_SHIFT));
  		return;
  	}
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/pci_dn.c linux-2.4.20-pre5/arch/ppc64/kernel/pci_dn.c
--- linux-2.4.20-pre4/arch/ppc64/kernel/pci_dn.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/pci_dn.c	Wed Aug 28 16:37:31 2002
@@ -249,8 +249,9 @@
 	*eads = *other_eads;
 	eads->devfn &= ~7;	/* make it function zero */
 	eads->tce_table = NULL;
-	/* NOTE: share properties.  We could copy but for now this should suffice.
-	 * The full_name is also incorrect...but seems harmless.
+	/*
+	 * NOTE: share properties.  We could copy but for now this should
+	 * suffice.  The full_name is also incorrect...but seems harmless.
 	 */
 	eads->child = NULL;
 	eads->next = NULL;
@@ -285,21 +286,25 @@
 		dev->sysdata = dn;
 		/* ToDo: call some device init hook here */
 	} else {
-		/* Now it is very possible that we can't find the device because it is
-		 * not the zero'th device of a mutifunction device and we don't have
-		 * permission to read the zero'th device.  If this is the case, Linux
-		 * would ordinarily skip all the other functions.
+		/* Now it is very possible that we can't find the device
+		 * because it is not the zero'th device of a mutifunction
+		 * device and we don't have permission to read the zero'th
+		 * device.  If this is the case, Linux would ordinarily skip
+		 * all the other functions.
 		 */
 		if ((searchval & 0x7) == 0) {
 			struct device_node *thisdevdn;
 			/* Ok, we are looking for fn == 0.  Let's check for other functions. */
 			thisdevdn = (struct device_node *)traverse_pci_devices(phb_dn, is_devfn_sub_node, NULL, (void *)searchval);
 			if (thisdevdn) {
-				/* Ah ha!  There does exist a sub function.  Now this isn't an exact
-				 * match for searchval, but in order to get Linux to believe the sub
-				 * functions exist we will need to manufacture a fake device_node
-				 * for this zero'th function.  To keept this simple for now we only
-				 * handle pci bridges and we just hand back the found node which
+				/* Ah ha!  There does exist a sub function.
+				 * Now this isn't an exact match for
+				 * searchval, but in order to get Linux to
+				 * believe the sub functions exist we will
+				 * need to manufacture a fake device_node for
+				 * this zero'th function.  To keept this
+				 * simple for now we only handle pci bridges
+				 * and we just hand back the found node which
 				 * isn't correct, but Linux won't care.
 				 */
 				char *device_type = (char *)get_property(thisdevdn, "device_type", 0);
@@ -368,7 +373,6 @@
 	}
 }
 
-
 /******************************************************************
  * Fixup the bus->sysdata ptrs to point to the bus' device_node.
  * This is done late in pcibios_init().  We do this mostly for
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/perfmon.c linux-2.4.20-pre5/arch/ppc64/kernel/perfmon.c
--- linux-2.4.20-pre4/arch/ppc64/kernel/perfmon.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre5/arch/ppc64/kernel/perfmon.c	Wed Aug 28 16:37:31 2002
@@ -0,0 +1,404 @@
+/*
+ * This file contains the code to configure and utilize the ppc64 pmc hardware
+ * Copyright (C) 2002 David Engebretsen <engebret@us.ibm.com>
+ */
+
+#include <asm/proc_fs.h>
+#include <asm/paca.h>
+#include <asm/iSeries/ItLpPaca.h>
+#include <asm/iSeries/ItLpQueue.h>
+#include <asm/processor.h>
+#include <linux/proc_fs.h>
+#include <linux/spinlock.h>
+#include <asm/pmc.h>
+#include <asm/uaccess.h>
+#include <asm/naca.h>
+#include <asm/perfmon.h>
+
+extern char _stext[], _etext[], _end[];
+struct perfmon_base_struct perfmon_base = {0, 0, 0, 0, 0, PMC_STATE_INITIAL};
+
+int alloc_perf_buffer(int size);
+int free_perf_buffer(void);
+int clear_buffers(void);
+void pmc_stop(void *data);
+void pmc_start(void *data);
+void pmc_touch_bolted(void *data);
+void dump_pmc_struct(struct perfmon_struct *perfdata);
+void dump_hardware_pmc_struct(void *perfdata);
+int  decr_profile(struct perfmon_struct *perfdata);
+int  pmc_profile(struct perfmon_struct *perfdata);
+int  pmc_set_general(struct perfmon_struct *perfdata);
+int  pmc_set_user_general(struct perfmon_struct *perfdata);
+void pmc_configure(void *data);
+
+asmlinkage int
+sys_perfmonctl (int cmd, void *data) 
+{ 
+	struct perfmon_struct *pdata;
+	int err;
+
+	printk("sys_perfmonctl: cmd = 0x%x\n", cmd); 
+	pdata = kmalloc(sizeof(struct perfmon_struct), GFP_USER);
+	err = __copy_from_user(pdata, data, sizeof(struct perfmon_struct));
+	switch(cmd) {
+	case PMC_OP_ALLOC:
+		alloc_perf_buffer(0); 
+		break;
+	case PMC_OP_FREE:
+		free_perf_buffer(); 
+		break;
+	case PMC_OP_CLEAR:
+		clear_buffers();
+		break;
+	case PMC_OP_DUMP:
+		dump_pmc_struct(pdata);
+		copy_to_user(data, pdata, sizeof(struct perfmon_struct));
+		break;
+	case PMC_OP_DUMP_HARDWARE:
+		dump_hardware_pmc_struct(pdata);
+		smp_call_function(dump_hardware_pmc_struct, (void *)pdata, 0, 1);
+		break;
+	case PMC_OP_DECR_PROFILE: /* NIA time sampling */
+		decr_profile(pdata); 
+		break;
+	case PMC_OP_PMC_PROFILE:
+		pmc_profile(pdata); 
+		break;
+	case PMC_OP_SET:
+		pmc_set_general(pdata); 
+		break;
+	case PMC_OP_SET_USER:
+		pmc_set_user_general(pdata); 
+		break;
+	default:
+		printk("Perfmon: Unknown operation\n");
+		break;
+	}
+
+	kfree(pdata); 
+	return 0;
+}
+
+int alloc_perf_buffer(int size) 
+{
+	int i;
+
+	printk("Perfmon: allocate buffer\n");
+	if(perfmon_base.state == PMC_STATE_INITIAL) {
+		perfmon_base.profile_length = (((unsigned long) &_etext - 
+				   (unsigned long) &_stext) >> 2) * sizeof(int);
+		perfmon_base.profile_buffer = (unsigned long)btmalloc(perfmon_base.profile_length);
+		perfmon_base.trace_length = 1024*1024*16;
+		perfmon_base.trace_buffer = (unsigned long)btmalloc(perfmon_base.trace_length);
+
+		if(perfmon_base.profile_buffer && perfmon_base.trace_buffer) {
+			memset((char *)perfmon_base.profile_buffer, 0, perfmon_base.profile_length);
+			printk("Profile buffer created at address 0x%lx of length 0x%lx\n",
+			       perfmon_base.profile_buffer, perfmon_base.profile_length); 
+		} else {
+			printk("Profile buffer creation failed\n");
+			return 0;
+		}
+
+		/* Fault in the first bolted segment - it then remains in the stab for all time */
+		pmc_touch_bolted(NULL); 
+		smp_call_function(pmc_touch_bolted, (void *)NULL, 0, 1);
+
+		for (i=0; i<MAX_PACAS; ++i) {
+			paca[i].prof_shift = 2;
+			paca[i].prof_len = perfmon_base.profile_length;
+			paca[i].prof_buffer = (unsigned *)(perfmon_base.profile_buffer);
+			paca[i].prof_stext = (unsigned *)&_stext;
+
+			paca[i].prof_etext = (unsigned *)&_etext;
+			mb();
+		} 
+
+		perfmon_base.state = PMC_STATE_READY; 
+	}
+
+	return 0;
+}
+
+int free_perf_buffer() 
+{
+	printk("Perfmon: free buffer\n");
+
+	if(perfmon_base.state == PMC_STATE_INITIAL) {
+		printk("Perfmon: free buffer failed - no buffer was allocated.\n"); 
+		return -1;
+	}
+
+	btfree((void *)perfmon_base.profile_buffer); 
+	btfree((void *)perfmon_base.trace_buffer); 
+
+	perfmon_base.profile_length = 0;
+	perfmon_base.profile_buffer = 0;
+	perfmon_base.trace_buffer   = 0;
+	perfmon_base.trace_length   = 0;
+	perfmon_base.trace_end      = 0;
+	perfmon_base.state = PMC_STATE_INITIAL; 
+
+	return(0); 
+}
+
+int clear_buffers() 
+{
+	if(perfmon_base.state == PMC_STATE_INITIAL) {
+		printk("Perfmon: clear buffer failed - no buffer was allocated.\n"); 
+		return -1;
+	}
+
+	printk("Perfmon: clear buffer\n");
+	
+	/* Stop counters on all processors -- blocking */
+	pmc_stop(NULL); 
+	smp_call_function(pmc_stop, (void *)NULL, 0, 1);
+	
+	/* Clear the buffers */
+	memset((char *)perfmon_base.profile_buffer, 0, perfmon_base.profile_length);
+	memset((char *)perfmon_base.trace_buffer, 0, perfmon_base.trace_length);
+	
+	/* Reset the trace buffer point */
+	perfmon_base.trace_end = 0;
+	
+	/* Restart counters on all processors -- blocking */
+	pmc_start(NULL); 
+	smp_call_function(pmc_start, (void *)NULL, 0, 1);
+
+	return(0); 
+}
+
+void pmc_stop(void *data) 
+{
+	/* Freeze all counters, leave everything else alone */
+	mtspr( MMCR0, mfspr( MMCR0 ) | 0x80000000 );
+}
+
+void pmc_start(void *data) 
+{
+	/* Free all counters, leave everything else alone */
+	mtspr( MMCR0, mfspr( MMCR0 ) & 0x7fffffff );
+}
+
+void pmc_touch_bolted(void *data) 
+{
+	volatile int touch;
+
+	/* Hack to fault the buffer into the segment table */
+	touch = *((int *)(perfmon_base.profile_buffer));
+}
+
+void dump_pmc_struct(struct perfmon_struct *perfdata) 
+{
+	unsigned int cpu = perfdata->vdata.pmc_info.cpu, i;
+
+	if(cpu > MAX_PACAS) return;
+
+	printk("PMC Control Mode: 0x%lx\n", perfmon_base.state);
+	printk("PMC[1 - 2] = 0x%16.16lx 0x%16.16lx\n",
+	       paca[cpu].pmcc[0], paca[cpu].pmcc[1]);
+	printk("PMC[3 - 4] = 0x%16.16lx 0x%16.16lx\n",
+	       paca[cpu].pmcc[2], paca[cpu].pmcc[3]);
+	printk("PMC[5 - 6] = 0x%16.16lx 0x%16.16lx\n",
+	       paca[cpu].pmcc[4], paca[cpu].pmcc[5]);
+	printk("PMC[7 - 8] = 0x%16.16lx 0x%16.16lx\n",
+	       paca[cpu].pmcc[6], paca[cpu].pmcc[7]);
+
+	perfdata->vdata.pmc_info.mode = perfmon_base.state;
+	for(i = 0; i < 11; i++) 
+		perfdata->vdata.pmc_info.pmc_base[i]  = paca[cpu].pmc[i];
+
+	for(i = 0; i < 8; i++) 
+		perfdata->vdata.pmc_info.pmc_cumulative[i]  = paca[cpu].pmcc[i];
+}
+
+void dump_hardware_pmc_struct(void *perfdata) 
+{
+	unsigned int cpu = smp_processor_id();
+
+	printk("PMC[%2.2d][1 - 4]  = 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x\n",
+	       cpu, (u32) mfspr(PMC1),(u32) mfspr(PMC2),(u32) mfspr(PMC3),(u32) mfspr(PMC4));
+	printk("PMC[%2.2d][5 - 8]  = 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x\n",
+	       cpu, (u32) mfspr(PMC5),(u32) mfspr(PMC6),(u32) mfspr(PMC7),(u32) mfspr(PMC8));
+	printk("MMCR[%2.2d][0,1,A] = 0x%8.8x 0x%8.8x 0x%8.8x\n",
+	       cpu, (u32) mfspr(MMCR0),(u32) mfspr(MMCR1),(u32) mfspr(MMCRA));
+}
+
+int decr_profile(struct perfmon_struct *perfdata) 
+{
+	int i;
+
+	printk("Perfmon: NIA decrementer profile\n");
+
+	if(perfmon_base.state == PMC_STATE_INITIAL) {
+		printk("Perfmon: failed - no buffer was allocated.\n"); 
+		return -1;
+	}
+	
+	/* Stop counters on all processors -- blocking */
+	pmc_stop(NULL); 
+	smp_call_function(pmc_stop, (void *)NULL, 0, 1);
+	
+	for (i=0; i<MAX_PACAS; ++i) {
+		paca[i].prof_mode = PMC_STATE_DECR_PROFILE;
+	}
+	
+	perfmon_base.state = PMC_STATE_DECR_PROFILE; 
+	mb(); 
+
+	return 0;
+}
+
+int pmc_profile(struct perfmon_struct *perfdata) 
+{
+	struct pmc_struct *pdata = &(perfdata->vdata.pmc);
+	int i;
+
+	printk("Perfmon: NIA PMC profile and CPI\n");
+
+	if(perfmon_base.state == PMC_STATE_INITIAL) {
+		printk("Perfmon: failed - no buffer was allocated.\n"); 
+		return -1;
+	}
+
+	/* Stop counters on all processors -- blocking */
+	pmc_stop(NULL); 
+	smp_call_function(pmc_stop, (void *)NULL, 0, 1);
+	
+	for (i=0; i<MAX_PACAS; ++i) {
+		paca[i].prof_mode = PMC_STATE_PROFILE_KERN;
+	}
+	perfmon_base.state = PMC_STATE_PROFILE_KERN; 
+
+	pdata->pmc[0] = 0x7f000000;
+	for(i = 1; i < 8; i++) 
+		pdata->pmc[i] = 0x0;
+	pdata->pmc[8] = 0x26000000 | (0x01 << (31 - 25) | (0x1));
+	pdata->pmc[9] = (0x3 << (31-4)); /* Instr completed */
+	pdata->pmc[10] = 0x00000000 | (0x1 << (31 - 30));
+
+	mb();
+
+	pmc_configure((void *)perfdata);
+	smp_call_function(pmc_configure, (void *)perfdata, 0, 0);
+
+	return 0;
+}
+
+int pmc_set_general(struct perfmon_struct *perfdata) 
+{
+	int i;
+
+	printk("Perfmon: PMC sampling - General\n");
+
+	if(perfmon_base.state == PMC_STATE_INITIAL) {
+		printk("Perfmon: failed - no buffer was allocated.\n"); 
+		return -1;
+	}
+
+	/* Stop counters on all processors -- blocking */
+	pmc_stop(NULL); 
+	smp_call_function(pmc_stop, (void *)NULL, 0, 1);
+	
+	for (i=0; i<MAX_PACAS; ++i) {
+		paca[i].prof_mode = PMC_STATE_TRACE_KERN;
+	}
+	perfmon_base.state = PMC_STATE_TRACE_KERN; 
+	mb();
+
+	pmc_configure((void *)perfdata);
+	smp_call_function(pmc_configure, (void *)perfdata, 0, 0);
+
+	return 0;
+}
+
+int pmc_set_user_general(struct perfmon_struct *perfdata) 
+{
+	struct pmc_struct *pdata = &(perfdata->vdata.pmc);
+	int pid = perfdata->header.pid;
+	struct task_struct *task;
+	int i;
+
+	printk("Perfmon: PMC sampling - general user\n");
+
+	if(perfmon_base.state == PMC_STATE_INITIAL) {
+		printk("Perfmon: failed - no buffer was allocated.\n"); 
+		return -1;
+	}
+
+	if(pid) {
+		printk("Perfmon: pid = 0x%x\n", pid);
+		read_lock(&tasklist_lock);
+		task = find_task_by_pid(pid);
+		if (task) {
+			printk("Perfmon: task = 0x%lx\n", (u64) task);
+			task->thread.regs->msr |= 0x4;
+#if 0
+			for(i = 0; i < 11; i++)
+				task->thread.pmc[i] = pdata->pmc[i];
+#endif
+		} else {
+			printk("Perfmon: task not found\n");
+			read_unlock(&tasklist_lock);
+			return -1;
+		}
+	}
+	read_unlock(&tasklist_lock);
+
+	/* Stop counters on all processors -- blocking */
+	pmc_stop(NULL); 
+	smp_call_function(pmc_stop, (void *)NULL, 0, 1);
+	
+	for (i=0; i<MAX_PACAS; ++i) {
+		paca[i].prof_mode = PMC_STATE_TRACE_USER;
+	}
+	perfmon_base.state = PMC_STATE_TRACE_USER; 
+	mb();
+
+	pmc_configure((void *)perfdata);
+	smp_call_function(pmc_configure, (void *)perfdata, 0, 0);
+
+	return 0;
+}
+
+void pmc_configure(void *data)
+{
+	struct paca_struct *lpaca = get_paca();
+	struct perfmon_struct *perfdata = (struct perfmon_struct *)data;
+	struct pmc_struct *pdata = &(perfdata->vdata.pmc);
+	unsigned long cmd_rec, i;
+
+	/* Indicate to hypervisor that we are using the PMCs */
+	if(naca->platform == PLATFORM_ISERIES_LPAR)
+		lpaca->xLpPacaPtr->xPMCRegsInUse = 1;
+
+	/* Freeze all counters */
+	mtspr( MMCR0, 0x80000000 ); mtspr( MMCR1, 0x00000000 );
+
+	cmd_rec = 0xFFUL << 56;
+	cmd_rec |= perfdata->header.type;
+	*((unsigned long *)(perfmon_base.trace_buffer + perfmon_base.trace_end)) = cmd_rec;
+	perfmon_base.trace_end += 8;
+
+	/* Clear all the PMCs */
+	mtspr( PMC1, 0 ); mtspr( PMC2, 0 ); mtspr( PMC3, 0 );
+	mtspr( PMC4, 0 ); mtspr( PMC5, 0 ); mtspr( PMC6, 0 );
+	mtspr( PMC7, 0 ); mtspr( PMC8, 0 );
+
+	for(i = 0; i < 11; i++)
+		lpaca->pmc[i]  = pdata->pmc[i];
+
+	mtspr(PMC1, lpaca->pmc[0]); mtspr(PMC2, lpaca->pmc[1]);
+	mtspr(PMC3, lpaca->pmc[2]); mtspr(PMC4, lpaca->pmc[3]);
+	mtspr(PMC5, lpaca->pmc[4]); mtspr(PMC6, lpaca->pmc[5]);
+	mtspr(PMC7, lpaca->pmc[6]); mtspr(PMC8, lpaca->pmc[7]);
+	mtspr(MMCR1, lpaca->pmc[9]); mtspr(MMCRA, lpaca->pmc[10]);
+
+	mb();
+	
+	/* Start all counters */
+	mtspr( MMCR0, lpaca->pmc[8]);
+}
+
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/pmc.c linux-2.4.20-pre5/arch/ppc64/kernel/pmc.c
--- linux-2.4.20-pre4/arch/ppc64/kernel/pmc.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/pmc.c	Wed Aug 28 16:37:31 2002
@@ -31,7 +31,7 @@
 
 #include <linux/proc_fs.h>
 #include <linux/spinlock.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <asm/pmc.h>
 #include <asm/uaccess.h>
@@ -39,6 +39,10 @@
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
 #include <asm/mmu_context.h>
+#include <asm/page.h>
+#include <asm/machdep.h>
+#include <asm/lmb.h>
+#include <asm/abs_addr.h>
 #include <asm/ppcdebug.h>
 
 struct _pmc_sw pmc_sw_system = {
@@ -69,6 +73,8 @@
 struct mm_struct btmalloc_mm = {pgd             : bolted_dir,
                                 page_table_lock : SPIN_LOCK_UNLOCKED};
 
+extern spinlock_t hash_table_lock;
+
 char *
 ppc64_pmc_stab(int file)
 {
@@ -204,15 +210,16 @@
 void* btmalloc (unsigned long size) {
 	pgd_t *pgdp;
 	pmd_t *pmdp;
-	pte_t *ptep;
-	unsigned long ea_base, ea;
+	pte_t *ptep, pte;
+	unsigned long ea_base, ea, hpteflags;
 	struct vm_struct *area;
-	unsigned long pa, pg_count, page, vsid;
+	unsigned long pa, pg_count, page, vsid, slot, va, arpn, vpn;
   
 	size = PAGE_ALIGN(size);
 	if (!size || (size >> PAGE_SHIFT) > num_physpages) return NULL;
 
 	spin_lock(&btmalloc_mm.page_table_lock);
+	spin_lock(&hash_table_lock);
 
 	/* Get a virtual address region in the bolted space */
 	area = get_btm_area(size, 0);
@@ -228,6 +235,10 @@
 	for(page = 0; page < pg_count; page++) {
 		pa = get_free_page(GFP_KERNEL) - PAGE_OFFSET; 
 		ea = ea_base + (page * PAGE_SIZE);
+		vsid = get_kernel_vsid(ea);
+		va = ( vsid << 28 ) | ( pa & 0xfffffff );
+		vpn = va >> PAGE_SHIFT;
+		arpn = ((unsigned long)__v2a(ea)) >> PAGE_SHIFT;
 
 		/* Get a pointer to the linux page table entry for this page
 		 * allocating pmd or pte pages along the way as needed.  Note
@@ -236,15 +247,23 @@
 		pgdp = pgd_offset_b(ea);
 		pmdp = pmd_alloc(&btmalloc_mm, pgdp, ea);
 		ptep = pte_alloc(&btmalloc_mm, pmdp, ea);
+		pte = *ptep;
 
 		/* Clear any old hpte and set the new linux pte */
 		set_pte(ptep, mk_pte_phys(pa & PAGE_MASK, PAGE_KERNEL));
 
-		vsid = get_kernel_vsid(ea);
-		build_valid_hpte(vsid, ea, pa, ptep, 
-				  _PAGE_ACCESSED|_PAGE_COHERENT|PP_RWXX, 1);
+		hpteflags = _PAGE_ACCESSED|_PAGE_COHERENT|PP_RWXX;
+
+		pte_val(pte) &= ~_PAGE_HPTEFLAGS;
+		pte_val(pte) |= _PAGE_HASHPTE;
+
+		slot = ppc_md.hpte_insert(vpn, arpn, hpteflags, 1, 0);  
+
+		pte_val(pte) |= ((slot<<12) & 
+				 (_PAGE_GROUP_IX | _PAGE_SECONDARY));
 	}
 
+	spin_unlock(&hash_table_lock);
 	spin_unlock(&btmalloc_mm.page_table_lock);
 	return (void*)ea_base;
 }
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/ppc_ksyms.c linux-2.4.20-pre5/arch/ppc64/kernel/ppc_ksyms.c
--- linux-2.4.20-pre4/arch/ppc64/kernel/ppc_ksyms.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/ppc_ksyms.c	Wed Aug 28 16:37:31 2002
@@ -40,15 +40,18 @@
 #include <asm/machdep.h>
 #include <asm/hw_irq.h>
 #include <asm/abs_addr.h>
-#ifdef CONFIG_SMP
 #include <asm/smplock.h>
-#endif /* CONFIG_SMP */
 #ifdef CONFIG_PPC_ISERIES
 #include <asm/iSeries/iSeries_pci.h>
 #include <asm/iSeries/iSeries_proc.h>
 #include <asm/iSeries/mf.h>
 #include <asm/iSeries/HvLpEvent.h>
 #include <asm/iSeries/HvLpConfig.h>
+#include <asm/iSeries/ItLpNaca.h>
+#include <asm/iSeries/ItExtVpdPanel.h>
+#include <asm/iSeries/LparData.h>
+#else
+#include <asm/rtas.h>
 #endif
 
 /* Tell string.h we don't want memcpy etc. as cpp defines */
@@ -61,6 +64,7 @@
 extern void AlignmentException(struct pt_regs *regs);
 extern void ProgramCheckException(struct pt_regs *regs);
 extern void SingleStepException(struct pt_regs *regs);
+extern int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
 extern int sys_sigreturn(struct pt_regs *regs);
 extern int do_signal(sigset_t *, struct pt_regs *);
 extern int register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int, unsigned int, unsigned long, struct file *));
@@ -82,6 +86,7 @@
 EXPORT_SYMBOL(AlignmentException);
 EXPORT_SYMBOL(ProgramCheckException);
 EXPORT_SYMBOL(SingleStepException);
+EXPORT_SYMBOL(sys_ioctl);
 EXPORT_SYMBOL(sys_sigreturn);
 EXPORT_SYMBOL(enable_irq);
 EXPORT_SYMBOL(disable_irq);
@@ -160,6 +165,8 @@
 EXPORT_SYMBOL(mf_allocateLpEvents);
 EXPORT_SYMBOL(mf_deallocateLpEvents);
 EXPORT_SYMBOL(HvLpConfig_getLpIndex_outline);
+EXPORT_SYMBOL(itLpNaca);
+EXPORT_SYMBOL(xItExtVpdPanel);
 #endif
 
 EXPORT_SYMBOL(_insb);
@@ -189,6 +196,8 @@
 EXPORT_SYMBOL(iSeries_Read_Long);
 EXPORT_SYMBOL(iSeries_Device_ToggleReset);
 EXPORT_SYMBOL(iSeries_Write_Word);
+EXPORT_SYMBOL(iSeries_memset_io);
+EXPORT_SYMBOL(iSeries_memcpy_toio);
 EXPORT_SYMBOL(iSeries_memcpy_fromio);
 EXPORT_SYMBOL(iSeries_Read_Word);
 EXPORT_SYMBOL(iSeries_Read_Byte);
@@ -238,6 +247,13 @@
 EXPORT_SYMBOL(find_all_nodes);
 EXPORT_SYMBOL(get_property);
 
+#ifdef CONFIG_PPC_PSERIES
+EXPORT_SYMBOL(rtas_proc_dir);
+EXPORT_SYMBOL(rtas_firmware_flash_list);
+EXPORT_SYMBOL(rtas_token);
+EXPORT_SYMBOL(rtas_call);
+#endif
+
 #ifndef CONFIG_PPC_ISERIES
 EXPORT_SYMBOL(kd_mksound);
 #endif
@@ -288,3 +304,8 @@
 #endif
 
 EXPORT_SYMBOL(tb_ticks_per_usec);
+
+#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)
+extern void dump_send_ipi(int (*dump_ipi_callback)(struct pt_regs *));
+EXPORT_SYMBOL(dump_send_ipi);
+#endif
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/proc_pmc.c linux-2.4.20-pre5/arch/ppc64/kernel/proc_pmc.c
--- linux-2.4.20-pre4/arch/ppc64/kernel/proc_pmc.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/proc_pmc.c	Wed Aug 28 16:37:31 2002
@@ -41,6 +41,8 @@
 #include <asm/pmc.h>
 #include <asm/uaccess.h>
 #include <asm/naca.h>
+#include <asm/rtas.h>
+#include <asm/perfmon.h>
 
 /* pci Flight Recorder AHT */
 extern void proc_pciFr_init(struct proc_dir_entry *proc_ppc64_root);
@@ -63,6 +65,10 @@
 			     int count, int *eof, void *data);
 int proc_ppc64_pmc_htab_read(char *page, char **start, off_t off,
 			     int count, int *eof, void *data);
+int proc_ppc64_pmc_profile_read(char *page, char **start, off_t off,
+				int count, int *eof, void *data);
+int proc_ppc64_pmc_profile_read(char *page, char **start, off_t off,
+				int count, int *eof, void *data);
 int proc_ppc64_pmc_hw_read(char *page, char **start, off_t off, 
 			   int count, int *eof, void *data);
 
@@ -88,6 +94,34 @@
 int proc_pmc_set_pmc7(  struct file *file, const char *buffer, unsigned long count, void *data);
 int proc_pmc_set_pmc8(  struct file *file, const char *buffer, unsigned long count, void *data);
 
+static loff_t  nacamap_seek( struct file *file, loff_t off, int whence);
+static ssize_t nacamap_read( struct file *file, char *buf, size_t nbytes, loff_t *ppos);
+static int     nacamap_mmap( struct file *file, struct vm_area_struct *vma );
+
+static struct file_operations nacamap_fops = {
+	llseek:	nacamap_seek,
+	read:	nacamap_read,
+	mmap:	nacamap_mmap
+};
+
+static ssize_t read_profile(struct file *file, char *buf, size_t count, loff_t *ppos);
+static ssize_t write_profile(struct file * file, const char * buf,
+			     size_t count, loff_t *ppos);
+static ssize_t read_trace(struct file *file, char *buf, size_t count, loff_t *ppos);
+static ssize_t write_trace(struct file * file, const char * buf,
+			     size_t count, loff_t *ppos);
+
+static struct file_operations proc_profile_operations = {
+	read:		read_profile,
+	write:		write_profile,
+};
+
+static struct file_operations proc_trace_operations = {
+	read:		read_trace,
+	write:		write_trace,
+};
+
+extern struct perfmon_base_struct perfmon_base;
 
 void proc_ppc64_init(void)
 {
@@ -107,8 +141,14 @@
 	if (!proc_ppc64_root) return;
 	spin_unlock(&proc_ppc64_lock);
 
-	/* /proc/ppc64/naca -- raw naca contents.  Only readable to root */
-	create_proc_read_entry("naca", S_IRUSR, proc_ppc64_root, proc_ppc64_page_read, naca);
+	ent = create_proc_entry("naca", S_IFREG|S_IRUGO, proc_ppc64_root);
+	if ( ent ) {
+		ent->nlink = 1;
+		ent->data = 0;
+		ent->size = 4096;
+		ent->proc_fops = &nacamap_fops;
+	}
+
 	/* /proc/ppc64/paca/XX -- raw paca contents.  Only readable to root */
 	ent = proc_mkdir("paca", proc_ppc64_root);
 	if (ent) {
@@ -116,6 +156,9 @@
 			proc_ppc64_create_paca(i, ent);
 	}
 
+	/* Placeholder for rtas interfaces. */
+	rtas_proc_dir = proc_mkdir("rtas", proc_ppc64_root);
+
 	/* Create the /proc/ppc64/pcifr for the Pci Flight Recorder.	 */
 	proc_pciFr_init(proc_ppc64_root);
 
@@ -167,6 +210,20 @@
 		ent->write_proc = (void *)proc_ppc64_pmc_htab_read;
 	}
 
+	ent = create_proc_entry("profile", S_IWUSR | S_IRUGO, proc_ppc64_pmc_system_root);
+	if (ent) {
+		ent->nlink = 1;
+		ent->proc_fops = &proc_profile_operations;
+		/* ent->size = (1+prof_len) * sizeof(unsigned int); */
+	}
+
+	ent = create_proc_entry("trace", S_IWUSR | S_IRUGO, proc_ppc64_pmc_system_root);
+	if (ent) {
+		ent->nlink = 1;
+		ent->proc_fops = &proc_trace_operations;
+		/* ent->size = (1+prof_len) * sizeof(unsigned int); */
+	}
+
 	/* Create directories for the hardware counters. */
 	for (i = 0; i < naca->processorCount; i++) {
 		ent = create_proc_entry("hardware", S_IRUGO | S_IWUSR, 
@@ -336,6 +393,60 @@
 	return n;
 }
 
+static ssize_t read_profile(struct file *file, char *buf,
+			    size_t count, loff_t *ppos)
+{
+	unsigned long p = *ppos;
+	ssize_t read;
+	char * pnt;
+	unsigned int sample_step = 4;
+
+	if (p >= (perfmon_base.profile_length+1)) return 0;
+	if (count > (perfmon_base.profile_length+1) - p)
+		count = (perfmon_base.profile_length+1) - p;
+	read = 0;
+
+	while (p < sizeof(unsigned int) && count > 0) {
+		put_user(*((char *)(&sample_step)+p),buf);
+		buf++; p++; count--; read++;
+	}
+	pnt = (char *)(perfmon_base.profile_buffer) + p - sizeof(unsigned int);
+	copy_to_user(buf,(void *)pnt,count);
+	read += count;
+	*ppos += read;
+	return read;
+}
+
+static ssize_t read_trace(struct file *file, char *buf,
+			    size_t count, loff_t *ppos)
+{
+	unsigned long p = *ppos;
+	ssize_t read;
+	char * pnt;
+	unsigned int sample_step = 4;
+
+	if (p >= (perfmon_base.trace_length)) return 0;
+	if (count > (perfmon_base.trace_length) - p)
+		count = (perfmon_base.trace_length) - p;
+	read = 0;
+
+	pnt = (char *)(perfmon_base.trace_buffer) + p; //  - sizeof(unsigned int);
+	copy_to_user(buf,(void *)pnt,count);
+	read += count;
+	*ppos += read;
+	return read;
+}
+
+static ssize_t write_trace(struct file * file, const char * buf,
+			     size_t count, loff_t *ppos)
+{
+}
+
+static ssize_t write_profile(struct file * file, const char * buf,
+			     size_t count, loff_t *ppos)
+{
+}
+
 int 
 proc_ppc64_pmc_hw_read(char *page, char **start, off_t off, 
 			     int count, int *eof, void *data)
@@ -377,6 +488,7 @@
     if (!ent) return;
     ent->nlink = 1;
     ent->data = (void *)0;
+    ent->size = 0;
     ent->read_proc = proc_get_titanTod;
     ent->write_proc = NULL;
 
@@ -838,3 +950,73 @@
 	return count;
 }
 
+static loff_t nacamap_seek( struct file *file, loff_t off, int whence)
+{
+	loff_t new;
+	struct proc_dir_entry *dp;
+
+	dp = file->f_dentry->d_inode->u.generic_ip;
+
+	switch(whence) {
+	case 0:
+		new = off;
+		break;
+	case 1:
+		new = file->f_pos + off;
+		break;
+	case 2:
+		new = dp->size + off;
+		break;
+	default:
+		return -EINVAL;
+	}
+	if ( new < 0 || new > dp->size )
+		return -EINVAL;
+	return (file->f_pos = new);
+}
+
+static ssize_t nacamap_read( struct file *file, char *buf, size_t nbytes, loff_t *ppos)
+{
+	unsigned pos = *ppos;
+	unsigned size;
+	char * fromaddr;
+	struct proc_dir_entry *dp;
+
+	dp = file->f_dentry->d_inode->u.generic_ip;
+
+	size = dp->size;
+	if ( pos >= size )
+		return 0;
+	if ( nbytes >= size )
+		nbytes = size;
+	if ( pos + nbytes > size )
+		nbytes = size - pos;
+	fromaddr = (char *)(KERNELBASE + 0x4000 + pos);
+
+	copy_to_user( buf, fromaddr, nbytes );
+	*ppos = pos + nbytes;
+	return nbytes;
+}
+
+static int nacamap_mmap( struct file *file, struct vm_area_struct *vma )
+{
+	unsigned long pa;
+	long size;
+	long fsize;
+	struct proc_dir_entry *dp;
+
+	dp = file->f_dentry->d_inode->u.generic_ip;
+
+	pa = 0x4000;
+	fsize = 4096;
+
+	vma->vm_flags |= VM_SHM | VM_LOCKED;
+
+	size = vma->vm_end - vma->vm_start;
+	if ( size != 4096 )
+		return -EINVAL;
+
+	remap_page_range( vma->vm_start, pa, 4096, vma->vm_page_prot );
+	return 0;
+}
+
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/process.c linux-2.4.20-pre5/arch/ppc64/kernel/process.c
--- linux-2.4.20-pre4/arch/ppc64/kernel/process.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/process.c	Wed Aug 28 16:37:31 2002
@@ -278,87 +278,45 @@
 	current->thread.fpscr = 0;
 }
 
-asmlinkage int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6,
-			 struct pt_regs *regs)
+int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6,
+	      struct pt_regs *regs)
 {
-	unsigned long clone_flags = p1;
-	int res;
-
-	PPCDBG(PPCDBG_SYS64, "sys_clone - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-
-	res = do_fork(clone_flags, regs->gpr[1], regs, 0);
-#ifdef CONFIG_SMP
-	/* When we clone the idle task we keep the same pid but
-	 * the return value of 0 for both causes problems.
-	 * -- Cort
-	 */
-	if ((current->pid == 0) && (current == &init_task))
-		res = 1;
-#endif /* CONFIG_SMP */
-
-	PPCDBG(PPCDBG_SYS64, "sys_clone - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-
-	return res;
+	return do_fork(p1, regs->gpr[1], regs, 0);
 }
 
-asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6,
-			struct pt_regs *regs)
+int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6,
+	     struct pt_regs *regs)
 {
-	int res;
-	
-	PPCDBG(PPCDBG_SYS64, "sys_fork - entered - pid=%ld comm=%s \n", current->pid, current->comm);
-
-	res = do_fork(SIGCHLD, regs->gpr[1], regs, 0);
-
-#ifdef CONFIG_SMP
-	/* When we clone the idle task we keep the same pid but
-	 * the return value of 0 for both causes problems.
-	 * -- Cort
-	 */
-	if ((current->pid == 0) && (current == &init_task))
-		res = 1;
-#endif /* CONFIG_SMP */
-	
-	PPCDBG(PPCDBG_SYS64, "sys_fork - exited - pid=%ld comm=%s \n", current->pid, current->comm);
-
-	return res;
+	return do_fork(SIGCHLD, regs->gpr[1], regs, 0);
 }
 
-asmlinkage int sys_vfork(int p1, int p2, int p3, int p4, int p5, int p6,
+int sys_vfork(int p1, int p2, int p3, int p4, int p5, int p6,
 			 struct pt_regs *regs)
 {
-  	PPCDBG(PPCDBG_SYS64, "sys_vfork - running - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-
 	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gpr[1], regs, 0);
 }
 
-asmlinkage int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
-			  unsigned long a3, unsigned long a4, unsigned long a5,
-			  struct pt_regs *regs)
+int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
+	       unsigned long a3, unsigned long a4, unsigned long a5,
+	       struct pt_regs *regs)
 {
 	int error;
 	char * filename;
-
-	PPCDBG(PPCDBG_SYS64, "sys_execve - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-
+	
 	filename = getname((char *) a0);
 	error = PTR_ERR(filename);
 	if (IS_ERR(filename))
 		goto out;
 	if (regs->msr & MSR_FP)
 		giveup_fpu(current);
-
-	PPCDBG(PPCDBG_SYS64, "sys_execve - before do_execve : filename = %s\n", filename);
-
+  
 	error = do_execve(filename, (char **) a1, (char **) a2, regs);
-
+  
 	if (error == 0)
 		current->ptrace &= ~PT_DTRACE;
 	putname(filename);
 
-  out:
-	PPCDBG(PPCDBG_SYS64, "sys_execve - exited - pid=%ld current=%lx comm=%s error = %lx\n", current->pid, current, current->comm, error);
-
+out:
 	return error;
 }
 
@@ -405,7 +363,7 @@
 	 * __get_free_pages() might give us a page > KERNBASE+256M which
 	 * is mapped with large ptes so we can't set up the guard page.
 	 */
-	if (__is_processor(PV_POWER4))
+	if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p))
 		return;
 
 	for (i=0; i < naca->processorCount; i++) {
@@ -469,10 +427,10 @@
 
 	printk("Call backtrace: \n");
 	while (sp) {
-		if (__get_user( i, &sp[2] ))
+		if (__get_user(i, &sp[2]))
 			break;
 		printk("%016lX ", i);
-		printk("%s\n", ppc_find_proc_name( (unsigned *)i, name_buf, 256 ));
+		printk("%s\n", ppc_find_proc_name((unsigned *)i, name_buf, 256));
 		if (cnt > 32) break;
 		if (__get_user(sp, (unsigned long **)sp))
 			break;
@@ -499,7 +457,7 @@
 	do {
 		sp = *(unsigned long *)sp;
 		if (sp < (stack_page + (2 * PAGE_SIZE)) ||
-		    sp >= (stack_page + (THREAD_SIZE * PAGE_SIZE)))
+		    sp >= (stack_page + THREAD_SIZE))
 			return 0;
 		if (count > 0) {
 			ip = *(unsigned long *)(sp + 16);
@@ -524,7 +482,7 @@
 	do {
 		sp = *(unsigned long *)sp;
 		if (sp < (stack_page + (2 * PAGE_SIZE)) ||
-		    sp >= (stack_page + (THREAD_SIZE * PAGE_SIZE)))
+		    sp >= (stack_page + THREAD_SIZE))
 			break;
 		if (count > 0) {
 			ip = *(unsigned long *)(sp + 16);
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/prom.c linux-2.4.20-pre5/arch/ppc64/kernel/prom.c
--- linux-2.4.20-pre4/arch/ppc64/kernel/prom.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/prom.c	Wed Aug 28 16:37:31 2002
@@ -1,4 +1,4 @@
-/*
+/* - undefined for user space
  * 
  *
  * Procedures for interfacing to Open Firmware.
@@ -217,7 +217,10 @@
 
 void cacheable_memzero(void *, unsigned int);
 
-extern char cmd_line[512];	/* XXX */
+#ifndef CONFIG_CMDLINE
+#define CONFIG_CMDLINE ""
+#endif
+char cmd_line[512] = CONFIG_CMDLINE;
 unsigned long dev_tree_size;
 
 #ifdef CONFIG_HMT
@@ -340,6 +343,7 @@
 	struct prom_t *_prom = PTRRELOC(&prom);
         struct naca_struct *_naca = RELOC(naca);
 
+	/* NOTE: _naca->debug_switch is already initialized. */
 #ifdef DEBUG_PROM
 	prom_print(RELOC("prom_initialize_naca: start...\n"));
 #endif
@@ -358,23 +362,43 @@
 			 * d-cache and i-cache sizes... -Peter
 			 */
 			if ( num_cpus == 1 ) {
-				u32 size;
+				u32 size, lsize, sets;
 
 				call_prom(RELOC("getprop"), 4, 1, node,
-					  RELOC("d-cache-line-size"),
+					  RELOC("d-cache-size"),
 					  &size, sizeof(size));
 
-				_naca->dCacheL1LineSize     = size;
-				_naca->dCacheL1LogLineSize  = __ilog2(size);
-				_naca->dCacheL1LinesPerPage = PAGE_SIZE / size;
+				call_prom(RELOC("getprop"), 4, 1, node,
+					  RELOC("d-cache-line-size"),
+					  &lsize, sizeof(lsize));
+
+				call_prom(RELOC("getprop"), 4, 1, node,
+					  RELOC("d-cache-sets"),
+					  &sets, sizeof(sets));
+
+				_naca->dCacheL1Size         = size;
+				_naca->dCacheL1LineSize     = lsize;
+				_naca->dCacheL1LogLineSize  = __ilog2(lsize);
+				_naca->dCacheL1LinesPerPage = PAGE_SIZE/lsize;
+				_naca->dCacheL1Assoc = size / lsize / sets;
 
 				call_prom(RELOC("getprop"), 4, 1, node,
 					  RELOC("i-cache-line-size"),
 					  &size, sizeof(size));
 
-				_naca->iCacheL1LineSize     = size;
-				_naca->iCacheL1LogLineSize  = __ilog2(size);
-				_naca->iCacheL1LinesPerPage = PAGE_SIZE / size;
+				call_prom(RELOC("getprop"), 4, 1, node,
+					  RELOC("i-cache-line-size"),
+					  &lsize, sizeof(lsize));
+
+				call_prom(RELOC("getprop"), 4, 1, node,
+					  RELOC("i-cache-sets"),
+					  &sets, sizeof(sets));
+
+				_naca->iCacheL1Size         = size;
+				_naca->iCacheL1LineSize     = lsize;
+				_naca->iCacheL1LogLineSize  = __ilog2(lsize);
+				_naca->iCacheL1LinesPerPage = PAGE_SIZE/lsize;
+				_naca->iCacheL1Assoc = size / lsize / sets;
 
 				if (_naca->platform == PLATFORM_PSERIES_LPAR) {
 					u32 pft_size[2];
@@ -477,6 +501,11 @@
 	 */
 	_naca->slb_size = 64;
 
+	/* Add an eye catcher and the naca layout version number */
+	strcpy(_naca->eye_catcher, RELOC("PPC64"));
+	_naca->version     = 1;
+	_naca->processor   = _get_PVR() >> 16;
+
 #ifdef DEBUG_PROM
         prom_print(RELOC("naca->processorCount       = 0x"));
         prom_print_hex(_naca->processorCount);
@@ -620,8 +649,8 @@
 }
 
 
-static unsigned long __init
-prom_instantiate_rtas(unsigned long mem)
+static void __init
+prom_instantiate_rtas(void)
 {
 	unsigned long offset = reloc_offset();
 	struct prom_t *_prom = PTRRELOC(&prom);
@@ -654,16 +683,18 @@
 	        _rtas->size = getprop_rval;
 		prom_print(RELOC("instantiating rtas"));
 		if (_rtas->size != 0) {
-			/*
-			 * Ask OF for some space for RTAS.
-			 * Actually OF has bugs so we just arbitrarily
-			 * use memory at the 6MB point.
+			unsigned long rtas_region = RTAS_INSTANTIATE_MAX;
+
+			/* Grab some space within the first RTAS_INSTANTIATE_MAX bytes
+			 * of physical memory (or within the RMO region) because RTAS
+			 * runs in 32-bit mode and relocate off.
 			 */
-			// The new code...
-			mem = PAGE_ALIGN(mem);
-			_rtas->base = mem + offset - KERNELBASE;
+			if ( _naca->platform == PLATFORM_PSERIES_LPAR ) {
+				struct lmb *_lmb  = PTRRELOC(&lmb);
+				rtas_region = min(_lmb->rmo_size, RTAS_INSTANTIATE_MAX);
+			}
+			_rtas->base = lmb_alloc_base(_rtas->size, PAGE_SIZE, rtas_region);
 
-			mem += _rtas->size;
 			prom_print(RELOC(" at 0x"));
 			prom_print_hex(_rtas->base);
 
@@ -700,8 +731,6 @@
 #ifdef DEBUG_PROM
 	prom_print(RELOC("prom_instantiate_rtas: end...\n"));
 #endif
-
-	return mem;
 }
 
 unsigned long prom_strtoul(const char *cp)
@@ -912,8 +941,6 @@
 			    (strstr(model, RELOC("peedwagon")) == NULL) &&
 			    (strstr(model, RELOC("innipeg")) == NULL))
 				continue;
-		} else {
-			prom_print(RELOC("No known I/O bridge chip found.\n"));
 		}
 
 		if ((type[0] == 0) || (strstr(type, RELOC("pci")) == NULL)) {
@@ -1231,6 +1258,110 @@
 #endif
 }
 
+#ifdef CONFIG_PPCDBG
+extern char *trace_names[];	/* defined in udbg.c -- need a better interface */
+
+static void parse_ppcdbg_optionlist(const char *cmd,
+				    const char *cmdend)
+{
+	unsigned long offset = reloc_offset();
+	char **_trace_names = PTRRELOC(&trace_names[0]);
+	const char *all = RELOC("all");
+        struct naca_struct *_naca = RELOC(naca);
+	const char *p, *pend;
+	int onoff, i, cmdidx;
+	unsigned long mask;
+	char cmdbuf[30];
+
+	for (p = cmd, pend = strchr(p, ',');
+	     p < cmdend;
+	     pend = strchr(p, ',')) {
+		if (pend == NULL || pend > cmdend)
+			pend = cmdend;
+		onoff = 1;	/* default */
+		if (*p == '+' || *p == '-') {
+			/* explicit on or off */
+			onoff = (*p == '+');
+			p++;
+		}
+		/* parse out p..pend here */
+		if (pend - p < sizeof(cmdbuf)) {
+			strncpy(cmdbuf, p, pend - p);
+			cmdbuf[pend - p] = '\0';
+			for (cmdidx = -1, i = 0; i < PPCDBG_NUM_FLAGS; i++) {
+				if (_trace_names[i] &&
+				    (strcmp(PTRRELOC(_trace_names[i]), cmdbuf) == 0)) {
+					cmdidx = i;
+					break;
+				}
+			}
+			mask = 0;
+			if (cmdidx >= 0) {
+				mask = (1 << cmdidx);
+			} else if (strcmp(cmdbuf, all) == 0) {
+				mask = PPCDBG_ALL;
+			} else {
+				prom_print(RELOC("ppcdbg: unknown debug: "));
+				prom_print(cmdbuf);
+				prom_print_nl();
+			}
+			if (mask) {
+				if (onoff)
+					_naca->debug_switch |= mask;
+				else
+					_naca->debug_switch &= ~mask;
+			}
+		}
+		p = pend+1;
+	}
+}
+
+/*
+ * Parse ppcdbg= cmdline option.
+ *
+ * Option names are listed in <asm/ppcdebug.h> in the trace_names
+ * table.  Multiple names may be listed separated by commas (no whitespace),
+ * and each option may be preceeded by a + or - to force on or off state.
+ * The special option "all" may also be used.  They are processed strictly
+ * left to right.  Multiple ppcdbg= options are the command line are treated
+ * as a single option list.
+ *
+ * Examples:  ppcdbg=phb_init,buswalk
+ *            ppcdbg=all,-mm,-tce
+ *
+ * ToDo: add "group" names that map to common combinations of flags.
+ */
+void parse_ppcdbg_cmd_line(const char *line)
+{
+	unsigned long offset = reloc_offset();
+	const char *ppcdbgopt = RELOC("ppcdbg=");
+	struct naca_struct *_naca = RELOC(naca);
+	const char *cmd, *end;
+
+	_naca->debug_switch = PPC_DEBUG_DEFAULT; /* | PPCDBG_BUSWALK | PPCDBG_PHBINIT | PPCDBG_MM | PPCDBG_MMINIT | PPCDBG_TCEINIT | PPCDBG_TCE */
+	cmd = line;
+	while (cmd && (cmd = strstr(cmd, ppcdbgopt)) != NULL) {
+		cmd += 7;	/* skip ppcdbg= */
+		for (end = cmd;
+		     *end != '\0' && *end != '\t' && *end != ' ';
+		     end++)
+			; /* scan to whitespace or end */
+		parse_ppcdbg_optionlist(cmd, end);
+	}
+}
+#endif /* CONFIG_PPCDBG */
+
+
+/*
+ * Do minimal cmd_line parsing for early boot options.
+ */
+static void __init
+prom_parse_cmd_line(char *line)
+{
+#ifdef CONFIG_PPCDBG
+	parse_ppcdbg_cmd_line(line);
+#endif
+}
 
 /*
  * We enter here early on, when the Open Firmware prom is still
@@ -1246,13 +1377,14 @@
 	ihandle prom_mmu, prom_op, prom_root, prom_cpu;
 	phandle cpu_pkg;
 	unsigned long offset = reloc_offset();
-	long l;
+	long l, sz;
 	char *p, *d;
  	unsigned long phys;
         u32 getprop_rval;
         struct naca_struct   *_naca = RELOC(naca);
 	struct paca_struct *_xPaca = PTRRELOC(&paca[0]);
 	struct prom_t *_prom = PTRRELOC(&prom);
+	char *_cmd_line = PTRRELOC(&cmd_line[0]);
 
 	/* Default machine type. */
 	_naca->platform = PLATFORM_PSERIES;
@@ -1337,6 +1469,15 @@
 	}
 	_prom->encode_phys_size = (getprop_rval==1) ? 32 : 64;
 
+	/* Fetch the cmd_line */
+	sz = (long)call_prom(RELOC("getprop"), 4, 1, _prom->chosen,
+			    RELOC("bootargs"), _cmd_line,
+			    sizeof(cmd_line)-1);
+	if (sz > 0)
+		_cmd_line[sz] = '\0';
+
+	prom_parse_cmd_line(_cmd_line);
+
 #ifdef DEBUG_PROM
 	prom_print(RELOC("DRENG:    Detect OF version...\n"));
 #endif
@@ -1344,7 +1485,6 @@
 	prom_op = (ihandle)call_prom(RELOC("finddevice"), 1, 1, RELOC("/openprom"));
 	if (prom_op != (ihandle)-1) {
 		char model[64];
-		long sz;
 		sz = (long)call_prom(RELOC("getprop"), 4, 1, prom_op,
 				    RELOC("model"), model, 64);
 		if (sz > 0) {
@@ -1404,7 +1544,7 @@
 
 	mem = prom_bi_rec_reserve(mem);
 
-	mem = prom_instantiate_rtas(mem);
+	prom_instantiate_rtas();
         
         /* Initialize some system info into the Naca early... */
         mem = prom_initialize_naca(mem);
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/ptrace.c linux-2.4.20-pre5/arch/ppc64/kernel/ptrace.c
--- linux-2.4.20-pre4/arch/ppc64/kernel/ptrace.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/ptrace.c	Wed Aug 28 16:37:31 2002
@@ -1,5 +1,5 @@
 /*
- *  linux/arch/ppc/kernel/ptrace.c
+ *  linux/arch/ppc64/kernel/ptrace.c
  *
  *  PowerPC version
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -126,14 +126,9 @@
 		ret = ptrace_attach(child);
 		goto out_tsk;
 	}
-	ret = -ESRCH;
-	if (!(child->ptrace & PT_PTRACED))
-		goto out_tsk;
-	if (child->state != TASK_STOPPED) {
-		if (request != PTRACE_KILL)
-			goto out_tsk;
-	}
-	if (child->p_pptr != current)
+
+	ret = ptrace_check_attach(child, request == PTRACE_KILL);
+	if (ret < 0)
 		goto out_tsk;
 
 	switch (request) {
@@ -153,16 +148,17 @@
 
 	/* read the word at location addr in the USER area. */
 	case PTRACE_PEEKUSR: {
-		unsigned long index, tmp;
+		unsigned long index;
+		unsigned long tmp;
 
 		ret = -EIO;
 		/* convert to index and check */
 		index = (unsigned long) addr >> 3;
-		if ((addr & 7) || index > PT_FPSCR)
+		if ((addr & 7) || (index > PT_FPSCR))
 			break;
 
 		if (index < PT_FPR0) {
-			tmp = get_reg(child, (int) index);
+			tmp = get_reg(child, (int)index);
 		} else {
 			if (child->thread.regs->msr & MSR_FP)
 				giveup_fpu(child);
@@ -176,7 +172,8 @@
 	case PTRACE_POKETEXT: /* write the word at location addr. */
 	case PTRACE_POKEDATA:
 		ret = 0;
-		if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
+		if (access_process_vm(child, addr, &data, sizeof(data), 1)
+				== sizeof(data))
 			break;
 		ret = -EIO;
 		break;
@@ -188,7 +185,7 @@
 		ret = -EIO;
 		/* convert to index and check */
 		index = (unsigned long) addr >> 3;
-		if ((addr & 7) || index > PT_FPSCR)
+		if ((addr & 7) || (index > PT_FPSCR))
 			break;
 
 		if (index == PT_ORIG_R3)
@@ -221,11 +218,11 @@
 		break;
 	}
 
-/*
- * make the child exit.  Best I can do is send it a sigkill. 
- * perhaps it should be put in the status that it wants to 
- * exit.
- */
+	/*
+	 * make the child exit.  Best I can do is send it a sigkill.
+	 * perhaps it should be put in the status that it wants to
+	 * exit.
+	 */
 	case PTRACE_KILL: {
 		ret = 0;
 		if (child->state == TASK_ZOMBIE)	/* already dead */
@@ -254,56 +251,50 @@
 		ret = ptrace_detach(child, data);
 		break;
 
-	case PPC_PTRACE_GETREGS:
-	{ /* Get GPRs 0 - 31. */
+	case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */
 		u64 tmp;
 		u64 cntr;
+
 		ret = 0; 
-		for (cntr=0; cntr<32 && ret==0; ++cntr)
-		{
+		for (cntr=0; cntr<32 && ret==0; ++cntr) {
 			tmp = ((u64*)child->thread.regs)[cntr];
 			ret = put_user(tmp, (u64*)(data+cntr));
 		}
 		break;
 	}
 
-	case PPC_PTRACE_SETREGS:
-	{ /* Set GPRs 0 - 31. */
+	case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */
 		u64 cntr;
+
 		ret = 0; 
 		for (cntr=0; cntr<32 && ret==0; ++cntr)
-		{
 			ret = put_reg(child, cntr, *(u64*)(data+cntr));
-		}
 		break;
 	}
 
-	case PPC_PTRACE_GETFPREGS:
-	{ /* Get FPRs 0 - 31. */
+	case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */
 		u64 tmp;
 		u64 cntr;
+
 		ret = -EIO;
 		if (child->thread.regs->msr & MSR_FP)
 			giveup_fpu(child);
 		ret = 0; 
-		for (cntr=0; cntr<32 && ret==0; ++cntr)
-		{
+		for (cntr=0; cntr<32 && ret==0; ++cntr) {
 			tmp = ((u64*)child->thread.fpr)[cntr];
 			ret = put_user(tmp, (u64*)(data+cntr));
 		}
 		break;
 	}
 
-	case PPC_PTRACE_SETFPREGS:
-	{ /* Get FPRs 0 - 31. */
+	case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */
 		u64 cntr;
+
 		ret = -EIO;
 		if (child->thread.regs->msr & MSR_FP)
 			giveup_fpu(child);
 		for (cntr=0; cntr<32; ++cntr)
-		{
 			((u64*)child->thread.fpr)[cntr] = *(u64*)(data+cntr);
-		}
 		ret = 0; 
 		break;
 	}
@@ -338,4 +329,3 @@
 		current->exit_code = 0;
 	}
 }
-
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/ptrace32.c linux-2.4.20-pre5/arch/ppc64/kernel/ptrace32.c
--- linux-2.4.20-pre4/arch/ppc64/kernel/ptrace32.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/ptrace32.c	Wed Aug 28 16:37:31 2002
@@ -1,5 +1,5 @@
 /*
- *  linux/arch/ppc/kernel/ptrace32.c
+ *  linux/arch/ppc64/kernel/ptrace32.c
  *
  *  PowerPC version
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -86,8 +86,8 @@
 int sys32_ptrace(long request, long pid, unsigned long addr, unsigned long data)
 {
 	struct task_struct *child;
-	int ret  = -EPERM;
-  
+	int ret = -EPERM;
+
 	lock_kernel();
 	if (request == PTRACE_TRACEME) {
 		/* are we already being traced? */
@@ -115,18 +115,12 @@
 		ret = ptrace_attach(child);
 		goto out_tsk;
 	}
-	ret = -ESRCH;
-	if (!(child->ptrace & PT_PTRACED))
-		goto out_tsk;
-	if (child->state != TASK_STOPPED) {
-		if (request != PTRACE_KILL)
-			goto out_tsk;
-	}
-	if (child->p_pptr != current)
+
+	ret = ptrace_check_attach(child, request == PTRACE_KILL);
+	if (ret < 0)
 		goto out_tsk;
 
-	switch (request)
-	{
+	switch (request) {
 	/* Read word at location ADDR */
 	/* when I and D space are separate, these will need to be fixed. */
 	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
@@ -143,11 +137,15 @@
 		break;
 	}
 
-	/* Read 4 bytes of the other process' storage */
-	/*  data is a pointer specifying where the user wants the 4 bytes copied into */
-	/*  addr is a pointer in the user's storage that contains an 8 byte address in the other process of the 4 bytes that is to be read */
-	/* (this is run in a 32-bit process looking at a 64-bit process) */
-	/* when I and D space are separate, these will need to be fixed. */
+	/*
+	 * Read 4 bytes of the other process' storage
+	 *  data is a pointer specifying where the user wants the
+	 *	4 bytes copied into
+	 *  addr is a pointer in the user's storage that contains an 8 byte
+	 *	address in the other process of the 4 bytes that is to be read
+	 * (this is run in a 32-bit process looking at a 64-bit process)
+	 * when I and D space are separate, these will need to be fixed.
+	 */
 	case PPC_PTRACE_PEEKTEXT_3264:
 	case PPC_PTRACE_PEEKDATA_3264: 
 	{
@@ -158,7 +156,7 @@
 		ret = -EIO;
 
 		/* Get the addr in the other process that we want to read */
-		if (get_user(addrOthers,(u32**)addr) != 0)
+		if (get_user(addrOthers, (u32**)addr) != 0)
 			break;
 
 		copied = access_process_vm(child, (u64)addrOthers, &tmp_mem_value, sizeof(tmp_mem_value), 0);
@@ -177,7 +175,7 @@
 		ret = -EIO;
 		/* convert to index and check */
 		index = (unsigned long) addr >> 2;
-		if ((addr & 3) || index > PT_FPSCR32)
+		if ((addr & 3) || (index > PT_FPSCR32))
 			break;
 
 		if (index < PT_FPR0) {
@@ -185,9 +183,10 @@
 		} else {
 			if (child->thread.regs->msr & MSR_FP)
 				giveup_fpu(child);
-			/* the user space code considers the floating point to be 
-			 *   an array of unsigned int (32 bits) - the index passed 
-			 *   in is based on this assumption.
+			/*
+			 * the user space code considers the floating point
+			 * to be an array of unsigned int (32 bits) - the
+			 * index passed in is based on this assumption.
 			 */
 			tmp_reg_value = ((unsigned int *)child->thread.fpr)[index - PT_FPR0];
 		}
@@ -196,12 +195,15 @@
 		break;
 	}
   
-	/* Read 4 bytes out of the other process' pt_regs area */
-	/*  data is a pointer specifying where the user wants the 4 bytes copied into */
-	/*  addr is the offset into the other process' pt_regs structure that is to be read */
-	/* (this is run in a 32-bit process looking at a 64-bit process) */
-	case PPC_PTRACE_PEEKUSR_3264:
-	{
+	/*
+	 * Read 4 bytes out of the other process' pt_regs area
+	 *  data is a pointer specifying where the user wants the
+	 *	4 bytes copied into
+	 *  addr is the offset into the other process' pt_regs structure
+	 *	that is to be read
+	 * (this is run in a 32-bit process looking at a 64-bit process)
+	 */
+	case PPC_PTRACE_PEEKUSR_3264: {
 		u32 index;
 		u32 reg32bits;
 		u64 tmp_reg_value;
@@ -222,8 +224,7 @@
 		if ((addr & 3) || numReg > PT_FPSCR)
 			break;
 
-		if (numReg >= PT_FPR0)
-		{
+		if (numReg >= PT_FPR0) {
 			if (child->thread.regs->msr & MSR_FP)
 				giveup_fpu(child);
 		        if (numReg == PT_FPSCR) 
@@ -251,11 +252,15 @@
 		break;
 	}
 
-	/* Write 4 bytes into the other process' storage */
-	/*  data is the 4 bytes that the user wants written */
-	/*  addr is a pointer in the user's storage that contains an 8 byte address in the other process where the 4 bytes that is to be written */
-	/* (this is run in a 32-bit process looking at a 64-bit process) */
-	/* when I and D space are separate, these will need to be fixed. */
+	/*
+	 * Write 4 bytes into the other process' storage
+	 *  data is the 4 bytes that the user wants written
+	 *  addr is a pointer in the user's storage that contains an
+	 *	8 byte address in the other process where the 4 bytes
+	 *	that is to be written
+	 * (this is run in a 32-bit process looking at a 64-bit process)
+	 * when I and D space are separate, these will need to be fixed.
+	 */
 	case PPC_PTRACE_POKETEXT_3264:
 	case PPC_PTRACE_POKEDATA_3264:
 	{
@@ -267,7 +272,6 @@
 		ret = -EIO;
 		if (get_user(addrOthers,(u32**)addr) != 0)
 			break;
-
 		ret = 0;
 		bytesWritten = access_process_vm(child, (u64)addrOthers, &tmp_value_to_write, sizeof(tmp_value_to_write), 1);
 		if (bytesWritten == sizeof(tmp_value_to_write))
@@ -281,63 +285,61 @@
 		unsigned long index;
 
 		ret = -EIO;
-
 		/* convert to index and check */
 		index = (unsigned long) addr >> 2;
-		if ((addr & 3) || index > PT_FPSCR32)
+		if ((addr & 3) || (index > PT_FPSCR32))
 			break;
 
 		if (index == PT_ORIG_R3)
 			break;
-
-
 		if (index < PT_FPR0) {
 			ret = put_reg(child, index, data);
 		} else {
 			if (child->thread.regs->msr & MSR_FP)
 				giveup_fpu(child);
-      /* the user space code considers the floating point to be 
-       *   an array of unsigned int (32 bits) - the index passed 
-       *   in is based on this assumption.
-       */
-
+			/*
+			 * the user space code considers the floating point
+			 * to be an array of unsigned int (32 bits) - the
+			 * index passed in is based on this assumption.
+			 */
 			((unsigned int *)child->thread.fpr)[index - PT_FPR0] = data;
 			ret = 0;
 		}
 		break;
 	}
 
-	/* Write 4 bytes into the other process' pt_regs area */
-	/*  data is the 4 bytes that the user wants written */
-	/*  addr is the offset into the other process' pt_regs structure that is to be written into */
-	/* (this is run in a 32-bit process looking at a 64-bit process) */
-	case PPC_PTRACE_POKEUSR_3264:
-	{
+	/*
+	 * Write 4 bytes into the other process' pt_regs area
+	 *  data is the 4 bytes that the user wants written
+	 *  addr is the offset into the other process' pt_regs structure
+	 *	that is to be written into
+	 * (this is run in a 32-bit process looking at a 64-bit process)
+	 */
+	case PPC_PTRACE_POKEUSR_3264: {
 		u32 index;
 		u32 numReg;
 
 		ret = -EIO;
-
 		/* Determine which register the user wants */
 		index = (u64)addr >> 2;  /* Divide addr by 4 */
 		numReg = index / 2;
-
-		/* Validate the input - check to see if address is on the wrong boundary or beyond the end of the user area */
-		if ((addr & 3) || numReg > PT_FPSCR)
+		/*
+		 * Validate the input - check to see if address is on the
+		 * wrong boundary or beyond the end of the user area
+		 */
+		if ((addr & 3) || (numReg > PT_FPSCR))
 			break;
 		/* Insure it is a register we let them change */
-		if ((numReg == PT_ORIG_R3) || ((numReg > PT_CCR) && (numReg < PT_FPR0)))
+		if ((numReg == PT_ORIG_R3)
+				|| ((numReg > PT_CCR) && (numReg < PT_FPR0)))
 			break;
-
-		if (numReg >= PT_FPR0)
-		{
+		if (numReg >= PT_FPR0) {
 			if (child->thread.regs->msr & MSR_FP)
 				giveup_fpu(child);
 		}
-
 		if (numReg == PT_MSR)
-			data = (data & MSR_DEBUGCHANGE) | (child->thread.regs->msr & ~MSR_DEBUGCHANGE);
-
+			data = (data & MSR_DEBUGCHANGE)
+				| (child->thread.regs->msr & ~MSR_DEBUGCHANGE);
 		((u32*)child->thread.regs)[index] = data;
 		ret = 0;
 		break;
@@ -361,8 +363,8 @@
 	}
 
 	/*
-	 * make the child exit.  Best I can do is send it a sigkill. 
-	 * perhaps it should be put in the status that it wants to 
+	 * make the child exit.  Best I can do is send it a sigkill.
+	 * perhaps it should be put in the status that it wants to
 	 * exit.
 	 */
 	case PTRACE_KILL: {
@@ -403,4 +405,3 @@
 	unlock_kernel();
 	return ret;
 }
-
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/rtas.c linux-2.4.20-pre5/arch/ppc64/kernel/rtas.c
--- linux-2.4.20-pre4/arch/ppc64/kernel/rtas.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/rtas.c	Wed Aug 28 16:37:31 2002
@@ -15,6 +15,7 @@
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/spinlock.h>
+#include <linux/fs.h>
 
 #include <asm/init.h>
 #include <asm/prom.h>
@@ -24,8 +25,12 @@
 #include <asm/paca.h>
 #include <asm/page.h>
 #include <asm/system.h>
+#include <asm/abs_addr.h>
 #include <asm/udbg.h>
 
+struct proc_dir_entry *rtas_proc_dir;	/* /proc/ppc64/rtas dir */
+struct flash_block_list_header rtas_firmware_flash_list = {0, 0};
+
 /*
  * prom_init() is called very early on, before the kernel text
  * and data have been mapped to KERNELBASE.  At this point the code
@@ -103,18 +108,13 @@
 	enter_rtas((void *)__pa((unsigned long)rtas));	
 }
 
-#if 0
-#define DEBUG_RTAS
-#endif
 __openfirmware
 int
 rtas_token(const char *service)
 {
 	int *tokp;
 	if (rtas.dev == NULL) {
-#ifdef DEBUG_RTAS
-		udbg_printf("\tNo rtas device in device-tree...\n");
-#endif /* DEBUG_RTAS */
+		PPCDBG(PPCDBG_RTAS,"\tNo rtas device in device-tree...\n");
 		return RTAS_UNKNOWN_SERVICE;
 	}
 	tokp = (int *) get_property(rtas.dev, service, NULL);
@@ -131,13 +131,11 @@
 	unsigned long s;
 	struct rtas_args *rtas_args = &(get_paca()->xRtas);
 
-#ifdef DEBUG_RTAS
-	udbg_printf("Entering rtas_call\n");
-	udbg_printf("\ttoken    = 0x%x\n", token);
-	udbg_printf("\tnargs    = %d\n", nargs);
-	udbg_printf("\tnret     = %d\n", nret);
-	udbg_printf("\t&outputs = 0x%lx\n", outputs);
-#endif /* DEBUG_RTAS */
+	PPCDBG(PPCDBG_RTAS, "Entering rtas_call\n");
+	PPCDBG(PPCDBG_RTAS, "\ttoken    = 0x%x\n", token);
+	PPCDBG(PPCDBG_RTAS, "\tnargs    = %d\n", nargs);
+	PPCDBG(PPCDBG_RTAS, "\tnret     = %d\n", nret);
+	PPCDBG(PPCDBG_RTAS, "\t&outputs = 0x%lx\n", outputs);
 	if (token == RTAS_UNKNOWN_SERVICE)
 		return -1;
 
@@ -147,10 +145,8 @@
 	rtas_args->rets  = (rtas_arg_t *)&(rtas_args->args[nargs]);
 	va_start(list, outputs);
 	for (i = 0; i < nargs; ++i) {
-	  rtas_args->args[i] = (rtas_arg_t)LONG_LSW(va_arg(list, ulong));
-#ifdef DEBUG_RTAS
-	  udbg_printf("\tnarg[%d] = 0x%lx\n", i, rtas_args->args[i]);
-#endif /* DEBUG_RTAS */
+		rtas_args->args[i] = (rtas_arg_t)LONG_LSW(va_arg(list, ulong));
+		PPCDBG(PPCDBG_RTAS, "\tnarg[%d] = 0x%lx\n", i, rtas_args->args[i]);
 	}
 	va_end(list);
 
@@ -162,22 +158,19 @@
 #else
 	spin_lock_irqsave(&rtas.lock, s);
 #endif
-#ifdef DEBUG_RTAS
-	udbg_printf("\tentering rtas with 0x%lx\n", (void *)__pa((unsigned long)rtas_args));
-#endif /* DEBUG_RTAS */
+	PPCDBG(PPCDBG_RTAS, "\tentering rtas with 0x%lx\n",
+		(void *)__pa((unsigned long)rtas_args));
 	enter_rtas((void *)__pa((unsigned long)rtas_args));
-#ifdef DEBUG_RTAS
-	udbg_printf("\treturned from rtas ...\n");
-#endif /* DEBUG_RTAS */
+	PPCDBG(PPCDBG_RTAS, "\treturned from rtas ...\n");
 #if 0   /* Gotta do something different here, use global lock for now... */
 	spin_unlock_irqrestore(&rtas_args->lock, s);
 #else
 	spin_unlock_irqrestore(&rtas.lock, s);
 #endif
-#ifdef DEBUG_RTAS
-	for(i=0; i < nret ;i++)
-	  udbg_printf("\tnret[%d] = 0x%lx\n", i, (ulong)rtas_args->rets[i]);
-#endif /* DEBUG_RTAS */
+	ifppcdebug(PPCDBG_RTAS) {
+		for(i=0; i < nret ;i++)
+			udbg_printf("\tnret[%d] = 0x%lx\n", i, (ulong)rtas_args->rets[i]);
+	}
 
 	if (nret > 1 && outputs != NULL)
 		for (i = 0; i < nret-1; ++i)
@@ -185,9 +178,87 @@
 	return (ulong)((nret > 0) ? rtas_args->rets[0] : 0);
 }
 
+#define FLASH_BLOCK_LIST_VERSION (1UL)
+static void
+rtas_flash_firmware(void)
+{
+	unsigned long image_size;
+	struct flash_block_list *f, *next, *flist;
+	unsigned long rtas_block_list;
+	int i, status, update_token;
+
+	update_token = rtas_token("ibm,update-flash-64-and-reboot");
+	if (update_token == RTAS_UNKNOWN_SERVICE) {
+		printk(KERN_ALERT "FLASH: ibm,update-flash-64-and-reboot is not available -- not a service partition?\n");
+		printk(KERN_ALERT "FLASH: firmware will not be flashed\n");
+		return;
+	}
+
+	/* NOTE: the "first" block list is a global var with no data
+	 * blocks in the kernel data segment.  We do this because
+	 * we want to ensure this block_list addr is under 4GB.
+	 */
+	rtas_firmware_flash_list.num_blocks = 0;
+	flist = (struct flash_block_list *)&rtas_firmware_flash_list;
+	rtas_block_list = virt_to_absolute((unsigned long)flist);
+	if (rtas_block_list >= (4UL << 20)) {
+		printk(KERN_ALERT "FLASH: kernel bug...flash list header addr above 4GB\n");
+		return;
+	}
+
+	printk(KERN_ALERT "FLASH: preparing saved firmware image for flash\n");
+	/* Update the block_list in place. */
+	image_size = 0;
+	for (f = flist; f; f = next) {
+		/* Translate data addrs to absolute */
+		for (i = 0; i < f->num_blocks; i++) {
+			f->blocks[i].data = (char *)virt_to_absolute((unsigned long)f->blocks[i].data);
+			image_size += f->blocks[i].length;
+		}
+		next = f->next;
+		f->next = (struct flash_block_list *)virt_to_absolute((unsigned long)f->next);
+		/* make num_blocks into the version/length field */
+		f->num_blocks = (FLASH_BLOCK_LIST_VERSION << 56) | ((f->num_blocks+1)*16);
+	}
+
+	printk(KERN_ALERT "FLASH: flash image is %ld bytes\n", image_size);
+	printk(KERN_ALERT "FLASH: performing flash and reboot\n");
+	ppc_md.progress("Flashing        \n", 0x0);
+	ppc_md.progress("Please Wait...  ", 0x0);
+	printk(KERN_ALERT "FLASH: this will take several minutes.  Do not power off!\n");
+	status = rtas_call(update_token, 1, 1, NULL, rtas_block_list);
+	switch (status) {	/* should only get "bad" status */
+	    case 0:
+		printk(KERN_ALERT "FLASH: success\n");
+		break;
+	    case -1:
+		printk(KERN_ALERT "FLASH: hardware error.  Firmware may not be not flashed\n");
+		break;
+	    case -3:
+		printk(KERN_ALERT "FLASH: image is corrupt or not correct for this platform.  Firmware not flashed\n");
+		break;
+	    case -4:
+		printk(KERN_ALERT "FLASH: flash failed when partially complete.  System may not reboot\n");
+		break;
+	    default:
+		printk(KERN_ALERT "FLASH: unknown flash return code %d\n", status);
+		break;
+	}
+}
+
+void rtas_flash_bypass_warning(void)
+{
+	printk(KERN_ALERT "FLASH: firmware flash requires a reboot\n");
+	printk(KERN_ALERT "FLASH: the firmware image will NOT be flashed\n");
+}
+
+
 void __chrp
 rtas_restart(char *cmd)
 {
+	if (rtas_firmware_flash_list.next)
+		rtas_flash_firmware();
+
         printk("RTAS system-reboot returned %ld\n",
 	       rtas_call(rtas_token("system-reboot"), 0, 1, NULL));
         for (;;);
@@ -196,6 +267,8 @@
 void __chrp
 rtas_power_off(void)
 {
+	if (rtas_firmware_flash_list.next)
+		rtas_flash_bypass_warning();
         /* allow power on only with power button press */
         printk("RTAS power-off returned %ld\n",
                rtas_call(rtas_token("power-off"), 2, 1, NULL,0xffffffff,0xffffffff));
@@ -205,5 +278,7 @@
 void __chrp
 rtas_halt(void)
 {
+	if (rtas_firmware_flash_list.next)
+		rtas_flash_bypass_warning();
         rtas_power_off();
 }
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/rtas_flash.c linux-2.4.20-pre5/arch/ppc64/kernel/rtas_flash.c
--- linux-2.4.20-pre4/arch/ppc64/kernel/rtas_flash.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre5/arch/ppc64/kernel/rtas_flash.c	Wed Aug 28 16:37:31 2002
@@ -0,0 +1,240 @@
+/*
+ *  c 2001 PPC 64 Team, IBM Corp
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ *
+ * /proc/ppc64/rtas/firmware_flash interface
+ *
+ * This file implements a firmware_flash interface to pump a firmware
+ * image into the kernel.  At reboot time rtas_restart() will see the
+ * firmware image and flash it as it reboots (see rtas.c).
+ */
+
+#include <linux/module.h>
+
+#include <linux/config.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <asm/rtas.h>
+
+#define MODULE_VERSION "1.0"
+#define MODULE_NAME "rtas_flash"
+
+#define FIRMWARE_FLASH_NAME "firmware_flash"
+
+/* Local copy of the flash block list.
+ * We only allow one open of the flash proc file and create this
+ * list as we go.  This list will be put in the kernel's
+ * rtas_firmware_flash_list global var once it is fully read.
+ *
+ * For convenience as we build the list we use virtual addrs,
+ * we do not fill in the version number, and the length field
+ * is treated as the number of entries currently in the block
+ * (i.e. not a byte count).  This is all fixed on release.
+ */
+static struct flash_block_list *flist;
+static char *flash_msg;
+static int flash_possible;
+
+static int rtas_flash_open(struct inode *inode, struct file *file)
+{
+	if ((file->f_mode & FMODE_WRITE) && flash_possible) {
+		if (flist)
+			return -EBUSY;
+		flist = (struct flash_block_list *)get_free_page(GFP_KERNEL);
+		if (!flist)
+			return -ENOMEM;
+	}
+	return 0;
+}
+
+/* Do simple sanity checks on the flash image. */
+static int flash_list_valid(struct flash_block_list *flist)
+{
+	struct flash_block_list *f;
+	int i;
+	unsigned long block_size, image_size;
+
+	flash_msg = NULL;
+	/* Paranoid self test here.  We also collect the image size. */
+	image_size = 0;
+	for (f = flist; f; f = f->next) {
+		for (i = 0; i < f->num_blocks; i++) {
+			if (f->blocks[i].data == NULL) {
+				flash_msg = "error: internal error null data\n";
+				return 0;
+			}
+			block_size = f->blocks[i].length;
+			if (block_size <= 0 || block_size > PAGE_SIZE) {
+				flash_msg = "error: internal error bad length\n";
+				return 0;
+			}
+			image_size += block_size;
+		}
+	}
+	if (image_size < (256 << 10)) {
+		if (image_size < 2)
+			flash_msg = NULL;	/* allow "clear" of image */
+		else
+			flash_msg = "error: flash image short\n";
+		return 0;
+	}
+	printk(KERN_INFO "FLASH: flash image with %ld bytes stored for hardware flash on reboot\n", image_size);
+	return 1;
+}
+
+static void free_flash_list(struct flash_block_list *f)
+{
+	struct flash_block_list *next;
+	int i;
+
+	while (f) {
+		for (i = 0; i < f->num_blocks; i++)
+			free_page((unsigned long)(f->blocks[i].data));
+		next = f->next;
+		free_page((unsigned long)f);
+		f = next;
+	}
+}
+
+static int rtas_flash_release(struct inode *inode, struct file *file)
+{
+	if (flist) {
+		/* Always clear saved list on a new attempt. */
+		if (rtas_firmware_flash_list.next) {
+			free_flash_list(rtas_firmware_flash_list.next);
+			rtas_firmware_flash_list.next = NULL;
+		}
+
+		if (flash_list_valid(flist))
+			rtas_firmware_flash_list.next = flist;
+		else
+			free_flash_list(flist);
+		flist = NULL;
+	}
+	return 0;
+}
+
+/* Reading the proc file will show status (not the firmware contents) */
+static ssize_t rtas_flash_read(struct file *file, char *buf,
+			       size_t count, loff_t *ppos)
+{
+	int error;
+	char *msg;
+	int msglen;
+
+	if (!flash_possible) {
+		msg = "error: this partition does not have service authority\n";
+	} else if (flist) {
+		msg = "info: this file is busy for write by some process\n";
+	} else if (flash_msg) {
+		msg = flash_msg;	/* message from last flash attempt */
+	} else if (rtas_firmware_flash_list.next) {
+		msg = "ready: firmware image ready for flash on reboot\n";
+	} else {
+		msg = "info: no firmware image for flash\n";
+	}
+	msglen = strlen(msg);
+	if (msglen > count)
+		msglen = count;
+
+	if (ppos && *ppos != 0)
+		return 0;	/* be cheap */
+
+	error = verify_area(VERIFY_WRITE, buf, msglen);
+	if (error)
+		return -EINVAL;
+
+	copy_to_user(buf, msg, msglen);
+
+	if (ppos)
+		*ppos = msglen;
+	return msglen;
+}
+
+/* We could be much more efficient here.  But to keep this function
+ * simple we allocate a page to the block list no matter how small the
+ * count is.  If the system is low on memory it will be just as well
+ * that we fail....
+ */
+static ssize_t rtas_flash_write(struct file *file, const char *buffer,
+				size_t count, loff_t *off)
+{
+	size_t len = count;
+	char *p;
+	int next_free;
+	struct flash_block_list *fl = flist;
+
+	if (!flash_possible || len == 0)
+		return len;	/* discard data */
+
+	while (fl->next)
+		fl = fl->next; /* seek to last block_list for append */
+	next_free = fl->num_blocks;
+	if (next_free == FLASH_BLOCKS_PER_NODE) {
+		/* Need to allocate another block_list */
+		fl->next = (struct flash_block_list *)get_free_page(GFP_KERNEL);
+		if (!fl->next)
+			return -ENOMEM;
+		fl = fl->next;
+		next_free = 0;
+	}
+
+	if (len > PAGE_SIZE)
+		len = PAGE_SIZE;
+	p = (char *)get_free_page(GFP_KERNEL);
+	if (!p)
+		return -ENOMEM;
+	if(copy_from_user(p, buffer, len)) {
+		free_page((unsigned long)p);
+		return -EFAULT;
+	}
+	fl->blocks[next_free].data = p;
+	fl->blocks[next_free].length = len;
+	fl->num_blocks++;
+
+	return len;
+}
+
+static struct file_operations rtas_flash_operations = {
+	read:		rtas_flash_read,
+	write:		rtas_flash_write,
+	open:		rtas_flash_open,
+	release:	rtas_flash_release,
+};
+
+
+int __init rtas_flash_init(void)
+{
+	struct proc_dir_entry *ent = NULL;
+
+	if (!rtas_proc_dir) {
+		printk(KERN_WARNING "rtas proc dir does not already exist");
+		return -ENOENT;
+	}
+
+	if (rtas_token("ibm,update-flash-64-and-reboot") != RTAS_UNKNOWN_SERVICE)
+		flash_possible = 1;
+
+	if ((ent = create_proc_entry(FIRMWARE_FLASH_NAME, S_IRUSR | S_IWUSR, rtas_proc_dir)) != NULL) {
+		ent->nlink = 1;
+		ent->proc_fops = &rtas_flash_operations;
+		ent->owner = THIS_MODULE;
+	}
+	return 0;
+}
+
+void __exit rtas_flash_cleanup(void)
+{
+	if (!rtas_proc_dir)
+		return;
+	remove_proc_entry(FIRMWARE_FLASH_NAME, rtas_proc_dir);
+}
+
+module_init(rtas_flash_init);
+module_exit(rtas_flash_cleanup);
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/rtasd.c linux-2.4.20-pre5/arch/ppc64/kernel/rtasd.c
--- linux-2.4.20-pre4/arch/ppc64/kernel/rtasd.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/rtasd.c	Wed Aug 28 16:37:31 2002
@@ -98,9 +98,7 @@
 	rtas_log_size -= 1;
 	spin_unlock(&rtas_log_lock);
 
-	copy_to_user(buf, tmp, count);
-	error = count;
-
+	error = copy_to_user(buf, tmp, count) ? -EFAULT : count;
 out:
 	kfree(tmp);
 	return error;
@@ -624,6 +622,31 @@
 	}
 }
 
+#define MAX_LOG_DEBUG 10
+/* Print log debug data.  This appears after the location code.
+ * We limit the number of debug logs in case the data is somehow corrupt.
+ */
+static void printk_log_debug(char *buf)
+{
+	unsigned char *p = (unsigned char *)_ALIGN((unsigned long)buf, 8);
+	int len, n, logged;
+
+	logged = 0;
+	while ((logged < MAX_LOG_DEBUG) && (len = ((p[0] << 8) | p[1])) != 2) {
+		/* len includes 2-byte length thus len == 2 is the end */
+		printk("RTAS: Log Debug: ");
+		if (len >= 4)	/* next 2 bytes are an ascii code */
+			printk("%c%c ", p[2], p[3]);
+		for (n=4; n < len; n++)
+			printk("%02x", p[n]);
+		printk("\n");
+		p += len;
+		logged++;
+	}
+	if (logged == 0)
+		printk("RTAS: no log debug data present\n");
+}
+
 
 /* Yeah, the output here is ugly, but we want a CE to be
  * able to grep RTAS /var/log/messages and see all the info
@@ -637,8 +660,11 @@
 	if (strcmp(buf+8+40, "IBM") == 0) {
 		/* Location code follows */
 		char *loc = buf+8+40+4;
-		if (*loc >= 'A' && *loc <= 'Z')	/* Sanity check */
+		int len = strlen(loc);
+		if (len < 64) {	/* Sanity check */
 			printk(RTAS_ERR "Location Code: %s\n", loc);
+			printk_log_debug(loc+len+1);
+		}
 	}
 
 	printk(RTAS_ERR "%s: (%s) type: %s\n",
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/setup.c linux-2.4.20-pre5/arch/ppc64/kernel/setup.c
--- linux-2.4.20-pre4/arch/ppc64/kernel/setup.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/setup.c	Wed Aug 28 16:37:31 2002
@@ -21,6 +21,8 @@
 #include <linux/ide.h>
 #include <linux/seq_file.h>
 #include <linux/ioport.h>
+#include <linux/console.h>
+#include <linux/version.h>
 #include <asm/init.h>
 #include <asm/io.h>
 #include <asm/prom.h>
@@ -40,6 +42,7 @@
 /* extern void *stab; */
 extern HTAB htab_data;
 extern unsigned long loops_per_jiffy;
+extern int preferred_console;	/* from kernel/printk.c */
 
 extern unsigned long embedded_sysmap_start;
 extern unsigned long embedded_sysmap_end;
@@ -68,6 +71,10 @@
 extern void xmon_map_scc(void);
 #endif
 
+#ifdef CONFIG_KDB
+extern void kdb_map_scc(void);
+#endif
+
 char saved_command_line[256];
 unsigned char aux_device_present;
 
@@ -109,15 +116,12 @@
 int icache_bsize;
 int ucache_bsize;
 
-/*
- * Initialize the PPCDBG state.  Called before relocation has been enabled.
- */
-void ppcdbg_initialize(void) {
-	unsigned long offset = reloc_offset();
-	struct naca_struct *_naca = RELOC(naca);
-
-	_naca->debug_switch = PPC_DEBUG_DEFAULT; /* | PPCDBG_BUSWALK | PPCDBG_PHBINIT | PPCDBG_MM | PPCDBG_MMINIT | PPCDBG_TCEINIT | PPCDBG_TCE */;
-}
+static struct console udbg_console = {
+	name:	"udbg",
+	write:	udbg_console_write,
+	flags:	CON_PRINTBUFFER,
+	index:	-1,
+};
 
 /*
  * Do some initial setup of the system.  The paramters are those which 
@@ -157,66 +161,29 @@
 #endif
 	}
 
-	udbg_puts("\n-----------------------------------------------------\n");
-	udbg_puts("Naca Info...\n\n");
-	udbg_puts("naca                       = 0x");
-	udbg_puthex((unsigned long)naca);
-	udbg_putc('\n');
-
-	udbg_puts("naca->processorCount       = 0x");
-	udbg_puthex(naca->processorCount);
-	udbg_putc('\n');
-
-	udbg_puts("naca->physicalMemorySize   = 0x");
-	udbg_puthex(naca->physicalMemorySize);
-	udbg_putc('\n');
-
-	udbg_puts("naca->dCacheL1LineSize     = 0x");
-	udbg_puthex(naca->dCacheL1LineSize);
-	udbg_putc('\n');
-
-	udbg_puts("naca->dCacheL1LogLineSize  = 0x");
-	udbg_puthex(naca->dCacheL1LogLineSize);
-	udbg_putc('\n');
-
-	udbg_puts("naca->dCacheL1LinesPerPage = 0x");
-	udbg_puthex(naca->dCacheL1LinesPerPage);
-	udbg_putc('\n');
-
-	udbg_puts("naca->iCacheL1LineSize     = 0x");
-	udbg_puthex(naca->iCacheL1LineSize);
-	udbg_putc('\n');
-
-	udbg_puts("naca->iCacheL1LogLineSize  = 0x");
-	udbg_puthex(naca->iCacheL1LogLineSize);
-	udbg_putc('\n');
-
-	udbg_puts("naca->iCacheL1LinesPerPage = 0x");
-	udbg_puthex(naca->iCacheL1LinesPerPage);
-	udbg_putc('\n');
-
-	udbg_puts("naca->pftSize              = 0x");
-	udbg_puthex(naca->pftSize);
-	udbg_putc('\n');
-
-	udbg_puts("naca->serialPortAddr       = 0x");
-	udbg_puthex(naca->serialPortAddr);
-	udbg_putc('\n');
-
-	udbg_puts("naca->interrupt_controller = 0x");
-	udbg_puthex(naca->interrupt_controller);
-	udbg_putc('\n');
-
-	udbg_printf("\nHTAB Info ...\n\n"); 
-	udbg_puts("htab_data.htab             = 0x");
-	udbg_puthex((unsigned long)htab_data.htab);
-	udbg_putc('\n');
-	udbg_puts("htab_data.num_ptegs        = 0x");
-	udbg_puthex(htab_data.htab_num_ptegs);
-	udbg_putc('\n');
+	if (naca->platform & PLATFORM_PSERIES) {
+		register_console(&udbg_console);
+		preferred_console = -1;
+	}
 
-	udbg_puts("\n-----------------------------------------------------\n");
+	printk("Starting Linux PPC64 %s\n", UTS_RELEASE);
 
+	printk("-----------------------------------------------------\n");
+	printk("naca                       = 0x%p\n", naca);
+	printk("naca->processorCount       = 0x%x\n", naca->processorCount);
+	printk("naca->physicalMemorySize   = 0x%lx\n", naca->physicalMemorySize);
+	printk("naca->dCacheL1LineSize     = 0x%x\n", naca->dCacheL1LineSize);
+	printk("naca->dCacheL1LogLineSize  = 0x%x\n", naca->dCacheL1LogLineSize);
+	printk("naca->dCacheL1LinesPerPage = 0x%x\n", naca->dCacheL1LinesPerPage);
+	printk("naca->iCacheL1LineSize     = 0x%x\n", naca->iCacheL1LineSize);
+	printk("naca->iCacheL1LogLineSize  = 0x%x\n", naca->iCacheL1LogLineSize);
+	printk("naca->iCacheL1LinesPerPage = 0x%x\n", naca->iCacheL1LinesPerPage);
+	printk("naca->pftSize              = 0x%lx\n", naca->pftSize);
+	printk("naca->debug_switch         = 0x%lx\n", naca->debug_switch);
+	printk("naca->interrupt_controller = 0x%lx\n", naca->interrupt_controller);
+	printk("htab_data.htab             = 0x%p\n", htab_data.htab);
+	printk("htab_data.num_ptegs        = 0x%lx\n", htab_data.htab_num_ptegs);
+	printk("-----------------------------------------------------\n");
 
 	if (naca->platform & PLATFORM_PSERIES) {
 		finish_device_tree();
@@ -226,14 +193,28 @@
 	mm_init_ppc64();
 
 	switch (naca->platform) {
-	case PLATFORM_ISERIES_LPAR:
+	    case PLATFORM_ISERIES_LPAR:
 		iSeries_init();
 		break;
-	default:
+	    default:
 		/* The following relies on the device tree being */
 		/* fully configured.                             */
 		parse_cmd_line(r3, r4, r5, r6, r7);
 	}
+	ppc64_boot_msg(0x10, "Setup System");
+}
+
+/* This is called just before console_init().
+ * It will be obsolete when Linux gets real early console support (2.5?)
+ * We need to hack preferred_console to retain the correct behavior
+ */
+void setup_before_console_init(void)
+{
+	if (naca->platform & PLATFORM_PSERIES) {
+		int save = preferred_console;
+		unregister_console(&udbg_console);
+		preferred_console = save;
+	}
 }
 
 void machine_restart(char *cmd)
@@ -284,6 +265,9 @@
 	pvr = paca[cpu_id].pvr;
 
 	switch (PVR_VER(pvr)) {
+	case PV_NORTHSTAR:
+		seq_printf(m, "RS64-II (northstar)\n");
+		break;
 	case PV_PULSAR:
 		seq_printf(m, "RS64-III (pulsar)\n");
 		break;
@@ -302,6 +286,9 @@
 	case PV_630p:
 		seq_printf(m, "POWER3 (630+)\n");
 		break;
+	case PV_POWER4p:
+		seq_printf(m, "POWER4+ (gq)\n");
+		break;
 	default:
 		seq_printf(m, "Unknown (%08x)\n", pvr);
 		break;
@@ -328,7 +315,7 @@
 	if (ppc_md.setup_residual != NULL)
 		ppc_md.setup_residual(m, cpu_id);
 
-	seq_printf(m, "revision\t: %hd.%hd\n", maj, min);
+	seq_printf(m, "revision\t: %hd.%hd\n\n", maj, min);
 	
 	return 0;
 }
@@ -369,18 +356,9 @@
 	}
 #endif
 
-	cmd_line[0] = 0;
-	chosen = find_devices("chosen");
-	if (chosen != NULL) {
-		p = get_property(chosen, "bootargs", NULL);
-		if (p != NULL)
-			strncpy(cmd_line, p, sizeof(cmd_line));
-	}
-	cmd_line[sizeof(cmd_line) - 1] = 0;
-
 	/* Look for mem= option on command line */
 	if (strstr(cmd_line, "mem=")) {
-		char *p, *q;
+		char *q;
 		unsigned long maxmem = 0;
 		extern unsigned long __max_memory;
 
@@ -399,7 +377,6 @@
 		}
 		__max_memory = maxmem;
 	}
-	ppc_md.progress("id mach: done", 0x200);
 }
 
 
@@ -477,7 +454,6 @@
 	printk("Calibrating delay loop... %lu.%02lu BogoMips\n",
 			       loops_per_jiffy/(500000/HZ),
 			       loops_per_jiffy/(5000/HZ) % 100);
-
 }	
 
 extern void (*calibrate_delay)(void);
@@ -495,15 +471,18 @@
 
 	calibrate_delay = ppc64_calibrate_delay;
 
+	ppc64_boot_msg(0x12, "Setup Arch");
 #ifdef CONFIG_XMON
 	xmon_map_scc();
 	if (strstr(cmd_line, "xmon"))
 		xmon(0);
 #endif /* CONFIG_XMON */
+
 #ifdef CONFIG_KDB
-	xmon_map_scc();	/* in kdb/start.c --need to rename TAI */
+	kdb_map_scc();	
+	if (strstr(cmd_line, "kdb=early"))
+		kdb(KDB_REASON_CALL,0,0);
 #endif
-	ppc_md.progress("setup_arch:enter", 0x3eab);
 
 #if defined(CONFIG_KGDB)
 	kgdb_map_scc();
@@ -532,12 +511,11 @@
 
 	/* set up the bootmem stuff with available memory */
 	do_init_bootmem();
-	ppc_md.progress("setup_arch:bootmem", 0x3eab);
 
 	ppc_md.setup_arch();
 
 	paging_init();
-	ppc_md.progress("setup_arch: exit", 0x3eab);
+	ppc64_boot_msg(0x15, "Setup Done");
 }
 
 #ifdef CONFIG_IDE
@@ -638,6 +616,53 @@
 }
 #endif
 
+/* ToDo: do something useful if ppc_md is not yet setup. */
+#define PPC64_LINUX_FUNCTION 0x0f000000
+#define PPC64_IPL_MESSAGE 0xc0000000
+#define PPC64_TERM_MESSAGE 0xb0000000
+#define PPC64_ATTN_MESSAGE 0xa0000000
+#define PPC64_DUMP_MESSAGE 0xd0000000
+
+static void ppc64_do_msg(unsigned int src, const char *msg)
+{
+	if (ppc_md.progress) {
+		char buf[32];
+
+		sprintf(buf, "%08x        \n", src);
+		ppc_md.progress(buf, 0);
+		sprintf(buf, "%-16s", msg);
+		ppc_md.progress(buf, 0);
+	}
+}
+
+/* Print a boot progress message. */
+void ppc64_boot_msg(unsigned int src, const char *msg)
+{
+	ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_IPL_MESSAGE|src, msg);
+	printk("[boot]%04x %s\n", src, msg);
+}
+
+/* Print a termination message (print only -- does not stop the kernel) */
+void ppc64_terminate_msg(unsigned int src, const char *msg)
+{
+	ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_TERM_MESSAGE|src, msg);
+	printk("[terminate]%04x %s\n", src, msg);
+}
+
+/* Print something that needs attention (device error, etc) */
+void ppc64_attention_msg(unsigned int src, const char *msg)
+{
+	ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_ATTN_MESSAGE|src, msg);
+	printk("[attention]%04x %s\n", src, msg);
+}
+
+/* Print a dump progress message. */
+void ppc64_dump_msg(unsigned int src, const char *msg)
+{
+	ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_DUMP_MESSAGE|src, msg);
+	printk("[dump]%04x %s\n", src, msg);
+}
+
 
 void exception_trace(unsigned long trap)
 {
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/signal.c linux-2.4.20-pre5/arch/ppc64/kernel/signal.c
--- linux-2.4.20-pre4/arch/ppc64/kernel/signal.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/signal.c	Wed Aug 28 16:37:31 2002
@@ -1,8 +1,6 @@
 /*
  *  linux/arch/ppc64/kernel/signal.c
  *
- *  
- *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
  *
@@ -637,11 +635,6 @@
 	 */
 	if (current->thread.flags & PPC_FLAG_32BIT)
 		return do_signal32(oldset, regs);
-  
-        PPCDBG(PPCDBG_SIGNAL, "do_signal - running - pid=%ld current=%lx comm=%s \n", 
-               current->pid, current, current->comm);
-
-  
 
         if (!oldset)
 		oldset = &current->blocked;
@@ -716,7 +709,7 @@
 				continue;
 
 			switch (signr) {
-			case SIGCONT: case SIGCHLD: case SIGWINCH:
+			case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG:
 				continue;
 
 			case SIGTSTP: case SIGTTIN: case SIGTTOU:
@@ -724,13 +717,16 @@
 					continue;
 				/* FALLTHRU */
 
-			case SIGSTOP:
+			case SIGSTOP: {
+				struct signal_struct *sig;
 				current->state = TASK_STOPPED;
 				current->exit_code = signr;
-				if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
+				sig = current->p_pptr->sig;
+				if (sig && !(sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
 					notify_parent(current, SIGCHLD);
 				schedule();
 				continue;
+			}
 
 			case SIGQUIT: case SIGILL: case SIGTRAP:
 			case SIGABRT: case SIGFPE: case SIGSEGV:
@@ -740,10 +736,7 @@
 				/* FALLTHRU */
 
 			default:
-				sigaddset(&current->pending.signal, signr);
-				recalc_sigpending(current);
-				current->flags |= PF_SIGNALED;
-				do_exit(exit_code);
+				sig_exit(signr, exit_code, &info);
 				/* NOTREACHED */
 			}
 		}
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/signal32.c linux-2.4.20-pre5/arch/ppc64/kernel/signal32.c
--- linux-2.4.20-pre4/arch/ppc64/kernel/signal32.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/signal32.c	Wed Aug 28 16:37:31 2002
@@ -1406,7 +1406,7 @@
 				continue;
 
 			switch (signr) {
-			case SIGCONT: case SIGCHLD: case SIGWINCH:
+			case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG:
 				continue;
 
 			case SIGTSTP: case SIGTTIN: case SIGTTOU:
@@ -1430,10 +1430,7 @@
 				/* FALLTHRU */
 
 			default:
-				sigaddset(&current->pending.signal, signr);
-				recalc_sigpending(current);
-				current->flags |= PF_SIGNALED;
-				do_exit(exit_code);
+				sig_exit(signr, exit_code, &info);
 				/* NOTREACHED */
 			}
 		}
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/smp.c linux-2.4.20-pre5/arch/ppc64/kernel/smp.c
--- linux-2.4.20-pre4/arch/ppc64/kernel/smp.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/smp.c	Wed Aug 28 16:37:31 2002
@@ -52,6 +52,14 @@
 #include <asm/ppcdebug.h>
 #include "open_pic.h"
 #include <asm/machdep.h>
+#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)
+int (*dump_ipi_function_ptr)(struct pt_regs *);
+#include <linux/dump.h>
+#endif
+
+#ifdef CONFIG_KDB
+#include <linux/kdb.h>
+#endif
 
 int smp_threads_ready = 0;
 volatile int smp_commenced = 0;
@@ -93,9 +101,21 @@
        } while(0)
 
 #ifdef CONFIG_KDB
+/* save regs here before calling kdb_ipi */
+struct pt_regs *kdb_smp_regs[NR_CPUS]; 
+
+/* called for each processor.. drop each into kdb. */
+void smp_kdb_stop_proc(void)
+{
+    kdb_ipi(kdb_smp_regs[smp_processor_id()], NULL);
+}
+
 void smp_kdb_stop(void)
 {
+  int ret=0;
+  ret =    smp_call_function(smp_kdb_stop_proc, NULL, 1, 0);
 }
+
 #endif
 
 static inline void set_tb(unsigned int upper, unsigned int lower)
@@ -161,7 +181,7 @@
 			paca[i].next_jiffy_update_tb = paca[0].next_jiffy_update_tb;
 		}
 	}
-	
+
 	smp_tb_synchronized = 1;
 	return np;
 }
@@ -263,8 +283,6 @@
 	paca[nr].xProcStart = 1;
 }
 
-extern struct gettimeofday_struct do_gtod;
-
 static void smp_space_timers( unsigned nr )
 {
 	unsigned long offset, i;
@@ -285,8 +303,8 @@
 		/* timebases already synced under the hypervisor. */
 		paca[cpu_nr].next_jiffy_update_tb = tb_last_stamp = get_tb();
 		if (cpu_nr == 0) {
-			do_gtod.tb_orig_stamp = tb_last_stamp;
-			/* Should update do_gtod.stamp_xsec.
+			naca->tb_orig_stamp = tb_last_stamp;
+			/* Should update naca->stamp_xsec.
 			 * For now we leave it which means the time can be some
 			 * number of msecs off until someone does a settimeofday()
 			 */
@@ -312,7 +330,7 @@
 			mb();
 			frozen = 0;
 			tb_last_stamp = get_tb();
-			do_gtod.tb_orig_stamp = tb_last_stamp;
+			naca->tb_orig_stamp = tb_last_stamp;
 			smp_tb_synchronized = 1;
 		} else {
 			atomic_inc(&ready);
@@ -346,7 +364,7 @@
 			set_bit(msg, &xics_ipi_message[i]);
 			mb();
 			xics_cause_IPI(i);
-			}
+		}
 	}
 }
 
@@ -387,6 +405,9 @@
 	
 	switch( msg ) {
 	case PPC_MSG_CALL_FUNCTION:
+#ifdef CONFIG_KDB
+		kdb_smp_regs[smp_processor_id()]=regs;
+#endif
 		smp_call_function_interrupt();
 		break;
 	case PPC_MSG_RESCHEDULE: 
@@ -394,15 +415,16 @@
 		break;
 #ifdef CONFIG_XMON
 	case PPC_MSG_XMON_BREAK:
-		xmon(regs);
+	        /* ToDo: need a nmi way to handle this.  Soft disable? */
+#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)
+	        if (dump_ipi_function_ptr) {
+			printk(KERN_ALERT "got dump ipi...\n");
+			dump_ipi_function_ptr(regs);
+		} else
+#endif
+			xmon(regs);
 		break;
 #endif /* CONFIG_XMON */
-#ifdef CONFIG_KDB
-	case PPC_MSG_XMON_BREAK:
-	        /* This isn't finished yet, obviously -TAI */
-		kdb(KDB_REASON_KEYBOARD,0, (kdb_eframe_t) regs);
-		break;
-#endif
 	default:
 		printk("SMP %d: smp_message_recv(): unknown msg %d\n",
 		       smp_processor_id(), msg);
@@ -422,6 +444,18 @@
 }
 #endif /* CONFIG_XMON */
 
+#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)
+void dump_send_ipi(int (*dump_ipi_callback)(struct pt_regs *))
+{
+	dump_ipi_function_ptr = dump_ipi_callback;
+	if (dump_ipi_callback) {
+		printk(KERN_ALERT "dump_send_ipi...\n");
+		mb();
+		smp_message_pass(MSG_ALL_BUT_SELF, PPC_MSG_XMON_BREAK, 0, 0);
+	}
+}
+#endif
+
 static void stop_this_cpu(void *dummy)
 {
 	__cli();
@@ -463,7 +497,7 @@
  * remote CPUs are nearly ready to execute <<func>> or are or have executed.
  *
  * You must not call this function with disabled interrupts or from a
- * hardware interrupt handler, you may call it from a bottom half handler.
+ * hardware interrupt handler or from a bottom half handler.
  */
 int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
 			int wait)
@@ -498,6 +532,10 @@
 #ifdef CONFIG_XMON
                         xmon(0);
 #endif
+#ifdef CONFIG_KDB
+			kdb(KDB_REASON_CALL,0, (kdb_eframe_t) 0);
+#endif
+
 #ifdef CONFIG_PPC_ISERIES
 			HvCall_terminateMachineSrc();
 #endif
@@ -550,6 +588,7 @@
 		atomic_inc(&call_data->finished);
 }
 
+
 extern unsigned long decr_overclock;
 
 void __init smp_boot_cpus(void)
@@ -577,7 +616,7 @@
 	init_idle();
 
 	for (i = 0; i < NR_CPUS; i++) {
-		paca[i].prof_counter=1;
+		paca[i].prof_counter = 1;
 		paca[i].prof_multiplier = 1;
 		if(i != 0) {
 		        /*
@@ -611,7 +650,7 @@
 	if (cpu_nr > max_cpus)
 		cpu_nr = max_cpus;
 
-#ifdef CONFIG_ISERIES
+#ifdef CONFIG_PPC_ISERIES
 	smp_space_timers( cpu_nr );
 #endif
 
@@ -742,7 +781,7 @@
 {
 }
 
-int __init setup_profiling_timer(unsigned int multiplier)
+int setup_profiling_timer(unsigned int multiplier)
 {
 	return 0;
 }
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/stab.c linux-2.4.20-pre5/arch/ppc64/kernel/stab.c
--- linux-2.4.20-pre4/arch/ppc64/kernel/stab.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/stab.c	Wed Aug 28 16:37:31 2002
@@ -35,7 +35,7 @@
 	esid = GET_ESID(KERNELBASE);
 	vsid = get_kernel_vsid(esid << SID_SHIFT); 
 
-	if (!__is_processor(PV_POWER4)) {
+	if (!__is_processor(PV_POWER4) && !__is_processor(PV_POWER4p)) {
                 __asm__ __volatile__("isync; slbia; isync":::"memory");
 		make_ste(stab, esid, vsid);
 	} else {
@@ -305,7 +305,7 @@
 	unsigned char *segments = get_paca()->xSegments;
 	unsigned long flags, i;
 
-	if(!__is_processor(PV_POWER4)) {
+	if (!__is_processor(PV_POWER4) && !__is_processor(PV_POWER4p)) {
 		unsigned long entry;
 		STE *ste;
 
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/sys_ppc32.c linux-2.4.20-pre5/arch/ppc64/kernel/sys_ppc32.c
--- linux-2.4.20-pre4/arch/ppc64/kernel/sys_ppc32.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/sys_ppc32.c	Wed Aug 28 16:37:31 2002
@@ -81,47 +81,6 @@
  */
 #define MSR_USERCHANGE	(MSR_FE0 | MSR_FE1)
 
-/* In order to reduce some races, while at the same time doing additional
- * checking and hopefully speeding things up, we copy filenames to the
- * kernel data space before using them..
- *
- * POSIX.1 2.4: an empty pathname is invalid (ENOENT).
- */
-static inline int do_getname32(const char *filename, char *page)
-{
-	int retval;
-
-	/* 32bit pointer will be always far below TASK_SIZE :)) */
-	retval = strncpy_from_user((char *)page, (char *)filename, PAGE_SIZE);
-	if (retval > 0) {
-		if (retval < PAGE_SIZE)
-			return 0;
-		return -ENAMETOOLONG;
-	} else if (!retval)
-		retval = -ENOENT;
-	return retval;
-}
-
-char * getname32(const char *filename)
-{
-	char *tmp, *result;
-
-	result = ERR_PTR(-ENOMEM);
-  tmp =  __getname();
-	if (tmp)  {
-		int retval = do_getname32(filename, tmp);
-
-		result = tmp;
-		if (retval < 0) {
-			putname(tmp);
-			result = ERR_PTR(retval);
-		}
-	}
-	return result;
-}
-
-
-
 extern asmlinkage long sys_utime(char * filename, struct utimbuf * times);
 
 struct utimbuf32 {
@@ -141,7 +100,7 @@
 		return sys_utime(filename, NULL);
 	if (get_user(t.actime, &times->actime) || __get_user(t.modtime, &times->modtime))
 		return -EFAULT;
-	filenam = getname32(filename);
+	filenam = getname(filename);
 
 	ret = PTR_ERR(filenam);
 	if (!IS_ERR(filenam)) {
@@ -554,7 +513,7 @@
 		return sys_quotactl(cmd, special,
 				    id, (caddr_t)addr);
 	}
-	spec = getname32 (special);
+	spec = getname (special);
 	err = PTR_ERR(spec);
 	if (IS_ERR(spec)) return err;
 	old_fs = get_fs ();
@@ -899,15 +858,6 @@
 	return ret;
 }
 
-
-
-
-/*
- * Due to some executables calling the wrong select we sometimes
- * get wrong args.  This determines how the args are being passed
- * (a single ptr to them all args passed) then calls
- * sys_select() with the appropriate args. -- Cort
- */
 /* Note: it is necessary to treat n as an unsigned int, 
  * with the corresponding cast to a signed int to insure that the 
  * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
@@ -915,14 +865,9 @@
  */
 asmlinkage int ppc32_select(u32 n, u32* inp, u32* outp, u32* exp, u32 tvp_x)
 {
-	if ((unsigned int)n >= 4096)
-		panic("ppc32_select - wrong arguments were passed in \n");
-
 	return sys32_select((int)n, inp, outp, exp, tvp_x);
 }
 
-
-
 static int cp_new_stat32(struct inode *inode, struct stat32 *statbuf)
 {
 	unsigned long ino, blksize, blocks;
@@ -1090,7 +1035,7 @@
 	
 	PPCDBG(PPCDBG_SYS32X, "sys32_statfs - entered - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
 	
-	pth = getname32 (path);
+	pth = getname (path);
 	ret = PTR_ERR(pth);
 	if (!IS_ERR(pth)) {
 		set_fs (KERNEL_DS);
@@ -2883,9 +2828,6 @@
 		}
 		break;
 	}
-#if 0
-	udbg_printf("  err3 = 0x%lx\n", err); 
-#endif
 	return err;
 }
 
@@ -4000,11 +3942,6 @@
 	int error;
 	char * filename;
 	
-	ifppcdebug(PPCDBG_SYS32) {
-		udbg_printf("sys32_execve - entered - pid=%ld, comm=%s \n", current->pid, current->comm);
-		//PPCDBG(PPCDBG_SYS32NI, "               a0=%lx, a1=%lx, a2=%lx, a3=%lx, a4=%lx, a5=%lx, regs=%p \n", a0, a1, a2, a3, a4, a5, regs);
-	}
-
 	filename = getname((char *) a0);
 	error = PTR_ERR(filename);
 	if (IS_ERR(filename))
@@ -4019,10 +3956,6 @@
 	putname(filename);
 
 out:
-	ifppcdebug(PPCDBG_SYS32) {
-		udbg_printf("sys32_execve - exited - returning %x - pid=%ld \n", error, current->pid);
-		//udbg_printf("sys32_execve - at exit - regs->gpr[1]=%lx, gpr[3]=%lx, gpr[4]=%lx, gpr[5]=%lx, gpr[6]=%lx \n", regs->gpr[1], regs->gpr[3], regs->gpr[4], regs->gpr[5], regs->gpr[6]);
-	}
 	return error;
 }
 
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/time.c linux-2.4.20-pre5/arch/ppc64/kernel/time.c
--- linux-2.4.20-pre4/arch/ppc64/kernel/time.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/time.c	Wed Aug 28 16:37:31 2002
@@ -47,6 +47,7 @@
 #include <linux/time.h>
 #include <linux/init.h>
 
+#include <asm/naca.h>
 #include <asm/segment.h>
 #include <asm/io.h>
 #include <asm/processor.h>
@@ -64,6 +65,8 @@
 
 void smp_local_timer_interrupt(struct pt_regs *);
 
+extern void setup_before_console_init();
+
 /* keep track of when we need to update the rtc */
 time_t last_rtc_update;
 extern rwlock_t xtime_lock;
@@ -83,12 +86,9 @@
 unsigned long next_xtime_sync_tb;
 unsigned long xtime_sync_interval;
 unsigned long tb_to_xs;
-unsigned      tb_to_us;
 unsigned long processor_freq;
 spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
 
-struct gettimeofday_struct do_gtod;
-
 extern unsigned long wall_jiffies;
 extern unsigned long lpEvent_count;
 extern int smp_tb_synchronized;
@@ -99,15 +99,14 @@
 extern unsigned long prof_shift;
 extern char _stext;
 
+extern struct timezone sys_tz;
+
 void ppc_adjtimex(void);
 
 static unsigned adjusting_time = 0;
 
-static inline void ppc_do_profile (unsigned long nip)
+static void ppc_do_profile (unsigned long nip)
 {
-	if (!prof_buffer)
-		return;
-
 	/*
 	 * Only measure the CPUs specified by /proc/irq/prof_cpu_mask.
 	 * (default is all CPUs.)
@@ -181,9 +180,9 @@
 #ifdef CONFIG_PPC_ISERIES
 
 /* 
- * This function recalibrates the timebase based on the 49-bit time-of-day value in the Titan chip.
- * The Titan is much more accurate than the value returned by the service processor for the
- * timebase frequency.  
+ * This function recalibrates the timebase based on the 49-bit time-of-day
+ * value in the Titan chip.  The Titan is much more accurate than the value
+ * returned by the service processor for the timebase frequency.  
  */
 
 static void iSeries_tb_recal(void)
@@ -213,9 +212,9 @@
 				tb_ticks_per_jiffy = new_tb_ticks_per_jiffy;
 				tb_ticks_per_sec   = new_tb_ticks_per_sec;
 				div128_by_32( XSEC_PER_SEC, 0, tb_ticks_per_sec, &divres );
-				do_gtod.tb_ticks_per_sec = tb_ticks_per_sec;
+				naca->tb_ticks_per_sec = tb_ticks_per_sec;
 				tb_to_xs = divres.result_low;
-				do_gtod.varp->tb_to_xs = tb_to_xs;
+				naca->tb_to_xs = tb_to_xs;
 			}
 			else {
 				printk( "Titan recalibrate: FAILED (difference > 4 percent)\n"
@@ -256,10 +255,8 @@
 
 	irq_enter(cpu);
 
-#ifndef CONFIG_PPC_ISERIES
-	if (!user_mode(regs))
+	if ((!user_mode(regs)) && (prof_buffer))
 		ppc_do_profile(instruction_pointer(regs));
-#endif
 
 	lpaca->xLpPaca.xIntDword.xFields.xDecrInt = 0;
 
@@ -306,17 +303,62 @@
 {
         unsigned long sec, usec, tb_ticks;
 	unsigned long xsec, tb_xsec;
-	struct gettimeofday_vars * temp_varp;
 	unsigned long temp_tb_to_xs, temp_stamp_xsec;
+	unsigned long tb_count_1, tb_count_2;
+	unsigned long always_zero;
+	struct naca_struct *gtdp;
+	
+	gtdp = (struct naca_struct *)0xC000000000004000;
+	/* 
+	 * The following loop guarantees that we see a consistent view of the
+	 * tb_to_xs and stamp_xsec variables.  These two variables can change
+	 * (eg. when xntpd adjusts the clock frequency) and an inconsistent
+	 * view (one variable changed, the other not) could result in a wildly
+	 * wrong result for do_gettimeofday. 
+	 *
+	 * The code which updates these variables (ppc_adjtimex below)
+	 * increments tb_update_count, then updates the two variables and then
+	 * increments tb_update_count again.  This code reads tb_update_count,
+	 * reads the two variables and then reads tb_update_count again.  It
+	 * loops doing this until the two reads of tb_update_count yield the
+	 * same value and that value is even.  This ensures a consistent view
+	 * of the two variables.
+	 *
+	 * The strange looking assembler code below causes the hardware to
+	 * think that reading the two variables is dependent on the first read
+	 * of tb_update_count and that the second reading of tb_update_count is
+	 * dependent on reading the two variables.  This assures ordering
+	 * without the need for a lwsync, which is much more expensive.
+	 */
+	do {
+		tb_ticks = get_tb() - gtdp->tb_orig_stamp;
+
+		tb_count_1 = gtdp->tb_update_count;
+
+		__asm__ __volatile__ (
+"		andc 	%0,%2,%2\n\
+		add	%1,%3,%0\n\
+"		: "=&r"(always_zero), "=r"(gtdp)
+		: "r"(tb_count_1), "r"(gtdp) );
+
+		temp_tb_to_xs = gtdp->tb_to_xs;
+		temp_stamp_xsec = gtdp->stamp_xsec;
+
+		__asm__ __volatile__ (
+"		add	%0,%2,%3\n\
+		andc	%0,%0,%0\n\
+		add	%1,%4,%0\n\
+"		: "=&r"(always_zero), "=r"(gtdp)
+		: "r"(temp_stamp_xsec), "r"(temp_tb_to_xs), "r"(gtdp) );
+
+		tb_count_2 = gtdp->tb_update_count;
+
+	} while ( tb_count_2 - ( tb_count_1 & 0xfffffffffffffffe ) ); 
 
 	/* These calculations are faster (gets rid of divides)
 	 * if done in units of 1/2^20 rather than microseconds.
 	 * The conversion to microseconds at the end is done
 	 * without a divide (and in fact, without a multiply) */
-	tb_ticks = get_tb() - do_gtod.tb_orig_stamp;
-	temp_varp = do_gtod.varp;
-	temp_tb_to_xs = temp_varp->tb_to_xs;
-	temp_stamp_xsec = temp_varp->stamp_xsec;
 	tb_xsec = mulhdu( tb_ticks, temp_tb_to_xs );
 	xsec = temp_stamp_xsec + tb_xsec;
 	sec = xsec / XSEC_PER_SEC;
@@ -370,21 +412,24 @@
 	time_maxerror = NTP_PHASE_LIMIT;
 	time_esterror = NTP_PHASE_LIMIT;
 
-	delta_xsec = mulhdu( (tb_last_stamp-do_gtod.tb_orig_stamp), do_gtod.varp->tb_to_xs );
+	delta_xsec = mulhdu( (tb_last_stamp-naca->tb_orig_stamp), naca->tb_to_xs );
 	new_xsec = (new_usec * XSEC_PER_SEC) / USEC_PER_SEC;
 	new_xsec += new_sec * XSEC_PER_SEC;
 	if ( new_xsec > delta_xsec ) {
-		do_gtod.varp->stamp_xsec = new_xsec - delta_xsec;
+		naca->stamp_xsec = new_xsec - delta_xsec;
 	}
 	else {
 		/* This is only for the case where the user is setting the time
 		 * way back to a time such that the boot time would have been
-		 * before 1970 ... eg. we booted ten days ago, and we are setting
-		 * the time to Jan 5, 1970 */
-		do_gtod.varp->stamp_xsec = new_xsec;
-		do_gtod.tb_orig_stamp = tb_last_stamp;
+		 * before 1970 ... eg. we booted ten days ago, and we are
+		 * setting the time to Jan 5, 1970 */
+		naca->stamp_xsec = new_xsec;
+		naca->tb_orig_stamp = tb_last_stamp;
 	}
 
+	naca->tz_minuteswest = sys_tz.tz_minuteswest;
+	naca->tz_dsttime = sys_tz.tz_dsttime;
+
 	write_unlock_irqrestore(&xtime_lock, flags);
 }
 
@@ -453,13 +498,11 @@
 	xtime.tv_sec = mktime(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
 			      tm.tm_hour, tm.tm_min, tm.tm_sec);
 	tb_last_stamp = get_tb();
-	do_gtod.tb_orig_stamp = tb_last_stamp;
-	do_gtod.varp = &do_gtod.vars[0];
-	do_gtod.var_idx = 0;
-	do_gtod.varp->stamp_xsec = xtime.tv_sec * XSEC_PER_SEC;
-	do_gtod.tb_ticks_per_sec = tb_ticks_per_sec;
-	do_gtod.varp->tb_to_xs = tb_to_xs;
-	do_gtod.tb_to_us = tb_to_us;
+	naca->tb_orig_stamp = tb_last_stamp;
+	naca->tb_update_count = 0;
+	naca->tb_ticks_per_sec = tb_ticks_per_sec;
+	naca->stamp_xsec = xtime.tv_sec * XSEC_PER_SEC;
+	naca->tb_to_xs = tb_to_xs;
 
 	xtime_sync_interval = tb_ticks_per_sec - (tb_ticks_per_sec/8);
 	next_xtime_sync_tb = tb_last_stamp + xtime_sync_interval;
@@ -470,23 +513,21 @@
 	last_rtc_update = xtime.tv_sec;
 	write_unlock_irqrestore(&xtime_lock, flags);
 
-#ifdef CONFIG_PPC_ISERIES
-	/* HACK HACK This allows the iSeries profiling to use /proc/profile */
-	prof_shift = 0;
-#endif
-
 	/* Not exact, but the timer interrupt takes care of this */
 	set_dec(tb_ticks_per_jiffy);
+
+	/* This horrible hack gives setup a hook just before console_init */
+	setup_before_console_init();
 }
 
 /* 
  * After adjtimex is called, adjust the conversion of tb ticks
  * to microseconds to keep do_gettimeofday synchronized 
  * with ntpd.
-
+ *
  * Use the time_adjust, time_freq and time_offset computed by adjtimex to 
  * adjust the frequency.
-*/
+ */
 
 /* #define DEBUG_PPC_ADJTIMEX 1 */
 
@@ -497,8 +538,6 @@
 	long delta_freq, ltemp;
 	struct div_result divres; 
 	unsigned long flags;
-	struct gettimeofday_vars * temp_varp;
-	unsigned temp_idx;
 	long singleshot_ppm = 0;
 
 	/* Compute parts per million frequency adjustment to accomplish the time adjustment
@@ -529,8 +568,11 @@
 		
 		/* Compute parts per million frequency adjustment to match time_adjust */
 		singleshot_ppm = tickadj * HZ;	
-		/* The adjustment should be tickadj*HZ to match the code in linux/kernel/timer.c, but
-		   experiments show that this is too large. 3/4 of tickadj*HZ seems about right */
+		/*
+		 * The adjustment should be tickadj*HZ to match the code in
+		 * linux/kernel/timer.c, but experiments show that this is too
+		 * large. 3/4 of tickadj*HZ seems about right
+		 */
 		singleshot_ppm -= singleshot_ppm / 4;
 		/* Use SHIFT_USEC to get it into the same units as time_freq */	
 		singleshot_ppm <<= SHIFT_USEC;
@@ -564,36 +606,38 @@
 	printk("ppc_adjtimex: tb_ticks_per_sec - base = %ld  new = %ld\n", tb_ticks_per_sec, new_tb_ticks_per_sec);
 #endif
 				
-	/* Compute a new value of tb_to_xs (used to convert tb to microseconds and a new value of 
-	   stamp_xsec which is the time (in 1/2^20 second units) corresponding to tb_orig_stamp.  This 
-	   new value of stamp_xsec compensates for the change in frequency (implied by the new tb_to_xs)
-	   which guarantees that the current time remains the same */ 
-	tb_ticks = get_tb() - do_gtod.tb_orig_stamp;
+	/*
+	 * Compute a new value of tb_to_xs (used to convert tb to microseconds
+	 * and a new value of stamp_xsec which is the time (in 1/2^20 second
+	 * units) corresponding to tb_orig_stamp.  This new value of stamp_xsec
+	 * compensates for the change in frequency (implied by the new
+	 * tb_to_xs) and so guarantees that the current time remains the same
+	 *
+	 */ 
+	tb_ticks = get_tb() - naca->tb_orig_stamp;
 	div128_by_32( 1024*1024, 0, new_tb_ticks_per_sec, &divres );
 	new_tb_to_xs = divres.result_low;
 	new_xsec = mulhdu( tb_ticks, new_tb_to_xs );
 
 	write_lock_irqsave( &xtime_lock, flags );
-	old_xsec = mulhdu( tb_ticks, do_gtod.varp->tb_to_xs );
-	new_stamp_xsec = do_gtod.varp->stamp_xsec + old_xsec - new_xsec;
+	old_xsec = mulhdu( tb_ticks, naca->tb_to_xs );
+	new_stamp_xsec = naca->stamp_xsec + old_xsec - new_xsec;
 
-	/* There are two copies of tb_to_xs and stamp_xsec so that no lock is needed to access and use these
-	   values in do_gettimeofday.  We alternate the copies and as long as a reasonable time elapses between
-	   changes, there will never be inconsistent values.  ntpd has a minimum of one minute between updates */
-
-	if (do_gtod.var_idx == 0) {
-		temp_varp = &do_gtod.vars[1];
-		temp_idx  = 1;
-	}
-	else {
-		temp_varp = &do_gtod.vars[0];
-		temp_idx  = 0;
-	}
-	temp_varp->tb_to_xs = new_tb_to_xs;
-	temp_varp->stamp_xsec = new_stamp_xsec;
-	mb();
-	do_gtod.varp = temp_varp;
-	do_gtod.var_idx = temp_idx;
+	/*
+	 * tb_update_count is used to allow the problem state gettimeofday code
+	 * to assure itself that it sees a consistent view of the tb_to_xs and
+	 * stamp_xsec variables.  It reads the tb_update_count, then reads
+	 * tb_to_xs and stamp_xsec and then reads tb_update_count again.  If
+	 * the two values of tb_update_count match and are even then the
+	 * tb_to_xs and stamp_xsec values are consistent.  If not, then it
+	 * loops back and reads them again until this criteria is met.
+	 */
+	++(naca->tb_update_count);
+	wmb();
+	naca->tb_to_xs = new_tb_to_xs;
+	naca->stamp_xsec = new_stamp_xsec;
+	wmb();
+	++(naca->tb_update_count);
 
 	write_unlock_irqrestore( &xtime_lock, flags );
 
@@ -691,6 +735,7 @@
 	GregorianDay(tm);
 }
 
+#if 0
 /* Auxiliary function to compute scaling factors */
 /* Actually the choice of a timebase running at 1/4 the of the bus
  * frequency giving resolution of a few tens of nanoseconds is quite nice.
@@ -720,6 +765,7 @@
         if (err <= inscale/2) mlt++;
         return mlt;
   }
+#endif
 
 /*
  * Divide a 128-bit dividend by a 32-bit divisor, leaving a 128 bit
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/traps.c linux-2.4.20-pre5/arch/ppc64/kernel/traps.c
--- linux-2.4.20-pre4/arch/ppc64/kernel/traps.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/traps.c	Wed Aug 28 16:37:31 2002
@@ -29,6 +29,8 @@
 #include <linux/interrupt.h>
 #include <linux/config.h>
 #include <linux/init.h>
+#include <asm/iSeries/HvCall.h>
+#include <asm/iSeries/HvCallCfg.h>
 
 #ifdef CONFIG_KDB
 #include <linux/kdb.h>
@@ -71,8 +73,23 @@
 int (*debugger_iabr_match)(struct pt_regs *regs);
 int (*debugger_dabr_match)(struct pt_regs *regs);
 void (*debugger_fault_handler)(struct pt_regs *regs);
-#endif
-#endif
+#else
+#ifdef CONFIG_KDB
+/* kdb has different call parms */
+/* ... */
+void (*debugger)(struct pt_regs *regs) = kdb;
+int (*debugger_bpt)(struct pt_regs *regs);
+int (*debugger_sstep)(struct pt_regs *regs);
+int (*debugger_iabr_match)(struct pt_regs *regs);
+int (*debugger_dabr_match)(struct pt_regs *regs);
+/* - only defined during (xmon) mread */
+void (*debugger_fault_handler)(struct pt_regs *regs);
+#endif /* kdb */
+#endif /* kgdb */
+#endif /* xmon */
+
+void set_local_DABR(void *valp);
+
 /*
  * Trap & Exception support
  */
@@ -151,7 +168,16 @@
 	xmon(regs);
 	udbg_printf("leaving xmon...\n");
 #endif
+#if defined(CONFIG_KDB)
+	kdb(KDB_REASON_ENTER, regs->trap, (kdb_eframe_t) regs);
+	udbg_printf("leaving kdb...\n");
+#endif
+
+/*
+allow system to resume after reset.
 	for(;;);
+*/
+
 }
 
 
@@ -272,14 +298,6 @@
 	_exception(SIGTRAP, regs);	
 }
 
-/* Dummy handler for Performance Monitor */
-
-void
-PerformanceMonitorException(struct pt_regs *regs)
-{
-	_exception(SIGTRAP, regs);
-}
-
 void
 AlignmentException(struct pt_regs *regs)
 {
@@ -307,3 +325,20 @@
 void __init trap_init(void)
 {
 }
+
+/*
+ * Set the DABR on all processors in the system.  The value is defined as:
+ * DAB(0:60), Break Translate(61), Write(62), Read(63)
+ */
+void
+set_all_DABR(unsigned long val) {
+	set_local_DABR(&val); 
+	smp_call_function(set_local_DABR, &val, 0, 0);
+}
+
+void
+set_local_DABR(void *valp) {
+	unsigned long val = *((unsigned long *)valp); 
+
+	HvCall_setDABR(val);
+}
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/udbg.c linux-2.4.20-pre5/arch/ppc64/kernel/udbg.c
--- linux-2.4.20-pre4/arch/ppc64/kernel/udbg.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/udbg.c	Wed Aug 28 16:37:31 2002
@@ -52,8 +52,6 @@
 
 volatile struct NS16550 *udbg_comport;
 
-spinlock_t udbg_lock = SPIN_LOCK_UNLOCKED;
-
 void
 udbg_init_uart(void *comport)
 {
@@ -161,6 +159,12 @@
 }
 
 void
+udbg_console_write(struct console *con, const char *s, unsigned int n)
+{
+	udbg_write(s, n);
+}
+
+void
 udbg_puthex(unsigned long val)
 {
 	int i, nibbles = sizeof(val)*2;
@@ -190,16 +194,13 @@
 void
 udbg_printf(const char *fmt, ...)
 {
-	unsigned long flags;
 	unsigned char buf[256];
 
 	va_list args;
 	va_start(args, fmt);
 
-	spin_lock_irqsave(&udbg_lock, flags);
 	vsprintf(buf, fmt, args);
 	udbg_puts(buf);
-	spin_unlock_irqrestore(&udbg_lock, flags);
 
 	va_end(args);
 }
@@ -208,7 +209,6 @@
 void
 udbg_ppcdbg(unsigned long debug_flags, const char *fmt, ...)
 {
-	unsigned long flags;
 	unsigned long active_debugs = debug_flags & naca->debug_switch;
 
 	if ( active_debugs ) {
@@ -216,7 +216,6 @@
 		unsigned char buf[256];
 		unsigned long i, len = 0;
 
-		spin_lock_irqsave(&udbg_lock, flags);
 		for(i=0; i < PPCDBG_NUM_FLAGS ;i++) {
 			if (((1U << i) & active_debugs) && 
 			    trace_names[i]) {
@@ -237,7 +236,6 @@
 		va_start(ap, fmt);
 		vsprintf(buf, fmt, ap);
 		udbg_puts(buf);
-		spin_unlock_irqrestore(&udbg_lock, flags);
 		
 		va_end(ap);
 	}
diff -urN linux-2.4.20-pre4/arch/ppc64/kernel/xics.c linux-2.4.20-pre5/arch/ppc64/kernel/xics.c
--- linux-2.4.20-pre4/arch/ppc64/kernel/xics.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/kernel/xics.c	Wed Aug 28 16:37:31 2002
@@ -231,9 +231,9 @@
 		}
 	} else if( vec == XICS_IRQ_SPURIOUS ) {
 		irq = -1;
-		printk("spurious PPC interrupt!\n");
-	} else
+	} else {
 		irq = real_irq_to_virt(vec) + XICS_IRQ_OFFSET;
+	}
 	return irq;
 }
 
@@ -285,6 +285,8 @@
 	struct device_node *np;
 	uint *ireg, ilen, indx=0;
 
+	ppc64_boot_msg(0x20, "XICS Init");
+
 	ibm_get_xive = rtas_token("ibm,get-xive");
 	ibm_set_xive = rtas_token("ibm,set-xive");
 	ibm_int_off = rtas_token("ibm,int-off");
@@ -347,6 +349,7 @@
 	np = find_type_devices("interrupt-controller");
 	if (!np) {
 		printk(KERN_WARNING "xics:  no ISA Interrupt Controller\n");
+		xics_irq_8259_cascade_real = -1;
 		xics_irq_8259_cascade = -1;
 	} else {
 		ireg = (uint *) get_property(np, "interrupts", 0);
@@ -399,6 +402,7 @@
 	request_irq(XICS_IPI + XICS_IRQ_OFFSET, xics_ipi_action, 0, "IPI", 0);
 	irq_desc[XICS_IPI+XICS_IRQ_OFFSET].status |= IRQ_PER_CPU;
 #endif
+	ppc64_boot_msg(0x21, "XICS Done");
 }
 
 void xics_isa_init(void)
diff -urN linux-2.4.20-pre4/arch/ppc64/lib/string.S linux-2.4.20-pre5/arch/ppc64/lib/string.S
--- linux-2.4.20-pre4/arch/ppc64/lib/string.S	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/lib/string.S	Wed Aug 28 16:37:31 2002
@@ -351,9 +351,9 @@
 #endif /* MAX_COPY_PREFETCH */
 
 	mtctr	r0
-53:
 	dcbt	r3,r4
-	dcbz	r11,r6
+53:
+54:	dcbz	r11,r6
 /* had to move these to keep extable in order */
 	.section __ex_table,"a"
 	.align	3
@@ -361,7 +361,7 @@
 	.llong	71b,101f
 	.llong	72b,102f
 	.llong	73b,103f
-	.llong	53b,105f
+	.llong	54b,105f
 	.text
 /* the main body of the cacheline loop */
 	COPY_16_BYTES_WITHEX(0)
@@ -504,11 +504,11 @@
 	add	r4,r0,r4
 	subf	r6,r0,r6
 	srwi	r0,r4,2
+	andi.	r4,r4,3
 	mtctr	r0
-	bdz	6f
+	bdz	7f
 1:	stwu	r5,4(r6)
 	bdnz	1b
-6:	andi.	r4,r4,3
 	/* clear byte sized chunks */
 7:	cmpwi	0,r4,0
 	beqlr
@@ -517,14 +517,20 @@
 8:	stbu	r5,1(r6)
 	bdnz	8b
 	blr
-99:	li	r3,-EFAULT
+90:	mr	r3,r4
+	blr
+91:	mfctr	r3
+	slwi	r3,r3,2
+	add	r3,r3,r4
+	blr
+92:	mfctr	r3
 	blr
 
 	.section __ex_table,"a"
 	.align	3
-	.llong	11b,99b
-	.llong	1b,99b
-	.llong	8b,99b
+	.llong	11b,90b
+	.llong	1b,91b
+	.llong	8b,92b
 	.text
 
 _GLOBAL(__strncpy_from_user)
diff -urN linux-2.4.20-pre4/arch/ppc64/mm/fault.c linux-2.4.20-pre5/arch/ppc64/mm/fault.c
--- linux-2.4.20-pre4/arch/ppc64/mm/fault.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/mm/fault.c	Wed Aug 28 16:37:31 2002
@@ -38,7 +38,11 @@
 
 #include <asm/ppcdebug.h>
 
-#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+#if defined(CONFIG_KDB)
+#include <linux/kdb.h>
+#endif
+	
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB) || defined(CONFIG_KDB)
 extern void (*debugger)(struct pt_regs *);
 extern void (*debugger_fault_handler)(struct pt_regs *);
 extern int (*debugger_dabr_match)(struct pt_regs *);
@@ -118,7 +122,7 @@
 
 good_area:
 	code = SEGV_ACCERR;
-	
+
 	/* a write */
 	if (is_write) {
 		if (!(vma->vm_flags & VM_WRITE))
@@ -159,7 +163,7 @@
 
 bad_area:
 	up_read(&mm->mmap_sem);
-	
+
 	/* User mode accesses cause a SIGSEGV */
 	if (user_mode(regs)) {
 		info.si_signo = SIGSEGV;
@@ -224,8 +228,10 @@
 	if (debugger_kernel_faults)
 		debugger(regs);
 #endif
+#if defined(CONFIG_KDB)
+	kdb(KDB_REASON_FAULT, regs->trap, regs);
+#endif	
 	print_backtrace( (unsigned long *)regs->gpr[1] );
 	panic("kernel access of bad area pc %lx lr %lx address %lX tsk %s/%d",
 	      regs->nip,regs->link,address,current->comm,current->pid);
 }
-
diff -urN linux-2.4.20-pre4/arch/ppc64/mm/init.c linux-2.4.20-pre5/arch/ppc64/mm/init.c
--- linux-2.4.20-pre4/arch/ppc64/mm/init.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/mm/init.c	Wed Aug 28 16:37:31 2002
@@ -1,6 +1,4 @@
 /*
- *  
- *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
  *
@@ -214,7 +212,7 @@
 	else {
 		ea = ioremap_bot;
 		ioremap_bot += size;
-        }
+	}
 
 	if ((flags & _PAGE_PRESENT) == 0)
 		flags |= pgprot_val(PAGE_KERNEL);
@@ -231,9 +229,9 @@
 void iounmap(void *addr) 
 {
 #ifdef CONFIG_PPC_ISERIES
-     /* iSeries I/O Remap is a noop              */
+	/* iSeries I/O Remap is a noop              */
 	return;
-#else 
+#else
 	/* DRENG / PPPBBB todo */
 	return;
 #endif
@@ -264,7 +262,7 @@
 		/* If the mm subsystem is not fully up, we cannot create a
 		 * linux page table entry for this mapping.  Simply bolt an
 		 * entry in the hardware page table. 
- 		 */
+		 */
 		vsid = get_kernel_vsid(ea);
 		make_pte(htab_data.htab,
 			(vsid << 28) | (ea & 0xFFFFFFF), // va (NOT the ea)
@@ -434,12 +432,11 @@
 }
 #endif
 
-
-
 /*
  * Do very early mm setup.
  */
-void __init mm_init_ppc64(void) {
+void __init mm_init_ppc64(void)
+{
 	struct paca_struct *lpaca;
 	unsigned long guard_page, index;
 
@@ -467,8 +464,6 @@
 	ppc_md.progress("MM:exit", 0x211);
 }
 
-
-
 /*
  * Initialize the bootmem system and give it all the memory we
  * have available.
@@ -488,7 +483,7 @@
 	bootmap_pages = bootmem_bootmap_pages(total_pages);
 
 	start = (unsigned long)__a2p(lmb_alloc(bootmap_pages<<PAGE_SHIFT, PAGE_SIZE));
-	if( start == 0 ) {
+	if (start == 0) {
 		udbg_printf("do_init_bootmem: failed to allocate a bitmap.\n");
 		udbg_printf("\tbootmap_pages = 0x%lx.\n", bootmap_pages);
 		PPCDBG_ENTER_DEBUGGER(); 
@@ -502,7 +497,7 @@
 	PPCDBG(PPCDBG_MMINIT, "\tboot_mapsize        = 0x%lx\n", boot_mapsize);
 
 	/* add all physical memory to the bootmem map */
-	for (i=0; i < lmb.memory.cnt ;i++) {
+	for (i=0; i < lmb.memory.cnt; i++) {
 		unsigned long physbase, size;
 		unsigned long type = lmb.memory.region[i].type;
 
@@ -514,7 +509,7 @@
 		free_bootmem(physbase, size);
 	}
 	/* reserve the sections we're already using */
-	for (i=0; i < lmb.reserved.cnt ;i++) {
+	for (i=0; i < lmb.reserved.cnt; i++) {
 		unsigned long physbase = lmb.reserved.region[i].physbase;
 		unsigned long size = lmb.reserved.region[i].size;
 #if 0 /* PPPBBB */
@@ -538,19 +533,12 @@
 	/*
 	 * All pages are DMA-able so we put them all in the DMA zone.
 	 */
-	zones_size[0] = lmb_end_of_DRAM() >> PAGE_SHIFT;
+	zones_size[ZONE_DMA] = lmb_end_of_DRAM() >> PAGE_SHIFT;
 	for (i = 1; i < MAX_NR_ZONES; i++)
 		zones_size[i] = 0;
 	free_area_init(zones_size);
 }
 
-extern unsigned long prof_shift;
-extern unsigned long prof_len;
-extern unsigned int * prof_buffer;
-extern unsigned long dprof_shift;
-extern unsigned long dprof_len;
-extern unsigned int * dprof_buffer;
-
 void initialize_paca_hardware_interrupt_stack(void);
 
 void __init mem_init(void)
@@ -609,10 +597,6 @@
 
 #ifdef CONFIG_PPC_ISERIES
 	create_virtual_bus_tce_table();
-	/* HACK HACK This allows the iSeries profiling to use /proc/profile */
-	prof_shift = dprof_shift;
-	prof_len = dprof_len;
-	prof_buffer = dprof_buffer;
 #endif
 }
 
diff -urN linux-2.4.20-pre4/arch/ppc64/xmon/privinst.h linux-2.4.20-pre5/arch/ppc64/xmon/privinst.h
--- linux-2.4.20-pre4/arch/ppc64/xmon/privinst.h	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/xmon/privinst.h	Wed Aug 28 16:37:32 2002
@@ -6,7 +6,6 @@
  *      as published by the Free Software Foundation; either version
  *      2 of the License, or (at your option) any later version.
  */
-#include <linux/config.h>
 
 #define GETREG(reg)		\
     static inline unsigned long get_ ## reg (void)	\
diff -urN linux-2.4.20-pre4/arch/ppc64/xmon/start.c linux-2.4.20-pre5/arch/ppc64/xmon/start.c
--- linux-2.4.20-pre4/arch/ppc64/xmon/start.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/xmon/start.c	Wed Aug 28 16:37:32 2002
@@ -9,6 +9,7 @@
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/sysrq.h>
+#include <linux/fs.h>
 #include <asm/machdep.h>
 #include <asm/io.h>
 #include <asm/page.h>
diff -urN linux-2.4.20-pre4/arch/ppc64/xmon/xmon.c linux-2.4.20-pre5/arch/ppc64/xmon/xmon.c
--- linux-2.4.20-pre4/arch/ppc64/xmon/xmon.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/ppc64/xmon/xmon.c	Wed Aug 28 16:37:32 2002
@@ -123,12 +123,10 @@
 static void mem_check(void);
 static void mem_find_real(void);
 static void mem_find_vsid(void);
-static void mem_check_full_group(void);
 static void mem_check_pagetable_vsids (void);
 
 static void mem_map_check_slab(void);
 static void mem_map_lock_pages(void);
-static void mem_map_check_hash(void);
 static void mem_check_dup_rpn (void);
 static void debug_trace(void);
 
@@ -191,13 +189,6 @@
 	asm volatile("sync; isync");
 }
 
-extern inline void __delay(unsigned int loops)
-{
-	if (loops != 0)
-		__asm__ __volatile__("mtctr %0; 1: bdnz 1b" : :
-				     "r" (loops) : "ctr");
-}
-
 /* (Ref: 64-bit PowerPC ELF ABI Spplement; Ian Lance Taylor, Zembu Labs).
  A PPC stack frame looks like this:
 
@@ -544,7 +535,7 @@
 		}
 	}
 
-	if (!__is_processor(PV_POWER4)) {
+	if (!__is_processor(PV_POWER4) && !__is_processor(PV_POWER4p)) {
 		if (dabr.enabled)
 			set_dabr(dabr.address);
 		if (iabr.enabled)
@@ -561,7 +552,7 @@
 
 	if (naca->platform != PLATFORM_PSERIES)
 		return;
-	if (!__is_processor(PV_POWER4)) {
+	if (!__is_processor(PV_POWER4) && !__is_processor(PV_POWER4p)) {
 		set_dabr(0);
 		set_iabr(0);
 	}
@@ -634,15 +625,9 @@
 			case 'c':
 				mem_check();
 				break;
-			case 'g':
-				mem_check_full_group();
-				break;
 			case 'j':
 				mem_map_check_slab();
 				break;
-			case 'h':
-				mem_map_check_hash();
-				break;
 			case 'f':
 				mem_find_real();
 				break;
@@ -864,7 +849,7 @@
 	cmd = inchar();
 	switch (cmd) {
 	case 'd':	/* bd - hardware data breakpoint */
-		if (__is_processor(PV_POWER4)) {
+		if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p)) {
 			printf("Not implemented on POWER4\n");
 			break;
 		}
@@ -884,8 +869,7 @@
 			dabr.address = (dabr.address & ~7) | mode;
 		break;
 	case 'i':	/* bi - hardware instr breakpoint */
-		if (__is_processor(PV_POWER4)) {
-			printf("Not implemented on POWER4\n");
+		if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p)) {
 			break;
 		}
 		iabr.address = 0;
@@ -2490,34 +2474,6 @@
 	printf(" count of locked pages = %d \n", lock_count); 
 }
 
-
-
-void mem_map_check_hash()
-{
-	int i = max_mapnr;
-	
-	while (i-- > 0)  {
-		/* skip the reserved */
-		if (!PageReserved(mem_map+i)) {
-			if (((mem_map+i)->next_hash) != NULL) {
-				if ( REGION_ID((mem_map+i)->next_hash) != KERNEL_REGION_ID ) {
-					printf(" mem_map check hash - non c0 entry - "
-					       "address/value = %p %lx\n", mem_map+i,(mem_map+i)->next_hash);
-				} 
-				if ((unsigned long)((mem_map+i)->next_hash) ==  KERNELBASE){
-					printf(" mem_map check hash - 0x%lx  entry = %p \n",
-					       KERNELBASE, mem_map+i);
-				} 
-			}
-		} else {
-			if (page_count(mem_map+i) < 0) {
-				printf(" reserved page with negative count- entry = %lx \n", mem_map+i);
-			}
-		}
-	}
-	printf(" mem_map check hash completed \n");
-}
-
 void mem_check_dup_rpn ()
 {
 	unsigned long htab_size_bytes;
@@ -2727,70 +2683,6 @@
 
 }
 
-
-void mem_check_full_group()
-{
-	unsigned long htab_size_bytes;
-	unsigned count;
-	unsigned count_array[] = {0,0,0,0,0,0,0,0,0}; 
-	unsigned i;
-	unsigned long htab_end;
-	HPTE *hpte1, *hpte2, *hpte3;
-	u64  rpn = 0;
-
-	htab_size_bytes = htab_data.htab_num_ptegs * 128; // 128B / PTEG
-	htab_end = (unsigned long)htab_data.htab + htab_size_bytes;
-
-	printf("\nHardware Page Find full groups \n-------------------\n");
-	printf("htab base      : %.16lx\n", htab_data.htab);
-	printf("htab size      : %.16lx\n", htab_size_bytes);
-
-	for (hpte1 = htab_data.htab; (unsigned long)hpte1 < htab_end; hpte1= hpte1 + 8)
-	{
-		count = 0;
-		hpte2 = hpte1;
-		for (i=0; i<8; ++i)
-		{
-			if ( hpte2->dw0.dw0.v != 0 )
-			{
-				count++;
-			}
-			hpte2++;
-		}
-		if (count == 8 )
-		{
-			printf("  full group starting with entry %lx \n", hpte1);
-			hpte3 = hpte1;
-			for (i=0; i<8; ++i)
-			{
-				if ( hpte3->dw0.dw0.v != 0 )
-				{
-					printf(" entry number %d   \n",i);
-					printf("          vsid: %.13lx   api: %.2lx  hash: %.1lx\n", 
-					       (hpte3->dw0.dw0.avpn)>>5, 
-					       (hpte3->dw0.dw0.avpn) & 0x1f,
-					       (hpte3->dw0.dw0.h));
-					printf("          rpn: %.13lx \n", (hpte3->dw1.dw1.rpn)); 
-					// Dump out the memmap array entry address, corresponding virtual address, and reference count.
-					rpn = hpte3->dw1.dw1.rpn;
-					printf("          mem_map+rpn=%p, virtual@=%p, count=%lx \n", mem_map+rpn, (mem_map+rpn)->virtual, (mem_map+rpn)->count);
-				}
-				hpte3++;
-			}
-			if (xmon_interrupted())
-				return;
-		}
-
-		count_array[count]++;
-	}
-	for (i=1; i<9; ++i)
-	{
-		printf("  group count for size  %i = %lx \n", i, count_array[i]);
-	}
-
-	printf("\nDone -------------------\n");
-}
-
 static void debug_trace(void) {
         unsigned long val, cmd, on;
 
diff -urN linux-2.4.20-pre4/arch/s390/mm/fault.c linux-2.4.20-pre5/arch/s390/mm/fault.c
--- linux-2.4.20-pre4/arch/s390/mm/fault.c	Wed Aug 28 16:36:45 2002
+++ linux-2.4.20-pre5/arch/s390/mm/fault.c	Wed Aug 28 16:37:32 2002
@@ -291,12 +291,11 @@
  * us unable to handle the page fault gracefully.
 */
 out_of_memory:
-	up_read(&mm->mmap_sem);
 	if (tsk->pid == 1) {
 		yield();
-		down_read(&mm->mmap_sem);
 		goto survive;
 	}
+	up_read(&mm->mmap_sem);
 	printk("VM: killing process %s\n", tsk->comm);
 	if (regs->psw.mask & PSW_PROBLEM_STATE)
 		do_exit(SIGKILL);
diff -urN linux-2.4.20-pre4/arch/s390x/mm/fault.c linux-2.4.20-pre5/arch/s390x/mm/fault.c
--- linux-2.4.20-pre4/arch/s390x/mm/fault.c	Wed Aug 28 16:36:45 2002
+++ linux-2.4.20-pre5/arch/s390x/mm/fault.c	Wed Aug 28 16:37:32 2002
@@ -291,12 +291,11 @@
  * us unable to handle the page fault gracefully.
 */
 out_of_memory:
-	up_read(&mm->mmap_sem);
 	if (tsk->pid == 1) {
 		yield();
-		down_read(&mm->mmap_sem);
 		goto survive;
 	}
+	up_read(&mm->mmap_sem);
 	printk("VM: killing process %s\n", tsk->comm);
 	if (regs->psw.mask & PSW_PROBLEM_STATE)
 		do_exit(SIGKILL);
diff -urN linux-2.4.20-pre4/arch/sh/mm/fault.c linux-2.4.20-pre5/arch/sh/mm/fault.c
--- linux-2.4.20-pre4/arch/sh/mm/fault.c	Wed Aug 28 16:36:45 2002
+++ linux-2.4.20-pre5/arch/sh/mm/fault.c	Wed Aug 28 16:37:33 2002
@@ -205,12 +205,11 @@
  * us unable to handle the page fault gracefully.
  */
 out_of_memory:
-	up_read(&mm->mmap_sem);
 	if (current->pid == 1) {
 		yield();
-		down_read(&mm->mmap_sem);
 		goto survive;
 	}
+	up_read(&mm->mmap_sem);
 	printk("VM: killing process %s\n", tsk->comm);
 	if (user_mode(regs))
 		do_exit(SIGKILL);
diff -urN linux-2.4.20-pre4/arch/sparc/kernel/pcic.c linux-2.4.20-pre5/arch/sparc/kernel/pcic.c
--- linux-2.4.20-pre4/arch/sparc/kernel/pcic.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/sparc/kernel/pcic.c	Wed Aug 28 16:37:35 2002
@@ -869,7 +869,7 @@
 {
 }
 
-int pcibios_enable_device(struct pci_dev *pdev)
+int pcibios_enable_device(struct pci_dev *pdev, int mask)
 {
 	return 0;
 }
diff -urN linux-2.4.20-pre4/arch/sparc64/config.in linux-2.4.20-pre5/arch/sparc64/config.in
--- linux-2.4.20-pre4/arch/sparc64/config.in	Wed Aug 28 16:36:45 2002
+++ linux-2.4.20-pre5/arch/sparc64/config.in	Wed Aug 28 16:37:42 2002
@@ -262,10 +262,10 @@
 
 mainmenu_option next_comment
 comment 'XFree86 DRI support'
-bool 'Direct Rendering Manager (XFree86 DRI support)' CONFIG_DRM
-dep_tristate '  Creator/Creator3D' CONFIG_DRM_FFB $CONFIG_DRM
-dep_tristate '  3dfx Banshee/Voodoo3+' CONFIG_DRM_TDFX $CONFIG_DRM
-dep_tristate '  ATI Rage 128' CONFIG_DRM_R128 $CONFIG_DRM
+bool 'Direct Rendering Manager (XFree86 DRI support)' CONFIG_DRM_NEW
+dep_tristate '  Creator/Creator3D' CONFIG_DRM_FFB $CONFIG_DRM_NEW
+dep_tristate '  3dfx Banshee/Voodoo3+' CONFIG_DRM_TDFX $CONFIG_DRM_NEW
+dep_tristate '  ATI Rage 128' CONFIG_DRM_R128 $CONFIG_DRM_NEW
 endmenu
 
 source drivers/input/Config.in
diff -urN linux-2.4.20-pre4/arch/sparc64/defconfig linux-2.4.20-pre5/arch/sparc64/defconfig
--- linux-2.4.20-pre4/arch/sparc64/defconfig	Wed Aug 28 16:36:45 2002
+++ linux-2.4.20-pre5/arch/sparc64/defconfig	Wed Aug 28 16:37:42 2002
@@ -225,6 +225,7 @@
 #
 CONFIG_NET_SCHED=y
 CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
 CONFIG_NET_SCH_CSZ=m
 CONFIG_NET_SCH_PRIO=m
 CONFIG_NET_SCH_RED=m
@@ -476,17 +477,16 @@
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
 CONFIG_TULIP=m
-# CONFIG_TC35815 is not set
 # CONFIG_TULIP_MWI is not set
 # CONFIG_TULIP_MMIO is not set
 CONFIG_DE4X5=m
 CONFIG_DGRS=m
 # CONFIG_DM9102 is not set
 CONFIG_EEPRO100=m
+CONFIG_E100=m
 # CONFIG_LNE390 is not set
 CONFIG_FEALNX=m
 CONFIG_NATSEMI=m
-# CONFIG_NATSEMI_CABLE_MAGIC is not set
 CONFIG_NE2K_PCI=m
 # CONFIG_NE3210 is not set
 # CONFIG_ES3210 is not set
@@ -495,11 +495,12 @@
 # CONFIG_8139TOO_PIO is not set
 # CONFIG_8139TOO_TUNE_TWISTER is not set
 # CONFIG_8139TOO_8129 is not set
-# CONFIG_8139_NEW_RX_RESET is not set
+# CONFIG_8139_OLD_RX_RESET is not set
 CONFIG_SIS900=m
 CONFIG_EPIC100=m
 CONFIG_SUNDANCE=m
 # CONFIG_TLAN is not set
+# CONFIG_TC35815 is not set
 CONFIG_VIA_RHINE=m
 # CONFIG_VIA_RHINE_MMIO is not set
 CONFIG_WINBOND_840=m
@@ -511,6 +512,7 @@
 CONFIG_ACENIC=m
 # CONFIG_ACENIC_OMIT_TIGON_I is not set
 CONFIG_DL2K=m
+CONFIG_E1000=m
 CONFIG_MYRI_SBUS=m
 CONFIG_NS83820=m
 CONFIG_HAMACHI=m
@@ -570,7 +572,7 @@
 #
 # XFree86 DRI support
 #
-CONFIG_DRM=y
+CONFIG_DRM_NEW=y
 CONFIG_DRM_FFB=m
 CONFIG_DRM_TDFX=m
 # CONFIG_DRM_R128 is not set
@@ -660,7 +662,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -766,6 +767,7 @@
 # CONFIG_USB_AUDIO is not set
 # CONFIG_USB_EMI26 is not set
 CONFIG_USB_BLUETOOTH=m
+CONFIG_USB_MIDI=m
 CONFIG_USB_STORAGE=m
 # CONFIG_USB_STORAGE_DEBUG is not set
 # CONFIG_USB_STORAGE_DATAFAB is not set
@@ -784,6 +786,7 @@
 CONFIG_USB_HID=y
 CONFIG_USB_HIDINPUT=y
 # CONFIG_USB_HIDDEV is not set
+CONFIG_USB_AIPTEK=m
 CONFIG_USB_WACOM=m
 
 #
@@ -836,6 +839,7 @@
 CONFIG_USB_SERIAL_IPAQ=m
 # CONFIG_USB_SERIAL_IR is not set
 CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
 CONFIG_USB_SERIAL_KEYSPAN_PDA=m
 CONFIG_USB_SERIAL_KEYSPAN=m
 # CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
@@ -858,6 +862,7 @@
 #
 CONFIG_USB_RIO500=m
 # CONFIG_USB_AUERSWALD is not set
+CONFIG_USB_TIGL=m
 # CONFIG_USB_BRLVGER is not set
 
 #
@@ -866,16 +871,20 @@
 CONFIG_BLUEZ=m
 CONFIG_BLUEZ_L2CAP=m
 CONFIG_BLUEZ_SCO=m
+CONFIG_BLUEZ_BNEP=m
+CONFIG_BNEP_MC_FILTER=y
+CONFIG_BNEP_PROTO_FILTER=y
 
 #
 # Bluetooth device drivers
 #
 CONFIG_BLUEZ_HCIUSB=m
-CONFIG_BLUEZ_USB_FW_LOAD=y
 CONFIG_BLUEZ_USB_ZERO_PACKET=y
 CONFIG_BLUEZ_HCIUART=m
 CONFIG_BLUEZ_HCIUART_H4=y
 # CONFIG_BLUEZ_HCIDTL1 is not set
+# CONFIG_BLUEZ_HCIBT3C is not set
+# CONFIG_BLUEZ_HCIBLUECARD is not set
 CONFIG_BLUEZ_HCIVHCI=m
 
 #
@@ -893,3 +902,9 @@
 # CONFIG_DEBUG_BUGVERBOSE is not set
 # CONFIG_DEBUG_DCFLUSH is not set
 # CONFIG_STACK_DEBUG is not set
+
+#
+# Library routines
+#
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff -urN linux-2.4.20-pre4/arch/sparc64/kernel/chmc.c linux-2.4.20-pre5/arch/sparc64/kernel/chmc.c
--- linux-2.4.20-pre4/arch/sparc64/kernel/chmc.c	Thu Apr 12 12:10:25 2001
+++ linux-2.4.20-pre5/arch/sparc64/kernel/chmc.c	Wed Aug 28 16:37:42 2002
@@ -420,7 +420,7 @@
 	int index;
 
 	/* This driver is only for cheetah platforms. */
-	if (tlb_type != cheetah)
+	if (tlb_type != cheetah && tlb_type != cheetah_plus)
 		return -ENODEV;
 
 	index = probe_for_string("memory-controller", 0);
diff -urN linux-2.4.20-pre4/arch/sparc64/kernel/cpu.c linux-2.4.20-pre5/arch/sparc64/kernel/cpu.c
--- linux-2.4.20-pre4/arch/sparc64/kernel/cpu.c	Sun Mar 25 18:14:21 2001
+++ linux-2.4.20-pre5/arch/sparc64/kernel/cpu.c	Wed Aug 28 16:37:42 2002
@@ -36,6 +36,7 @@
   { 0x17, 0x12, 0, "UltraSparc IIi integrated FPU"},
   { 0x17, 0x13, 0, "UltraSparc IIe integrated FPU"},
   { 0x3e, 0x14, 0, "UltraSparc III integrated FPU"},
+  { 0x3e, 0x15, 0, "UltraSparc III+ integrated FPU"},
 };
 
 #define NSPARCFPU  (sizeof(linux_sparc_fpu)/sizeof(struct cpu_fp_info))
@@ -47,6 +48,7 @@
   { 0x17, 0x12, "TI UltraSparc IIi"},
   { 0x17, 0x13, "TI UltraSparc IIe"},
   { 0x3e, 0x14, "TI UltraSparc III (Cheetah)"},
+  { 0x3e, 0x15, "TI UltraSparc III+ (Cheetah+)"},
 };
 
 #define NSPARCCHIPS  (sizeof(linux_sparc_chips)/sizeof(struct cpu_iu_info))
diff -urN linux-2.4.20-pre4/arch/sparc64/kernel/devices.c linux-2.4.20-pre5/arch/sparc64/kernel/devices.c
--- linux-2.4.20-pre4/arch/sparc64/kernel/devices.c	Tue Jun 12 11:08:46 2001
+++ linux-2.4.20-pre5/arch/sparc64/kernel/devices.c	Wed Aug 28 16:37:42 2002
@@ -57,7 +57,8 @@
 				if (tlb_type == spitfire) {
 					prom_getproperty(scan, "upa-portid",
 							 (char *) &thismid, sizeof(thismid));
-				} else if (tlb_type == cheetah) {
+				} else if (tlb_type == cheetah ||
+					   tlb_type == cheetah_plus) {
 					prom_getproperty(scan, "portid",
 							 (char *) &thismid, sizeof(thismid));
 				}
diff -urN linux-2.4.20-pre4/arch/sparc64/kernel/dtlb_base.S linux-2.4.20-pre5/arch/sparc64/kernel/dtlb_base.S
--- linux-2.4.20-pre4/arch/sparc64/kernel/dtlb_base.S	Wed Oct 17 14:16:39 2001
+++ linux-2.4.20-pre5/arch/sparc64/kernel/dtlb_base.S	Wed Aug 28 16:37:42 2002
@@ -70,7 +70,7 @@
 	CREATE_VPTE_OFFSET1(%g4, %g6)			! Create VPTE offset
 	be,pn		%xcc, 3f			! Yep, special processing
 	 CREATE_VPTE_OFFSET2(%g4, %g6)			! Create VPTE offset
-	cmp		%g5, 3				! Last trap level?
+	cmp		%g5, 4				! Last trap level?
 	be,pn		%xcc, longpath			! Yep, cannot risk VPTE miss
 	 nop						! delay slot
 
diff -urN linux-2.4.20-pre4/arch/sparc64/kernel/entry.S linux-2.4.20-pre5/arch/sparc64/kernel/entry.S
--- linux-2.4.20-pre4/arch/sparc64/kernel/entry.S	Fri Dec 21 09:41:53 2001
+++ linux-2.4.20-pre5/arch/sparc64/kernel/entry.S	Wed Aug 28 16:37:43 2002
@@ -774,7 +774,14 @@
 	membar		#Sync
 	sethi		%hi(109f), %g7
 	ba,pt		%xcc, etraptl1
-	 or		%g7, %lo(109f), %g7	! Merge in below
+109:	 or		%g7, %lo(109b), %g7
+	mov		%l4, %o1
+	mov		%l5, %o2
+	call		instruction_access_exception_tl1
+	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	ba,pt		%xcc, rtrap
+	 clr		%l6
+
 __do_instruction_access_exception:
 	rdpr		%pstate, %g4
 	wrpr		%g4, PSTATE_MG|PSTATE_AG, %pstate
@@ -1074,6 +1081,181 @@
 	jmpl		%g2 + %lo(cheetah_deferred_trap), %g0
 	 mov		1, %g1
 
+	/* Cheetah+ specific traps. These are for the new I/D cache parity
+	 * error traps.  The first argument to cheetah_plus_parity_handler
+	 * is encoded as follows:
+	 *
+	 * Bit0:	0=dcache,1=icache
+	 * Bit1:	0=recoverable,1=unrecoverable
+	 */
+	.globl		cheetah_plus_dcpe_trap_vector, cheetah_plus_dcpe_trap_vector_tl1
+cheetah_plus_dcpe_trap_vector:
+	membar		#Sync
+	sethi		%hi(do_cheetah_plus_data_parity), %g7
+	jmpl		%g7 + %lo(do_cheetah_plus_data_parity), %g0
+	 nop
+	nop
+	nop
+	nop
+	nop
+
+do_cheetah_plus_data_parity:
+	ba,pt		%xcc, etrap
+	 rd		%pc, %g7
+	mov		0x0, %o0
+	call		cheetah_plus_parity_error
+	 add		%sp, STACK_BIAS + REGWIN_SZ, %o1
+	ba,pt		%xcc, rtrap
+	 clr		%l6
+
+cheetah_plus_dcpe_trap_vector_tl1:
+	membar		#Sync
+	wrpr		PSTATE_IG | PSTATE_PEF | PSTATE_PRIV, %pstate
+	sethi		%hi(do_dcpe_tl1), %g3
+	jmpl		%g3 + %lo(do_dcpe_tl1), %g0
+	 nop
+	nop
+	nop
+	nop
+
+	.globl		cheetah_plus_icpe_trap_vector, cheetah_plus_icpe_trap_vector_tl1
+cheetah_plus_icpe_trap_vector:
+	membar		#Sync
+	sethi		%hi(do_cheetah_plus_insn_parity), %g7
+	jmpl		%g7 + %lo(do_cheetah_plus_insn_parity), %g0
+	 nop
+	nop
+	nop
+	nop
+	nop
+
+do_cheetah_plus_insn_parity:
+	ba,pt		%xcc, etrap
+	 rd		%pc, %g7
+	mov		0x1, %o0
+	call		cheetah_plus_parity_error
+	 add		%sp, STACK_BIAS + REGWIN_SZ, %o1
+	ba,pt		%xcc, rtrap
+	 clr		%l6
+
+cheetah_plus_icpe_trap_vector_tl1:
+	membar		#Sync
+	wrpr		PSTATE_IG | PSTATE_PEF | PSTATE_PRIV, %pstate
+	sethi		%hi(do_icpe_tl1), %g3
+	jmpl		%g3 + %lo(do_icpe_tl1), %g0
+	 nop
+	nop
+	nop
+	nop
+
+	/* If we take one of these traps when tl >= 1, then we
+	 * jump to interrupt globals.  If some trap level above us
+	 * was also using interrupt globals, we cannot recover.
+	 * We may use all interrupt global registers except %g6.
+	 */
+	.globl		do_dcpe_tl1, do_icpe_tl1
+do_dcpe_tl1:
+	rdpr		%tl, %g1		! Save original trap level
+	mov		1, %g2			! Setup TSTATE checking loop
+	sethi		%hi(TSTATE_IG), %g3	! TSTATE mask bit
+1:	wrpr		%g2, %tl		! Set trap level to check
+	rdpr		%tstate, %g4		! Read TSTATE for this level
+	andcc		%g4, %g3, %g0		! Interrupt globals in use?
+	bne,a,pn	%xcc, do_dcpe_tl1_fatal	! Yep, irrecoverable
+	 wrpr		%g1, %tl		! Restore original trap level
+	add		%g2, 1, %g2		! Next trap level
+	cmp		%g2, %g1		! Hit them all yet?
+	ble,pt		%icc, 1b		! Not yet
+	 nop
+	wrpr		%g1, %tl		! Restore original trap level
+do_dcpe_tl1_nonfatal:	/* Ok we may use interrupt globals safely. */
+	/* Reset D-cache parity */
+	sethi		%hi(1 << 16), %g1	! D-cache size
+	mov		(1 << 5), %g2		! D-cache line size
+	sub		%g1, %g2, %g1		! Move down 1 cacheline
+1:	srl		%g1, 14, %g3		! Compute UTAG
+	membar		#Sync
+	stxa		%g3, [%g1] ASI_DCACHE_UTAG
+	membar		#Sync
+	sub		%g2, 8, %g3		! 64-bit data word within line
+2:	membar		#Sync
+	stxa		%g0, [%g1 + %g3] ASI_DCACHE_DATA
+	membar		#Sync
+	subcc		%g3, 8, %g3		! Next 64-bit data word
+	bge,pt		%icc, 2b
+	 nop
+	subcc		%g1, %g2, %g1		! Next cacheline
+	bge,pt		%icc, 1b
+	 nop
+	ba,pt		%xcc, dcpe_icpe_tl1_common
+	 nop
+
+do_dcpe_tl1_fatal:
+	sethi		%hi(1f), %g7
+	ba,pt		%xcc, etraptl1
+1:	or		%g7, %lo(1b), %g7
+	mov		0x2, %o0
+	call		cheetah_plus_parity_error
+	 add		%sp, STACK_BIAS + REGWIN_SZ, %o1
+	ba,pt		%xcc, rtrap
+	 clr		%l6
+
+do_icpe_tl1:
+	rdpr		%tl, %g1		! Save original trap level
+	mov		1, %g2			! Setup TSTATE checking loop
+	sethi		%hi(TSTATE_IG), %g3	! TSTATE mask bit
+1:	wrpr		%g2, %tl		! Set trap level to check
+	rdpr		%tstate, %g4		! Read TSTATE for this level
+	andcc		%g4, %g3, %g0		! Interrupt globals in use?
+	bne,a,pn	%xcc, do_icpe_tl1_fatal	! Yep, irrecoverable
+	 wrpr		%g1, %tl		! Restore original trap level
+	add		%g2, 1, %g2		! Next trap level
+	cmp		%g2, %g1		! Hit them all yet?
+	ble,pt		%icc, 1b		! Not yet
+	 nop
+	wrpr		%g1, %tl		! Restore original trap level
+do_icpe_tl1_nonfatal:	/* Ok we may use interrupt globals safely. */
+	/* Flush I-cache */
+	sethi		%hi(1 << 15), %g1	! I-cache size
+	mov		(1 << 5), %g2		! I-cache line size
+	sub		%g1, %g2, %g1
+1:	or		%g1, (2 << 3), %g3
+	stxa		%g0, [%g3] ASI_IC_TAG
+	membar		#Sync
+	subcc		%g1, %g2, %g1
+	bge,pt		%icc, 1b
+	 nop
+	ba,pt		%xcc, dcpe_icpe_tl1_common
+	 nop
+
+do_icpe_tl1_fatal:
+	sethi		%hi(1f), %g7
+	ba,pt		%xcc, etraptl1
+1:	or		%g7, %lo(1b), %g7
+	mov		0x3, %o0
+	call		cheetah_plus_parity_error
+	 add		%sp, STACK_BIAS + REGWIN_SZ, %o1
+	ba,pt		%xcc, rtrap
+	 clr		%l6
+	
+dcpe_icpe_tl1_common:
+	/* Flush D-cache, re-enable D/I caches in DCU and finally
+	 * retry the trapping instruction.
+	 */
+	sethi		%hi(1 << 16), %g1	! D-cache size
+	mov		(1 << 5), %g2		! D-cache line size
+	sub		%g1, %g2, %g1
+1:	stxa		%g0, [%g1] ASI_DCACHE_TAG
+	membar		#Sync
+	subcc		%g1, %g2, %g1
+	bge,pt		%icc, 1b
+	 nop
+	ldxa		[%g0] ASI_DCU_CONTROL_REG, %g1
+	or		%g1, (DCU_DC | DCU_IC), %g1
+	stxa		%g1, [%g0] ASI_DCU_CONTROL_REG
+	membar		#Sync
+	retry
+
 	/* Cheetah FECC trap handling, we get here from tl{0,1}_fecc
 	 * in the trap table.  That code has done a memory barrier
 	 * and has disabled both the I-cache and D-cache in the DCU
@@ -1637,12 +1819,17 @@
 	or	%g2, %lo(xtime), %g2
 	or	%g1, %lo(timer_tick_compare), %g1
 1:	rdpr	%ver, %o2
-	sethi	%hi(0x003e0014), %o1
+	sethi	%hi(CHEETAH_ID), %o1
 	srlx	%o2, 32, %o2
-	or	%o1, %lo(0x003e0014), %o1
+	or	%o1, %lo(CHEETAH_ID), %o1
 	membar	#Sync
 	ldda	[%g2] ASI_NUCLEUS_QUAD_LDD, %o4
 	cmp	%o2, %o1
+	be,a,pn	%xcc, 3f
+	 rd	%asr24, %o1
+	sethi	%hi(CHEETAH_PLUS_ID), %o1
+	or	%o1, %lo(CHEETAH_PLUS_ID), %o1
+	cmp	%o2, %o1
 	bne,pt	%xcc, 2f
 	 nop
 	ba,pt	%xcc, 3f
diff -urN linux-2.4.20-pre4/arch/sparc64/kernel/etrap.S linux-2.4.20-pre5/arch/sparc64/kernel/etrap.S
--- linux-2.4.20-pre4/arch/sparc64/kernel/etrap.S	Thu Sep 20 14:11:57 2001
+++ linux-2.4.20-pre5/arch/sparc64/kernel/etrap.S	Wed Aug 28 16:37:43 2002
@@ -107,8 +107,56 @@
 		 stb	%g0, [%l4 + %l3]					! Store		Group
 		nop
 
-etraptl1:	rdpr	%tstate, %g1						! Single	Group+4bubbles
-		sub	%sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2		! IEU1
+etraptl1:	/* Save tstate/tpc/tnpc of TL 1-->4 and the tl register itself.
+		 * We place this right after pt_regs on the trap stack.  The layout
+		 * is:
+		 *	0x00	TL1's TSTATE
+		 *	0x08	TL1's TPC
+		 *	0x10	TL1's TNPC
+		 *	 ...
+		 *	0x58	TL4's TNPC
+		 *	0x60	TL
+		 */
+		sub	%sp, (24 * 8) + 8, %g2
+		rdpr	%tl, %g1
+
+		wrpr	%g0, 1, %tl
+		rdpr	%tstate, %g3
+		stx	%g3, [%g2 + STACK_BIAS + 0x00]
+		rdpr	%tpc, %g3
+		stx	%g3, [%g2 + STACK_BIAS + 0x08]
+		rdpr	%tnpc, %g3
+		stx	%g3, [%g2 + STACK_BIAS + 0x10]
+
+		wrpr	%g0, 2, %tl
+		rdpr	%tstate, %g3
+		stx	%g3, [%g2 + STACK_BIAS + 0x18]
+		rdpr	%tpc, %g3
+		stx	%g3, [%g2 + STACK_BIAS + 0x20]
+		rdpr	%tnpc, %g3
+		stx	%g3, [%g2 + STACK_BIAS + 0x28]
+
+		wrpr	%g0, 3, %tl
+		rdpr	%tstate, %g3
+		stx	%g3, [%g2 + STACK_BIAS + 0x30]
+		rdpr	%tpc, %g3
+		stx	%g3, [%g2 + STACK_BIAS + 0x38]
+		rdpr	%tnpc, %g3
+		stx	%g3, [%g2 + STACK_BIAS + 0x40]
+
+		wrpr	%g0, 4, %tl
+		rdpr	%tstate, %g3
+		stx	%g3, [%g2 + STACK_BIAS + 0x48]
+		rdpr	%tpc, %g3
+		stx	%g3, [%g2 + STACK_BIAS + 0x50]
+		rdpr	%tnpc, %g3
+		stx	%g3, [%g2 + STACK_BIAS + 0x58]
+
+		wrpr	%g1, %tl
+		stx	%g1, [%g2 + STACK_BIAS + 0x60]
+
+		rdpr	%tstate, %g1						! Single	Group+4bubbles
+		sub	%g2, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2		! IEU1
 		ba,pt	%xcc, 1b						! CTI		Group
 		 andcc	%g1, TSTATE_PRIV, %g0					! IEU0
 
diff -urN linux-2.4.20-pre4/arch/sparc64/kernel/head.S linux-2.4.20-pre5/arch/sparc64/kernel/head.S
--- linux-2.4.20-pre4/arch/sparc64/kernel/head.S	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/sparc64/kernel/head.S	Wed Aug 28 16:37:43 2002
@@ -79,24 +79,34 @@
 	 */
 sparc64_boot:
 	rdpr	%ver, %g1
-	sethi	%hi(0x003e0014), %g5
+	sethi	%hi(CHEETAH_ID), %g5
 	srlx	%g1, 32, %g1
-	or	%g5, %lo(0x003e0014), %g5
+	or	%g5, %lo(CHEETAH_ID), %g5
+	cmp	%g1, %g5
+	be,pn	%icc, cheetah_boot
+	 sethi	%hi(CHEETAH_PLUS_ID), %g5
+	or	%g5, %lo(CHEETAH_PLUS_ID), %g5
 	cmp	%g1, %g5
 	bne,pt	%icc, spitfire_boot
 	 nop
 
+cheetah_plus_boot:
+	/* Preserve OBP choosen DCU and DCR register settings.  */
+	ba,pt	%xcc, cheetah_generic_boot
+	 nop
+
 cheetah_boot:
 	mov	DCR_BPE | DCR_RPE | DCR_SI | DCR_IFPOE | DCR_MS, %g1
 	wr	%g1, %asr18
 
-	sethi	%uhi(DCU_ME | DCU_RE | /*DCU_PE |*/ DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5
-	or	%g5, %ulo(DCU_ME | DCU_RE | /*DCU_PE |*/ DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5
+	sethi	%uhi(DCU_ME|DCU_RE|DCU_HPE|DCU_SPE|DCU_SL|DCU_WE), %g5
+	or	%g5, %ulo(DCU_ME|DCU_RE|DCU_HPE|DCU_SPE|DCU_SL|DCU_WE), %g5
 	sllx	%g5, 32, %g5
 	or	%g5, DCU_DM | DCU_IM | DCU_DC | DCU_IC, %g5
 	stxa	%g5, [%g0] ASI_DCU_CONTROL_REG
 	membar	#Sync
 
+cheetah_generic_boot:
 	mov	TSB_EXTENSION_P, %g3
 	stxa	%g0, [%g3] ASI_DMMU
 	stxa	%g0, [%g3] ASI_IMMU
@@ -149,6 +159,7 @@
 	 add	%l0, (1 << 3), %l0
 
 cheetah_got_tlbentry:
+	ldxa	[%l0] ASI_ITLB_DATA_ACCESS, %g0
 	ldxa	[%l0] ASI_ITLB_DATA_ACCESS, %g1
 	membar	#Sync
 	and	%g1, %g3, %g1
@@ -200,6 +211,36 @@
 	blu,pt	%xcc, 1b
 	 add	%l0, (1 << 3), %l0
 
+	/* On Cheetah+, have to check second DTLB.  */
+	rdpr	%ver, %g1
+	srlx	%g1, 32, %g1
+	sethi	%hi(CHEETAH_PLUS_ID), %l0
+	or	%l0, %lo(CHEETAH_PLUS_ID), %l0
+	cmp	%g1, %l0
+	bne,pt	%icc, 9f
+	 nop
+
+	set	3 << 16, %l0
+1:	ldxa	[%l0] ASI_DTLB_TAG_READ, %g1
+	membar	#Sync
+	andn	%g1, %l2, %g1
+	cmp	%g1, %g3
+	blu,pn	%xcc, 2f
+	 cmp	%g1, %g7
+	bgeu,pn	%xcc, 2f
+	 nop
+	stxa	%g0, [%l7] ASI_DMMU
+	membar	#Sync
+	stxa	%g0, [%l0] ASI_DTLB_DATA_ACCESS
+	membar	#Sync
+	
+2:	and	%l0, (511 << 3), %g1
+	cmp	%g1, (511 << 3)
+	blu,pt	%xcc, 1b
+	 add	%l0, (1 << 3), %l0
+
+9:
+
 	/* Now lock the TTE we created into ITLB-0 and DTLB-0,
 	 * entry 15 (and maybe 14 too).
 	 */
@@ -432,20 +473,26 @@
 	membar	#Sync
 
 	rdpr	%ver, %g1
-	sethi	%hi(0x003e0014), %g5
+	sethi	%hi(CHEETAH_ID), %g5
 	srlx	%g1, 32, %g1
-	or	%g5, %lo(0x003e0014), %g5
+	or	%g5, %lo(CHEETAH_ID), %g5
+	cmp	%g1, %g5
+	be,pn	%icc, cheetah_tlb_fixup
+	 sethi	%hi(CHEETAH_PLUS_ID), %g5
+	or	%g5, %lo(CHEETAH_PLUS_ID), %g5
 	cmp	%g1, %g5
 	bne,pt	%icc, spitfire_tlb_fixup
 	 nop
 
 cheetah_tlb_fixup:
 	set	(0 << 16) | (15 << 3), %g7
+	ldxa	[%g7] ASI_ITLB_DATA_ACCESS, %g0
 	ldxa	[%g7] ASI_ITLB_DATA_ACCESS, %g1
 	andn	%g1, (_PAGE_G), %g1
 	stxa	%g1, [%g7] ASI_ITLB_DATA_ACCESS
 	membar	#Sync
 
+	ldxa	[%g7] ASI_DTLB_DATA_ACCESS, %g0
 	ldxa	[%g7] ASI_DTLB_DATA_ACCESS, %g1
 	andn	%g1, (_PAGE_G), %g1
 	stxa	%g1, [%g7] ASI_DTLB_DATA_ACCESS
@@ -455,9 +502,17 @@
 	flush	%g3
 	membar	#Sync
 
-	/* Set TLB type to cheetah. */
-	mov	1, %g2
-	sethi	%hi(tlb_type), %g5
+	sethi	%hi(CHEETAH_PLUS_ID), %g5
+	or	%g5, %lo(CHEETAH_PLUS_ID), %g5
+	rdpr	%ver, %g2
+	srlx	%g2, 32, %g2
+	cmp	%g2, %g5
+	bne,a,pt %icc, 1f
+	 mov	1, %g2		/* Set TLB type to cheetah. */
+
+	mov	2, %g2		/* Set TLB type to cheetah+. */
+
+1:	sethi	%hi(tlb_type), %g5
 	stw	%g2, [%g5 + %lo(tlb_type)]
 
 	/* Patch copy/page operations to cheetah optimized versions. */
@@ -465,6 +520,8 @@
 	 nop
 	call	cheetah_patch_pgcopyops
 	 nop
+	call	cheetah_patch_cachetlbops
+	 nop
 
 	ba,pt	%xcc, tlb_fixup_done
 	 nop
@@ -577,18 +634,23 @@
 	or	%g2, KERN_LOWBITS, %g2
 
 	rdpr		%ver, %g3
-	sethi		%hi(0x003e0014), %g7
+	sethi		%hi(CHEETAH_ID), %g7
 	srlx		%g3, 32, %g3
-	or		%g7, %lo(0x003e0014), %g7
+	or		%g7, %lo(CHEETAH_ID), %g7
+	cmp		%g3, %g7
+	be,pn		%icc, cheetah_vpte_base
+	sethi		%hi(CHEETAH_PLUS_ID), %g7
+	or		%g7, %lo(CHEETAH_PLUS_ID), %g7
 	cmp		%g3, %g7
-	bne,pt		%icc, 1f
+	bne,pt		%icc, spitfire_vpte_base
 	 nop
 
+cheetah_vpte_base:
 	sethi		%uhi(VPTE_BASE_CHEETAH), %g3
 	or		%g3, %ulo(VPTE_BASE_CHEETAH), %g3
 	ba,pt		%xcc, 2f
 	 sllx		%g3, 32, %g3
-1:
+spitfire_vpte_base:
 	sethi		%uhi(VPTE_BASE_SPITFIRE), %g3
 	or		%g3, %ulo(VPTE_BASE_SPITFIRE), %g3
 	sllx		%g3, 32, %g3
@@ -616,13 +678,18 @@
 
 not_starfire:
 	rdpr		%ver, %g1
-	sethi		%hi(0x003e0014), %g5
+	sethi		%hi(CHEETAH_ID), %g5
 	srlx		%g1, 32, %g1
-	or		%g7, %lo(0x003e0014), %g5
+	or		%g5, %lo(CHEETAH_ID), %g5
+	cmp		%g1, %g5
+	be,pn		%icc, is_cheetah
+	 sethi		%hi(CHEETAH_PLUS_ID), %g5
+	or		%g5, %lo(CHEETAH_PLUS_ID), %g5
 	cmp		%g1, %g5
 	bne,pt		%icc, not_cheetah
 	 nop
 
+is_cheetah:
 	ldxa		[%g0] ASI_SAFARI_CONFIG, %g1
 	srlx		%g1, 17, %g1
 	ba,pt		%xcc, set_worklist
@@ -646,14 +713,19 @@
 	wr	%g0, 0, %tick_cmpr
 
 	rdpr		%ver, %g1
-	sethi		%hi(0x003e0014), %g5
+	sethi		%hi(CHEETAH_ID), %g5
 	srlx		%g1, 32, %g1
-	or		%g7, %lo(0x003e0014), %g5
+	or		%g5, %lo(CHEETAH_ID), %g5
 	cmp		%g1, %g5
-	bne,pt		%icc, 1f
+	be,pn		%icc, 1f
+	 sethi		%hi(CHEETAH_PLUS_ID), %g5
+	or		%g5, %lo(CHEETAH_PLUS_ID), %g5
+	cmp		%g1, %g5
+	bne,pt		%icc, 2f
 	 nop
 
 	/* Disable STICK_INT interrupts. */
+1:
 	sethi		%hi(0x80000000), %g1
 	sllx		%g1, 32, %g1
 	wr		%g1, %asr25
@@ -661,7 +733,7 @@
 	/* Ok, we're done setting up all the state our trap mechanims needs,
 	 * now get back into normal globals and let the PROM know what is up.
 	 */
-1:
+2:
 	wrpr	%g0, %g0, %wstate
 	wrpr	%o1, PSTATE_IE, %pstate
 
diff -urN linux-2.4.20-pre4/arch/sparc64/kernel/irq.c linux-2.4.20-pre5/arch/sparc64/kernel/irq.c
--- linux-2.4.20-pre4/arch/sparc64/kernel/irq.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/sparc64/kernel/irq.c	Wed Aug 28 16:37:43 2002
@@ -147,7 +147,7 @@
 	if (imap == 0UL)
 		return;
 
-	if (tlb_type == cheetah) {
+	if (tlb_type == cheetah || tlb_type == cheetah_plus) {
 		/* We set it to our Safari AID. */
 		__asm__ __volatile__("ldxa [%%g0] %1, %0"
 				     : "=r" (tid)
@@ -1139,7 +1139,7 @@
 	unsigned long imap = bucket->imap;
 	unsigned int tid;
 
-	if (tlb_type == cheetah) {
+	if (tlb_type == cheetah || tlb_type == cheetah_plus) {
 		tid = __cpu_logical_map[goal_cpu] << 26;
 		tid &= IMAP_AID_SAFARI;
 	} else if (this_is_starfire == 0) {
diff -urN linux-2.4.20-pre4/arch/sparc64/kernel/pci.c linux-2.4.20-pre5/arch/sparc64/kernel/pci.c
--- linux-2.4.20-pre4/arch/sparc64/kernel/pci.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/sparc64/kernel/pci.c	Wed Aug 28 16:37:43 2002
@@ -315,7 +315,7 @@
 {
 }
 
-int pcibios_enable_device(struct pci_dev *pdev)
+int pcibios_enable_device(struct pci_dev *pdev, int mask)
 {
 	return 0;
 }
diff -urN linux-2.4.20-pre4/arch/sparc64/kernel/ptrace.c linux-2.4.20-pre5/arch/sparc64/kernel/ptrace.c
--- linux-2.4.20-pre4/arch/sparc64/kernel/ptrace.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/sparc64/kernel/ptrace.c	Wed Aug 28 16:37:43 2002
@@ -576,7 +576,7 @@
 	{
 		unsigned long va;
 
-		if (tlb_type == cheetah) {
+		if (tlb_type == cheetah || tlb_type == cheetah_plus) {
 			for (va = 0; va < (1 << 16); va += (1 << 5))
 				spitfire_put_dcache_tag(va, 0x0);
 			/* No need to mess with I-cache on Cheetah. */
diff -urN linux-2.4.20-pre4/arch/sparc64/kernel/setup.c linux-2.4.20-pre5/arch/sparc64/kernel/setup.c
--- linux-2.4.20-pre4/arch/sparc64/kernel/setup.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/sparc64/kernel/setup.c	Wed Aug 28 16:37:43 2002
@@ -182,7 +182,7 @@
 
 			if (tlb_type == spitfire)
 				tte = spitfire_get_dtlb_data(SPITFIRE_HIGHEST_LOCKED_TLBENT);
-			else if (tlb_type == cheetah)
+			else if (tlb_type == cheetah || tlb_type == cheetah_plus)
 				tte = cheetah_get_ldtlb_data(CHEETAH_HIGHEST_LOCKED_TLBENT);
 
 			res = PROM_TRUE;
@@ -497,7 +497,7 @@
 		extern unsigned int irqsz_patchme[1];
 		irqsz_patchme[0] |= ((i == SMP_CACHE_BYTES) ? SMP_CACHE_BYTES_SHIFT : \
 							SMP_CACHE_BYTES_SHIFT + 1);
-		flushi((long)&irqsz_patchme[1]);
+		flushi((long)&irqsz_patchme[0]);
 	} else {
 		prom_printf("Unexpected size of irq_stat[] elements\n");
 		prom_halt();
diff -urN linux-2.4.20-pre4/arch/sparc64/kernel/smp.c linux-2.4.20-pre5/arch/sparc64/kernel/smp.c
--- linux-2.4.20-pre4/arch/sparc64/kernel/smp.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/sparc64/kernel/smp.c	Wed Aug 28 16:37:43 2002
@@ -622,9 +622,9 @@
 extern unsigned long xcall_flush_tlb_page;
 extern unsigned long xcall_flush_tlb_mm;
 extern unsigned long xcall_flush_tlb_range;
-extern unsigned long xcall_flush_tlb_all;
-extern unsigned long xcall_tlbcachesync;
-extern unsigned long xcall_flush_cache_all;
+extern unsigned long xcall_flush_tlb_all_spitfire;
+extern unsigned long xcall_flush_tlb_all_cheetah;
+extern unsigned long xcall_flush_cache_all_spitfire;
 extern unsigned long xcall_report_regs;
 extern unsigned long xcall_receive_signal;
 extern unsigned long xcall_flush_dcache_page_cheetah;
@@ -744,13 +744,19 @@
 
 void smp_flush_cache_all(void)
 {
-	smp_cross_call(&xcall_flush_cache_all, 0, 0, 0);
-	__flush_cache_all();
+	/* Cheetah need do nothing. */
+	if (tlb_type == spitfire) {
+		smp_cross_call(&xcall_flush_cache_all_spitfire, 0, 0, 0);
+		__flush_cache_all();
+	}
 }
 
 void smp_flush_tlb_all(void)
 {
-	smp_cross_call(&xcall_flush_tlb_all, 0, 0, 0);
+	if (tlb_type == spitfire)
+		smp_cross_call(&xcall_flush_tlb_all_spitfire, 0, 0, 0);
+	else
+		smp_cross_call(&xcall_flush_tlb_all_cheetah, 0, 0, 0);
 	__flush_tlb_all();
 }
 
diff -urN linux-2.4.20-pre4/arch/sparc64/kernel/trampoline.S linux-2.4.20-pre5/arch/sparc64/kernel/trampoline.S
--- linux-2.4.20-pre4/arch/sparc64/kernel/trampoline.S	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/sparc64/kernel/trampoline.S	Wed Aug 28 16:37:43 2002
@@ -34,13 +34,22 @@
 	flushw
 
 	rdpr		%ver, %g1
-	sethi		%hi(0x003e0014), %g5
+	sethi		%hi(CHEETAH_ID), %g5
 	srlx		%g1, 32, %g1
-	or		%g5, %lo(0x003e0014), %g5
+	or		%g5, %lo(CHEETAH_ID), %g5
+	cmp		%g1, %g5
+	be,pn		%icc, cheetah_startup
+	 sethi		%hi(CHEETAH_PLUS_ID), %g5
+	or		%g5, %lo(CHEETAH_PLUS_ID), %g5
 	cmp		%g1, %g5
 	bne,pt		%icc, spitfire_startup
 	 nop
 
+cheetah_plus_startup:
+	/* Preserve OBP choosen DCU and DCR register settings.  */
+	ba,pt	%xcc, cheetah_generic_startup
+	 nop
+
 cheetah_startup:
 	mov		DCR_BPE | DCR_RPE | DCR_SI | DCR_IFPOE | DCR_MS, %g1
 	wr		%g1, %asr18
@@ -52,6 +61,7 @@
 	stxa		%g5, [%g0] ASI_DCU_CONTROL_REG
 	membar		#Sync
 
+cheetah_generic_startup:
 	mov	TSB_EXTENSION_P, %g3
 	stxa	%g0, [%g3] ASI_DMMU
 	stxa	%g0, [%g3] ASI_IMMU
@@ -118,9 +128,14 @@
 	stx		%g2, [%sp + 2047 + 128 + 0x30]
 
 	rdpr		%ver, %g1
-	sethi		%hi(0x003e0014), %g5
+	sethi		%hi(CHEETAH_ID), %g5
 	srlx		%g1, 32, %g1
-	or		%g5, %lo(0x003e0014), %g5
+	or		%g5, %lo(CHEETAH_ID), %g5
+	cmp		%g1, %g5
+	be,a,pn		%icc, 1f
+	 mov		15, %g2
+	sethi		%hi(CHEETAH_PLUS_ID), %g5
+	or		%g5, %lo(CHEETAH_PLUS_ID), %g5
 	cmp		%g1, %g5
 	bne,a,pt	%icc, 1f
 	 mov		63, %g2
@@ -153,9 +168,14 @@
 	stx		%g2, [%sp + 2047 + 128 + 0x30]
 
 	rdpr		%ver, %g1
-	sethi		%hi(0x003e0014), %g5
+	sethi		%hi(CHEETAH_ID), %g5
 	srlx		%g1, 32, %g1
-	or		%g5, %lo(0x003e0014), %g5
+	or		%g5, %lo(CHEETAH_ID), %g5
+	cmp		%g1, %g5
+	be,a,pn		%icc, 1f
+	 mov		15, %g2
+	sethi		%hi(CHEETAH_PLUS_ID), %g5
+	or		%g5, %lo(CHEETAH_PLUS_ID), %g5
 	cmp		%g1, %g5
 	bne,a,pt	%icc, 1f
 	 mov		63, %g2
@@ -228,13 +248,18 @@
 	or		%g2, KERN_LOWBITS, %g2
 
 	rdpr		%ver, %g3
-	sethi		%hi(0x003e0014), %g7
+	sethi		%hi(CHEETAH_ID), %g7
 	srlx		%g3, 32, %g3
-	or		%g7, %lo(0x003e0014), %g7
+	or		%g7, %lo(CHEETAH_ID), %g7
+	cmp		%g3, %g7
+	be,pn		%icc, 9f
+	 sethi		%hi(CHEETAH_PLUS_ID), %g7
+	or		%g7, %lo(CHEETAH_PLUS_ID), %g7
 	cmp		%g3, %g7
 	bne,pt		%icc, 1f
 	 nop
 
+9:
 	sethi		%uhi(VPTE_BASE_CHEETAH), %g3
 	or		%g3, %ulo(VPTE_BASE_CHEETAH), %g3
 	ba,pt		%xcc, 2f
diff -urN linux-2.4.20-pre4/arch/sparc64/kernel/traps.c linux-2.4.20-pre5/arch/sparc64/kernel/traps.c
--- linux-2.4.20-pre4/arch/sparc64/kernel/traps.c	Fri Dec 21 09:41:53 2001
+++ linux-2.4.20-pre5/arch/sparc64/kernel/traps.c	Wed Aug 28 16:37:44 2002
@@ -36,6 +36,33 @@
 #include <linux/kmod.h>
 #endif
 
+/* When an irrecoverable trap occurs at tl > 0, the trap entry
+ * code logs the trap state registers at every level in the trap
+ * stack.  It is found at (pt_regs + sizeof(pt_regs)) and the layout
+ * is as follows:
+ */
+struct tl1_traplog {
+	struct {
+		unsigned long tstate;
+		unsigned long tpc;
+		unsigned long tnpc;
+	} trapstack[4];
+	unsigned long tl;
+};
+
+static void dump_tl1_traplog(struct tl1_traplog *p)
+{
+	int i;
+
+	printk("TRAPLOG: Error at trap level 0x%lx, dumping track stack.\n",
+	       p->tl);
+	for (i = 0; i < 4; i++) {
+		printk("TRAPLOG: Trap level %d TSTATE[%016lx] TPC[%016lx] TNPC[%016lx]\n",
+		       i + 1,
+		       p->trapstack[i].tstate, p->trapstack[i].tpc, p->trapstack[i].tnpc);
+	}
+}
+
 void bad_trap (struct pt_regs *regs, long lvl)
 {
 	char buffer[32];
@@ -65,8 +92,10 @@
 
 void bad_trap_tl1 (struct pt_regs *regs, long lvl)
 {
-	char buffer[24];
+	char buffer[32];
 	
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
+
 	sprintf (buffer, "Bad trap %lx at tl>0", lvl);
 	die_if_kernel (buffer, regs);
 }
@@ -79,8 +108,8 @@
 }
 #endif
 
-void instruction_access_exception (struct pt_regs *regs,
-				   unsigned long sfsr, unsigned long sfar)
+void instruction_access_exception(struct pt_regs *regs,
+				  unsigned long sfsr, unsigned long sfar)
 {
 	siginfo_t info;
 
@@ -101,6 +130,13 @@
 	force_sig_info(SIGSEGV, &info, current);
 }
 
+void instruction_access_exception_tl1(struct pt_regs *regs,
+				      unsigned long sfsr, unsigned long sfar)
+{
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
+	instruction_access_exception(regs, sfsr, sfar);
+}
+
 void data_access_exception (struct pt_regs *regs,
 			    unsigned long sfsr, unsigned long sfar)
 {
@@ -166,7 +202,7 @@
 					    LSU_CONTROL_IM | LSU_CONTROL_DM),
 				     "i" (ASI_LSU_CONTROL)
 				     : "memory");
-	} else if (tlb_type == cheetah) {
+	} else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
 		/* Flush D-cache */
 		for (va = 0; va < (1 << 16); va += (1 << 5)) {
 			__asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
@@ -200,7 +236,7 @@
 		pci_poke_faulted = 1;
 
 		/* Why the fuck did they have to change this? */
-		if (tlb_type == cheetah)
+		if (tlb_type == cheetah || tlb_type == cheetah_plus)
 			regs->tpc += 4;
 
 		regs->tnpc = regs->tpc + 4;
@@ -389,10 +425,14 @@
 	return p;
 }
 
+extern unsigned int tl0_icpe[], tl1_icpe[];
+extern unsigned int tl0_dcpe[], tl1_dcpe[];
 extern unsigned int tl0_fecc[], tl1_fecc[];
 extern unsigned int tl0_cee[], tl1_cee[];
 extern unsigned int tl0_iae[], tl1_iae[];
 extern unsigned int tl0_dae[], tl1_dae[];
+extern unsigned int cheetah_plus_icpe_trap_vector[], cheetah_plus_icpe_trap_vector_tl1[];
+extern unsigned int cheetah_plus_dcpe_trap_vector[], cheetah_plus_dcpe_trap_vector_tl1[];
 extern unsigned int cheetah_fecc_trap_vector[], cheetah_fecc_trap_vector_tl1[];
 extern unsigned int cheetah_cee_trap_vector[], cheetah_cee_trap_vector_tl1[];
 extern unsigned int cheetah_deferred_trap_vector[], cheetah_deferred_trap_vector_tl1[];
@@ -494,6 +534,12 @@
 	memcpy(tl1_iae, cheetah_deferred_trap_vector_tl1, (8 * 4));
 	memcpy(tl0_dae, cheetah_deferred_trap_vector, (8 * 4));
 	memcpy(tl1_dae, cheetah_deferred_trap_vector_tl1, (8 * 4));
+	if (tlb_type == cheetah_plus) {
+		memcpy(tl0_dcpe, cheetah_plus_dcpe_trap_vector, (8 * 4));
+		memcpy(tl1_dcpe, cheetah_plus_dcpe_trap_vector_tl1, (8 * 4));
+		memcpy(tl0_icpe, cheetah_plus_icpe_trap_vector, (8 * 4));
+		memcpy(tl1_icpe, cheetah_plus_icpe_trap_vector_tl1, (8 * 4));
+	}
 	flushi(PAGE_OFFSET);
 }
 
@@ -532,9 +578,22 @@
  *
  * So we must only flush the I-cache when it is disabled.
  */
+static void __cheetah_flush_icache(void)
+{
+	unsigned long i;
+
+	/* Clear the valid bits in all the tags. */
+	for (i = 0; i < (1 << 15); i += (1 << 5)) {
+		__asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
+				     "membar #Sync"
+				     : /* no outputs */
+				     : "r" (i | (2 << 3)), "i" (ASI_IC_TAG));
+	}
+}
+
 static void cheetah_flush_icache(void)
 {
-	unsigned long dcu_save, i;
+	unsigned long dcu_save;
 
 	/* Save current DCU, disable I-cache. */
 	__asm__ __volatile__("ldxa [%%g0] %1, %0\n\t"
@@ -545,13 +604,7 @@
 			     : "i" (ASI_DCU_CONTROL_REG), "i" (DCU_IC)
 			     : "g1");
 
-	/* Clear the valid bits in all the tags. */
-	for (i = 0; i < (1 << 16); i += (1 << 5)) {
-		__asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
-				     "membar #Sync"
-				     : /* no outputs */
-				     : "r" (i | (2 << 3)), "i" (ASI_IC_TAG));
-	}
+	__cheetah_flush_icache();
 
 	/* Restore DCU register */
 	__asm__ __volatile__("stxa %0, [%%g0] %1\n\t"
@@ -572,6 +625,34 @@
 	}
 }
 
+/* In order to make the even parity correct we must do two things.
+ * First, we clear DC_data_parity and set DC_utag to an appropriate value.
+ * Next, we clear out all 32-bytes of data for that line.  Data of
+ * all-zero + tag parity value of zero == correct parity.
+ */
+static void cheetah_plus_zap_dcache_parity(void)
+{
+	unsigned long i;
+
+	for (i = 0; i < (1 << 16); i += (1 << 5)) {
+		unsigned long tag = (i >> 14);
+		unsigned long j;
+
+		__asm__ __volatile__("membar	#Sync\n\t"
+				     "stxa	%0, [%1] %2\n\t"
+				     "membar	#Sync"
+				     : /* no outputs */
+				     : "r" (tag), "r" (i),
+				       "i" (ASI_DCACHE_UTAG));
+		for (j = i; j < i + (1 << 5); j += (1 << 3))
+			__asm__ __volatile__("membar	#Sync\n\t"
+					     "stxa	%%g0, [%0] %1\n\t"
+					     "membar	#Sync"
+					     : /* no outputs */
+					     : "r" (j), "i" (ASI_DCACHE_DATA));
+	}
+}
+
 /* Conversion tables used to frob Cheetah AFSR syndrome values into
  * something palatable to the memory controller driver get_unumber
  * routine.
@@ -1294,6 +1375,46 @@
 		panic("Irrecoverable deferred error trap.\n");
 }
 
+/* Handle a D/I cache parity error trap.  TYPE is encoded as:
+ *
+ * Bit0:	0=dcache,1=icache
+ * Bit1:	0=recoverable,1=unrecoverable
+ *
+ * The hardware has disabled both the I-cache and D-cache in
+ * the %dcr register.  
+ */
+void cheetah_plus_parity_error(int type, struct pt_regs *regs)
+{
+	if (type & 0x1)
+		__cheetah_flush_icache();
+	else
+		cheetah_plus_zap_dcache_parity();
+	cheetah_flush_dcache();
+
+	/* Re-enable I-cache/D-cache */
+	__asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t"
+			     "or %%g1, %1, %%g1\n\t"
+			     "stxa %%g1, [%%g0] %0\n\t"
+			     "membar #Sync"
+			     : /* no outputs */
+			     : "i" (ASI_DCU_CONTROL_REG),
+			       "i" (DCU_DC | DCU_IC)
+			     : "g1");
+
+	if (type & 0x2) {
+		printk(KERN_EMERG "CPU[%d]: Cheetah+ %c-cache parity error at TPC[%016lx]\n",
+		       smp_processor_id(),
+		       (type & 0x1) ? 'I' : 'D',
+		       regs->tpc);
+		panic("Irrecoverable Cheetah+ parity error.");
+	}
+
+	printk(KERN_WARNING "CPU[%d]: Cheetah+ %c-cache parity error at TPC[%016lx]\n",
+	       smp_processor_id(),
+	       (type & 0x1) ? 'I' : 'D',
+	       regs->tpc);
+}
+
 void do_fpe_common(struct pt_regs *regs)
 {
 	if(regs->tstate & TSTATE_PRIV) {
@@ -1571,56 +1692,67 @@
 
 void do_cee_tl1(struct pt_regs *regs)
 {
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 	die_if_kernel("TL1: Cache Error Exception", regs);
 }
 
 void do_dae_tl1(struct pt_regs *regs)
 {
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 	die_if_kernel("TL1: Data Access Exception", regs);
 }
 
 void do_iae_tl1(struct pt_regs *regs)
 {
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 	die_if_kernel("TL1: Instruction Access Exception", regs);
 }
 
 void do_div0_tl1(struct pt_regs *regs)
 {
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 	die_if_kernel("TL1: DIV0 Exception", regs);
 }
 
 void do_fpdis_tl1(struct pt_regs *regs)
 {
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 	die_if_kernel("TL1: FPU Disabled", regs);
 }
 
 void do_fpieee_tl1(struct pt_regs *regs)
 {
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 	die_if_kernel("TL1: FPU IEEE Exception", regs);
 }
 
 void do_fpother_tl1(struct pt_regs *regs)
 {
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 	die_if_kernel("TL1: FPU Other Exception", regs);
 }
 
 void do_ill_tl1(struct pt_regs *regs)
 {
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 	die_if_kernel("TL1: Illegal Instruction Exception", regs);
 }
 
 void do_irq_tl1(struct pt_regs *regs)
 {
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 	die_if_kernel("TL1: IRQ Exception", regs);
 }
 
 void do_lddfmna_tl1(struct pt_regs *regs)
 {
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 	die_if_kernel("TL1: LDDF Exception", regs);
 }
 
 void do_stdfmna_tl1(struct pt_regs *regs)
 {
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 	die_if_kernel("TL1: STDF Exception", regs);
 }
 
@@ -1631,6 +1763,7 @@
 
 void do_paw_tl1(struct pt_regs *regs)
 {
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 	die_if_kernel("TL1: Phys Watchpoint Exception", regs);
 }
 
@@ -1641,11 +1774,13 @@
 
 void do_vaw_tl1(struct pt_regs *regs)
 {
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 	die_if_kernel("TL1: Virt Watchpoint Exception", regs);
 }
 
 void do_tof_tl1(struct pt_regs *regs)
 {
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 	die_if_kernel("TL1: Tag Overflow Exception", regs);
 }
 
diff -urN linux-2.4.20-pre4/arch/sparc64/kernel/ttable.S linux-2.4.20-pre5/arch/sparc64/kernel/ttable.S
--- linux-2.4.20-pre4/arch/sparc64/kernel/ttable.S	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/sparc64/kernel/ttable.S	Wed Aug 28 16:37:44 2002
@@ -7,6 +7,8 @@
 #include <linux/config.h>
 
 	.globl	sparc64_ttable_tl0, sparc64_ttable_tl1
+	.globl	tl0_icpe, tl1_icpe
+	.globl	tl0_dcpe, tl1_dcpe
 	.globl	tl0_fecc, tl1_fecc
 	.globl	tl0_cee, tl1_cee
 	.globl	tl0_iae, tl1_iae
@@ -79,7 +81,9 @@
 tl0_daprot:
 #include	"dtlb_prot.S"
 tl0_fecc:	BTRAP(0x70)	/* Fast-ECC on Cheetah */
-tl0_resv071:	BTRAP(0x71) BTRAP(0x72) BTRAP(0x73) BTRAP(0x74) BTRAP(0x75)
+tl0_dcpe:	BTRAP(0x71)	/* D-cache Parity Error on Cheetah+ */
+tl0_icpe:	BTRAP(0x72)	/* I-cache Parity Error on Cheetah+ */
+tl0_resv073:	BTRAP(0x73) BTRAP(0x74) BTRAP(0x75)
 tl0_resv076:	BTRAP(0x76) BTRAP(0x77) BTRAP(0x78) BTRAP(0x79) BTRAP(0x7a) BTRAP(0x7b)
 tl0_resv07c:	BTRAP(0x7c) BTRAP(0x7d) BTRAP(0x7e) BTRAP(0x7f)
 tl0_s0n:	SPILL_0_NORMAL
@@ -235,8 +239,10 @@
 #include	"dtlb_backend.S"
 tl1_daprot:
 #include	"dtlb_prot.S"
-tl1_fecc:	BTRAP(0x70)	/* Fast-ECC on Cheetah */
-tl1_resc071:	BTRAPTL1(0x71) BTRAPTL1(0x72) BTRAPTL1(0x73)
+tl1_fecc:	BTRAPTL1(0x70)	/* Fast-ECC on Cheetah */
+tl1_dcpe:	BTRAPTL1(0x71)	/* D-cache Parity Error on Cheetah+ */
+tl1_icpe:	BTRAPTL1(0x72)	/* I-cache Parity Error on Cheetah+ */
+tl1_resv073:	BTRAPTL1(0x73)
 tl1_resv074:	BTRAPTL1(0x74) BTRAPTL1(0x75) BTRAPTL1(0x76) BTRAPTL1(0x77)
 tl1_resv078:	BTRAPTL1(0x78) BTRAPTL1(0x79) BTRAPTL1(0x7a) BTRAPTL1(0x7b)
 tl1_resv07c:	BTRAPTL1(0x7c) BTRAPTL1(0x7d) BTRAPTL1(0x7e) BTRAPTL1(0x7f)
diff -urN linux-2.4.20-pre4/arch/sparc64/lib/blockops.S linux-2.4.20-pre5/arch/sparc64/lib/blockops.S
--- linux-2.4.20-pre4/arch/sparc64/lib/blockops.S	Fri Dec 21 09:41:53 2001
+++ linux-2.4.20-pre5/arch/sparc64/lib/blockops.S	Wed Aug 28 16:37:44 2002
@@ -64,14 +64,14 @@
 	ldub		[%g6 + AOFF_task_thread + AOFF_thread_use_blkcommit], %g3
 
 	/* Spitfire Errata #32 workaround */
-	mov		0x8, %o4
+	mov		PRIMARY_CONTEXT, %o4
 	stxa		%g0, [%o4] ASI_DMMU
 	membar		#Sync
 
 	ldxa		[%o3] ASI_DTLB_TAG_READ, %o4
 
 	/* Spitfire Errata #32 workaround */
-	mov		0x8, %o5
+	mov		PRIMARY_CONTEXT, %o5
 	stxa		%g0, [%o5] ASI_DMMU
 	membar		#Sync
 
@@ -83,14 +83,14 @@
 	add		%o3, (TLBTEMP_ENTSZ), %o3
 
 	/* Spitfire Errata #32 workaround */
-	mov		0x8, %g5
+	mov		PRIMARY_CONTEXT, %g5
 	stxa		%g0, [%g5] ASI_DMMU
 	membar		#Sync
 
 	ldxa		[%o3] ASI_DTLB_TAG_READ, %g5
 
 	/* Spitfire Errata #32 workaround */
-	mov		0x8, %g7
+	mov		PRIMARY_CONTEXT, %g7
 	stxa		%g0, [%g7] ASI_DMMU
 	membar		#Sync
 
@@ -107,7 +107,9 @@
 	rdpr		%ver, %g3
 	sllx		%g3, 16, %g3
 	srlx		%g3, 32 + 16, %g3
-	cmp		%g3, 0x14
+	cmp		%g3, 0x14			! CHEETAH_ID
+	be,pn		%icc, cheetah_copy_user_page
+	 cmp		%g3, 0x15			! CHEETAH_PLUS_ID
 	bne,pt		%icc, spitfire_copy_user_page
 	 nop
 
@@ -353,14 +355,14 @@
 	wrpr		%g3, PSTATE_IE, %pstate
 
 	/* Spitfire Errata #32 workaround */
-	mov		0x8, %g5
+	mov		PRIMARY_CONTEXT, %g5
 	stxa		%g0, [%g5] ASI_DMMU
 	membar		#Sync
 
 	ldxa		[%o3] ASI_DTLB_TAG_READ, %g5
 
 	/* Spitfire Errata #32 workaround */
-	mov		0x8, %g7
+	mov		PRIMARY_CONTEXT, %g7
 	stxa		%g0, [%g7] ASI_DMMU
 	membar		#Sync
 
@@ -405,7 +407,8 @@
 	retl
 	 nop
 
-1:	stxa		%g5, [%o2] ASI_DMMU
+1:
+	stxa		%g5, [%o2] ASI_DMMU
 	stxa		%g7, [%o3] ASI_DTLB_DATA_ACCESS
 	membar		#Sync
 	jmpl		%o7 + 0x8, %g0
diff -urN linux-2.4.20-pre4/arch/sparc64/mm/init.c linux-2.4.20-pre5/arch/sparc64/mm/init.c
--- linux-2.4.20-pre4/arch/sparc64/mm/init.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/sparc64/mm/init.c	Wed Aug 28 16:37:44 2002
@@ -258,6 +258,8 @@
 {
 	if (tlb_type == cheetah)
 		seq_printf(m, "MMU Type\t: Cheetah\n");
+	else if (tlb_type == cheetah_plus)
+		seq_printf(m, "MMU Type\t: Cheetah+\n");
 	else if (tlb_type == spitfire)
 		seq_printf(m, "MMU Type\t: Spitfire\n");
 	else
@@ -427,6 +429,7 @@
 		break;
 
 	case cheetah:
+	case cheetah_plus:
 		phys_page = cheetah_get_litlb_data(sparc64_highest_locked_tlbent());
 		break;
 	};
@@ -452,7 +455,7 @@
 			"i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS),
 			"i" (ASI_IMMU), "i" (ASI_ITLB_DATA_ACCESS)
 			: "memory");
-	} else if (tlb_type == cheetah) {
+	} else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
 		/* Lock this into i/d tlb-0 entry 11 */
 		__asm__ __volatile__(
 			"stxa	%%g0, [%2] %3\n\t"
@@ -597,9 +600,9 @@
 				spitfire_put_dtlb_data(i, 0x0UL);
 			}
 		}
-	} else if (tlb_type == cheetah) {
+	} else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
 		for (i = 0; i < 512; i++) {
-			unsigned long tag = cheetah_get_dtlb_tag(i);
+			unsigned long tag = cheetah_get_dtlb_tag(i, 2);
 
 			if ((tag & ~PAGE_MASK) == 0 &&
 			    (tag & PAGE_MASK) >= prom_reserved_base) {
@@ -607,7 +610,21 @@
 						     "membar #Sync"
 						     : /* no outputs */
 						     : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
-				cheetah_put_dtlb_data(i, 0x0UL);
+				cheetah_put_dtlb_data(i, 0x0UL, 2);
+			}
+
+			if (tlb_type != cheetah_plus)
+				continue;
+
+			tag = cheetah_get_dtlb_tag(i, 3);
+
+			if ((tag & ~PAGE_MASK) == 0 &&
+			    (tag & PAGE_MASK) >= prom_reserved_base) {
+				__asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
+						     "membar #Sync"
+						     : /* no outputs */
+						     : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
+				cheetah_put_dtlb_data(i, 0x0UL, 3);
 			}
 		}
 	} else {
@@ -656,7 +673,7 @@
 				if (tlb_type == spitfire)
 					spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent,
 							       prom_dtlb[i].tlb_data);
-				else if (tlb_type == cheetah)
+				else if (tlb_type == cheetah || tlb_type == cheetah_plus)
 					cheetah_put_ldtlb_data(prom_dtlb[i].tlb_ent,
 							       prom_dtlb[i].tlb_data);
 			}
@@ -669,7 +686,7 @@
 				if (tlb_type == spitfire)
 					spitfire_put_itlb_data(prom_itlb[i].tlb_ent,
 							       prom_itlb[i].tlb_data);
-				else if (tlb_type == cheetah)
+				else if (tlb_type == cheetah || tlb_type == cheetah_plus)
 					cheetah_put_litlb_data(prom_itlb[i].tlb_ent,
 							       prom_itlb[i].tlb_data);
 			}
@@ -804,7 +821,7 @@
 					break;
 			}
 		}
-	} else if (tlb_type == cheetah) {
+	} else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
 		int high = CHEETAH_HIGHEST_LOCKED_TLBENT - bigkernel;
 
 		for (i = 0; i < high; i++) {
@@ -876,7 +893,7 @@
 			if (tlb_type == spitfire)
 				spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent,
 						       prom_dtlb[i].tlb_data);
-			else if (tlb_type == cheetah)
+			else if (tlb_type == cheetah || tlb_type == cheetah_plus)
 				cheetah_put_ldtlb_data(prom_dtlb[i].tlb_ent,
 						      prom_dtlb[i].tlb_data);
 		}
@@ -977,7 +994,7 @@
 				spitfire_put_itlb_data(i, 0x0UL);
 			}
 		}
-	} else if (tlb_type == cheetah) {
+	} else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
 		cheetah_flush_dtlb_all();
 		cheetah_flush_itlb_all();
 	}
@@ -1110,7 +1127,7 @@
 				slot+2,
 				spitfire_get_itlb_tag(slot+2), spitfire_get_itlb_data(slot+2));
 		}
-	} else if (tlb_type == cheetah) {
+	} else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
 		printk ("Contents of itlb0:\n");
 		for (slot = 0; slot < 16; slot+=2) {
 			printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n",
@@ -1148,7 +1165,7 @@
 				slot+2,
 				spitfire_get_dtlb_tag(slot+2), spitfire_get_dtlb_data(slot+2));
 		}
-	} else if (tlb_type == cheetah) {
+	} else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
 		printk ("Contents of dtlb0:\n");
 		for (slot = 0; slot < 16; slot+=2) {
 			printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n",
@@ -1161,9 +1178,19 @@
 		for (slot = 0; slot < 512; slot+=2) {
 			printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n",
 				slot,
-				cheetah_get_dtlb_tag(slot), cheetah_get_dtlb_data(slot),
+				cheetah_get_dtlb_tag(slot, 2), cheetah_get_dtlb_data(slot, 2),
 				slot+1,
-				cheetah_get_dtlb_tag(slot+1), cheetah_get_dtlb_data(slot+1));
+				cheetah_get_dtlb_tag(slot+1, 2), cheetah_get_dtlb_data(slot+1, 2));
+		}
+		if (tlb_type == cheetah_plus) {
+			printk ("Contents of dtlb3:\n");
+			for (slot = 0; slot < 512; slot+=2) {
+				printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n",
+					slot,
+					cheetah_get_dtlb_tag(slot, 3), cheetah_get_dtlb_data(slot, 3),
+					slot+1,
+					cheetah_get_dtlb_tag(slot+1, 3), cheetah_get_dtlb_data(slot+1, 3));
+			}
 		}
 	}
 }
@@ -1341,7 +1368,7 @@
 			  "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), "r" (60 << 3)
 			: "memory");
 		}
-	} else if (tlb_type == cheetah) {
+	} else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
 		__asm__ __volatile__(
 	"	stxa	%1, [%0] %3\n"
 	"	stxa	%2, [%5] %4\n"
@@ -1646,7 +1673,7 @@
 	       initpages << (PAGE_SHIFT-10), 
 	       PAGE_OFFSET, (last_valid_pfn << PAGE_SHIFT));
 
-	if (tlb_type == cheetah)
+	if (tlb_type == cheetah || tlb_type == cheetah_plus)
 		cheetah_ecache_flush_init();
 }
 
diff -urN linux-2.4.20-pre4/arch/sparc64/mm/ultra.S linux-2.4.20-pre5/arch/sparc64/mm/ultra.S
--- linux-2.4.20-pre4/arch/sparc64/mm/ultra.S	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/arch/sparc64/mm/ultra.S	Wed Aug 28 16:37:44 2002
@@ -13,21 +13,12 @@
 #include <asm/pil.h>
 #include <asm/head.h>
 
-	/* Basically, all this madness has to do with the
-	 * fact that Cheetah does not support IMMU flushes
-	 * out of the secondary context.  Someone needs to
-	 * throw a south lake birthday party for the folks
+	/* Basically, most of the Spitfire vs. Cheetah madness
+	 * has to do with the fact that Cheetah does not support
+	 * IMMU flushes out of the secondary context.  Someone needs
+	 * to throw a south lake birthday party for the folks
 	 * in Microelectronics who refused to fix this shit.
 	 */
-#define BRANCH_IF_CHEETAH(tmp1, tmp2, label)		\
-	rdpr	%ver, %tmp1;				\
-	sethi	%hi(0x003e0014), %tmp2;			\
-	srlx	%tmp1, 32, %tmp1;			\
-	or	%tmp2, %lo(0x003e0014), %tmp2;		\
-	cmp	%tmp1, %tmp2;				\
-	be,pn	%icc, label;				\
-	 nop;						\
-	nop;
 
 	/* This file is meant to be read efficiently by the CPU, not humans.
 	 * Staraj sie tego nikomu nie pierdolnac...
@@ -36,9 +27,7 @@
 	.align		32
 	.globl		__flush_tlb_page, __flush_tlb_mm, __flush_tlb_range
 __flush_tlb_page: /* %o0=(ctx & TAG_CONTEXT_BITS), %o1=page&PAGE_MASK, %o2=SECONDARY_CONTEXT */
-/*IC1*/	BRANCH_IF_CHEETAH(g2, g3, __cheetah_flush_tlb_page)
-__spitfire_flush_tlb_page:
-/*IC2*/	ldxa		[%o2] ASI_DMMU, %g2
+	ldxa		[%o2] ASI_DMMU, %g2
 	cmp		%g2, %o0
 	bne,pn		%icc, __spitfire_flush_tlb_page_slow
 	 or		%o1, 0x10, %g3
@@ -46,27 +35,17 @@
 	stxa		%g0, [%g3] ASI_IMMU_DEMAP
 	retl
 	 flush		%g6
-__cheetah_flush_tlb_page:
-/*IC3*/	rdpr		%pstate, %g5
-	andn		%g5, PSTATE_IE, %g2
-	wrpr		%g2, 0x0, %pstate
-	wrpr		%g0, 1, %tl
-	mov		PRIMARY_CONTEXT, %o2
-	ldxa		[%o2] ASI_DMMU, %g2
-	stxa		%o0, [%o2] ASI_DMMU
-	stxa		%g0, [%o1] ASI_DMMU_DEMAP
-/*IC4*/	stxa		%g0, [%o1] ASI_IMMU_DEMAP
-	stxa		%g2, [%o2] ASI_DMMU
-	flush		%g6
-	wrpr		%g0, 0, %tl
-	retl
-	 wrpr		%g5, 0x0, %pstate
 	nop
 	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+
 __flush_tlb_mm: /* %o0=(ctx & TAG_CONTEXT_BITS), %o1=SECONDARY_CONTEXT */
-/*IC5*/	BRANCH_IF_CHEETAH(g2, g3, __cheetah_flush_tlb_mm)
-__spitfire_flush_tlb_mm:
-/*IC6*/	ldxa		[%o1] ASI_DMMU, %g2
+	ldxa		[%o1] ASI_DMMU, %g2
 	cmp		%g2, %o0
 	bne,pn		%icc, __spitfire_flush_tlb_mm_slow
 	 mov		0x50, %g3
@@ -74,30 +53,20 @@
 	stxa		%g0, [%g3] ASI_IMMU_DEMAP
 	retl
 	 flush		%g6
-__cheetah_flush_tlb_mm:
-/*IC7*/	rdpr		%pstate, %g5
-	andn		%g5, PSTATE_IE, %g2
-	wrpr		%g2, 0x0, %pstate
-	wrpr		%g0, 1, %tl
-	mov		PRIMARY_CONTEXT, %o2
-	mov		0x40, %g3
-	ldxa		[%o2] ASI_DMMU, %g2
-	stxa		%o0, [%o2] ASI_DMMU
-/*IC8*/	stxa		%g0, [%g3] ASI_DMMU_DEMAP
-	stxa		%g0, [%g3] ASI_IMMU_DEMAP
-	stxa		%g2, [%o2] ASI_DMMU
-	flush		%g6
-	wrpr		%g0, 0, %tl
-	retl
-	 wrpr		%g5, 0x0, %pstate
 	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+
 __flush_tlb_range: /* %o0=(ctx&TAG_CONTEXT_BITS), %o1=start&PAGE_MASK, %o2=SECONDARY_CONTEXT,
 		    * %o3=end&PAGE_MASK, %o4=PAGE_SIZE, %o5=(end - start)
 		    */
-/*IC9*/	BRANCH_IF_CHEETAH(g2, g3, __cheetah_flush_tlb_range)
-__spitfire_flush_tlb_range:
 #define TLB_MAGIC	207 /* Students, do you know how I calculated this?  -DaveM */
-/*IC10*/cmp		%o5, %o4
+	cmp		%o5, %o4
 	bleu,pt		%xcc, __flush_tlb_page
 	 srlx		%o5, PAGE_SHIFT, %g5
 	cmp		%g5, TLB_MAGIC
@@ -106,7 +75,7 @@
 	ldxa		[%o2] ASI_DMMU, %g2
 	cmp		%g2, %o0
 __spitfire_flush_tlb_range_page_by_page:
-/*IC11*/bne,pn		%icc, __spitfire_flush_tlb_range_pbp_slow
+	bne,pn		%icc, __spitfire_flush_tlb_range_pbp_slow
 	 sub		%o5, %o4, %o5
 1:	stxa		%g0, [%g5 + %o5] ASI_DMMU_DEMAP
 	stxa		%g0, [%g5 + %o5] ASI_IMMU_DEMAP
@@ -115,10 +84,9 @@
 	retl
 	 flush		%g6
 __spitfire_flush_tlb_range_constant_time: /* %o0=ctx, %o1=start, %o3=end */
-/*IC12*/rdpr		%pstate, %g1
+	rdpr		%pstate, %g1
 	wrpr		%g1, PSTATE_IE, %pstate
 	mov		TLB_TAG_ACCESS, %g3
-	/* XXX Spitfire dependency... */
 	mov		((SPITFIRE_HIGHEST_LOCKED_TLBENT-1) << 3), %g2
 
 	/* Spitfire Errata #32 workaround. */
@@ -130,7 +98,7 @@
 	and		%o4, TAG_CONTEXT_BITS, %o5
 	cmp		%o5, %o0
 	bne,pt		%icc, 2f
-/*IC13*/ andn		%o4, TAG_CONTEXT_BITS, %o4
+	 andn		%o4, TAG_CONTEXT_BITS, %o4
 	cmp		%o4, %o1
 	blu,pt		%xcc, 2f
 	 cmp		%o4, %o3
@@ -138,7 +106,7 @@
 2:	 ldxa		[%g2] ASI_DTLB_TAG_READ, %o4
 	and		%o4, TAG_CONTEXT_BITS, %o5
 	cmp		%o5, %o0
-/*IC14*/andn		%o4, TAG_CONTEXT_BITS, %o4
+	andn		%o4, TAG_CONTEXT_BITS, %o4
 	bne,pt		%icc, 3f
 	 cmp		%o4, %o1
 	blu,pt		%xcc, 3f
@@ -146,7 +114,7 @@
 	blu,pn		%xcc, 5f
 	 nop
 3:	brnz,pt		%g2, 1b
-/*IC15*/ sub		%g2, (1 << 3), %g2
+	 sub		%g2, (1 << 3), %g2
 	retl
 	 wrpr		%g1, 0x0, %pstate
 4:	stxa		%g0, [%g3] ASI_IMMU
@@ -162,7 +130,7 @@
 	 nop
 
 5:	stxa		%g0, [%g3] ASI_DMMU
-/*IC16*/stxa		%g0, [%g2] ASI_DTLB_DATA_ACCESS
+	stxa		%g0, [%g2] ASI_DTLB_DATA_ACCESS
 	flush		%g6
 
 	/* Spitfire Errata #32 workaround. */
@@ -173,33 +141,6 @@
 	ba,pt		%xcc, 3b
 	 nop
 
-	.align		32
-__cheetah_flush_tlb_range:
-	cmp		%o5, %o4
-	bleu,pt		%xcc, __cheetah_flush_tlb_page
-	 nop
-/*IC17*/rdpr		%pstate, %g5
-	andn		%g5, PSTATE_IE, %g2
-	wrpr		%g2, 0x0, %pstate
-	wrpr		%g0, 1, %tl
-	mov		PRIMARY_CONTEXT, %o2
-	sub		%o5, %o4, %o5
-	ldxa		[%o2] ASI_DMMU, %g2
-	stxa		%o0, [%o2] ASI_DMMU
-
-/*IC18*/
-1:	stxa		%g0, [%o1 + %o5] ASI_DMMU_DEMAP
-	stxa		%g0, [%o1 + %o5] ASI_IMMU_DEMAP
-	membar		#Sync
-	brnz,pt		%o5, 1b
-	 sub		%o5, %o4, %o5
-
-	stxa		%g2, [%o2] ASI_DMMU
-	flush		%g6
-	wrpr		%g0, 0, %tl
-	retl
-/*IC19*/ wrpr		%g5, 0x0, %pstate
-
 __spitfire_flush_tlb_mm_slow:
 	rdpr		%pstate, %g1
 	wrpr		%g1, PSTATE_IE, %pstate
@@ -208,7 +149,7 @@
 	stxa		%g0, [%g3] ASI_IMMU_DEMAP
 	flush		%g6
 	stxa		%g2, [%o1] ASI_DMMU
-/*IC18*/flush		%g6
+	flush		%g6
 	retl
 	 wrpr		%g1, 0, %pstate
 
@@ -218,7 +159,7 @@
 	stxa		%o0, [%o2] ASI_DMMU
 	stxa		%g0, [%g3] ASI_DMMU_DEMAP
 	stxa		%g0, [%g3] ASI_IMMU_DEMAP
-/*IC20*/flush		%g6
+	flush		%g6
 	stxa		%g2, [%o2] ASI_DMMU
 	flush		%g6
 	retl
@@ -228,7 +169,7 @@
 	rdpr		%pstate, %g1
 	wrpr		%g1, PSTATE_IE, %pstate
 	stxa		%o0, [%o2] ASI_DMMU
-/*IC21*/
+
 2:	stxa		%g0, [%g5 + %o5] ASI_DMMU_DEMAP
 	stxa		%g0, [%g5 + %o5] ASI_IMMU_DEMAP
 	brnz,pt		%o5, 2b
@@ -237,7 +178,7 @@
 	stxa		%g2, [%o2] ASI_DMMU
 	flush		%g6
 	retl
-/*IC22*/ wrpr		%g1, 0x0, %pstate
+	 wrpr		%g1, 0x0, %pstate
 
 /*
  * The following code flushes one page_size worth.
@@ -301,30 +242,6 @@
 	flush		%g6
 	ba,a,pt		%xcc, 3b
 
-	.align		64
-	.globl		__flush_dcache_page
-__flush_dcache_page:	/* %o0=kaddr, %o1=flush_icache */
-	sub		%o0, %g4, %o0
-	
-	rdpr		%ver, %g1
-	sethi		%hi(0x003e0014), %g2
-	srlx		%g1, 32, %g1
-	or		%g2, %lo(0x003e0014), %g2
-	cmp		%g1, %g2
-	bne,pt		%icc, flush_dcpage_spitfire
-	 nop
-
-flush_dcpage_cheetah:
-	sethi		%hi(PAGE_SIZE), %o4
-1:	subcc		%o4, (1 << 5), %o4
-	stxa		%g0, [%o0 + %o4] ASI_DCACHE_INVALIDATE
-	bne,pt		%icc, 1b
-	 nop
-	membar		#Sync
-	/* I-cache flush never needed on Cheetah, see callers. */
-	retl
-	 nop
-
 #if (PAGE_SHIFT == 13)
 #define DTAG_MASK 0x3
 #elif (PAGE_SHIFT == 16)
@@ -335,7 +252,10 @@
 #define DTAG_MASK 0x3ff
 #endif
 
-flush_dcpage_spitfire:
+	.align		64
+	.globl		__flush_dcache_page
+__flush_dcache_page:	/* %o0=kaddr, %o1=flush_icache */
+	sub		%o0, %g4, %o0
 	clr		%o4
 	srlx		%o0, 11, %o0
 	sethi		%hi(1 << 14), %o2
@@ -424,6 +344,119 @@
 1:	retl
 	 nop
 
+	/* Cheetah specific versions, patched at boot time.  */
+__cheetah_flush_tlb_page: /* 14 insns */
+	rdpr		%pstate, %g5
+	andn		%g5, PSTATE_IE, %g2
+	wrpr		%g2, 0x0, %pstate
+	wrpr		%g0, 1, %tl
+	mov		PRIMARY_CONTEXT, %o2
+	ldxa		[%o2] ASI_DMMU, %g2
+	stxa		%o0, [%o2] ASI_DMMU
+	stxa		%g0, [%o1] ASI_DMMU_DEMAP
+	stxa		%g0, [%o1] ASI_IMMU_DEMAP
+	stxa		%g2, [%o2] ASI_DMMU
+	flush		%g6
+	wrpr		%g0, 0, %tl
+	retl
+	 wrpr		%g5, 0x0, %pstate
+
+__cheetah_flush_tlb_mm: /* 15 insns */
+	rdpr		%pstate, %g5
+	andn		%g5, PSTATE_IE, %g2
+	wrpr		%g2, 0x0, %pstate
+	wrpr		%g0, 1, %tl
+	mov		PRIMARY_CONTEXT, %o2
+	mov		0x40, %g3
+	ldxa		[%o2] ASI_DMMU, %g2
+	stxa		%o0, [%o2] ASI_DMMU
+	stxa		%g0, [%g3] ASI_DMMU_DEMAP
+	stxa		%g0, [%g3] ASI_IMMU_DEMAP
+	stxa		%g2, [%o2] ASI_DMMU
+	flush		%g6
+	wrpr		%g0, 0, %tl
+	retl
+	 wrpr		%g5, 0x0, %pstate
+
+__cheetah_flush_tlb_range: /* 20 insns */
+	cmp		%o5, %o4
+	blu,pt		%xcc, 9f
+	 rdpr		%pstate, %g5
+	andn		%g5, PSTATE_IE, %g2
+	wrpr		%g2, 0x0, %pstate
+	wrpr		%g0, 1, %tl
+	mov		PRIMARY_CONTEXT, %o2
+	sub		%o5, %o4, %o5
+	ldxa		[%o2] ASI_DMMU, %g2
+	stxa		%o0, [%o2] ASI_DMMU
+1:	stxa		%g0, [%o1 + %o5] ASI_DMMU_DEMAP
+	stxa		%g0, [%o1 + %o5] ASI_IMMU_DEMAP
+	membar		#Sync
+	brnz,pt		%o5, 1b
+	 sub		%o5, %o4, %o5
+	stxa		%g2, [%o2] ASI_DMMU
+	flush		%g6
+	wrpr		%g0, 0, %tl
+9:	retl
+	 wrpr		%g5, 0x0, %pstate
+
+flush_dcpage_cheetah: /* 9 insns */
+	sub		%o0, %g4, %o0
+	sethi		%hi(PAGE_SIZE), %o4
+1:	subcc		%o4, (1 << 5), %o4
+	stxa		%g0, [%o0 + %o4] ASI_DCACHE_INVALIDATE
+	membar		#Sync
+	bne,pt		%icc, 1b
+	 nop
+	retl		/* I-cache flush never needed on Cheetah, see callers. */
+	 nop
+
+cheetah_patch_one:
+1:	lduw		[%o1], %g1
+	stw		%g1, [%o0]
+	flush		%o0
+	subcc		%o2, 1, %o2
+	add		%o1, 4, %o1
+	bne,pt		%icc, 1b
+	 add		%o0, 4, %o0
+	retl
+	 nop
+
+	.globl		cheetah_patch_cachetlbops
+cheetah_patch_cachetlbops:
+	save		%sp, -128, %sp
+
+	sethi		%hi(__flush_tlb_page), %o0
+	or		%o0, %lo(__flush_tlb_page), %o0
+	sethi		%hi(__cheetah_flush_tlb_page), %o1
+	or		%o1, %lo(__cheetah_flush_tlb_page), %o1
+	call		cheetah_patch_one
+	 mov		14, %o2
+
+	sethi		%hi(__flush_tlb_mm), %o0
+	or		%o0, %lo(__flush_tlb_mm), %o0
+	sethi		%hi(__cheetah_flush_tlb_mm), %o1
+	or		%o1, %lo(__cheetah_flush_tlb_mm), %o1
+	call		cheetah_patch_one
+	 mov		15, %o2
+
+	sethi		%hi(__flush_tlb_range), %o0
+	or		%o0, %lo(__flush_tlb_range), %o0
+	sethi		%hi(__cheetah_flush_tlb_range), %o1
+	or		%o1, %lo(__cheetah_flush_tlb_range), %o1
+	call		cheetah_patch_one
+	 mov		20, %o2
+
+	sethi		%hi(__flush_dcache_page), %o0
+	or		%o0, %lo(__flush_dcache_page), %o0
+	sethi		%hi(flush_dcpage_cheetah), %o1
+	or		%o1, %lo(flush_dcpage_cheetah), %o1
+	call		cheetah_patch_one
+	 mov		9, %o2
+
+	ret
+	 restore
+
 #ifdef CONFIG_SMP
 	/* These are all called by the slaves of a cross call, at
 	 * trap level 1, with interrupts fully disabled.
@@ -522,9 +555,9 @@
 	sethi		%hi(PAGE_SIZE), %g3
 1:	subcc		%g3, (1 << 5), %g3
 	stxa		%g0, [%g1 + %g3] ASI_DCACHE_INVALIDATE
+	membar		#Sync
 	bne,pt		%icc, 1b
 	 nop
-	membar		#Sync
 	retry
 	nop
 
@@ -587,10 +620,8 @@
 	.text
 
 	/* These two are not performance critical... */
-	.globl		xcall_flush_tlb_all
-xcall_flush_tlb_all:
-	BRANCH_IF_CHEETAH(g2, g3, __cheetah_xcall_flush_tlb_all)
-__spitfire_xcall_flush_tlb_all:
+	.globl		xcall_flush_tlb_all_spitfire
+xcall_flush_tlb_all_spitfire:
 	/* Spitfire Errata #32 workaround. */
 	sethi		%hi(errata32_hwbug), %g4
 	stx		%g0, [%g4 + %lo(errata32_hwbug)]
@@ -632,16 +663,15 @@
 	flush		%g6
 	retry
 
-__cheetah_xcall_flush_tlb_all:
+	.globl		xcall_flush_tlb_all_cheetah
+xcall_flush_tlb_all_cheetah:
 	mov		0x80, %g2
 	stxa		%g0, [%g2] ASI_DMMU_DEMAP
 	stxa		%g0, [%g2] ASI_IMMU_DEMAP
 	retry
 
-	.globl		xcall_flush_cache_all
-xcall_flush_cache_all:
-	BRANCH_IF_CHEETAH(g2, g3, __cheetah_xcall_flush_cache_all)
-__spitfire_xcall_flush_cache_all:
+	.globl		xcall_flush_cache_all_spitfire
+xcall_flush_cache_all_spitfire:
 	sethi		%hi(16383), %g2
 	or		%g2, %lo(16383), %g2
 	clr		%g3
@@ -654,13 +684,6 @@
 	flush		%g6
 	retry
 
-	/* Cheetah's caches are fully coherent in the sense that
-	 * caches are flushed here.  We need to verify this and
-	 * really just not even send out the xcall at the top level.
-	 */
-__cheetah_xcall_flush_cache_all:
-	retry
-
 	/* These just get rescheduled to PIL vectors. */
 	.globl		xcall_call_function
 xcall_call_function:
diff -urN linux-2.4.20-pre4/arch/x86_64/mm/fault.c linux-2.4.20-pre5/arch/x86_64/mm/fault.c
--- linux-2.4.20-pre4/arch/x86_64/mm/fault.c	Wed Aug 28 16:36:45 2002
+++ linux-2.4.20-pre5/arch/x86_64/mm/fault.c	Wed Aug 28 16:37:44 2002
@@ -144,9 +144,8 @@
 	if (in_interrupt() || !mm)
 		goto no_context;
 
-again:
 	down_read(&mm->mmap_sem);
-
+again:
 	vma = find_vma(mm, address);
 	if (!vma)
 		goto bad_area;
@@ -268,11 +267,11 @@
  * us unable to handle the page fault gracefully.
  */
 out_of_memory:
-	up_read(&mm->mmap_sem);
 	if (current->pid == 1) { 
 		yield();
 		goto again;
 	}
+	up_read(&mm->mmap_sem);
 	printk("VM: killing process %s\n", tsk->comm);
 	if (error_code & 4)
 		do_exit(SIGKILL);
diff -urN linux-2.4.20-pre4/drivers/block/cpqarray.c linux-2.4.20-pre5/drivers/block/cpqarray.c
--- linux-2.4.20-pre4/drivers/block/cpqarray.c	Wed Aug 28 16:36:46 2002
+++ linux-2.4.20-pre5/drivers/block/cpqarray.c	Wed Aug 28 16:37:45 2002
@@ -1141,12 +1141,8 @@
         }
 
 	complete_buffers(cmd->rq->bh, ok);
-
 	DBGPX(printk("Done with %p\n", cmd->rq););
-	req_finished_io(cmd->rq);
 	end_that_request_last(cmd->rq);
-
-
 }
 
 /*
diff -urN linux-2.4.20-pre4/drivers/block/genhd.c linux-2.4.20-pre5/drivers/block/genhd.c
--- linux-2.4.20-pre4/drivers/block/genhd.c	Wed Aug 28 16:36:46 2002
+++ linux-2.4.20-pre5/drivers/block/genhd.c	Wed Aug 28 16:37:45 2002
@@ -194,9 +194,7 @@
 
 	/* show the full disk and all non-0 size partitions of it */
 	for (n = 0; n < (gp->nr_real << gp->minor_shift); n++) {
-		int mask = (1<<gp->minor_shift) - 1;
-
-		if (!(n & mask) || gp->part[n].nr_sects) {
+		if (gp->part[n].nr_sects) {
 #ifdef CONFIG_BLK_STATS
 			struct hd_struct *hd = &gp->part[n];
 
diff -urN linux-2.4.20-pre4/drivers/block/ps2esdi.c linux-2.4.20-pre5/drivers/block/ps2esdi.c
--- linux-2.4.20-pre4/drivers/block/ps2esdi.c	Wed Aug 28 16:36:46 2002
+++ linux-2.4.20-pre5/drivers/block/ps2esdi.c	Wed Aug 28 16:37:45 2002
@@ -580,10 +580,10 @@
 	     cylinder, head, sector,
 	     CURRENT->current_nr_sectors, drive);
 
-	spin_unlock_irq(&io_request_irq);
+	spin_unlock_irq(&io_request_lock);
 	/* send the command block to the controller */
 	err = ps2esdi_out_cmd_blk(cmd_blk);
-	spin_lock_irq(&io_request_irq);
+	spin_lock_irq(&io_request_lock);
 	
 	if (err) {
 		printk(KERN_ERR "%s: Controller failed\n", DEVICE_NAME);
diff -urN linux-2.4.20-pre4/drivers/char/Config.in linux-2.4.20-pre5/drivers/char/Config.in
--- linux-2.4.20-pre4/drivers/char/Config.in	Wed Aug 28 16:36:47 2002
+++ linux-2.4.20-pre5/drivers/char/Config.in	Wed Aug 28 16:37:46 2002
@@ -54,6 +54,7 @@
       dep_tristate '  Multi-Tech multiport card support (EXPERIMENTAL)' CONFIG_ISI m
    fi
    tristate '  Microgate SyncLink card support' CONFIG_SYNCLINK
+   tristate '  SyncLink Multiport support' CONFIG_SYNCLINKMP
    tristate '  HDLC line discipline support' CONFIG_N_HDLC
    tristate '  SDL RISCom/8 card support' CONFIG_RISCOM8
    if [ "$CONFIG_X86_64" != "y" ]; then
@@ -246,7 +247,7 @@
    bool 'EFI Real Time Clock Services' CONFIG_EFI_RTC
 fi
 if [ "$CONFIG_OBSOLETE" = "y" -a "$CONFIG_ALPHA_BOOK1" = "y" ]; then
-   bool 'Tadpole ANA H8 Support'  CONFIG_H8
+   bool 'Tadpole ANA H8 Support (OBSOLETE)'  CONFIG_H8
 fi
 
 tristate 'Double Talk PC internal speech card support' CONFIG_DTLK
diff -urN linux-2.4.20-pre4/drivers/char/Makefile linux-2.4.20-pre5/drivers/char/Makefile
--- linux-2.4.20-pre4/drivers/char/Makefile	Wed Aug 28 16:36:47 2002
+++ linux-2.4.20-pre5/drivers/char/Makefile	Wed Aug 28 16:37:46 2002
@@ -178,6 +178,7 @@
 obj-$(CONFIG_ISI) += isicom.o
 obj-$(CONFIG_ESPSERIAL) += esp.o
 obj-$(CONFIG_SYNCLINK) += synclink.o
+obj-$(CONFIG_SYNCLINKMP) += synclinkmp.o
 obj-$(CONFIG_N_HDLC) += n_hdlc.o
 obj-$(CONFIG_SPECIALIX) += specialix.o
 obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o
diff -urN linux-2.4.20-pre4/drivers/char/amd7xx_tco.c linux-2.4.20-pre5/drivers/char/amd7xx_tco.c
--- linux-2.4.20-pre4/drivers/char/amd7xx_tco.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre5/drivers/char/amd7xx_tco.c	Wed Aug 28 16:37:46 2002
@@ -0,0 +1,377 @@
+/*
+ *	AMD 766/768 TCO Timer Driver
+ *	(c) Copyright 2002 Zwane Mwaikambo <zwane@commfireservices.com>
+ *	All Rights Reserved.
+ *
+ *	Parts from;
+ *	Hardware driver for the AMD 768 Random Number Generator (RNG)
+ *	(c) Copyright 2001 Red Hat Inc <alan@redhat.com>
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License version 2
+ *	as published by the Free Software Foundation.
+ *
+ *	The author(s) of this software shall not be held liable for damages
+ *	of any nature resulting due to the use of this software. This
+ *	software is provided AS-IS with no warranties.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/ioport.h>
+#include <linux/spinlock.h>
+#include <linux/ioport.h>
+#include <asm/semaphore.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#define AMDTCO_MODULE_VER	"build 20020601"
+#define AMDTCO_MODULE_NAME	"amd7xx_tco"
+#define PFX			AMDTCO_MODULE_NAME ": "
+
+#define	MAX_TIMEOUT	38	/* max of 38 seconds */
+
+/* pmbase registers */
+#define GLOBAL_SMI_REG	0x2a
+#define TCO_EN		(1 << 1)	/* bit 1 in global SMI register */
+#define TCO_RELOAD_REG	0x40		/* bits 0-5 are current count, 6-7 are reserved */
+#define TCO_INITVAL_REG	0x41		/* bits 0-5 are value to load, 6-7 are reserved */
+#define TCO_TIMEOUT_MASK	0x3f
+#define TCO_STATUS2_REG	0x46
+#define NDTO_STS2	(1 << 1)	/* we're interested in the second timeout */ 
+#define BOOT_STS	(1 << 2)	/* will be set if NDTO_STS2 was set before reboot */
+#define TCO_CTRL1_REG	0x48
+#define TCO_HALT	(1 << 11)
+
+static char banner[] __initdata = KERN_INFO PFX AMDTCO_MODULE_VER;
+static int timeout = 38;
+static u32 pmbase;		/* PMxx I/O base */
+static struct pci_dev *dev;
+static struct semaphore open_sem;
+spinlock_t amdtco_lock;	/* only for device access */
+static int expect_close = 0;
+
+MODULE_PARM(timeout, "i");
+MODULE_PARM_DESC(timeout, "range is 0-38 seconds, default is 38");
+
+static inline int amdtco_status(void)
+{
+	u16 reg;
+	int status = 0;
+
+	reg = inb(pmbase+TCO_CTRL1_REG);
+	if ((reg & TCO_HALT) == 0)
+		status |= WDIOF_KEEPALIVEPING;
+
+	reg = inb(pmbase+TCO_STATUS2_REG);
+	if (reg & BOOT_STS)
+		status |= WDIOF_CARDRESET;
+
+	return status;
+}
+
+static inline void amdtco_ping(void)
+{
+	u8 reg;
+
+	spin_lock(&amdtco_lock);
+	reg = inb(pmbase+TCO_RELOAD_REG);
+	outb(1 | reg, pmbase+TCO_RELOAD_REG);
+	spin_unlock(&amdtco_lock);
+}
+
+static inline int amdtco_gettimeout(void)
+{
+	return inb(TCO_RELOAD_REG) & TCO_TIMEOUT_MASK;
+}
+
+static inline void amdtco_settimeout(unsigned int timeout)
+{
+	u8 reg;
+
+	spin_lock(&amdtco_lock);
+	reg = inb(pmbase+TCO_INITVAL_REG);
+	reg |= timeout & TCO_TIMEOUT_MASK;
+	outb(reg, pmbase+TCO_INITVAL_REG);
+	spin_unlock(&amdtco_lock);
+}
+
+static inline void amdtco_global_enable(void)
+{
+	u16 reg;
+
+	spin_lock(&amdtco_lock);
+	reg = inw(pmbase+GLOBAL_SMI_REG);
+	reg |= TCO_EN;
+	outw(reg, pmbase+GLOBAL_SMI_REG);
+	spin_unlock(&amdtco_lock);
+}
+
+static inline void amdtco_enable(void)
+{
+	u16 reg;
+	
+	spin_lock(&amdtco_lock);
+	reg = inw(pmbase+TCO_CTRL1_REG);
+	reg &= ~TCO_HALT;
+	outw(reg, pmbase+TCO_CTRL1_REG);
+	spin_unlock(&amdtco_lock);
+}
+
+static inline void amdtco_disable(void)
+{
+	u16 reg;
+
+	spin_lock(&amdtco_lock);
+	reg = inw(pmbase+TCO_CTRL1_REG);
+	reg |= TCO_HALT;
+	outw(reg, pmbase+TCO_CTRL1_REG);
+	spin_unlock(&amdtco_lock);
+}
+
+static int amdtco_fop_open(struct inode *inode, struct file *file)
+{
+	if (down_trylock(&open_sem))
+		return -EBUSY;
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT	
+	MOD_INC_USE_COUNT;
+#endif
+
+	if (timeout > MAX_TIMEOUT)
+		timeout = MAX_TIMEOUT;
+
+	amdtco_settimeout(timeout);	
+	amdtco_global_enable();
+	amdtco_ping();
+	printk(KERN_INFO PFX "Watchdog enabled, timeout = %d/%d seconds",
+		amdtco_gettimeout(), timeout);
+	
+	return 0;
+}
+
+
+static int amdtco_fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	int new_timeout;
+	int tmp;
+
+	static struct watchdog_info ident = {
+		options:	WDIOF_SETTIMEOUT | WDIOF_CARDRESET,
+		identity:	"AMD 766/768"
+	};
+
+	switch (cmd) {
+		default:
+			return -ENOTTY;	
+
+		case WDIOC_GETSUPPORT:
+			if (copy_to_user((struct watchdog_info *)arg, &ident, sizeof ident))
+				return -EFAULT;
+			return 0;
+
+		case WDIOC_GETSTATUS:
+			return put_user(amdtco_status(), (int *)arg);
+	
+		case WDIOC_KEEPALIVE:
+			amdtco_ping();
+			return 0;
+
+		case WDIOC_SETTIMEOUT:
+			if (get_user(new_timeout, (int *)arg))
+				return -EFAULT;
+			
+			if (new_timeout < 0)
+				return -EINVAL;
+		
+			if (new_timeout > MAX_TIMEOUT)
+				new_timeout = MAX_TIMEOUT;
+
+			timeout = new_timeout;
+			amdtco_settimeout(timeout);
+			/* fall through and return the new timeout */
+
+		case WDIOC_GETTIMEOUT:
+			return put_user(amdtco_gettimeout(), (int *)arg);
+	
+		case WDIOC_SETOPTIONS:
+			if (copy_from_user(&tmp, (int *)arg, sizeof tmp))
+                                return -EFAULT;
+
+			if (tmp & WDIOS_DISABLECARD)
+				amdtco_disable();
+
+			if (tmp & WDIOS_ENABLECARD)
+				amdtco_enable();
+			
+			return 0;
+	}
+}
+
+
+static int amdtco_fop_release(struct inode *inode, struct file *file)
+{
+	if (expect_close) {
+		amdtco_disable();	
+		printk(KERN_INFO PFX "Watchdog disabled\n");
+	} else {
+		amdtco_ping();
+		printk(KERN_CRIT PFX "Unexpected close!, timeout in %d seconds)\n", timeout);
+	}	
+	
+	up(&open_sem);
+	return 0;
+}
+
+
+static ssize_t amdtco_fop_write(struct file *file, const char *data, size_t len, loff_t *ppos)
+{
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+	
+	if (len) {
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+		size_t i;
+		char c;
+		expect_close = 0;
+		
+		for (i = 0; i != len; i++) {
+			if (get_user(c, data + i))
+				return -EFAULT;
+
+			if (c == 'V')
+				expect_close = 1;
+		}
+#endif
+		amdtco_ping();
+		return len;
+	}
+
+	return 0;
+}
+
+
+static int amdtco_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
+{
+	if (code == SYS_DOWN || code == SYS_HALT)
+		amdtco_disable();
+
+	return NOTIFY_DONE;
+}
+
+
+static struct notifier_block amdtco_notifier =
+{
+	notifier_call:	amdtco_notify_sys
+};
+
+static struct file_operations amdtco_fops =
+{
+	owner:		THIS_MODULE,
+	write:		amdtco_fop_write,
+	ioctl:		amdtco_fop_ioctl,
+	open:		amdtco_fop_open,
+	release:	amdtco_fop_release
+};
+
+static struct miscdevice amdtco_miscdev =
+{
+	minor:		WATCHDOG_MINOR,
+	name:		"watchdog",
+	fops:		&amdtco_fops
+};
+
+static struct pci_device_id amdtco_pci_tbl[] __initdata = {
+	/* AMD 766 PCI_IDs here */
+	{ 0x1022, 0x7443, PCI_ANY_ID, PCI_ANY_ID, },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE (pci, amdtco_pci_tbl);
+
+static int __init amdtco_init(void)
+{
+	int ret;
+
+	sema_init(&open_sem, 1);
+	spin_lock_init(&amdtco_lock);
+
+	pci_for_each_dev(dev) {
+		if (pci_match_device (amdtco_pci_tbl, dev) != NULL)
+			goto found_one;
+	}
+
+	return -ENODEV;
+
+found_one:
+	
+	if ((ret = register_reboot_notifier(&amdtco_notifier))) {
+		printk(KERN_ERR PFX "Unable to register reboot notifier err = %d\n", ret);
+		goto out_clean;
+	}
+
+	if ((ret = misc_register(&amdtco_miscdev))) {
+		printk(KERN_ERR PFX "Unable to register miscdev on minor %d\n", WATCHDOG_MINOR);
+		goto out_unreg_reboot;
+	}
+
+	pci_read_config_dword(dev, 0x58, &pmbase);
+	pmbase &= 0x0000FF00;
+
+	if (pmbase == 0) {
+		printk (KERN_ERR PFX "power management base not set\n");
+		ret = -EIO;
+		goto out_unreg_misc;
+	}
+
+	/* ret = 0; */
+	printk(banner);
+	goto out_clean;
+
+out_unreg_misc:
+	misc_deregister(&amdtco_miscdev);
+out_unreg_reboot:
+	unregister_reboot_notifier(&amdtco_notifier);
+out_clean:
+	return ret;
+}
+
+static void __exit amdtco_exit(void)
+{
+	misc_deregister(&amdtco_miscdev);
+	unregister_reboot_notifier(&amdtco_notifier);
+}
+
+
+#ifndef MODULE
+static int __init amdtco_setup(char *str)
+{
+	int ints[4];
+
+	str = get_options (str, ARRAY_SIZE(ints), ints);
+	if (ints[0] > 0)
+		timeout = ints[1];
+
+	return 1;
+}
+
+__setup("amd7xx_tco=", amdtco_setup);
+#endif
+
+module_init(amdtco_init);
+module_exit(amdtco_exit);
+
+MODULE_AUTHOR("Zwane Mwaikambo <zwane@commfireservices.com>");
+MODULE_DESCRIPTION("AMD 766/768 TCO Timer Driver");
+MODULE_LICENSE("GPL");
+EXPORT_NO_SYMBOLS;
+
diff -urN linux-2.4.20-pre4/drivers/char/drm/Config.in linux-2.4.20-pre5/drivers/char/drm/Config.in
--- linux-2.4.20-pre4/drivers/char/drm/Config.in	Mon Feb 25 11:37:57 2002
+++ linux-2.4.20-pre5/drivers/char/drm/Config.in	Wed Aug 28 16:37:48 2002
@@ -10,5 +10,6 @@
 tristate '  ATI Rage 128' CONFIG_DRM_R128
 dep_tristate '  ATI Radeon' CONFIG_DRM_RADEON $CONFIG_AGP
 dep_tristate '  Intel I810' CONFIG_DRM_I810 $CONFIG_AGP
+dep_tristate '  Intel 830M' CONFIG_DRM_I830 $CONFIG_AGP
 dep_tristate '  Matrox g200/g400' CONFIG_DRM_MGA $CONFIG_AGP
 dep_tristate '  SiS' CONFIG_DRM_SIS $CONFIG_AGP
diff -urN linux-2.4.20-pre4/drivers/char/drm/Makefile linux-2.4.20-pre5/drivers/char/drm/Makefile
--- linux-2.4.20-pre4/drivers/char/drm/Makefile	Fri Dec 21 09:41:53 2001
+++ linux-2.4.20-pre5/drivers/char/drm/Makefile	Wed Aug 28 16:37:48 2002
@@ -3,13 +3,15 @@
 # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
 
 O_TARGET	:= drm.o
-list-multi	:= gamma.o tdfx.o r128.o mga.o i810.o radeon.o ffb.o sis.o
+list-multi	:= gamma.o tdfx.o r128.o mga.o i810.o i830.o radeon.o ffb.o sis.o
 
 gamma-objs  := gamma_drv.o gamma_dma.o
 tdfx-objs   := tdfx_drv.o
 r128-objs   := r128_drv.o r128_cce.o r128_state.o
 mga-objs    := mga_drv.o mga_dma.o mga_state.o mga_warp.o
 i810-objs   := i810_drv.o i810_dma.o
+i830-objs   := i830_drv.o i830_dma.o
+
 radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o
 ffb-objs    := ffb_drv.o ffb_context.o
 sis-objs    := sis_drv.o sis_ds.o sis_mm.o
@@ -20,6 +22,7 @@
 obj-$(CONFIG_DRM_RADEON)+= radeon.o
 obj-$(CONFIG_DRM_MGA)	+= mga.o
 obj-$(CONFIG_DRM_I810)	+= i810.o
+obj-$(CONFIG_DRM_I830)	+= i830.o
 obj-$(CONFIG_DRM_FFB)   += ffb.o
 obj-$(CONFIG_DRM_SIS)   += sis.o
 
@@ -37,6 +40,9 @@
 i810.o: $(i810-objs) $(lib)
 	$(LD) -r -o $@ $(i810-objs) $(lib)
 
+i830.o: $(i830-objs) $(lib)
+	$(LD) -r -o $@ $(i830-objs) $(lib)
+
 r128.o: $(r128-objs) $(lib)
 	$(LD) -r -o $@ $(r128-objs) $(lib)
 
diff -urN linux-2.4.20-pre4/drivers/char/drm/ati_pcigart.h linux-2.4.20-pre5/drivers/char/drm/ati_pcigart.h
--- linux-2.4.20-pre4/drivers/char/drm/ati_pcigart.h	Thu Nov 22 11:46:37 2001
+++ linux-2.4.20-pre5/drivers/char/drm/ati_pcigart.h	Wed Aug 28 16:37:48 2002
@@ -27,7 +27,6 @@
  *   Gareth Hughes <gareth@valinux.com>
  */
 
-#define __NO_VERSION__
 #include "drmP.h"
 
 #if PAGE_SIZE == 8192
diff -urN linux-2.4.20-pre4/drivers/char/drm/drm.h linux-2.4.20-pre5/drivers/char/drm/drm.h
--- linux-2.4.20-pre4/drivers/char/drm/drm.h	Fri Dec 21 09:41:53 2001
+++ linux-2.4.20-pre5/drivers/char/drm/drm.h	Wed Aug 28 16:37:48 2002
@@ -104,9 +104,8 @@
 #include "i810_drm.h"
 #include "r128_drm.h"
 #include "radeon_drm.h"
-#if defined(CONFIG_DRM_SIS) || defined(CONFIG_DRM_SIS_MODULE)
 #include "sis_drm.h"
-#endif
+#include "i830_drm.h"
 
 typedef struct drm_version {
 	int    version_major;	  /* Major version			    */
@@ -449,6 +448,12 @@
 #define DRM_IOCTL_I810_SWAP		DRM_IO(  0x46)
 #define DRM_IOCTL_I810_COPY		DRM_IOW( 0x47, drm_i810_copy_t)
 #define DRM_IOCTL_I810_DOCOPY		DRM_IO(  0x48)
+#define DRM_IOCTL_I810_OV0INFO		DRM_IOR( 0x49, drm_i810_overlay_t)
+#define DRM_IOCTL_I810_FSTATUS		DRM_IO ( 0x4a)
+#define DRM_IOCTL_I810_OV0FLIP		DRM_IO ( 0x4b)
+#define DRM_IOCTL_I810_MC		DRM_IOW( 0x4c, drm_i810_mc_t)
+#define DRM_IOCTL_I810_RSTATUS		DRM_IO ( 0x4d )
+
 
 /* Rage 128 specific ioctls */
 #define DRM_IOCTL_R128_INIT		DRM_IOW( 0x40, drm_r128_init_t)
@@ -483,7 +488,6 @@
 #define DRM_IOCTL_RADEON_INDIRECT	DRM_IOWR(0x4d, drm_radeon_indirect_t)
 #define DRM_IOCTL_RADEON_TEXTURE	DRM_IOWR(0x4e, drm_radeon_texture_t)
 
-#if defined(CONFIG_DRM_SIS) || defined(CONFIG_DRM_SIS_MODULE)
 /* SiS specific ioctls */
 #define SIS_IOCTL_FB_ALLOC		DRM_IOWR(0x44, drm_sis_mem_t)
 #define SIS_IOCTL_FB_FREE		DRM_IOW( 0x45, drm_sis_mem_t)
@@ -493,6 +497,16 @@
 #define SIS_IOCTL_FLIP			DRM_IOW( 0x48, drm_sis_flip_t)
 #define SIS_IOCTL_FLIP_INIT		DRM_IO(  0x49)
 #define SIS_IOCTL_FLIP_FINAL		DRM_IO(  0x50)
-#endif
+
+/* I830 specific ioctls */
+#define DRM_IOCTL_I830_INIT		DRM_IOW( 0x40, drm_i830_init_t)
+#define DRM_IOCTL_I830_VERTEX		DRM_IOW( 0x41, drm_i830_vertex_t)
+#define DRM_IOCTL_I830_CLEAR		DRM_IOW( 0x42, drm_i830_clear_t)
+#define DRM_IOCTL_I830_FLUSH		DRM_IO ( 0x43)
+#define DRM_IOCTL_I830_GETAGE		DRM_IO ( 0x44)
+#define DRM_IOCTL_I830_GETBUF		DRM_IOWR(0x45, drm_i830_dma_t)
+#define DRM_IOCTL_I830_SWAP		DRM_IO ( 0x46)
+#define DRM_IOCTL_I830_COPY		DRM_IOW( 0x47, drm_i830_copy_t)
+#define DRM_IOCTL_I830_DOCOPY		DRM_IO ( 0x48)
 
 #endif
diff -urN linux-2.4.20-pre4/drivers/char/drm/drmP.h linux-2.4.20-pre5/drivers/char/drm/drmP.h
--- linux-2.4.20-pre4/drivers/char/drm/drmP.h	Thu Nov 22 11:46:37 2001
+++ linux-2.4.20-pre5/drivers/char/drm/drmP.h	Wed Aug 28 16:37:48 2002
@@ -66,13 +66,8 @@
 #include <linux/types.h>
 #include <linux/agp_backend.h>
 #endif
-#if LINUX_VERSION_CODE >= 0x020100 /* KERNEL_VERSION(2,1,0) */
 #include <linux/tqueue.h>
 #include <linux/poll.h>
-#endif
-#if LINUX_VERSION_CODE < 0x020400
-#include "compat-pre24.h"
-#endif
 #include <asm/pgalloc.h>
 #include "drm.h"
 
@@ -81,12 +76,6 @@
 #define page_to_bus(page)	((unsigned int)(virt_to_bus(page_address(page))))
 #endif
 
-/* We just use virt_to_bus for pci_map_single on older kernels */
-#if LINUX_VERSION_CODE < 0x020400
-#define pci_map_single(hwdev, ptr, size, direction)	virt_to_bus(ptr)
-#define pci_unmap_single(hwdev, dma_addr, size, direction)
-#endif
-
 /* DRM template customization defaults
  */
 #ifndef __HAVE_AGP
@@ -119,87 +108,6 @@
 #define __REALLY_HAVE_MTRR	(__HAVE_MTRR && defined(CONFIG_MTRR))
 
 
-/* Begin the DRM...
- */
-
-#define DRM_DEBUG_CODE 2	  /* Include debugging code (if > 1, then
-				     also include looping detection. */
-
-#define DRM_HASH_SIZE	      16 /* Size of key hash table		  */
-#define DRM_KERNEL_CONTEXT    0	 /* Change drm_resctx if changed	  */
-#define DRM_RESERVED_CONTEXTS 1	 /* Change drm_resctx if changed	  */
-#define DRM_LOOPING_LIMIT     5000000
-#define DRM_BSZ		      1024 /* Buffer size for /dev/drm? output	  */
-#define DRM_TIME_SLICE	      (HZ/20)  /* Time slice for GLXContexts	  */
-#define DRM_LOCK_SLICE	      1	/* Time slice for lock, in jiffies	  */
-
-#define DRM_FLAG_DEBUG	  0x01
-#define DRM_FLAG_NOCTX	  0x02
-
-#define DRM_MEM_DMA	   0
-#define DRM_MEM_SAREA	   1
-#define DRM_MEM_DRIVER	   2
-#define DRM_MEM_MAGIC	   3
-#define DRM_MEM_IOCTLS	   4
-#define DRM_MEM_MAPS	   5
-#define DRM_MEM_VMAS	   6
-#define DRM_MEM_BUFS	   7
-#define DRM_MEM_SEGS	   8
-#define DRM_MEM_PAGES	   9
-#define DRM_MEM_FILES	  10
-#define DRM_MEM_QUEUES	  11
-#define DRM_MEM_CMDS	  12
-#define DRM_MEM_MAPPINGS  13
-#define DRM_MEM_BUFLISTS  14
-#define DRM_MEM_AGPLISTS  15
-#define DRM_MEM_TOTALAGP  16
-#define DRM_MEM_BOUNDAGP  17
-#define DRM_MEM_CTXBITMAP 18
-#define DRM_MEM_STUB      19
-#define DRM_MEM_SGLISTS   20
-
-#define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8)
-
-				/* Backward compatibility section */
-				/* _PAGE_WT changed to _PAGE_PWT in 2.2.6 */
-#ifndef _PAGE_PWT
-#define _PAGE_PWT _PAGE_WT
-#endif
-				/* Wait queue declarations changed in 2.3.1 */
-#ifndef DECLARE_WAITQUEUE
-#define DECLARE_WAITQUEUE(w,c) struct wait_queue w = { c, NULL }
-typedef struct wait_queue *wait_queue_head_t;
-#define init_waitqueue_head(q) *q = NULL;
-#endif
-
-				/* _PAGE_4M changed to _PAGE_PSE in 2.3.23 */
-#ifndef _PAGE_PSE
-#define _PAGE_PSE _PAGE_4M
-#endif
-
-				/* vm_offset changed to vm_pgoff in 2.3.25 */
-#if LINUX_VERSION_CODE < 0x020319
-#define VM_OFFSET(vma) ((vma)->vm_offset)
-#else
-#define VM_OFFSET(vma) ((vma)->vm_pgoff << PAGE_SHIFT)
-#endif
-
-				/* *_nopage return values defined in 2.3.26 */
-#ifndef NOPAGE_SIGBUS
-#define NOPAGE_SIGBUS 0
-#endif
-#ifndef NOPAGE_OOM
-#define NOPAGE_OOM 0
-#endif
-
-				/* module_init/module_exit added in 2.3.13 */
-#ifndef module_init
-#define module_init(x)  int init_module(void) { return x(); }
-#endif
-#ifndef module_exit
-#define module_exit(x)  void cleanup_module(void) { x(); }
-#endif
-
 				/* Generic cmpxchg added in 2.3.x */
 #ifndef __HAVE_ARCH_CMPXCHG
 				/* Include this here so that driver can be
@@ -211,7 +119,7 @@
 	unsigned long prev, cmp;
 
 	__asm__ __volatile__(
-	"1:	ldl_l %0,%5\n"
+	"1:	ldl_l %0,%2\n"
 	"	cmpeq %0,%3,%1\n"
 	"	beq %1,2f\n"
 	"	mov %4,%1\n"
@@ -222,8 +130,7 @@
 	"3:	br 1b\n"
 	".previous"
 	: "=&r"(prev), "=&r"(cmp), "=m"(*m)
-	: "r"((long) old), "r"(new), "m"(*m)
-	: "memory" );
+	: "r"((long) old), "r"(new), "m"(*m));
 
 	return prev;
 }
@@ -234,7 +141,7 @@
 	unsigned long prev, cmp;
 
 	__asm__ __volatile__(
-	"1:	ldq_l %0,%5\n"
+	"1:	ldq_l %0,%2\n"
 	"	cmpeq %0,%3,%1\n"
 	"	beq %1,2f\n"
 	"	mov %4,%1\n"
@@ -245,8 +152,7 @@
 	"3:	br 1b\n"
 	".previous"
 	: "=&r"(prev), "=&r"(cmp), "=m"(*m)
-	: "r"((long) old), "r"(new), "m"(*m)
-	: "memory" );
+	: "r"((long) old), "r"(new), "m"(*m));
 
 	return prev;
 }
@@ -298,42 +204,82 @@
 	return old;
 }
 
-#elif defined(__powerpc__)
-extern void __cmpxchg_called_with_bad_pointer(void);
-static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
-                                      unsigned long new, int size)
-{
-	unsigned long prev;
-
-	switch (size) {
-	case 4:
-		__asm__ __volatile__(
-			"sync;"
-			"0:    lwarx %0,0,%1 ;"
-			"      cmpl 0,%0,%3;"
-			"      bne 1f;"
-			"      stwcx. %2,0,%1;"
-			"      bne- 0b;"
-			"1:    "
-			"sync;"
-			: "=&r"(prev)
-			: "r"(ptr), "r"(new), "r"(old)
-			: "cr0", "memory");
-		return prev;
-	}
-	__cmpxchg_called_with_bad_pointer();
-	return old;
-}
-
-#endif /* i386, powerpc & alpha */
-
-#ifndef __alpha__
 #define cmpxchg(ptr,o,n)						\
   ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),		\
 				 (unsigned long)(n),sizeof(*(ptr))))
+#endif /* i386 & alpha */
 #endif
 
-#endif /* !__HAVE_ARCH_CMPXCHG */
+/* Begin the DRM...
+ */
+
+#define DRM_DEBUG_CODE 2	  /* Include debugging code (if > 1, then
+				     also include looping detection. */
+
+#define DRM_HASH_SIZE	      16 /* Size of key hash table		  */
+#define DRM_KERNEL_CONTEXT    0	 /* Change drm_resctx if changed	  */
+#define DRM_RESERVED_CONTEXTS 1	 /* Change drm_resctx if changed	  */
+#define DRM_LOOPING_LIMIT     5000000
+#define DRM_BSZ		      1024 /* Buffer size for /dev/drm? output	  */
+#define DRM_TIME_SLICE	      (HZ/20)  /* Time slice for GLXContexts	  */
+#define DRM_LOCK_SLICE	      1	/* Time slice for lock, in jiffies	  */
+
+#define DRM_FLAG_DEBUG	  0x01
+#define DRM_FLAG_NOCTX	  0x02
+
+#define DRM_MEM_DMA	   0
+#define DRM_MEM_SAREA	   1
+#define DRM_MEM_DRIVER	   2
+#define DRM_MEM_MAGIC	   3
+#define DRM_MEM_IOCTLS	   4
+#define DRM_MEM_MAPS	   5
+#define DRM_MEM_VMAS	   6
+#define DRM_MEM_BUFS	   7
+#define DRM_MEM_SEGS	   8
+#define DRM_MEM_PAGES	   9
+#define DRM_MEM_FILES	  10
+#define DRM_MEM_QUEUES	  11
+#define DRM_MEM_CMDS	  12
+#define DRM_MEM_MAPPINGS  13
+#define DRM_MEM_BUFLISTS  14
+#define DRM_MEM_AGPLISTS  15
+#define DRM_MEM_TOTALAGP  16
+#define DRM_MEM_BOUNDAGP  17
+#define DRM_MEM_CTXBITMAP 18
+#define DRM_MEM_STUB      19
+#define DRM_MEM_SGLISTS   20
+
+#define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8)
+
+#define VM_OFFSET(vma) ((vma)->vm_pgoff << PAGE_SHIFT)
+
+/* Macros to make printk easier */
+
+#if ( __GNUC__ > 2 )
+
+#define DRM_ERROR(fmt, arg...) \
+	printk(KERN_ERR "[" DRM_NAME ":%s] *ERROR* " fmt , __FUNCTION__, ##arg)
+#define DRM_MEM_ERROR(area, fmt, arg...) \
+	printk(KERN_ERR "[" DRM_NAME ":%s:%s] *ERROR* " fmt , __FUNCTION__, \
+	       DRM(mem_stats)[area].name , ##arg)
+#define DRM_INFO(fmt, arg...)  printk(KERN_INFO "[" DRM_NAME "] " fmt , ##arg)
+
+#if DRM_DEBUG_CODE
+#define DRM_DEBUG(fmt, arg...)						\
+	do {								\
+		if ( DRM(flags) & DRM_FLAG_DEBUG )			\
+			printk(KERN_DEBUG				\
+			       "[" DRM_NAME ":%s] " fmt ,		\
+			       __FUNCTION__,				\
+			       ##arg);					\
+	} while (0)
+#else
+#define DRM_DEBUG(fmt, arg...)		 do { } while (0)
+#endif
+
+#else	/* Gcc 2.x */
+
+/* Work around a C preprocessor bug */
 
 				/* Macros to make printk easier */
 #define DRM_ERROR(fmt, arg...) \
@@ -355,6 +301,9 @@
 #define DRM_DEBUG(fmt, arg...)		 do { } while (0)
 #endif
 
+#endif	/* Gcc 2.x */
+
+
 #define DRM_PROC_LIMIT (PAGE_SIZE-80)
 
 #define DRM_PROC_PRINT(fmt, arg...)					\
@@ -730,12 +679,8 @@
 #endif
 	struct pci_dev *pdev;
 #ifdef __alpha__
-#if LINUX_VERSION_CODE < 0x020403
-	struct pci_controler *hose;
-#else
 	struct pci_controller *hose;
 #endif
-#endif
 	drm_sg_mem_t      *sg;  /* Scatter gather memory */
 	unsigned long     *ctx_bitmap;
 	void		  *dev_private;
@@ -778,21 +723,6 @@
 			       struct poll_table_struct *wait);
 
 				/* Mapping support (drm_vm.h) */
-#if LINUX_VERSION_CODE < 0x020317
-extern unsigned long DRM(vm_nopage)(struct vm_area_struct *vma,
-				    unsigned long address,
-				    int unused);
-extern unsigned long DRM(vm_shm_nopage)(struct vm_area_struct *vma,
-					unsigned long address,
-					int unused);
-extern unsigned long DRM(vm_dma_nopage)(struct vm_area_struct *vma,
-					unsigned long address,
-					int unused);
-extern unsigned long DRM(vm_sg_nopage)(struct vm_area_struct *vma,
-				       unsigned long address,
-				       int unused);
-#else
-				/* Return type changed in 2.3.23 */
 extern struct page *DRM(vm_nopage)(struct vm_area_struct *vma,
 				   unsigned long address,
 				   int unused);
@@ -805,7 +735,6 @@
 extern struct page *DRM(vm_sg_nopage)(struct vm_area_struct *vma,
 				      unsigned long address,
 				      int unused);
-#endif
 extern void	     DRM(vm_open)(struct vm_area_struct *vma);
 extern void	     DRM(vm_close)(struct vm_area_struct *vma);
 extern void	     DRM(vm_shm_close)(struct vm_area_struct *vma);
diff -urN linux-2.4.20-pre4/drivers/char/drm/drm_agpsupport.h linux-2.4.20-pre5/drivers/char/drm/drm_agpsupport.h
--- linux-2.4.20-pre4/drivers/char/drm/drm_agpsupport.h	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/drivers/char/drm/drm_agpsupport.h	Wed Aug 28 16:37:48 2002
@@ -29,18 +29,13 @@
  *    Gareth Hughes <gareth@valinux.com>
  */
 
-#define __NO_VERSION__
 #include "drmP.h"
 #include <linux/module.h>
 
 #if __REALLY_HAVE_AGP
 
-#if LINUX_VERSION_CODE < 0x020400
-#include "agpsupport-pre24.h"
-#else
 #define DRM_AGP_GET (drm_agp_t *)inter_module_get("drm_agp")
 #define DRM_AGP_PUT inter_module_put("drm_agp")
-#endif
 
 static const drm_agp_t *drm_agp = NULL;
 
@@ -270,35 +265,29 @@
 		case INTEL_BX:		head->chipset = "Intel 440BX";   break;
 		case INTEL_GX:		head->chipset = "Intel 440GX";   break;
 		case INTEL_I810:	head->chipset = "Intel i810";    break;
-
-#if LINUX_VERSION_CODE >= 0x020400
 		case INTEL_I815:	head->chipset = "Intel i815";	 break;
 	 	case INTEL_I820:	head->chipset = "Intel i820";	 break;
 		case INTEL_I840:	head->chipset = "Intel i840";    break;
 		case INTEL_I845:	head->chipset = "Intel i845";    break;
 		case INTEL_I850:	head->chipset = "Intel i850";	 break;
-#endif
 
 		case VIA_GENERIC:	head->chipset = "VIA";           break;
 		case VIA_VP3:		head->chipset = "VIA VP3";       break;
 		case VIA_MVP3:		head->chipset = "VIA MVP3";      break;
-#if LINUX_VERSION_CODE >= 0x020400
 		case VIA_MVP4:		head->chipset = "VIA MVP4";      break;
 		case VIA_APOLLO_KX133:	head->chipset = "VIA Apollo KX133";
 			break;
 		case VIA_APOLLO_KT133:	head->chipset = "VIA Apollo KT133";
 			break;
-#endif
-
 		case VIA_APOLLO_PRO: 	head->chipset = "VIA Apollo Pro";
 			break;
+
 		case SIS_GENERIC:	head->chipset = "SiS";           break;
 		case AMD_GENERIC:	head->chipset = "AMD";           break;
 		case AMD_IRONGATE:	head->chipset = "AMD Irongate";  break;
 		case ALI_GENERIC:	head->chipset = "ALi";           break;
 		case ALI_M1541: 	head->chipset = "ALi M1541";     break;
 
-#if LINUX_VERSION_CODE >= 0x020402
 		case ALI_M1621: 	head->chipset = "ALi M1621";	 break;
 		case ALI_M1631: 	head->chipset = "ALi M1631";	 break;
 		case ALI_M1632: 	head->chipset = "ALi M1632";	 break;
@@ -306,28 +295,21 @@
 		case ALI_M1644: 	head->chipset = "ALi M1644";	 break;
 		case ALI_M1647: 	head->chipset = "ALi M1647";	 break;
 		case ALI_M1651: 	head->chipset = "ALi M1651";	 break;
-#endif
 
-#if LINUX_VERSION_CODE >= 0x020406
 		case SVWRKS_HE: 	head->chipset = "Serverworks HE";
 			break;
 		case SVWRKS_LE: 	head->chipset = "Serverworks LE";
 			break;
 		case SVWRKS_GENERIC: 	head->chipset = "Serverworks Generic";
 			break;
-#endif
 
 		case HP_ZX1:		head->chipset = "HP ZX1";	 break;
 
 		default:		head->chipset = "Unknown";       break;
 		}
-#if LINUX_VERSION_CODE <= 0x020408
-		head->cant_use_aperture = 0;
-		head->page_mask = ~(0xfff);
-#else
+
 		head->cant_use_aperture = head->agp_info.cant_use_aperture;
 		head->page_mask = head->agp_info.page_mask;
-#endif
 
 		DRM_INFO("AGP %d.%d on %s @ 0x%08lx %ZuMB\n",
 			 head->agp_info.version.major,
diff -urN linux-2.4.20-pre4/drivers/char/drm/drm_auth.h linux-2.4.20-pre5/drivers/char/drm/drm_auth.h
--- linux-2.4.20-pre4/drivers/char/drm/drm_auth.h	Thu Nov 22 11:46:37 2001
+++ linux-2.4.20-pre5/drivers/char/drm/drm_auth.h	Wed Aug 28 16:37:48 2002
@@ -29,7 +29,6 @@
  *    Gareth Hughes <gareth@valinux.com>
  */
 
-#define __NO_VERSION__
 #include "drmP.h"
 
 static int DRM(hash_magic)(drm_magic_t magic)
diff -urN linux-2.4.20-pre4/drivers/char/drm/drm_bufs.h linux-2.4.20-pre5/drivers/char/drm/drm_bufs.h
--- linux-2.4.20-pre4/drivers/char/drm/drm_bufs.h	Thu Nov 22 11:46:37 2001
+++ linux-2.4.20-pre5/drivers/char/drm/drm_bufs.h	Wed Aug 28 16:37:48 2002
@@ -29,7 +29,6 @@
  *    Gareth Hughes <gareth@valinux.com>
  */
 
-#define __NO_VERSION__
 #include <linux/vmalloc.h>
 #include "drmP.h"
 
@@ -229,11 +228,7 @@
 	DRM(free)(list, sizeof(*list), DRM_MEM_MAPS);
 
 	for (pt = dev->vmalist, prev = NULL; pt; prev = pt, pt = pt->next) {
-#if LINUX_VERSION_CODE >= 0x020300
 		if (pt->vma->vm_private_data == map) found_maps++;
-#else
-		if (pt->vma->vm_pte == map) found_maps++;
-#endif
 	}
 
 	if(!found_maps) {
@@ -1063,34 +1058,18 @@
 				goto done;
 			}
 
-#if LINUX_VERSION_CODE <= 0x020402
-			down( &current->mm->mmap_sem );
-#else
 			down_write( &current->mm->mmap_sem );
-#endif
 			virtual = do_mmap( filp, 0, map->size,
 					   PROT_READ | PROT_WRITE,
 					   MAP_SHARED,
 					   (unsigned long)map->offset );
-#if LINUX_VERSION_CODE <= 0x020402
-			up( &current->mm->mmap_sem );
-#else
 			up_write( &current->mm->mmap_sem );
-#endif
 		} else {
-#if LINUX_VERSION_CODE <= 0x020402
-			down( &current->mm->mmap_sem );
-#else
 			down_write( &current->mm->mmap_sem );
-#endif
 			virtual = do_mmap( filp, 0, dma->byte_count,
 					   PROT_READ | PROT_WRITE,
 					   MAP_SHARED, 0 );
-#if LINUX_VERSION_CODE <= 0x020402
-			up( &current->mm->mmap_sem );
-#else
 			up_write( &current->mm->mmap_sem );
-#endif
 		}
 		if ( virtual > -1024UL ) {
 			/* Real error */
diff -urN linux-2.4.20-pre4/drivers/char/drm/drm_context.h linux-2.4.20-pre5/drivers/char/drm/drm_context.h
--- linux-2.4.20-pre4/drivers/char/drm/drm_context.h	Fri Dec 21 09:41:53 2001
+++ linux-2.4.20-pre5/drivers/char/drm/drm_context.h	Wed Aug 28 16:37:48 2002
@@ -33,7 +33,6 @@
  *		needed by SiS driver's memory management.
  */
 
-#define __NO_VERSION__
 #include "drmP.h"
 
 #if __HAVE_CTX_BITMAP
diff -urN linux-2.4.20-pre4/drivers/char/drm/drm_dma.h linux-2.4.20-pre5/drivers/char/drm/drm_dma.h
--- linux-2.4.20-pre4/drivers/char/drm/drm_dma.h	Thu Nov 22 11:46:37 2001
+++ linux-2.4.20-pre5/drivers/char/drm/drm_dma.h	Wed Aug 28 16:37:48 2002
@@ -29,7 +29,6 @@
  *    Gareth Hughes <gareth@valinux.com>
  */
 
-#define __NO_VERSION__
 #include "drmP.h"
 
 #include <linux/interrupt.h>	/* For task queue support */
diff -urN linux-2.4.20-pre4/drivers/char/drm/drm_drawable.h linux-2.4.20-pre5/drivers/char/drm/drm_drawable.h
--- linux-2.4.20-pre4/drivers/char/drm/drm_drawable.h	Thu Nov 22 11:46:37 2001
+++ linux-2.4.20-pre5/drivers/char/drm/drm_drawable.h	Wed Aug 28 16:37:48 2002
@@ -29,7 +29,6 @@
  *    Gareth Hughes <gareth@valinux.com>
  */
 
-#define __NO_VERSION__
 #include "drmP.h"
 
 int DRM(adddraw)(struct inode *inode, struct file *filp,
diff -urN linux-2.4.20-pre4/drivers/char/drm/drm_drv.h linux-2.4.20-pre5/drivers/char/drm/drm_drv.h
--- linux-2.4.20-pre4/drivers/char/drm/drm_drv.h	Sun Oct 21 10:40:36 2001
+++ linux-2.4.20-pre5/drivers/char/drm/drm_drv.h	Wed Aug 28 16:37:48 2002
@@ -113,7 +113,6 @@
 #define DRIVER_IOCTLS
 #endif
 #ifndef DRIVER_FOPS
-#if LINUX_VERSION_CODE >= 0x020400
 #define DRIVER_FOPS				\
 static struct file_operations	DRM(fops) = {	\
 	owner:   THIS_MODULE,			\
@@ -126,19 +125,6 @@
 	fasync:	 DRM(fasync),			\
 	poll:	 DRM(poll),			\
 }
-#else
-#define DRIVER_FOPS				\
-static struct file_operations	DRM(fops) = {	\
-	open:	 DRM(open),			\
-	flush:	 DRM(flush),			\
-	release: DRM(release),			\
-	ioctl:	 DRM(ioctl),			\
-	mmap:	 DRM(mmap),			\
-	read:	 DRM(read),			\
-	fasync:	 DRM(fasync),			\
-	poll:	 DRM(poll),			\
-}
-#endif
 #endif
 
 
@@ -732,9 +718,6 @@
 
 	retcode = DRM(open_helper)( inode, filp, dev );
 	if ( !retcode ) {
-#if LINUX_VERSION_CODE < 0x020333
-		MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */
-#endif
 		atomic_inc( &dev->counts[_DRM_STAT_OPENS] );
 		spin_lock( &dev->count_lock );
 		if ( !dev->open_count++ ) {
@@ -853,9 +836,6 @@
 	 * End inline drm_release
 	 */
 
-#if LINUX_VERSION_CODE < 0x020333
-	MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */
-#endif
 	atomic_inc( &dev->counts[_DRM_STAT_CLOSES] );
 	spin_lock( &dev->count_lock );
 	if ( !--dev->open_count ) {
@@ -1047,25 +1027,6 @@
 
 	atomic_inc( &dev->counts[_DRM_STAT_UNLOCKS] );
 
-#if __HAVE_KERNEL_CTX_SWITCH
-	/* We no longer really hold it, but if we are the next
-	 * agent to request it then we should just be able to
-	 * take it immediately and not eat the ioctl.
-	 */
-	dev->lock.pid = 0;
-	{
-		__volatile__ unsigned int *plock = &dev->lock.hw_lock->lock;
-		unsigned int old, new, prev, ctx;
-
-		ctx = lock.context;
-		do {
-			old  = *plock;
-			new  = ctx;
-			prev = cmpxchg(plock, old, new);
-		} while (prev != old);
-	}
-	wake_up_interruptible(&dev->lock.lock_queue);
-#else
 	DRM(lock_transfer)( dev, &dev->lock.hw_lock->lock,
 			    DRM_KERNEL_CONTEXT );
 #if __HAVE_DMA_SCHEDULE
@@ -1080,7 +1041,6 @@
 			DRM_ERROR( "\n" );
 		}
 	}
-#endif /* !__HAVE_KERNEL_CTX_SWITCH */
 
 	unblock_all_signals();
 	return 0;
diff -urN linux-2.4.20-pre4/drivers/char/drm/drm_fops.h linux-2.4.20-pre5/drivers/char/drm/drm_fops.h
--- linux-2.4.20-pre4/drivers/char/drm/drm_fops.h	Thu Nov 22 11:46:37 2001
+++ linux-2.4.20-pre5/drivers/char/drm/drm_fops.h	Wed Aug 28 16:37:48 2002
@@ -30,7 +30,6 @@
  *    Gareth Hughes <gareth@valinux.com>
  */
 
-#define __NO_VERSION__
 #include "drmP.h"
 #include <linux/poll.h>
 
@@ -97,6 +96,23 @@
 
 	DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n",
 		  current->pid, dev->device, dev->open_count);
+	if ( dev->lock.hw_lock &&
+	     _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) &&
+	     dev->lock.pid == current->pid ) {
+		DRM_DEBUG( "Process %d closed fd, freeing lock for context %d\n",
+			   current->pid,
+			   _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock) );
+#if __HAVE_RELEASE
+		DRIVER_RELEASE();
+#endif
+		DRM(lock_free)( dev, &dev->lock.hw_lock->lock,
+				_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock) );
+
+				/* FIXME: may require heavy-handed reset of
+                                   hardware at this point, possibly
+                                   processed via a callback to the X
+                                   server. */
+	}
 	return 0;
 }
 
@@ -125,21 +141,31 @@
 	int	      avail;
 	int	      send;
 	int	      cur;
+	DECLARE_WAITQUEUE(wait, current);
 
 	DRM_DEBUG("%p, %p\n", dev->buf_rp, dev->buf_wp);
 
+	add_wait_queue(&dev->buf_readers, &wait);
+	set_current_state(TASK_INTERRUPTIBLE);
 	while (dev->buf_rp == dev->buf_wp) {
 		DRM_DEBUG("  sleeping\n");
 		if (filp->f_flags & O_NONBLOCK) {
+			remove_wait_queue(&dev->buf_readers, &wait);
+			set_current_state(TASK_RUNNING);
 			return -EAGAIN;
 		}
-		interruptible_sleep_on(&dev->buf_readers);
+		schedule(); /* wait for dev->buf_readers */
 		if (signal_pending(current)) {
 			DRM_DEBUG("  interrupted\n");
+			remove_wait_queue(&dev->buf_readers, &wait);
+			set_current_state(TASK_RUNNING);
 			return -ERESTARTSYS;
 		}
 		DRM_DEBUG("  awake\n");
+		set_current_state(TASK_INTERRUPTIBLE);
 	}
+	remove_wait_queue(&dev->buf_readers, &wait);
+	set_current_state(TASK_RUNNING);
 
 	left  = (dev->buf_rp + DRM_BSZ - dev->buf_wp) % DRM_BSZ;
 	avail = DRM_BSZ - left;
@@ -191,24 +217,8 @@
 		send -= count;
 	}
 
-#if LINUX_VERSION_CODE < 0x020315 && !defined(KILLFASYNCHASTHREEPARAMETERS)
-	/* The extra parameter to kill_fasync was added in 2.3.21, and is
-           _not_ present in _stock_ 2.2.14 and 2.2.15.  However, some
-           distributions patch 2.2.x kernels to add this parameter.  The
-           Makefile.linux attempts to detect this addition and defines
-           KILLFASYNCHASTHREEPARAMETERS if three parameters are found. */
-	if (dev->buf_async) kill_fasync(dev->buf_async, SIGIO);
-#else
-
-				/* Parameter added in 2.3.21. */
-#if LINUX_VERSION_CODE < 0x020400
-	if (dev->buf_async) kill_fasync(dev->buf_async, SIGIO, POLL_IN);
-#else
-				/* Type of first parameter changed in
-                                   Linux 2.4.0-test2... */
 	if (dev->buf_async) kill_fasync(&dev->buf_async, SIGIO, POLL_IN);
-#endif
-#endif
+
 	DRM_DEBUG("waking\n");
 	wake_up_interruptible(&dev->buf_readers);
 	return 0;
diff -urN linux-2.4.20-pre4/drivers/char/drm/drm_init.h linux-2.4.20-pre5/drivers/char/drm/drm_init.h
--- linux-2.4.20-pre4/drivers/char/drm/drm_init.h	Thu Nov 22 11:46:37 2001
+++ linux-2.4.20-pre5/drivers/char/drm/drm_init.h	Wed Aug 28 16:37:48 2002
@@ -29,7 +29,6 @@
  *    Gareth Hughes <gareth@valinux.com>
  */
 
-#define __NO_VERSION__
 #include "drmP.h"
 
 #if 0
diff -urN linux-2.4.20-pre4/drivers/char/drm/drm_ioctl.h linux-2.4.20-pre5/drivers/char/drm/drm_ioctl.h
--- linux-2.4.20-pre4/drivers/char/drm/drm_ioctl.h	Thu Nov 22 11:46:37 2001
+++ linux-2.4.20-pre5/drivers/char/drm/drm_ioctl.h	Wed Aug 28 16:37:48 2002
@@ -29,7 +29,6 @@
  *    Gareth Hughes <gareth@valinux.com>
  */
 
-#define __NO_VERSION__
 #include "drmP.h"
 
 int DRM(irq_busid)(struct inode *inode, struct file *filp,
diff -urN linux-2.4.20-pre4/drivers/char/drm/drm_lists.h linux-2.4.20-pre5/drivers/char/drm/drm_lists.h
--- linux-2.4.20-pre4/drivers/char/drm/drm_lists.h	Wed Aug  8 09:42:14 2001
+++ linux-2.4.20-pre5/drivers/char/drm/drm_lists.h	Wed Aug 28 16:37:48 2002
@@ -29,7 +29,6 @@
  *    Gareth Hughes <gareth@valinux.com>
  */
 
-#define __NO_VERSION__
 #include "drmP.h"
 
 #if __HAVE_DMA_WAITLIST
diff -urN linux-2.4.20-pre4/drivers/char/drm/drm_lock.h linux-2.4.20-pre5/drivers/char/drm/drm_lock.h
--- linux-2.4.20-pre4/drivers/char/drm/drm_lock.h	Thu Nov 22 11:46:37 2001
+++ linux-2.4.20-pre5/drivers/char/drm/drm_lock.h	Wed Aug 28 16:37:48 2002
@@ -29,7 +29,6 @@
  *    Gareth Hughes <gareth@valinux.com>
  */
 
-#define __NO_VERSION__
 #include "drmP.h"
 
 int DRM(block)(struct inode *inode, struct file *filp, unsigned int cmd,
diff -urN linux-2.4.20-pre4/drivers/char/drm/drm_memory.h linux-2.4.20-pre5/drivers/char/drm/drm_memory.h
--- linux-2.4.20-pre4/drivers/char/drm/drm_memory.h	Thu Nov 22 11:46:37 2001
+++ linux-2.4.20-pre5/drivers/char/drm/drm_memory.h	Wed Aug 28 16:37:48 2002
@@ -29,7 +29,6 @@
  *    Gareth Hughes <gareth@valinux.com>
  */
 
-#define __NO_VERSION__
 #include <linux/config.h>
 #include "drmP.h"
 #include <linux/wrapper.h>
@@ -85,12 +84,7 @@
 	}
 
 	si_meminfo(&si);
-#if LINUX_VERSION_CODE < 0x020317
-				/* Changed to page count in 2.3.23 */
-	DRM(ram_available) = si.totalram >> PAGE_SHIFT;
-#else
 	DRM(ram_available) = si.totalram;
-#endif
 	DRM(ram_used)	   = 0;
 }
 
@@ -257,12 +251,7 @@
 	for (addr = address, sz = bytes;
 	     sz > 0;
 	     addr += PAGE_SIZE, sz -= PAGE_SIZE) {
-#if LINUX_VERSION_CODE >= 0x020400
-				/* Argument type changed in 2.4.0-test6/pre8 */
 		mem_map_reserve(virt_to_page(addr));
-#else
-		mem_map_reserve(MAP_NR(addr));
-#endif
 	}
 
 	return address;
@@ -283,12 +272,7 @@
 		for (addr = address, sz = bytes;
 		     sz > 0;
 		     addr += PAGE_SIZE, sz -= PAGE_SIZE) {
-#if LINUX_VERSION_CODE >= 0x020400
-				/* Argument type changed in 2.4.0-test6/pre8 */
 			mem_map_unreserve(virt_to_page(addr));
-#else
-			mem_map_unreserve(MAP_NR(addr));
-#endif
 		}
 		free_pages(address, order);
 	}
diff -urN linux-2.4.20-pre4/drivers/char/drm/drm_proc.h linux-2.4.20-pre5/drivers/char/drm/drm_proc.h
--- linux-2.4.20-pre4/drivers/char/drm/drm_proc.h	Thu Nov 22 11:46:37 2001
+++ linux-2.4.20-pre5/drivers/char/drm/drm_proc.h	Wed Aug 28 16:37:48 2002
@@ -33,7 +33,6 @@
  *    the problem with the proc files not outputting all their information.
  */
 
-#define __NO_VERSION__
 #include "drmP.h"
 
 static int	   DRM(name_info)(char *buf, char **start, off_t offset,
diff -urN linux-2.4.20-pre4/drivers/char/drm/drm_scatter.h linux-2.4.20-pre5/drivers/char/drm/drm_scatter.h
--- linux-2.4.20-pre4/drivers/char/drm/drm_scatter.h	Thu Nov 22 11:46:37 2001
+++ linux-2.4.20-pre5/drivers/char/drm/drm_scatter.h	Wed Aug 28 16:37:48 2002
@@ -27,7 +27,6 @@
  *   Gareth Hughes <gareth@valinux.com>
  */
 
-#define __NO_VERSION__
 #include <linux/config.h>
 #include <linux/vmalloc.h>
 #include "drmP.h"
@@ -66,9 +65,6 @@
 	drm_scatter_gather_t request;
 	drm_sg_mem_t *entry;
 	unsigned long pages, i, j;
-	pgd_t *pgd;
-	pmd_t *pmd;
-	pte_t *pte;
 
 	DRM_DEBUG( "%s\n", __FUNCTION__ );
 
@@ -135,21 +131,10 @@
 	DRM_DEBUG( "sg alloc virtual = %p\n", entry->virtual );
 
 	for ( i = entry->handle, j = 0 ; j < pages ; i += PAGE_SIZE, j++ ) {
-		pgd = pgd_offset_k( i );
-		if ( !pgd_present( *pgd ) )
+		entry->pagelist[j] = vmalloc_to_page((void *)i);
+		if (!entry->pagelist[j])
 			goto failed;
-
-		pmd = pmd_offset( pgd, i );
-		if ( !pmd_present( *pmd ) )
-			goto failed;
-
-		pte = pte_offset( pmd, i );
-		if ( !pte_present( *pte ) )
-			goto failed;
-
-		entry->pagelist[j] = pte_page( *pte );
-
-		SetPageReserved( entry->pagelist[j] );
+		SetPageReserved(entry->pagelist[j]);
 	}
 
 	request.handle = entry->handle;
diff -urN linux-2.4.20-pre4/drivers/char/drm/drm_stub.h linux-2.4.20-pre5/drivers/char/drm/drm_stub.h
--- linux-2.4.20-pre4/drivers/char/drm/drm_stub.h	Thu Nov 22 11:46:37 2001
+++ linux-2.4.20-pre5/drivers/char/drm/drm_stub.h	Wed Aug 28 16:37:48 2002
@@ -28,13 +28,8 @@
  *
  */
 
-#define __NO_VERSION__
 #include "drmP.h"
 
-#if LINUX_VERSION_CODE < 0x020400
-#include "stubsupport-pre24.h"
-#endif
-
 #define DRM_STUB_MAXCARDS 16	/* Enough for one machine */
 
 static struct drm_stub_list {
@@ -70,9 +65,7 @@
 }
 
 static struct file_operations DRM(stub_fops) = {
-#if LINUX_VERSION_CODE >= 0x020400
 	owner:   THIS_MODULE,
-#endif
 	open:	 DRM(stub_open)
 };
 
diff -urN linux-2.4.20-pre4/drivers/char/drm/drm_vm.h linux-2.4.20-pre5/drivers/char/drm/drm_vm.h
--- linux-2.4.20-pre4/drivers/char/drm/drm_vm.h	Thu Nov 22 11:46:37 2001
+++ linux-2.4.20-pre5/drivers/char/drm/drm_vm.h	Wed Aug 28 16:37:48 2002
@@ -29,7 +29,6 @@
  *    Gareth Hughes <gareth@valinux.com>
  */
 
-#define __NO_VERSION__
 #include "drmP.h"
 
 struct vm_operations_struct   DRM(vm_ops) = {
@@ -56,16 +55,9 @@
 	close:   DRM(vm_close),
 };
 
-#if LINUX_VERSION_CODE < 0x020317
-unsigned long DRM(vm_nopage)(struct vm_area_struct *vma,
-			     unsigned long address,
-			     int unused)
-#else
-				/* Return type changed in 2.3.23 */
 struct page *DRM(vm_nopage)(struct vm_area_struct *vma,
 			    unsigned long address,
 			    int unused)
-#endif
 {
 #if __REALLY_HAVE_AGP
 	drm_file_t *priv  = vma->vm_file->private_data;
@@ -122,11 +114,7 @@
 		DRM_DEBUG("baddr = 0x%lx page = 0x%p, offset = 0x%lx\n",
 			  baddr, __va(agpmem->memory->memory[offset]), offset);
 
-#if LINUX_VERSION_CODE < 0x020317
-		return page_address(page);
-#else
 		return page;
-#endif
         }
 vm_nopage_error:
 #endif /* __REALLY_HAVE_AGP */
@@ -134,27 +122,13 @@
 	return NOPAGE_SIGBUS;		/* Disallow mremap */
 }
 
-#if LINUX_VERSION_CODE < 0x020317
-unsigned long DRM(vm_shm_nopage)(struct vm_area_struct *vma,
-				 unsigned long address,
-				 int unused)
-#else
-				/* Return type changed in 2.3.23 */
 struct page *DRM(vm_shm_nopage)(struct vm_area_struct *vma,
 				unsigned long address,
-				int unused)
-#endif
+				int write_access)
 {
-#if LINUX_VERSION_CODE >= 0x020300
 	drm_map_t	 *map	 = (drm_map_t *)vma->vm_private_data;
-#else
-	drm_map_t	 *map	 = (drm_map_t *)vma->vm_pte;
-#endif
 	unsigned long	 offset;
 	unsigned long	 i;
-	pgd_t		 *pgd;
-	pmd_t		 *pmd;
-	pte_t		 *pte;
 	struct page	 *page;
 
 	if (address > vma->vm_end) return NOPAGE_SIGBUS; /* Disallow mremap */
@@ -162,25 +136,13 @@
 
 	offset	 = address - vma->vm_start;
 	i = (unsigned long)map->handle + offset;
-	/* We have to walk page tables here because we need large SAREA's, and
-	 * they need to be virtually contiguous in kernel space.
-	 */
-	pgd = pgd_offset_k( i );
-	if( !pgd_present( *pgd ) ) return NOPAGE_OOM;
-	pmd = pmd_offset( pgd, i );
-	if( !pmd_present( *pmd ) ) return NOPAGE_OOM;
-	pte = pte_offset( pmd, i );
-	if( !pte_present( *pte ) ) return NOPAGE_OOM;
-
-	page = pte_page(*pte);
+	page = vmalloc_to_page((void *)i);
+	if (!page)
+		return NOPAGE_OOM;
 	get_page(page);
 
-	DRM_DEBUG("shm_nopage 0x%lx\n", address);
-#if LINUX_VERSION_CODE < 0x020317
-	return page_address(page);
-#else
+	DRM_DEBUG("0x%08lx => 0x%08llx\n", address, (u64)page_to_bus(page));
 	return page;
-#endif
 }
 
 /* Special close routine which deletes map information if we are the last
@@ -199,25 +161,14 @@
 
 	DRM_DEBUG("0x%08lx,0x%08lx\n",
 		  vma->vm_start, vma->vm_end - vma->vm_start);
-#if LINUX_VERSION_CODE < 0x020333
-	MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */
-#endif
 	atomic_dec(&dev->vma_count);
 
-#if LINUX_VERSION_CODE >= 0x020300
 	map = vma->vm_private_data;
-#else
-	map = vma->vm_pte;
-#endif
 
 	down(&dev->struct_sem);
 	for (pt = dev->vmalist, prev = NULL; pt; pt = next) {
 		next = pt->next;
-#if LINUX_VERSION_CODE >= 0x020300
 		if (pt->vma->vm_private_data == map) found_maps++;
-#else
-		if (pt->vma->vm_pte == map) found_maps++;
-#endif
 		if (pt->vma == vma) {
 			if (prev) {
 				prev->next = pt->next;
@@ -270,16 +221,9 @@
 	up(&dev->struct_sem);
 }
 
-#if LINUX_VERSION_CODE < 0x020317
-unsigned long DRM(vm_dma_nopage)(struct vm_area_struct *vma,
-				 unsigned long address,
-				 int unused)
-#else
-				/* Return type changed in 2.3.23 */
 struct page *DRM(vm_dma_nopage)(struct vm_area_struct *vma,
 				unsigned long address,
-				int unused)
-#endif
+				int write_access)
 {
 	drm_file_t	 *priv	 = vma->vm_file->private_data;
 	drm_device_t	 *dev	 = priv->dev;
@@ -299,30 +243,16 @@
 
 	get_page(page);
 
-	DRM_DEBUG("dma_nopage 0x%lx (page %lu)\n", address, page_nr); 
-#if LINUX_VERSION_CODE < 0x020317
-	return page_address(page);
-#else
+	DRM_DEBUG("0x%08lx (page %lu) => 0x%08llx\n", address, page_nr, 
+		  (u64)page_to_bus(page));
 	return page;
-#endif
 }
 
-#if LINUX_VERSION_CODE < 0x020317
-unsigned long DRM(vm_sg_nopage)(struct vm_area_struct *vma,
-				unsigned long address,
-				int unused)
-#else
-				/* Return type changed in 2.3.23 */
 struct page *DRM(vm_sg_nopage)(struct vm_area_struct *vma,
 			       unsigned long address,
-			       int unused)
-#endif
+			       int write_access)
 {
-#if LINUX_VERSION_CODE >= 0x020300
 	drm_map_t        *map    = (drm_map_t *)vma->vm_private_data;
-#else
-	drm_map_t        *map    = (drm_map_t *)vma->vm_pte;
-#endif
 	drm_file_t *priv = vma->vm_file->private_data;
 	drm_device_t *dev = priv->dev;
 	drm_sg_mem_t *entry = dev->sg;
@@ -342,11 +272,7 @@
 	page = entry->pagelist[page_offset];
 	get_page(page);
 
-#if LINUX_VERSION_CODE < 0x020317
-	return page_address(page);
-#else
 	return page;
-#endif
 }
 
 void DRM(vm_open)(struct vm_area_struct *vma)
@@ -358,10 +284,6 @@
 	DRM_DEBUG("0x%08lx,0x%08lx\n",
 		  vma->vm_start, vma->vm_end - vma->vm_start);
 	atomic_inc(&dev->vma_count);
-#if LINUX_VERSION_CODE < 0x020333
-				/* The map can exist after the fd is closed. */
-	MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */
-#endif
 
 	vma_entry = DRM(alloc)(sizeof(*vma_entry), DRM_MEM_VMAS);
 	if (vma_entry) {
@@ -382,9 +304,6 @@
 
 	DRM_DEBUG("0x%08lx,0x%08lx\n",
 		  vma->vm_start, vma->vm_end - vma->vm_start);
-#if LINUX_VERSION_CODE < 0x020333
-	MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */
-#endif
 	atomic_dec(&dev->vma_count);
 
 	down(&dev->struct_sem);
@@ -424,12 +343,6 @@
 
 	vma->vm_ops   = &DRM(vm_dma_ops);
 	vma->vm_flags |= VM_RESERVED; /* Don't swap */
-
-#if LINUX_VERSION_CODE < 0x020203 /* KERNEL_VERSION(2,2,3) */
-				/* In Linux 2.2.3 and above, this is
-				   handled in do_mmap() in mm/mmap.c. */
-	++filp->f_count;
-#endif
 	vma->vm_file  =	 filp;	/* Needed for drm_vm_open() */
 	DRM(vm_open)(vma);
 	return 0;
@@ -551,34 +464,19 @@
 		break;
 	case _DRM_SHM:
 		vma->vm_ops = &DRM(vm_shm_ops);
-#if LINUX_VERSION_CODE >= 0x020300
 		vma->vm_private_data = (void *)map;
-#else
-		vma->vm_pte = (unsigned long)map;
-#endif
 				/* Don't let this area swap.  Change when
 				   DRM_KERNEL advisory is supported. */
-		vma->vm_flags |= VM_RESERVED;
 		break;
 	case _DRM_SCATTER_GATHER:
 		vma->vm_ops = &DRM(vm_sg_ops);
-#if LINUX_VERSION_CODE >= 0x020300
 		vma->vm_private_data = (void *)map;
-#else
-		vma->vm_pte = (unsigned long)map;
-#endif
-                vma->vm_flags |= VM_RESERVED;
                 break;
 	default:
 		return -EINVAL;	/* This should never happen. */
 	}
 	vma->vm_flags |= VM_RESERVED; /* Don't swap */
 
-#if LINUX_VERSION_CODE < 0x020203 /* KERNEL_VERSION(2,2,3) */
-				/* In Linux 2.2.3 and above, this is
-				   handled in do_mmap() in mm/mmap.c. */
-	++filp->f_count;
-#endif
 	vma->vm_file  =	 filp;	/* Needed for drm_vm_open() */
 	DRM(vm_open)(vma);
 	return 0;
diff -urN linux-2.4.20-pre4/drivers/char/drm/gamma_dma.c linux-2.4.20-pre5/drivers/char/drm/gamma_dma.c
--- linux-2.4.20-pre4/drivers/char/drm/gamma_dma.c	Wed Aug  8 09:42:14 2001
+++ linux-2.4.20-pre5/drivers/char/drm/gamma_dma.c	Wed Aug 28 16:37:48 2002
@@ -29,7 +29,6 @@
  *
  */
 
-#define __NO_VERSION__
 #include "gamma.h"
 #include "drmP.h"
 #include "gamma_drv.h"
diff -urN linux-2.4.20-pre4/drivers/char/drm/i810_dma.c linux-2.4.20-pre5/drivers/char/drm/i810_dma.c
--- linux-2.4.20-pre4/drivers/char/drm/i810_dma.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/drivers/char/drm/i810_dma.c	Wed Aug 28 16:37:48 2002
@@ -30,11 +30,11 @@
  *
  */
 
-#define __NO_VERSION__
 #include "i810.h"
 #include "drmP.h"
 #include "i810_drv.h"
 #include <linux/interrupt.h>	/* For task queue support */
+#include <linux/module.h>
 
 /* in case we don't have a 2.3.99-pre6 kernel or later: */
 #ifndef VM_DONTCOPY
@@ -73,7 +73,7 @@
 	*(volatile unsigned int *)(virt + outring) = n;			\
 	outring += 4;							\
 	outring &= ringmask;						\
-} while (0);
+} while (0)
 
 static inline void i810_print_status_page(drm_device_t *dev)
 {
@@ -86,6 +86,7 @@
    	DRM_DEBUG(  "hw_status: LpRing Head ptr : %x\n", temp[1]);
    	DRM_DEBUG(  "hw_status: IRing Head ptr : %x\n", temp[2]);
       	DRM_DEBUG(  "hw_status: Reserved : %x\n", temp[3]);
+	DRM_DEBUG(  "hw_status: Last Render: %x\n", temp[4]);
    	DRM_DEBUG(  "hw_status: Driver Counter : %d\n", temp[5]);
    	for(i = 6; i < dma->buf_count + 6; i++) {
 	   	DRM_DEBUG( "buffer status idx : %d used: %d\n", i - 6, temp[i]);
@@ -182,11 +183,7 @@
 	if(buf_priv->currently_mapped == I810_BUF_MAPPED) return -EINVAL;
 
 	if(VM_DONTCOPY != 0) {
-#if LINUX_VERSION_CODE <= 0x020402
-		down( &current->mm->mmap_sem );
-#else
 		down_write( &current->mm->mmap_sem );
-#endif
 		old_fops = filp->f_op;
 		filp->f_op = &i810_buffer_fops;
 		dev_priv->mmap_buffer = buf;
@@ -202,11 +199,7 @@
 			retcode = (signed int)buf_priv->virtual;
 			buf_priv->virtual = 0;
 		}
-#if LINUX_VERSION_CODE <= 0x020402
-		up( &current->mm->mmap_sem );
-#else
 		up_write( &current->mm->mmap_sem );
-#endif
 	} else {
 		buf_priv->virtual = buf_priv->kernel_virtual;
    		buf_priv->currently_mapped = I810_BUF_MAPPED;
@@ -222,24 +215,11 @@
 	if(VM_DONTCOPY != 0) {
 		if(buf_priv->currently_mapped != I810_BUF_MAPPED)
 			return -EINVAL;
-#if LINUX_VERSION_CODE <= 0x020402
-		down( &current->mm->mmap_sem );
-#else
 		down_write( &current->mm->mmap_sem );
-#endif
-#if LINUX_VERSION_CODE < 0x020399
-        	retcode = do_munmap((unsigned long)buf_priv->virtual,
-				    (size_t) buf->total);
-#else
         	retcode = do_munmap(current->mm,
 				    (unsigned long)buf_priv->virtual,
 				    (size_t) buf->total);
-#endif
-#if LINUX_VERSION_CODE <= 0x020402
-		up( &current->mm->mmap_sem );
-#else
 		up_write( &current->mm->mmap_sem );
-#endif
 	}
    	buf_priv->currently_mapped = I810_BUF_UNMAPPED;
    	buf_priv->virtual = 0;
@@ -278,30 +258,6 @@
 	return retcode;
 }
 
-static unsigned long i810_alloc_page(drm_device_t *dev)
-{
-	unsigned long address;
-
-	address = __get_free_page(GFP_KERNEL);
-	if(address == 0UL)
-		return 0;
-
-	get_page(virt_to_page(address));
-	LockPage(virt_to_page(address));
-
-	return address;
-}
-
-static void i810_free_page(drm_device_t *dev, unsigned long page)
-{
-	if (page) {
-		struct page *p = virt_to_page(page);
-		put_page(p);
-		UnlockPage(p);
-		free_page(page);
-	}
-}
-
 static int i810_dma_cleanup(drm_device_t *dev)
 {
 	drm_device_dma_t *dma = dev->dma;
@@ -316,7 +272,8 @@
 					 dev_priv->ring.Size);
 		}
 	   	if(dev_priv->hw_status_page != 0UL) {
-		   	i810_free_page(dev, dev_priv->hw_status_page);
+		   	pci_free_consistent(dev->pdev, PAGE_SIZE, (void *)dev_priv->hw_status_page,
+		   		dev_priv->dma_status_page);
 		   	/* Need to rewrite hardware status page */
 		   	I810_WRITE(0x02080, 0x1ffff000);
 		}
@@ -474,12 +431,16 @@
 	dev_priv->back_offset = init->back_offset;
 	dev_priv->depth_offset = init->depth_offset;
 
+	dev_priv->overlay_offset = init->overlay_offset;
+	dev_priv->overlay_physical = init->overlay_physical;
+
 	dev_priv->front_di1 = init->front_offset | init->pitch_bits;
 	dev_priv->back_di1 = init->back_offset | init->pitch_bits;
 	dev_priv->zi1 = init->depth_offset | init->pitch_bits;
 
    	/* Program Hardware Status Page */
-   	dev_priv->hw_status_page = i810_alloc_page(dev);
+   	dev_priv->hw_status_page = (unsigned long)pci_alloc_consistent(dev->pdev, PAGE_SIZE,
+   			&dev_priv->dma_status_page);
    	if(dev_priv->hw_status_page == 0UL) {
 		dev->dev_private = (void *)dev_priv;
 		i810_dma_cleanup(dev);
@@ -489,7 +450,7 @@
    	memset((void *) dev_priv->hw_status_page, 0, PAGE_SIZE);
    	DRM_DEBUG("hw status page @ %lx\n", dev_priv->hw_status_page);
 
-   	I810_WRITE(0x02080, virt_to_bus((void *)dev_priv->hw_status_page));
+   	I810_WRITE(0x02080, dev_priv->dma_status_page);
    	DRM_DEBUG("Enabled hardware status page\n");
 
    	/* Now we need to init our freelist */
@@ -505,6 +466,12 @@
    	return 0;
 }
 
+
+int xfreeversion = -1;
+
+MODULE_PARM(xfreeversion, "i");
+MODULE_PARM_DESC(xfreeversion, "The version of XFree86 that needs to be supported");
+
 int i810_dma_init(struct inode *inode, struct file *filp,
 		  unsigned int cmd, unsigned long arg)
 {
@@ -516,6 +483,28 @@
 
   	if (copy_from_user(&init, (drm_i810_init_t *)arg, sizeof(init)))
 		return -EFAULT;
+		
+	if ((xfreeversion == 41) ||
+	    ((xfreeversion == -1) && (init.pitch == 0))) {
+		/*
+		 * Ok we have a problem here.  Someone decided it was
+		 * funny to add two fields in the middle of the
+		 * drm_i810_init_it structure in the transition between
+		 * XFree86 4.1.0 and 4.2.0.
+		 *
+		 * The code below tries to fix this ABI breakage up as
+		 * good as possible, unfortionatly it's impossible to
+		 * autodetect which interface the user wants, hence the
+		 * module parameter -- Arjan
+		 */
+
+	 	init.pitch_bits = init.h;
+	 	init.pitch = init.w;
+	 	init.h = init.overlay_physical;
+	 	init.w = init.overlay_offset;
+	 	init.overlay_physical = 0;
+	 	init.overlay_offset = 0;
+	}
 
    	switch(init.func) {
 	 	case I810_INIT_DMA:
@@ -1262,3 +1251,156 @@
 	if(VM_DONTCOPY == 0) return 1;
 	return 0;
 }
+
+static void i810_dma_dispatch_mc(drm_device_t *dev, drm_buf_t *buf, int used,
+		unsigned int last_render)
+{
+	drm_i810_private_t *dev_priv = dev->dev_private;
+	drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+	drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	unsigned long address = (unsigned long)buf->bus_address;
+	unsigned long start = address - dev->agp->base;
+	int u;
+	RING_LOCALS;
+
+	i810_kernel_lost_context(dev);
+
+	u = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT,
+		I810_BUF_HARDWARE);
+	if(u != I810_BUF_CLIENT) {
+		DRM_DEBUG("MC found buffer that isn't mine!\n");
+	}
+
+	if (used > 4*1024)
+		used = 0;
+
+	sarea_priv->dirty = 0x7f;
+
+	DRM_DEBUG("dispatch mc addr 0x%lx, used 0x%x\n",
+		address, used);
+
+	dev_priv->counter++;
+	DRM_DEBUG("dispatch counter : %ld\n", dev_priv->counter);
+	DRM_DEBUG("i810_dma_dispatch_mc\n");
+	DRM_DEBUG("start : %lx\n", start);
+	DRM_DEBUG("used : %d\n", used);
+	DRM_DEBUG("start + used - 4 : %ld\n", start + used - 4);
+
+	if (buf_priv->currently_mapped == I810_BUF_MAPPED) {
+		if (used & 4) {
+			*(u32 *)((u32)buf_priv->virtual + used) = 0;
+			used += 4;
+		}
+
+		i810_unmap_buffer(buf);
+	}
+	BEGIN_LP_RING(4);
+	OUT_RING( CMD_OP_BATCH_BUFFER );
+	OUT_RING( start | BB1_PROTECTED );
+	OUT_RING( start + used - 4 );
+	OUT_RING( 0 );
+	ADVANCE_LP_RING();
+
+
+	BEGIN_LP_RING(8);
+	OUT_RING( CMD_STORE_DWORD_IDX );
+	OUT_RING( buf_priv->my_use_idx );
+	OUT_RING( I810_BUF_FREE );
+	OUT_RING( 0 );
+
+	OUT_RING( CMD_STORE_DWORD_IDX );
+	OUT_RING( 16 );
+	OUT_RING( last_render );
+	OUT_RING( 0 );
+	ADVANCE_LP_RING();
+}
+
+int i810_dma_mc(struct inode *inode, struct file *filp,
+	unsigned int cmd, unsigned long arg)
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_device_dma_t *dma = dev->dma;
+	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+	u32 *hw_status = (u32 *)dev_priv->hw_status_page;
+	drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
+		dev_priv->sarea_priv;
+	drm_i810_mc_t mc;
+
+	if (copy_from_user(&mc, (drm_i810_mc_t *)arg, sizeof(mc)))
+		return -EFAULT;
+
+
+	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("i810_dma_mc called without lock held\n");
+		return -EINVAL;
+	}
+
+	i810_dma_dispatch_mc(dev, dma->buflist[mc.idx], mc.used,
+		mc.last_render );
+
+	atomic_add(mc.used, &dev->counts[_DRM_STAT_SECONDARY]);
+	atomic_inc(&dev->counts[_DRM_STAT_DMA]);
+	sarea_priv->last_enqueue = dev_priv->counter-1;
+	sarea_priv->last_dispatch = (int) hw_status[5];
+
+	return 0;
+}
+
+int i810_rstatus(struct inode *inode, struct file *filp,
+		unsigned int cmd, unsigned long arg)
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+
+	return (int)(((u32 *)(dev_priv->hw_status_page))[4]);
+}
+
+int i810_ov0_info(struct inode *inode, struct file *filp,
+		unsigned int cmd, unsigned long arg)
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+	drm_i810_overlay_t data;
+
+	data.offset = dev_priv->overlay_offset;
+	data.physical = dev_priv->overlay_physical;
+	copy_to_user((drm_i810_overlay_t *)arg,&data,sizeof(data));
+	return 0;
+}
+
+int i810_fstatus(struct inode *inode, struct file *filp,
+		unsigned int cmd, unsigned long arg)
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+
+	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("i810_fstatus called without lock held\n");
+		return -EINVAL;
+	}
+	return I810_READ(0x30008);
+}
+
+int i810_ov0_flip(struct inode *inode, struct file *filp,
+		unsigned int cmd, unsigned long arg)
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+
+	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("i810_ov0_flip called without lock held\n");
+		return -EINVAL;
+	}
+
+	//Tell the overlay to update
+	I810_WRITE(0x30000,dev_priv->overlay_physical | 0x80000000);
+
+	return 0;
+}
+
+
diff -urN linux-2.4.20-pre4/drivers/char/drm/i810_drm.h linux-2.4.20-pre5/drivers/char/drm/i810_drm.h
--- linux-2.4.20-pre4/drivers/char/drm/i810_drm.h	Wed Aug  8 09:42:15 2001
+++ linux-2.4.20-pre5/drivers/char/drm/i810_drm.h	Wed Aug 28 16:37:48 2002
@@ -112,6 +112,8 @@
 	unsigned int front_offset;
 	unsigned int back_offset;
 	unsigned int depth_offset;
+	unsigned int overlay_offset;
+	unsigned int overlay_physical;
 	unsigned int w;
 	unsigned int h;
 	unsigned int pitch;
@@ -196,4 +198,18 @@
 	int granted;
 } drm_i810_dma_t;
 
+typedef struct _drm_i810_overlay_t {
+	unsigned int offset;    /* Address of the Overlay Regs */
+	unsigned int physical;
+} drm_i810_overlay_t;
+
+typedef struct _drm_i810_mc {
+	int idx;                /* buffer index */
+	int used;               /* nr bytes in use */
+	int num_blocks;         /* number of GFXBlocks */
+	int *length;            /* List of lengths for GFXBlocks (FUTURE)*/
+	unsigned int last_render; /* Last Render Request */
+} drm_i810_mc_t;
+
+
 #endif /* _I810_DRM_H_ */
diff -urN linux-2.4.20-pre4/drivers/char/drm/i810_drv.c linux-2.4.20-pre5/drivers/char/drm/i810_drv.c
--- linux-2.4.20-pre4/drivers/char/drm/i810_drv.c	Wed Aug  8 09:42:15 2001
+++ linux-2.4.20-pre5/drivers/char/drm/i810_drv.c	Wed Aug 28 16:37:48 2002
@@ -39,10 +39,10 @@
 
 #define DRIVER_NAME		"i810"
 #define DRIVER_DESC		"Intel i810"
-#define DRIVER_DATE		"20010616"
+#define DRIVER_DATE		"20010920"
 
 #define DRIVER_MAJOR		1
-#define DRIVER_MINOR		1
+#define DRIVER_MINOR		2	
 #define DRIVER_PATCHLEVEL	0
 
 #define DRIVER_IOCTLS							    \
@@ -54,7 +54,12 @@
 	[DRM_IOCTL_NR(DRM_IOCTL_I810_GETBUF)] = { i810_getbuf,      1, 0 }, \
    	[DRM_IOCTL_NR(DRM_IOCTL_I810_SWAP)]   = { i810_swap_bufs,   1, 0 }, \
    	[DRM_IOCTL_NR(DRM_IOCTL_I810_COPY)]   = { i810_copybuf,     1, 0 }, \
-   	[DRM_IOCTL_NR(DRM_IOCTL_I810_DOCOPY)] = { i810_docopy,      1, 0 },
+   	[DRM_IOCTL_NR(DRM_IOCTL_I810_DOCOPY)] = { i810_docopy,      1, 0 }, \
+	[DRM_IOCTL_NR(DRM_IOCTL_I810_OV0INFO)] = { i810_ov0_info,   1, 0 }, \
+	[DRM_IOCTL_NR(DRM_IOCTL_I810_FSTATUS)] = { i810_fstatus,    1, 0 }, \
+	[DRM_IOCTL_NR(DRM_IOCTL_I810_OV0FLIP)] = { i810_ov0_flip,   1, 0 }, \
+	[DRM_IOCTL_NR(DRM_IOCTL_I810_MC)]      = { i810_dma_mc,     1, 1 }, \
+	[DRM_IOCTL_NR(DRM_IOCTL_I810_RSTATUS)] = { i810_rstatus,    1, 0 }
 
 
 #define __HAVE_COUNTERS         4
diff -urN linux-2.4.20-pre4/drivers/char/drm/i810_drv.h linux-2.4.20-pre5/drivers/char/drm/i810_drv.h
--- linux-2.4.20-pre4/drivers/char/drm/i810_drv.h	Wed Aug  8 09:42:15 2001
+++ linux-2.4.20-pre5/drivers/char/drm/i810_drv.h	Wed Aug 28 16:37:49 2002
@@ -63,6 +63,7 @@
 
       	unsigned long hw_status_page;
    	unsigned long counter;
+   	dma_addr_t dma_status_page;
 
    	atomic_t flush_done;
    	wait_queue_head_t flush_queue;	/* Processes waiting until flush    */
@@ -73,6 +74,8 @@
 
 	int back_offset;
 	int depth_offset;
+	int overlay_offset;
+	int overlay_physical;
 	int w, h;
 	int pitch;
 } drm_i810_private_t;
@@ -94,6 +97,18 @@
 extern int i810_docopy(struct inode *inode, struct file *filp,
 		       unsigned int cmd, unsigned long arg);
 
+extern int i810_rstatus(struct inode *inode, struct file *filp,
+			unsigned int cmd, unsigned long arg);
+extern int i810_ov0_info(struct inode *inode, struct file *filp,
+			unsigned int cmd, unsigned long arg);
+extern int i810_fstatus(struct inode *inode, struct file *filp,
+			unsigned int cmd, unsigned long arg);
+extern int i810_ov0_flip(struct inode *inode, struct file *filp,
+			unsigned int cmd, unsigned long arg);
+extern int i810_dma_mc(struct inode *inode, struct file *filp,
+			unsigned int cmd, unsigned long arg);
+
+
 extern void i810_dma_quiescent(drm_device_t *dev);
 
 #define I810_VERBOSE 0
diff -urN linux-2.4.20-pre4/drivers/char/drm/i830.h linux-2.4.20-pre5/drivers/char/drm/i830.h
--- linux-2.4.20-pre4/drivers/char/drm/i830.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre5/drivers/char/drm/i830.h	Wed Aug 28 16:37:49 2002
@@ -0,0 +1,116 @@
+/* i830.h -- Intel I830 DRM template customization -*- linux-c -*-
+ * Created: Thu Feb 15 00:01:12 2001 by gareth@valinux.com
+ *
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Gareth Hughes <gareth@valinux.com>
+ */
+
+#ifndef __I830_H__
+#define __I830_H__
+
+/* This remains constant for all DRM template files.
+ */
+#define DRM(x) i830_##x
+
+/* General customization:
+ */
+#define __HAVE_AGP		1
+#define __MUST_HAVE_AGP		1
+#define __HAVE_MTRR		1
+#define __HAVE_CTX_BITMAP	1
+
+/* Driver customization:
+ */
+#define __HAVE_RELEASE		1
+#define DRIVER_RELEASE() do {						\
+	i830_reclaim_buffers( dev, priv->pid );				\
+} while (0)
+
+/* DMA customization:
+ */
+#define __HAVE_DMA		1
+#define __HAVE_DMA_QUEUE	1
+#define __HAVE_DMA_WAITLIST	1
+#define __HAVE_DMA_RECLAIM	1
+
+#define __HAVE_DMA_QUIESCENT	1
+#define DRIVER_DMA_QUIESCENT() do {					\
+	i830_dma_quiescent( dev );					\
+} while (0)
+
+#define __HAVE_DMA_IRQ		1
+#define __HAVE_DMA_IRQ_BH	1
+#define __HAVE_SHARED_IRQ       1
+#define DRIVER_PREINSTALL() do {					\
+	drm_i830_private_t *dev_priv =					\
+		(drm_i830_private_t *)dev->dev_private;			\
+	u16 tmp;							\
+   	tmp = I830_READ16( I830REG_HWSTAM );				\
+   	tmp = tmp & 0x6000;						\
+   	I830_WRITE16( I830REG_HWSTAM, tmp );				\
+									\
+      	tmp = I830_READ16( I830REG_INT_MASK_R );			\
+   	tmp = tmp & 0x6000;		/* Unmask interrupts */		\
+   	I830_WRITE16( I830REG_INT_MASK_R, tmp );			\
+   	tmp = I830_READ16( I830REG_INT_ENABLE_R );			\
+   	tmp = tmp & 0x6000;		/* Disable all interrupts */	\
+      	I830_WRITE16( I830REG_INT_ENABLE_R, tmp );			\
+} while (0)
+
+#define DRIVER_POSTINSTALL() do {					\
+	drm_i830_private_t *dev_priv =					\
+		(drm_i830_private_t *)dev->dev_private;	\
+	u16 tmp;							\
+   	tmp = I830_READ16( I830REG_INT_ENABLE_R );			\
+   	tmp = tmp & 0x6000;						\
+   	tmp = tmp | 0x0003;	/* Enable bp & user interrupts */	\
+   	I830_WRITE16( I830REG_INT_ENABLE_R, tmp );			\
+} while (0)
+
+#define DRIVER_UNINSTALL() do {						\
+	drm_i830_private_t *dev_priv =					\
+		(drm_i830_private_t *)dev->dev_private;			\
+	u16 tmp;							\
+	if ( dev_priv ) {						\
+		tmp = I830_READ16( I830REG_INT_IDENTITY_R );		\
+		tmp = tmp & ~(0x6000);	/* Clear all interrupts */	\
+		if ( tmp != 0 )						\
+			I830_WRITE16( I830REG_INT_IDENTITY_R, tmp );	\
+									\
+		tmp = I830_READ16( I830REG_INT_ENABLE_R );		\
+		tmp = tmp & 0x6000;	/* Disable all interrupts */	\
+		I830_WRITE16( I830REG_INT_ENABLE_R, tmp );		\
+	}								\
+} while (0)
+
+/* Buffer customization:
+ */
+
+#define DRIVER_BUF_PRIV_T	drm_i830_buf_priv_t
+
+#define DRIVER_AGP_BUFFERS_MAP( dev )					\
+	((drm_i830_private_t *)((dev)->dev_private))->buffer_map
+
+#endif
diff -urN linux-2.4.20-pre4/drivers/char/drm/i830_dma.c linux-2.4.20-pre5/drivers/char/drm/i830_dma.c
--- linux-2.4.20-pre4/drivers/char/drm/i830_dma.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre5/drivers/char/drm/i830_dma.c	Wed Aug 28 16:37:49 2002
@@ -0,0 +1,1369 @@
+/* i830_dma.c -- DMA support for the I830 -*- linux-c -*-
+ * Created: Mon Dec 13 01:50:01 1999 by jhartmann@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
+ *	    Jeff Hartmann <jhartmann@valinux.com>
+ *      Keith Whitwell <keithw@valinux.com>
+ *      Abraham vd Merwe <abraham@2d3d.co.za>
+ *
+ */
+
+#include "i830.h"
+#include "drmP.h"
+#include "i830_drv.h"
+#include <linux/interrupt.h>	/* For task queue support */
+#include <linux/delay.h>
+/* in case we don't have a 2.3.99-pre6 kernel or later: */
+#ifndef VM_DONTCOPY
+#define VM_DONTCOPY 0
+#endif
+
+#define I830_BUF_FREE		2
+#define I830_BUF_CLIENT		1
+#define I830_BUF_HARDWARE      	0
+
+#define I830_BUF_UNMAPPED 0
+#define I830_BUF_MAPPED   1
+
+#define RING_LOCALS	unsigned int outring, ringmask; volatile char *virt;
+
+
+#define DO_IDLE_WORKAROUND()					\
+do {								\
+   int _head;							\
+   int _tail;							\
+   do { 							\
+      _head = I830_READ(LP_RING + RING_HEAD) & HEAD_ADDR;	\
+      _tail = I830_READ(LP_RING + RING_TAIL) & TAIL_ADDR;	\
+      udelay(1);						\
+   } while(_head != _tail);					\
+} while(0)
+
+#define I830_SYNC_WORKAROUND 0
+
+#define BEGIN_LP_RING(n) do {				\
+	if (I830_VERBOSE)				\
+		DRM_DEBUG("BEGIN_LP_RING(%d) in %s\n",	\
+			  n, __FUNCTION__);		\
+	if (I830_SYNC_WORKAROUND)			\
+		DO_IDLE_WORKAROUND();			\
+	if (dev_priv->ring.space < n*4) 		\
+		i830_wait_ring(dev, n*4);		\
+	dev_priv->ring.space -= n*4;			\
+	outring = dev_priv->ring.tail;			\
+	ringmask = dev_priv->ring.tail_mask;		\
+	virt = dev_priv->ring.virtual_start;		\
+} while (0)
+
+#define ADVANCE_LP_RING() do {					\
+	if (I830_VERBOSE) DRM_DEBUG("ADVANCE_LP_RING\n");	\
+	dev_priv->ring.tail = outring;				\
+	I830_WRITE(LP_RING + RING_TAIL, outring);		\
+} while(0)
+
+#define OUT_RING(n) do {						\
+	if (I830_VERBOSE) DRM_DEBUG("   OUT_RING %x\n", (int)(n));	\
+	*(volatile unsigned int *)(virt + outring) = n;			\
+	outring += 4;							\
+	outring &= ringmask;						\
+} while (0);
+
+static inline void i830_print_status_page(drm_device_t *dev)
+{
+   	drm_device_dma_t *dma = dev->dma;
+      	drm_i830_private_t *dev_priv = dev->dev_private;
+	u8 *temp = dev_priv->hw_status_page;
+   	int i;
+
+   	DRM_DEBUG(  "hw_status: Interrupt Status : %x\n", temp[0]);
+   	DRM_DEBUG(  "hw_status: LpRing Head ptr : %x\n", temp[1]);
+   	DRM_DEBUG(  "hw_status: IRing Head ptr : %x\n", temp[2]);
+      	DRM_DEBUG(  "hw_status: Reserved : %x\n", temp[3]);
+   	DRM_DEBUG(  "hw_status: Driver Counter : %d\n", temp[5]);
+   	for(i = 9; i < dma->buf_count + 9; i++) {
+	   	DRM_DEBUG( "buffer status idx : %d used: %d\n", i - 9, temp[i]);
+	}
+}
+
+static drm_buf_t *i830_freelist_get(drm_device_t *dev)
+{
+   	drm_device_dma_t *dma = dev->dma;
+	int		 i;
+   	int 		 used;
+   
+	/* Linear search might not be the best solution */
+
+   	for (i = 0; i < dma->buf_count; i++) {
+	   	drm_buf_t *buf = dma->buflist[ i ];
+	   	drm_i830_buf_priv_t *buf_priv = buf->dev_private;
+		/* In use is already a pointer */
+	   	used = cmpxchg(buf_priv->in_use, I830_BUF_FREE, 
+			       I830_BUF_CLIENT);
+	   	if(used == I830_BUF_FREE) {
+			return buf;
+		}
+	}
+   	return NULL;
+}
+
+/* This should only be called if the buffer is not sent to the hardware
+ * yet, the hardware updates in use for us once its on the ring buffer.
+ */
+
+static int i830_freelist_put(drm_device_t *dev, drm_buf_t *buf)
+{
+   	drm_i830_buf_priv_t *buf_priv = buf->dev_private;
+   	int used;
+   
+   	/* In use is already a pointer */
+   	used = cmpxchg(buf_priv->in_use, I830_BUF_CLIENT, I830_BUF_FREE);
+   	if(used != I830_BUF_CLIENT) {
+	   	DRM_ERROR("Freeing buffer thats not in use : %d\n", buf->idx);
+	   	return -EINVAL;
+	}
+   
+   	return 0;
+}
+
+static struct file_operations i830_buffer_fops = {
+	open:	 DRM(open),
+	flush:	 DRM(flush),
+	release: DRM(release),
+	ioctl:	 DRM(ioctl),
+	mmap:	 i830_mmap_buffers,
+	read:	 DRM(read),
+	fasync:	 DRM(fasync),
+      	poll:	 DRM(poll),
+};
+
+int i830_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
+{
+	drm_file_t	    *priv	  = filp->private_data;
+	drm_device_t	    *dev;
+	drm_i830_private_t  *dev_priv;
+	drm_buf_t           *buf;
+	drm_i830_buf_priv_t *buf_priv;
+
+	lock_kernel();
+	dev	 = priv->dev;
+	dev_priv = dev->dev_private;
+	buf      = dev_priv->mmap_buffer;
+	buf_priv = buf->dev_private;
+   
+	vma->vm_flags |= (VM_IO | VM_DONTCOPY);
+	vma->vm_file = filp;
+   
+   	buf_priv->currently_mapped = I830_BUF_MAPPED;
+	unlock_kernel();
+
+	if (remap_page_range(vma->vm_start,
+			     VM_OFFSET(vma),
+			     vma->vm_end - vma->vm_start,
+			     vma->vm_page_prot)) return -EAGAIN;
+	return 0;
+}
+
+static int i830_map_buffer(drm_buf_t *buf, struct file *filp)
+{
+	drm_file_t	  *priv	  = filp->private_data;
+	drm_device_t	  *dev	  = priv->dev;
+	drm_i830_buf_priv_t *buf_priv = buf->dev_private;
+      	drm_i830_private_t *dev_priv = dev->dev_private;
+   	struct file_operations *old_fops;
+	int retcode = 0;
+
+	if(buf_priv->currently_mapped == I830_BUF_MAPPED) return -EINVAL;
+
+	if(VM_DONTCOPY != 0) {
+		down_write( &current->mm->mmap_sem );
+		old_fops = filp->f_op;
+		filp->f_op = &i830_buffer_fops;
+		dev_priv->mmap_buffer = buf;
+		buf_priv->virtual = (void *)do_mmap(filp, 0, buf->total, 
+						    PROT_READ|PROT_WRITE,
+						    MAP_SHARED, 
+						    buf->bus_address);
+		dev_priv->mmap_buffer = NULL;
+   		filp->f_op = old_fops;
+		if ((unsigned long)buf_priv->virtual > -1024UL) {
+			/* Real error */
+			DRM_DEBUG("mmap error\n");
+			retcode = (signed int)buf_priv->virtual;
+			buf_priv->virtual = 0;
+		}
+		up_write( &current->mm->mmap_sem );
+	} else {
+		buf_priv->virtual = buf_priv->kernel_virtual;
+   		buf_priv->currently_mapped = I830_BUF_MAPPED;
+	}
+	return retcode;
+}
+
+static int i830_unmap_buffer(drm_buf_t *buf)
+{
+	drm_i830_buf_priv_t *buf_priv = buf->dev_private;
+	int retcode = 0;
+
+	if(VM_DONTCOPY != 0) {
+		if(buf_priv->currently_mapped != I830_BUF_MAPPED) 
+			return -EINVAL;
+		down_write( &current->mm->mmap_sem );
+        	retcode = do_munmap(current->mm, 
+				    (unsigned long)buf_priv->virtual, 
+				    (size_t) buf->total);
+   		up_write( &current->mm->mmap_sem );
+	}
+   	buf_priv->currently_mapped = I830_BUF_UNMAPPED;
+   	buf_priv->virtual = 0;
+
+	return retcode;
+}
+
+static int i830_dma_get_buffer(drm_device_t *dev, drm_i830_dma_t *d, 
+			       struct file *filp)
+{
+	drm_file_t	  *priv	  = filp->private_data;
+	drm_buf_t	  *buf;
+	drm_i830_buf_priv_t *buf_priv;
+	int retcode = 0;
+
+	buf = i830_freelist_get(dev);
+	if (!buf) {
+		retcode = -ENOMEM;
+	   	DRM_DEBUG("retcode=%d\n", retcode);
+		return retcode;
+	}
+   
+	retcode = i830_map_buffer(buf, filp);
+	if(retcode) {
+		i830_freelist_put(dev, buf);
+	   	DRM_DEBUG("mapbuf failed, retcode %d\n", retcode);
+		return retcode;
+	}
+	buf->pid     = priv->pid;
+	buf_priv = buf->dev_private;	
+	d->granted = 1;
+   	d->request_idx = buf->idx;
+   	d->request_size = buf->total;
+   	d->virtual = buf_priv->virtual;
+
+	return retcode;
+}
+
+static int i830_dma_cleanup(drm_device_t *dev)
+{
+	drm_device_dma_t *dma = dev->dma;
+
+	if(dev->dev_private) {
+		int i;
+	   	drm_i830_private_t *dev_priv = 
+	     		(drm_i830_private_t *) dev->dev_private;
+	   
+	   	if(dev_priv->ring.virtual_start) {
+		   	DRM(ioremapfree)((void *) dev_priv->ring.virtual_start,
+					 dev_priv->ring.Size);
+		}
+	   	if(dev_priv->hw_status_page != NULL) {
+	   		pci_free_consistent(dev->pdev, PAGE_SIZE, 
+	   		    dev_priv->hw_status_page, dev_priv->dma_status_page);
+		   	/* Need to rewrite hardware status page */
+		   	I830_WRITE(0x02080, 0x1ffff000);
+		}
+	   	DRM(free)(dev->dev_private, sizeof(drm_i830_private_t), 
+			 DRM_MEM_DRIVER);
+	   	dev->dev_private = NULL;
+
+		for (i = 0; i < dma->buf_count; i++) {
+			drm_buf_t *buf = dma->buflist[ i ];
+			drm_i830_buf_priv_t *buf_priv = buf->dev_private;
+			DRM(ioremapfree)(buf_priv->kernel_virtual, buf->total);
+		}
+	}
+   	return 0;
+}
+
+static int i830_wait_ring(drm_device_t *dev, int n)
+{
+   	drm_i830_private_t *dev_priv = dev->dev_private;
+   	drm_i830_ring_buffer_t *ring = &(dev_priv->ring);
+   	int iters = 0;
+   	unsigned long end;
+	unsigned int last_head = I830_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
+
+	end = jiffies + (HZ*3);
+   	while (ring->space < n) {
+	   	ring->head = I830_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
+	   	ring->space = ring->head - (ring->tail+8);
+		if (ring->space < 0) ring->space += ring->Size;
+	   
+		if (ring->head != last_head) {
+			end = jiffies + (HZ*3);
+			last_head = ring->head;
+		}
+	  
+	   	iters++;
+		if(time_before(end,jiffies)) {
+		   	DRM_ERROR("space: %d wanted %d\n", ring->space, n);
+		   	DRM_ERROR("lockup\n");
+		   	goto out_wait_ring;
+		}
+
+	   	udelay(1);
+	}
+
+out_wait_ring:   
+   	return iters;
+}
+
+static void i830_kernel_lost_context(drm_device_t *dev)
+{
+      	drm_i830_private_t *dev_priv = dev->dev_private;
+   	drm_i830_ring_buffer_t *ring = &(dev_priv->ring);
+      
+   	ring->head = I830_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
+     	ring->tail = I830_READ(LP_RING + RING_TAIL);
+     	ring->space = ring->head - (ring->tail+8);
+     	if (ring->space < 0) ring->space += ring->Size;
+}
+
+static int i830_freelist_init(drm_device_t *dev, drm_i830_private_t *dev_priv)
+{
+      	drm_device_dma_t *dma = dev->dma;
+   	int my_idx = 36;
+   	u32 *hw_status = (u32 *)(dev_priv->hw_status_page + my_idx);
+   	int i;
+
+   	if(dma->buf_count > 1019) {
+	   	/* Not enough space in the status page for the freelist */
+	   	return -EINVAL;
+	}
+
+   	for (i = 0; i < dma->buf_count; i++) {
+	   	drm_buf_t *buf = dma->buflist[ i ];
+	   	drm_i830_buf_priv_t *buf_priv = buf->dev_private;
+
+	   	buf_priv->in_use = hw_status++;
+	   	buf_priv->my_use_idx = my_idx;
+	   	my_idx += 4;
+
+	   	*buf_priv->in_use = I830_BUF_FREE;
+
+		buf_priv->kernel_virtual = DRM(ioremap)(buf->bus_address, 
+							buf->total);
+	}
+	return 0;
+}
+
+static int i830_dma_initialize(drm_device_t *dev, 
+			       drm_i830_private_t *dev_priv,
+			       drm_i830_init_t *init)
+{
+	struct list_head *list;
+
+   	memset(dev_priv, 0, sizeof(drm_i830_private_t));
+
+	list_for_each(list, &dev->maplist->head) {
+		drm_map_list_t *r_list = (drm_map_list_t *)list;
+		if( r_list->map &&
+		    r_list->map->type == _DRM_SHM &&
+		    r_list->map->flags & _DRM_CONTAINS_LOCK ) {
+			dev_priv->sarea_map = r_list->map;
+ 			break;
+ 		}
+ 	}
+
+	if(!dev_priv->sarea_map) {
+		dev->dev_private = (void *)dev_priv;
+		i830_dma_cleanup(dev);
+		DRM_ERROR("can not find sarea!\n");
+		return -EINVAL;
+	}
+	DRM_FIND_MAP( dev_priv->mmio_map, init->mmio_offset );
+	if(!dev_priv->mmio_map) {
+		dev->dev_private = (void *)dev_priv;
+		i830_dma_cleanup(dev);
+		DRM_ERROR("can not find mmio map!\n");
+		return -EINVAL;
+	}
+	DRM_FIND_MAP( dev_priv->buffer_map, init->buffers_offset );
+	if(!dev_priv->buffer_map) {
+		dev->dev_private = (void *)dev_priv;
+		i830_dma_cleanup(dev);
+		DRM_ERROR("can not find dma buffer map!\n");
+		return -EINVAL;
+	}
+
+	dev_priv->sarea_priv = (drm_i830_sarea_t *)
+		((u8 *)dev_priv->sarea_map->handle +
+		 init->sarea_priv_offset);
+
+   	atomic_set(&dev_priv->flush_done, 0);
+	init_waitqueue_head(&dev_priv->flush_queue);
+
+   	dev_priv->ring.Start = init->ring_start;
+   	dev_priv->ring.End = init->ring_end;
+   	dev_priv->ring.Size = init->ring_size;
+
+   	dev_priv->ring.virtual_start = DRM(ioremap)(dev->agp->base + 
+						    init->ring_start, 
+						    init->ring_size);
+
+   	if (dev_priv->ring.virtual_start == NULL) {
+		dev->dev_private = (void *) dev_priv;
+	   	i830_dma_cleanup(dev);
+	   	DRM_ERROR("can not ioremap virtual address for"
+			  " ring buffer\n");
+	   	return -ENOMEM;
+	}
+
+   	dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
+   
+	dev_priv->w = init->w;
+	dev_priv->h = init->h;
+	dev_priv->pitch = init->pitch;
+	dev_priv->back_offset = init->back_offset;
+	dev_priv->depth_offset = init->depth_offset;
+
+	dev_priv->front_di1 = init->front_offset | init->pitch_bits;
+	dev_priv->back_di1 = init->back_offset | init->pitch_bits;
+	dev_priv->zi1 = init->depth_offset | init->pitch_bits;
+
+	dev_priv->cpp = init->cpp;
+	/* We are using seperate values as placeholders for mechanisms for
+	 * private backbuffer/depthbuffer usage.
+	 */
+
+	dev_priv->back_pitch = init->back_pitch;
+	dev_priv->depth_pitch = init->depth_pitch;
+
+   	/* Program Hardware Status Page */
+   	dev_priv->hw_status_page = pci_alloc_consistent(dev->pdev, PAGE_SIZE, 
+						&dev_priv->dma_status_page);
+   	if(dev_priv->hw_status_page == NULL) {
+		dev->dev_private = (void *)dev_priv;
+		i830_dma_cleanup(dev);
+		DRM_ERROR("Can not allocate hardware status page\n");
+		return -ENOMEM;
+	}
+   	memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
+	DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page);
+   
+   	I830_WRITE(0x02080, dev_priv->dma_status_page);
+	DRM_DEBUG("Enabled hardware status page\n");
+   
+   	/* Now we need to init our freelist */
+   	if(i830_freelist_init(dev, dev_priv) != 0) {
+		dev->dev_private = (void *)dev_priv;
+	   	i830_dma_cleanup(dev);
+	   	DRM_ERROR("Not enough space in the status page for"
+			  " the freelist\n");
+	   	return -ENOMEM;
+	}
+	dev->dev_private = (void *)dev_priv;
+
+   	return 0;
+}
+
+int i830_dma_init(struct inode *inode, struct file *filp,
+		  unsigned int cmd, unsigned long arg)
+{
+   	drm_file_t *priv = filp->private_data;
+   	drm_device_t *dev = priv->dev;
+   	drm_i830_private_t *dev_priv;
+   	drm_i830_init_t init;
+   	int retcode = 0;
+	
+  	if (copy_from_user(&init, (drm_i830_init_t *)arg, sizeof(init)))
+		return -EFAULT;
+	
+   	switch(init.func) {
+	 	case I830_INIT_DMA:
+			dev_priv = DRM(alloc)(sizeof(drm_i830_private_t), 
+					      DRM_MEM_DRIVER);
+	   		if(dev_priv == NULL) return -ENOMEM;
+	   		retcode = i830_dma_initialize(dev, dev_priv, &init);
+	   	break;
+	 	case I830_CLEANUP_DMA:
+	   		retcode = i830_dma_cleanup(dev);
+	   	break;
+	 	default:
+	   		retcode = -EINVAL;
+	   	break;
+	}
+   
+   	return retcode;
+}
+
+/* Most efficient way to verify state for the i830 is as it is
+ * emitted.  Non-conformant state is silently dropped.
+ *
+ * Use 'volatile' & local var tmp to force the emitted values to be
+ * identical to the verified ones.
+ */
+static void i830EmitContextVerified( drm_device_t *dev, 
+				     volatile unsigned int *code )
+{
+   	drm_i830_private_t *dev_priv = dev->dev_private;
+	int i, j = 0;
+	unsigned int tmp;
+	RING_LOCALS;
+
+	BEGIN_LP_RING( I830_CTX_SETUP_SIZE );
+	for ( i = 0 ; i < I830_CTX_SETUP_SIZE ; i++ ) {
+		tmp = code[i];
+
+#if 0
+		if ((tmp & (7<<29)) == (3<<29) &&
+		    (tmp & (0x1f<<24)) < (0x1d<<24)) {
+			OUT_RING( tmp ); 
+			j++;
+		} else {
+			printk("Skipping %d\n", i);
+		}
+#else
+		OUT_RING( tmp ); 
+		j++;
+#endif
+	}
+
+	if (j & 1) 
+		OUT_RING( 0 ); 
+
+	ADVANCE_LP_RING();
+}
+
+static void i830EmitTexVerified( drm_device_t *dev, 
+				 volatile unsigned int *code ) 
+{
+   	drm_i830_private_t *dev_priv = dev->dev_private;
+	int i, j = 0;
+	unsigned int tmp;
+	RING_LOCALS;
+
+	BEGIN_LP_RING( I830_TEX_SETUP_SIZE );
+
+	OUT_RING( GFX_OP_MAP_INFO );
+	OUT_RING( code[I830_TEXREG_MI1] );
+	OUT_RING( code[I830_TEXREG_MI2] );
+	OUT_RING( code[I830_TEXREG_MI3] );
+	OUT_RING( code[I830_TEXREG_MI4] );
+	OUT_RING( code[I830_TEXREG_MI5] );
+
+	for ( i = 6 ; i < I830_TEX_SETUP_SIZE ; i++ ) {
+		tmp = code[i];
+		OUT_RING( tmp ); 
+		j++;
+	} 
+
+	if (j & 1) 
+		OUT_RING( 0 ); 
+
+	ADVANCE_LP_RING();
+}
+
+static void i830EmitTexBlendVerified( drm_device_t *dev, 
+				     volatile unsigned int *code,
+				     volatile unsigned int num)
+{
+   	drm_i830_private_t *dev_priv = dev->dev_private;
+	int i, j = 0;
+	unsigned int tmp;
+	RING_LOCALS;
+
+	BEGIN_LP_RING( num );
+
+	for ( i = 0 ; i < num ; i++ ) {
+		tmp = code[i];
+		OUT_RING( tmp );
+		j++;
+	}
+
+	if (j & 1) 
+		OUT_RING( 0 ); 
+
+	ADVANCE_LP_RING();
+}
+
+static void i830EmitTexPalette( drm_device_t *dev,
+			        unsigned int *palette,
+			        int number,
+			        int is_shared )
+{
+   	drm_i830_private_t *dev_priv = dev->dev_private;
+	int i;
+	RING_LOCALS;
+
+	BEGIN_LP_RING( 258 );
+
+	if(is_shared == 1) {
+		OUT_RING(CMD_OP_MAP_PALETTE_LOAD |
+			 MAP_PALETTE_NUM(0) |
+			 MAP_PALETTE_BOTH);
+	} else {
+		OUT_RING(CMD_OP_MAP_PALETTE_LOAD | MAP_PALETTE_NUM(number));
+	}
+	for(i = 0; i < 256; i++) {
+		OUT_RING(palette[i]);
+	}
+	OUT_RING(0);
+}
+
+/* Need to do some additional checking when setting the dest buffer.
+ */
+static void i830EmitDestVerified( drm_device_t *dev, 
+				  volatile unsigned int *code ) 
+{	
+   	drm_i830_private_t *dev_priv = dev->dev_private;
+	unsigned int tmp;
+	RING_LOCALS;
+
+	BEGIN_LP_RING( I830_DEST_SETUP_SIZE + 6 );
+
+	tmp = code[I830_DESTREG_CBUFADDR];
+	if (tmp == dev_priv->front_di1) {
+		/* Don't use fence when front buffer rendering */
+		OUT_RING( CMD_OP_DESTBUFFER_INFO );
+		OUT_RING( BUF_3D_ID_COLOR_BACK | 
+			  BUF_3D_PITCH(dev_priv->back_pitch * dev_priv->cpp) );
+		OUT_RING( tmp );
+
+		OUT_RING( CMD_OP_DESTBUFFER_INFO );
+		OUT_RING( BUF_3D_ID_DEPTH |
+			  BUF_3D_PITCH(dev_priv->depth_pitch * dev_priv->cpp));
+		OUT_RING( dev_priv->zi1 );
+	} else if(tmp == dev_priv->back_di1) {
+		OUT_RING( CMD_OP_DESTBUFFER_INFO );
+		OUT_RING( BUF_3D_ID_COLOR_BACK | 
+			  BUF_3D_PITCH(dev_priv->back_pitch * dev_priv->cpp) |
+			  BUF_3D_USE_FENCE);
+		OUT_RING( tmp );
+
+		OUT_RING( CMD_OP_DESTBUFFER_INFO );
+		OUT_RING( BUF_3D_ID_DEPTH | BUF_3D_USE_FENCE | 
+			  BUF_3D_PITCH(dev_priv->depth_pitch * dev_priv->cpp));
+		OUT_RING( dev_priv->zi1 );
+	} else {
+		DRM_DEBUG("bad di1 %x (allow %x or %x)\n",
+			  tmp, dev_priv->front_di1, dev_priv->back_di1);
+	}
+
+	/* invarient:
+	 */
+
+
+	OUT_RING( GFX_OP_DESTBUFFER_VARS );
+	OUT_RING( code[I830_DESTREG_DV1] );
+
+	OUT_RING( GFX_OP_DRAWRECT_INFO );
+	OUT_RING( code[I830_DESTREG_DR1] );
+	OUT_RING( code[I830_DESTREG_DR2] );
+	OUT_RING( code[I830_DESTREG_DR3] );
+	OUT_RING( code[I830_DESTREG_DR4] );
+
+	/* Need to verify this */
+	tmp = code[I830_DESTREG_SENABLE];
+	if((tmp & ~0x3) == GFX_OP_SCISSOR_ENABLE) {
+		OUT_RING( tmp );
+	} else {
+		DRM_DEBUG("bad scissor enable\n");
+		OUT_RING( 0 );
+	}
+
+	OUT_RING( code[I830_DESTREG_SENABLE] );
+
+	OUT_RING( GFX_OP_SCISSOR_RECT );
+	OUT_RING( code[I830_DESTREG_SR1] );
+	OUT_RING( code[I830_DESTREG_SR2] );
+
+	ADVANCE_LP_RING();
+}
+
+static void i830EmitState( drm_device_t *dev )
+{
+   	drm_i830_private_t *dev_priv = dev->dev_private;
+      	drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	unsigned int dirty = sarea_priv->dirty;
+
+	if (dirty & I830_UPLOAD_BUFFERS) {
+		i830EmitDestVerified( dev, sarea_priv->BufferState );
+		sarea_priv->dirty &= ~I830_UPLOAD_BUFFERS;
+	}
+
+	if (dirty & I830_UPLOAD_CTX) {
+		i830EmitContextVerified( dev, sarea_priv->ContextState );
+		sarea_priv->dirty &= ~I830_UPLOAD_CTX;
+	}
+
+	if (dirty & I830_UPLOAD_TEX0) {
+		i830EmitTexVerified( dev, sarea_priv->TexState[0] );
+		sarea_priv->dirty &= ~I830_UPLOAD_TEX0;
+	}
+
+	if (dirty & I830_UPLOAD_TEX1) {
+		i830EmitTexVerified( dev, sarea_priv->TexState[1] );
+		sarea_priv->dirty &= ~I830_UPLOAD_TEX1;
+	}
+
+	if (dirty & I830_UPLOAD_TEXBLEND0) {
+		i830EmitTexBlendVerified( dev, sarea_priv->TexBlendState[0],
+				sarea_priv->TexBlendStateWordsUsed[0]);
+		sarea_priv->dirty &= ~I830_UPLOAD_TEXBLEND0;
+	}
+
+	if (dirty & I830_UPLOAD_TEXBLEND1) {
+		i830EmitTexBlendVerified( dev, sarea_priv->TexBlendState[1],
+				sarea_priv->TexBlendStateWordsUsed[1]);
+		sarea_priv->dirty &= ~I830_UPLOAD_TEXBLEND1;
+	}
+
+	if (dirty & I830_UPLOAD_TEX_PALETTE_SHARED) {
+	   i830EmitTexPalette(dev, sarea_priv->Palette[0], 0, 1);
+	} else {
+	   if (dirty & I830_UPLOAD_TEX_PALETTE_N(0)) {
+	      i830EmitTexPalette(dev, sarea_priv->Palette[0], 0, 0);
+	      sarea_priv->dirty &= ~I830_UPLOAD_TEX_PALETTE_N(0);
+	   }
+	   if (dirty & I830_UPLOAD_TEX_PALETTE_N(1)) {
+	      i830EmitTexPalette(dev, sarea_priv->Palette[1], 1, 0);
+	      sarea_priv->dirty &= ~I830_UPLOAD_TEX_PALETTE_N(1);
+	   }
+	}
+}
+
+static void i830_dma_dispatch_clear( drm_device_t *dev, int flags, 
+				    unsigned int clear_color,
+				    unsigned int clear_zval,
+				    unsigned int clear_depthmask)
+{
+   	drm_i830_private_t *dev_priv = dev->dev_private;
+      	drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	int nbox = sarea_priv->nbox;
+	drm_clip_rect_t *pbox = sarea_priv->boxes;
+	int pitch = dev_priv->pitch;
+	int cpp = dev_priv->cpp;
+	int i;
+	unsigned int BR13, CMD, D_CMD;
+	RING_LOCALS;
+
+  	i830_kernel_lost_context(dev);
+
+	switch(cpp) {
+	case 2: 
+		BR13 = (0xF0 << 16) | (pitch * cpp) | (1<<24);
+		D_CMD = CMD = XY_COLOR_BLT_CMD;
+		break;
+	case 4:
+		BR13 = (0xF0 << 16) | (pitch * cpp) | (1<<24) | (1<<25);
+		CMD = (XY_COLOR_BLT_CMD | XY_COLOR_BLT_WRITE_ALPHA | 
+		       XY_COLOR_BLT_WRITE_RGB);
+		D_CMD = XY_COLOR_BLT_CMD;
+		if(clear_depthmask & 0x00ffffff)
+			D_CMD |= XY_COLOR_BLT_WRITE_RGB;
+		if(clear_depthmask & 0xff000000)
+			D_CMD |= XY_COLOR_BLT_WRITE_ALPHA;
+		break;
+	default:
+		BR13 = (0xF0 << 16) | (pitch * cpp) | (1<<24);
+		D_CMD = CMD = XY_COLOR_BLT_CMD;
+		break;
+	}
+
+      	if (nbox > I830_NR_SAREA_CLIPRECTS)
+     		nbox = I830_NR_SAREA_CLIPRECTS;
+
+	for (i = 0 ; i < nbox ; i++, pbox++) {
+		if (pbox->x1 > pbox->x2 ||
+		    pbox->y1 > pbox->y2 ||
+		    pbox->x2 > dev_priv->w ||
+		    pbox->y2 > dev_priv->h)
+			continue;
+
+	   	if ( flags & I830_FRONT ) {	    
+		   	DRM_DEBUG("clear front\n");
+			BEGIN_LP_RING( 6 );	    
+			OUT_RING( CMD );
+			OUT_RING( BR13 );
+			OUT_RING( (pbox->y1 << 16) | pbox->x1 );
+			OUT_RING( (pbox->y2 << 16) | pbox->x2 );
+			OUT_RING( 0 );
+			OUT_RING( clear_color );
+			ADVANCE_LP_RING();
+		}
+
+		if ( flags & I830_BACK ) {
+			DRM_DEBUG("clear back\n");
+			BEGIN_LP_RING( 6 );	    
+			OUT_RING( CMD );
+			OUT_RING( BR13 );
+			OUT_RING( (pbox->y1 << 16) | pbox->x1 );
+			OUT_RING( (pbox->y2 << 16) | pbox->x2 );
+			OUT_RING( dev_priv->back_offset );
+			OUT_RING( clear_color );
+			ADVANCE_LP_RING();
+		}
+
+		if ( flags & I830_DEPTH ) {
+			DRM_DEBUG("clear depth\n");
+			BEGIN_LP_RING( 6 );
+			OUT_RING( D_CMD );
+			OUT_RING( BR13 );
+			OUT_RING( (pbox->y1 << 16) | pbox->x1 );
+			OUT_RING( (pbox->y2 << 16) | pbox->x2 );
+			OUT_RING( dev_priv->depth_offset );
+			OUT_RING( clear_zval );
+			ADVANCE_LP_RING();
+		}
+	}
+}
+
+static void i830_dma_dispatch_swap( drm_device_t *dev )
+{
+   	drm_i830_private_t *dev_priv = dev->dev_private;
+      	drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	int nbox = sarea_priv->nbox;
+	drm_clip_rect_t *pbox = sarea_priv->boxes;
+	int pitch = dev_priv->pitch;
+	int cpp = dev_priv->cpp;
+	int ofs = dev_priv->back_offset;
+	int i;
+	unsigned int CMD, BR13;
+	RING_LOCALS;
+
+	DRM_DEBUG("swapbuffers\n");
+
+	switch(cpp) {
+	case 2: 
+		BR13 = (pitch * cpp) | (0xCC << 16) | (1<<24);
+		CMD = XY_SRC_COPY_BLT_CMD;
+		break;
+	case 4:
+		BR13 = (pitch * cpp) | (0xCC << 16) | (1<<24) | (1<<25);
+		CMD = (XY_SRC_COPY_BLT_CMD | XY_SRC_COPY_BLT_WRITE_ALPHA |
+		       XY_SRC_COPY_BLT_WRITE_RGB);
+		break;
+	default:
+		BR13 = (pitch * cpp) | (0xCC << 16) | (1<<24);
+		CMD = XY_SRC_COPY_BLT_CMD;
+		break;
+	}
+
+  	i830_kernel_lost_context(dev);
+
+      	if (nbox > I830_NR_SAREA_CLIPRECTS)
+     		nbox = I830_NR_SAREA_CLIPRECTS;
+
+	for (i = 0 ; i < nbox; i++, pbox++) 
+	{
+		if (pbox->x1 > pbox->x2 ||
+		    pbox->y1 > pbox->y2 ||
+		    pbox->x2 > dev_priv->w ||
+		    pbox->y2 > dev_priv->h)
+			continue;
+ 
+		DRM_DEBUG("dispatch swap %d,%d-%d,%d!\n",
+			  pbox->x1, pbox->y1,
+			  pbox->x2, pbox->y2);
+
+		BEGIN_LP_RING( 8 );
+		OUT_RING( CMD );
+		OUT_RING( BR13 );
+
+		OUT_RING( (pbox->y1 << 16) |
+			  pbox->x1 );
+		OUT_RING( (pbox->y2 << 16) |
+			  pbox->x2 );
+
+		OUT_RING( 0 /* front ofs always zero */ );
+		OUT_RING( (pbox->y1 << 16) |
+			  pbox->x1 );
+
+		OUT_RING( BR13 & 0xffff );
+		OUT_RING( ofs );
+
+		ADVANCE_LP_RING();
+	}
+}
+
+
+static void i830_dma_dispatch_vertex(drm_device_t *dev, 
+				     drm_buf_t *buf,
+				     int discard,
+				     int used)
+{
+   	drm_i830_private_t *dev_priv = dev->dev_private;
+	drm_i830_buf_priv_t *buf_priv = buf->dev_private;
+   	drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv;
+   	drm_clip_rect_t *box = sarea_priv->boxes;
+   	int nbox = sarea_priv->nbox;
+	unsigned long address = (unsigned long)buf->bus_address;
+	unsigned long start = address - dev->agp->base;     
+	int i = 0, u;
+   	RING_LOCALS;
+
+   	i830_kernel_lost_context(dev);
+
+   	if (nbox > I830_NR_SAREA_CLIPRECTS) 
+		nbox = I830_NR_SAREA_CLIPRECTS;
+
+	if (discard) {
+		u = cmpxchg(buf_priv->in_use, I830_BUF_CLIENT, 
+			    I830_BUF_HARDWARE);
+		if(u != I830_BUF_CLIENT) {
+			DRM_DEBUG("xxxx 2\n");
+		}
+	}
+
+	if (used > 4*1024) 
+		used = 0;
+
+	if (sarea_priv->dirty)
+	   i830EmitState( dev );
+
+  	DRM_DEBUG("dispatch vertex addr 0x%lx, used 0x%x nbox %d\n", 
+		  address, used, nbox);
+
+   	dev_priv->counter++;
+   	DRM_DEBUG(  "dispatch counter : %ld\n", dev_priv->counter);
+   	DRM_DEBUG(  "i830_dma_dispatch\n");
+   	DRM_DEBUG(  "start : %lx\n", start);
+	DRM_DEBUG(  "used : %d\n", used);
+   	DRM_DEBUG(  "start + used - 4 : %ld\n", start + used - 4);
+
+	if (buf_priv->currently_mapped == I830_BUF_MAPPED) {
+		*(u32 *)buf_priv->virtual = (GFX_OP_PRIMITIVE |
+					     sarea_priv->vertex_prim |
+					     ((used/4)-2));
+		
+		if (used & 4) {
+			*(u32 *)((u32)buf_priv->virtual + used) = 0;
+			used += 4;
+		}
+
+		i830_unmap_buffer(buf);
+	}
+		   
+	if (used) {
+		do {
+			if (i < nbox) {
+				BEGIN_LP_RING(6);
+				OUT_RING( GFX_OP_DRAWRECT_INFO );
+				OUT_RING( sarea_priv->BufferState[I830_DESTREG_DR1] );
+				OUT_RING( box[i].x1 | (box[i].y1<<16) );
+				OUT_RING( box[i].x2 | (box[i].y2<<16) );
+				OUT_RING( sarea_priv->BufferState[I830_DESTREG_DR4] );
+				OUT_RING( 0 );
+				ADVANCE_LP_RING();
+			}
+
+			BEGIN_LP_RING(4);
+
+			OUT_RING( MI_BATCH_BUFFER );
+			OUT_RING( start | MI_BATCH_NON_SECURE );
+			OUT_RING( start + used - 4 );
+			OUT_RING( 0 );
+			ADVANCE_LP_RING();
+			
+		} while (++i < nbox);
+	}
+
+	BEGIN_LP_RING(10);
+	OUT_RING( CMD_STORE_DWORD_IDX );
+	OUT_RING( 20 );
+	OUT_RING( dev_priv->counter );
+	OUT_RING( 0 );
+
+	if (discard) {
+		OUT_RING( CMD_STORE_DWORD_IDX );
+		OUT_RING( buf_priv->my_use_idx );
+		OUT_RING( I830_BUF_FREE );
+		OUT_RING( 0 );
+	}
+
+      	OUT_RING( CMD_REPORT_HEAD );
+	OUT_RING( 0 );
+   	ADVANCE_LP_RING();
+}
+
+/* Interrupts are only for flushing */
+void i830_dma_service(int irq, void *device, struct pt_regs *regs)
+{
+	drm_device_t	 *dev = (drm_device_t *)device;
+      	drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private;
+   	u16 temp;
+   
+      	temp = I830_READ16(I830REG_INT_IDENTITY_R);
+   	temp = temp & ~(0x6000);
+   	if(temp != 0) I830_WRITE16(I830REG_INT_IDENTITY_R, 
+				   temp); /* Clear all interrupts */
+	else
+	   return;
+ 
+   	queue_task(&dev->tq, &tq_immediate);
+   	mark_bh(IMMEDIATE_BH);
+}
+
+void DRM(dma_immediate_bh)(void *device)
+{
+	drm_device_t *dev = (drm_device_t *) device;
+      	drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private;
+
+   	atomic_set(&dev_priv->flush_done, 1);
+   	wake_up_interruptible(&dev_priv->flush_queue);
+}
+
+static inline void i830_dma_emit_flush(drm_device_t *dev)
+{
+   	drm_i830_private_t *dev_priv = dev->dev_private;
+   	RING_LOCALS;
+
+   	i830_kernel_lost_context(dev);
+
+   	BEGIN_LP_RING(2);
+      	OUT_RING( CMD_REPORT_HEAD );
+      	OUT_RING( GFX_OP_USER_INTERRUPT );
+      	ADVANCE_LP_RING();
+
+	i830_wait_ring( dev, dev_priv->ring.Size - 8 );
+	atomic_set(&dev_priv->flush_done, 1);
+	wake_up_interruptible(&dev_priv->flush_queue);
+}
+
+static inline void i830_dma_quiescent_emit(drm_device_t *dev)
+{
+      	drm_i830_private_t *dev_priv = dev->dev_private;
+   	RING_LOCALS;
+
+  	i830_kernel_lost_context(dev);
+
+   	BEGIN_LP_RING(4);
+   	OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE );
+   	OUT_RING( CMD_REPORT_HEAD );
+      	OUT_RING( 0 );
+      	OUT_RING( GFX_OP_USER_INTERRUPT );
+   	ADVANCE_LP_RING();
+
+	i830_wait_ring( dev, dev_priv->ring.Size - 8 );
+	atomic_set(&dev_priv->flush_done, 1);
+	wake_up_interruptible(&dev_priv->flush_queue);
+}
+
+void i830_dma_quiescent(drm_device_t *dev)
+{
+      	DECLARE_WAITQUEUE(entry, current);
+  	drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private;
+	unsigned long end;      
+
+   	if(dev_priv == NULL) {
+	   	return;
+	}
+      	atomic_set(&dev_priv->flush_done, 0);
+   	add_wait_queue(&dev_priv->flush_queue, &entry);
+   	end = jiffies + (HZ*3);
+   
+   	for (;;) {
+		current->state = TASK_INTERRUPTIBLE;
+	      	i830_dma_quiescent_emit(dev);
+	   	if (atomic_read(&dev_priv->flush_done) == 1) break;
+		if(time_before(end, jiffies)) {
+		   	DRM_ERROR("lockup\n");
+		   	break;
+		}	   
+	      	schedule_timeout(HZ*3);
+	      	if (signal_pending(current)) {
+		   	break;
+		}
+	}
+   
+   	current->state = TASK_RUNNING;
+   	remove_wait_queue(&dev_priv->flush_queue, &entry);
+   
+   	return;
+}
+
+static int i830_flush_queue(drm_device_t *dev)
+{
+   	DECLARE_WAITQUEUE(entry, current);
+  	drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private;
+	drm_device_dma_t *dma = dev->dma;
+	unsigned long end;
+   	int i, ret = 0;      
+
+   	if(dev_priv == NULL) {
+	   	return 0;
+	}
+      	atomic_set(&dev_priv->flush_done, 0);
+   	add_wait_queue(&dev_priv->flush_queue, &entry);
+   	end = jiffies + (HZ*3);
+   	for (;;) {
+		current->state = TASK_INTERRUPTIBLE;
+	      	i830_dma_emit_flush(dev);
+	   	if (atomic_read(&dev_priv->flush_done) == 1) break;
+		if(time_before(end, jiffies)) {
+		   	DRM_ERROR("lockup\n");
+		   	break;
+		}	   
+	      	schedule_timeout(HZ*3);
+	      	if (signal_pending(current)) {
+		   	ret = -EINTR; /* Can't restart */
+		   	break;
+		}
+	}
+   
+   	current->state = TASK_RUNNING;
+   	remove_wait_queue(&dev_priv->flush_queue, &entry);
+
+
+   	for (i = 0; i < dma->buf_count; i++) {
+	   	drm_buf_t *buf = dma->buflist[ i ];
+	   	drm_i830_buf_priv_t *buf_priv = buf->dev_private;
+	   
+		int used = cmpxchg(buf_priv->in_use, I830_BUF_HARDWARE, 
+				   I830_BUF_FREE);
+
+		if (used == I830_BUF_HARDWARE)
+			DRM_DEBUG("reclaimed from HARDWARE\n");
+		if (used == I830_BUF_CLIENT)
+			DRM_DEBUG("still on client HARDWARE\n");
+	}
+
+   	return ret;
+}
+
+/* Must be called with the lock held */
+void i830_reclaim_buffers(drm_device_t *dev, pid_t pid)
+{
+	drm_device_dma_t *dma = dev->dma;
+	int		 i;
+
+	if (!dma) return;
+      	if (!dev->dev_private) return;
+	if (!dma->buflist) return;
+
+        i830_flush_queue(dev);
+
+	for (i = 0; i < dma->buf_count; i++) {
+	   	drm_buf_t *buf = dma->buflist[ i ];
+	   	drm_i830_buf_priv_t *buf_priv = buf->dev_private;
+	   
+		if (buf->pid == pid && buf_priv) {
+			int used = cmpxchg(buf_priv->in_use, I830_BUF_CLIENT, 
+					   I830_BUF_FREE);
+
+			if (used == I830_BUF_CLIENT)
+				DRM_DEBUG("reclaimed from client\n");
+		   	if(buf_priv->currently_mapped == I830_BUF_MAPPED)
+		     		buf_priv->currently_mapped = I830_BUF_UNMAPPED;
+		}
+	}
+}
+
+int i830_flush_ioctl(struct inode *inode, struct file *filp, 
+		     unsigned int cmd, unsigned long arg)
+{
+   	drm_file_t	  *priv	  = filp->private_data;
+   	drm_device_t	  *dev	  = priv->dev;
+   
+   	DRM_DEBUG("i830_flush_ioctl\n");
+   	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("i830_flush_ioctl called without lock held\n");
+		return -EINVAL;
+	}
+
+   	i830_flush_queue(dev);
+   	return 0;
+}
+
+int i830_dma_vertex(struct inode *inode, struct file *filp,
+	       unsigned int cmd, unsigned long arg)
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_device_dma_t *dma = dev->dma;
+   	drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private;
+      	u32 *hw_status = (u32 *)dev_priv->hw_status_page;
+   	drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *) 
+     					dev_priv->sarea_priv; 
+	drm_i830_vertex_t vertex;
+
+	if (copy_from_user(&vertex, (drm_i830_vertex_t *)arg, sizeof(vertex)))
+		return -EFAULT;
+
+   	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("i830_dma_vertex called without lock held\n");
+		return -EINVAL;
+	}
+
+	DRM_DEBUG("i830 dma vertex, idx %d used %d discard %d\n",
+		  vertex.idx, vertex.used, vertex.discard);
+
+	if(vertex.idx < 0 || vertex.idx > dma->buf_count) return -EINVAL;
+
+	i830_dma_dispatch_vertex( dev, 
+				  dma->buflist[ vertex.idx ], 
+				  vertex.discard, vertex.used );
+
+	sarea_priv->last_enqueue = dev_priv->counter-1;
+   	sarea_priv->last_dispatch = (int) hw_status[5];
+   
+	return 0;
+}
+
+int i830_clear_bufs(struct inode *inode, struct file *filp,
+		   unsigned int cmd, unsigned long arg)
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_i830_clear_t clear;
+
+   	if (copy_from_user(&clear, (drm_i830_clear_t *)arg, sizeof(clear)))
+		return -EFAULT;
+   
+   	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("i830_clear_bufs called without lock held\n");
+		return -EINVAL;
+	}
+
+	/* GH: Someone's doing nasty things... */
+	if (!dev->dev_private) {
+		return -EINVAL;
+	}
+
+	i830_dma_dispatch_clear( dev, clear.flags, 
+				 clear.clear_color, 
+				 clear.clear_depth,
+			         clear.clear_depthmask);
+   	return 0;
+}
+
+int i830_swap_bufs(struct inode *inode, struct file *filp,
+		  unsigned int cmd, unsigned long arg)
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->dev;
+   
+	DRM_DEBUG("i830_swap_bufs\n");
+
+   	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("i830_swap_buf called without lock held\n");
+		return -EINVAL;
+	}
+
+	i830_dma_dispatch_swap( dev );
+   	return 0;
+}
+
+int i830_getage(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+   	drm_file_t	  *priv	    = filp->private_data;
+	drm_device_t	  *dev	    = priv->dev;
+   	drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private;
+      	u32 *hw_status = (u32 *)dev_priv->hw_status_page;
+   	drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *) 
+     					dev_priv->sarea_priv; 
+
+      	sarea_priv->last_dispatch = (int) hw_status[5];
+	return 0;
+}
+
+int i830_getbuf(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	drm_file_t	  *priv	    = filp->private_data;
+	drm_device_t	  *dev	    = priv->dev;
+	int		  retcode   = 0;
+	drm_i830_dma_t	  d;
+   	drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private;
+   	u32 *hw_status = (u32 *)dev_priv->hw_status_page;
+   	drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *) 
+     					dev_priv->sarea_priv; 
+
+	DRM_DEBUG("getbuf\n");
+   	if (copy_from_user(&d, (drm_i830_dma_t *)arg, sizeof(d)))
+		return -EFAULT;
+   
+	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("i830_dma called without lock held\n");
+		return -EINVAL;
+	}
+	
+	d.granted = 0;
+
+	retcode = i830_dma_get_buffer(dev, &d, filp);
+
+	DRM_DEBUG("i830_dma: %d returning %d, granted = %d\n",
+		  current->pid, retcode, d.granted);
+
+	if (copy_to_user((drm_dma_t *)arg, &d, sizeof(d)))
+		return -EFAULT;
+   	sarea_priv->last_dispatch = (int) hw_status[5];
+
+	return retcode;
+}
+
+int i830_copybuf(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	drm_file_t	  *priv	    = filp->private_data;
+	drm_device_t	  *dev	    = priv->dev;
+	drm_i830_copy_t	  d;
+   	drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private;
+   	u32 *hw_status = (u32 *)dev_priv->hw_status_page;
+   	drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *) 
+     					dev_priv->sarea_priv; 
+	drm_buf_t *buf;
+	drm_i830_buf_priv_t *buf_priv;
+	drm_device_dma_t *dma = dev->dma;
+
+	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("i830_dma called without lock held\n");
+		return -EINVAL;
+	}
+   
+   	if (copy_from_user(&d, (drm_i830_copy_t *)arg, sizeof(d)))
+		return -EFAULT;
+
+	if(d.idx < 0 || d.idx > dma->buf_count) return -EINVAL;
+	buf = dma->buflist[ d.idx ];
+   	buf_priv = buf->dev_private;
+	if (buf_priv->currently_mapped != I830_BUF_MAPPED) return -EPERM;
+
+	if(d.used < 0 || d.used > buf->total) return -EINVAL;
+
+   	if (copy_from_user(buf_priv->virtual, d.address, d.used))
+		return -EFAULT;
+
+   	sarea_priv->last_dispatch = (int) hw_status[5];
+
+	return 0;
+}
+
+int i830_docopy(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	if(VM_DONTCOPY == 0) return 1;
+	return 0;
+}
diff -urN linux-2.4.20-pre4/drivers/char/drm/i830_drm.h linux-2.4.20-pre5/drivers/char/drm/i830_drm.h
--- linux-2.4.20-pre4/drivers/char/drm/i830_drm.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre5/drivers/char/drm/i830_drm.h	Wed Aug 28 16:37:49 2002
@@ -0,0 +1,238 @@
+#ifndef _I830_DRM_H_
+#define _I830_DRM_H_
+
+/* WARNING: These defines must be the same as what the Xserver uses.
+ * if you change them, you must change the defines in the Xserver.
+ */
+
+#ifndef _I830_DEFINES_
+#define _I830_DEFINES_
+
+#define I830_DMA_BUF_ORDER		12
+#define I830_DMA_BUF_SZ 		(1<<I830_DMA_BUF_ORDER)
+#define I830_DMA_BUF_NR 		256
+#define I830_NR_SAREA_CLIPRECTS 	8
+
+/* Each region is a minimum of 64k, and there are at most 64 of them.
+ */
+#define I830_NR_TEX_REGIONS 64
+#define I830_LOG_MIN_TEX_REGION_SIZE 16
+
+/* if defining I830_ENABLE_4_TEXTURES, do it in i830_3d_reg.h, too */
+#if !defined(I830_ENABLE_4_TEXTURES)
+#define I830_TEXTURE_COUNT	2
+#define I830_TEXBLEND_COUNT	2	/* always same as TEXTURE_COUNT? */
+#else /* defined(I830_ENABLE_4_TEXTURES) */
+#define I830_TEXTURE_COUNT	4
+#define I830_TEXBLEND_COUNT	4	/* always same as TEXTURE_COUNT? */
+#endif /* I830_ENABLE_4_TEXTURES */
+
+#define I830_TEXBLEND_SIZE	12	/* (4 args + op) * 2 + COLOR_FACTOR */
+
+#define I830_UPLOAD_CTX			0x1
+#define I830_UPLOAD_BUFFERS		0x2
+#define I830_UPLOAD_CLIPRECTS		0x4
+#define I830_UPLOAD_TEX0_IMAGE		0x100 /* handled clientside */
+#define I830_UPLOAD_TEX0_CUBE		0x200 /* handled clientside */
+#define I830_UPLOAD_TEX1_IMAGE		0x400 /* handled clientside */
+#define I830_UPLOAD_TEX1_CUBE		0x800 /* handled clientside */
+#define I830_UPLOAD_TEX2_IMAGE		0x1000 /* handled clientside */
+#define I830_UPLOAD_TEX2_CUBE		0x2000 /* handled clientside */
+#define I830_UPLOAD_TEX3_IMAGE		0x4000 /* handled clientside */
+#define I830_UPLOAD_TEX3_CUBE		0x8000 /* handled clientside */
+#define I830_UPLOAD_TEX_N_IMAGE(n)	(0x100 << (n * 2))
+#define I830_UPLOAD_TEX_N_CUBE(n)	(0x200 << (n * 2))
+#define I830_UPLOAD_TEXIMAGE_MASK	0xff00
+#define I830_UPLOAD_TEX0			0x10000
+#define I830_UPLOAD_TEX1			0x20000
+#define I830_UPLOAD_TEX2			0x40000
+#define I830_UPLOAD_TEX3			0x80000
+#define I830_UPLOAD_TEX_N(n)		(0x10000 << (n))
+#define I830_UPLOAD_TEX_MASK		0xf0000
+#define I830_UPLOAD_TEXBLEND0		0x100000
+#define I830_UPLOAD_TEXBLEND1		0x200000
+#define I830_UPLOAD_TEXBLEND2		0x400000
+#define I830_UPLOAD_TEXBLEND3		0x800000
+#define I830_UPLOAD_TEXBLEND_N(n)	(0x100000 << (n))
+#define I830_UPLOAD_TEXBLEND_MASK	0xf00000
+#define I830_UPLOAD_TEX_PALETTE_N(n)    (0x1000000 << (n))
+#define I830_UPLOAD_TEX_PALETTE_SHARED	0x4000000
+
+/* Indices into buf.Setup where various bits of state are mirrored per
+ * context and per buffer.  These can be fired at the card as a unit,
+ * or in a piecewise fashion as required.
+ */
+
+/* Destbuffer state 
+ *    - backbuffer linear offset and pitch -- invarient in the current dri
+ *    - zbuffer linear offset and pitch -- also invarient
+ *    - drawing origin in back and depth buffers.
+ *
+ * Keep the depth/back buffer state here to acommodate private buffers
+ * in the future.
+ */
+
+#define I830_DESTREG_CBUFADDR 0
+/* Invarient */
+#define I830_DESTREG_DBUFADDR 1
+#define I830_DESTREG_DV0 2
+#define I830_DESTREG_DV1 3
+#define I830_DESTREG_SENABLE 4
+#define I830_DESTREG_SR0 5
+#define I830_DESTREG_SR1 6
+#define I830_DESTREG_SR2 7
+#define I830_DESTREG_DR0 8
+#define I830_DESTREG_DR1 9
+#define I830_DESTREG_DR2 10
+#define I830_DESTREG_DR3 11
+#define I830_DESTREG_DR4 12
+#define I830_DEST_SETUP_SIZE 13
+
+/* Context state
+ */
+#define I830_CTXREG_STATE1		0
+#define I830_CTXREG_STATE2		1
+#define I830_CTXREG_STATE3		2
+#define I830_CTXREG_STATE4		3
+#define I830_CTXREG_STATE5		4
+#define I830_CTXREG_IALPHAB		5
+#define I830_CTXREG_STENCILTST		6
+#define I830_CTXREG_ENABLES_1		7
+#define I830_CTXREG_ENABLES_2		8
+#define I830_CTXREG_AA			9
+#define I830_CTXREG_FOGCOLOR		10
+#define I830_CTXREG_BLENDCOLR0		11
+#define I830_CTXREG_BLENDCOLR		12 /* Dword 1 of 2 dword command */
+#define I830_CTXREG_VF			13
+#define I830_CTXREG_VF2			14
+#define I830_CTXREG_MCSB0		15
+#define I830_CTXREG_MCSB1		16
+#define I830_CTX_SETUP_SIZE		17
+
+/* Texture state (per tex unit)
+ */
+
+#define I830_TEXREG_MI0	0	/* GFX_OP_MAP_INFO (6 dwords) */
+#define I830_TEXREG_MI1	1
+#define I830_TEXREG_MI2	2
+#define I830_TEXREG_MI3	3
+#define I830_TEXREG_MI4	4
+#define I830_TEXREG_MI5	5
+#define I830_TEXREG_MF	6	/* GFX_OP_MAP_FILTER */
+#define I830_TEXREG_MLC	7	/* GFX_OP_MAP_LOD_CTL */
+#define I830_TEXREG_MLL	8	/* GFX_OP_MAP_LOD_LIMITS */
+#define I830_TEXREG_MCS	9	/* GFX_OP_MAP_COORD_SETS */
+#define I830_TEX_SETUP_SIZE 10
+
+#define I830_FRONT   0x1
+#define I830_BACK    0x2
+#define I830_DEPTH   0x4
+
+#endif /* _I830_DEFINES_ */
+
+typedef struct _drm_i830_init {
+	enum {
+		I830_INIT_DMA = 0x01,
+		I830_CLEANUP_DMA = 0x02
+	} func;
+	unsigned int mmio_offset;
+	unsigned int buffers_offset;
+	int sarea_priv_offset;
+	unsigned int ring_start;
+	unsigned int ring_end;
+	unsigned int ring_size;
+	unsigned int front_offset;
+	unsigned int back_offset;
+	unsigned int depth_offset;
+	unsigned int w;
+	unsigned int h;
+	unsigned int pitch;
+	unsigned int pitch_bits;
+	unsigned int back_pitch;
+	unsigned int depth_pitch;
+	unsigned int cpp;
+} drm_i830_init_t;
+
+/* Warning: If you change the SAREA structure you must change the Xserver
+ * structure as well */
+
+typedef struct _drm_i830_tex_region {
+	unsigned char next, prev; /* indices to form a circular LRU  */
+	unsigned char in_use;	/* owned by a client, or free? */
+	int age;		/* tracked by clients to update local LRU's */
+} drm_i830_tex_region_t;
+
+typedef struct _drm_i830_sarea {
+	unsigned int ContextState[I830_CTX_SETUP_SIZE];
+   	unsigned int BufferState[I830_DEST_SETUP_SIZE];
+	unsigned int TexState[I830_TEXTURE_COUNT][I830_TEX_SETUP_SIZE];
+	unsigned int TexBlendState[I830_TEXBLEND_COUNT][I830_TEXBLEND_SIZE];
+	unsigned int TexBlendStateWordsUsed[I830_TEXBLEND_COUNT];
+	unsigned int Palette[2][256];
+   	unsigned int dirty;
+
+	unsigned int nbox;
+	drm_clip_rect_t boxes[I830_NR_SAREA_CLIPRECTS];
+
+	/* Maintain an LRU of contiguous regions of texture space.  If
+	 * you think you own a region of texture memory, and it has an
+	 * age different to the one you set, then you are mistaken and
+	 * it has been stolen by another client.  If global texAge
+	 * hasn't changed, there is no need to walk the list.
+	 *
+	 * These regions can be used as a proxy for the fine-grained
+	 * texture information of other clients - by maintaining them
+	 * in the same lru which is used to age their own textures,
+	 * clients have an approximate lru for the whole of global
+	 * texture space, and can make informed decisions as to which
+	 * areas to kick out.  There is no need to choose whether to
+	 * kick out your own texture or someone else's - simply eject
+	 * them all in LRU order.  
+	 */
+
+	drm_i830_tex_region_t texList[I830_NR_TEX_REGIONS+1]; 
+				/* Last elt is sentinal */
+        int texAge;		/* last time texture was uploaded */
+        int last_enqueue;	/* last time a buffer was enqueued */
+	int last_dispatch;	/* age of the most recently dispatched buffer */
+	int last_quiescent;     /*  */
+	int ctxOwner;		/* last context to upload state */
+
+	int vertex_prim;
+} drm_i830_sarea_t;
+
+typedef struct _drm_i830_clear {
+	int clear_color;
+	int clear_depth;
+	int flags;
+	unsigned int clear_colormask;
+	unsigned int clear_depthmask;
+} drm_i830_clear_t;
+
+
+
+/* These may be placeholders if we have more cliprects than
+ * I830_NR_SAREA_CLIPRECTS.  In that case, the client sets discard to
+ * false, indicating that the buffer will be dispatched again with a
+ * new set of cliprects.
+ */
+typedef struct _drm_i830_vertex {
+   	int idx;		/* buffer index */
+	int used;		/* nr bytes in use */
+	int discard;		/* client is finished with the buffer? */
+} drm_i830_vertex_t;
+
+typedef struct _drm_i830_copy_t {
+   	int idx;		/* buffer index */
+	int used;		/* nr bytes in use */
+	void *address;		/* Address to copy from */
+} drm_i830_copy_t;
+
+typedef struct drm_i830_dma {
+	void *virtual;
+	int request_idx;
+	int request_size;
+	int granted;
+} drm_i830_dma_t;
+
+#endif /* _I830_DRM_H_ */
diff -urN linux-2.4.20-pre4/drivers/char/drm/i830_drv.c linux-2.4.20-pre5/drivers/char/drm/i830_drv.c
--- linux-2.4.20-pre4/drivers/char/drm/i830_drv.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre5/drivers/char/drm/i830_drv.c	Wed Aug 28 16:37:49 2002
@@ -0,0 +1,102 @@
+/* i830_drv.c -- I810 driver -*- linux-c -*-
+ * Created: Mon Dec 13 01:56:22 1999 by jhartmann@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ *    Jeff Hartmann <jhartmann@valinux.com>
+ *    Gareth Hughes <gareth@valinux.com>
+ *    Abraham vd Merwe <abraham@2d3d.co.za>
+ */
+
+#include <linux/config.h>
+#include "i830.h"
+#include "drmP.h"
+#include "i830_drv.h"
+
+#define DRIVER_AUTHOR		"VA Linux Systems Inc."
+
+#define DRIVER_NAME		"i830"
+#define DRIVER_DESC		"Intel 830M"
+#define DRIVER_DATE		"20011004"
+
+#define DRIVER_MAJOR		1
+#define DRIVER_MINOR		2
+#define DRIVER_PATCHLEVEL	0
+
+#define DRIVER_IOCTLS							    \
+	[DRM_IOCTL_NR(DRM_IOCTL_I830_INIT)]   = { i830_dma_init,    1, 1 }, \
+   	[DRM_IOCTL_NR(DRM_IOCTL_I830_VERTEX)] = { i830_dma_vertex,  1, 0 }, \
+   	[DRM_IOCTL_NR(DRM_IOCTL_I830_CLEAR)]  = { i830_clear_bufs,  1, 0 }, \
+      	[DRM_IOCTL_NR(DRM_IOCTL_I830_FLUSH)]  = { i830_flush_ioctl, 1, 0 }, \
+   	[DRM_IOCTL_NR(DRM_IOCTL_I830_GETAGE)] = { i830_getage,      1, 0 }, \
+	[DRM_IOCTL_NR(DRM_IOCTL_I830_GETBUF)] = { i830_getbuf,      1, 0 }, \
+   	[DRM_IOCTL_NR(DRM_IOCTL_I830_SWAP)]   = { i830_swap_bufs,   1, 0 }, \
+   	[DRM_IOCTL_NR(DRM_IOCTL_I830_COPY)]   = { i830_copybuf,     1, 0 }, \
+   	[DRM_IOCTL_NR(DRM_IOCTL_I830_DOCOPY)] = { i830_docopy,      1, 0 },
+
+#define __HAVE_COUNTERS         4
+#define __HAVE_COUNTER6         _DRM_STAT_IRQ
+#define __HAVE_COUNTER7         _DRM_STAT_PRIMARY
+#define __HAVE_COUNTER8         _DRM_STAT_SECONDARY
+#define __HAVE_COUNTER9         _DRM_STAT_DMA
+
+
+#include "drm_agpsupport.h"
+#include "drm_auth.h"
+#include "drm_bufs.h"
+#include "drm_context.h"
+#include "drm_dma.h"
+#include "drm_drawable.h"
+#include "drm_drv.h"
+
+#ifndef MODULE
+/* DRM(options) is called by the kernel to parse command-line options
+ * passed via the boot-loader (e.g., LILO).  It calls the insmod option
+ * routine, drm_parse_drm.
+ */
+
+/* JH- We have to hand expand the string ourselves because of the cpp.  If
+ * anyone can think of a way that we can fit into the __setup macro without
+ * changing it, then please send the solution my way.
+ */
+static int __init i830_options( char *str )
+{
+   DRM(parse_options)( str );
+   return 1;
+}
+
+__setup( DRIVER_NAME "=", i830_options );
+#endif
+
+#include "drm_fops.h"
+#include "drm_init.h"
+#include "drm_ioctl.h"
+#include "drm_lock.h"
+#include "drm_lists.h"
+#include "drm_memory.h"
+#include "drm_proc.h"
+#include "drm_vm.h"
+#include "drm_stub.h"
diff -urN linux-2.4.20-pre4/drivers/char/drm/i830_drv.h linux-2.4.20-pre5/drivers/char/drm/i830_drv.h
--- linux-2.4.20-pre4/drivers/char/drm/i830_drv.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre5/drivers/char/drm/i830_drv.h	Wed Aug 28 16:37:49 2002
@@ -0,0 +1,215 @@
+/* i830_drv.h -- Private header for the I830 driver -*- linux-c -*-
+ * Created: Mon Dec 13 01:50:01 1999 by jhartmann@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
+ * 	    Jeff Hartmann <jhartmann@valinux.com>
+ *
+ */
+
+#ifndef _I830_DRV_H_
+#define _I830_DRV_H_
+
+typedef struct drm_i830_buf_priv {
+   	u32 *in_use;
+   	int my_use_idx;
+	int currently_mapped;
+	void *virtual;
+	void *kernel_virtual;
+	int map_count;
+   	struct vm_area_struct *vma;
+} drm_i830_buf_priv_t;
+
+typedef struct _drm_i830_ring_buffer{
+	int tail_mask;
+	unsigned long Start;
+	unsigned long End;
+	unsigned long Size;
+	u8 *virtual_start;
+	int head;
+	int tail;
+	int space;
+} drm_i830_ring_buffer_t;
+
+typedef struct drm_i830_private {
+	drm_map_t *sarea_map;
+	drm_map_t *buffer_map;
+	drm_map_t *mmio_map;
+
+	drm_i830_sarea_t *sarea_priv;
+   	drm_i830_ring_buffer_t ring;
+
+      	u8 *hw_status_page;
+   	unsigned long counter;
+   	
+   	dma_addr_t dma_status_page;
+
+   	atomic_t flush_done;
+   	wait_queue_head_t flush_queue;	/* Processes waiting until flush    */
+	drm_buf_t *mmap_buffer;
+	
+	u32 front_di1, back_di1, zi1;
+	
+	int back_offset;
+	int depth_offset;
+	int w, h;
+	int pitch;
+	int back_pitch;
+	int depth_pitch;
+	unsigned int cpp;
+} drm_i830_private_t;
+
+				/* i830_dma.c */
+extern int  i830_dma_schedule(drm_device_t *dev, int locked);
+extern int  i830_getbuf(struct inode *inode, struct file *filp,
+			unsigned int cmd, unsigned long arg);
+extern int  i830_dma_init(struct inode *inode, struct file *filp,
+			  unsigned int cmd, unsigned long arg);
+extern int  i830_flush_ioctl(struct inode *inode, struct file *filp,
+			     unsigned int cmd, unsigned long arg);
+extern void i830_reclaim_buffers(drm_device_t *dev, pid_t pid);
+extern int  i830_getage(struct inode *inode, struct file *filp, unsigned int cmd,
+			unsigned long arg);
+extern int i830_mmap_buffers(struct file *filp, struct vm_area_struct *vma);
+extern int i830_copybuf(struct inode *inode, struct file *filp, 
+			unsigned int cmd, unsigned long arg);
+extern int i830_docopy(struct inode *inode, struct file *filp, 
+		       unsigned int cmd, unsigned long arg);
+
+extern void i830_dma_quiescent(drm_device_t *dev);
+
+extern int i830_dma_vertex(struct inode *inode, struct file *filp,
+			  unsigned int cmd, unsigned long arg);
+
+extern int i830_swap_bufs(struct inode *inode, struct file *filp,
+			 unsigned int cmd, unsigned long arg);
+
+extern int i830_clear_bufs(struct inode *inode, struct file *filp,
+			  unsigned int cmd, unsigned long arg);
+
+#define I830_VERBOSE 0
+
+#define I830_BASE(reg)		((unsigned long) \
+				dev_priv->mmio_map->handle)
+#define I830_ADDR(reg)		(I830_BASE(reg) + reg)
+#define I830_DEREF(reg)		*(__volatile__ int *)I830_ADDR(reg)
+#define I830_READ(reg)		I830_DEREF(reg)
+#define I830_WRITE(reg,val) 	do { I830_DEREF(reg) = val; } while (0)
+#define I830_DEREF16(reg)	*(__volatile__ u16 *)I830_ADDR(reg)
+#define I830_READ16(reg) 	I830_DEREF16(reg)
+#define I830_WRITE16(reg,val)	do { I830_DEREF16(reg) = val; } while (0)
+
+#define GFX_OP_USER_INTERRUPT 		((0<<29)|(2<<23))
+#define GFX_OP_BREAKPOINT_INTERRUPT	((0<<29)|(1<<23))
+#define CMD_REPORT_HEAD			(7<<23)
+#define CMD_STORE_DWORD_IDX		((0x21<<23) | 0x1)
+#define CMD_OP_BATCH_BUFFER  ((0x0<<29)|(0x30<<23)|0x1)
+
+#define INST_PARSER_CLIENT   0x00000000
+#define INST_OP_FLUSH        0x02000000
+#define INST_FLUSH_MAP_CACHE 0x00000001
+
+
+#define BB1_START_ADDR_MASK   (~0x7)
+#define BB1_PROTECTED         (1<<0)
+#define BB1_UNPROTECTED       (0<<0)
+#define BB2_END_ADDR_MASK     (~0x7)
+
+#define I830REG_HWSTAM		0x02098
+#define I830REG_INT_IDENTITY_R	0x020a4
+#define I830REG_INT_MASK_R 	0x020a8
+#define I830REG_INT_ENABLE_R	0x020a0
+
+#define LP_RING     		0x2030
+#define HP_RING     		0x2040
+#define RING_TAIL      		0x00
+#define TAIL_ADDR		0x000FFFF8
+#define RING_HEAD      		0x04
+#define HEAD_WRAP_COUNT     	0xFFE00000
+#define HEAD_WRAP_ONE       	0x00200000
+#define HEAD_ADDR           	0x001FFFFC
+#define RING_START     		0x08
+#define START_ADDR          	0x00FFFFF8
+#define RING_LEN       		0x0C
+#define RING_NR_PAGES       	0x000FF000 
+#define RING_REPORT_MASK    	0x00000006
+#define RING_REPORT_64K     	0x00000002
+#define RING_REPORT_128K    	0x00000004
+#define RING_NO_REPORT      	0x00000000
+#define RING_VALID_MASK     	0x00000001
+#define RING_VALID          	0x00000001
+#define RING_INVALID        	0x00000000
+
+#define GFX_OP_SCISSOR         ((0x3<<29)|(0x1c<<24)|(0x10<<19))
+#define SC_UPDATE_SCISSOR       (0x1<<1)
+#define SC_ENABLE_MASK          (0x1<<0)
+#define SC_ENABLE               (0x1<<0)
+
+#define GFX_OP_SCISSOR_INFO    ((0x3<<29)|(0x1d<<24)|(0x81<<16)|(0x1))
+#define SCI_YMIN_MASK      (0xffff<<16)
+#define SCI_XMIN_MASK      (0xffff<<0)
+#define SCI_YMAX_MASK      (0xffff<<16)
+#define SCI_XMAX_MASK      (0xffff<<0)
+
+#define GFX_OP_SCISSOR_ENABLE	 ((0x3<<29)|(0x1c<<24)|(0x10<<19))
+#define GFX_OP_SCISSOR_RECT	 ((0x3<<29)|(0x1d<<24)|(0x81<<16)|1)
+#define GFX_OP_COLOR_FACTOR      ((0x3<<29)|(0x1d<<24)|(0x1<<16)|0x0)
+#define GFX_OP_STIPPLE           ((0x3<<29)|(0x1d<<24)|(0x83<<16))
+#define GFX_OP_MAP_INFO          ((0x3<<29)|(0x1d<<24)|0x4)
+#define GFX_OP_DESTBUFFER_VARS   ((0x3<<29)|(0x1d<<24)|(0x85<<16)|0x0)
+#define GFX_OP_DRAWRECT_INFO     ((0x3<<29)|(0x1d<<24)|(0x80<<16)|(0x3))
+#define GFX_OP_PRIMITIVE         ((0x3<<29)|(0x1f<<24))
+
+#define CMD_OP_DESTBUFFER_INFO	 ((0x3<<29)|(0x1d<<24)|(0x8e<<16)|1)
+
+
+#define BR00_BITBLT_CLIENT   0x40000000
+#define BR00_OP_COLOR_BLT    0x10000000
+#define BR00_OP_SRC_COPY_BLT 0x10C00000
+#define BR13_SOLID_PATTERN   0x80000000
+
+#define BUF_3D_ID_COLOR_BACK    (0x3<<24)
+#define BUF_3D_ID_DEPTH         (0x7<<24)
+#define BUF_3D_USE_FENCE        (1<<23)
+#define BUF_3D_PITCH(x)         (((x)/4)<<2)
+
+#define CMD_OP_MAP_PALETTE_LOAD	((3<<29)|(0x1d<<24)|(0x82<<16)|255)
+#define MAP_PALETTE_NUM(x)	((x<<8) & (1<<8))
+#define MAP_PALETTE_BOTH	(1<<11)
+
+#define XY_COLOR_BLT_CMD		((2<<29)|(0x50<<22)|0x4)
+#define XY_COLOR_BLT_WRITE_ALPHA	(1<<21)
+#define XY_COLOR_BLT_WRITE_RGB		(1<<20)
+
+#define XY_SRC_COPY_BLT_CMD             ((2<<29)|(0x53<<22)|6)
+#define XY_SRC_COPY_BLT_WRITE_ALPHA     (1<<21)
+#define XY_SRC_COPY_BLT_WRITE_RGB       (1<<20)
+
+#define MI_BATCH_BUFFER 	((0x30<<23)|1)
+#define MI_BATCH_NON_SECURE	(1)
+
+
+#endif
+
diff -urN linux-2.4.20-pre4/drivers/char/drm/mga_dma.c linux-2.4.20-pre5/drivers/char/drm/mga_dma.c
--- linux-2.4.20-pre4/drivers/char/drm/mga_dma.c	Wed Aug  8 09:42:15 2001
+++ linux-2.4.20-pre5/drivers/char/drm/mga_dma.c	Wed Aug 28 16:37:49 2002
@@ -33,7 +33,6 @@
  *    Gareth Hughes <gareth@valinux.com>
  */
 
-#define __NO_VERSION__
 #include "mga.h"
 #include "drmP.h"
 #include "mga_drv.h"
diff -urN linux-2.4.20-pre4/drivers/char/drm/mga_drv.h linux-2.4.20-pre5/drivers/char/drm/mga_drv.h
--- linux-2.4.20-pre4/drivers/char/drm/mga_drv.h	Wed Aug 28 16:36:47 2002
+++ linux-2.4.20-pre5/drivers/char/drm/mga_drv.h	Wed Aug 28 16:37:49 2002
@@ -213,7 +213,7 @@
 		} else if ( dev_priv->prim.space <			\
 			    dev_priv->prim.high_mark ) {		\
 			if ( MGA_DMA_DEBUG )				\
-				DRM_INFO( __FUNCTION__": wrap...\n" );	\
+				DRM_INFO( "%s: wrap...\n", __FUNCTION__ );	\
 			return -EBUSY;					\
 		}							\
 	}								\
@@ -224,7 +224,7 @@
 	if ( test_bit( 0, &dev_priv->prim.wrapped ) ) {			\
 		if ( mga_do_wait_for_idle( dev_priv ) < 0 ) {		\
 			if ( MGA_DMA_DEBUG )				\
-				DRM_INFO( __FUNCTION__": wrap...\n" );	\
+				DRM_INFO( "%s: wrap...\n", __FUNCTION__ );	\
 			return -EBUSY;					\
 		}							\
 		mga_do_dma_wrap_end( dev_priv );			\
@@ -276,7 +276,7 @@
 #define FLUSH_DMA()							\
 do {									\
 	if ( 0 ) {							\
-		DRM_INFO( __FUNCTION__ ":\n" );				\
+		DRM_INFO( "%s:\n" , __FUNCTION__);			\
 		DRM_INFO( "   tail=0x%06x head=0x%06lx\n",		\
 			  dev_priv->prim.tail,				\
 			  MGA_READ( MGA_PRIMADDRESS ) -			\
diff -urN linux-2.4.20-pre4/drivers/char/drm/mga_state.c linux-2.4.20-pre5/drivers/char/drm/mga_state.c
--- linux-2.4.20-pre4/drivers/char/drm/mga_state.c	Wed Aug  8 09:42:15 2001
+++ linux-2.4.20-pre5/drivers/char/drm/mga_state.c	Wed Aug 28 16:37:49 2002
@@ -32,7 +32,6 @@
  *    Gareth Hughes <gareth@valinux.com>
  */
 
-#define __NO_VERSION__
 #include "mga.h"
 #include "drmP.h"
 #include "mga_drv.h"
@@ -513,7 +512,7 @@
 	int nbox = sarea_priv->nbox;
 	int i;
 	DMA_LOCALS;
-	DRM_DEBUG( __FUNCTION__ ":\n" );
+	DRM_DEBUG("%s:\n" , __FUNCTION__);
 
 	BEGIN_DMA( 1 );
 
@@ -607,7 +606,7 @@
 	int nbox = sarea_priv->nbox;
 	int i;
 	DMA_LOCALS;
-	DRM_DEBUG( __FUNCTION__ ":\n" );
+	DRM_DEBUG( "%s:\n", __FUNCTION__ );
 
 	sarea_priv->last_frame.head = dev_priv->prim.tail;
 	sarea_priv->last_frame.wrap = dev_priv->prim.last_wrap;
@@ -816,7 +815,7 @@
 	int nbox = sarea_priv->nbox;
 	u32 scandir = 0, i;
 	DMA_LOCALS;
-	DRM_DEBUG( __FUNCTION__ ":\n" );
+	DRM_DEBUG( "%s:\n", __FUNCTION__ );
 
 	BEGIN_DMA( 4 + nbox );
 
@@ -1019,7 +1018,7 @@
 	drm_buf_t *buf;
 	drm_mga_buf_priv_t *buf_priv;
 	drm_mga_iload_t iload;
-	DRM_DEBUG( __FUNCTION__ ":\n" );
+	DRM_DEBUG( "%s:\n", __FUNCTION__ );
 
 	LOCK_TEST_WITH_RETURN( dev );
 
@@ -1029,7 +1028,7 @@
 #if 0
 	if ( mga_do_wait_for_idle( dev_priv ) < 0 ) {
 		if ( MGA_DMA_DEBUG )
-			DRM_INFO( __FUNCTION__": -EBUSY\n" );
+			DRM_INFO( "%s: -EBUSY\n" , __FUNCTION__);
 		return -EBUSY;
 	}
 #endif
diff -urN linux-2.4.20-pre4/drivers/char/drm/mga_warp.c linux-2.4.20-pre5/drivers/char/drm/mga_warp.c
--- linux-2.4.20-pre4/drivers/char/drm/mga_warp.c	Wed Aug  8 09:42:15 2001
+++ linux-2.4.20-pre5/drivers/char/drm/mga_warp.c	Wed Aug 28 16:37:49 2002
@@ -27,7 +27,6 @@
  *    Gareth Hughes <gareth@valinux.com>
  */
 
-#define __NO_VERSION__
 #include "mga.h"
 #include "drmP.h"
 #include "mga_drv.h"
diff -urN linux-2.4.20-pre4/drivers/char/drm/r128_cce.c linux-2.4.20-pre5/drivers/char/drm/r128_cce.c
--- linux-2.4.20-pre4/drivers/char/drm/r128_cce.c	Mon Aug 27 07:40:33 2001
+++ linux-2.4.20-pre5/drivers/char/drm/r128_cce.c	Wed Aug 28 16:37:49 2002
@@ -28,7 +28,6 @@
  *    Gareth Hughes <gareth@valinux.com>
  */
 
-#define __NO_VERSION__
 #include "r128.h"
 #include "drmP.h"
 #include "r128_drv.h"
@@ -352,8 +351,8 @@
 
 		R128_WRITE( R128_PM4_BUFFER_DL_RPTR_ADDR,
      			    entry->busaddr[page_ofs]);
-		DRM_DEBUG( "ring rptr: offset=0x%08x handle=0x%08lx\n",
-			   entry->busaddr[page_ofs],
+		DRM_DEBUG( "ring rptr: offset=0x%08llx handle=0x%08lx\n",
+			   (u64)entry->busaddr[page_ofs],
      			   entry->handle + tmp_ofs );
 	}
 
diff -urN linux-2.4.20-pre4/drivers/char/drm/r128_drv.c linux-2.4.20-pre5/drivers/char/drm/r128_drv.c
--- linux-2.4.20-pre4/drivers/char/drm/r128_drv.c	Wed Aug  8 09:42:15 2001
+++ linux-2.4.20-pre5/drivers/char/drm/r128_drv.c	Wed Aug 28 16:37:49 2002
@@ -39,11 +39,11 @@
 
 #define DRIVER_NAME		"r128"
 #define DRIVER_DESC		"ATI Rage 128"
-#define DRIVER_DATE		"20010405"
+#define DRIVER_DATE		"20010917"
 
 #define DRIVER_MAJOR		2
-#define DRIVER_MINOR		1
-#define DRIVER_PATCHLEVEL	6
+#define DRIVER_MINOR		2
+#define DRIVER_PATCHLEVEL	0
 
 #define DRIVER_IOCTLS							    \
    [DRM_IOCTL_NR(DRM_IOCTL_DMA)]             = { r128_cce_buffers,  1, 0 }, \
diff -urN linux-2.4.20-pre4/drivers/char/drm/r128_drv.h linux-2.4.20-pre5/drivers/char/drm/r128_drv.h
--- linux-2.4.20-pre4/drivers/char/drm/r128_drv.h	Mon Aug 27 07:40:33 2001
+++ linux-2.4.20-pre5/drivers/char/drm/r128_drv.h	Wed Aug 28 16:37:49 2002
@@ -469,7 +469,7 @@
 		DRM_ERROR( "ring space check failed!\n" );		\
 		return -EBUSY;						\
 	}								\
- __ring_space_done:							\
+ __ring_space_done: ;							\
 } while (0)
 
 #define VB_AGE_TEST_WITH_RETURN( dev_priv )				\
diff -urN linux-2.4.20-pre4/drivers/char/drm/r128_state.c linux-2.4.20-pre5/drivers/char/drm/r128_state.c
--- linux-2.4.20-pre4/drivers/char/drm/r128_state.c	Wed Aug  8 09:42:15 2001
+++ linux-2.4.20-pre5/drivers/char/drm/r128_state.c	Wed Aug 28 16:37:49 2002
@@ -27,7 +27,6 @@
  *    Gareth Hughes <gareth@valinux.com>
  */
 
-#define __NO_VERSION__
 #include "r128.h"
 #include "drmP.h"
 #include "r128_drv.h"
@@ -1519,10 +1518,75 @@
 {
 	drm_file_t *priv = filp->private_data;
 	drm_device_t *dev = priv->dev;
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	drm_device_dma_t *dma = dev->dma;
+	drm_buf_t *buf;
+	drm_r128_buf_priv_t *buf_priv;
+	drm_r128_indirect_t indirect;
+#if 0
+	RING_LOCALS;
+#endif
 
 	LOCK_TEST_WITH_RETURN( dev );
 
-	/* Indirect buffer firing is not supported at this time.
+	if ( !dev_priv ) {
+		DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
+		return -EINVAL;
+	}
+
+	if ( copy_from_user( &indirect, (drm_r128_indirect_t *)arg,
+			     sizeof(indirect) ) )
+		return -EFAULT;
+
+	DRM_DEBUG( "indirect: idx=%d s=%d e=%d d=%d\n",
+		   indirect.idx, indirect.start,
+		   indirect.end, indirect.discard );
+
+	if ( indirect.idx < 0 || indirect.idx >= dma->buf_count ) {
+		DRM_ERROR( "buffer index %d (of %d max)\n",
+			   indirect.idx, dma->buf_count - 1 );
+		return -EINVAL;
+	}
+
+	buf = dma->buflist[indirect.idx];
+	buf_priv = buf->dev_private;
+
+	if ( buf->pid != current->pid ) {
+		DRM_ERROR( "process %d using buffer owned by %d\n",
+			   current->pid, buf->pid );
+		return -EINVAL;
+	}
+	if ( buf->pending ) {
+		DRM_ERROR( "sending pending buffer %d\n", indirect.idx );
+		return -EINVAL;
+	}
+
+	if ( indirect.start < buf->used ) {
+		DRM_ERROR( "reusing indirect: start=0x%x actual=0x%x\n",
+			   indirect.start, buf->used );
+		return -EINVAL;
+	}
+
+	RING_SPACE_TEST_WITH_RETURN( dev_priv );
+	VB_AGE_TEST_WITH_RETURN( dev_priv );
+
+	buf->used = indirect.end;
+	buf_priv->discard = indirect.discard;
+
+#if 0
+	/* Wait for the 3D stream to idle before the indirect buffer
+	 * containing 2D acceleration commands is processed.
 	 */
-	return -EINVAL;
+	BEGIN_RING( 2 );
+	RADEON_WAIT_UNTIL_3D_IDLE();
+	ADVANCE_RING();
+#endif
+
+	/* Dispatch the indirect buffer full of commands from the
+	 * X server.  This is insecure and is thus only available to
+	 * privileged clients.
+	 */
+	r128_cce_dispatch_indirect( dev, buf, indirect.start, indirect.end );
+
+	return 0;
 }
diff -urN linux-2.4.20-pre4/drivers/char/drm/radeon_cp.c linux-2.4.20-pre5/drivers/char/drm/radeon_cp.c
--- linux-2.4.20-pre4/drivers/char/drm/radeon_cp.c	Fri Sep 14 14:29:41 2001
+++ linux-2.4.20-pre5/drivers/char/drm/radeon_cp.c	Wed Aug 28 16:37:49 2002
@@ -28,7 +28,6 @@
  *    Gareth Hughes <gareth@valinux.com>
  */
 
-#define __NO_VERSION__
 #include "radeon.h"
 #include "drmP.h"
 #include "radeon_drv.h"
@@ -623,8 +622,8 @@
 
 		RADEON_WRITE( RADEON_CP_RB_RPTR_ADDR,
 			     entry->busaddr[page_ofs]);
-		DRM_DEBUG( "ring rptr: offset=0x%08x handle=0x%08lx\n",
-			   entry->busaddr[page_ofs],
+		DRM_DEBUG( "ring rptr: offset=0x%08llx handle=0x%08lx\n",
+			   (u64)entry->busaddr[page_ofs],
 			   entry->handle + tmp_ofs );
 	}
 
diff -urN linux-2.4.20-pre4/drivers/char/drm/radeon_drv.h linux-2.4.20-pre5/drivers/char/drm/radeon_drv.h
--- linux-2.4.20-pre4/drivers/char/drm/radeon_drv.h	Mon Aug 27 07:40:33 2001
+++ linux-2.4.20-pre5/drivers/char/drm/radeon_drv.h	Wed Aug 28 16:37:49 2002
@@ -660,7 +660,7 @@
 		DRM_ERROR( "ring space check failed!\n" );		\
 		return -EBUSY;						\
 	}								\
- __ring_space_done:							\
+ __ring_space_done: ;							\
 } while (0)
 
 #define VB_AGE_TEST_WITH_RETURN( dev_priv )				\
diff -urN linux-2.4.20-pre4/drivers/char/drm/radeon_state.c linux-2.4.20-pre5/drivers/char/drm/radeon_state.c
--- linux-2.4.20-pre4/drivers/char/drm/radeon_state.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/drivers/char/drm/radeon_state.c	Wed Aug 28 16:37:49 2002
@@ -27,7 +27,6 @@
  *    Kevin E. Martin <martin@valinux.com>
  */
 
-#define __NO_VERSION__
 #include "radeon.h"
 #include "drmP.h"
 #include "radeon_drv.h"
diff -urN linux-2.4.20-pre4/drivers/char/drm/sis_ds.c linux-2.4.20-pre5/drivers/char/drm/sis_ds.c
--- linux-2.4.20-pre4/drivers/char/drm/sis_ds.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/drivers/char/drm/sis_ds.c	Wed Aug 28 16:37:49 2002
@@ -28,7 +28,6 @@
  * 
  */
 
-#define __NO_VERSION__
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
diff -urN linux-2.4.20-pre4/drivers/char/drm/sis_mm.c linux-2.4.20-pre5/drivers/char/drm/sis_mm.c
--- linux-2.4.20-pre4/drivers/char/drm/sis_mm.c	Wed Aug 28 16:36:47 2002
+++ linux-2.4.20-pre5/drivers/char/drm/sis_mm.c	Wed Aug 28 16:37:49 2002
@@ -28,7 +28,6 @@
  * 
  */
 
-#define __NO_VERSION__
 #include "sis.h"
 #include <linux/sisfb.h>
 #include "drmP.h"
@@ -125,7 +124,7 @@
   if(!del_alloc_set(fb.context, VIDEO_TYPE, fb.free))
     retval = -1;
 
-  DRM_DEBUG("free fb, offset = %d\n", fb.free);
+  DRM_DEBUG("free fb, offset = %ld\n", fb.free);
   
   return retval;
 }
@@ -223,7 +222,7 @@
   if(!del_alloc_set(agp.context, AGP_TYPE, agp.free))
     retval = -1;
 
-  DRM_DEBUG("free agp, free = %d\n", agp.free);
+  DRM_DEBUG("free agp, free = %ld\n", agp.free);
   
   return retval;
 }
diff -urN linux-2.4.20-pre4/drivers/char/drm-4.0/i810_dma.c linux-2.4.20-pre5/drivers/char/drm-4.0/i810_dma.c
--- linux-2.4.20-pre4/drivers/char/drm-4.0/i810_dma.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre5/drivers/char/drm-4.0/i810_dma.c	Wed Aug 28 16:37:50 2002
@@ -83,7 +83,7 @@
 	*(volatile unsigned int *)(virt + outring) = n;			\
 	outring += 4;							\
 	outring &= ringmask;						\
-} while (0);
+} while (0)
 
 static inline void i810_print_status_page(drm_device_t *dev)
 {
@@ -279,7 +279,7 @@
 	address = __get_free_page(GFP_KERNEL);
 	if(address == 0UL) 
 		return 0;
-	
+
 	get_page(virt_to_page(address));
 	LockPage(virt_to_page(address));
    
diff -urN linux-2.4.20-pre4/drivers/char/i8k.c linux-2.4.20-pre5/drivers/char/i8k.c
--- linux-2.4.20-pre4/drivers/char/i8k.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.20-pre5/drivers/char/i8k.c	Wed Aug 28 16:37:50 2002
@@ -22,12 +22,15 @@
 #include <linux/init.h>
 #include <linux/proc_fs.h>
 #include <linux/apm_bios.h>
+#include <linux/kbd_kern.h>
+#include <linux/kbd_ll.h>
+#include <linux/timer.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
 #include <linux/i8k.h>
 
-#define I8K_VERSION		"1.7 21/11/2001"
+#define I8K_VERSION		"1.13 14/05/2002"
 
 #define I8K_SMM_FN_STATUS	0x0025
 #define I8K_SMM_POWER_STATUS	0x0069
@@ -55,6 +58,19 @@
 
 #define DELL_SIGNATURE		"Dell Computer"
 
+/* Interval between polling of keys, in jiffies. */
+#define I8K_POLL_INTERVAL	(HZ/20)
+#define I8K_REPEAT_DELAY	250	/* 250 ms */
+#define I8K_REPEAT_RATE		10
+
+/*
+ * (To be escaped) Scancodes for the keys.  These were chosen to match other
+ * "Internet" keyboards.
+ */
+#define I8K_KEYS_UP_SCANCODE	0x30
+#define I8K_KEYS_DOWN_SCANCODE	0x2e
+#define I8K_KEYS_MUTE_SCANCODE	0x20
+
 static char *supported_models[] = {
     "Inspiron",
     "Latitude",
@@ -67,19 +83,34 @@
 static char serial_number[16] = "?";
 
 int force = 0;
+int restricted = 0;
+int handle_buttons = 0;
+int repeat_delay = I8K_REPEAT_DELAY;
+int repeat_rate = I8K_REPEAT_RATE;
 int power_status = 0;
 
+static struct timer_list  i8k_keys_timer;
+
 MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)");
 MODULE_DESCRIPTION("Driver for accessing SMM BIOS on Dell laptops");
 MODULE_LICENSE("GPL");
 MODULE_PARM(force, "i");
+MODULE_PARM(restricted, "i");
+MODULE_PARM(handle_buttons, "i");
+MODULE_PARM(repeat_delay, "i");
+MODULE_PARM(repeat_rate, "i");
 MODULE_PARM(power_status, "i");
 MODULE_PARM_DESC(force, "Force loading without checking for supported models");
+MODULE_PARM_DESC(restricted, "Allow fan control if SYS_ADMIN capability set");
+MODULE_PARM_DESC(handle_buttons, "Generate keyboard events for i8k buttons");
+MODULE_PARM_DESC(repeat_delay, "I8k buttons repeat delay (ms)");
+MODULE_PARM_DESC(repeat_rate, "I8k buttons repeat rate");
 MODULE_PARM_DESC(power_status, "Report power status in /proc/i8k");
 
 static ssize_t i8k_read(struct file *, char *, size_t, loff_t *);
 static int i8k_ioctl(struct inode *, struct file *, unsigned int,
 		     unsigned long);
+static void i8k_keys_set_timer(void);
 
 static struct file_operations i8k_fops = {
     read:	i8k_read,
@@ -370,6 +401,9 @@
 	break;
 
     case I8K_SET_FAN:
+	if (restricted && !capable(CAP_SYS_ADMIN)) {
+	    return -EPERM;
+	}
 	if (copy_from_user(&val, (int *)arg, sizeof(int))) {
 	    return -EFAULT;
 	}
@@ -483,6 +517,61 @@
     return len;
 }
 
+/*
+ * i8k_keys stuff. Thanks to David Bustos <bustos@caltech.edu>
+ */
+
+static unsigned char i8k_keys_make_scancode(int x) {
+    switch (x) {
+    case I8K_FN_UP:	return I8K_KEYS_UP_SCANCODE;
+    case I8K_FN_DOWN:	return I8K_KEYS_DOWN_SCANCODE;
+    case I8K_FN_MUTE:	return I8K_KEYS_MUTE_SCANCODE;
+    }
+
+    return 0;
+}
+
+static void i8k_keys_poll(unsigned long data) {
+    static int last = 0;
+    static int repeat = 0;
+
+    int  curr;
+
+    curr = i8k_get_fn_status();
+    if (curr >= 0) {
+	if (curr != last) {
+	    repeat = jiffies + (HZ * repeat_delay / 1000);
+
+	    if (last != 0) {
+		handle_scancode(0xe0, 0);
+		handle_scancode(i8k_keys_make_scancode(last), 0);
+	    }
+
+	    if (curr != 0) {
+		handle_scancode(0xe0, 1);
+		handle_scancode(i8k_keys_make_scancode(curr), 1);
+	    }
+	} else {
+	    /* Generate keyboard repeat events with current scancode -- dz */
+	    if ((curr) && (repeat_rate > 0) && (jiffies >= repeat)) {
+		repeat = jiffies + (HZ / repeat_rate);
+		handle_scancode(0xe0, 1);
+		handle_scancode(i8k_keys_make_scancode(curr), 1);
+	    }
+	}
+
+	last = curr;
+    }
+
+    /* Reset the timer. */
+    i8k_keys_set_timer();
+}
+
+static void i8k_keys_set_timer() {
+    i8k_keys_timer.expires = jiffies + I8K_POLL_INTERVAL;
+    add_timer(&i8k_keys_timer);
+}
+
 static char* __init string_trim(char *s, int size)
 {
     int len;
@@ -757,6 +846,16 @@
 	   "Dell laptop SMM driver v%s Massimo Dal Zotto (dz@debian.org)\n",
 	   I8K_VERSION);
 
+    /* Register the i8k_keys timer. */
+    if (handle_buttons) {
+	printk(KERN_INFO
+	       "i8k: enabling buttons events, delay=%d, rate=%d\n",
+	       repeat_delay, repeat_rate);
+	init_timer(&i8k_keys_timer);
+	i8k_keys_timer.function = i8k_keys_poll;
+	i8k_keys_set_timer();
+    }
+
     return 0;
 }
 
@@ -771,6 +870,11 @@
     /* Remove the proc entry */
     remove_proc_entry("i8k", NULL);
 
+    /* Unregister the i8k_keys timer. */
+    while (handle_buttons && !del_timer(&i8k_keys_timer)) {
+	schedule_timeout(I8K_POLL_INTERVAL);
+    }
+
     printk(KERN_INFO "i8k: module unloaded\n");
 }
 #endif
diff -urN linux-2.4.20-pre4/drivers/char/synclink.c linux-2.4.20-pre5/drivers/char/synclink.c
--- linux-2.4.20-pre4/drivers/char/synclink.c	Wed Aug 28 16:36:47 2002
+++ linux-2.4.20-pre5/drivers/char/synclink.c	Wed Aug 28 16:37:51 2002
@@ -880,22 +880,22 @@
  * Global linked list of SyncLink devices
  */
 struct mgsl_struct *mgsl_device_list;
-int mgsl_device_count;
+static int mgsl_device_count;
 
 /*
  * Set this param to non-zero to load eax with the
  * .text section address and breakpoint on module load.
  * This is useful for use with gdb and add-symbol-file command.
  */
-int break_on_load;
+static int break_on_load;
 
 /*
  * Driver major number, defaults to zero to get auto
  * assigned major number. May be forced as module parameter.
  */
-int ttymajor;
+static int ttymajor;
 
-int cuamajor;
+static int cuamajor;
 
 /*
  * Array of user specified options for ISA adapters.
diff -urN linux-2.4.20-pre4/drivers/char/synclinkmp.c linux-2.4.20-pre5/drivers/char/synclinkmp.c
--- linux-2.4.20-pre4/drivers/char/synclinkmp.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre5/drivers/char/synclinkmp.c	Wed Aug 28 16:37:51 2002
@@ -0,0 +1,5611 @@
+/*
+ * $Id: synclinkmp.c,v 3.17 2002/04/22 16:05:39 paulkf Exp $
+ *
+ * Device driver for Microgate SyncLink Multiport
+ * high speed multiprotocol serial adapter.
+ *
+ * written by Paul Fulghum for Microgate Corporation
+ * paulkf@microgate.com
+ *
+ * Microgate and SyncLink are trademarks of Microgate Corporation
+ *
+ * Derived from serial.c written by Theodore Ts'o and Linus Torvalds
+ * This code is released under the GNU General Public License (GPL)
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define VERSION(ver,rel,seq) (((ver)<<16) | ((rel)<<8) | (seq))
+#if defined(__i386__)
+#  define BREAKPOINT() asm("   int $3");
+#else
+#  define BREAKPOINT() { }
+#endif
+
+#define MAX_DEVICES 12
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/netdevice.h>
+#include <linux/vmalloc.h>
+#include <linux/init.h>
+#include <asm/serial.h>
+#include <linux/delay.h>
+#include <linux/ioctl.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+#include <asm/bitops.h>
+#include <asm/types.h>
+#include <linux/termios.h>
+#include <linux/tqueue.h>
+
+#ifdef CONFIG_SYNCLINK_SYNCPPP_MODULE
+#define CONFIG_SYNCLINK_SYNCPPP 1
+#endif
+
+#ifdef CONFIG_SYNCLINK_SYNCPPP
+#include <net/syncppp.h>
+#endif
+
+#include <asm/segment.h>
+#define GET_USER(error,value,addr) error = get_user(value,addr)
+#define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0
+#define PUT_USER(error,value,addr) error = put_user(value,addr)
+#define COPY_TO_USER(error,dest,src,size) error = copy_to_user(dest,src,size) ? -EFAULT : 0
+
+#include <asm/uaccess.h>
+
+#include "linux/synclink.h"
+
+static MGSL_PARAMS default_params = {
+	MGSL_MODE_HDLC,			/* unsigned long mode */
+	0,				/* unsigned char loopback; */
+	HDLC_FLAG_UNDERRUN_ABORT15,	/* unsigned short flags; */
+	HDLC_ENCODING_NRZI_SPACE,	/* unsigned char encoding; */
+	0,				/* unsigned long clock_speed; */
+	0xff,				/* unsigned char addr_filter; */
+	HDLC_CRC_16_CCITT,		/* unsigned short crc_type; */
+	HDLC_PREAMBLE_LENGTH_8BITS,	/* unsigned char preamble_length; */
+	HDLC_PREAMBLE_PATTERN_NONE,	/* unsigned char preamble; */
+	9600,				/* unsigned long data_rate; */
+	8,				/* unsigned char data_bits; */
+	1,				/* unsigned char stop_bits; */
+	ASYNC_PARITY_NONE		/* unsigned char parity; */
+};
+
+/* size in bytes of DMA data buffers */
+#define SCABUFSIZE 	1024
+#define SCA_MEM_SIZE	0x40000
+#define SCA_BASE_SIZE   512
+#define SCA_REG_SIZE    16
+#define SCA_MAX_PORTS   4
+#define SCAMAXDESC 	128
+
+#define	BUFFERLISTSIZE	4096
+
+/* SCA-I style DMA buffer descriptor */
+typedef struct _SCADESC
+{
+	u16	next;		/* lower l6 bits of next descriptor addr */
+	u16	buf_ptr;	/* lower 16 bits of buffer addr */
+	u8	buf_base;	/* upper 8 bits of buffer addr */
+	u8	pad1;
+	u16	length;		/* length of buffer */
+	u8	status;		/* status of buffer */
+	u8	pad2;
+} SCADESC, *PSCADESC;
+
+typedef struct _SCADESC_EX
+{
+	/* device driver bookkeeping section */
+	char 	*virt_addr;    	/* virtual address of data buffer */
+	u16	phys_entry;	/* lower 16-bits of physical address of this descriptor */
+} SCADESC_EX, *PSCADESC_EX;
+
+/* The queue of BH actions to be performed */
+
+#define BH_RECEIVE  1
+#define BH_TRANSMIT 2
+#define BH_STATUS   4
+
+#define IO_PIN_SHUTDOWN_LIMIT 100
+
+#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+struct	_input_signal_events {
+	int	ri_up;
+	int	ri_down;
+	int	dsr_up;
+	int	dsr_down;
+	int	dcd_up;
+	int	dcd_down;
+	int	cts_up;
+	int	cts_down;
+};
+
+/*
+ * Device instance data structure
+ */
+typedef struct _synclinkmp_info {
+	void *if_ptr;				/* General purpose pointer (used by SPPP) */
+	int			magic;
+	int			flags;
+	int			count;		/* count of opens */
+	int			line;
+	unsigned short		close_delay;
+	unsigned short		closing_wait;	/* time to wait before closing */
+
+	struct mgsl_icount	icount;
+
+	struct termios		normal_termios;
+	struct termios		callout_termios;
+
+	struct tty_struct 	*tty;
+	int			timeout;
+	int			x_char;		/* xon/xoff character */
+	int			blocked_open;	/* # of blocked opens */
+	long			session;	/* Session of opening process */
+	long			pgrp;		/* pgrp of opening process */
+	u16			read_status_mask1;  /* break detection (SR1 indications) */
+	u16			read_status_mask2;  /* parity/framing/overun (SR2 indications) */
+	unsigned char 		ignore_status_mask1;  /* break detection (SR1 indications) */
+	unsigned char		ignore_status_mask2;  /* parity/framing/overun (SR2 indications) */
+	unsigned char 		*tx_buf;
+	int			tx_put;
+	int			tx_get;
+	int			tx_count;
+
+	wait_queue_head_t	open_wait;
+	wait_queue_head_t	close_wait;
+
+	wait_queue_head_t	status_event_wait_q;
+	wait_queue_head_t	event_wait_q;
+	struct timer_list	tx_timer;	/* HDLC transmit timeout timer */
+	struct _synclinkmp_info	*next_device;	/* device list link */
+	struct timer_list	status_timer;	/* input signal status check timer */
+
+	spinlock_t lock;		/* spinlock for synchronizing with ISR */
+	struct tq_struct task;	 		/* task structure for scheduling bh */
+
+	u32 max_frame_size;			/* as set by device config */
+
+	u32 pending_bh;
+
+	int bh_running;				/* Protection from multiple */
+	int isr_overflow;
+	int bh_requested;
+
+	int dcd_chkcount;			/* check counts to prevent */
+	int cts_chkcount;			/* too many IRQs if a signal */
+	int dsr_chkcount;			/* is floating */
+	int ri_chkcount;
+
+	char *buffer_list;			/* virtual address of Rx & Tx buffer lists */
+	unsigned long buffer_list_phys;
+
+	unsigned int rx_buf_count;		/* count of total allocated Rx buffers */
+	SCADESC *rx_buf_list;   		/* list of receive buffer entries */
+	SCADESC_EX rx_buf_list_ex[SCAMAXDESC]; /* list of receive buffer entries */
+	unsigned int current_rx_buf;
+
+	unsigned int tx_buf_count;		/* count of total allocated Tx buffers */
+	SCADESC *tx_buf_list;		/* list of transmit buffer entries */
+	SCADESC_EX tx_buf_list_ex[SCAMAXDESC]; /* list of transmit buffer entries */
+	unsigned int last_tx_buf;
+
+	unsigned char *tmp_rx_buf;
+	unsigned int tmp_rx_buf_count;
+
+	int rx_enabled;
+	int rx_overflow;
+
+	int tx_enabled;
+	int tx_active;
+	u32 idle_mode;
+
+	unsigned char ie0_value;
+	unsigned char ie1_value;
+	unsigned char ie2_value;
+	unsigned char ctrlreg_value;
+	unsigned char old_signals;
+
+	char device_name[25];			/* device instance name */
+
+	int port_count;
+	int adapter_num;
+	int port_num;
+
+	struct _synclinkmp_info *port_array[SCA_MAX_PORTS];
+
+	unsigned int bus_type;			/* expansion bus type (ISA,EISA,PCI) */
+
+	unsigned int irq_level;			/* interrupt level */
+	unsigned long irq_flags;
+	int irq_requested;			/* nonzero if IRQ requested */
+
+	MGSL_PARAMS params;			/* communications parameters */
+
+	unsigned char serial_signals;		/* current serial signal states */
+
+	int irq_occurred;			/* for diagnostics use */
+	unsigned int init_error;		/* Initialization startup error */
+
+	u32 last_mem_alloc;
+	unsigned char* memory_base;		/* shared memory address (PCI only) */
+	u32 phys_memory_base;
+    	int shared_mem_requested;
+
+	unsigned char* sca_base;		/* HD64570 SCA Memory address */
+	u32 phys_sca_base;
+	u32 sca_offset;
+	int sca_base_requested;
+
+	unsigned char* lcr_base;		/* local config registers (PCI only) */
+	u32 phys_lcr_base;
+	u32 lcr_offset;
+	int lcr_mem_requested;
+
+	unsigned char* statctrl_base;		/* status/control register memory */
+	u32 phys_statctrl_base;
+	u32 statctrl_offset;
+	int sca_statctrl_requested;
+
+	u32 misc_ctrl_value;
+	char flag_buf[MAX_ASYNC_BUFFER_SIZE];
+	char char_buf[MAX_ASYNC_BUFFER_SIZE];
+	BOOLEAN drop_rts_on_tx_done;
+
+	struct	_input_signal_events	input_signal_events;
+
+	/* SPPP/Cisco HDLC device parts */
+	int netcount;
+	int dosyncppp;
+	spinlock_t netlock;
+#ifdef CONFIG_SYNCLINK_SYNCPPP
+	struct ppp_device pppdev;
+	char netname[10];
+	struct net_device *netdev;
+	struct net_device_stats netstats;
+	struct net_device netdevice;
+#endif
+} SLMP_INFO;
+
+#define MGSL_MAGIC 0x5401
+
+/*
+ * define serial signal status change macros
+ */
+#define	MISCSTATUS_DCD_LATCHED	(SerialSignal_DCD<<8)	/* indicates change in DCD */
+#define MISCSTATUS_RI_LATCHED	(SerialSignal_RI<<8)	/* indicates change in RI */
+#define MISCSTATUS_CTS_LATCHED	(SerialSignal_CTS<<8)	/* indicates change in CTS */
+#define MISCSTATUS_DSR_LATCHED	(SerialSignal_DSR<<8)	/* change in DSR */
+
+/* Common Register macros */
+#define LPR	0x00
+#define PABR0	0x02
+#define PABR1	0x03
+#define WCRL	0x04
+#define WCRM	0x05
+#define WCRH	0x06
+#define DPCR	0x08
+#define DMER	0x09
+#define ISR0	0x10
+#define ISR1	0x11
+#define ISR2	0x12
+#define IER0	0x14
+#define IER1	0x15
+#define IER2	0x16
+#define ITCR	0x18
+#define INTVR 	0x1a
+#define IMVR	0x1c
+
+/* MSCI Register macros */
+#define TRB	0x20
+#define TRBL	0x20
+#define TRBH	0x21
+#define SR0	0x22
+#define SR1	0x23
+#define SR2	0x24
+#define SR3	0x25
+#define FST	0x26
+#define IE0	0x28
+#define IE1	0x29
+#define IE2	0x2a
+#define FIE	0x2b
+#define CMD	0x2c
+#define MD0	0x2e
+#define MD1	0x2f
+#define MD2	0x30
+#define CTL	0x31
+#define SA0	0x32
+#define SA1	0x33
+#define IDL	0x34
+#define TMC	0x35
+#define RXS	0x36
+#define TXS	0x37
+#define TRC0	0x38
+#define TRC1	0x39
+#define RRC	0x3a
+#define CST0	0x3c
+#define CST1	0x3d
+
+/* Timer Register Macros */
+#define TCNT	0x60
+#define TCNTL	0x60
+#define TCNTH	0x61
+#define TCONR	0x62
+#define TCONRL	0x62
+#define TCONRH	0x63
+#define TMCS	0x64
+#define TEPR	0x65
+
+/* DMA Controller Register macros */
+#define DAR	0x80
+#define DARL	0x80
+#define DARH	0x81
+#define DARB	0x82
+#define BAR	0x80
+#define BARL	0x80
+#define BARH	0x81
+#define BARB	0x82
+#define SAR	0x84
+#define SARL	0x84
+#define SARH	0x85
+#define SARB	0x86
+#define CPB	0x86
+#define CDA	0x88
+#define CDAL	0x88
+#define CDAH	0x89
+#define EDA	0x8a
+#define EDAL	0x8a
+#define EDAH	0x8b
+#define BFL	0x8c
+#define BFLL	0x8c
+#define BFLH	0x8d
+#define BCR	0x8e
+#define BCRL	0x8e
+#define BCRH	0x8f
+#define DSR	0x90
+#define DMR	0x91
+#define FCT	0x93
+#define DIR	0x94
+#define DCMD	0x95
+
+/* combine with timer or DMA register address */
+#define TIMER0	0x00
+#define TIMER1	0x08
+#define TIMER2	0x10
+#define TIMER3	0x18
+#define RXDMA 	0x00
+#define TXDMA 	0x20
+
+/* SCA Command Codes */
+#define NOOP		0x00
+#define TXRESET		0x01
+#define TXENABLE	0x02
+#define TXDISABLE	0x03
+#define TXCRCINIT	0x04
+#define TXCRCEXCL	0x05
+#define TXEOM		0x06
+#define TXABORT		0x07
+#define MPON		0x08
+#define TXBUFCLR	0x09
+#define RXRESET		0x11
+#define RXENABLE	0x12
+#define RXDISABLE	0x13
+#define RXCRCINIT	0x14
+#define RXREJECT	0x15
+#define SEARCHMP	0x16
+#define RXCRCEXCL	0x17
+#define RXCRCCALC	0x18
+#define CHRESET		0x21
+#define HUNT		0x31
+
+/* DMA command codes */
+#define SWABORT		0x01
+#define FEICLEAR	0x02
+
+/* IE0 */
+#define TXINTE 		BIT7
+#define RXINTE 		BIT6
+#define TXRDYE 		BIT1
+#define RXRDYE 		BIT0
+
+/* IE1 & SR1 */
+#define UDRN   	BIT7
+#define IDLE   	BIT6
+#define SYNCD  	BIT4
+#define FLGD   	BIT4
+#define CCTS   	BIT3
+#define CDCD   	BIT2
+#define BRKD   	BIT1
+#define ABTD   	BIT1
+#define GAPD   	BIT1
+#define BRKE   	BIT0
+#define IDLD	BIT0
+
+/* IE2 & SR2 */
+#define EOM	BIT7
+#define PMP	BIT6
+#define SHRT	BIT6
+#define PE	BIT5
+#define ABT	BIT5
+#define FRME	BIT4
+#define RBIT	BIT4
+#define OVRN	BIT3
+#define CRCE	BIT2
+
+
+#define jiffies_from_ms(a) ((((a) * HZ)/1000)+1)
+
+/*
+ * Global linked list of SyncLink devices
+ */
+static SLMP_INFO *synclinkmp_device_list = NULL;
+static int synclinkmp_adapter_count = -1;
+static int synclinkmp_device_count = 0;
+
+/*
+ * Set this param to non-zero to load eax with the
+ * .text section address and breakpoint on module load.
+ * This is useful for use with gdb and add-symbol-file command.
+ */
+static int break_on_load=0;
+
+/*
+ * Driver major number, defaults to zero to get auto
+ * assigned major number. May be forced as module parameter.
+ */
+static int ttymajor=0;
+static int cuamajor=0;
+
+/*
+ * Array of user specified options for ISA adapters.
+ */
+static int debug_level = 0;
+static int maxframe[MAX_DEVICES] = {0,};
+static int dosyncppp[MAX_DEVICES] = {0,};
+
+MODULE_PARM(break_on_load,"i");
+MODULE_PARM(ttymajor,"i");
+MODULE_PARM(cuamajor,"i");
+MODULE_PARM(debug_level,"i");
+MODULE_PARM(maxframe,"1-" __MODULE_STRING(MAX_DEVICES) "i");
+MODULE_PARM(dosyncppp,"1-" __MODULE_STRING(MAX_DEVICES) "i");
+
+static char *driver_name = "SyncLink MultiPort driver";
+static char *driver_version = "$Revision: 3.17 $";
+
+static int __init synclinkmp_init_one(struct pci_dev *dev,const struct pci_device_id *ent);
+static void __exit synclinkmp_remove_one(struct pci_dev *dev);
+
+static struct pci_device_id synclinkmp_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_MICROGATE, PCI_DEVICE_ID_MICROGATE_SCA, PCI_ANY_ID, PCI_ANY_ID, },
+	{ 0, }, /* terminate list */
+};
+MODULE_DEVICE_TABLE(pci, synclinkmp_pci_tbl);
+
+static struct pci_driver synclinkmp_pci_driver = {
+	name:		"synclinkmp",
+	id_table:	synclinkmp_pci_tbl,
+	probe:		synclinkmp_init_one,
+	remove:		synclinkmp_remove_one,
+};
+
+
+static struct tty_driver serial_driver, callout_driver;
+static int serial_refcount;
+
+/* number of characters left in xmit buffer before we ask for more */
+#define WAKEUP_CHARS 256
+
+static struct tty_struct *serial_table[MAX_DEVICES];
+static struct termios *serial_termios[MAX_DEVICES];
+static struct termios *serial_termios_locked[MAX_DEVICES];
+
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+
+/* tty callbacks */
+
+static int  open(struct tty_struct *tty, struct file * filp);
+static void close(struct tty_struct *tty, struct file * filp);
+static void hangup(struct tty_struct *tty);
+static void set_termios(struct tty_struct *tty, struct termios *old_termios);
+
+static int  write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count);
+static void put_char(struct tty_struct *tty, unsigned char ch);
+static void send_xchar(struct tty_struct *tty, char ch);
+static void wait_until_sent(struct tty_struct *tty, int timeout);
+static int  write_room(struct tty_struct *tty);
+static void flush_chars(struct tty_struct *tty);
+static void flush_buffer(struct tty_struct *tty);
+static void tx_hold(struct tty_struct *tty);
+static void tx_release(struct tty_struct *tty);
+
+static int  ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg);
+static int  read_proc(char *page, char **start, off_t off, int count,int *eof, void *data);
+static int  chars_in_buffer(struct tty_struct *tty);
+static void throttle(struct tty_struct * tty);
+static void unthrottle(struct tty_struct * tty);
+static void set_break(struct tty_struct *tty, int break_state);
+
+/* sppp support and callbacks */
+
+#ifdef CONFIG_SYNCLINK_SYNCPPP
+static void sppp_init(SLMP_INFO *info);
+static void sppp_delete(SLMP_INFO *info);
+static void sppp_rx_done(SLMP_INFO *info, char *buf, int size);
+static void sppp_tx_done(SLMP_INFO *info);
+
+static int  sppp_cb_open(struct net_device *d);
+static int  sppp_cb_close(struct net_device *d);
+static int  sppp_cb_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+static int  sppp_cb_tx(struct sk_buff *skb, struct net_device *dev);
+static void sppp_cb_tx_timeout(struct net_device *dev);
+static struct net_device_stats *sppp_cb_net_stats(struct net_device *dev);
+#endif
+
+/* ioctl handlers */
+
+static int  get_stats(SLMP_INFO *info, struct mgsl_icount *user_icount);
+static int  get_params(SLMP_INFO *info, MGSL_PARAMS *params);
+static int  set_params(SLMP_INFO *info, MGSL_PARAMS *params);
+static int  get_txidle(SLMP_INFO *info, int*idle_mode);
+static int  set_txidle(SLMP_INFO *info, int idle_mode);
+static int  tx_enable(SLMP_INFO *info, int enable);
+static int  tx_abort(SLMP_INFO *info);
+static int  rx_enable(SLMP_INFO *info, int enable);
+static int  map_status(int signals);
+static int  modem_input_wait(SLMP_INFO *info,int arg);
+static int  wait_mgsl_event(SLMP_INFO *info, int *mask_ptr);
+static int  get_modem_info(SLMP_INFO *info, unsigned int *value);
+static int  set_modem_info(SLMP_INFO *info, unsigned int cmd,unsigned int *value);
+static void set_break(struct tty_struct *tty, int break_state);
+
+static void add_device(SLMP_INFO *info);
+static void device_init(int adapter_num, struct pci_dev *pdev);
+static int  claim_resources(SLMP_INFO *info);
+static void release_resources(SLMP_INFO *info);
+
+static int  startup(SLMP_INFO *info);
+static int  block_til_ready(struct tty_struct *tty, struct file * filp,SLMP_INFO *info);
+static void shutdown(SLMP_INFO *info);
+static void program_hw(SLMP_INFO *info);
+static void change_params(SLMP_INFO *info);
+
+static int  init_adapter(SLMP_INFO *info);
+static int  register_test(SLMP_INFO *info);
+static int  irq_test(SLMP_INFO *info);
+static int  loopback_test(SLMP_INFO *info);
+static int  adapter_test(SLMP_INFO *info);
+static int  memory_test(SLMP_INFO *info);
+
+static void reset_adapter(SLMP_INFO *info);
+static void reset_port(SLMP_INFO *info);
+static void async_mode(SLMP_INFO *info);
+static void hdlc_mode(SLMP_INFO *info);
+
+static void rx_stop(SLMP_INFO *info);
+static void rx_start(SLMP_INFO *info);
+static void rx_reset_buffers(SLMP_INFO *info);
+static void rx_free_frame_buffers(SLMP_INFO *info, unsigned int first, unsigned int last);
+static int  rx_get_frame(SLMP_INFO *info);
+
+static void tx_start(SLMP_INFO *info);
+static void tx_stop(SLMP_INFO *info);
+static void tx_load_fifo(SLMP_INFO *info);
+static void tx_set_idle(SLMP_INFO *info);
+static void tx_load_dma_buffer(SLMP_INFO *info, const char *buf, unsigned int count);
+
+static void get_signals(SLMP_INFO *info);
+static void set_signals(SLMP_INFO *info);
+static void enable_loopback(SLMP_INFO *info, int enable);
+static void set_rate(SLMP_INFO *info, u32 data_rate);
+
+static int  bh_action(SLMP_INFO *info);
+static void bh_handler(void* Context);
+static void bh_receive(SLMP_INFO *info);
+static void bh_transmit(SLMP_INFO *info);
+static void bh_status(SLMP_INFO *info);
+static void isr_timer(SLMP_INFO *info);
+static void isr_rxint(SLMP_INFO *info);
+static void isr_rxrdy(SLMP_INFO *info);
+static void isr_txint(SLMP_INFO *info);
+static void isr_txrdy(SLMP_INFO *info);
+static void isr_rxdmaok(SLMP_INFO *info);
+static void isr_rxdmaerror(SLMP_INFO *info);
+static void isr_txdmaok(SLMP_INFO *info);
+static void isr_txdmaerror(SLMP_INFO *info);
+static void isr_io_pin(SLMP_INFO *info, u16 status);
+static void synclinkmp_interrupt(int irq, void *dev_id, struct pt_regs * regs);
+
+static int  alloc_dma_bufs(SLMP_INFO *info);
+static void free_dma_bufs(SLMP_INFO *info);
+static int  alloc_buf_list(SLMP_INFO *info);
+static int  alloc_frame_bufs(SLMP_INFO *info, SCADESC *list, SCADESC_EX *list_ex,int count);
+static int  alloc_tmp_rx_buf(SLMP_INFO *info);
+static void free_tmp_rx_buf(SLMP_INFO *info);
+
+static void load_pci_memory(SLMP_INFO *info, char* dest, const char* src, unsigned short count);
+static void trace_block(SLMP_INFO *info, const char* data, int count, int xmit);
+static void tx_timeout(unsigned long context);
+static void status_timeout(unsigned long context);
+
+static unsigned char read_reg(SLMP_INFO *info, unsigned char addr);
+static void write_reg(SLMP_INFO *info, unsigned char addr, unsigned char val);
+static u16 read_reg16(SLMP_INFO *info, unsigned char addr);
+static void write_reg16(SLMP_INFO *info, unsigned char addr, u16 val);
+static unsigned char read_status_reg(SLMP_INFO * info);
+static void write_control_reg(SLMP_INFO * info);
+
+
+static unsigned char rx_active_fifo_level = 16;	// rx request FIFO activation level in bytes
+static unsigned char tx_active_fifo_level = 16;	// tx request FIFO activation level in bytes
+static unsigned char tx_negate_fifo_level = 32;	// tx request FIFO negation level in bytes
+
+static u32 misc_ctrl_value = 0x007e4040;
+static u32 lcr1_brdr_value = 0x0080002d;
+
+static u32 read_ahead_count = 8;
+
+/* DPCR, DMA Priority Control
+ *
+ * 07..05  Not used, must be 0
+ * 04      BRC, bus release condition: 0=all transfers complete
+ *              1=release after 1 xfer on all channels
+ * 03      CCC, channel change condition: 0=every cycle
+ *              1=after each channel completes all xfers
+ * 02..00  PR<2..0>, priority 100=round robin
+ *
+ * 00000100 = 0x00
+ */
+static unsigned char dma_priority = 0x04;
+
+// Number of bytes that can be written to shared RAM
+// in a single write operation
+static u32 sca_pci_load_interval = 64;
+
+/*
+ * 1st function defined in .text section. Calling this function in
+ * init_module() followed by a breakpoint allows a remote debugger
+ * (gdb) to get the .text address for the add-symbol-file command.
+ * This allows remote debugging of dynamically loadable modules.
+ */
+static void* synclinkmp_get_text_ptr(void);
+static void* synclinkmp_get_text_ptr() {return synclinkmp_get_text_ptr;}
+
+static inline int sanity_check(SLMP_INFO *info,
+			       kdev_t device, const char *routine)
+{
+#ifdef SANITY_CHECK
+	static const char *badmagic =
+		"Warning: bad magic number for synclinkmp_struct (%s) in %s\n";
+	static const char *badinfo =
+		"Warning: null synclinkmp_struct for (%s) in %s\n";
+
+	if (!info) {
+		printk(badinfo, kdevname(device), routine);
+		return 1;
+	}
+	if (info->magic != MGSL_MAGIC) {
+		printk(badmagic, kdevname(device), routine);
+		return 1;
+	}
+#endif
+	return 0;
+}
+
+/* tty callbacks */
+
+/* Called when a port is opened.  Init and enable port.
+ */
+static int open(struct tty_struct *tty, struct file *filp)
+{
+	SLMP_INFO *info;
+	int retval, line;
+	unsigned long flags;
+
+	line = MINOR(tty->device) - tty->driver.minor_start;
+	if ((line < 0) || (line >= synclinkmp_device_count)) {
+		printk("%s(%d): open with illegal line #%d.\n",
+			__FILE__,__LINE__,line);
+		return -ENODEV;
+	}
+
+	info = synclinkmp_device_list;
+	while(info && info->line != line)
+		info = info->next_device;
+	if ( !info ){
+		printk("%s(%d):%s Can't find specified device on open (line=%d)\n",
+			__FILE__,__LINE__,info->device_name,line);
+		return -ENODEV;
+	}
+
+	if ( info->init_error ) {
+		printk("%s(%d):%s device is not allocated, init error=%d\n",
+			__FILE__,__LINE__,info->device_name,info->init_error);
+		return -ENODEV;
+	}
+
+	tty->driver_data = info;
+	info->tty = tty;
+	if (sanity_check(info, tty->device, "open"))
+		return -ENODEV;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s open(), old ref count = %d\n",
+			 __FILE__,__LINE__,tty->driver.name, info->count);
+
+	MOD_INC_USE_COUNT;
+
+	/* If port is closing, signal caller to try again */
+	if (tty_hung_up_p(filp) || info->flags & ASYNC_CLOSING){
+		if (info->flags & ASYNC_CLOSING)
+			interruptible_sleep_on(&info->close_wait);
+		retval = ((info->flags & ASYNC_HUP_NOTIFY) ?
+			-EAGAIN : -ERESTARTSYS);
+		goto cleanup;
+	}
+
+	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+
+	spin_lock_irqsave(&info->netlock, flags);
+	if (info->netcount) {
+		retval = -EBUSY;
+		spin_unlock_irqrestore(&info->netlock, flags);
+		goto cleanup;
+	}
+	info->count++;
+	spin_unlock_irqrestore(&info->netlock, flags);
+
+	if (info->count == 1) {
+		/* 1st open on this device, init hardware */
+		retval = startup(info);
+		if (retval < 0)
+			goto cleanup;
+	}
+
+	retval = block_til_ready(tty, filp, info);
+	if (retval) {
+		if (debug_level >= DEBUG_LEVEL_INFO)
+			printk("%s(%d):%s block_til_ready() returned %d\n",
+				 __FILE__,__LINE__, info->device_name, retval);
+		goto cleanup;
+	}
+
+	if ((info->count == 1) &&
+	    info->flags & ASYNC_SPLIT_TERMIOS) {
+		if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+			*tty->termios = info->normal_termios;
+		else
+			*tty->termios = info->callout_termios;
+		change_params(info);
+	}
+
+	info->session = current->session;
+	info->pgrp    = current->pgrp;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s open() success\n",
+			 __FILE__,__LINE__, info->device_name);
+	retval = 0;
+
+cleanup:
+	if (retval) {
+		if(MOD_IN_USE)
+			MOD_DEC_USE_COUNT;
+		if(info->count)
+			info->count--;
+	}
+
+	return retval;
+}
+
+/* Called when port is closed. Wait for remaining data to be
+ * sent. Disable port and free resources.
+ */
+static void close(struct tty_struct *tty, struct file *filp)
+{
+	SLMP_INFO * info = (SLMP_INFO *)tty->driver_data;
+
+	if (!info || sanity_check(info, tty->device, "close"))
+		return;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s close() entry, count=%d\n",
+			 __FILE__,__LINE__, info->device_name, info->count);
+
+	if (!info->count || tty_hung_up_p(filp))
+		goto cleanup;
+
+	if ((tty->count == 1) && (info->count != 1)) {
+		/*
+		 * tty->count is 1 and the tty structure will be freed.
+		 * info->count should be one in this case.
+		 * if it's not, correct it so that the port is shutdown.
+		 */
+		printk("%s(%d):%s close: bad refcount; tty->count is 1, "
+		       "info->count is %d\n",
+			 __FILE__,__LINE__, info->device_name, info->count);
+		info->count = 1;
+	}
+
+	info->count--;
+
+	/* if at least one open remaining, leave hardware active */
+	if (info->count)
+		goto cleanup;
+
+	info->flags |= ASYNC_CLOSING;
+
+	/* Save the termios structure, since this port may have
+	 * separate termios for callout and dialin.
+	 */
+	if (info->flags & ASYNC_NORMAL_ACTIVE)
+		info->normal_termios = *tty->termios;
+	if (info->flags & ASYNC_CALLOUT_ACTIVE)
+		info->callout_termios = *tty->termios;
+
+	/* set tty->closing to notify line discipline to
+	 * only process XON/XOFF characters. Only the N_TTY
+	 * discipline appears to use this (ppp does not).
+	 */
+	tty->closing = 1;
+
+	/* wait for transmit data to clear all layers */
+
+	if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) {
+		if (debug_level >= DEBUG_LEVEL_INFO)
+			printk("%s(%d):%s close() calling tty_wait_until_sent\n",
+				 __FILE__,__LINE__, info->device_name );
+		tty_wait_until_sent(tty, info->closing_wait);
+	}
+
+ 	if (info->flags & ASYNC_INITIALIZED)
+ 		wait_until_sent(tty, info->timeout);
+
+	if (tty->driver.flush_buffer)
+		tty->driver.flush_buffer(tty);
+
+	if (tty->ldisc.flush_buffer)
+		tty->ldisc.flush_buffer(tty);
+
+	shutdown(info);
+
+	tty->closing = 0;
+	info->tty = 0;
+
+	if (info->blocked_open) {
+		if (info->close_delay) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(info->close_delay);
+		}
+		wake_up_interruptible(&info->open_wait);
+	}
+
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
+			 ASYNC_CLOSING);
+
+	wake_up_interruptible(&info->close_wait);
+
+cleanup:
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s close() exit, count=%d\n", __FILE__,__LINE__,
+			tty->driver.name, info->count);
+	if(MOD_IN_USE)
+		MOD_DEC_USE_COUNT;
+}
+
+/* Called by tty_hangup() when a hangup is signaled.
+ * This is the same as closing all open descriptors for the port.
+ */
+static void hangup(struct tty_struct *tty)
+{
+	SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s hangup()\n",
+			 __FILE__,__LINE__, info->device_name );
+
+	if (sanity_check(info, tty->device, "hangup"))
+		return;
+
+	flush_buffer(tty);
+	shutdown(info);
+
+	info->count = 0;
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+	info->tty = 0;
+
+	wake_up_interruptible(&info->open_wait);
+}
+
+/* Set new termios settings
+ */
+static void set_termios(struct tty_struct *tty, struct termios *old_termios)
+{
+	SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+	unsigned long flags;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s set_termios()\n", __FILE__,__LINE__,
+			tty->driver.name );
+
+	/* just return if nothing has changed */
+	if ((tty->termios->c_cflag == old_termios->c_cflag)
+	    && (RELEVANT_IFLAG(tty->termios->c_iflag)
+		== RELEVANT_IFLAG(old_termios->c_iflag)))
+	  return;
+
+	change_params(info);
+
+	/* Handle transition to B0 status */
+	if (old_termios->c_cflag & CBAUD &&
+	    !(tty->termios->c_cflag & CBAUD)) {
+		info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
+		spin_lock_irqsave(&info->lock,flags);
+	 	set_signals(info);
+		spin_unlock_irqrestore(&info->lock,flags);
+	}
+
+	/* Handle transition away from B0 status */
+	if (!(old_termios->c_cflag & CBAUD) &&
+	    tty->termios->c_cflag & CBAUD) {
+		info->serial_signals |= SerialSignal_DTR;
+ 		if (!(tty->termios->c_cflag & CRTSCTS) ||
+ 		    !test_bit(TTY_THROTTLED, &tty->flags)) {
+			info->serial_signals |= SerialSignal_RTS;
+ 		}
+		spin_lock_irqsave(&info->lock,flags);
+	 	set_signals(info);
+		spin_unlock_irqrestore(&info->lock,flags);
+	}
+
+	/* Handle turning off CRTSCTS */
+	if (old_termios->c_cflag & CRTSCTS &&
+	    !(tty->termios->c_cflag & CRTSCTS)) {
+		tty->hw_stopped = 0;
+		tx_release(tty);
+	}
+}
+
+/* Send a block of data
+ *
+ * Arguments:
+ *
+ * 	tty		pointer to tty information structure
+ * 	from_user	flag: 1 = from user process
+ * 	buf		pointer to buffer containing send data
+ * 	count		size of send data in bytes
+ *
+ * Return Value:	number of characters written
+ */
+static int write(struct tty_struct *tty, int from_user,
+		 const unsigned char *buf, int count)
+{
+	int	c, ret = 0, err;
+	SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+	unsigned long flags;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s write() count=%d\n",
+		       __FILE__,__LINE__,info->device_name,count);
+
+	if (sanity_check(info, tty->device, "write"))
+		goto cleanup;
+
+	if (!tty || !info->tx_buf)
+		goto cleanup;
+
+	if (info->params.mode == MGSL_MODE_HDLC) {
+		if (count > info->max_frame_size) {
+			ret = -EIO;
+			goto cleanup;
+		}
+		if (info->tx_active)
+			goto cleanup;
+		if (info->tx_count) {
+			/* send accumulated data from send_char() calls */
+			/* as frame and wait before accepting more data. */
+			tx_load_dma_buffer(info, info->tx_buf, info->tx_count);
+			goto start;
+		}
+		if (!from_user) {
+			ret = info->tx_count = count;
+			tx_load_dma_buffer(info, buf, count);
+			goto start;
+		}
+	}
+
+	for (;;) {
+		c = MIN(count,
+			MIN(info->max_frame_size - info->tx_count - 1,
+			    info->max_frame_size - info->tx_put));
+		if (c <= 0)
+			break;
+			
+		if (from_user) {
+			COPY_FROM_USER(err, info->tx_buf + info->tx_put, buf, c);
+			if (err) {
+				if (!ret)
+					ret = -EFAULT;
+				break;
+			}
+		} else
+			memcpy(info->tx_buf + info->tx_put, buf, c);
+
+		spin_lock_irqsave(&info->lock,flags);
+		info->tx_put += c;
+		if (info->tx_put >= info->max_frame_size)
+			info->tx_put -= info->max_frame_size;
+		info->tx_count += c;
+		spin_unlock_irqrestore(&info->lock,flags);
+
+		buf += c;
+		count -= c;
+		ret += c;
+	}
+
+	if (info->params.mode == MGSL_MODE_HDLC) {
+		if (count) {
+			ret = info->tx_count = 0;
+			goto cleanup;
+		}
+		tx_load_dma_buffer(info, info->tx_buf, info->tx_count);
+	}
+start:
+ 	if (info->tx_count && !tty->stopped && !tty->hw_stopped) {
+		spin_lock_irqsave(&info->lock,flags);
+		if (!info->tx_active)
+		 	tx_start(info);
+		spin_unlock_irqrestore(&info->lock,flags);
+ 	}
+
+cleanup:
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk( "%s(%d):%s write() returning=%d\n",
+			__FILE__,__LINE__,info->device_name,ret);
+	return ret;
+}
+
+/* Add a character to the transmit buffer.
+ */
+static void put_char(struct tty_struct *tty, unsigned char ch)
+{
+	SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+	unsigned long flags;
+
+	if ( debug_level >= DEBUG_LEVEL_INFO ) {
+		printk( "%s(%d):%s put_char(%d)\n",
+			__FILE__,__LINE__,info->device_name,ch);
+	}
+
+	if (sanity_check(info, tty->device, "put_char"))
+		return;
+
+	if (!tty || !info->tx_buf)
+		return;
+
+	spin_lock_irqsave(&info->lock,flags);
+
+	if ( (info->params.mode != MGSL_MODE_HDLC) ||
+	     !info->tx_active ) {
+
+		if (info->tx_count < info->max_frame_size - 1) {
+			info->tx_buf[info->tx_put++] = ch;
+			if (info->tx_put >= info->max_frame_size)
+				info->tx_put -= info->max_frame_size;
+			info->tx_count++;
+		}
+	}
+
+	spin_unlock_irqrestore(&info->lock,flags);
+}
+
+/* Send a high-priority XON/XOFF character
+ */
+static void send_xchar(struct tty_struct *tty, char ch)
+{
+	SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+	unsigned long flags;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s send_xchar(%d)\n",
+			 __FILE__,__LINE__, info->device_name, ch );
+
+	if (sanity_check(info, tty->device, "send_xchar"))
+		return;
+
+	info->x_char = ch;
+	if (ch) {
+		/* Make sure transmit interrupts are on */
+		spin_lock_irqsave(&info->lock,flags);
+		if (!info->tx_enabled)
+		 	tx_start(info);
+		spin_unlock_irqrestore(&info->lock,flags);
+	}
+}
+
+/* Wait until the transmitter is empty.
+ */
+static void wait_until_sent(struct tty_struct *tty, int timeout)
+{
+	SLMP_INFO * info = (SLMP_INFO *)tty->driver_data;
+	unsigned long orig_jiffies, char_time;
+
+	if (!info )
+		return;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s wait_until_sent() entry\n",
+			 __FILE__,__LINE__, info->device_name );
+
+	if (sanity_check(info, tty->device, "wait_until_sent"))
+		return;
+
+	if (!(info->flags & ASYNC_INITIALIZED))
+		goto exit;
+
+	orig_jiffies = jiffies;
+
+	/* Set check interval to 1/5 of estimated time to
+	 * send a character, and make it at least 1. The check
+	 * interval should also be less than the timeout.
+	 * Note: use tight timings here to satisfy the NIST-PCTS.
+	 */
+
+	if ( info->params.data_rate ) {
+	       	char_time = info->timeout/(32 * 5);
+		if (!char_time)
+			char_time++;
+	} else
+		char_time = 1;
+
+	if (timeout)
+		char_time = MIN(char_time, timeout);
+
+	if ( info->params.mode == MGSL_MODE_HDLC ) {
+		while (info->tx_active) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(char_time);
+			if (signal_pending(current))
+				break;
+			if (timeout && ((orig_jiffies + timeout) < jiffies))
+				break;
+		}
+	} else {
+		//TODO: determine if there is something similar to USC16C32
+		// 	TXSTATUS_ALL_SENT status
+		while ( info->tx_active && info->tx_enabled) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(char_time);
+			if (signal_pending(current))
+				break;
+			if (timeout && ((orig_jiffies + timeout) < jiffies))
+				break;
+		}
+	}
+
+exit:
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s wait_until_sent() exit\n",
+			 __FILE__,__LINE__, info->device_name );
+}
+
+/* Return the count of free bytes in transmit buffer
+ */
+static int write_room(struct tty_struct *tty)
+{
+	SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+	int ret;
+
+	if (sanity_check(info, tty->device, "write_room"))
+		return 0;
+
+	if (info->params.mode == MGSL_MODE_HDLC) {
+		ret = (info->tx_active) ? 0 : HDLC_MAX_FRAME_SIZE;
+	} else {
+		ret = info->max_frame_size - info->tx_count - 1;
+		if (ret < 0)
+			ret = 0;
+	}
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s write_room()=%d\n",
+		       __FILE__, __LINE__, info->device_name, ret);
+
+	return ret;
+}
+
+/* enable transmitter and send remaining buffered characters
+ */
+static void flush_chars(struct tty_struct *tty)
+{
+	SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+	unsigned long flags;
+
+	if ( debug_level >= DEBUG_LEVEL_INFO )
+		printk( "%s(%d):%s flush_chars() entry tx_count=%d\n",
+			__FILE__,__LINE__,info->device_name,info->tx_count);
+
+	if (sanity_check(info, tty->device, "flush_chars"))
+		return;
+
+	if (info->tx_count <= 0 || tty->stopped || tty->hw_stopped ||
+	    !info->tx_buf)
+		return;
+
+	if ( debug_level >= DEBUG_LEVEL_INFO )
+		printk( "%s(%d):%s flush_chars() entry, starting transmitter\n",
+			__FILE__,__LINE__,info->device_name );
+
+	spin_lock_irqsave(&info->lock,flags);
+
+	if (!info->tx_active) {
+		if ( (info->params.mode == MGSL_MODE_HDLC) &&
+			info->tx_count ) {
+			/* operating in synchronous (frame oriented) mode */
+			/* copy data from circular tx_buf to */
+			/* transmit DMA buffer. */
+			tx_load_dma_buffer(info,
+				 info->tx_buf,info->tx_count);
+		}
+	 	tx_start(info);
+	}
+
+	spin_unlock_irqrestore(&info->lock,flags);
+}
+
+/* Discard all data in the send buffer
+ */
+static void flush_buffer(struct tty_struct *tty)
+{
+	SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+	unsigned long flags;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s flush_buffer() entry\n",
+			 __FILE__,__LINE__, info->device_name );
+
+	if (sanity_check(info, tty->device, "flush_buffer"))
+		return;
+
+	spin_lock_irqsave(&info->lock,flags);
+	info->tx_count = info->tx_put = info->tx_get = 0;
+	del_timer(&info->tx_timer);
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	wake_up_interruptible(&tty->write_wait);
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+	    tty->ldisc.write_wakeup)
+		(tty->ldisc.write_wakeup)(tty);
+}
+
+/* throttle (stop) transmitter
+ */
+static void tx_hold(struct tty_struct *tty)
+{
+	SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+	unsigned long flags;
+
+	if (sanity_check(info, tty->device, "tx_hold"))
+		return;
+
+	if ( debug_level >= DEBUG_LEVEL_INFO )
+		printk("%s(%d):%s tx_hold()\n",
+			__FILE__,__LINE__,info->device_name);
+
+	spin_lock_irqsave(&info->lock,flags);
+	if (info->tx_enabled)
+	 	tx_stop(info);
+	spin_unlock_irqrestore(&info->lock,flags);
+}
+
+/* release (start) transmitter
+ */
+static void tx_release(struct tty_struct *tty)
+{
+	SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+	unsigned long flags;
+
+	if (sanity_check(info, tty->device, "tx_release"))
+		return;
+
+	if ( debug_level >= DEBUG_LEVEL_INFO )
+		printk("%s(%d):%s tx_release()\n",
+			__FILE__,__LINE__,info->device_name);
+
+	spin_lock_irqsave(&info->lock,flags);
+	if (!info->tx_enabled)
+	 	tx_start(info);
+	spin_unlock_irqrestore(&info->lock,flags);
+}
+
+/* Service an IOCTL request
+ *
+ * Arguments:
+ *
+ * 	tty	pointer to tty instance data
+ * 	file	pointer to associated file object for device
+ * 	cmd	IOCTL command code
+ * 	arg	command argument/context
+ *
+ * Return Value:	0 if success, otherwise error code
+ */
+static int ioctl(struct tty_struct *tty, struct file *file,
+		 unsigned int cmd, unsigned long arg)
+{
+	SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+	int error;
+	struct mgsl_icount cnow;	/* kernel counter temps */
+	struct serial_icounter_struct *p_cuser;	/* user space */
+	unsigned long flags;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s ioctl() cmd=%08X\n", __FILE__,__LINE__,
+			info->device_name, cmd );
+
+	if (sanity_check(info, tty->device, "ioctl"))
+		return -ENODEV;
+
+	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+	    (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
+		if (tty->flags & (1 << TTY_IO_ERROR))
+		    return -EIO;
+	}
+
+	switch (cmd) {
+	case TIOCMGET:
+		return get_modem_info(info, (unsigned int *) arg);
+	case TIOCMBIS:
+	case TIOCMBIC:
+	case TIOCMSET:
+		return set_modem_info(info, cmd, (unsigned int *) arg);
+	case MGSL_IOCGPARAMS:
+		return get_params(info,(MGSL_PARAMS *)arg);
+	case MGSL_IOCSPARAMS:
+		return set_params(info,(MGSL_PARAMS *)arg);
+	case MGSL_IOCGTXIDLE:
+		return get_txidle(info,(int*)arg);
+	case MGSL_IOCSTXIDLE:
+		return set_txidle(info,(int)arg);
+	case MGSL_IOCTXENABLE:
+		return tx_enable(info,(int)arg);
+	case MGSL_IOCRXENABLE:
+		return rx_enable(info,(int)arg);
+	case MGSL_IOCTXABORT:
+		return tx_abort(info);
+	case MGSL_IOCGSTATS:
+		return get_stats(info,(struct mgsl_icount*)arg);
+	case MGSL_IOCWAITEVENT:
+		return wait_mgsl_event(info,(int*)arg);
+	case MGSL_IOCLOOPTXDONE:
+		return 0; // TODO: Not supported, need to document
+	case MGSL_IOCCLRMODCOUNT:
+		while(MOD_IN_USE)
+			MOD_DEC_USE_COUNT;
+		return 0;
+		/* Wait for modem input (DCD,RI,DSR,CTS) change
+		 * as specified by mask in arg (TIOCM_RNG/DSR/CD/CTS)
+		 */
+	case TIOCMIWAIT:
+		return modem_input_wait(info,(int)arg);
+		
+		/*
+		 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+		 * Return: write counters to the user passed counter struct
+		 * NB: both 1->0 and 0->1 transitions are counted except for
+		 *     RI where only 0->1 is counted.
+		 */
+	case TIOCGICOUNT:
+		spin_lock_irqsave(&info->lock,flags);
+		cnow = info->icount;
+		spin_unlock_irqrestore(&info->lock,flags);
+		p_cuser = (struct serial_icounter_struct *) arg;
+		PUT_USER(error,cnow.cts, &p_cuser->cts);
+		if (error) return error;
+		PUT_USER(error,cnow.dsr, &p_cuser->dsr);
+		if (error) return error;
+		PUT_USER(error,cnow.rng, &p_cuser->rng);
+		if (error) return error;
+		PUT_USER(error,cnow.dcd, &p_cuser->dcd);
+		if (error) return error;
+		PUT_USER(error,cnow.rx, &p_cuser->rx);
+		if (error) return error;
+		PUT_USER(error,cnow.tx, &p_cuser->tx);
+		if (error) return error;
+		PUT_USER(error,cnow.frame, &p_cuser->frame);
+		if (error) return error;
+		PUT_USER(error,cnow.overrun, &p_cuser->overrun);
+		if (error) return error;
+		PUT_USER(error,cnow.parity, &p_cuser->parity);
+		if (error) return error;
+		PUT_USER(error,cnow.brk, &p_cuser->brk);
+		if (error) return error;
+		PUT_USER(error,cnow.buf_overrun, &p_cuser->buf_overrun);
+		if (error) return error;
+		return 0;
+	default:
+		return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+/*
+ * /proc fs routines....
+ */
+
+static inline int line_info(char *buf, SLMP_INFO *info)
+{
+	char	stat_buf[30];
+	int	ret;
+	unsigned long flags;
+
+	ret = sprintf(buf, "%s: SCABase=%08x Mem=%08X StatusControl=%08x LCR=%08X\n"
+		       "\tIRQ=%d MaxFrameSize=%u\n",
+		info->device_name,
+		info->phys_sca_base,
+		info->phys_memory_base,
+		info->phys_statctrl_base,
+		info->phys_lcr_base,
+		info->irq_level,
+		info->max_frame_size );
+
+	/* output current serial signal states */
+	spin_lock_irqsave(&info->lock,flags);
+ 	get_signals(info);
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	stat_buf[0] = 0;
+	stat_buf[1] = 0;
+	if (info->serial_signals & SerialSignal_RTS)
+		strcat(stat_buf, "|RTS");
+	if (info->serial_signals & SerialSignal_CTS)
+		strcat(stat_buf, "|CTS");
+	if (info->serial_signals & SerialSignal_DTR)
+		strcat(stat_buf, "|DTR");
+	if (info->serial_signals & SerialSignal_DSR)
+		strcat(stat_buf, "|DSR");
+	if (info->serial_signals & SerialSignal_DCD)
+		strcat(stat_buf, "|CD");
+	if (info->serial_signals & SerialSignal_RI)
+		strcat(stat_buf, "|RI");
+
+	if (info->params.mode == MGSL_MODE_HDLC) {
+		ret += sprintf(buf+ret, "\tHDLC txok:%d rxok:%d",
+			      info->icount.txok, info->icount.rxok);
+		if (info->icount.txunder)
+			ret += sprintf(buf+ret, " txunder:%d", info->icount.txunder);
+		if (info->icount.txabort)
+			ret += sprintf(buf+ret, " txabort:%d", info->icount.txabort);
+		if (info->icount.rxshort)
+			ret += sprintf(buf+ret, " rxshort:%d", info->icount.rxshort);
+		if (info->icount.rxlong)
+			ret += sprintf(buf+ret, " rxlong:%d", info->icount.rxlong);
+		if (info->icount.rxover)
+			ret += sprintf(buf+ret, " rxover:%d", info->icount.rxover);
+		if (info->icount.rxcrc)
+			ret += sprintf(buf+ret, " rxlong:%d", info->icount.rxcrc);
+	} else {
+		ret += sprintf(buf+ret, "\tASYNC tx:%d rx:%d",
+			      info->icount.tx, info->icount.rx);
+		if (info->icount.frame)
+			ret += sprintf(buf+ret, " fe:%d", info->icount.frame);
+		if (info->icount.parity)
+			ret += sprintf(buf+ret, " pe:%d", info->icount.parity);
+		if (info->icount.brk)
+			ret += sprintf(buf+ret, " brk:%d", info->icount.brk);
+		if (info->icount.overrun)
+			ret += sprintf(buf+ret, " oe:%d", info->icount.overrun);
+	}
+
+	/* Append serial signal status to end */
+	ret += sprintf(buf+ret, " %s\n", stat_buf+1);
+
+	ret += sprintf(buf+ret, "\ttxactive=%d bh_req=%d bh_run=%d pending_bh=%x\n",
+	 info->tx_active,info->bh_requested,info->bh_running,
+	 info->pending_bh);
+
+	return ret;
+}
+
+/* Called to print information about devices
+ */
+int read_proc(char *page, char **start, off_t off, int count,
+	      int *eof, void *data)
+{
+	int len = 0, l;
+	off_t	begin = 0;
+	SLMP_INFO *info;
+
+	len += sprintf(page, "synclinkmp driver:%s\n", driver_version);
+
+	info = synclinkmp_device_list;
+	while( info ) {
+		l = line_info(page + len, info);
+		len += l;
+		if (len+begin > off+count)
+			goto done;
+		if (len+begin < off) {
+			begin += len;
+			len = 0;
+		}
+		info = info->next_device;
+	}
+
+	*eof = 1;
+done:
+	if (off >= len+begin)
+		return 0;
+	*start = page + (off-begin);
+	return ((count < begin+len-off) ? count : begin+len-off);
+}
+
+/* Return the count of bytes in transmit buffer
+ */
+static int chars_in_buffer(struct tty_struct *tty)
+{
+	SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+
+	if (sanity_check(info, tty->device, "chars_in_buffer"))
+		return 0;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s chars_in_buffer()=%d\n",
+		       __FILE__, __LINE__, info->device_name, info->tx_count);
+
+	return info->tx_count;
+}
+
+/* Signal remote device to throttle send data (our receive data)
+ */
+static void throttle(struct tty_struct * tty)
+{
+	SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+	unsigned long flags;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s throttle() entry\n",
+			 __FILE__,__LINE__, info->device_name );
+
+	if (sanity_check(info, tty->device, "throttle"))
+		return;
+
+	if (I_IXOFF(tty))
+		send_xchar(tty, STOP_CHAR(tty));
+
+ 	if (tty->termios->c_cflag & CRTSCTS) {
+		spin_lock_irqsave(&info->lock,flags);
+		info->serial_signals &= ~SerialSignal_RTS;
+	 	set_signals(info);
+		spin_unlock_irqrestore(&info->lock,flags);
+	}
+}
+
+/* Signal remote device to stop throttling send data (our receive data)
+ */
+static void unthrottle(struct tty_struct * tty)
+{
+	SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+	unsigned long flags;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s unthrottle() entry\n",
+			 __FILE__,__LINE__, info->device_name );
+
+	if (sanity_check(info, tty->device, "unthrottle"))
+		return;
+
+	if (I_IXOFF(tty)) {
+		if (info->x_char)
+			info->x_char = 0;
+		else
+			send_xchar(tty, START_CHAR(tty));
+	}
+
+ 	if (tty->termios->c_cflag & CRTSCTS) {
+		spin_lock_irqsave(&info->lock,flags);
+		info->serial_signals |= SerialSignal_RTS;
+	 	set_signals(info);
+		spin_unlock_irqrestore(&info->lock,flags);
+	}
+}
+
+/* set or clear transmit break condition
+ * break_state	-1=set break condition, 0=clear
+ */
+static void set_break(struct tty_struct *tty, int break_state)
+{
+	unsigned char RegValue;
+	SLMP_INFO * info = (SLMP_INFO *)tty->driver_data;
+	unsigned long flags;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s set_break(%d)\n",
+			 __FILE__,__LINE__, info->device_name, break_state);
+
+	if (sanity_check(info, tty->device, "set_break"))
+		return;
+
+	spin_lock_irqsave(&info->lock,flags);
+	RegValue = read_reg(info, CTL);
+ 	if (break_state == -1)
+		RegValue |= BIT3;
+	else
+		RegValue &= ~BIT3;
+	write_reg(info, CTL, RegValue);
+	spin_unlock_irqrestore(&info->lock,flags);
+}
+
+#ifdef CONFIG_SYNCLINK_SYNCPPP
+
+/* syncppp support and callbacks */
+
+static void sppp_init(SLMP_INFO *info)
+{
+	struct net_device *d;
+
+	sprintf(info->netname,"mgslm%dp%d",info->adapter_num,info->port_num);
+
+	info->if_ptr = &info->pppdev;
+	info->netdev = info->pppdev.dev = &info->netdevice;
+
+	sppp_attach(&info->pppdev);
+
+	d = info->netdev;
+	strcpy(d->name,info->netname);
+	d->base_addr = 0;
+	d->irq = info->irq_level;
+	d->dma = 0;
+	d->priv = info;
+	d->init = NULL;
+	d->open = sppp_cb_open;
+	d->stop = sppp_cb_close;
+	d->hard_start_xmit = sppp_cb_tx;
+	d->do_ioctl = sppp_cb_ioctl;
+	d->get_stats = sppp_cb_net_stats;
+	d->tx_timeout = sppp_cb_tx_timeout;
+	d->watchdog_timeo = 10*HZ;
+
+#if LINUX_VERSION_CODE < VERSION(2,4,4) 
+	dev_init_buffers(d);
+#endif
+
+	if (register_netdev(d) == -1) {
+		printk(KERN_WARNING "%s: register_netdev failed.\n", d->name);
+		sppp_detach(info->netdev);
+		return;
+	}
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("sppp_init(%s)\n",info->netname);
+}
+
+static void sppp_delete(SLMP_INFO *info)
+{
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("sppp_delete(%s)\n",info->netname);
+	sppp_detach(info->netdev);
+	unregister_netdev(info->netdev);
+}
+
+static int sppp_cb_open(struct net_device *d)
+{
+	SLMP_INFO *info = d->priv;
+	int err, flags;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("sppp_cb_open(%s)\n",info->netname);
+
+	spin_lock_irqsave(&info->netlock, flags);
+	if (info->count != 0 || info->netcount != 0) {
+		printk(KERN_WARNING "%s: sppp_cb_open returning busy\n", info->netname);
+		spin_unlock_irqrestore(&info->netlock, flags);
+		return -EBUSY;
+	}
+	info->netcount=1;
+	MOD_INC_USE_COUNT;
+	spin_unlock_irqrestore(&info->netlock, flags);
+
+	/* claim resources and init adapter */
+	if ((err = startup(info)) != 0)
+		goto open_fail;
+
+	/* allow syncppp module to do open processing */
+	if ((err = sppp_open(d)) != 0) {
+		shutdown(info);
+		goto open_fail;
+	}
+
+	info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
+	program_hw(info);
+
+	d->trans_start = jiffies;
+	netif_start_queue(d);
+	return 0;
+
+open_fail:
+	spin_lock_irqsave(&info->netlock, flags);
+	info->netcount=0;
+	MOD_DEC_USE_COUNT;
+	spin_unlock_irqrestore(&info->netlock, flags);
+	return err;
+}
+
+static void sppp_cb_tx_timeout(struct net_device *dev)
+{
+	SLMP_INFO *info = dev->priv;
+	int flags;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("sppp_tx_timeout(%s)\n",info->netname);
+
+	info->netstats.tx_errors++;
+	info->netstats.tx_aborted_errors++;
+
+	spin_lock_irqsave(&info->lock,flags);
+	tx_stop(info);
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	netif_wake_queue(dev);
+}
+
+static int sppp_cb_tx(struct sk_buff *skb, struct net_device *dev)
+{
+	SLMP_INFO *info = dev->priv;
+	unsigned long flags;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("sppp_tx(%s)\n",info->netname);
+
+	netif_stop_queue(dev);
+
+	info->tx_count = skb->len;
+	tx_load_dma_buffer(info, skb->data, skb->len);
+	info->netstats.tx_packets++;
+	info->netstats.tx_bytes += skb->len;
+	dev_kfree_skb(skb);
+
+	dev->trans_start = jiffies;
+
+	spin_lock_irqsave(&info->lock,flags);
+	if (!info->tx_active)
+	 	tx_start(info);
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	return 0;
+}
+
+static int sppp_cb_close(struct net_device *d)
+{
+	SLMP_INFO *info = d->priv;
+	unsigned long flags;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("sppp_cb_close(%s)\n",info->netname);
+
+	/* shutdown adapter and release resources */
+	shutdown(info);
+
+	/* allow syncppp to do close processing */
+	sppp_close(d);
+	netif_stop_queue(d);
+
+	spin_lock_irqsave(&info->netlock, flags);
+	info->netcount=0;
+	MOD_DEC_USE_COUNT;
+	spin_unlock_irqrestore(&info->netlock, flags);
+	return 0;
+}
+
+static void sppp_rx_done(SLMP_INFO *info, char *buf, int size)
+{
+	struct sk_buff *skb = dev_alloc_skb(size);
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("sppp_rx_done(%s)\n",info->netname);
+	if (skb == NULL) {
+		printk(KERN_NOTICE "%s: cant alloc skb, dropping packet\n",
+			info->netname);
+		info->netstats.rx_dropped++;
+		return;
+	}
+
+	memcpy(skb_put(skb, size),buf,size);
+
+	skb->protocol = htons(ETH_P_WAN_PPP);
+	skb->dev = info->netdev;
+	skb->mac.raw = skb->data;
+	info->netstats.rx_packets++;
+	info->netstats.rx_bytes += size;
+	netif_rx(skb);
+	info->netdev->trans_start = jiffies;
+}
+
+static void sppp_tx_done(SLMP_INFO *info)
+{
+	if (netif_queue_stopped(info->netdev))
+	    netif_wake_queue(info->netdev);
+}
+
+static struct net_device_stats *sppp_cb_net_stats(struct net_device *dev)
+{
+	SLMP_INFO *info = dev->priv;
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("net_stats(%s)\n",info->netname);
+	return &info->netstats;
+}
+
+static int sppp_cb_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	SLMP_INFO *info = (SLMP_INFO *)dev->priv;
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):ioctl %s cmd=%08X\n", __FILE__,__LINE__,
+			info->netname, cmd );
+	return sppp_do_ioctl(dev, ifr, cmd);
+}
+
+#endif /* ifdef CONFIG_SYNCLINK_SYNCPPP */
+
+
+/* Return next bottom half action to perform.
+ * Return Value:	BH action code or 0 if nothing to do.
+ */
+int bh_action(SLMP_INFO *info)
+{
+	unsigned long flags;
+	int rc = 0;
+
+	spin_lock_irqsave(&info->lock,flags);
+
+	if (info->pending_bh & BH_RECEIVE) {
+		info->pending_bh &= ~BH_RECEIVE;
+		rc = BH_RECEIVE;
+	} else if (info->pending_bh & BH_TRANSMIT) {
+		info->pending_bh &= ~BH_TRANSMIT;
+		rc = BH_TRANSMIT;
+	} else if (info->pending_bh & BH_STATUS) {
+		info->pending_bh &= ~BH_STATUS;
+		rc = BH_STATUS;
+	}
+
+	if (!rc) {
+		/* Mark BH routine as complete */
+		info->bh_running   = 0;
+		info->bh_requested = 0;
+	}
+
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	return rc;
+}
+
+/* Perform bottom half processing of work items queued by ISR.
+ */
+void bh_handler(void* Context)
+{
+	SLMP_INFO *info = (SLMP_INFO*)Context;
+	int action;
+
+	if (!info)
+		return;
+
+	if ( debug_level >= DEBUG_LEVEL_BH )
+		printk( "%s(%d):%s bh_handler() entry\n",
+			__FILE__,__LINE__,info->device_name);
+
+	info->bh_running = 1;
+
+	while((action = bh_action(info)) != 0) {
+
+		/* Process work item */
+		if ( debug_level >= DEBUG_LEVEL_BH )
+			printk( "%s(%d):%s bh_handler() work item action=%d\n",
+				__FILE__,__LINE__,info->device_name, action);
+
+		switch (action) {
+
+		case BH_RECEIVE:
+			bh_receive(info);
+			break;
+		case BH_TRANSMIT:
+			bh_transmit(info);
+			break;
+		case BH_STATUS:
+			bh_status(info);
+			break;
+		default:
+			/* unknown work item ID */
+			printk("%s(%d):%s Unknown work item ID=%08X!\n",
+				__FILE__,__LINE__,info->device_name,action);
+			break;
+		}
+	}
+
+	if ( debug_level >= DEBUG_LEVEL_BH )
+		printk( "%s(%d):%s bh_handler() exit\n",
+			__FILE__,__LINE__,info->device_name);
+}
+
+void bh_receive(SLMP_INFO *info)
+{
+	if ( debug_level >= DEBUG_LEVEL_BH )
+		printk( "%s(%d):%s bh_receive()\n",
+			__FILE__,__LINE__,info->device_name);
+
+	while( rx_get_frame(info) );
+}
+
+void bh_transmit(SLMP_INFO *info)
+{
+	struct tty_struct *tty = info->tty;
+
+	if ( debug_level >= DEBUG_LEVEL_BH )
+		printk( "%s(%d):%s bh_transmit() entry\n",
+			__FILE__,__LINE__,info->device_name);
+
+	if (tty) {
+		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+		    tty->ldisc.write_wakeup) {
+			if ( debug_level >= DEBUG_LEVEL_BH )
+				printk( "%s(%d):%s calling ldisc.write_wakeup\n",
+					__FILE__,__LINE__,info->device_name);
+			(tty->ldisc.write_wakeup)(tty);
+		}
+		wake_up_interruptible(&tty->write_wait);
+	}
+}
+
+void bh_status(SLMP_INFO *info)
+{
+	if ( debug_level >= DEBUG_LEVEL_BH )
+		printk( "%s(%d):%s bh_status() entry\n",
+			__FILE__,__LINE__,info->device_name);
+
+	info->ri_chkcount = 0;
+	info->dsr_chkcount = 0;
+	info->dcd_chkcount = 0;
+	info->cts_chkcount = 0;
+}
+
+void isr_timer(SLMP_INFO * info)
+{
+	unsigned char timer = (info->port_num & 1) ? TIMER2 : TIMER0;
+
+	/* IER2<7..4> = timer<3..0> interrupt enables (0=disabled) */
+	write_reg(info, IER2, 0);
+
+	/* TMCS, Timer Control/Status Register
+	 *
+	 * 07      CMF, Compare match flag (read only) 1=match
+	 * 06      ECMI, CMF Interrupt Enable: 0=disabled
+	 * 05      Reserved, must be 0
+	 * 04      TME, Timer Enable
+	 * 03..00  Reserved, must be 0
+	 *
+	 * 0000 0000
+	 */
+	write_reg(info, (unsigned char)(timer + TMCS), 0);
+
+	info->irq_occurred = TRUE;
+
+	if ( debug_level >= DEBUG_LEVEL_ISR )
+		printk("%s(%d):%s isr_timer()\n",
+			__FILE__,__LINE__,info->device_name);
+}
+
+void isr_rxint(SLMP_INFO * info)
+{
+ 	struct tty_struct *tty = info->tty;
+ 	struct	mgsl_icount *icount = &info->icount;
+	unsigned char status = read_reg(info, SR1);
+	unsigned char status2 = read_reg(info, SR2);
+
+	/* clear status bits */
+	if ( status & (FLGD + IDLD + CDCD + BRKD) )
+		write_reg(info, SR1, 
+				(unsigned char)(status & (FLGD + IDLD + CDCD + BRKD)));
+
+	if ( status2 & OVRN )
+		write_reg(info, SR2, (unsigned char)(status2 & OVRN));
+	
+	if ( debug_level >= DEBUG_LEVEL_ISR )
+		printk("%s(%d):%s isr_rxint status=%02X %02x\n",
+			__FILE__,__LINE__,info->device_name,status,status2);
+
+	if (info->params.mode == MGSL_MODE_ASYNC) {
+		if (status & BRKD) {
+			icount->brk++;
+
+			/* process break detection if tty control
+			 * is not set to ignore it
+			 */
+			if ( tty ) {
+				if (!(status & info->ignore_status_mask1)) {
+					if (info->read_status_mask1 & BRKD) {
+						*tty->flip.flag_buf_ptr = TTY_BREAK;
+						if (info->flags & ASYNC_SAK)
+							do_SAK(tty);
+					}
+				}
+			}
+		}
+	}
+	else {
+		if (status & (FLGD|IDLD)) {
+			if (status & FLGD)
+				info->icount.exithunt++;
+			else if (status & IDLD)
+				info->icount.rxidle++;
+			wake_up_interruptible(&info->event_wait_q);
+		}
+	}
+
+	if (status & CDCD) {
+		/* simulate a common modem status change interrupt
+		 * for our handler
+		 */
+		get_signals( info );
+		isr_io_pin(info,
+			MISCSTATUS_DCD_LATCHED|(info->serial_signals&SerialSignal_DCD));
+	}
+}
+
+/*
+ * handle async rx data interrupts
+ */
+void isr_rxrdy(SLMP_INFO * info)
+{
+	u16 status;
+	unsigned char DataByte;
+ 	struct tty_struct *tty = info->tty;
+ 	struct	mgsl_icount *icount = &info->icount;
+
+	if ( debug_level >= DEBUG_LEVEL_ISR )
+		printk("%s(%d):%s isr_rxrdy\n",
+			__FILE__,__LINE__,info->device_name);
+
+	while((status = read_reg(info,CST0)) & BIT0)
+	{
+		DataByte = read_reg(info,TRB);
+
+		if ( tty ) {
+			if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+				continue;
+
+			*tty->flip.char_buf_ptr = DataByte;
+			*tty->flip.flag_buf_ptr = 0;
+		}
+
+		icount->rx++;
+
+		if ( status & (PE + FRME + OVRN) ) {
+			printk("%s(%d):%s rxerr=%04X\n",
+				__FILE__,__LINE__,info->device_name,status);
+
+			/* update error statistics */
+			if (status & PE)
+				icount->parity++;
+			else if (status & FRME)
+				icount->frame++;
+			else if (status & OVRN)
+				icount->overrun++;
+
+			/* discard char if tty control flags say so */
+			if (status & info->ignore_status_mask2)
+				continue;
+
+			status &= info->read_status_mask2;
+
+			if ( tty ) {
+				if (status & PE)
+					*tty->flip.flag_buf_ptr = TTY_PARITY;
+				else if (status & FRME)
+					*tty->flip.flag_buf_ptr = TTY_FRAME;
+				if (status & OVRN) {
+					/* Overrun is special, since it's
+					 * reported immediately, and doesn't
+					 * affect the current character
+					 */
+					if (tty->flip.count < TTY_FLIPBUF_SIZE) {
+						tty->flip.count++;
+						tty->flip.flag_buf_ptr++;
+						tty->flip.char_buf_ptr++;
+						*tty->flip.flag_buf_ptr = TTY_OVERRUN;
+					}
+				}
+			}
+		}	/* end of if (error) */
+
+		if ( tty ) {
+			tty->flip.flag_buf_ptr++;
+			tty->flip.char_buf_ptr++;
+			tty->flip.count++;
+		}
+	}
+
+	if ( debug_level >= DEBUG_LEVEL_ISR ) {
+		printk("%s(%d):%s isr_rxrdy() flip count=%d\n",
+			__FILE__,__LINE__,info->device_name,
+			tty ? tty->flip.count : 0);
+		printk("%s(%d):%s rx=%d brk=%d parity=%d frame=%d overrun=%d\n",
+			__FILE__,__LINE__,info->device_name,
+			icount->rx,icount->brk,icount->parity,
+			icount->frame,icount->overrun);
+	}
+
+	if ( tty && tty->flip.count )
+		tty_flip_buffer_push(tty);
+}
+
+void isr_txeom(SLMP_INFO * info, unsigned char status)
+{
+	if ( debug_level >= DEBUG_LEVEL_ISR )
+		printk("%s(%d):%s isr_txeom status=%02x\n",
+			__FILE__,__LINE__,info->device_name,status);
+
+	/* disable and clear MSCI interrupts */
+	info->ie1_value &= ~(IDLE + UDRN);
+	write_reg(info, IE1, info->ie1_value);
+	write_reg(info, SR1, (unsigned char)(UDRN + IDLE));
+
+	write_reg(info, TXDMA + DIR, 0x00); /* disable Tx DMA IRQs */
+	write_reg(info, TXDMA + DSR, 0xc0); /* clear IRQs and disable DMA */
+	write_reg(info, TXDMA + DCMD, SWABORT);	/* reset/init DMA channel */
+
+	if ( info->tx_active ) {
+		if (info->params.mode != MGSL_MODE_ASYNC) {
+			if (status & UDRN)
+				info->icount.txunder++;
+			else if (status & IDLE)
+				info->icount.txok++;
+		}
+
+		info->tx_active = 0;
+		info->tx_count = info->tx_put = info->tx_get = 0;
+
+		del_timer(&info->tx_timer);
+
+		if (info->params.mode != MGSL_MODE_ASYNC && info->drop_rts_on_tx_done ) {
+			info->serial_signals &= ~SerialSignal_RTS;
+			info->drop_rts_on_tx_done = 0;
+			set_signals(info);
+		}
+
+#ifdef CONFIG_SYNCLINK_SYNCPPP
+		if (info->netcount)
+			sppp_tx_done(info);
+		else
+#endif
+		{
+			if (info->tty && (info->tty->stopped || info->tty->hw_stopped)) {
+				tx_stop(info);
+				return;
+			}
+			info->pending_bh |= BH_TRANSMIT;
+		}
+	}
+}
+
+
+/*
+ * handle tx status interrupts
+ */
+void isr_txint(SLMP_INFO * info)
+{
+	unsigned char status = read_reg(info, SR1);
+
+	/* clear status bits */
+	write_reg(info, SR1, (unsigned char)(status & (UDRN + IDLE + CCTS)));
+
+	if ( debug_level >= DEBUG_LEVEL_ISR )
+		printk("%s(%d):%s isr_txint status=%02x\n",
+			__FILE__,__LINE__,info->device_name,status);
+
+	if (status & (UDRN + IDLE))
+		isr_txeom(info, status);
+
+	if (status & CCTS) {
+		/* simulate a common modem status change interrupt
+		 * for our handler
+		 */
+		get_signals( info );
+		isr_io_pin(info,
+			MISCSTATUS_CTS_LATCHED|(info->serial_signals&SerialSignal_CTS));
+
+	}
+}
+
+/*
+ * handle async tx data interrupts
+ */
+void isr_txrdy(SLMP_INFO * info)
+{
+	if ( debug_level >= DEBUG_LEVEL_ISR )
+		printk("%s(%d):%s isr_txrdy() tx_count=%d\n",
+			__FILE__,__LINE__,info->device_name,info->tx_count);
+
+	if (info->tty && (info->tty->stopped || info->tty->hw_stopped)) {
+		tx_stop(info);
+		return;
+	}
+
+	if ( info->tx_count )
+		tx_load_fifo( info );
+	else {
+		info->tx_active = 0;
+		info->ie0_value &= ~TXRDYE;
+		write_reg(info, IE0, info->ie0_value);
+	}
+
+	if (info->tx_count < WAKEUP_CHARS)
+		info->pending_bh |= BH_TRANSMIT;
+}
+
+void isr_rxdmaok(SLMP_INFO * info)
+{
+	/* BIT7 = EOT (end of transfer)
+	 * BIT6 = EOM (end of message/frame)
+	 */
+	unsigned char status = read_reg(info,RXDMA + DSR) & 0xc0;
+
+	/* clear IRQ (BIT0 must be 1 to prevent clearing DE bit) */
+	write_reg(info, RXDMA + DSR, (unsigned char)(status | 1));
+
+	if ( debug_level >= DEBUG_LEVEL_ISR )
+		printk("%s(%d):%s isr_rxdmaok(), status=%02x\n",
+			__FILE__,__LINE__,info->device_name,status);
+
+	info->pending_bh |= BH_RECEIVE;
+}
+
+void isr_rxdmaerror(SLMP_INFO * info)
+{
+	/* BIT5 = BOF (buffer overflow)
+	 * BIT4 = COF (counter overflow)
+	 */
+	unsigned char status = read_reg(info,RXDMA + DSR) & 0x30;
+
+	/* clear IRQ (BIT0 must be 1 to prevent clearing DE bit) */
+	write_reg(info, RXDMA + DSR, (unsigned char)(status | 1));
+
+	if ( debug_level >= DEBUG_LEVEL_ISR )
+		printk("%s(%d):%s isr_rxdmaerror(), status=%02x\n",
+			__FILE__,__LINE__,info->device_name,status);
+
+	info->rx_overflow = TRUE;
+	info->pending_bh |= BH_RECEIVE;
+}
+
+void isr_txdmaok(SLMP_INFO * info)
+{
+	/* BIT7 = EOT (end of transfer, used for async mode)
+	 * BIT6 = EOM (end of message/frame, used for sync mode)
+	 *
+	 * We don't look at DMA status because only EOT is enabled
+	 * and we always clear and disable all tx DMA IRQs.
+	 */
+//	unsigned char dma_status = read_reg(info,TXDMA + DSR) & 0xc0;
+	unsigned char status_reg1 = read_reg(info, SR1);
+
+	write_reg(info, TXDMA + DIR, 0x00);	/* disable Tx DMA IRQs */
+	write_reg(info, TXDMA + DSR, 0xc0); /* clear IRQs and disable DMA */
+	write_reg(info, TXDMA + DCMD, SWABORT);	/* reset/init DMA channel */
+
+	if ( debug_level >= DEBUG_LEVEL_ISR )
+		printk("%s(%d):%s isr_txdmaok(), status=%02x\n",
+			__FILE__,__LINE__,info->device_name,status_reg1);
+
+	/* If transmitter already idle, do end of frame processing,
+	 * otherwise enable interrupt for tx IDLE.
+	 */
+	if (status_reg1 & IDLE)
+		isr_txeom(info, IDLE);
+	else {
+		/* disable and clear underrun IRQ, enable IDLE interrupt */
+		info->ie1_value |= IDLE;
+		info->ie1_value &= ~UDRN;
+		write_reg(info, IE1, info->ie1_value);
+
+		write_reg(info, SR1, UDRN);
+	}
+}
+
+void isr_txdmaerror(SLMP_INFO * info)
+{
+	/* BIT5 = BOF (buffer overflow)
+	 * BIT4 = COF (counter overflow)
+	 */
+	unsigned char status = read_reg(info,TXDMA + DSR) & 0x30;
+
+	/* clear IRQ (BIT0 must be 1 to prevent clearing DE bit) */
+	write_reg(info, TXDMA + DSR, (unsigned char)(status | 1));
+
+	if ( debug_level >= DEBUG_LEVEL_ISR )
+		printk("%s(%d):%s isr_txdmaerror(), status=%02x\n",
+			__FILE__,__LINE__,info->device_name,status);
+}
+
+/* handle input serial signal changes
+ */
+void isr_io_pin( SLMP_INFO *info, u16 status )
+{
+ 	struct	mgsl_icount *icount;
+
+	if ( debug_level >= DEBUG_LEVEL_ISR )
+		printk("%s(%d):isr_io_pin status=%04X\n",
+			__FILE__,__LINE__,status);
+
+	if (status & (MISCSTATUS_CTS_LATCHED | MISCSTATUS_DCD_LATCHED |
+	              MISCSTATUS_DSR_LATCHED | MISCSTATUS_RI_LATCHED) ) {
+		icount = &info->icount;
+		/* update input line counters */
+		if (status & MISCSTATUS_RI_LATCHED) {
+			icount->rng++;
+			if ( status & SerialSignal_RI )
+				info->input_signal_events.ri_up++;
+			else
+				info->input_signal_events.ri_down++;
+		}
+		if (status & MISCSTATUS_DSR_LATCHED) {
+			icount->dsr++;
+			if ( status & SerialSignal_DSR )
+				info->input_signal_events.dsr_up++;
+			else
+				info->input_signal_events.dsr_down++;
+		}
+		if (status & MISCSTATUS_DCD_LATCHED) {
+			if ((info->dcd_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) {
+				info->ie1_value &= ~CDCD;
+				write_reg(info, IE1, info->ie1_value);
+			}
+			icount->dcd++;
+			if (status & SerialSignal_DCD) {
+				info->input_signal_events.dcd_up++;
+#ifdef CONFIG_SYNCLINK_SYNCPPP
+				if (info->netcount)
+					sppp_reopen(info->netdev);
+#endif
+			} else
+				info->input_signal_events.dcd_down++;
+		}
+		if (status & MISCSTATUS_CTS_LATCHED)
+		{
+			if ((info->cts_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) {
+				info->ie1_value &= ~CCTS;
+				write_reg(info, IE1, info->ie1_value);
+			}
+			icount->cts++;
+			if ( status & SerialSignal_CTS )
+				info->input_signal_events.cts_up++;
+			else
+				info->input_signal_events.cts_down++;
+		}
+		wake_up_interruptible(&info->status_event_wait_q);
+		wake_up_interruptible(&info->event_wait_q);
+
+		if ( (info->flags & ASYNC_CHECK_CD) &&
+		     (status & MISCSTATUS_DCD_LATCHED) ) {
+			if ( debug_level >= DEBUG_LEVEL_ISR )
+				printk("%s CD now %s...", info->device_name,
+				       (status & SerialSignal_DCD) ? "on" : "off");
+			if (status & SerialSignal_DCD)
+				wake_up_interruptible(&info->open_wait);
+			else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+				   (info->flags & ASYNC_CALLOUT_NOHUP))) {
+				if ( debug_level >= DEBUG_LEVEL_ISR )
+					printk("doing serial hangup...");
+				if (info->tty)
+					tty_hangup(info->tty);
+			}
+		}
+
+		if ( (info->flags & ASYNC_CTS_FLOW) &&
+		     (status & MISCSTATUS_CTS_LATCHED) ) {
+			if ( info->tty ) {
+				if (info->tty->hw_stopped) {
+					if (status & SerialSignal_CTS) {
+						if ( debug_level >= DEBUG_LEVEL_ISR )
+							printk("CTS tx start...");
+			 			info->tty->hw_stopped = 0;
+						tx_start(info);
+						info->pending_bh |= BH_TRANSMIT;
+						return;
+					}
+				} else {
+					if (!(status & SerialSignal_CTS)) {
+						if ( debug_level >= DEBUG_LEVEL_ISR )
+							printk("CTS tx stop...");
+			 			info->tty->hw_stopped = 1;
+						tx_stop(info);
+					}
+				}
+			}
+		}
+	}
+
+	info->pending_bh |= BH_STATUS;
+}
+
+/* Interrupt service routine entry point.
+ *
+ * Arguments:
+ * 	irq		interrupt number that caused interrupt
+ * 	dev_id		device ID supplied during interrupt registration
+ * 	regs		interrupted processor context
+ */
+static void synclinkmp_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+	SLMP_INFO * info;
+	unsigned char status, status0, status1=0;
+	unsigned char dmastatus, dmastatus0, dmastatus1=0;
+	unsigned char timerstatus0, timerstatus1=0;
+	unsigned char shift;
+	unsigned int i;
+	unsigned short tmp;
+
+	if ( debug_level >= DEBUG_LEVEL_ISR )
+		printk("%s(%d): synclinkmp_interrupt(%d)entry.\n",
+			__FILE__,__LINE__,irq);
+
+	info = (SLMP_INFO *)dev_id;
+	if (!info)
+		return;
+
+	spin_lock(&info->lock);
+
+	for(;;) {
+
+		/* get status for SCA0 (ports 0-1) */
+		tmp = read_reg16(info, ISR0);	/* get ISR0 and ISR1 in one read */
+		status0 = (unsigned char)tmp;
+		dmastatus0 = (unsigned char)(tmp>>8);
+		timerstatus0 = read_reg(info, ISR2);
+
+		if ( debug_level >= DEBUG_LEVEL_ISR )
+			printk("%s(%d):%s status0=%02x, dmastatus0=%02x, timerstatus0=%02x\n",
+				__FILE__,__LINE__,info->device_name,
+				status0,dmastatus0,timerstatus0);
+
+		if (info->port_count == 4) {
+			/* get status for SCA1 (ports 2-3) */
+			tmp = read_reg16(info->port_array[2], ISR0);
+			status1 = (unsigned char)tmp;
+			dmastatus1 = (unsigned char)(tmp>>8);
+			timerstatus1 = read_reg(info->port_array[2], ISR2);
+
+			if ( debug_level >= DEBUG_LEVEL_ISR )
+				printk("%s(%d):%s status1=%02x, dmastatus1=%02x, timerstatus1=%02x\n",
+					__FILE__,__LINE__,info->device_name,
+					status1,dmastatus1,timerstatus1);
+		}
+
+		if (!status0 && !dmastatus0 && !timerstatus0 &&
+			 !status1 && !dmastatus1 && !timerstatus1)
+			break;
+
+		for(i=0; i < info->port_count ; i++) {
+			if (info->port_array[i] == NULL)
+				continue;
+			if (i < 2) {
+				status = status0;
+				dmastatus = dmastatus0;
+			} else {
+				status = status1;
+				dmastatus = dmastatus1;
+			}
+
+			shift = i & 1 ? 4 :0;
+
+			if (status & BIT0 << shift)
+				isr_rxrdy(info->port_array[i]);
+			if (status & BIT1 << shift)
+				isr_txrdy(info->port_array[i]);
+			if (status & BIT2 << shift)
+				isr_rxint(info->port_array[i]);
+			if (status & BIT3 << shift)
+				isr_txint(info->port_array[i]);
+
+			if (dmastatus & BIT0 << shift)
+				isr_rxdmaerror(info->port_array[i]);
+			if (dmastatus & BIT1 << shift)
+				isr_rxdmaok(info->port_array[i]);
+			if (dmastatus & BIT2 << shift)
+				isr_txdmaerror(info->port_array[i]);
+			if (dmastatus & BIT3 << shift)
+				isr_txdmaok(info->port_array[i]);
+		}
+
+		if (timerstatus0 & (BIT5 | BIT4))
+			isr_timer(info->port_array[0]);
+		if (timerstatus0 & (BIT7 | BIT6))
+			isr_timer(info->port_array[1]);
+		if (timerstatus1 & (BIT5 | BIT4))
+			isr_timer(info->port_array[2]);
+		if (timerstatus1 & (BIT7 | BIT6))
+			isr_timer(info->port_array[3]);
+	}
+
+	for(i=0; i < info->port_count ; i++) {
+		SLMP_INFO * port = info->port_array[i];
+
+		/* Request bottom half processing if there's something
+		 * for it to do and the bh is not already running.
+		 *
+		 * Note: startup adapter diags require interrupts.
+		 * do not request bottom half processing if the
+		 * device is not open in a normal mode.
+		 */
+		if ( port && (port->count || port->netcount) &&
+		     port->pending_bh && !port->bh_running &&
+		     !port->bh_requested ) {
+			if ( debug_level >= DEBUG_LEVEL_ISR )
+				printk("%s(%d):%s queueing bh task.\n",
+					__FILE__,__LINE__,port->device_name);
+			queue_task(&port->task, &tq_immediate);
+			mark_bh(IMMEDIATE_BH);
+			port->bh_requested = 1;
+		}
+	}
+
+	spin_unlock(&info->lock);
+
+	if ( debug_level >= DEBUG_LEVEL_ISR )
+		printk("%s(%d):synclinkmp_interrupt(%d)exit.\n",
+			__FILE__,__LINE__,irq);
+}
+
+/* Initialize and start device.
+ */
+static int startup(SLMP_INFO * info)
+{
+	if ( debug_level >= DEBUG_LEVEL_INFO )
+		printk("%s(%d):%s tx_releaseup()\n",__FILE__,__LINE__,info->device_name);
+
+	if (info->flags & ASYNC_INITIALIZED)
+		return 0;
+
+	if (!info->tx_buf) {
+		info->tx_buf = (unsigned char *)kmalloc(info->max_frame_size, GFP_KERNEL);
+		if (!info->tx_buf) {
+			printk(KERN_ERR"%s(%d):%s can't allocate transmit buffer\n",
+				__FILE__,__LINE__,info->device_name);
+			return -ENOMEM;
+		}
+	}
+
+	info->pending_bh = 0;
+
+	init_timer(&info->tx_timer);
+	info->tx_timer.data = (unsigned long)info;
+	info->tx_timer.function = tx_timeout;
+
+	/* program hardware for current parameters */
+	reset_port(info);
+
+	change_params(info);
+
+	init_timer(&info->status_timer);
+	info->status_timer.data = (unsigned long)info;
+	info->status_timer.function = status_timeout;
+	info->status_timer.expires = jiffies + jiffies_from_ms(10);
+	add_timer(&info->status_timer);
+
+	if (info->tty)
+		clear_bit(TTY_IO_ERROR, &info->tty->flags);
+
+	info->flags |= ASYNC_INITIALIZED;
+
+	return 0;
+}
+
+/* Called by close() and hangup() to shutdown hardware
+ */
+static void shutdown(SLMP_INFO * info)
+{
+	unsigned long flags;
+
+	if (!(info->flags & ASYNC_INITIALIZED))
+		return;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s synclinkmp_shutdown()\n",
+			 __FILE__,__LINE__, info->device_name );
+
+	/* clear status wait queue because status changes */
+	/* can't happen after shutting down the hardware */
+	wake_up_interruptible(&info->status_event_wait_q);
+	wake_up_interruptible(&info->event_wait_q);
+
+	del_timer(&info->tx_timer);
+	del_timer(&info->status_timer);
+
+	if (info->tx_buf) {
+		free_page((unsigned long) info->tx_buf);
+		info->tx_buf = 0;
+	}
+
+	spin_lock_irqsave(&info->lock,flags);
+
+	reset_port(info);
+
+ 	if (!info->tty || info->tty->termios->c_cflag & HUPCL) {
+ 		info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS);
+		set_signals(info);
+	}
+
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	if (info->tty)
+		set_bit(TTY_IO_ERROR, &info->tty->flags);
+
+	info->flags &= ~ASYNC_INITIALIZED;
+}
+
+static void program_hw(SLMP_INFO *info)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&info->lock,flags);
+
+	rx_stop(info);
+	tx_stop(info);
+
+	info->tx_count = info->tx_put = info->tx_get = 0;
+
+	if (info->params.mode == MGSL_MODE_HDLC || info->netcount)
+		hdlc_mode(info);
+	else
+		async_mode(info);
+
+	set_signals(info);
+
+	info->dcd_chkcount = 0;
+	info->cts_chkcount = 0;
+	info->ri_chkcount = 0;
+	info->dsr_chkcount = 0;
+
+	info->ie1_value |= (CDCD|CCTS);
+	write_reg(info, IE1, info->ie1_value);
+
+	get_signals(info);
+
+	if (info->netcount || (info->tty && info->tty->termios->c_cflag & CREAD) )
+		rx_start(info);
+
+	spin_unlock_irqrestore(&info->lock,flags);
+}
+
+/* Reconfigure adapter based on new parameters
+ */
+static void change_params(SLMP_INFO *info)
+{
+	unsigned cflag;
+	int bits_per_char;
+
+	if (!info->tty || !info->tty->termios)
+		return;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s change_params()\n",
+			 __FILE__,__LINE__, info->device_name );
+
+	cflag = info->tty->termios->c_cflag;
+
+	/* if B0 rate (hangup) specified then negate DTR and RTS */
+	/* otherwise assert DTR and RTS */
+ 	if (cflag & CBAUD)
+		info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
+	else
+		info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
+
+	/* byte size and parity */
+
+	switch (cflag & CSIZE) {
+	      case CS5: info->params.data_bits = 5; break;
+	      case CS6: info->params.data_bits = 6; break;
+	      case CS7: info->params.data_bits = 7; break;
+	      case CS8: info->params.data_bits = 8; break;
+	      /* Never happens, but GCC is too dumb to figure it out */
+	      default:  info->params.data_bits = 7; break;
+	      }
+
+	if (cflag & CSTOPB)
+		info->params.stop_bits = 2;
+	else
+		info->params.stop_bits = 1;
+
+	info->params.parity = ASYNC_PARITY_NONE;
+	if (cflag & PARENB) {
+		if (cflag & PARODD)
+			info->params.parity = ASYNC_PARITY_ODD;
+		else
+			info->params.parity = ASYNC_PARITY_EVEN;
+#ifdef CMSPAR
+		if (cflag & CMSPAR)
+			info->params.parity = ASYNC_PARITY_SPACE;
+#endif
+	}
+
+	/* calculate number of jiffies to transmit a full
+	 * FIFO (32 bytes) at specified data rate
+	 */
+	bits_per_char = info->params.data_bits +
+			info->params.stop_bits + 1;
+
+	/* if port data rate is set to 460800 or less then
+	 * allow tty settings to override, otherwise keep the
+	 * current data rate.
+	 */
+	if (info->params.data_rate <= 460800) {
+		info->params.data_rate = tty_get_baud_rate(info->tty);
+	}
+
+	if ( info->params.data_rate ) {
+		info->timeout = (32*HZ*bits_per_char) /
+				info->params.data_rate;
+	}
+	info->timeout += HZ/50;		/* Add .02 seconds of slop */
+
+	if (cflag & CRTSCTS)
+		info->flags |= ASYNC_CTS_FLOW;
+	else
+		info->flags &= ~ASYNC_CTS_FLOW;
+
+	if (cflag & CLOCAL)
+		info->flags &= ~ASYNC_CHECK_CD;
+	else
+		info->flags |= ASYNC_CHECK_CD;
+
+	/* process tty input control flags */
+
+	info->read_status_mask2 = OVRN;
+	if (I_INPCK(info->tty))
+		info->read_status_mask2 |= PE | FRME;
+ 	if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
+ 		info->read_status_mask1 |= BRKD;
+	if (I_IGNPAR(info->tty))
+		info->ignore_status_mask2 |= PE | FRME;
+	if (I_IGNBRK(info->tty)) {
+		info->ignore_status_mask1 |= BRKD;
+		/* If ignoring parity and break indicators, ignore
+		 * overruns too.  (For real raw support).
+		 */
+		if (I_IGNPAR(info->tty))
+			info->ignore_status_mask2 |= OVRN;
+	}
+
+	program_hw(info);
+}
+
+static int get_stats(SLMP_INFO * info, struct mgsl_icount *user_icount)
+{
+	int err;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s get_params()\n",
+			 __FILE__,__LINE__, info->device_name);
+
+	COPY_TO_USER(err,user_icount, &info->icount, sizeof(struct mgsl_icount));
+	if (err) {
+		if ( debug_level >= DEBUG_LEVEL_INFO )
+			printk( "%s(%d):%s get_stats() user buffer copy failed\n",
+				__FILE__,__LINE__,info->device_name);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int get_params(SLMP_INFO * info, MGSL_PARAMS *user_params)
+{
+	int err;
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s get_params()\n",
+			 __FILE__,__LINE__, info->device_name);
+
+	COPY_TO_USER(err,user_params, &info->params, sizeof(MGSL_PARAMS));
+	if (err) {
+		if ( debug_level >= DEBUG_LEVEL_INFO )
+			printk( "%s(%d):%s get_params() user buffer copy failed\n",
+				__FILE__,__LINE__,info->device_name);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int set_params(SLMP_INFO * info, MGSL_PARAMS *new_params)
+{
+ 	unsigned long flags;
+	MGSL_PARAMS tmp_params;
+	int err;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s set_params\n",
+			__FILE__,__LINE__,info->device_name );
+	COPY_FROM_USER(err,&tmp_params, new_params, sizeof(MGSL_PARAMS));
+	if (err) {
+		if ( debug_level >= DEBUG_LEVEL_INFO )
+			printk( "%s(%d):%s set_params() user buffer copy failed\n",
+				__FILE__,__LINE__,info->device_name);
+		return -EFAULT;
+	}
+
+	spin_lock_irqsave(&info->lock,flags);
+	memcpy(&info->params,&tmp_params,sizeof(MGSL_PARAMS));
+	spin_unlock_irqrestore(&info->lock,flags);
+
+ 	change_params(info);
+
+	return 0;
+}
+
+static int get_txidle(SLMP_INFO * info, int*idle_mode)
+{
+	int err;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s get_txidle()=%d\n",
+			 __FILE__,__LINE__, info->device_name, info->idle_mode);
+
+	COPY_TO_USER(err,idle_mode, &info->idle_mode, sizeof(int));
+	if (err) {
+		if ( debug_level >= DEBUG_LEVEL_INFO )
+			printk( "%s(%d):%s get_txidle() user buffer copy failed\n",
+				__FILE__,__LINE__,info->device_name);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int set_txidle(SLMP_INFO * info, int idle_mode)
+{
+ 	unsigned long flags;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s set_txidle(%d)\n",
+			__FILE__,__LINE__,info->device_name, idle_mode );
+
+	spin_lock_irqsave(&info->lock,flags);
+	info->idle_mode = idle_mode;
+	tx_set_idle( info );
+	spin_unlock_irqrestore(&info->lock,flags);
+	return 0;
+}
+
+static int tx_enable(SLMP_INFO * info, int enable)
+{
+ 	unsigned long flags;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s tx_enable(%d)\n",
+			__FILE__,__LINE__,info->device_name, enable);
+
+	spin_lock_irqsave(&info->lock,flags);
+	if ( enable ) {
+		if ( !info->tx_enabled ) {
+			tx_start(info);
+		}
+	} else {
+		if ( info->tx_enabled )
+			tx_stop(info);
+	}
+	spin_unlock_irqrestore(&info->lock,flags);
+	return 0;
+}
+
+/* abort send HDLC frame
+ */
+static int tx_abort(SLMP_INFO * info)
+{
+ 	unsigned long flags;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s tx_abort()\n",
+			__FILE__,__LINE__,info->device_name);
+
+	spin_lock_irqsave(&info->lock,flags);
+	if ( info->tx_active && info->params.mode == MGSL_MODE_HDLC ) {
+		info->ie1_value &= ~UDRN;
+		info->ie1_value |= IDLE;
+		write_reg(info, IE1, info->ie1_value);	/* disable tx status interrupts */
+		write_reg(info, SR1, (unsigned char)(IDLE + UDRN));	/* clear pending */
+
+		write_reg(info, TXDMA + DSR, 0);		/* disable DMA channel */
+		write_reg(info, TXDMA + DCMD, SWABORT);	/* reset/init DMA channel */
+
+   		write_reg(info, CMD, TXABORT);
+	}
+	spin_unlock_irqrestore(&info->lock,flags);
+	return 0;
+}
+
+static int rx_enable(SLMP_INFO * info, int enable)
+{
+ 	unsigned long flags;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s rx_enable(%d)\n",
+			__FILE__,__LINE__,info->device_name,enable);
+
+	spin_lock_irqsave(&info->lock,flags);
+	if ( enable ) {
+		if ( !info->rx_enabled )
+			rx_start(info);
+	} else {
+		if ( info->rx_enabled )
+			rx_stop(info);
+	}
+	spin_unlock_irqrestore(&info->lock,flags);
+	return 0;
+}
+
+static int map_status(int signals)
+{
+	/* Map status bits to API event bits */
+
+	return ((signals & SerialSignal_DSR) ? MgslEvent_DsrActive : MgslEvent_DsrInactive) +
+	       ((signals & SerialSignal_CTS) ? MgslEvent_CtsActive : MgslEvent_CtsInactive) +
+	       ((signals & SerialSignal_DCD) ? MgslEvent_DcdActive : MgslEvent_DcdInactive) +
+	       ((signals & SerialSignal_RI)  ? MgslEvent_RiActive : MgslEvent_RiInactive);
+}
+
+/* wait for specified event to occur
+ */
+static int wait_mgsl_event(SLMP_INFO * info, int * mask_ptr)
+{
+ 	unsigned long flags;
+	int s;
+	int rc=0;
+	struct mgsl_icount cprev, cnow;
+	int events;
+	int mask;
+	struct	_input_signal_events oldsigs, newsigs;
+	DECLARE_WAITQUEUE(wait, current);
+
+	COPY_FROM_USER(rc,&mask, mask_ptr, sizeof(int));
+	if (rc) {
+		return  -EFAULT;
+	}
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s wait_mgsl_event(%d)\n",
+			__FILE__,__LINE__,info->device_name,mask);
+
+	spin_lock_irqsave(&info->lock,flags);
+
+	/* return immediately if state matches requested events */
+	get_signals(info);
+	s = map_status(info->serial_signals);
+
+	events = mask &
+		( ((s & SerialSignal_DSR) ? MgslEvent_DsrActive:MgslEvent_DsrInactive) +
+ 		  ((s & SerialSignal_DCD) ? MgslEvent_DcdActive:MgslEvent_DcdInactive) +
+		  ((s & SerialSignal_CTS) ? MgslEvent_CtsActive:MgslEvent_CtsInactive) +
+		  ((s & SerialSignal_RI)  ? MgslEvent_RiActive :MgslEvent_RiInactive) );
+	if (events) {
+		spin_unlock_irqrestore(&info->lock,flags);
+		goto exit;
+	}
+
+	/* save current irq counts */
+	cprev = info->icount;
+	oldsigs = info->input_signal_events;
+
+	/* enable hunt and idle irqs if needed */
+	if (mask & (MgslEvent_ExitHuntMode+MgslEvent_IdleReceived)) {
+		unsigned char oldval = info->ie1_value;
+		unsigned char newval = oldval +
+			 (mask & MgslEvent_ExitHuntMode ? FLGD:0) +
+			 (mask & MgslEvent_IdleReceived ? IDLE:0);
+		if ( oldval != newval ) {
+			info->ie1_value = newval;
+			write_reg(info, IE1, info->ie1_value);
+		}
+	}
+
+	set_current_state(TASK_INTERRUPTIBLE);
+	add_wait_queue(&info->event_wait_q, &wait);
+
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	for(;;) {
+		schedule();
+		if (signal_pending(current)) {
+			rc = -ERESTARTSYS;
+			break;
+		}
+
+		/* get current irq counts */
+		spin_lock_irqsave(&info->lock,flags);
+		cnow = info->icount;
+		newsigs = info->input_signal_events;
+		set_current_state(TASK_INTERRUPTIBLE);
+		spin_unlock_irqrestore(&info->lock,flags);
+
+		/* if no change, wait aborted for some reason */
+		if (newsigs.dsr_up   == oldsigs.dsr_up   &&
+		    newsigs.dsr_down == oldsigs.dsr_down &&
+		    newsigs.dcd_up   == oldsigs.dcd_up   &&
+		    newsigs.dcd_down == oldsigs.dcd_down &&
+		    newsigs.cts_up   == oldsigs.cts_up   &&
+		    newsigs.cts_down == oldsigs.cts_down &&
+		    newsigs.ri_up    == oldsigs.ri_up    &&
+		    newsigs.ri_down  == oldsigs.ri_down  &&
+		    cnow.exithunt    == cprev.exithunt   &&
+		    cnow.rxidle      == cprev.rxidle) {
+			rc = -EIO;
+			break;
+		}
+
+		events = mask &
+			( (newsigs.dsr_up   != oldsigs.dsr_up   ? MgslEvent_DsrActive:0)   +
+			  (newsigs.dsr_down != oldsigs.dsr_down ? MgslEvent_DsrInactive:0) +
+			  (newsigs.dcd_up   != oldsigs.dcd_up   ? MgslEvent_DcdActive:0)   +
+			  (newsigs.dcd_down != oldsigs.dcd_down ? MgslEvent_DcdInactive:0) +
+			  (newsigs.cts_up   != oldsigs.cts_up   ? MgslEvent_CtsActive:0)   +
+			  (newsigs.cts_down != oldsigs.cts_down ? MgslEvent_CtsInactive:0) +
+			  (newsigs.ri_up    != oldsigs.ri_up    ? MgslEvent_RiActive:0)    +
+			  (newsigs.ri_down  != oldsigs.ri_down  ? MgslEvent_RiInactive:0)  +
+			  (cnow.exithunt    != cprev.exithunt   ? MgslEvent_ExitHuntMode:0) +
+			  (cnow.rxidle      != cprev.rxidle     ? MgslEvent_IdleReceived:0) );
+		if (events)
+			break;
+
+		cprev = cnow;
+		oldsigs = newsigs;
+	}
+
+	remove_wait_queue(&info->event_wait_q, &wait);
+	set_current_state(TASK_RUNNING);
+
+
+	if (mask & (MgslEvent_ExitHuntMode + MgslEvent_IdleReceived)) {
+		spin_lock_irqsave(&info->lock,flags);
+		if (!waitqueue_active(&info->event_wait_q)) {
+			/* disable enable exit hunt mode/idle rcvd IRQs */
+			info->ie1_value &= ~(FLGD|IDLE);
+			write_reg(info, IE1, info->ie1_value);
+		}
+		spin_unlock_irqrestore(&info->lock,flags);
+	}
+exit:
+	if ( rc == 0 )
+		PUT_USER(rc, events, mask_ptr);
+
+	return rc;
+}
+
+static int modem_input_wait(SLMP_INFO *info,int arg)
+{
+ 	unsigned long flags;
+	int rc;
+	struct mgsl_icount cprev, cnow;
+	DECLARE_WAITQUEUE(wait, current);
+
+	/* save current irq counts */
+	spin_lock_irqsave(&info->lock,flags);
+	cprev = info->icount;
+	add_wait_queue(&info->status_event_wait_q, &wait);
+	set_current_state(TASK_INTERRUPTIBLE);
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	for(;;) {
+		schedule();
+		if (signal_pending(current)) {
+			rc = -ERESTARTSYS;
+			break;
+		}
+
+		/* get new irq counts */
+		spin_lock_irqsave(&info->lock,flags);
+		cnow = info->icount;
+		set_current_state(TASK_INTERRUPTIBLE);
+		spin_unlock_irqrestore(&info->lock,flags);
+
+		/* if no change, wait aborted for some reason */
+		if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
+		    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) {
+			rc = -EIO;
+			break;
+		}
+
+		/* check for change in caller specified modem input */
+		if ((arg & TIOCM_RNG && cnow.rng != cprev.rng) ||
+		    (arg & TIOCM_DSR && cnow.dsr != cprev.dsr) ||
+		    (arg & TIOCM_CD  && cnow.dcd != cprev.dcd) ||
+		    (arg & TIOCM_CTS && cnow.cts != cprev.cts)) {
+			rc = 0;
+			break;
+		}
+
+		cprev = cnow;
+	}
+	remove_wait_queue(&info->status_event_wait_q, &wait);
+	set_current_state(TASK_RUNNING);
+	return rc;
+}
+
+/* return the state of the serial control and status signals
+ */
+static int get_modem_info(SLMP_INFO * info, unsigned int *value)
+{
+	unsigned int result;
+ 	unsigned long flags;
+	int err;
+
+	spin_lock_irqsave(&info->lock,flags);
+ 	get_signals(info);
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	result = ((info->serial_signals & SerialSignal_RTS) ? TIOCM_RTS:0) +
+		((info->serial_signals & SerialSignal_DTR) ? TIOCM_DTR:0) +
+		((info->serial_signals & SerialSignal_DCD) ? TIOCM_CAR:0) +
+		((info->serial_signals & SerialSignal_RI)  ? TIOCM_RNG:0) +
+		((info->serial_signals & SerialSignal_DSR) ? TIOCM_DSR:0) +
+		((info->serial_signals & SerialSignal_CTS) ? TIOCM_CTS:0);
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s synclinkmp_get_modem_info() value=%08X\n",
+			 __FILE__,__LINE__, info->device_name, result );
+
+	PUT_USER(err,result,value);
+	return err;
+}
+
+/* set modem control signals (DTR/RTS)
+ *
+ * 	cmd	signal command: TIOCMBIS = set bit TIOCMBIC = clear bit
+ *		TIOCMSET = set/clear signal values
+ * 	value	bit mask for command
+ */
+static int set_modem_info(SLMP_INFO * info, unsigned int cmd,
+			  unsigned int *value)
+{
+ 	int error;
+ 	unsigned int arg;
+ 	unsigned long flags;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s synclinkmp_set_modem_info()\n",
+			__FILE__,__LINE__,info->device_name );
+
+ 	GET_USER(error,arg,value);
+ 	if (error)
+ 		return error;
+
+ 	switch (cmd) {
+ 	case TIOCMBIS:
+ 		if (arg & TIOCM_RTS)
+ 			info->serial_signals |= SerialSignal_RTS;
+ 		if (arg & TIOCM_DTR)
+ 			info->serial_signals |= SerialSignal_DTR;
+ 		break;
+ 	case TIOCMBIC:
+ 		if (arg & TIOCM_RTS)
+ 			info->serial_signals &= ~SerialSignal_RTS;
+ 		if (arg & TIOCM_DTR)
+ 			info->serial_signals &= ~SerialSignal_DTR;
+ 		break;
+ 	case TIOCMSET:
+ 		if (arg & TIOCM_RTS)
+ 			info->serial_signals |= SerialSignal_RTS;
+		else
+ 			info->serial_signals &= ~SerialSignal_RTS;
+
+ 		if (arg & TIOCM_DTR)
+ 			info->serial_signals |= SerialSignal_DTR;
+		else
+ 			info->serial_signals &= ~SerialSignal_DTR;
+ 		break;
+ 	default:
+ 		return -EINVAL;
+ 	}
+
+	spin_lock_irqsave(&info->lock,flags);
+ 	set_signals(info);
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	return 0;
+}
+
+
+
+/* Block the current process until the specified port is ready to open.
+ */
+static int block_til_ready(struct tty_struct *tty, struct file *filp,
+			   SLMP_INFO *info)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	int		retval;
+	int		do_clocal = 0, extra_count = 0;
+	unsigned long	flags;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s block_til_ready()\n",
+			 __FILE__,__LINE__, tty->driver.name );
+
+	if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
+		/* this is a callout device */
+		/* just verify that normal device is not in use */
+		if (info->flags & ASYNC_NORMAL_ACTIVE)
+			return -EBUSY;
+		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    (info->flags & ASYNC_SESSION_LOCKOUT) &&
+		    (info->session != current->session))
+		    return -EBUSY;
+		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    (info->flags & ASYNC_PGRP_LOCKOUT) &&
+		    (info->pgrp != current->pgrp))
+		    return -EBUSY;
+		info->flags |= ASYNC_CALLOUT_ACTIVE;
+		return 0;
+	}
+
+	if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){
+		/* nonblock mode is set or port is not enabled */
+		/* just verify that callout device is not active */
+		if (info->flags & ASYNC_CALLOUT_ACTIVE)
+			return -EBUSY;
+		info->flags |= ASYNC_NORMAL_ACTIVE;
+		return 0;
+	}
+
+	if (info->flags & ASYNC_CALLOUT_ACTIVE) {
+		if (info->normal_termios.c_cflag & CLOCAL)
+			do_clocal = 1;
+	} else {
+		if (tty->termios->c_cflag & CLOCAL)
+			do_clocal = 1;
+	}
+
+	/* Wait for carrier detect and the line to become
+	 * free (i.e., not in use by the callout).  While we are in
+	 * this loop, info->count is dropped by one, so that
+	 * close() knows when to free things.  We restore it upon
+	 * exit, either normal or abnormal.
+	 */
+
+	retval = 0;
+	add_wait_queue(&info->open_wait, &wait);
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s block_til_ready() before block, count=%d\n",
+			 __FILE__,__LINE__, tty->driver.name, info->count );
+
+	save_flags(flags); cli();
+	if (!tty_hung_up_p(filp)) {
+		extra_count = 1;
+		info->count--;
+	}
+	restore_flags(flags);
+	info->blocked_open++;
+
+	while (1) {
+		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+ 		    (tty->termios->c_cflag & CBAUD)) {
+			spin_lock_irqsave(&info->lock,flags);
+			info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
+		 	set_signals(info);
+			spin_unlock_irqrestore(&info->lock,flags);
+		}
+
+		set_current_state(TASK_INTERRUPTIBLE);
+
+		if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)){
+			retval = (info->flags & ASYNC_HUP_NOTIFY) ?
+					-EAGAIN : -ERESTARTSYS;
+			break;
+		}
+
+		spin_lock_irqsave(&info->lock,flags);
+	 	get_signals(info);
+		spin_unlock_irqrestore(&info->lock,flags);
+
+ 		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+ 		    !(info->flags & ASYNC_CLOSING) &&
+ 		    (do_clocal || (info->serial_signals & SerialSignal_DCD)) ) {
+ 			break;
+		}
+
+		if (signal_pending(current)) {
+			retval = -ERESTARTSYS;
+			break;
+		}
+
+		if (debug_level >= DEBUG_LEVEL_INFO)
+			printk("%s(%d):%s block_til_ready() count=%d\n",
+				 __FILE__,__LINE__, tty->driver.name, info->count );
+
+		schedule();
+	}
+
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&info->open_wait, &wait);
+
+	if (extra_count)
+		info->count++;
+	info->blocked_open--;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s block_til_ready() after, count=%d\n",
+			 __FILE__,__LINE__, tty->driver.name, info->count );
+
+	if (!retval)
+		info->flags |= ASYNC_NORMAL_ACTIVE;
+
+	return retval;
+}
+
+int alloc_dma_bufs(SLMP_INFO *info)
+{
+	unsigned short BuffersPerFrame;
+	unsigned short BufferCount;
+
+	// Force allocation to start at 64K boundary for each port.
+	// This is necessary because *all* buffer descriptors for a port
+	// *must* be in the same 64K block. All descriptors on a port
+	// share a common 'base' address (upper 8 bits of 24 bits) programmed
+	// into the CBP register.
+	info->port_array[0]->last_mem_alloc = (SCA_MEM_SIZE/4) * info->port_num;
+
+	/* Calculate the number of DMA buffers necessary to hold the */
+	/* largest allowable frame size. Note: If the max frame size is */
+	/* not an even multiple of the DMA buffer size then we need to */
+	/* round the buffer count per frame up one. */
+
+	BuffersPerFrame = (unsigned short)(info->max_frame_size/SCABUFSIZE);
+	if ( info->max_frame_size % SCABUFSIZE )
+		BuffersPerFrame++;
+
+	/* calculate total number of data buffers (SCABUFSIZE) possible
+	 * in one ports memory (SCA_MEM_SIZE/4) after allocating memory
+	 * for the descriptor list (BUFFERLISTSIZE).
+	 */
+	BufferCount = (SCA_MEM_SIZE/4 - BUFFERLISTSIZE)/SCABUFSIZE;
+
+	/* limit number of buffers to maximum amount of descriptors */
+	if (BufferCount > BUFFERLISTSIZE/sizeof(SCADESC))
+		BufferCount = BUFFERLISTSIZE/sizeof(SCADESC);
+
+	/* use enough buffers to transmit one max size frame */
+	info->tx_buf_count = BuffersPerFrame + 1;
+
+	/* never use more than half the available buffers for transmit */
+	if (info->tx_buf_count > (BufferCount/2))
+		info->tx_buf_count = BufferCount/2;
+
+	if (info->tx_buf_count > SCAMAXDESC)
+		info->tx_buf_count = SCAMAXDESC;
+
+	/* use remaining buffers for receive */
+	info->rx_buf_count = BufferCount - info->tx_buf_count;
+
+	if (info->rx_buf_count > SCAMAXDESC)
+		info->rx_buf_count = SCAMAXDESC;
+
+	if ( debug_level >= DEBUG_LEVEL_INFO )
+		printk("%s(%d):%s Allocating %d TX and %d RX DMA buffers.\n",
+			__FILE__,__LINE__, info->device_name,
+			info->tx_buf_count,info->rx_buf_count);
+
+	if ( alloc_buf_list( info ) < 0 ||
+		alloc_frame_bufs(info,
+		  			info->rx_buf_list,
+		  			info->rx_buf_list_ex,
+					info->rx_buf_count) < 0 ||
+		alloc_frame_bufs(info,
+					info->tx_buf_list,
+					info->tx_buf_list_ex,
+					info->tx_buf_count) < 0 ||
+		alloc_tmp_rx_buf(info) < 0 ) {
+		printk("%s(%d):%s Can't allocate DMA buffer memory\n",
+			__FILE__,__LINE__, info->device_name);
+		return -ENOMEM;
+	}
+
+	rx_reset_buffers( info );
+
+	return 0;
+}
+
+/* Allocate DMA buffers for the transmit and receive descriptor lists.
+ */
+int alloc_buf_list(SLMP_INFO *info)
+{
+	unsigned int i;
+
+	/* build list in adapter shared memory */
+	info->buffer_list = info->memory_base + info->port_array[0]->last_mem_alloc;
+	info->buffer_list_phys = info->port_array[0]->last_mem_alloc;
+	info->port_array[0]->last_mem_alloc += BUFFERLISTSIZE;
+
+	memset(info->buffer_list, 0, BUFFERLISTSIZE);
+
+	/* Save virtual address pointers to the receive and */
+	/* transmit buffer lists. (Receive 1st). These pointers will */
+	/* be used by the processor to access the lists. */
+	info->rx_buf_list = (SCADESC *)info->buffer_list;
+
+	info->tx_buf_list = (SCADESC *)info->buffer_list;
+	info->tx_buf_list += info->rx_buf_count;
+
+	/* Build links for circular buffer entry lists (tx and rx)
+	 *
+	 * Note: links are physical addresses read by the SCA device
+	 * to determine the next buffer entry to use.
+	 */
+
+	for ( i = 0; i < info->rx_buf_count; i++ ) {
+		/* calculate and store physical address of this buffer entry */
+		info->rx_buf_list_ex[i].phys_entry =
+			info->buffer_list_phys + (i * sizeof(SCABUFSIZE));
+
+		/* calculate and store physical address of */
+		/* next entry in cirular list of entries */
+		info->rx_buf_list[i].next = info->buffer_list_phys;
+		if ( i < info->rx_buf_count - 1 )
+			info->rx_buf_list[i].next += (i + 1) * sizeof(SCADESC);
+
+		info->rx_buf_list[i].length = SCABUFSIZE;
+	}
+
+	for ( i = 0; i < info->tx_buf_count; i++ ) {
+		/* calculate and store physical address of this buffer entry */
+		info->tx_buf_list_ex[i].phys_entry = info->buffer_list_phys +
+			((info->rx_buf_count + i) * sizeof(SCADESC));
+
+		/* calculate and store physical address of */
+		/* next entry in cirular list of entries */
+
+		info->tx_buf_list[i].next = info->buffer_list_phys +
+			info->rx_buf_count * sizeof(SCADESC);
+
+		if ( i < info->tx_buf_count - 1 )
+			info->tx_buf_list[i].next += (i + 1) * sizeof(SCADESC);
+	}
+
+	return 0;
+}
+
+/* Allocate the frame DMA buffers used by the specified buffer list.
+ */
+int alloc_frame_bufs(SLMP_INFO *info, SCADESC *buf_list,SCADESC_EX *buf_list_ex,int count)
+{
+	int i;
+	unsigned long phys_addr;
+
+	for ( i = 0; i < count; i++ ) {
+		buf_list_ex[i].virt_addr = info->memory_base + info->port_array[0]->last_mem_alloc;
+		phys_addr = info->port_array[0]->last_mem_alloc;
+		info->port_array[0]->last_mem_alloc += SCABUFSIZE;
+
+		buf_list[i].buf_ptr  = (unsigned short)phys_addr;
+		buf_list[i].buf_base = (unsigned char)(phys_addr >> 16);
+	}
+
+	return 0;
+}
+
+void free_dma_bufs(SLMP_INFO *info)
+{
+	info->buffer_list = NULL;
+	info->rx_buf_list = NULL;
+	info->tx_buf_list = NULL;
+}
+
+/* allocate buffer large enough to hold max_frame_size.
+ * This buffer is used to pass an assembled frame to the line discipline.
+ */
+int alloc_tmp_rx_buf(SLMP_INFO *info)
+{
+	info->tmp_rx_buf = kmalloc(info->max_frame_size, GFP_KERNEL);
+	if (info->tmp_rx_buf == NULL)
+		return -ENOMEM;
+	return 0;
+}
+
+void free_tmp_rx_buf(SLMP_INFO *info)
+{
+	if (info->tmp_rx_buf)
+		kfree(info->tmp_rx_buf);
+	info->tmp_rx_buf = NULL;
+}
+
+int claim_resources(SLMP_INFO *info)
+{
+	if (request_mem_region(info->phys_memory_base,0x40000,"synclinkmp") == NULL) {
+		printk( "%s(%d):%s mem addr conflict, Addr=%08X\n",
+			__FILE__,__LINE__,info->device_name, info->phys_memory_base);
+		goto errout;
+	}
+	else
+		info->shared_mem_requested = 1;
+
+	if (request_mem_region(info->phys_lcr_base + info->lcr_offset,128,"synclinkmp") == NULL) {
+		printk( "%s(%d):%s lcr mem addr conflict, Addr=%08X\n",
+			__FILE__,__LINE__,info->device_name, info->phys_lcr_base);
+		goto errout;
+	}
+	else
+		info->lcr_mem_requested = 1;
+
+	if (request_mem_region(info->phys_sca_base + info->sca_offset,512,"synclinkmp") == NULL) {
+		printk( "%s(%d):%s sca mem addr conflict, Addr=%08X\n",
+			__FILE__,__LINE__,info->device_name, info->phys_sca_base);
+		goto errout;
+	}
+	else
+		info->sca_base_requested = 1;
+
+	if (request_mem_region(info->phys_statctrl_base + info->statctrl_offset,16,"synclinkmp") == NULL) {
+		printk( "%s(%d):%s stat/ctrl mem addr conflict, Addr=%08X\n",
+			__FILE__,__LINE__,info->device_name, info->phys_statctrl_base);
+		goto errout;
+	}
+	else
+		info->sca_statctrl_requested = 1;
+
+	info->memory_base = ioremap(info->phys_memory_base,SCA_MEM_SIZE);
+	if (!info->memory_base) {
+		printk( "%s(%d):%s Cant map shared memory, MemAddr=%08X\n",
+			__FILE__,__LINE__,info->device_name, info->phys_memory_base );
+		goto errout;
+	}
+
+	if ( !memory_test(info) ) {
+		printk( "%s(%d):Shared Memory Test failed for device %s MemAddr=%08X\n",
+			__FILE__,__LINE__,info->device_name, info->phys_memory_base );
+		goto errout;
+	}
+
+	info->lcr_base = ioremap(info->phys_lcr_base,PAGE_SIZE) + info->lcr_offset;
+	if (!info->lcr_base) {
+		printk( "%s(%d):%s Cant map LCR memory, MemAddr=%08X\n",
+			__FILE__,__LINE__,info->device_name, info->phys_lcr_base );
+		goto errout;
+	}
+
+	info->sca_base = ioremap(info->phys_sca_base,PAGE_SIZE) + info->sca_offset;
+	if (!info->sca_base) {
+		printk( "%s(%d):%s Cant map SCA memory, MemAddr=%08X\n",
+			__FILE__,__LINE__,info->device_name, info->phys_sca_base );
+		goto errout;
+	}
+
+	info->statctrl_base = ioremap(info->phys_statctrl_base,PAGE_SIZE) + info->statctrl_offset;
+	if (!info->statctrl_base) {
+		printk( "%s(%d):%s Cant map SCA Status/Control memory, MemAddr=%08X\n",
+			__FILE__,__LINE__,info->device_name, info->phys_statctrl_base );
+		goto errout;
+	}
+
+	return 0;
+
+errout:
+	release_resources( info );
+	return -ENODEV;
+}
+
+void release_resources(SLMP_INFO *info)
+{
+	if ( debug_level >= DEBUG_LEVEL_INFO )
+		printk( "%s(%d):%s release_resources() entry\n",
+			__FILE__,__LINE__,info->device_name );
+
+	if ( info->irq_requested ) {
+		free_irq(info->irq_level, info);
+		info->irq_requested = 0;
+	}
+
+	if ( info->shared_mem_requested ) {
+		release_mem_region(info->phys_memory_base,0x40000);
+		info->shared_mem_requested = 0;
+	}
+	if ( info->lcr_mem_requested ) {
+		release_mem_region(info->phys_lcr_base + info->lcr_offset,128);
+		info->lcr_mem_requested = 0;
+	}
+	if ( info->sca_base_requested ) {
+		release_mem_region(info->phys_sca_base + info->sca_offset,512);
+		info->sca_base_requested = 0;
+	}
+	if ( info->sca_statctrl_requested ) {
+		release_mem_region(info->phys_statctrl_base + info->statctrl_offset,16);
+		info->sca_statctrl_requested = 0;
+	}
+
+	if (info->memory_base){
+		iounmap(info->memory_base);
+		info->memory_base = 0;
+	}
+
+	if (info->sca_base) {
+		iounmap(info->sca_base - info->sca_offset);
+		info->sca_base=0;
+	}
+
+	if (info->statctrl_base) {
+		iounmap(info->statctrl_base - info->statctrl_offset);
+		info->statctrl_base=0;
+	}
+
+	if (info->lcr_base){
+		iounmap(info->lcr_base - info->lcr_offset);
+		info->lcr_base = 0;
+	}
+
+	if ( debug_level >= DEBUG_LEVEL_INFO )
+		printk( "%s(%d):%s release_resources() exit\n",
+			__FILE__,__LINE__,info->device_name );
+}
+
+/* Add the specified device instance data structure to the
+ * global linked list of devices and increment the device count.
+ */
+void add_device(SLMP_INFO *info)
+{
+	info->next_device = NULL;
+	info->line = synclinkmp_device_count;
+	sprintf(info->device_name,"ttySLM%dp%d",info->adapter_num,info->port_num);
+
+	if (info->line < MAX_DEVICES) {
+		if (maxframe[info->line])
+			info->max_frame_size = maxframe[info->line];
+		info->dosyncppp = dosyncppp[info->line];
+	}
+
+	synclinkmp_device_count++;
+
+	if ( !synclinkmp_device_list )
+		synclinkmp_device_list = info;
+	else {
+		SLMP_INFO *current_dev = synclinkmp_device_list;
+		while( current_dev->next_device )
+			current_dev = current_dev->next_device;
+		current_dev->next_device = info;
+	}
+
+	if ( info->max_frame_size < 4096 )
+		info->max_frame_size = 4096;
+	else if ( info->max_frame_size > 65535 )
+		info->max_frame_size = 65535;
+
+	printk( "SyncLink MultiPort %s: "
+		"Mem=(%08x %08X %08x %08X) IRQ=%d MaxFrameSize=%u\n",
+		info->device_name,
+		info->phys_sca_base,
+		info->phys_memory_base,
+		info->phys_statctrl_base,
+		info->phys_lcr_base,
+		info->irq_level,
+		info->max_frame_size );
+
+#ifdef CONFIG_SYNCLINK_SYNCPPP
+	if (info->dosyncppp)
+		sppp_init(info);
+#endif
+}
+
+/* Allocate and initialize a device instance structure
+ *
+ * Return Value:	pointer to SLMP_INFO if success, otherwise NULL
+ */
+SLMP_INFO *alloc_dev(int adapter_num, int port_num, struct pci_dev *pdev)
+{
+	SLMP_INFO *info;
+
+	info = (SLMP_INFO *)kmalloc(sizeof(SLMP_INFO),
+		 GFP_KERNEL);
+
+	if (!info) {
+		printk("%s(%d) Error can't allocate device instance data for adapter %d, port %d\n",
+			__FILE__,__LINE__, adapter_num, port_num);
+	} else {
+		memset(info, 0, sizeof(SLMP_INFO));
+		info->magic = MGSL_MAGIC;
+		info->task.sync = 0;
+		info->task.routine = bh_handler;
+		info->task.data    = info;
+		info->max_frame_size = 4096;
+		info->close_delay = 5*HZ/10;
+		info->closing_wait = 30*HZ;
+		init_waitqueue_head(&info->open_wait);
+		init_waitqueue_head(&info->close_wait);
+		init_waitqueue_head(&info->status_event_wait_q);
+		init_waitqueue_head(&info->event_wait_q);
+		spin_lock_init(&info->netlock);
+		memcpy(&info->params,&default_params,sizeof(MGSL_PARAMS));
+		info->idle_mode = HDLC_TXIDLE_FLAGS;
+		info->adapter_num = adapter_num;
+		info->port_num = port_num;
+
+		/* Copy configuration info to device instance data */
+		info->irq_level = pdev->irq;
+		info->phys_lcr_base = pci_resource_start(pdev,0);
+		info->phys_sca_base = pci_resource_start(pdev,2);
+		info->phys_memory_base = pci_resource_start(pdev,3);
+		info->phys_statctrl_base = pci_resource_start(pdev,4);
+
+		/* Because veremap only works on page boundaries we must map
+		 * a larger area than is actually implemented for the LCR
+		 * memory range. We map a full page starting at the page boundary.
+		 */
+		info->lcr_offset    = info->phys_lcr_base & (PAGE_SIZE-1);
+		info->phys_lcr_base &= ~(PAGE_SIZE-1);
+
+		info->sca_offset    = info->phys_sca_base & (PAGE_SIZE-1);
+		info->phys_sca_base &= ~(PAGE_SIZE-1);
+
+		info->statctrl_offset    = info->phys_statctrl_base & (PAGE_SIZE-1);
+		info->phys_statctrl_base &= ~(PAGE_SIZE-1);
+
+		info->bus_type = MGSL_BUS_TYPE_PCI;
+		info->irq_flags = SA_SHIRQ;
+
+		/* Store the PCI9050 misc control register value because a flaw
+		 * in the PCI9050 prevents LCR registers from being read if
+		 * BIOS assigns an LCR base address with bit 7 set.
+		 *
+		 * Only the misc control register is accessed for which only
+		 * write access is needed, so set an initial value and change
+		 * bits to the device instance data as we write the value
+		 * to the actual misc control register.
+		 */
+		info->misc_ctrl_value = 0x087e4546;
+
+		/* initial port state is unknown - if startup errors
+		 * occur, init_error will be set to indicate the
+		 * problem. Once the port is fully initialized,
+		 * this value will be set to 0 to indicate the
+		 * port is available.
+		 */
+		info->init_error = -1;
+	}
+
+	return info;
+}
+
+void device_init(int adapter_num, struct pci_dev *pdev)
+{
+	SLMP_INFO *port_array[SCA_MAX_PORTS];
+	int port;
+
+	/* allocate device instances for up to SCA_MAX_PORTS devices */
+	for ( port = 0; port < SCA_MAX_PORTS; ++port ) {
+		port_array[port] = alloc_dev(adapter_num,port,pdev);
+		if( port_array[port] == NULL ) {
+			for ( --port; port >= 0; --port )
+				kfree(port_array[port]);
+			return;
+		}
+	}
+
+	/* give copy of port_array to all ports and add to device list  */
+	for ( port = 0; port < SCA_MAX_PORTS; ++port ) {
+		memcpy(port_array[port]->port_array,port_array,sizeof(port_array));
+		add_device( port_array[port] );
+		spin_lock_init(&port_array[port]->lock);
+	}
+
+	/* Allocate and claim adapter resources */
+	if ( !claim_resources(port_array[0]) ) {
+
+		alloc_dma_bufs(port_array[0]);
+
+		/* copy resource information from first port to others */
+		for ( port = 1; port < SCA_MAX_PORTS; ++port ) {
+			port_array[port]->lock  = port_array[0]->lock;
+			port_array[port]->irq_level     = port_array[0]->irq_level;
+			port_array[port]->memory_base   = port_array[0]->memory_base;
+			port_array[port]->sca_base      = port_array[0]->sca_base;
+			port_array[port]->statctrl_base = port_array[0]->statctrl_base;
+			port_array[port]->lcr_base      = port_array[0]->lcr_base;
+			alloc_dma_bufs(port_array[port]);
+		}
+
+		if ( request_irq(port_array[0]->irq_level,
+					synclinkmp_interrupt,
+					port_array[0]->irq_flags,
+					port_array[0]->device_name,
+					port_array[0]) < 0 ) {
+			printk( "%s(%d):%s Cant request interrupt, IRQ=%d\n",
+				__FILE__,__LINE__,
+				port_array[0]->device_name,
+				port_array[0]->irq_level );
+		}
+		else {
+			port_array[0]->irq_requested = 1;
+			adapter_test(port_array[0]);
+		}
+	}
+}
+
+/* Driver initialization entry point.
+ */
+
+static int __init synclinkmp_init(void)
+{
+	SLMP_INFO *info;
+
+	EXPORT_NO_SYMBOLS;
+
+	if (break_on_load) {
+	 	synclinkmp_get_text_ptr();
+  		BREAKPOINT();
+	}
+
+ 	printk("%s %s\n", driver_name, driver_version);
+
+	synclinkmp_adapter_count = -1;
+	pci_register_driver(&synclinkmp_pci_driver);
+
+	if ( !synclinkmp_device_list ) {
+		printk("%s(%d):No SyncLink devices found.\n",__FILE__,__LINE__);
+		return -ENODEV;
+	}
+
+	memset(serial_table,0,sizeof(struct tty_struct*)*MAX_DEVICES);
+	memset(serial_termios,0,sizeof(struct termios*)*MAX_DEVICES);
+	memset(serial_termios_locked,0,sizeof(struct termios*)*MAX_DEVICES);
+
+	/* Initialize the tty_driver structure */
+
+	memset(&serial_driver, 0, sizeof(struct tty_driver));
+	serial_driver.magic = TTY_DRIVER_MAGIC;
+	serial_driver.driver_name = "synclinkmp";
+	serial_driver.name = "ttySLM";
+	serial_driver.major = ttymajor;
+	serial_driver.minor_start = 64;
+	serial_driver.num = synclinkmp_device_count;
+	serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
+	serial_driver.subtype = SERIAL_TYPE_NORMAL;
+	serial_driver.init_termios = tty_std_termios;
+	serial_driver.init_termios.c_cflag =
+		B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	serial_driver.flags = TTY_DRIVER_REAL_RAW;
+	serial_driver.refcount = &serial_refcount;
+	serial_driver.table = serial_table;
+	serial_driver.termios = serial_termios;
+	serial_driver.termios_locked = serial_termios_locked;
+
+	serial_driver.open = open;
+	serial_driver.close = close;
+	serial_driver.write = write;
+	serial_driver.put_char = put_char;
+	serial_driver.flush_chars = flush_chars;
+	serial_driver.write_room = write_room;
+	serial_driver.chars_in_buffer = chars_in_buffer;
+	serial_driver.flush_buffer = flush_buffer;
+	serial_driver.ioctl = ioctl;
+	serial_driver.throttle = throttle;
+	serial_driver.unthrottle = unthrottle;
+	serial_driver.send_xchar = send_xchar;
+	serial_driver.break_ctl = set_break;
+	serial_driver.wait_until_sent = wait_until_sent;
+ 	serial_driver.read_proc = read_proc;
+	serial_driver.set_termios = set_termios;
+	serial_driver.stop = tx_hold;
+	serial_driver.start = tx_release;
+	serial_driver.hangup = hangup;
+
+	/*
+	 * The callout device is just like normal device except for
+	 * major number and the subtype code.
+	 */
+	callout_driver = serial_driver;
+	callout_driver.name = "cuaSLM";
+	callout_driver.major = cuamajor;
+	callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+	callout_driver.read_proc = 0;
+	callout_driver.proc_entry = 0;
+
+	if (tty_register_driver(&serial_driver) < 0)
+		printk("%s(%d):Couldn't register serial driver\n",
+			__FILE__,__LINE__);
+
+	if (tty_register_driver(&callout_driver) < 0)
+		printk("%s(%d):Couldn't register callout driver\n",
+			__FILE__,__LINE__);
+
+ 	printk("%s %s, tty major#%d callout major#%d\n",
+		driver_name, driver_version,
+		serial_driver.major, callout_driver.major);
+
+	/* Propagate these values to all device instances */
+
+	info = synclinkmp_device_list;
+	while(info){
+		info->callout_termios = callout_driver.init_termios;
+		info->normal_termios  = serial_driver.init_termios;
+		info = info->next_device;
+	}
+
+	return 0;
+}
+
+static void __exit synclinkmp_exit(void)
+{
+	unsigned long flags;
+	int rc;
+	SLMP_INFO *info;
+	SLMP_INFO *tmp;
+
+	printk("Unloading %s %s\n", driver_name, driver_version);
+	save_flags(flags);
+	cli();
+	if ((rc = tty_unregister_driver(&serial_driver)))
+		printk("%s(%d) failed to unregister tty driver err=%d\n",
+		       __FILE__,__LINE__,rc);
+	if ((rc = tty_unregister_driver(&callout_driver)))
+		printk("%s(%d) failed to unregister callout driver err=%d\n",
+		       __FILE__,__LINE__,rc);
+	restore_flags(flags);
+
+	info = synclinkmp_device_list;
+	while(info) {
+#ifdef CONFIG_SYNCLINK_SYNCPPP
+		if (info->dosyncppp)
+			sppp_delete(info);
+#endif
+		reset_port(info);
+		if ( info->port_num == 0 ) {
+			if ( info->irq_requested ) {
+				free_irq(info->irq_level, info);
+				info->irq_requested = 0;
+			}
+		}
+		info = info->next_device;
+	}
+
+	/* port 0 of each adapter originally claimed
+	 * all resources, release those now
+	 */
+	info = synclinkmp_device_list;
+	while(info) {
+		free_dma_bufs(info);
+		free_tmp_rx_buf(info);
+		if ( info->port_num == 0 ) {
+			spin_lock_irqsave(&info->lock,flags);
+			reset_adapter(info);
+			write_reg(info, LPR, 1);		/* set low power mode */
+			spin_unlock_irqrestore(&info->lock,flags);
+			release_resources(info);
+		}
+		tmp = info;
+		info = info->next_device;
+		kfree(tmp);
+	}
+
+	pci_unregister_driver(&synclinkmp_pci_driver);
+}
+
+module_init(synclinkmp_init);
+module_exit(synclinkmp_exit);
+
+/* Set the port for internal loopback mode.
+ * The TxCLK and RxCLK signals are generated from the BRG and
+ * the TxD is looped back to the RxD internally.
+ */
+void enable_loopback(SLMP_INFO *info, int enable)
+{
+	if (enable) {
+		/* MD2 (Mode Register 2)
+		 * 01..00  CNCT<1..0> Channel Connection 11=Local Loopback
+		 */
+		write_reg(info, MD2, (unsigned char)(read_reg(info, MD2) | (BIT1 + BIT0)));
+
+		/* degate external TxC clock source */
+		info->port_array[0]->ctrlreg_value |= (BIT0 << (info->port_num * 2));
+		write_control_reg(info);
+
+		/* RXS/TXS (Rx/Tx clock source)
+		 * 07      Reserved, must be 0
+		 * 06..04  Clock Source, 100=BRG
+		 * 03..00  Clock Divisor, 0000=1
+		 */
+		write_reg(info, RXS, 0x40);
+		write_reg(info, TXS, 0x40);
+
+	} else {
+		/* MD2 (Mode Register 2)
+	 	 * 01..00  CNCT<1..0> Channel connection, 0=normal
+		 */
+		write_reg(info, MD2, (unsigned char)(read_reg(info, MD2) & ~(BIT1 + BIT0)));
+
+		/* RXS/TXS (Rx/Tx clock source)
+		 * 07      Reserved, must be 0
+		 * 06..04  Clock Source, 000=RxC/TxC Pin
+		 * 03..00  Clock Divisor, 0000=1
+		 */
+		write_reg(info, RXS, 0x00);
+		write_reg(info, TXS, 0x00);
+	}
+
+	/* set LinkSpeed if available, otherwise default to 2Mbps */
+	if (info->params.clock_speed)
+		set_rate(info, info->params.clock_speed);
+	else
+		set_rate(info, 3686400);
+}
+
+/* Set the baud rate register to the desired speed
+ *
+ *	data_rate	data rate of clock in bits per second
+ *			A data rate of 0 disables the AUX clock.
+ */
+void set_rate( SLMP_INFO *info, u32 data_rate )
+{
+       	u32 TMCValue;
+       	unsigned char BRValue;
+	u32 Divisor=0;
+
+	/* fBRG = fCLK/(TMC * 2^BR)
+	 */
+	if (data_rate != 0) {
+		Divisor = 14745600/data_rate;
+		if (!Divisor)
+			Divisor = 1;
+
+		TMCValue = Divisor;
+
+		BRValue = 0;
+		if (TMCValue != 1 && TMCValue != 2) {
+			/* BRValue of 0 provides 50/50 duty cycle *only* when
+			 * TMCValue is 1 or 2. BRValue of 1 to 9 always provides
+			 * 50/50 duty cycle.
+			 */
+			BRValue = 1;
+			TMCValue >>= 1;
+		}
+
+		/* while TMCValue is too big for TMC register, divide
+		 * by 2 and increment BR exponent.
+		 */
+		for(; TMCValue > 256 && BRValue < 10; BRValue++)
+			TMCValue >>= 1;
+
+		write_reg(info, TXS,
+			(unsigned char)((read_reg(info, TXS) & 0xf0) | BRValue));
+		write_reg(info, RXS,
+			(unsigned char)((read_reg(info, RXS) & 0xf0) | BRValue));
+		write_reg(info, TMC, (unsigned char)TMCValue);
+	}
+	else {
+		write_reg(info, TXS,0);
+		write_reg(info, RXS,0);
+		write_reg(info, TMC, 0);
+	}
+}
+
+/* Disable receiver
+ */
+void rx_stop(SLMP_INFO *info)
+{
+	if (debug_level >= DEBUG_LEVEL_ISR)
+		printk("%s(%d):%s rx_stop()\n",
+			 __FILE__,__LINE__, info->device_name );
+
+	write_reg(info, CMD, RXRESET);
+
+	info->ie0_value &= ~RXRDYE;
+	write_reg(info, IE0, info->ie0_value);	/* disable Rx data interrupts */
+
+	write_reg(info, RXDMA + DSR, 0);	/* disable Rx DMA */
+	write_reg(info, RXDMA + DCMD, SWABORT);	/* reset/init Rx DMA */
+	write_reg(info, RXDMA + DIR, 0);	/* disable Rx DMA interrupts */
+
+	info->rx_enabled = 0;
+	info->rx_overflow = 0;
+}
+
+/* enable the receiver
+ */
+void rx_start(SLMP_INFO *info)
+{
+	int i;
+
+	if (debug_level >= DEBUG_LEVEL_ISR)
+		printk("%s(%d):%s rx_start()\n",
+			 __FILE__,__LINE__, info->device_name );
+
+	write_reg(info, CMD, RXRESET);
+
+	if ( info->params.mode == MGSL_MODE_HDLC ) {
+		/* HDLC, disabe IRQ on rxdata */
+		info->ie0_value &= ~RXRDYE;
+		write_reg(info, IE0, info->ie0_value);
+
+		/* Reset all Rx DMA buffers and program rx dma */
+		write_reg(info, RXDMA + DSR, 0);		/* disable Rx DMA */
+		write_reg(info, RXDMA + DCMD, SWABORT);	/* reset/init Rx DMA */
+
+		for (i = 0; i < info->rx_buf_count; i++) {
+			info->rx_buf_list[i].status = 0xff;
+
+			// throttle to 4 shared memory writes at a time to prevent
+			// hogging local bus (keep latency time for DMA requests low).
+			if (!(i % 4))
+				read_status_reg(info);
+		}
+		info->current_rx_buf = 0;
+
+		/* set current/1st descriptor address */
+		write_reg16(info, RXDMA + CDA,
+			info->rx_buf_list_ex[0].phys_entry);
+
+		/* set new last rx descriptor address */
+		write_reg16(info, RXDMA + EDA,
+			info->rx_buf_list_ex[info->rx_buf_count - 1].phys_entry);
+
+		/* set buffer length (shared by all rx dma data buffers) */
+		write_reg16(info, RXDMA + BFL, SCABUFSIZE);
+
+		write_reg(info, RXDMA + DIR, 0x60);	/* enable Rx DMA interrupts (EOM/BOF) */
+		write_reg(info, RXDMA + DSR, 0xf2);	/* clear Rx DMA IRQs, enable Rx DMA */
+	} else {
+		/* async, enable IRQ on rxdata */
+		info->ie0_value |= RXRDYE;
+		write_reg(info, IE0, info->ie0_value);
+	}
+
+	write_reg(info, CMD, RXENABLE);
+
+	info->rx_overflow = FALSE;
+	info->rx_enabled = 1;
+}
+
+/* Enable the transmitter and send a transmit frame if
+ * one is loaded in the DMA buffers.
+ */
+void tx_start(SLMP_INFO *info)
+{
+	if (debug_level >= DEBUG_LEVEL_ISR)
+		printk("%s(%d):%s tx_start() tx_count=%d\n",
+			 __FILE__,__LINE__, info->device_name,info->tx_count );
+
+	if (!info->tx_enabled ) {
+		write_reg(info, CMD, TXRESET);
+		write_reg(info, CMD, TXENABLE);
+		info->tx_enabled = TRUE;
+	}
+
+	if ( info->tx_count ) {
+
+		/* If auto RTS enabled and RTS is inactive, then assert */
+		/* RTS and set a flag indicating that the driver should */
+		/* negate RTS when the transmission completes. */
+
+		info->drop_rts_on_tx_done = 0;
+
+		if (info->params.mode != MGSL_MODE_ASYNC) {
+
+			if ( info->params.flags & HDLC_FLAG_AUTO_RTS ) {
+				get_signals( info );
+				if ( !(info->serial_signals & SerialSignal_RTS) ) {
+					info->serial_signals |= SerialSignal_RTS;
+					set_signals( info );
+					info->drop_rts_on_tx_done = 1;
+				}
+			}
+
+			write_reg(info, TXDMA + DSR, 0); 		/* disable DMA channel */
+			write_reg(info, TXDMA + DCMD, SWABORT);	/* reset/init DMA channel */
+	
+			/* set TX CDA (current descriptor address) */
+			write_reg16(info, TXDMA + CDA,
+				info->tx_buf_list_ex[0].phys_entry);
+	
+			/* set TX EDA (last descriptor address) */
+			write_reg16(info, TXDMA + EDA,
+				info->tx_buf_list_ex[info->last_tx_buf].phys_entry);
+	
+			/* clear IDLE and UDRN status bit */
+			info->ie1_value &= ~(IDLE + UDRN);
+			if (info->params.mode != MGSL_MODE_ASYNC)
+				info->ie1_value |= UDRN;     		/* HDLC, IRQ on underrun */
+			write_reg(info, IE1, info->ie1_value);	/* enable MSCI interrupts */
+			write_reg(info, SR1, (unsigned char)(IDLE + UDRN));
+	
+			write_reg(info, TXDMA + DIR, 0x40);		/* enable Tx DMA interrupts (EOM) */
+			write_reg(info, TXDMA + DSR, 0xf2);		/* clear Tx DMA IRQs, enable Tx DMA */
+	
+			info->tx_timer.expires = jiffies + jiffies_from_ms(5000);
+			add_timer(&info->tx_timer);
+		}
+		else {
+			tx_load_fifo(info);
+			/* async, enable IRQ on txdata */
+			info->ie0_value |= TXRDYE;
+			write_reg(info, IE0, info->ie0_value);
+		}
+
+		info->tx_active = 1;
+	}
+}
+
+/* stop the transmitter and DMA
+ */
+void tx_stop( SLMP_INFO *info )
+{
+	if (debug_level >= DEBUG_LEVEL_ISR)
+		printk("%s(%d):%s tx_stop()\n",
+			 __FILE__,__LINE__, info->device_name );
+
+	del_timer(&info->tx_timer);
+
+	write_reg(info, TXDMA + DSR, 0);		/* disable DMA channel */
+	write_reg(info, TXDMA + DCMD, SWABORT);	/* reset/init DMA channel */
+
+	write_reg(info, CMD, TXRESET);
+
+	info->ie1_value &= ~(UDRN + IDLE);
+	write_reg(info, IE1, info->ie1_value);	/* disable tx status interrupts */
+	write_reg(info, SR1, (unsigned char)(IDLE + UDRN));	/* clear pending */
+
+	info->ie0_value &= ~TXRDYE;
+	write_reg(info, IE0, info->ie0_value);	/* disable tx data interrupts */
+
+	info->tx_enabled = 0;
+	info->tx_active  = 0;
+}
+
+/* Fill the transmit FIFO until the FIFO is full or
+ * there is no more data to load.
+ */
+void tx_load_fifo(SLMP_INFO *info)
+{
+	u8 TwoBytes[2];
+
+	/* do nothing is now tx data available and no XON/XOFF pending */
+
+	if ( !info->tx_count && !info->x_char )
+		return;
+
+	/* load the Transmit FIFO until FIFOs full or all data sent */
+
+	while( info->tx_count && (read_reg(info,SR0) & BIT1) ) {
+
+		/* there is more space in the transmit FIFO and */
+		/* there is more data in transmit buffer */
+
+		if ( (info->tx_count > 1) && !info->x_char ) {
+ 			/* write 16-bits */
+			TwoBytes[0] = info->tx_buf[info->tx_get++];
+			if (info->tx_get >= info->max_frame_size)
+				info->tx_get -= info->max_frame_size;
+			TwoBytes[1] = info->tx_buf[info->tx_get++];
+			if (info->tx_get >= info->max_frame_size)
+				info->tx_get -= info->max_frame_size;
+
+			write_reg16(info, TRB, *((u16 *)TwoBytes));
+
+			info->tx_count -= 2;
+			info->icount.tx += 2;
+		} else {
+			/* only 1 byte left to transmit or 1 FIFO slot left */
+
+			if (info->x_char) {
+				/* transmit pending high priority char */
+				write_reg(info, TRB, info->x_char);
+				info->x_char = 0;
+			} else {
+				write_reg(info, TRB, info->tx_buf[info->tx_get++]);
+				if (info->tx_get >= info->max_frame_size)
+					info->tx_get -= info->max_frame_size;
+				info->tx_count--;
+			}
+			info->icount.tx++;
+		}
+	}
+}
+
+/* Reset a port to a known state
+ */
+void reset_port(SLMP_INFO *info)
+{
+	if (info->sca_base) {
+
+		tx_stop(info);
+		rx_stop(info);
+
+		info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS);
+		set_signals(info);
+
+		/* disable all port interrupts */
+		info->ie0_value = 0;
+		info->ie1_value = 0;
+		info->ie2_value = 0;
+		write_reg(info, IE0, info->ie0_value);
+		write_reg(info, IE1, info->ie1_value);
+		write_reg(info, IE2, info->ie2_value);
+
+		write_reg(info, CMD, CHRESET);
+	}
+}
+
+/* Reset all the ports to a known state.
+ */
+void reset_adapter(SLMP_INFO *info)
+{
+	int i;
+
+	for ( i=0; i < SCA_MAX_PORTS; ++i) {
+		if (info->port_array[i])
+			reset_port(info->port_array[i]);
+	}
+}
+
+/* Program port for asynchronous communications.
+ */
+void async_mode(SLMP_INFO *info)
+{
+
+  	unsigned char RegValue;
+
+	tx_stop(info);
+	rx_stop(info);
+
+	/* MD0, Mode Register 0
+	 *
+	 * 07..05  PRCTL<2..0>, Protocol Mode, 000=async
+	 * 04      AUTO, Auto-enable (RTS/CTS/DCD)
+	 * 03      Reserved, must be 0
+	 * 02      CRCCC, CRC Calculation, 0=disabled
+	 * 01..00  STOP<1..0> Stop bits (00=1,10=2)
+	 *
+	 * 0000 0000
+	 */
+	RegValue = 0x00;
+	if (info->params.stop_bits != 1)
+		RegValue |= BIT1;
+	write_reg(info, MD0, RegValue);
+
+	/* MD1, Mode Register 1
+	 *
+	 * 07..06  BRATE<1..0>, bit rate, 00=1/1 01=1/16 10=1/32 11=1/64
+	 * 05..04  TXCHR<1..0>, tx char size, 00=8 bits,01=7,10=6,11=5
+	 * 03..02  RXCHR<1..0>, rx char size
+	 * 01..00  PMPM<1..0>, Parity mode, 00=none 10=even 11=odd
+	 *
+	 * 0100 0000
+	 */
+	RegValue = 0x40;
+	switch (info->params.data_bits) {
+	case 7: RegValue |= BIT4 + BIT2; break;
+	case 6: RegValue |= BIT5 + BIT3; break;
+	case 5: RegValue |= BIT5 + BIT4 + BIT3 + BIT2; break;
+	}
+	if (info->params.parity != ASYNC_PARITY_NONE) {
+		RegValue |= BIT1;
+		if (info->params.parity == ASYNC_PARITY_ODD)
+			RegValue |= BIT0;
+	}
+	write_reg(info, MD1, RegValue);
+
+	/* MD2, Mode Register 2
+	 *
+	 * 07..02  Reserved, must be 0
+	 * 01..00  CNCT<1..0> Channel connection, 0=normal
+	 *
+	 * 0000 0000
+	 */
+	RegValue = 0x00;
+	write_reg(info, MD2, RegValue);
+
+	/* RXS, Receive clock source
+	 *
+	 * 07      Reserved, must be 0
+	 * 06..04  RXCS<2..0>, clock source, 000=RxC Pin, 100=BRG, 110=DPLL
+	 * 03..00  RXBR<3..0>, rate divisor, 0000=1
+	 */
+	RegValue=BIT6;
+	write_reg(info, RXS, RegValue);
+
+	/* TXS, Transmit clock source
+	 *
+	 * 07      Reserved, must be 0
+	 * 06..04  RXCS<2..0>, clock source, 000=TxC Pin, 100=BRG, 110=Receive Clock
+	 * 03..00  RXBR<3..0>, rate divisor, 0000=1
+	 */
+	RegValue=BIT6;
+	write_reg(info, TXS, RegValue);
+
+	/* Control Register
+	 *
+	 * 6,4,2,0  CLKSEL<3..0>, 0 = TcCLK in, 1 = Auxclk out
+	 */
+	info->port_array[0]->ctrlreg_value |= (BIT0 << (info->port_num * 2));
+	write_control_reg(info);
+
+	tx_set_idle(info);
+
+	/* RRC Receive Ready Control 0
+	 *
+	 * 07..05  Reserved, must be 0
+	 * 04..00  RRC<4..0> Rx FIFO trigger active 0x00 = 1 byte
+	 */
+	write_reg(info, TRC0, 0x00);
+
+	/* TRC0 Transmit Ready Control 0
+	 *
+	 * 07..05  Reserved, must be 0
+	 * 04..00  TRC<4..0> Tx FIFO trigger active 0x10 = 16 bytes
+	 */
+	write_reg(info, TRC0, 0x10);
+
+	/* TRC1 Transmit Ready Control 1
+	 *
+	 * 07..05  Reserved, must be 0
+	 * 04..00  TRC<4..0> Tx FIFO trigger inactive 0x1e = 31 bytes (full-1)
+	 */
+	write_reg(info, TRC1, 0x1e);
+
+	/* CTL, MSCI control register
+	 *
+	 * 07..06  Reserved, set to 0
+	 * 05      UDRNC, underrun control, 0=abort 1=CRC+flag (HDLC/BSC)
+	 * 04      IDLC, idle control, 0=mark 1=idle register
+	 * 03      BRK, break, 0=off 1 =on (async)
+	 * 02      SYNCLD, sync char load enable (BSC) 1=enabled
+	 * 01      GOP, go active on poll (LOOP mode) 1=enabled
+	 * 00      RTS, RTS output control, 0=active 1=inactive
+	 *
+	 * 0001 0001
+	 */
+	RegValue = 0x10;
+	if (!(info->serial_signals & SerialSignal_RTS))
+		RegValue |= 0x01;
+	write_reg(info, CTL, RegValue);
+
+	/* enable status interrupts */
+	info->ie0_value |= TXINTE + RXINTE;
+	write_reg(info, IE0, info->ie0_value);
+
+	/* enable break detect interrupt */
+	info->ie1_value = BRKD;
+	write_reg(info, IE1, info->ie1_value);
+
+	/* enable rx overrun interrupt */
+	info->ie2_value = OVRN;
+	write_reg(info, IE2, info->ie2_value);
+
+	set_rate( info, info->params.data_rate * 16 );
+
+	if (info->params.loopback)
+		enable_loopback(info,1);
+}
+
+/* Program the SCA for HDLC communications.
+ */
+void hdlc_mode(SLMP_INFO *info)
+{
+	unsigned char RegValue;
+	u32 DpllDivisor;
+
+	// Can't use DPLL because SCA outputs recovered clock on RxC when
+	// DPLL mode selected. This causes output contention with RxC receiver.
+	// Use of DPLL would require external hardware to disable RxC receiver
+	// when DPLL mode selected.
+	info->params.flags &= ~(HDLC_FLAG_TXC_DPLL + HDLC_FLAG_RXC_DPLL);
+
+	/* disable DMA interrupts */
+	write_reg(info, TXDMA + DIR, 0);
+	write_reg(info, RXDMA + DIR, 0);
+
+	/* MD0, Mode Register 0
+	 *
+	 * 07..05  PRCTL<2..0>, Protocol Mode, 100=HDLC
+	 * 04      AUTO, Auto-enable (RTS/CTS/DCD)
+	 * 03      Reserved, must be 0
+	 * 02      CRCCC, CRC Calculation, 1=enabled
+	 * 01      CRC1, CRC selection, 0=CRC-16,1=CRC-CCITT-16
+	 * 00      CRC0, CRC initial value, 1 = all 1s
+	 *
+	 * 1000 0001
+	 */
+	RegValue = 0x81;
+	if (info->params.flags & HDLC_FLAG_AUTO_CTS)
+		RegValue |= BIT4;
+	if (info->params.flags & HDLC_FLAG_AUTO_DCD)
+		RegValue |= BIT4;
+	if (info->params.crc_type == HDLC_CRC_16_CCITT)
+		RegValue |= BIT2 + BIT1;
+	write_reg(info, MD0, RegValue);
+
+	/* MD1, Mode Register 1
+	 *
+	 * 07..06  ADDRS<1..0>, Address detect, 00=no addr check
+	 * 05..04  TXCHR<1..0>, tx char size, 00=8 bits
+	 * 03..02  RXCHR<1..0>, rx char size, 00=8 bits
+	 * 01..00  PMPM<1..0>, Parity mode, 00=no parity
+	 *
+	 * 0000 0000
+	 */
+	RegValue = 0x00;
+	write_reg(info, MD1, RegValue);
+
+	/* MD2, Mode Register 2
+	 *
+	 * 07      NRZFM, 0=NRZ, 1=FM
+	 * 06..05  CODE<1..0> Encoding, 00=NRZ
+	 * 04..03  DRATE<1..0> DPLL Divisor, 00=8
+	 * 02      Reserved, must be 0
+	 * 01..00  CNCT<1..0> Channel connection, 0=normal
+	 *
+	 * 0000 0000
+	 */
+	RegValue = 0x00;
+	switch(info->params.encoding) {
+	case HDLC_ENCODING_NRZI:	  RegValue |= BIT5; break;
+	case HDLC_ENCODING_BIPHASE_MARK:  RegValue |= BIT7 + BIT5; break; /* aka FM1 */
+	case HDLC_ENCODING_BIPHASE_SPACE: RegValue |= BIT7 + BIT6; break; /* aka FM0 */
+	case HDLC_ENCODING_BIPHASE_LEVEL: RegValue |= BIT7; break; 	/* aka Manchester */
+#if 0
+	case HDLC_ENCODING_NRZB:	       				/* not supported */
+	case HDLC_ENCODING_NRZI_MARK:          				/* not supported */
+	case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: 				/* not supported */
+#endif
+	}
+	if ( info->params.flags & HDLC_FLAG_DPLL_DIV16 ) {
+		DpllDivisor = 16;
+		RegValue |= BIT3;
+	} else if ( info->params.flags & HDLC_FLAG_DPLL_DIV8 ) {
+		DpllDivisor = 8;
+	} else {
+		DpllDivisor = 32;
+		RegValue |= BIT4;
+	}
+	write_reg(info, MD2, RegValue);
+
+
+	/* RXS, Receive clock source
+	 *
+	 * 07      Reserved, must be 0
+	 * 06..04  RXCS<2..0>, clock source, 000=RxC Pin, 100=BRG, 110=DPLL
+	 * 03..00  RXBR<3..0>, rate divisor, 0000=1
+	 */
+	RegValue=0;
+	if (info->params.flags & HDLC_FLAG_RXC_BRG)
+		RegValue |= BIT6;
+	if (info->params.flags & HDLC_FLAG_RXC_DPLL)
+		RegValue |= BIT6 + BIT5;
+	write_reg(info, RXS, RegValue);
+
+	/* TXS, Transmit clock source
+	 *
+	 * 07      Reserved, must be 0
+	 * 06..04  RXCS<2..0>, clock source, 000=TxC Pin, 100=BRG, 110=Receive Clock
+	 * 03..00  RXBR<3..0>, rate divisor, 0000=1
+	 */
+	RegValue=0;
+	if (info->params.flags & HDLC_FLAG_TXC_BRG)
+		RegValue |= BIT6;
+	if (info->params.flags & HDLC_FLAG_TXC_DPLL)
+		RegValue |= BIT6 + BIT5;
+	write_reg(info, TXS, RegValue);
+
+	if (info->params.flags & HDLC_FLAG_RXC_DPLL)
+		set_rate(info, info->params.clock_speed * DpllDivisor);
+	else
+		set_rate(info, info->params.clock_speed);
+
+	/* GPDATA (General Purpose I/O Data Register)
+	 *
+	 * 6,4,2,0  CLKSEL<3..0>, 0 = TcCLK in, 1 = Auxclk out
+	 */
+	if (info->params.flags & HDLC_FLAG_TXC_BRG)
+		info->port_array[0]->ctrlreg_value |= (BIT0 << (info->port_num * 2));
+	else
+		info->port_array[0]->ctrlreg_value &= ~(BIT0 << (info->port_num * 2));
+	write_control_reg(info);
+
+	/* RRC Receive Ready Control 0
+	 *
+	 * 07..05  Reserved, must be 0
+	 * 04..00  RRC<4..0> Rx FIFO trigger active
+	 */
+	write_reg(info, RRC, rx_active_fifo_level);
+
+	/* TRC0 Transmit Ready Control 0
+	 *
+	 * 07..05  Reserved, must be 0
+	 * 04..00  TRC<4..0> Tx FIFO trigger active
+	 */
+	write_reg(info, TRC0, tx_active_fifo_level);
+
+	/* TRC1 Transmit Ready Control 1
+	 *
+	 * 07..05  Reserved, must be 0
+	 * 04..00  TRC<4..0> Tx FIFO trigger inactive 0x1f = 32 bytes (full)
+	 */
+	write_reg(info, TRC1, (unsigned char)(tx_negate_fifo_level - 1));
+
+	/* DMR, DMA Mode Register
+	 *
+	 * 07..05  Reserved, must be 0
+	 * 04      TMOD, Transfer Mode: 1=chained-block
+	 * 03      Reserved, must be 0
+	 * 02      NF, Number of Frames: 1=multi-frame
+	 * 01      CNTE, Frame End IRQ Counter enable: 0=disabled
+	 * 00      Reserved, must be 0
+	 *
+	 * 0001 0100
+	 */
+	write_reg(info, TXDMA + DMR, 0x14);
+	write_reg(info, RXDMA + DMR, 0x14);
+
+	/* Set chain pointer base (upper 8 bits of 24 bit addr) */
+	write_reg(info, RXDMA + CPB,
+		(unsigned char)(info->buffer_list_phys >> 16));
+
+	/* Set chain pointer base (upper 8 bits of 24 bit addr) */
+	write_reg(info, TXDMA + CPB,
+		(unsigned char)(info->buffer_list_phys >> 16));
+
+	/* enable status interrupts. other code enables/disables
+	 * the individual sources for these two interrupt classes.
+	 */
+	info->ie0_value |= TXINTE + RXINTE;
+	write_reg(info, IE0, info->ie0_value);
+
+	/* CTL, MSCI control register
+	 *
+	 * 07..06  Reserved, set to 0
+	 * 05      UDRNC, underrun control, 0=abort 1=CRC+flag (HDLC/BSC)
+	 * 04      IDLC, idle control, 0=mark 1=idle register
+	 * 03      BRK, break, 0=off 1 =on (async)
+	 * 02      SYNCLD, sync char load enable (BSC) 1=enabled
+	 * 01      GOP, go active on poll (LOOP mode) 1=enabled
+	 * 00      RTS, RTS output control, 0=active 1=inactive
+	 *
+	 * 0001 0001
+	 */
+	RegValue = 0x10;
+	if (!(info->serial_signals & SerialSignal_RTS))
+		RegValue |= 0x01;
+	write_reg(info, CTL, RegValue);
+
+	/* preamble not supported ! */
+
+	tx_set_idle(info);
+	tx_stop(info);
+	rx_stop(info);
+
+	set_rate(info, info->params.clock_speed);
+
+	if (info->params.loopback)
+		enable_loopback(info,1);
+}
+
+/* Set the transmit HDLC idle mode
+ */
+void tx_set_idle(SLMP_INFO *info)
+{
+	unsigned char RegValue = 0xff;
+
+	/* Map API idle mode to SCA register bits */
+	switch(info->idle_mode) {
+	case HDLC_TXIDLE_FLAGS:			RegValue = 0x7e; break;
+	case HDLC_TXIDLE_ALT_ZEROS_ONES:	RegValue = 0xaa; break;
+	case HDLC_TXIDLE_ZEROS:			RegValue = 0x00; break;
+	case HDLC_TXIDLE_ONES:			RegValue = 0xff; break;
+	case HDLC_TXIDLE_ALT_MARK_SPACE:	RegValue = 0xaa; break;
+	case HDLC_TXIDLE_SPACE:			RegValue = 0x00; break;
+	case HDLC_TXIDLE_MARK:			RegValue = 0xff; break;
+	}
+
+	write_reg(info, IDL, RegValue);
+}
+
+/* Query the adapter for the state of the V24 status (input) signals.
+ */
+void get_signals(SLMP_INFO *info)
+{
+	u16 status = read_reg(info, SR3);
+	u16 gpstatus = read_status_reg(info);
+	u16 testbit;
+
+	/* clear all serial signals except DTR and RTS */
+	info->serial_signals &= SerialSignal_DTR + SerialSignal_RTS;
+
+	/* set serial signal bits to reflect MISR */
+
+	if (!(status & BIT3))
+		info->serial_signals |= SerialSignal_CTS;
+
+	if ( !(status & BIT2))
+		info->serial_signals |= SerialSignal_DCD;
+
+	testbit = BIT1 << (info->port_num * 2); // Port 0..3 RI is GPDATA<1,3,5,7>
+	if (!(gpstatus & testbit))
+		info->serial_signals |= SerialSignal_RI;
+
+	testbit = BIT0 << (info->port_num * 2); // Port 0..3 DSR is GPDATA<0,2,4,6>
+	if (!(gpstatus & testbit))
+		info->serial_signals |= SerialSignal_DSR;
+}
+
+/* Set the state of DTR and RTS based on contents of
+ * serial_signals member of device context.
+ */
+void set_signals(SLMP_INFO *info)
+{
+	unsigned char RegValue;
+	u16 EnableBit;
+
+	RegValue = read_reg(info, CTL);
+	if (info->serial_signals & SerialSignal_RTS)
+		RegValue &= ~BIT0;
+	else
+		RegValue |= BIT0;
+	write_reg(info, CTL, RegValue);
+
+	// Port 0..3 DTR is ctrl reg <1,3,5,7>
+	EnableBit = BIT1 << (info->port_num*2);
+	if (info->serial_signals & SerialSignal_DTR)
+		info->port_array[0]->ctrlreg_value &= ~EnableBit;
+	else
+		info->port_array[0]->ctrlreg_value |= EnableBit;
+	write_control_reg(info);
+}
+
+/*******************/
+/* DMA Buffer Code */
+/*******************/
+
+/* Set the count for all receive buffers to SCABUFSIZE
+ * and set the current buffer to the first buffer. This effectively
+ * makes all buffers free and discards any data in buffers.
+ */
+void rx_reset_buffers(SLMP_INFO *info)
+{
+	rx_free_frame_buffers(info, 0, info->rx_buf_count - 1);
+}
+
+/* Free the buffers used by a received frame
+ *
+ * info   pointer to device instance data
+ * first  index of 1st receive buffer of frame
+ * last   index of last receive buffer of frame
+ */
+void rx_free_frame_buffers(SLMP_INFO *info, unsigned int first, unsigned int last)
+{
+	int done = 0;
+
+	while(!done) {
+	        /* reset current buffer for reuse */
+		info->rx_buf_list[first].status = 0xff;
+
+	        if (first == last) {
+	                done = 1;
+	                /* set new last rx descriptor address */
+			write_reg16(info, RXDMA + EDA, info->rx_buf_list_ex[first].phys_entry);
+	        }
+
+	        first++;
+		if (first == info->rx_buf_count)
+			first = 0;
+	}
+
+	/* set current buffer to next buffer after last buffer of frame */
+	info->current_rx_buf = first;
+}
+
+/* Return a received frame from the receive DMA buffers.
+ * Only frames received without errors are returned.
+ *
+ * Return Value:	1 if frame returned, otherwise 0
+ */
+int rx_get_frame(SLMP_INFO *info)
+{
+	unsigned int StartIndex, EndIndex;	/* index of 1st and last buffers of Rx frame */
+	unsigned short status;
+	unsigned int framesize = 0;
+	int ReturnCode = 0;
+	unsigned long flags;
+	struct tty_struct *tty = info->tty;
+	unsigned char addr_field = 0xff;
+   	SCADESC *desc;
+	SCADESC_EX *desc_ex;
+
+CheckAgain:
+	/* assume no frame returned, set zero length */
+	framesize = 0;
+	addr_field = 0xff;
+
+	/*
+	 * current_rx_buf points to the 1st buffer of the next available
+	 * receive frame. To find the last buffer of the frame look for
+	 * a non-zero status field in the buffer entries. (The status
+	 * field is set by the 16C32 after completing a receive frame.
+	 */
+	StartIndex = EndIndex = info->current_rx_buf;
+
+	for ( ;; ) {
+		desc = &info->rx_buf_list[EndIndex];
+		desc_ex = &info->rx_buf_list_ex[EndIndex];
+
+		if (desc->status == 0xff)
+			goto Cleanup;	/* current desc still in use, no frames available */
+
+		if (framesize == 0 && info->params.addr_filter != 0xff)
+			addr_field = desc_ex->virt_addr[0];
+
+		framesize += desc->length;
+
+		/* Status != 0 means last buffer of frame */
+		if (desc->status)
+			break;
+
+		EndIndex++;
+		if (EndIndex == info->rx_buf_count)
+			EndIndex = 0;
+
+		if (EndIndex == info->current_rx_buf) {
+			/* all buffers have been 'used' but none mark	   */
+			/* the end of a frame. Reset buffers and receiver. */
+			if ( info->rx_enabled ){
+				spin_lock_irqsave(&info->lock,flags);
+				rx_start(info);
+				spin_unlock_irqrestore(&info->lock,flags);
+			}
+			goto Cleanup;
+		}
+
+	}
+
+	/* check status of receive frame */
+
+	/* frame status is byte stored after frame data
+	 *
+	 * 7 EOM (end of msg), 1 = last buffer of frame
+	 * 6 Short Frame, 1 = short frame
+	 * 5 Abort, 1 = frame aborted
+	 * 4 Residue, 1 = last byte is partial
+	 * 3 Overrun, 1 = overrun occurred during frame reception
+	 * 2 CRC,     1 = CRC error detected
+	 *
+	 */
+	status = desc->status;
+
+	/* ignore CRC bit if not using CRC (bit is undefined) */
+	/* Note:CRC is not save to data buffer */
+	if (info->params.crc_type == HDLC_CRC_NONE)
+		status &= ~BIT2;
+
+	if (framesize == 0 ||
+		 (addr_field != 0xff && addr_field != info->params.addr_filter)) {
+		/* discard 0 byte frames, this seems to occur sometime
+		 * when remote is idling flags.
+		 */
+		rx_free_frame_buffers(info, StartIndex, EndIndex);
+		goto CheckAgain;
+	}
+
+	if (framesize < 2)
+		status |= BIT6;
+
+	if (status & (BIT6+BIT5+BIT3+BIT2)) {
+		/* received frame has errors,
+		 * update counts and mark frame size as 0
+		 */
+		if (status & BIT6)
+			info->icount.rxshort++;
+		else if (status & BIT5)
+			info->icount.rxabort++;
+		else if (status & BIT3)
+			info->icount.rxover++;
+		else
+			info->icount.rxcrc++;
+
+		framesize = 0;
+
+#ifdef CONFIG_SYNCLINK_SYNCPPP
+		info->netstats.rx_errors++;
+		info->netstats.rx_frame_errors++;
+#endif
+	}
+
+	if ( debug_level >= DEBUG_LEVEL_BH )
+		printk("%s(%d):%s rx_get_frame() status=%04X size=%d\n",
+			__FILE__,__LINE__,info->device_name,status,framesize);
+
+	if ( debug_level >= DEBUG_LEVEL_DATA )
+		trace_block(info,info->rx_buf_list_ex[StartIndex].virt_addr,
+			MIN(framesize,SCABUFSIZE),0);
+
+	if (framesize) {
+		if (framesize > info->max_frame_size)
+			info->icount.rxlong++;
+		else {
+			/* copy dma buffer(s) to contiguous intermediate buffer */
+			int copy_count = framesize;
+			int index = StartIndex;
+			unsigned char *ptmp = info->tmp_rx_buf;
+			info->tmp_rx_buf_count = framesize;
+
+			info->icount.rxok++;
+
+			while(copy_count) {
+				int partial_count = MIN(copy_count,SCABUFSIZE);
+				memcpy( ptmp,
+					info->rx_buf_list_ex[index].virt_addr,
+					partial_count );
+				ptmp += partial_count;
+				copy_count -= partial_count;
+
+				if ( ++index == info->rx_buf_count )
+					index = 0;
+			}
+
+#ifdef CONFIG_SYNCLINK_SYNCPPP
+			if (info->netcount) {
+				/* pass frame to syncppp device */
+				sppp_rx_done(info,info->tmp_rx_buf,framesize);
+			}
+			else
+#endif
+			{
+				if ( tty && tty->ldisc.receive_buf ) {
+					/* Call the line discipline receive callback directly. */
+					tty->ldisc.receive_buf(tty,
+						info->tmp_rx_buf,
+						info->flag_buf,
+						framesize);
+				}
+			}
+		}
+	}
+	/* Free the buffers used by this frame. */
+	rx_free_frame_buffers( info, StartIndex, EndIndex );
+
+	ReturnCode = 1;
+
+Cleanup:
+	if ( info->rx_enabled && info->rx_overflow ) {
+		/* Receiver is enabled, but needs to restarted due to
+		 * rx buffer overflow. If buffers are empty, restart receiver.
+		 */
+		if (info->rx_buf_list[EndIndex].status == 0xff) {
+			spin_lock_irqsave(&info->lock,flags);
+			rx_start(info);
+			spin_unlock_irqrestore(&info->lock,flags);
+		}
+	}
+
+	return ReturnCode;
+}
+
+/* load the transmit DMA buffer with data
+ */
+void tx_load_dma_buffer(SLMP_INFO *info, const char *buf, unsigned int count)
+{
+	unsigned short copy_count;
+	unsigned int i = 0;
+	SCADESC *desc;
+	SCADESC_EX *desc_ex;
+
+	if ( debug_level >= DEBUG_LEVEL_DATA )
+		trace_block(info,buf, MIN(count,SCABUFSIZE), 1);
+
+	/* Copy source buffer to one or more DMA buffers, starting with
+	 * the first transmit dma buffer.
+	 */
+	for(i=0;;)
+	{
+		copy_count = MIN(count,SCABUFSIZE);
+
+		desc = &info->tx_buf_list[i];
+		desc_ex = &info->tx_buf_list_ex[i];
+
+		load_pci_memory(info, desc_ex->virt_addr,buf,copy_count);
+
+		desc->length = copy_count;
+		desc->status = 0;
+
+		buf += copy_count;
+		count -= copy_count;
+
+		if (!count)
+			break;
+
+		i++;
+		if (i >= info->tx_buf_count)
+			i = 0;
+	}
+
+	info->tx_buf_list[i].status = 0x81;	/* set EOM and EOT status */
+	info->last_tx_buf = ++i;
+}
+
+int register_test(SLMP_INFO *info)
+{
+	static unsigned char testval[] = {0x00, 0xff, 0xaa, 0x55, 0x69, 0x96};
+	static unsigned int count = sizeof(testval)/sizeof(unsigned char);
+	unsigned int i;
+	int rc = TRUE;
+	unsigned long flags;
+
+	spin_lock_irqsave(&info->lock,flags);
+	reset_port(info);
+
+	/* assume failure */
+	info->init_error = DiagStatus_AddressFailure;
+
+	/* Write bit patterns to various registers but do it out of */
+	/* sync, then read back and verify values. */
+
+	for (i = 0 ; i < count ; i++) {
+		write_reg(info, TMC, testval[i]);
+		write_reg(info, IDL, testval[(i+1)%count]);
+		write_reg(info, SA0, testval[(i+2)%count]);
+		write_reg(info, SA1, testval[(i+3)%count]);
+
+		if ( (read_reg(info, TMC) != testval[i]) ||
+			  (read_reg(info, IDL) != testval[(i+1)%count]) ||
+			  (read_reg(info, SA0) != testval[(i+2)%count]) ||
+			  (read_reg(info, SA1) != testval[(i+3)%count]) )
+		{
+			rc = FALSE;
+			break;
+		}
+	}
+
+	reset_port(info);
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	return rc;
+}
+
+int irq_test(SLMP_INFO *info)
+{
+	unsigned long timeout;
+	unsigned long flags;
+
+	unsigned char timer = (info->port_num & 1) ? TIMER2 : TIMER0;
+
+	spin_lock_irqsave(&info->lock,flags);
+	reset_port(info);
+
+	/* assume failure */
+	info->init_error = DiagStatus_IrqFailure;
+	info->irq_occurred = FALSE;
+
+	/* setup timer0 on SCA0 to interrupt */
+
+	/* IER2<7..4> = timer<3..0> interrupt enables (1=enabled) */
+	write_reg(info, IER2, (unsigned char)((info->port_num & 1) ? BIT6 : BIT4));
+
+	write_reg(info, (unsigned char)(timer + TEPR), 0);	/* timer expand prescale */
+	write_reg16(info, (unsigned char)(timer + TCONR), 1);	/* timer constant */
+
+
+	/* TMCS, Timer Control/Status Register
+	 *
+	 * 07      CMF, Compare match flag (read only) 1=match
+	 * 06      ECMI, CMF Interrupt Enable: 1=enabled
+	 * 05      Reserved, must be 0
+	 * 04      TME, Timer Enable
+	 * 03..00  Reserved, must be 0
+	 *
+	 * 0101 0000
+	 */
+	write_reg(info, (unsigned char)(timer + TMCS), 0x50);
+
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	timeout=100;
+	while( timeout-- && !info->irq_occurred ) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(jiffies_from_ms(10));
+	}
+
+	spin_lock_irqsave(&info->lock,flags);
+	reset_port(info);
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	return info->irq_occurred;
+}
+
+/* initialize individual SCA device (2 ports)
+ */
+int sca_init(SLMP_INFO *info)
+{
+	/* set wait controller to single mem partition (low), no wait states */
+	write_reg(info, PABR0, 0);	/* wait controller addr boundary 0 */
+	write_reg(info, PABR1, 0);	/* wait controller addr boundary 1 */
+	write_reg(info, WCRL, 0);	/* wait controller low range */
+	write_reg(info, WCRM, 0);	/* wait controller mid range */
+	write_reg(info, WCRH, 0);	/* wait controller high range */
+
+	/* DPCR, DMA Priority Control
+	 *
+	 * 07..05  Not used, must be 0
+	 * 04      BRC, bus release condition: 0=all transfers complete
+	 * 03      CCC, channel change condition: 0=every cycle
+	 * 02..00  PR<2..0>, priority 100=round robin
+	 *
+	 * 00000100 = 0x04
+	 */
+	write_reg(info, DPCR, dma_priority);
+
+	/* DMA Master Enable, BIT7: 1=enable all channels */
+	write_reg(info, DMER, 0x80);
+
+	/* enable all interrupt classes */
+	write_reg(info, IER0, 0xff);	/* TxRDY,RxRDY,TxINT,RxINT (ports 0-1) */
+	write_reg(info, IER1, 0xff);	/* DMIB,DMIA (channels 0-3) */
+	write_reg(info, IER2, 0xf0);	/* TIRQ (timers 0-3) */
+
+	/* ITCR, interrupt control register
+	 * 07      IPC, interrupt priority, 0=MSCI->DMA
+	 * 06..05  IAK<1..0>, Acknowledge cycle, 00=non-ack cycle
+	 * 04      VOS, Vector Output, 0=unmodified vector
+	 * 03..00  Reserved, must be 0
+	 */
+	write_reg(info, ITCR, 0);
+
+	return TRUE;
+}
+
+/* initialize adapter hardware
+ */
+int init_adapter(SLMP_INFO *info)
+{
+	int i;
+
+	/* Set BIT30 of Local Control Reg 0x50 to reset SCA */
+	volatile u32 *MiscCtrl = (u32 *)(info->lcr_base + 0x50);
+	u32 readval;
+
+	info->misc_ctrl_value |= BIT30;
+	*MiscCtrl = info->misc_ctrl_value;
+
+	/*
+	 * Force at least 170ns delay before clearing
+	 * reset bit. Each read from LCR takes at least
+	 * 30ns so 10 times for 300ns to be safe.
+	 */
+	for(i=0;i<10;i++)
+		readval = *MiscCtrl;
+
+	info->misc_ctrl_value &= ~BIT30;
+	*MiscCtrl = info->misc_ctrl_value;
+
+	/* init control reg (all DTRs off, all clksel=input) */
+	info->ctrlreg_value = 0xaa;
+	write_control_reg(info);
+
+	{
+		volatile u32 *LCR1BRDR = (u32 *)(info->lcr_base + 0x2c);
+		lcr1_brdr_value &= ~(BIT5 + BIT4 + BIT3);
+
+		switch(read_ahead_count)
+		{
+		case 16:
+			lcr1_brdr_value |= BIT5 + BIT4 + BIT3;
+			break;
+		case 8:
+			lcr1_brdr_value |= BIT5 + BIT4;
+			break;
+		case 4:
+			lcr1_brdr_value |= BIT5 + BIT3;
+			break;
+		case 0:
+			lcr1_brdr_value |= BIT5;
+			break;
+		}
+
+		*LCR1BRDR = lcr1_brdr_value;
+		*MiscCtrl = misc_ctrl_value;
+	}
+
+	sca_init(info->port_array[0]);
+	sca_init(info->port_array[2]);
+
+	return TRUE;
+}
+
+/* Loopback an HDLC frame to test the hardware
+ * interrupt and DMA functions.
+ */
+int loopback_test(SLMP_INFO *info)
+{
+#define TESTFRAMESIZE 20
+
+	unsigned long timeout;
+	u16 count = TESTFRAMESIZE;
+	unsigned char buf[TESTFRAMESIZE];
+	int rc = FALSE;
+	unsigned long flags;
+
+	struct tty_struct *oldtty = info->tty;
+	u32 speed = info->params.clock_speed;
+
+	info->params.clock_speed = 3686400;
+	info->tty = 0;
+
+	/* assume failure */
+	info->init_error = DiagStatus_DmaFailure;
+
+	/* build and send transmit frame */
+	for (count = 0; count < TESTFRAMESIZE;++count)
+		buf[count] = (unsigned char)count;
+
+	memset(info->tmp_rx_buf,0,TESTFRAMESIZE);
+
+	/* program hardware for HDLC and enabled receiver */
+	spin_lock_irqsave(&info->lock,flags);
+	hdlc_mode(info);
+	enable_loopback(info,1);
+       	rx_start(info);
+	info->tx_count = count;
+	tx_load_dma_buffer(info,buf,count);
+	tx_start(info);
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	/* wait for receive complete */
+	/* Set a timeout for waiting for interrupt. */
+	for ( timeout = 100; timeout; --timeout ) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(jiffies_from_ms(10));
+
+		if (rx_get_frame(info)) {
+			rc = TRUE;
+			break;
+		}
+	}
+
+	/* verify received frame length and contents */
+	if (rc == TRUE &&
+		( info->tmp_rx_buf_count != count ||
+		  memcmp(buf, info->tmp_rx_buf,count))) {
+		rc = FALSE;
+	}
+
+	spin_lock_irqsave(&info->lock,flags);
+	reset_adapter(info);
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	info->params.clock_speed = speed;
+	info->tty = oldtty;
+
+	return rc;
+}
+
+/* Perform diagnostics on hardware
+ */
+int adapter_test( SLMP_INFO *info )
+{
+	unsigned long flags;
+	if ( debug_level >= DEBUG_LEVEL_INFO )
+		printk( "%s(%d):Testing device %s\n",
+			__FILE__,__LINE__,info->device_name );
+
+	spin_lock_irqsave(&info->lock,flags);
+	init_adapter(info);
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	info->port_array[0]->port_count = 0;
+
+	if ( register_test(info->port_array[0]) &&
+		register_test(info->port_array[1])) {
+
+		info->port_array[0]->port_count = 2;
+
+		if ( register_test(info->port_array[2]) &&
+			register_test(info->port_array[3]) )
+			info->port_array[0]->port_count += 2;
+	}
+	else {
+		printk( "%s(%d):Register test failure for device %s Addr=%08lX\n",
+			__FILE__,__LINE__,info->device_name, (unsigned long)(info->phys_sca_base));
+		return -ENODEV;
+	}
+
+	if ( !irq_test(info->port_array[0]) ||
+		!irq_test(info->port_array[1]) ||
+		 (info->port_count == 4 && !irq_test(info->port_array[2])) ||
+		 (info->port_count == 4 && !irq_test(info->port_array[3]))) {
+		printk( "%s(%d):Interrupt test failure for device %s IRQ=%d\n",
+			__FILE__,__LINE__,info->device_name, (unsigned short)(info->irq_level) );
+		return -ENODEV;
+	}
+
+	if (!loopback_test(info->port_array[0]) ||
+		!loopback_test(info->port_array[1]) ||
+		 (info->port_count == 4 && !loopback_test(info->port_array[2])) ||
+		 (info->port_count == 4 && !loopback_test(info->port_array[3]))) {
+		printk( "%s(%d):DMA test failure for device %s\n",
+			__FILE__,__LINE__,info->device_name);
+		return -ENODEV;
+	}
+
+	if ( debug_level >= DEBUG_LEVEL_INFO )
+		printk( "%s(%d):device %s passed diagnostics\n",
+			__FILE__,__LINE__,info->device_name );
+
+	info->port_array[0]->init_error = 0;
+	info->port_array[1]->init_error = 0;
+	if ( info->port_count > 2 ) {
+		info->port_array[2]->init_error = 0;
+		info->port_array[3]->init_error = 0;
+	}
+
+	return 0;
+}
+
+/* Test the shared memory on a PCI adapter.
+ */
+int memory_test(SLMP_INFO *info)
+{
+	static unsigned long testval[] = { 0x0, 0x55555555, 0xaaaaaaaa,
+		0x66666666, 0x99999999, 0xffffffff, 0x12345678 };
+	unsigned long count = sizeof(testval)/sizeof(unsigned long);
+	unsigned long i;
+	unsigned long limit = SCA_MEM_SIZE/sizeof(unsigned long);
+	unsigned long * addr = (unsigned long *)info->memory_base;
+
+	/* Test data lines with test pattern at one location. */
+
+	for ( i = 0 ; i < count ; i++ ) {
+		*addr = testval[i];
+		if ( *addr != testval[i] )
+			return FALSE;
+	}
+
+	/* Test address lines with incrementing pattern over */
+	/* entire address range. */
+
+	for ( i = 0 ; i < limit ; i++ ) {
+		*addr = i * 4;
+		addr++;
+	}
+
+	addr = (unsigned long *)info->memory_base;
+
+	for ( i = 0 ; i < limit ; i++ ) {
+		if ( *addr != i * 4 )
+			return FALSE;
+		addr++;
+	}
+
+	memset( info->memory_base, 0, SCA_MEM_SIZE );
+	return TRUE;
+}
+
+/* Load data into PCI adapter shared memory.
+ *
+ * The PCI9050 releases control of the local bus
+ * after completing the current read or write operation.
+ *
+ * While the PCI9050 write FIFO not empty, the
+ * PCI9050 treats all of the writes as a single transaction
+ * and does not release the bus. This causes DMA latency problems
+ * at high speeds when copying large data blocks to the shared memory.
+ *
+ * This function breaks a write into multiple transations by
+ * interleaving a read which flushes the write FIFO and 'completes'
+ * the write transation. This allows any pending DMA request to gain control
+ * of the local bus in a timely fasion.
+ */
+void load_pci_memory(SLMP_INFO *info, char* dest, const char* src, unsigned short count)
+{
+	/* A load interval of 16 allows for 4 32-bit writes at */
+	/* 136ns each for a maximum latency of 542ns on the local bus.*/
+
+	unsigned short interval = count / sca_pci_load_interval;
+	unsigned short i;
+
+	for ( i = 0 ; i < interval ; i++ )
+	{
+		memcpy(dest, src, sca_pci_load_interval);
+		read_status_reg(info);
+		dest += sca_pci_load_interval;
+		src += sca_pci_load_interval;
+	}
+
+	memcpy(dest, src, count % sca_pci_load_interval);
+}
+
+void trace_block(SLMP_INFO *info,const char* data, int count, int xmit)
+{
+	int i;
+	int linecount;
+	if (xmit)
+		printk("%s tx data:\n",info->device_name);
+	else
+		printk("%s rx data:\n",info->device_name);
+
+	while(count) {
+		if (count > 16)
+			linecount = 16;
+		else
+			linecount = count;
+
+		for(i=0;i<linecount;i++)
+			printk("%02X ",(unsigned char)data[i]);
+		for(;i<17;i++)
+			printk("   ");
+		for(i=0;i<linecount;i++) {
+			if (data[i]>=040 && data[i]<=0176)
+				printk("%c",data[i]);
+			else
+				printk(".");
+		}
+		printk("\n");
+
+		data  += linecount;
+		count -= linecount;
+	}
+}	/* end of trace_block() */
+
+/* called when HDLC frame times out
+ * update stats and do tx completion processing
+ */
+void tx_timeout(unsigned long context)
+{
+	SLMP_INFO *info = (SLMP_INFO*)context;
+	unsigned long flags;
+
+	if ( debug_level >= DEBUG_LEVEL_INFO )
+		printk( "%s(%d):%s tx_timeout()\n",
+			__FILE__,__LINE__,info->device_name);
+	if(info->tx_active && info->params.mode == MGSL_MODE_HDLC) {
+		info->icount.txtimeout++;
+	}
+	spin_lock_irqsave(&info->lock,flags);
+	info->tx_active = 0;
+	info->tx_count = info->tx_put = info->tx_get = 0;
+
+	spin_unlock_irqrestore(&info->lock,flags);
+
+#ifdef CONFIG_SYNCLINK_SYNCPPP
+	if (info->netcount)
+		sppp_tx_done(info);
+	else
+#endif
+		bh_transmit(info);
+}
+
+/* called to periodically check the DSR/RI modem signal input status
+ */
+void status_timeout(unsigned long context)
+{
+	u16 status = 0;
+	SLMP_INFO *info = (SLMP_INFO*)context;
+	unsigned long flags;
+	unsigned char delta;
+
+
+	spin_lock_irqsave(&info->lock,flags);
+	get_signals(info);
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	/* check for DSR/RI state change */
+
+	delta = info->old_signals ^ info->serial_signals;
+	info->old_signals = info->serial_signals;
+
+	if (delta & SerialSignal_DSR)
+		status |= MISCSTATUS_DSR_LATCHED|(info->serial_signals&SerialSignal_DSR);
+
+	if (delta & SerialSignal_RI)
+		status |= MISCSTATUS_RI_LATCHED|(info->serial_signals&SerialSignal_RI);
+
+	if (delta & SerialSignal_DCD)
+		status |= MISCSTATUS_DCD_LATCHED|(info->serial_signals&SerialSignal_DCD);
+
+	if (delta & SerialSignal_CTS)
+		status |= MISCSTATUS_CTS_LATCHED|(info->serial_signals&SerialSignal_CTS);
+
+	if (status)
+		isr_io_pin(info,status);
+
+	info->status_timer.data = (unsigned long)info;
+	info->status_timer.function = status_timeout;
+	info->status_timer.expires = jiffies + jiffies_from_ms(10);
+	add_timer(&info->status_timer);
+}
+
+
+/* Register Access Routines -
+ * All registers are memory mapped
+ */
+#define CALC_REGADDR() \
+	unsigned char * RegAddr = (unsigned char*)(info->sca_base + Addr); \
+	if (info->port_num > 1) \
+		RegAddr += 256;	    		/* port 0-1 SCA0, 2-3 SCA1 */ \
+	if ( info->port_num & 1) { \
+		if (Addr > 0x7f) \
+			RegAddr += 0x40;	/* DMA access */ \
+		else if (Addr > 0x1f && Addr < 0x60) \
+			RegAddr += 0x20;	/* MSCI access */ \
+	}
+
+
+unsigned char read_reg(SLMP_INFO * info, unsigned char Addr)
+{
+	CALC_REGADDR();
+	return *RegAddr;
+}
+void write_reg(SLMP_INFO * info, unsigned char Addr, unsigned char Value)
+{
+	CALC_REGADDR();
+	*RegAddr = Value;
+}
+
+u16 read_reg16(SLMP_INFO * info, unsigned char Addr)
+{
+	CALC_REGADDR();
+	return *((u16 *)RegAddr);
+}
+
+void write_reg16(SLMP_INFO * info, unsigned char Addr, u16 Value)
+{
+	CALC_REGADDR();
+	*((u16 *)RegAddr) = Value;
+}
+
+unsigned char read_status_reg(SLMP_INFO * info)
+{
+	unsigned char *RegAddr = (unsigned char *)info->statctrl_base;
+	return *RegAddr;
+}
+
+void write_control_reg(SLMP_INFO * info)
+{
+	unsigned char *RegAddr = (unsigned char *)info->statctrl_base;
+	*RegAddr = info->port_array[0]->ctrlreg_value;
+}
+
+
+static int __init synclinkmp_init_one (struct pci_dev *dev,
+				       const struct pci_device_id *ent)
+{
+	if (pci_enable_device(dev)) {
+		printk("error enabling pci device %p\n", dev);
+		return -EIO;
+	}
+	device_init( ++synclinkmp_adapter_count, dev );
+	return 0;
+}
+
+static void __exit synclinkmp_remove_one (struct pci_dev *dev)
+{
+}
diff -urN linux-2.4.20-pre4/drivers/char/vt.c linux-2.4.20-pre5/drivers/char/vt.c
--- linux-2.4.20-pre4/drivers/char/vt.c	Wed Aug 28 16:36:47 2002
+++ linux-2.4.20-pre5/drivers/char/vt.c	Wed Aug 28 16:37:53 2002
@@ -481,7 +481,7 @@
 		ucval = keyboard_type;
 		goto setchar;
 
-#if defined(__i386__) || defined(__mc68000__) || defined(__ppc__) || defined(__sparc__)
+#if defined(CONFIG_X86)
 		/*
 		 * These cannot be implemented on any machine that implements
 		 * ioperm() in user level (such as Alpha PCs).
diff -urN linux-2.4.20-pre4/drivers/hotplug/pci_hotplug_core.c linux-2.4.20-pre5/drivers/hotplug/pci_hotplug_core.c
--- linux-2.4.20-pre4/drivers/hotplug/pci_hotplug_core.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre5/drivers/hotplug/pci_hotplug_core.c	Wed Aug 28 16:37:54 2002
@@ -76,7 +76,6 @@
 };
 
 static struct super_operations pcihpfs_ops;
-static struct file_operations pcihpfs_dir_operations;
 static struct file_operations default_file_operations;
 static struct inode_operations pcihpfs_dir_inode_operations;
 static struct vfsmount *pcihpfs_mount;	/* one of the mounts of our fs for reference counting */
@@ -122,7 +121,7 @@
 			break;
 		case S_IFDIR:
 			inode->i_op = &pcihpfs_dir_inode_operations;
-			inode->i_fop = &pcihpfs_dir_operations;
+			inode->i_fop = &dcache_dir_ops;
 			break;
 		}
 	}
@@ -235,11 +234,6 @@
 	return 0;
 }
 
-static struct file_operations pcihpfs_dir_operations = {
-	read:		generic_read_dir,
-	readdir:	dcache_readdir,
-};
-
 static struct file_operations default_file_operations = {
 	read:		default_read_file,
 	write:		default_write_file,
@@ -966,7 +960,7 @@
 	if (get_slot_from_name (slot->name) != NULL) {
 		spin_unlock (&list_lock);
 		kfree (core);
-		return -EINVAL;
+		return -EEXIST;
 	}
 
 	slot->core_priv = core;
diff -urN linux-2.4.20-pre4/drivers/ieee1394/pcilynx.c linux-2.4.20-pre5/drivers/ieee1394/pcilynx.c
--- linux-2.4.20-pre4/drivers/ieee1394/pcilynx.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre5/drivers/ieee1394/pcilynx.c	Wed Aug 28 16:37:55 2002
@@ -896,6 +896,12 @@
         ssize_t retval;
         void *membase;
 
+	if (*offset != off)	/* Check for EOF before we trust wrap */
+		return 0;
+	
+	if (off + count > off)
+		return 0;
+		
         if ((off + count) > PCILYNX_MAX_MEMORY + 1) {
                 count = PCILYNX_MAX_MEMORY + 1 - off;
         }
diff -urN linux-2.4.20-pre4/drivers/isdn/hisax/hisax_debug.h linux-2.4.20-pre5/drivers/isdn/hisax/hisax_debug.h
--- linux-2.4.20-pre4/drivers/isdn/hisax/hisax_debug.h	Sun Sep 30 12:26:05 2001
+++ linux-2.4.20-pre5/drivers/isdn/hisax/hisax_debug.h	Wed Aug 28 16:37:55 2002
@@ -28,7 +28,7 @@
 
 #define DBG(level, format, arg...) do { \
 if (level & __debug_variable) \
-printk(KERN_DEBUG __FUNCTION__ ": " format "\n" , ## arg); \
+printk(KERN_DEBUG "%s: " format "\n" , __FUNCTION__ , ## arg); \
 } while (0)
 
 #define DBG_PACKET(level,data,count) \
diff -urN linux-2.4.20-pre4/drivers/md/md.c linux-2.4.20-pre5/drivers/md/md.c
--- linux-2.4.20-pre4/drivers/md/md.c	Wed Aug 28 16:36:52 2002
+++ linux-2.4.20-pre5/drivers/md/md.c	Wed Aug 28 16:37:58 2002
@@ -3712,7 +3712,7 @@
  * Searches all registered partitions for autorun RAID arrays
  * at boot time.
  */
-static int detected_devices[128];
+static kdev_t detected_devices[128];
 static int dev_cnt;
 
 void md_autodetect_dev(kdev_t dev)
diff -urN linux-2.4.20-pre4/drivers/media/video/bttv-driver.c linux-2.4.20-pre5/drivers/media/video/bttv-driver.c
--- linux-2.4.20-pre4/drivers/media/video/bttv-driver.c	Wed Aug 28 16:36:52 2002
+++ linux-2.4.20-pre5/drivers/media/video/bttv-driver.c	Wed Aug 28 16:37:58 2002
@@ -1215,7 +1215,8 @@
 static long bttv_read(struct video_device *v, char *buf, unsigned long count, int nonblock)
 {
 	struct bttv *btv= (struct bttv *)v;
-	int q,todo;
+	int q;
+	unsigned long todo;
 	DECLARE_WAITQUEUE(wait, current);
 
 	/* BROKEN: RETURNS VBI WHEN IT SHOULD RETURN GRABBED VIDEO FRAME */
diff -urN linux-2.4.20-pre4/drivers/message/i2o/README.ioctl linux-2.4.20-pre5/drivers/message/i2o/README.ioctl
--- linux-2.4.20-pre4/drivers/message/i2o/README.ioctl	Mon Jun 19 13:30:55 2000
+++ linux-2.4.20-pre5/drivers/message/i2o/README.ioctl	Wed Aug 28 16:38:00 2002
@@ -318,7 +318,7 @@
    DESCRIPTION
 
    This function posts an ExecConfigValidate message to the controller
-   identified by iop. This message indicates that the the current
+   identified by iop. This message indicates that the current
    configuration is accepted. The iop changes the status of suspect drivers 
    to valid and may delete old drivers from its store.
 
diff -urN linux-2.4.20-pre4/drivers/message/i2o/i2o_core.c linux-2.4.20-pre5/drivers/message/i2o/i2o_core.c
--- linux-2.4.20-pre4/drivers/message/i2o/i2o_core.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre5/drivers/message/i2o/i2o_core.c	Wed Aug 28 16:38:00 2002
@@ -3390,8 +3390,9 @@
 	{
 		if(i2o_quiesce_controller(c))
 		{
-			printk(KERN_WARNING "i2o: Could not quiesce %s."  "
-				Verify setup on next system power up.\n", c->name);
+			printk(KERN_WARNING "i2o: Could not quiesce %s.\n"
+			       "Verify setup on next system power up.\n",
+			       c->name);
 		}
 	}
 
diff -urN linux-2.4.20-pre4/drivers/message/i2o/i2o_pci.c linux-2.4.20-pre5/drivers/message/i2o/i2o_pci.c
--- linux-2.4.20-pre4/drivers/message/i2o/i2o_pci.c	Wed Aug 28 16:36:54 2002
+++ linux-2.4.20-pre5/drivers/message/i2o/i2o_pci.c	Wed Aug 28 16:38:00 2002
@@ -335,6 +335,11 @@
 			continue;
 		printk(KERN_INFO "i2o: I2O controller on bus %d at %d.\n",
 			dev->bus->number, dev->devfn);
+		if(pci_set_dma_mask(dev, 0xffffffff))
+		{
+			printk(KERN_WARNING "I2O controller on bus %d at %d : No suitable DMA available\n", dev->bus->number, dev->devfn);
+		 	continue;
+		}
 		pci_set_master(dev);
 		if(i2o_pci_install(dev)==0)
 			count++;
diff -urN linux-2.4.20-pre4/drivers/net/8139cp.c linux-2.4.20-pre5/drivers/net/8139cp.c
--- linux-2.4.20-pre4/drivers/net/8139cp.c	Wed Aug 28 16:36:54 2002
+++ linux-2.4.20-pre5/drivers/net/8139cp.c	Wed Aug 28 16:38:00 2002
@@ -303,13 +303,12 @@
 struct cp_desc {
 	u32		opts1;
 	u32		opts2;
-	u32		addr_lo;
-	u32		addr_hi;
+	u64		addr;
 };
 
 struct ring_info {
 	struct sk_buff		*skb;
-	dma64_addr_t		mapping;
+	dma_addr_t		mapping;
 	unsigned		frag;
 };
 
@@ -579,7 +578,7 @@
 
 	while (rx_work--) {
 		u32 status, len;
-		dma64_addr_t mapping;
+		dma_addr_t mapping;
 		struct sk_buff *skb, *new_skb;
 		struct cp_desc *desc;
 		unsigned buflen;
@@ -646,8 +645,7 @@
 		else
 			desc->opts1 = cpu_to_le32(DescOwn | cp->rx_buf_sz);
 		cp->rx_ring[rx_tail].opts2 = 0;
-		cp->rx_ring[rx_tail].addr_lo = cpu_to_le32(mapping & 0xffffffff);
-		cp->rx_ring[rx_tail].addr_hi = cpu_to_le32(mapping >> 32);
+		cp->rx_ring[rx_tail].addr = cpu_to_le64(mapping);
 		rx_tail = NEXT_RX(rx_tail);
 	}
 
@@ -779,14 +777,13 @@
 	if (skb_shinfo(skb)->nr_frags == 0) {
 		struct cp_desc *txd = &cp->tx_ring[entry];
 		u32 len;
-		dma64_addr_t mapping;
+		dma_addr_t mapping;
 
 		len = skb->len;
 		mapping = pci_map_single(cp->pdev, skb->data, len, PCI_DMA_TODEVICE);
 		eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
 		CP_VLAN_TX_TAG(txd, vlan_tag);
-		txd->addr_lo = cpu_to_le32(mapping & 0xffffffff);
-		txd->addr_hi = cpu_to_le32(mapping >> 32);
+		txd->addr = cpu_to_le64(mapping);
 		wmb();
 
 #ifdef CP_TX_CHECKSUM
@@ -815,7 +812,7 @@
 	} else {
 		struct cp_desc *txd;
 		u32 first_len;
-		dma64_addr_t first_mapping;
+		dma_addr_t first_mapping;
 		int frag, first_entry = entry;
 #ifdef CP_TX_CHECKSUM
 		const struct iphdr *ip = skb->nh.iph;
@@ -836,7 +833,7 @@
 			skb_frag_t *this_frag = &skb_shinfo(skb)->frags[frag];
 			u32 len;
 			u32 ctrl;
-			dma64_addr_t mapping;
+			dma_addr_t mapping;
 
 			len = this_frag->size;
 			mapping = pci_map_single(cp->pdev,
@@ -862,8 +859,7 @@
 
 			txd = &cp->tx_ring[entry];
 			CP_VLAN_TX_TAG(txd, vlan_tag);
-			txd->addr_lo = cpu_to_le32(mapping & 0xffffffff);
-			txd->addr_hi = cpu_to_le32(mapping >> 32);
+			txd->addr = cpu_to_le64(mapping);
 			wmb();
 
 			txd->opts1 = cpu_to_le32(ctrl);
@@ -877,8 +873,7 @@
 
 		txd = &cp->tx_ring[first_entry];
 		CP_VLAN_TX_TAG(txd, vlan_tag);
-		txd->addr_lo = cpu_to_le32(first_mapping & 0xffffffff);
-		txd->addr_hi = cpu_to_le32(first_mapping >> 32);
+		txd->addr = cpu_to_le64(first_mapping);
 		wmb();
 
 #ifdef CP_TX_CHECKSUM
@@ -1098,10 +1093,7 @@
 			cp->rx_ring[i].opts1 =
 				cpu_to_le32(DescOwn | cp->rx_buf_sz);
 		cp->rx_ring[i].opts2 = 0;
-		cp->rx_ring[i].addr_lo =
-			cpu_to_le32(cp->rx_skb[i].mapping & 0xffffffff);
-		cp->rx_ring[i].addr_hi =
-			cpu_to_le32(cp->rx_skb[i].mapping >> 32);
+		cp->rx_ring[i].addr = cpu_to_le64(cp->rx_skb[i].mapping);
 	}
 
 	return 0;
diff -urN linux-2.4.20-pre4/drivers/net/cs89x0.h linux-2.4.20-pre5/drivers/net/cs89x0.h
--- linux-2.4.20-pre4/drivers/net/cs89x0.h	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre5/drivers/net/cs89x0.h	Wed Aug 28 16:38:03 2002
@@ -385,11 +385,11 @@
 #define A_CNF_10B_T 0x0001
 #define A_CNF_AUI 0x0002
 #define A_CNF_10B_2 0x0004
-#define A_CNF_MEDIA_TYPE 0x0060
-#define A_CNF_MEDIA_AUTO 0x0000
+#define A_CNF_MEDIA_TYPE 0x0070
+#define A_CNF_MEDIA_AUTO 0x0070
 #define A_CNF_MEDIA_10B_T 0x0020
 #define A_CNF_MEDIA_AUI 0x0040
-#define A_CNF_MEDIA_10B_2 0x0060
+#define A_CNF_MEDIA_10B_2 0x0010
 #define A_CNF_DC_DC_POLARITY 0x0080
 #define A_CNF_NO_AUTO_POLARITY 0x2000
 #define A_CNF_LOW_RX_SQUELCH 0x4000
diff -urN linux-2.4.20-pre4/drivers/net/e100/LICENSE linux-2.4.20-pre5/drivers/net/e100/LICENSE
--- linux-2.4.20-pre4/drivers/net/e100/LICENSE	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre5/drivers/net/e100/LICENSE	Wed Aug 28 16:38:03 2002
@@ -0,0 +1,339 @@
+
+"This software program is licensed subject to the GNU General Public License 
+(GPL). Version 2, June 1991, available at 
+<http://www.fsf.org/copyleft/gpl.html>"
+
+GNU General Public License 
+
+Version 2, June 1991
+
+Copyright (C) 1989, 1991 Free Software Foundation, Inc.  
+59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
+
+Everyone is permitted to copy and distribute verbatim copies of this license
+document, but changing it is not allowed.
+
+Preamble
+
+The licenses for most software are designed to take away your freedom to 
+share and change it. By contrast, the GNU General Public License is intended
+to guarantee your freedom to share and change free software--to make sure 
+the software is free for all its users. This General Public License applies 
+to most of the Free Software Foundation's software and to any other program 
+whose authors commit to using it. (Some other Free Software Foundation 
+software is covered by the GNU Library General Public License instead.) You 
+can apply it to your programs, too.
+
+When we speak of free software, we are referring to freedom, not price. Our
+General Public Licenses are designed to make sure that you have the freedom 
+to distribute copies of free software (and charge for this service if you 
+wish), that you receive source code or can get it if you want it, that you 
+can change the software or use pieces of it in new free programs; and that 
+you know you can do these things.
+
+To protect your rights, we need to make restrictions that forbid anyone to 
+deny you these rights or to ask you to surrender the rights. These 
+restrictions translate to certain responsibilities for you if you distribute
+copies of the software, or if you modify it.
+
+For example, if you distribute copies of such a program, whether gratis or 
+for a fee, you must give the recipients all the rights that you have. You 
+must make sure that they, too, receive or can get the source code. And you 
+must show them these terms so they know their rights.
+ 
+We protect your rights with two steps: (1) copyright the software, and (2) 
+offer you this license which gives you legal permission to copy, distribute 
+and/or modify the software. 
+
+Also, for each author's protection and ours, we want to make certain that 
+everyone understands that there is no warranty for this free software. If 
+the software is modified by someone else and passed on, we want its 
+recipients to know that what they have is not the original, so that any 
+problems introduced by others will not reflect on the original authors' 
+reputations. 
+
+Finally, any free program is threatened constantly by software patents. We 
+wish to avoid the danger that redistributors of a free program will 
+individually obtain patent licenses, in effect making the program 
+proprietary. To prevent this, we have made it clear that any patent must be 
+licensed for everyone's free use or not licensed at all. 
+
+The precise terms and conditions for copying, distribution and modification 
+follow. 
+
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+0. This License applies to any program or other work which contains a notice
+   placed by the copyright holder saying it may be distributed under the 
+   terms of this General Public License. The "Program", below, refers to any
+   such program or work, and a "work based on the Program" means either the 
+   Program or any derivative work under copyright law: that is to say, a 
+   work containing the Program or a portion of it, either verbatim or with 
+   modifications and/or translated into another language. (Hereinafter, 
+   translation is included without limitation in the term "modification".) 
+   Each licensee is addressed as "you". 
+
+   Activities other than copying, distribution and modification are not 
+   covered by this License; they are outside its scope. The act of running 
+   the Program is not restricted, and the output from the Program is covered 
+   only if its contents constitute a work based on the Program (independent 
+   of having been made by running the Program). Whether that is true depends
+   on what the Program does. 
+
+1. You may copy and distribute verbatim copies of the Program's source code 
+   as you receive it, in any medium, provided that you conspicuously and 
+   appropriately publish on each copy an appropriate copyright notice and 
+   disclaimer of warranty; keep intact all the notices that refer to this 
+   License and to the absence of any warranty; and give any other recipients 
+   of the Program a copy of this License along with the Program. 
+
+   You may charge a fee for the physical act of transferring a copy, and you 
+   may at your option offer warranty protection in exchange for a fee. 
+
+2. You may modify your copy or copies of the Program or any portion of it, 
+   thus forming a work based on the Program, and copy and distribute such 
+   modifications or work under the terms of Section 1 above, provided that 
+   you also meet all of these conditions: 
+
+   * a) You must cause the modified files to carry prominent notices stating 
+        that you changed the files and the date of any change. 
+
+   * b) You must cause any work that you distribute or publish, that in 
+        whole or in part contains or is derived from the Program or any part 
+        thereof, to be licensed as a whole at no charge to all third parties
+        under the terms of this License. 
+
+   * c) If the modified program normally reads commands interactively when 
+        run, you must cause it, when started running for such interactive 
+        use in the most ordinary way, to print or display an announcement 
+        including an appropriate copyright notice and a notice that there is
+        no warranty (or else, saying that you provide a warranty) and that 
+        users may redistribute the program under these conditions, and 
+        telling the user how to view a copy of this License. (Exception: if 
+        the Program itself is interactive but does not normally print such 
+        an announcement, your work based on the Program is not required to 
+        print an announcement.) 
+
+   These requirements apply to the modified work as a whole. If identifiable 
+   sections of that work are not derived from the Program, and can be 
+   reasonably considered independent and separate works in themselves, then 
+   this License, and its terms, do not apply to those sections when you 
+   distribute them as separate works. But when you distribute the same 
+   sections as part of a whole which is a work based on the Program, the 
+   distribution of the whole must be on the terms of this License, whose 
+   permissions for other licensees extend to the entire whole, and thus to 
+   each and every part regardless of who wrote it. 
+
+   Thus, it is not the intent of this section to claim rights or contest 
+   your rights to work written entirely by you; rather, the intent is to 
+   exercise the right to control the distribution of derivative or 
+   collective works based on the Program. 
+
+   In addition, mere aggregation of another work not based on the Program 
+   with the Program (or with a work based on the Program) on a volume of a 
+   storage or distribution medium does not bring the other work under the 
+   scope of this License. 
+
+3. You may copy and distribute the Program (or a work based on it, under 
+   Section 2) in object code or executable form under the terms of Sections 
+   1 and 2 above provided that you also do one of the following: 
+
+   * a) Accompany it with the complete corresponding machine-readable source 
+        code, which must be distributed under the terms of Sections 1 and 2 
+        above on a medium customarily used for software interchange; or, 
+
+   * b) Accompany it with a written offer, valid for at least three years, 
+        to give any third party, for a charge no more than your cost of 
+        physically performing source distribution, a complete machine-
+        readable copy of the corresponding source code, to be distributed 
+        under the terms of Sections 1 and 2 above on a medium customarily 
+        used for software interchange; or, 
+
+   * c) Accompany it with the information you received as to the offer to 
+        distribute corresponding source code. (This alternative is allowed 
+        only for noncommercial distribution and only if you received the 
+        program in object code or executable form with such an offer, in 
+        accord with Subsection b above.) 
+
+   The source code for a work means the preferred form of the work for 
+   making modifications to it. For an executable work, complete source code 
+   means all the source code for all modules it contains, plus any 
+   associated interface definition files, plus the scripts used to control 
+   compilation and installation of the executable. However, as a special 
+   exception, the source code distributed need not include anything that is 
+   normally distributed (in either source or binary form) with the major 
+   components (compiler, kernel, and so on) of the operating system on which
+   the executable runs, unless that component itself accompanies the 
+   executable. 
+
+   If distribution of executable or object code is made by offering access 
+   to copy from a designated place, then offering equivalent access to copy 
+   the source code from the same place counts as distribution of the source 
+   code, even though third parties are not compelled to copy the source 
+   along with the object code. 
+
+4. You may not copy, modify, sublicense, or distribute the Program except as
+   expressly provided under this License. Any attempt otherwise to copy, 
+   modify, sublicense or distribute the Program is void, and will 
+   automatically terminate your rights under this License. However, parties 
+   who have received copies, or rights, from you under this License will not
+   have their licenses terminated so long as such parties remain in full 
+   compliance. 
+
+5. You are not required to accept this License, since you have not signed 
+   it. However, nothing else grants you permission to modify or distribute 
+   the Program or its derivative works. These actions are prohibited by law 
+   if you do not accept this License. Therefore, by modifying or 
+   distributing the Program (or any work based on the Program), you 
+   indicate your acceptance of this License to do so, and all its terms and
+   conditions for copying, distributing or modifying the Program or works 
+   based on it. 
+
+6. Each time you redistribute the Program (or any work based on the 
+   Program), the recipient automatically receives a license from the 
+   original licensor to copy, distribute or modify the Program subject to 
+   these terms and conditions. You may not impose any further restrictions 
+   on the recipients' exercise of the rights granted herein. You are not 
+   responsible for enforcing compliance by third parties to this License. 
+
+7. If, as a consequence of a court judgment or allegation of patent 
+   infringement or for any other reason (not limited to patent issues), 
+   conditions are imposed on you (whether by court order, agreement or 
+   otherwise) that contradict the conditions of this License, they do not 
+   excuse you from the conditions of this License. If you cannot distribute 
+   so as to satisfy simultaneously your obligations under this License and 
+   any other pertinent obligations, then as a consequence you may not 
+   distribute the Program at all. For example, if a patent license would 
+   not permit royalty-free redistribution of the Program by all those who 
+   receive copies directly or indirectly through you, then the only way you 
+   could satisfy both it and this License would be to refrain entirely from 
+   distribution of the Program. 
+
+   If any portion of this section is held invalid or unenforceable under any
+   particular circumstance, the balance of the section is intended to apply
+   and the section as a whole is intended to apply in other circumstances. 
+
+   It is not the purpose of this section to induce you to infringe any 
+   patents or other property right claims or to contest validity of any 
+   such claims; this section has the sole purpose of protecting the 
+   integrity of the free software distribution system, which is implemented 
+   by public license practices. Many people have made generous contributions
+   to the wide range of software distributed through that system in 
+   reliance on consistent application of that system; it is up to the 
+   author/donor to decide if he or she is willing to distribute software 
+   through any other system and a licensee cannot impose that choice. 
+
+   This section is intended to make thoroughly clear what is believed to be 
+   a consequence of the rest of this License. 
+
+8. If the distribution and/or use of the Program is restricted in certain 
+   countries either by patents or by copyrighted interfaces, the original 
+   copyright holder who places the Program under this License may add an 
+   explicit geographical distribution limitation excluding those countries, 
+   so that distribution is permitted only in or among countries not thus 
+   excluded. In such case, this License incorporates the limitation as if 
+   written in the body of this License. 
+
+9. The Free Software Foundation may publish revised and/or new versions of 
+   the General Public License from time to time. Such new versions will be 
+   similar in spirit to the present version, but may differ in detail to 
+   address new problems or concerns. 
+
+   Each version is given a distinguishing version number. If the Program 
+   specifies a version number of this License which applies to it and "any 
+   later version", you have the option of following the terms and 
+   conditions either of that version or of any later version published by 
+   the Free Software Foundation. If the Program does not specify a version 
+   number of this License, you may choose any version ever published by the 
+   Free Software Foundation. 
+
+10. If you wish to incorporate parts of the Program into other free programs
+    whose distribution conditions are different, write to the author to ask 
+    for permission. For software which is copyrighted by the Free Software 
+    Foundation, write to the Free Software Foundation; we sometimes make 
+    exceptions for this. Our decision will be guided by the two goals of 
+    preserving the free status of all derivatives of our free software and 
+    of promoting the sharing and reuse of software generally. 
+
+   NO WARRANTY
+
+11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 
+    FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 
+    OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 
+    PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER 
+    EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
+    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE 
+    ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH 
+    YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL 
+    NECESSARY SERVICING, REPAIR OR CORRECTION. 
+
+12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 
+    WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 
+    REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR 
+    DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL 
+    DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM 
+    (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED 
+    INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF 
+    THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR 
+    OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 
+
+END OF TERMS AND CONDITIONS
+
+How to Apply These Terms to Your New Programs
+
+If you develop a new program, and you want it to be of the greatest 
+possible use to the public, the best way to achieve this is to make it free 
+software which everyone can redistribute and change under these terms. 
+
+To do so, attach the following notices to the program. It is safest to 
+attach them to the start of each source file to most effectively convey the
+exclusion of warranty; and each file should have at least the "copyright" 
+line and a pointer to where the full notice is found. 
+
+one line to give the program's name and an idea of what it does.
+Copyright (C) yyyy  name of author
+
+This program is free software; you can redistribute it and/or modify it 
+under the terms of the GNU General Public License as published by the Free 
+Software Foundation; either version 2 of the License, or (at your option) 
+any later version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT 
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
+more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 
+Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Also add information on how to contact you by electronic and paper mail. 
+
+If the program is interactive, make it output a short notice like this when 
+it starts in an interactive mode: 
+
+Gnomovision version 69, Copyright (C) year name of author Gnomovision comes 
+with ABSOLUTELY NO WARRANTY; for details type 'show w'.  This is free 
+software, and you are welcome to redistribute it under certain conditions; 
+type 'show c' for details.
+
+The hypothetical commands 'show w' and 'show c' should show the appropriate 
+parts of the General Public License. Of course, the commands you use may be 
+called something other than 'show w' and 'show c'; they could even be 
+mouse-clicks or menu items--whatever suits your program. 
+
+You should also get your employer (if you work as a programmer) or your 
+school, if any, to sign a "copyright disclaimer" for the program, if 
+necessary. Here is a sample; alter the names: 
+
+Yoyodyne, Inc., hereby disclaims all copyright interest in the program 
+'Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+signature of Ty Coon, 1 April 1989
+Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into 
+proprietary programs. If your program is a subroutine library, you may 
+consider it more useful to permit linking proprietary applications with the 
+library. If this is what you want to do, use the GNU Library General Public 
+License instead of this License.
diff -urN linux-2.4.20-pre4/drivers/net/e100/e100.h linux-2.4.20-pre5/drivers/net/e100/e100.h
--- linux-2.4.20-pre4/drivers/net/e100/e100.h	Wed Aug 28 16:36:54 2002
+++ linux-2.4.20-pre5/drivers/net/e100/e100.h	Wed Aug 28 16:38:03 2002
@@ -1,73 +1,28 @@
 /*******************************************************************************
 
-This software program is available to you under a choice of one of two 
-licenses. You may choose to be licensed under either the GNU General Public 
-License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html, 
-or the Intel BSD + Patent License, the text of which follows:
-
-Recipient has requested a license and Intel Corporation ("Intel") is willing
-to grant a license for the software entitled Linux Base Driver for the 
-Intel(R) PRO/100 Family of Adapters (e100) (the "Software") being provided 
-by Intel Corporation. The following definitions apply to this license:
-
-"Licensed Patents" means patent claims licensable by Intel Corporation which 
-are necessarily infringed by the use of sale of the Software alone or when 
-combined with the operating system referred to below.
-
-"Recipient" means the party to whom Intel delivers this Software.
-
-"Licensee" means Recipient and those third parties that receive a license to 
-any operating system available under the GNU General Public License 2.0 or 
-later.
-
-Copyright (c) 1999 - 2002 Intel Corporation.
-All rights reserved.
-
-The license is provided to Recipient and Recipient's Licensees under the 
-following terms.
-
-Redistribution and use in source and binary forms of the Software, with or 
-without modification, are permitted provided that the following conditions 
-are met:
-
-Redistributions of source code of the Software may retain the above 
-copyright notice, this list of conditions and the following disclaimer.
-
-Redistributions in binary form of the Software may reproduce the above 
-copyright notice, this list of conditions and the following disclaimer in 
-the documentation and/or materials provided with the distribution.
-
-Neither the name of Intel Corporation nor the names of its contributors 
-shall be used to endorse or promote products derived from this Software 
-without specific prior written permission.
-
-Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, 
-royalty-free patent license under Licensed Patents to make, use, sell, offer 
-to sell, import and otherwise transfer the Software, if any, in source code 
-and object code form. This license shall include changes to the Software 
-that are error corrections or other minor changes to the Software that do 
-not add functionality or features when the Software is incorporated in any 
-version of an operating system that has been distributed under the GNU 
-General Public License 2.0 or later. This patent license shall apply to the 
-combination of the Software and any operating system licensed under the GNU 
-General Public License 2.0 or later if, at the time Intel provides the 
-Software to Recipient, such addition of the Software to the then publicly 
-available versions of such operating systems available under the GNU General 
-Public License 2.0 or later (whether in gold, beta or alpha form) causes 
-such combination to be covered by the Licensed Patents. The patent license 
-shall not apply to any other combinations which include the Software. NO 
-hardware per se is licensed hereunder.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
-IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
-ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY 
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
-(INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
-ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED 
-AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR 
-TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  
+  This program is free software; you can redistribute it and/or modify it 
+  under the terms of the GNU General Public License as published by the Free 
+  Software Foundation; either version 2 of the License, or (at your option) 
+  any later version.
+  
+  This program is distributed in the hope that it will be useful, but WITHOUT 
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
+  more details.
+  
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59 
+  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 *******************************************************************************/
 
 #ifndef _E100_INC_
@@ -104,6 +59,7 @@
 #include <linux/proc_fs.h>
 #include <linux/ip.h>
 
+#define E100_REGS_LEN 1
 /*
  *  Configure parameters for buffers per controller.
  *  If the machine this is being used on is a faster machine (i.e. > 150MHz)
diff -urN linux-2.4.20-pre4/drivers/net/e100/e100_config.c linux-2.4.20-pre5/drivers/net/e100/e100_config.c
--- linux-2.4.20-pre4/drivers/net/e100/e100_config.c	Wed Aug 28 16:36:54 2002
+++ linux-2.4.20-pre5/drivers/net/e100/e100_config.c	Wed Aug 28 16:38:03 2002
@@ -1,73 +1,28 @@
 /*******************************************************************************
 
-This software program is available to you under a choice of one of two 
-licenses. You may choose to be licensed under either the GNU General Public 
-License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html, 
-or the Intel BSD + Patent License, the text of which follows:
-
-Recipient has requested a license and Intel Corporation ("Intel") is willing
-to grant a license for the software entitled Linux Base Driver for the 
-Intel(R) PRO/100 Family of Adapters (e100) (the "Software") being provided 
-by Intel Corporation. The following definitions apply to this license:
-
-"Licensed Patents" means patent claims licensable by Intel Corporation which 
-are necessarily infringed by the use of sale of the Software alone or when 
-combined with the operating system referred to below.
-
-"Recipient" means the party to whom Intel delivers this Software.
-
-"Licensee" means Recipient and those third parties that receive a license to 
-any operating system available under the GNU General Public License 2.0 or 
-later.
-
-Copyright (c) 1999 - 2002 Intel Corporation.
-All rights reserved.
-
-The license is provided to Recipient and Recipient's Licensees under the 
-following terms.
-
-Redistribution and use in source and binary forms of the Software, with or 
-without modification, are permitted provided that the following conditions 
-are met:
-
-Redistributions of source code of the Software may retain the above 
-copyright notice, this list of conditions and the following disclaimer.
-
-Redistributions in binary form of the Software may reproduce the above 
-copyright notice, this list of conditions and the following disclaimer in 
-the documentation and/or materials provided with the distribution.
-
-Neither the name of Intel Corporation nor the names of its contributors 
-shall be used to endorse or promote products derived from this Software 
-without specific prior written permission.
-
-Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, 
-royalty-free patent license under Licensed Patents to make, use, sell, offer 
-to sell, import and otherwise transfer the Software, if any, in source code 
-and object code form. This license shall include changes to the Software 
-that are error corrections or other minor changes to the Software that do 
-not add functionality or features when the Software is incorporated in any 
-version of an operating system that has been distributed under the GNU 
-General Public License 2.0 or later. This patent license shall apply to the 
-combination of the Software and any operating system licensed under the GNU 
-General Public License 2.0 or later if, at the time Intel provides the 
-Software to Recipient, such addition of the Software to the then publicly 
-available versions of such operating systems available under the GNU General 
-Public License 2.0 or later (whether in gold, beta or alpha form) causes 
-such combination to be covered by the Licensed Patents. The patent license 
-shall not apply to any other combinations which include the Software. NO 
-hardware per se is licensed hereunder.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
-IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
-ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY 
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
-(INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
-ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED 
-AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR 
-TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  
+  This program is free software; you can redistribute it and/or modify it 
+  under the terms of the GNU General Public License as published by the Free 
+  Software Foundation; either version 2 of the License, or (at your option) 
+  any later version.
+  
+  This program is distributed in the hope that it will be useful, but WITHOUT 
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
+  more details.
+  
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59 
+  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 *******************************************************************************/
 
 /**********************************************************************
diff -urN linux-2.4.20-pre4/drivers/net/e100/e100_config.h linux-2.4.20-pre5/drivers/net/e100/e100_config.h
--- linux-2.4.20-pre4/drivers/net/e100/e100_config.h	Wed Aug 28 16:36:54 2002
+++ linux-2.4.20-pre5/drivers/net/e100/e100_config.h	Wed Aug 28 16:38:03 2002
@@ -1,73 +1,28 @@
 /*******************************************************************************
 
-This software program is available to you under a choice of one of two 
-licenses. You may choose to be licensed under either the GNU General Public 
-License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html, 
-or the Intel BSD + Patent License, the text of which follows:
-
-Recipient has requested a license and Intel Corporation ("Intel") is willing
-to grant a license for the software entitled Linux Base Driver for the 
-Intel(R) PRO/100 Family of Adapters (e100) (the "Software") being provided 
-by Intel Corporation. The following definitions apply to this license:
-
-"Licensed Patents" means patent claims licensable by Intel Corporation which 
-are necessarily infringed by the use of sale of the Software alone or when 
-combined with the operating system referred to below.
-
-"Recipient" means the party to whom Intel delivers this Software.
-
-"Licensee" means Recipient and those third parties that receive a license to 
-any operating system available under the GNU General Public License 2.0 or 
-later.
-
-Copyright (c) 1999 - 2002 Intel Corporation.
-All rights reserved.
-
-The license is provided to Recipient and Recipient's Licensees under the 
-following terms.
-
-Redistribution and use in source and binary forms of the Software, with or 
-without modification, are permitted provided that the following conditions 
-are met:
-
-Redistributions of source code of the Software may retain the above 
-copyright notice, this list of conditions and the following disclaimer.
-
-Redistributions in binary form of the Software may reproduce the above 
-copyright notice, this list of conditions and the following disclaimer in 
-the documentation and/or materials provided with the distribution.
-
-Neither the name of Intel Corporation nor the names of its contributors 
-shall be used to endorse or promote products derived from this Software 
-without specific prior written permission.
-
-Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, 
-royalty-free patent license under Licensed Patents to make, use, sell, offer 
-to sell, import and otherwise transfer the Software, if any, in source code 
-and object code form. This license shall include changes to the Software 
-that are error corrections or other minor changes to the Software that do 
-not add functionality or features when the Software is incorporated in any 
-version of an operating system that has been distributed under the GNU 
-General Public License 2.0 or later. This patent license shall apply to the 
-combination of the Software and any operating system licensed under the GNU 
-General Public License 2.0 or later if, at the time Intel provides the 
-Software to Recipient, such addition of the Software to the then publicly 
-available versions of such operating systems available under the GNU General 
-Public License 2.0 or later (whether in gold, beta or alpha form) causes 
-such combination to be covered by the Licensed Patents. The patent license 
-shall not apply to any other combinations which include the Software. NO 
-hardware per se is licensed hereunder.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
-IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
-ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY 
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
-(INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
-ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED 
-AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR 
-TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  
+  This program is free software; you can redistribute it and/or modify it 
+  under the terms of the GNU General Public License as published by the Free 
+  Software Foundation; either version 2 of the License, or (at your option) 
+  any later version.
+  
+  This program is distributed in the hope that it will be useful, but WITHOUT 
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
+  more details.
+  
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59 
+  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 *******************************************************************************/
 
 #ifndef _E100_CONFIG_INC_
diff -urN linux-2.4.20-pre4/drivers/net/e100/e100_eeprom.c linux-2.4.20-pre5/drivers/net/e100/e100_eeprom.c
--- linux-2.4.20-pre4/drivers/net/e100/e100_eeprom.c	Wed Aug 28 16:36:54 2002
+++ linux-2.4.20-pre5/drivers/net/e100/e100_eeprom.c	Wed Aug 28 16:38:03 2002
@@ -1,77 +1,28 @@
 /*******************************************************************************
 
-This software program is available to you under a choice of one of two 
-licenses. You may choose to be licensed under either the GNU General Public 
-License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html, 
-or the Intel BSD + Patent License, the text of which follows:
-
-Recipient has requested a license and Intel Corporation ("Intel") is willing
-to grant a license for the software entitled Linux Base Driver for the 
-Intel(R) PRO/100 Family of Adapters (e100) (the "Software") being provided 
-by Intel Corporation. The following definitions apply to this license:
-
-"Licensed Patents" means patent claims licensable by Intel Corporation which 
-are necessarily infringed by the use of sale of the Software alone or when 
-combined with the operating system referred to below.
-
-"Recipient" means the party to whom Intel delivers this Software.
-
-"Licensee" means Recipient and those third parties that receive a license to 
-any operating system available under the GNU General Public License 2.0 or 
-later.
-
-Copyright (c) 1999 - 2002 Intel Corporation.
-All rights reserved.
-
-The license is provided to Recipient and Recipient's Licensees under the 
-following terms.
-
-Redistribution and use in source and binary forms of the Software, with or 
-without modification, are permitted provided that the following conditions 
-are met:
-
-Redistributions of source code of the Software may retain the above 
-copyright notice, this list of conditions and the following disclaimer.
-
-Redistributions in binary form of the Software may reproduce the above 
-copyright notice, this list of conditions and the following disclaimer in 
-the documentation and/or materials provided with the distribution.
-
-Neither the name of Intel Corporation nor the names of its contributors 
-shall be used to endorse or promote products derived from this Software 
-without specific prior written permission.
-
-Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, 
-royalty-free patent license under Licensed Patents to make, use, sell, offer 
-to sell, import and otherwise transfer the Software, if any, in source code 
-and object code form. This license shall include changes to the Software 
-that are error corrections or other minor changes to the Software that do 
-not add functionality or features when the Software is incorporated in any 
-version of an operating system that has been distributed under the GNU 
-General Public License 2.0 or later. This patent license shall apply to the 
-combination of the Software and any operating system licensed under the GNU 
-General Public License 2.0 or later if, at the time Intel provides the 
-Software to Recipient, such addition of the Software to the then publicly 
-available versions of such operating systems available under the GNU General 
-Public License 2.0 or later (whether in gold, beta or alpha form) causes 
-such combination to be covered by the Licensed Patents. The patent license 
-shall not apply to any other combinations which include the Software. NO 
-hardware per se is licensed hereunder.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
-IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
-ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY 
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
-(INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
-ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED 
-AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR 
-TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*******************************************************************************
-
-Portions (C) 2002 Red Hat, Inc. under the terms of the GNU GPL v2.
-
+  
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  
+  This program is free software; you can redistribute it and/or modify it 
+  under the terms of the GNU General Public License as published by the Free 
+  Software Foundation; either version 2 of the License, or (at your option) 
+  any later version.
+  
+  This program is distributed in the hope that it will be useful, but WITHOUT 
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
+  more details.
+  
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59 
+  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 *******************************************************************************/
 
 /**********************************************************************
diff -urN linux-2.4.20-pre4/drivers/net/e100/e100_main.c linux-2.4.20-pre5/drivers/net/e100/e100_main.c
--- linux-2.4.20-pre4/drivers/net/e100/e100_main.c	Wed Aug 28 16:36:54 2002
+++ linux-2.4.20-pre5/drivers/net/e100/e100_main.c	Wed Aug 28 16:38:03 2002
@@ -1,77 +1,28 @@
 /*******************************************************************************
 
-This software program is available to you under a choice of one of two 
-licenses. You may choose to be licensed under either the GNU General Public 
-License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html, 
-or the Intel BSD + Patent License, the text of which follows:
-
-Recipient has requested a license and Intel Corporation ("Intel") is willing
-to grant a license for the software entitled Linux Base Driver for the 
-Intel(R) PRO/100 Family of Adapters (e100) (the "Software") being provided 
-by Intel Corporation. The following definitions apply to this license:
-
-"Licensed Patents" means patent claims licensable by Intel Corporation which 
-are necessarily infringed by the use of sale of the Software alone or when 
-combined with the operating system referred to below.
-
-"Recipient" means the party to whom Intel delivers this Software.
-
-"Licensee" means Recipient and those third parties that receive a license to 
-any operating system available under the GNU General Public License 2.0 or 
-later.
-
-Copyright (c) 1999 - 2002 Intel Corporation.
-All rights reserved.
-
-The license is provided to Recipient and Recipient's Licensees under the 
-following terms.
-
-Redistribution and use in source and binary forms of the Software, with or 
-without modification, are permitted provided that the following conditions 
-are met:
-
-Redistributions of source code of the Software may retain the above 
-copyright notice, this list of conditions and the following disclaimer.
-
-Redistributions in binary form of the Software may reproduce the above 
-copyright notice, this list of conditions and the following disclaimer in 
-the documentation and/or materials provided with the distribution.
-
-Neither the name of Intel Corporation nor the names of its contributors 
-shall be used to endorse or promote products derived from this Software 
-without specific prior written permission.
-
-Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, 
-royalty-free patent license under Licensed Patents to make, use, sell, offer 
-to sell, import and otherwise transfer the Software, if any, in source code 
-and object code form. This license shall include changes to the Software 
-that are error corrections or other minor changes to the Software that do 
-not add functionality or features when the Software is incorporated in any 
-version of an operating system that has been distributed under the GNU 
-General Public License 2.0 or later. This patent license shall apply to the 
-combination of the Software and any operating system licensed under the GNU 
-General Public License 2.0 or later if, at the time Intel provides the 
-Software to Recipient, such addition of the Software to the then publicly 
-available versions of such operating systems available under the GNU General 
-Public License 2.0 or later (whether in gold, beta or alpha form) causes 
-such combination to be covered by the Licensed Patents. The patent license 
-shall not apply to any other combinations which include the Software. NO 
-hardware per se is licensed hereunder.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
-IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
-ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY 
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
-(INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
-ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED 
-AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR 
-TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*******************************************************************************
-
-Portions (C) 2002 Red Hat, Inc. under the terms of the GNU GPL v2.
-
+  
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  
+  This program is free software; you can redistribute it and/or modify it 
+  under the terms of the GNU General Public License as published by the Free 
+  Software Foundation; either version 2 of the License, or (at your option) 
+  any later version.
+  
+  This program is distributed in the hope that it will be useful, but WITHOUT 
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
+  more details.
+  
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59 
+  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 *******************************************************************************/
 
 /**********************************************************************
@@ -95,6 +46,21 @@
 
 /* Change Log
  *
+ * 2.1.12       8/2/02
+ *   o Feature: ethtool register dump
+ *   o Bug fix: Driver passes wrong name to /proc/interrupts
+ *   o Bug fix: Ethernet bridging not working 
+ *   o Bug fix: Promiscuous mode is not working
+ *   o Bug fix: Checked return value from copy_from_user (William Stinson,
+ *     wstinson@infonie.fr)
+ *   o Bug fix: ARP wake on LAN fails
+ *   o Bug fix: mii-diag does not update driver level's speed, duplex and
+ *     re-configure flow control
+ *   o Bug fix: Ethtool shows wrong speed/duplex when not connected
+ *   o Bug fix: Ethtool shows wrong speed/duplex when reconnected if forced 
+ *     speed/duplex
+ *   o Bug fix: PHY loopback diagnostic fails
+ *
  * 2.1.6        7/5/02
  *   o Added device ID support for Dell LOM.
  *   o Added device ID support for 82511QM mobile nics.
@@ -145,6 +111,7 @@
 
 #define E100_EEPROM_MAGIC 0x1234
 static int e100_ethtool_glink(struct net_device *, struct ifreq *);
+static int e100_ethtool_gregs(struct net_device *, struct ifreq *);
 static int e100_ethtool_nway_rst(struct net_device *, struct ifreq *);
 static int e100_ethtool_wol(struct net_device *, struct ifreq *);
 static unsigned char e100_setup_filter(struct e100_private *bdp);
@@ -176,7 +143,7 @@
 
 /* Global Data structures and variables */
 char e100_copyright[] __devinitdata = "Copyright (c) 2002 Intel Corporation";
-char e100_driver_version[]="2.1.6-k1";
+char e100_driver_version[]="2.1.15-k1";
 const char *e100_full_driver_name = "Intel(R) PRO/100 Network Driver";
 char e100_short_driver_name[] = "e100";
 static int e100nics = 0;
@@ -397,7 +364,7 @@
 
 MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
 MODULE_DESCRIPTION("Intel(R) PRO/100 Network Driver");
-MODULE_LICENSE("Dual BSD/GPL");
+MODULE_LICENSE("GPL");
 
 E100_PARAM(TxDescriptors, "Number of transmit descriptors");
 E100_PARAM(RxDescriptors, "Number of receive descriptors");
@@ -779,16 +746,6 @@
 		bdp->non_tx_command_state = E100_NON_TX_IDLE;
 	}
 
-	/* Set up wol options and enable PME if wol is enabled */
-	if (bdp->wolopts) {
-		e100_do_wol(pcid, bdp);
-		/* Enable PME for power state D3 */
-		pci_enable_wake(pcid, 3, 1);
-		/* Set power state to D1 in case driver is RELOADED */
-		/* If system powers down, device is switched from D1 to D3 */
-		pci_set_power_state(pcid, 1);
-	}
-
 	e100_clear_structs(dev);
 
 	--e100nics;
@@ -1028,7 +985,7 @@
 
 	e100_start_ru(bdp);
 	if ((rc = request_irq(dev->irq, &e100intr, SA_SHIRQ,
-			      e100_short_driver_name, dev)) != 0) {
+			      dev->name, dev)) != 0) {
 		del_timer_sync(&bdp->watchdog_timer);
 		goto err_exit;
 	}
@@ -1059,7 +1016,9 @@
 	bdp->intr_mask = SCB_INT_MASK;
 	e100_isolate_driver(bdp);
 
-	bdp->ip_lbytes = e100_get_ip_lbytes(dev);
+	netif_carrier_off(bdp->device);
+	bdp->cur_line_speed = 0;
+	bdp->cur_dplx_mode = 0;
 	free_irq(dev->irq, dev);
 	e100_clear_pools(bdp);
 
@@ -1243,7 +1202,7 @@
 	if (bdp->driver_isolated) {
 		goto exit;
 	}
-	promisc_enbl = (dev->flags & IFF_PROMISC);
+	promisc_enbl = ((dev->flags & IFF_PROMISC) == IFF_PROMISC);
 	mulcast_enbl = ((dev->flags & IFF_ALLMULTI) ||
 			(dev->mc_count > MAX_MULTICAST_ADDRS));
 
@@ -3343,6 +3302,9 @@
 	case ETHTOOL_GDRVINFO:
 		rc = e100_ethtool_get_drvinfo(dev, ifr);
 		break;
+	case ETHTOOL_GREGS:
+		rc = e100_ethtool_gregs(dev, ifr);
+		break;
 	case ETHTOOL_NWAY_RST:
 		rc = e100_ethtool_nway_rst(dev, ifr);
 		break;
@@ -3390,9 +3352,15 @@
 	ecmd.transceiver = XCVR_INTERNAL;
 	ecmd.phy_address = bdp->phy_addr;
 
-	ecmd.speed = bdp->cur_line_speed;
-	ecmd.duplex =
-		(bdp->cur_dplx_mode == HALF_DUPLEX) ? DUPLEX_HALF : DUPLEX_FULL;
+	if (netif_carrier_ok(bdp->device)) {
+		ecmd.speed = bdp->cur_line_speed;
+		ecmd.duplex =
+			(bdp->cur_dplx_mode == HALF_DUPLEX) ? DUPLEX_HALF : DUPLEX_FULL;
+	}
+	else {
+		ecmd.speed = -1;
+		ecmd.duplex = -1;
+	}
 
 	ecmd.advertising = ADVERTISED_TP;
 
@@ -3514,7 +3482,8 @@
 	bdp = dev->priv;
 	info.cmd = ETHTOOL_GLINK;
 
-	info.data = e100_get_link_state(bdp);
+	/* Consider both PHY link and netif_running */
+	info.data = e100_update_link_state(bdp);
 
 	if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
 		return -EFAULT;
@@ -3551,6 +3520,36 @@
 }
 
 static int
+e100_ethtool_gregs(struct net_device *dev, struct ifreq *ifr)
+{
+	struct e100_private *bdp;
+	u32 regs_buff[E100_REGS_LEN];
+	struct ethtool_regs regs = {ETHTOOL_GREGS};
+	void *addr = ifr->ifr_data;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+	bdp = dev->priv;
+
+	if(copy_from_user(&regs, addr, sizeof(regs)))
+		return -EFAULT;
+
+	regs.version = (1 << 24) | bdp->rev_id;
+	regs_buff[0] = readb(&(bdp->scb->scb_cmd_hi)) << 24 |
+		readb(&(bdp->scb->scb_cmd_low)) << 16 |
+		readw(&(bdp->scb->scb_status));
+
+	if(copy_to_user(addr, &regs, sizeof(regs)))
+		return -EFAULT;
+
+	addr += offsetof(struct ethtool_regs, data);
+	if(copy_to_user(addr, regs_buff, regs.len))
+		return -EFAULT;
+
+	return 0;
+}
+
+static int
 e100_ethtool_nway_rst(struct net_device *dev, struct ifreq *ifr)
 {
 	struct e100_private *bdp;
@@ -3581,10 +3580,11 @@
 
 	strncpy(info.driver, e100_short_driver_name, sizeof (info.driver) - 1);
 	strncpy(info.version, e100_driver_version, sizeof (info.version) - 1);
-	strncpy(info.fw_version, e100_get_brand_msg(bdp),
+	strncpy(info.fw_version, "N/A",
 		sizeof (info.fw_version) - 1);
 	strncpy(info.bus_info, bdp->pdev->slot_name,
 		sizeof (info.bus_info) - 1);
+	info.regdump_len  = E100_REGS_LEN * sizeof(u32);
 	info.eedump_len = (bdp->eeprom_size << 1);	
 	info.testinfo_len = E100_MAX_TEST_RES;
 	if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
@@ -3896,7 +3896,6 @@
 		if (copy_to_user(ifr->ifr_data, &wolinfo, sizeof (wolinfo)))
 			res = -EFAULT;
 		break;
-
 	case ETHTOOL_SWOL:
 		/* If ALL requests are supported or request is DISABLE wol */
 		if (((wolinfo.wolopts & bdp->wolsupported) == wolinfo.wolopts)
@@ -3905,6 +3904,8 @@
 		} else {
 			res = -EOPNOTSUPP;
 		}
+		if (wolinfo.wolopts & WAKE_ARP)
+			bdp->ip_lbytes = e100_get_ip_lbytes(dev);
 		break;
 	default:
 		break;
@@ -3982,8 +3983,30 @@
 		if (netif_running(dev)) {
 			return -EBUSY;
 		}
-		e100_mdi_write(bdp, data_ptr->reg_num & 0x1f, bdp->phy_addr,
+		/* If reg = 0 && change speed/duplex */
+		if (data_ptr->reg_num == 0 && 
+			(data_ptr->val_in == (BMCR_ANENABLE | BMCR_ANRESTART) /* restart cmd */
+			|| data_ptr->val_in == (BMCR_RESET) /* reset cmd */ 
+			|| data_ptr->val_in & (BMCR_SPEED100 | BMCR_FULLDPLX) 
+			|| data_ptr->val_in == 0)) {
+				if (data_ptr->val_in == (BMCR_ANENABLE | BMCR_ANRESTART)
+					|| data_ptr->val_in == (BMCR_RESET))
+					bdp->params.e100_speed_duplex = E100_AUTONEG;
+				else if (data_ptr->val_in == (BMCR_SPEED100 | BMCR_FULLDPLX))
+					bdp->params.e100_speed_duplex = E100_SPEED_100_FULL;
+				else if (data_ptr->val_in == (BMCR_SPEED100))
+					bdp->params.e100_speed_duplex = E100_SPEED_100_HALF;
+				else if (data_ptr->val_in == (BMCR_FULLDPLX))
+					bdp->params.e100_speed_duplex = E100_SPEED_10_FULL;
+				else
+					bdp->params.e100_speed_duplex = E100_SPEED_10_HALF;
+				e100_set_speed_duplex(bdp);
+		}
+		else {
+			e100_mdi_write(bdp, data_ptr->reg_num, bdp->phy_addr,
 			       data_ptr->val_in);
+		}
+		
 		break;
 
 	default:
@@ -4154,6 +4177,7 @@
 e100_notify_reboot(struct notifier_block *nb, unsigned long event, void *p)
 {
         struct pci_dev *pdev = NULL;
+	
         switch(event) {
         case SYS_DOWN:
         case SYS_HALT:
@@ -4163,7 +4187,8 @@
 				/* If net_device struct is allocated? */
                                 if (pci_get_drvdata(pdev))
 					e100_suspend(pdev, 3);
-                	}
+
+			}
 		}
         }
         return NOTIFY_DONE;
@@ -4180,7 +4205,6 @@
 
 	/* If wol is enabled */
 	if (bdp->wolopts) {
-		bdp->ip_lbytes = e100_get_ip_lbytes(netdev);
 		e100_do_wol(pcid, bdp);
 		pci_enable_wake(pcid, 3, 1);	/* Enable PME for power state D3 */
 		pci_set_power_state(pcid, 3);	/* Set power state to D3.        */
@@ -4189,7 +4213,6 @@
 		pci_disable_device(pcid);
 		pci_set_power_state(pcid, state);
 	}
-
 	return 0;
 }
 
@@ -4217,7 +4240,6 @@
 
 	return 0;
 }
-
 #endif /* CONFIG_PM */
 
 static void
diff -urN linux-2.4.20-pre4/drivers/net/e100/e100_phy.c linux-2.4.20-pre5/drivers/net/e100/e100_phy.c
--- linux-2.4.20-pre4/drivers/net/e100/e100_phy.c	Wed Aug 28 16:36:54 2002
+++ linux-2.4.20-pre5/drivers/net/e100/e100_phy.c	Wed Aug 28 16:38:03 2002
@@ -1,73 +1,28 @@
 /*******************************************************************************
 
-This software program is available to you under a choice of one of two 
-licenses. You may choose to be licensed under either the GNU General Public 
-License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html, 
-or the Intel BSD + Patent License, the text of which follows:
-
-Recipient has requested a license and Intel Corporation ("Intel") is willing
-to grant a license for the software entitled Linux Base Driver for the 
-Intel(R) PRO/100 Family of Adapters (e100) (the "Software") being provided 
-by Intel Corporation. The following definitions apply to this license:
-
-"Licensed Patents" means patent claims licensable by Intel Corporation which 
-are necessarily infringed by the use of sale of the Software alone or when 
-combined with the operating system referred to below.
-
-"Recipient" means the party to whom Intel delivers this Software.
-
-"Licensee" means Recipient and those third parties that receive a license to 
-any operating system available under the GNU General Public License 2.0 or 
-later.
-
-Copyright (c) 1999 - 2002 Intel Corporation.
-All rights reserved.
-
-The license is provided to Recipient and Recipient's Licensees under the 
-following terms.
-
-Redistribution and use in source and binary forms of the Software, with or 
-without modification, are permitted provided that the following conditions 
-are met:
-
-Redistributions of source code of the Software may retain the above 
-copyright notice, this list of conditions and the following disclaimer.
-
-Redistributions in binary form of the Software may reproduce the above 
-copyright notice, this list of conditions and the following disclaimer in 
-the documentation and/or materials provided with the distribution.
-
-Neither the name of Intel Corporation nor the names of its contributors 
-shall be used to endorse or promote products derived from this Software 
-without specific prior written permission.
-
-Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, 
-royalty-free patent license under Licensed Patents to make, use, sell, offer 
-to sell, import and otherwise transfer the Software, if any, in source code 
-and object code form. This license shall include changes to the Software 
-that are error corrections or other minor changes to the Software that do 
-not add functionality or features when the Software is incorporated in any 
-version of an operating system that has been distributed under the GNU 
-General Public License 2.0 or later. This patent license shall apply to the 
-combination of the Software and any operating system licensed under the GNU 
-General Public License 2.0 or later if, at the time Intel provides the 
-Software to Recipient, such addition of the Software to the then publicly 
-available versions of such operating systems available under the GNU General 
-Public License 2.0 or later (whether in gold, beta or alpha form) causes 
-such combination to be covered by the Licensed Patents. The patent license 
-shall not apply to any other combinations which include the Software. NO 
-hardware per se is licensed hereunder.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
-IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
-ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY 
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
-(INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
-ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED 
-AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR 
-TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  
+  This program is free software; you can redistribute it and/or modify it 
+  under the terms of the GNU General Public License as published by the Free 
+  Software Foundation; either version 2 of the License, or (at your option) 
+  any later version.
+  
+  This program is distributed in the hope that it will be useful, but WITHOUT 
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
+  more details.
+  
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59 
+  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 *******************************************************************************/
 
 #include "e100_phy.h"
@@ -90,11 +45,12 @@
  * Returns:
  *	NOTHING
  */
-void
+int
 e100_mdi_write(struct e100_private *bdp, u32 reg_addr, u32 phy_addr, u16 data)
 {
 	int e100_retry;
 	u32 temp_val;
+	unsigned int mdi_cntrl;
 
 	spin_lock_bh(&bdp->mdi_access_lock);
 	temp_val = (((u32) data) | (reg_addr << 16) |
@@ -107,13 +63,18 @@
 
 	/* poll for the mdi write to complete */
 	e100_retry = E100_CMD_WAIT;
-	while ((!(readl(&bdp->scb->scb_mdi_cntrl) & MDI_PHY_READY)) &&
-	       (e100_retry)) {
+	while ((!((mdi_cntrl = readl(&bdp->scb->scb_mdi_cntrl)) & MDI_PHY_READY)) && (e100_retry)) {
 
 		udelay(20);
 		e100_retry--;
 	}
 	spin_unlock_bh(&bdp->mdi_access_lock);
+	if (mdi_cntrl & MDI_PHY_READY) 
+		return 0;
+	else {
+		printk(KERN_ERR "e100: MDI write timeout\n");
+		return 1;
+	}
 }
 
 /* 
@@ -135,11 +96,12 @@
  * Returns:
  *	NOTHING
  */
-void
+int
 e100_mdi_read(struct e100_private *bdp, u32 reg_addr, u32 phy_addr, u16 *data)
 {
 	int e100_retry;
 	u32 temp_val;
+	unsigned int mdi_cntrl;
 
 	spin_lock_bh(&bdp->mdi_access_lock);
 	/* Issue the read command to the MDI control register. */
@@ -152,16 +114,22 @@
 
 	/* poll for the mdi read to complete */
 	e100_retry = E100_CMD_WAIT;
-	while ((!(readl(&bdp->scb->scb_mdi_cntrl) & MDI_PHY_READY)) &&
-	       (e100_retry)) {
+	while ((!((mdi_cntrl = readl(&bdp->scb->scb_mdi_cntrl)) & MDI_PHY_READY)) && (e100_retry)) {
 
 		udelay(20);
 		e100_retry--;
 	}
 
-	// return the lower word
-	*data = (u16) readl(&bdp->scb->scb_mdi_cntrl);
 	spin_unlock_bh(&bdp->mdi_access_lock);
+	if (mdi_cntrl & MDI_PHY_READY) {
+		/* return the lower word */
+		*data = (u16) mdi_cntrl;
+		return 0;
+	}
+	else {
+		printk(KERN_ERR "e100: MDI read timeout\n");
+		return 1;
+	}
 }
 
 static unsigned char __devinit
@@ -525,10 +493,8 @@
 	/* First we should check to see if we have link */
 	/* If we don't have a link no reason to print a speed and duplex */
 	if (!e100_update_link_state(bdp)) {
-		return;
-	}
-
-	if (bdp->flags & DF_SPEED_FORCED) {
+		bdp->cur_line_speed = 0;
+		bdp->cur_dplx_mode = 0;
 		return;
 	}
 
@@ -662,10 +628,13 @@
 	u16 control;
 	unsigned long expires;
 
+	e100_phy_reset(bdp);
+
 	bdp->flags |= DF_SPEED_FORCED;
 
 	e100_mdi_read(bdp, MII_BMCR, bdp->phy_addr, &control);
 	control &= ~BMCR_ANENABLE;
+	control &= ~BMCR_LOOPBACK;
 
 	/* Check e100.c values */
 	switch (bdp->params.e100_speed_duplex) {
@@ -883,7 +852,7 @@
 }
 
 void
-e100_phy_reset(struct e100_private *bdp)
+e100_phy_autoneg(struct e100_private *bdp)
 {
 	u16 ctrl_reg;
 
@@ -894,6 +863,23 @@
 	udelay(100);
 }
 
+void
+e100_phy_set_loopback(struct e100_private *bdp)
+{
+	u16 ctrl_reg;
+	ctrl_reg = BMCR_LOOPBACK;
+	e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg);
+		udelay(100);
+}
+	
+void
+e100_phy_reset(struct e100_private *bdp)
+{
+	u16 ctrl_reg;
+	ctrl_reg = BMCR_RESET;
+	e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg);
+}
+
 unsigned char __devinit
 e100_phy_init(struct e100_private *bdp)
 {
@@ -960,7 +946,8 @@
 /* 
  * Procedure: e100_update_link_state
  * 
- * Description: This routine updates the link status of the adapter
+ * Description: This routine updates the link status of the adapter,
+ * 		also considering netif_running
  *
  * Arguments:  bdp - Pointer to the e100_private structure for the board
  *		    
@@ -974,7 +961,8 @@
 {
 	unsigned char link;
 
-	link = e100_get_link_state(bdp);
+	/* Logical AND PHY link & netif_running */
+	link = e100_get_link_state(bdp) && netif_running(bdp->device);
 
 	if (link) {
 		if (!netif_carrier_ok(bdp->device))
diff -urN linux-2.4.20-pre4/drivers/net/e100/e100_phy.h linux-2.4.20-pre5/drivers/net/e100/e100_phy.h
--- linux-2.4.20-pre4/drivers/net/e100/e100_phy.h	Wed Aug 28 16:36:54 2002
+++ linux-2.4.20-pre5/drivers/net/e100/e100_phy.h	Wed Aug 28 16:38:03 2002
@@ -1,73 +1,28 @@
 /*******************************************************************************
 
-This software program is available to you under a choice of one of two 
-licenses. You may choose to be licensed under either the GNU General Public 
-License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html, 
-or the Intel BSD + Patent License, the text of which follows:
-
-Recipient has requested a license and Intel Corporation ("Intel") is willing
-to grant a license for the software entitled Linux Base Driver for the 
-Intel(R) PRO/100 Family of Adapters (e100) (the "Software") being provided 
-by Intel Corporation. The following definitions apply to this license:
-
-"Licensed Patents" means patent claims licensable by Intel Corporation which 
-are necessarily infringed by the use of sale of the Software alone or when 
-combined with the operating system referred to below.
-
-"Recipient" means the party to whom Intel delivers this Software.
-
-"Licensee" means Recipient and those third parties that receive a license to 
-any operating system available under the GNU General Public License 2.0 or 
-later.
-
-Copyright (c) 1999 - 2002 Intel Corporation.
-All rights reserved.
-
-The license is provided to Recipient and Recipient's Licensees under the 
-following terms.
-
-Redistribution and use in source and binary forms of the Software, with or 
-without modification, are permitted provided that the following conditions 
-are met:
-
-Redistributions of source code of the Software may retain the above 
-copyright notice, this list of conditions and the following disclaimer.
-
-Redistributions in binary form of the Software may reproduce the above 
-copyright notice, this list of conditions and the following disclaimer in 
-the documentation and/or materials provided with the distribution.
-
-Neither the name of Intel Corporation nor the names of its contributors 
-shall be used to endorse or promote products derived from this Software 
-without specific prior written permission.
-
-Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, 
-royalty-free patent license under Licensed Patents to make, use, sell, offer 
-to sell, import and otherwise transfer the Software, if any, in source code 
-and object code form. This license shall include changes to the Software 
-that are error corrections or other minor changes to the Software that do 
-not add functionality or features when the Software is incorporated in any 
-version of an operating system that has been distributed under the GNU 
-General Public License 2.0 or later. This patent license shall apply to the 
-combination of the Software and any operating system licensed under the GNU 
-General Public License 2.0 or later if, at the time Intel provides the 
-Software to Recipient, such addition of the Software to the then publicly 
-available versions of such operating systems available under the GNU General 
-Public License 2.0 or later (whether in gold, beta or alpha form) causes 
-such combination to be covered by the Licensed Patents. The patent license 
-shall not apply to any other combinations which include the Software. NO 
-hardware per se is licensed hereunder.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
-IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
-ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY 
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
-(INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
-ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED 
-AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR 
-TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  
+  This program is free software; you can redistribute it and/or modify it 
+  under the terms of the GNU General Public License as published by the Free 
+  Software Foundation; either version 2 of the License, or (at your option) 
+  any later version.
+  
+  This program is distributed in the hope that it will be useful, but WITHOUT 
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
+  more details.
+  
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59 
+  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 *******************************************************************************/
 
 #ifndef _E100_PHY_INC_
@@ -196,8 +151,10 @@
 extern unsigned char e100_phy_check(struct e100_private *bdp);
 extern void e100_phy_set_speed_duplex(struct e100_private *bdp,
 				      unsigned char force_restart);
+extern void e100_phy_autoneg(struct e100_private *bdp);
 extern void e100_phy_reset(struct e100_private *bdp);
-extern void e100_mdi_write(struct e100_private *, u32, u32, u16);
-extern void e100_mdi_read(struct e100_private *, u32, u32, u16 *);
+extern void e100_phy_set_loopback(struct e100_private *bdp);
+extern int e100_mdi_write(struct e100_private *, u32, u32, u16);
+extern int e100_mdi_read(struct e100_private *, u32, u32, u16 *);
 
 #endif
diff -urN linux-2.4.20-pre4/drivers/net/e100/e100_proc.c linux-2.4.20-pre5/drivers/net/e100/e100_proc.c
--- linux-2.4.20-pre4/drivers/net/e100/e100_proc.c	Wed Aug 28 16:36:54 2002
+++ linux-2.4.20-pre5/drivers/net/e100/e100_proc.c	Wed Aug 28 16:38:03 2002
@@ -1,73 +1,28 @@
 /*******************************************************************************
 
-This software program is available to you under a choice of one of two 
-licenses. You may choose to be licensed under either the GNU General Public 
-License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html, 
-or the Intel BSD + Patent License, the text of which follows:
-
-Recipient has requested a license and Intel Corporation ("Intel") is willing
-to grant a license for the software entitled Linux Base Driver for the 
-Intel(R) PRO/100 Family of Adapters (e100) (the "Software") being provided 
-by Intel Corporation. The following definitions apply to this license:
-
-"Licensed Patents" means patent claims licensable by Intel Corporation which 
-are necessarily infringed by the use of sale of the Software alone or when 
-combined with the operating system referred to below.
-
-"Recipient" means the party to whom Intel delivers this Software.
-
-"Licensee" means Recipient and those third parties that receive a license to 
-any operating system available under the GNU General Public License 2.0 or 
-later.
-
-Copyright (c) 1999 - 2002 Intel Corporation.
-All rights reserved.
-
-The license is provided to Recipient and Recipient's Licensees under the 
-following terms.
-
-Redistribution and use in source and binary forms of the Software, with or 
-without modification, are permitted provided that the following conditions 
-are met:
-
-Redistributions of source code of the Software may retain the above 
-copyright notice, this list of conditions and the following disclaimer.
-
-Redistributions in binary form of the Software may reproduce the above 
-copyright notice, this list of conditions and the following disclaimer in 
-the documentation and/or materials provided with the distribution.
-
-Neither the name of Intel Corporation nor the names of its contributors 
-shall be used to endorse or promote products derived from this Software 
-without specific prior written permission.
-
-Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, 
-royalty-free patent license under Licensed Patents to make, use, sell, offer 
-to sell, import and otherwise transfer the Software, if any, in source code 
-and object code form. This license shall include changes to the Software 
-that are error corrections or other minor changes to the Software that do 
-not add functionality or features when the Software is incorporated in any 
-version of an operating system that has been distributed under the GNU 
-General Public License 2.0 or later. This patent license shall apply to the 
-combination of the Software and any operating system licensed under the GNU 
-General Public License 2.0 or later if, at the time Intel provides the 
-Software to Recipient, such addition of the Software to the then publicly 
-available versions of such operating systems available under the GNU General 
-Public License 2.0 or later (whether in gold, beta or alpha form) causes 
-such combination to be covered by the Licensed Patents. The patent license 
-shall not apply to any other combinations which include the Software. NO 
-hardware per se is licensed hereunder.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
-IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
-ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY 
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
-(INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
-ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED 
-AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR 
-TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  
+  This program is free software; you can redistribute it and/or modify it 
+  under the terms of the GNU General Public License as published by the Free 
+  Software Foundation; either version 2 of the License, or (at your option) 
+  any later version.
+  
+  This program is distributed in the hope that it will be useful, but WITHOUT 
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
+  more details.
+  
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59 
+  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 *******************************************************************************/
 
 /**********************************************************************
@@ -106,7 +61,7 @@
 extern char e100_driver_version[];
 extern struct net_device_stats *e100_get_stats(struct net_device *dev);
 extern char *e100_get_brand_msg(struct e100_private *bdp);
-extern void e100_mdi_write(struct e100_private *, u32, u32, u16);
+extern int e100_mdi_write(struct e100_private *, u32, u32, u16);
 
 static void e100_proc_cleanup(void);
 static unsigned char e100_init_proc_dir(void);
diff -urN linux-2.4.20-pre4/drivers/net/e100/e100_test.c linux-2.4.20-pre5/drivers/net/e100/e100_test.c
--- linux-2.4.20-pre4/drivers/net/e100/e100_test.c	Wed Aug 28 16:36:54 2002
+++ linux-2.4.20-pre5/drivers/net/e100/e100_test.c	Wed Aug 28 16:38:03 2002
@@ -1,73 +1,28 @@
 /*******************************************************************************
 
-This software program is available to you under a choice of one of two 
-licenses. You may choose to be licensed under either the GNU General Public 
-License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html, 
-or the Intel BSD + Patent License, the text of which follows:
-
-Recipient has requested a license and Intel Corporation ("Intel") is willing
-to grant a license for the software entitled Linux Base Driver for the 
-Intel(R) PRO/100 Family of Adapters (e100) (the "Software") being provided 
-by Intel Corporation. The following definitions apply to this license:
-
-"Licensed Patents" means patent claims licensable by Intel Corporation which 
-are necessarily infringed by the use of sale of the Software alone or when 
-combined with the operating system referred to below.
-
-"Recipient" means the party to whom Intel delivers this Software.
-
-"Licensee" means Recipient and those third parties that receive a license to 
-any operating system available under the GNU General Public License 2.0 or 
-later.
-
-Copyright (c) 1999 - 2002 Intel Corporation.
-All rights reserved.
-
-The license is provided to Recipient and Recipient's Licensees under the 
-following terms.
-
-Redistribution and use in source and binary forms of the Software, with or 
-without modification, are permitted provided that the following conditions 
-are met:
-
-Redistributions of source code of the Software may retain the above 
-copyright notice, this list of conditions and the following disclaimer.
-
-Redistributions in binary form of the Software may reproduce the above 
-copyright notice, this list of conditions and the following disclaimer in 
-the documentation and/or materials provided with the distribution.
-
-Neither the name of Intel Corporation nor the names of its contributors 
-shall be used to endorse or promote products derived from this Software 
-without specific prior written permission.
-
-Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, 
-royalty-free patent license under Licensed Patents to make, use, sell, offer 
-to sell, import and otherwise transfer the Software, if any, in source code 
-and object code form. This license shall include changes to the Software 
-that are error corrections or other minor changes to the Software that do 
-not add functionality or features when the Software is incorporated in any 
-version of an operating system that has been distributed under the GNU 
-General Public License 2.0 or later. This patent license shall apply to the 
-combination of the Software and any operating system licensed under the GNU 
-General Public License 2.0 or later if, at the time Intel provides the 
-Software to Recipient, such addition of the Software to the then publicly 
-available versions of such operating systems available under the GNU General 
-Public License 2.0 or later (whether in gold, beta or alpha form) causes 
-such combination to be covered by the Licensed Patents. The patent license 
-shall not apply to any other combinations which include the Software. NO 
-hardware per se is licensed hereunder.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
-IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
-ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY 
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
-(INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
-ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED 
-AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR 
-TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  
+  This program is free software; you can redistribute it and/or modify it 
+  under the terms of the GNU General Public License as published by the Free 
+  Software Foundation; either version 2 of the License, or (at your option) 
+  any later version.
+  
+  This program is distributed in the hope that it will be useful, but WITHOUT 
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
+  more details.
+  
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59 
+  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 *******************************************************************************/
 
 #include "e100.h"
@@ -76,6 +31,9 @@
 extern u16 e100_eeprom_read(struct e100_private *, u16);
 extern int e100_wait_exec_cmplx(struct e100_private *, u32,u8);
 extern void e100_phy_reset(struct e100_private *bdp);
+extern void e100_phy_autoneg(struct e100_private *bdp);
+extern void e100_phy_set_loopback(struct e100_private *bdp);
+extern void e100_force_speed_duplex(struct e100_private *bdp);
 
 static u8 e100_diag_selftest(struct net_device *);
 static u8 e100_diag_eeprom(struct net_device *);
@@ -284,6 +242,7 @@
 		 *dynamic_tbd = e100_config_dynamic_tbd(bdp,*dynamic_tbd);
 
 	if (set_loopback) {
+		/* Configure loopback on MAC */
 		e100_config_loopback_mode(bdp,loopback_mode);
 	} else {
 		e100_config_loopback_mode(bdp,NO_LOOPBACK);
@@ -292,16 +251,20 @@
 	e100_config(bdp);
 
 	if (loopback_mode == PHY_LOOPBACK) {
-		unsigned long expires = jiffies + HZ * 5;
-
 		if (set_loopback)
-			e100_phy_reset(bdp);
-
-		/* wait up to 5 secs for PHY loopback ON/OFF to take effect */
-		while ((e100_get_link_state(bdp) != set_loopback) &&
-		       time_before(jiffies, expires)) {
-			yield();
+                        /* Set PHY loopback mode */
+                        e100_phy_set_loopback(bdp);
+                else {	/* Back to normal speed and duplex */
+                	if (bdp->params.e100_speed_duplex == E100_AUTONEG)
+				/* Reset PHY and do autoneg */
+                        	e100_phy_autoneg(bdp);
+			else    
+				/* Reset PHY and force speed and duplex */
+				e100_force_speed_duplex(bdp);
 		}
+                /* Wait for PHY state change */
+		set_current_state(TASK_UNINTERRUPTIBLE);
+                schedule_timeout(HZ);
 	} else { /* For MAC loopback wait 500 msec to take effect */
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		schedule_timeout(HZ / 2);
@@ -321,6 +284,7 @@
 	rfd_t *rfd;
 	tbd_t *tbd;
 
+	/* tcb, tbd and transmit buffer are allocated */
 	tcb = pci_alloc_consistent(bdp->pdev,
 				   (sizeof (tcb_t) + sizeof (tbd_t) +
 				    LB_PACKET_SIZE),
@@ -328,22 +292,26 @@
         if (tcb == NULL)
 		return false;
 
-	memset(tcb, 0x00, sizeof (tcb_t) + LB_PACKET_SIZE);
+	memset(tcb, 0x00, sizeof (tcb_t) + sizeof (tbd_t) + LB_PACKET_SIZE);
 	tcb->tcb_phys = dma_handle;
 	tcb->tcb_hdr.cb_status = 0;
 	tcb->tcb_hdr.cb_cmd =
 		cpu_to_le16(CB_EL_BIT | CB_TRANSMIT | CB_TX_SF_BIT);
-	tcb->tcb_hdr.cb_lnk_ptr = cpu_to_le32(tcb->tcb_phys);
-	tcb->tcb_tbd_ptr = cpu_to_le32(0xffffffff);
+	/* Next command is null */
+	tcb->tcb_hdr.cb_lnk_ptr = cpu_to_le32(0xffffffff);
 	tcb->tcb_cnt = 0;
 	tcb->tcb_thrshld = bdp->tx_thld;
 	tcb->tcb_tbd_num = 1;
+	/* Set up tcb tbd pointer */
 	tcb->tcb_tbd_ptr = cpu_to_le32(tcb->tcb_phys + sizeof (tcb_t));
 	tbd = (tbd_t *) ((u8 *) tcb + sizeof (tcb_t));
+	/* Set up tbd transmit buffer */
 	tbd->tbd_buf_addr =
 		cpu_to_le32(le32_to_cpu(tcb->tcb_tbd_ptr) + sizeof (tbd_t));
 	tbd->tbd_buf_cnt = __constant_cpu_to_le16(1024);
-	memset((void *) ((u8 *) tbd + sizeof (tbd_t)), 0xFF, 1024);
+	/* The value of first 512 bytes is FF */
+	memset((void *) ((u8 *) tbd + sizeof (tbd_t)), 0xFF, 512);
+	/* The value of second 512 bytes is BA */
 	memset((void *) ((u8 *) tbd + sizeof (tbd_t) + 512), 0xBA, 512);
 	wmb();
 	rfd = pci_alloc_consistent(bdp->pdev, sizeof (rfd_t), &dma_handle);
@@ -358,10 +326,9 @@
 	memset(rfd, 0x00, sizeof (rfd_t));
 
 	/* init all fields in rfd */
-	rfd->rfd_header.cb_status = 0;
 	rfd->rfd_header.cb_cmd = cpu_to_le16(RFD_EL_BIT);
-	rfd->rfd_act_cnt = 0;
 	rfd->rfd_sz = cpu_to_le16(ETH_FRAME_LEN + CHKSUM_SIZE);
+	/* dma_handle is physical address of rfd */
 	bdp->loopback.dma_handle = dma_handle;
 	bdp->loopback.tcb = tcb;
 	bdp->loopback.rfd = rfd;
@@ -399,12 +366,15 @@
 static u8
 e100_diag_check_pkt(u8 *datap)
 {
-        if( (*datap)==0xFF) {
-                if(*(datap + 600) == 0xBA) {
-                        return true;
-                }
-        }
-        return false;
+	int i;
+	for (i = 0; i<512; i++) {
+		if( !((*datap)==0xFF && (*(datap + 512) == 0xBA)) ) {
+			printk (KERN_ERR "e100: check loopback packet failed at: %x\n", i);
+			return false;
+			}
+	}
+	printk (KERN_DEBUG "e100: Check received loopback packet OK\n");
+	return true;
 }
 
 /**
@@ -434,10 +404,14 @@
 		}
         }
 
-        if (rfd_status & RFD_STATUS_COMPLETE)
+        if (rfd_status & RFD_STATUS_COMPLETE) {
+		printk(KERN_DEBUG "e100: Loopback packet received\n");
                 return e100_diag_check_pkt(((u8 *)rfdp+bdp->rfd_size));
-	else
+	}
+	else {
+		printk(KERN_ERR "e100: Loopback packet not received\n");
 		return false;
+	}
 }
 
 /**
diff -urN linux-2.4.20-pre4/drivers/net/e100/e100_ucode.h linux-2.4.20-pre5/drivers/net/e100/e100_ucode.h
--- linux-2.4.20-pre4/drivers/net/e100/e100_ucode.h	Wed Aug 28 16:36:54 2002
+++ linux-2.4.20-pre5/drivers/net/e100/e100_ucode.h	Wed Aug 28 16:38:03 2002
@@ -1,73 +1,28 @@
 /*******************************************************************************
 
-This software program is available to you under a choice of one of two 
-licenses. You may choose to be licensed under either the GNU General Public 
-License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html, 
-or the Intel BSD + Patent License, the text of which follows:
-
-Recipient has requested a license and Intel Corporation ("Intel") is willing
-to grant a license for the software entitled Linux Base Driver for the 
-Intel(R) PRO/100 Family of Adapters (e100) (the "Software") being provided 
-by Intel Corporation. The following definitions apply to this license:
-
-"Licensed Patents" means patent claims licensable by Intel Corporation which 
-are necessarily infringed by the use of sale of the Software alone or when 
-combined with the operating system referred to below.
-
-"Recipient" means the party to whom Intel delivers this Software.
-
-"Licensee" means Recipient and those third parties that receive a license to 
-any operating system available under the GNU General Public License 2.0 or 
-later.
-
-Copyright (c) 1999 - 2002 Intel Corporation.
-All rights reserved.
-
-The license is provided to Recipient and Recipient's Licensees under the 
-following terms.
-
-Redistribution and use in source and binary forms of the Software, with or 
-without modification, are permitted provided that the following conditions 
-are met:
-
-Redistributions of source code of the Software may retain the above 
-copyright notice, this list of conditions and the following disclaimer.
-
-Redistributions in binary form of the Software may reproduce the above 
-copyright notice, this list of conditions and the following disclaimer in 
-the documentation and/or materials provided with the distribution.
-
-Neither the name of Intel Corporation nor the names of its contributors 
-shall be used to endorse or promote products derived from this Software 
-without specific prior written permission.
-
-Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, 
-royalty-free patent license under Licensed Patents to make, use, sell, offer 
-to sell, import and otherwise transfer the Software, if any, in source code 
-and object code form. This license shall include changes to the Software 
-that are error corrections or other minor changes to the Software that do 
-not add functionality or features when the Software is incorporated in any 
-version of an operating system that has been distributed under the GNU 
-General Public License 2.0 or later. This patent license shall apply to the 
-combination of the Software and any operating system licensed under the GNU 
-General Public License 2.0 or later if, at the time Intel provides the 
-Software to Recipient, such addition of the Software to the then publicly 
-available versions of such operating systems available under the GNU General 
-Public License 2.0 or later (whether in gold, beta or alpha form) causes 
-such combination to be covered by the Licensed Patents. The patent license 
-shall not apply to any other combinations which include the Software. NO 
-hardware per se is licensed hereunder.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
-IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
-ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY 
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
-(INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
-ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED 
-AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR 
-TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  
+  This program is free software; you can redistribute it and/or modify it 
+  under the terms of the GNU General Public License as published by the Free 
+  Software Foundation; either version 2 of the License, or (at your option) 
+  any later version.
+  
+  This program is distributed in the hope that it will be useful, but WITHOUT 
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
+  more details.
+  
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59 
+  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 *******************************************************************************/
 
 #ifndef _E100_UCODE_H_
diff -urN linux-2.4.20-pre4/drivers/net/e100/e100_vendor.h linux-2.4.20-pre5/drivers/net/e100/e100_vendor.h
--- linux-2.4.20-pre4/drivers/net/e100/e100_vendor.h	Wed Aug 28 16:36:54 2002
+++ linux-2.4.20-pre5/drivers/net/e100/e100_vendor.h	Wed Aug 28 16:38:03 2002
@@ -1,73 +1,28 @@
 /*******************************************************************************
 
-This software program is available to you under a choice of one of two 
-licenses. You may choose to be licensed under either the GNU General Public 
-License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html, 
-or the Intel BSD + Patent License, the text of which follows:
-
-Recipient has requested a license and Intel Corporation ("Intel") is willing
-to grant a license for the software entitled Linux Base Driver for the 
-Intel(R) PRO/100 Family of Adapters (e100) (the "Software") being provided 
-by Intel Corporation. The following definitions apply to this license:
-
-"Licensed Patents" means patent claims licensable by Intel Corporation which 
-are necessarily infringed by the use of sale of the Software alone or when 
-combined with the operating system referred to below.
-
-"Recipient" means the party to whom Intel delivers this Software.
-
-"Licensee" means Recipient and those third parties that receive a license to 
-any operating system available under the GNU General Public License 2.0 or 
-later.
-
-Copyright (c) 1999 - 2002 Intel Corporation.
-All rights reserved.
-
-The license is provided to Recipient and Recipient's Licensees under the 
-following terms.
-
-Redistribution and use in source and binary forms of the Software, with or 
-without modification, are permitted provided that the following conditions 
-are met:
-
-Redistributions of source code of the Software may retain the above 
-copyright notice, this list of conditions and the following disclaimer.
-
-Redistributions in binary form of the Software may reproduce the above 
-copyright notice, this list of conditions and the following disclaimer in 
-the documentation and/or materials provided with the distribution.
-
-Neither the name of Intel Corporation nor the names of its contributors 
-shall be used to endorse or promote products derived from this Software 
-without specific prior written permission.
-
-Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, 
-royalty-free patent license under Licensed Patents to make, use, sell, offer 
-to sell, import and otherwise transfer the Software, if any, in source code 
-and object code form. This license shall include changes to the Software 
-that are error corrections or other minor changes to the Software that do 
-not add functionality or features when the Software is incorporated in any 
-version of an operating system that has been distributed under the GNU 
-General Public License 2.0 or later. This patent license shall apply to the 
-combination of the Software and any operating system licensed under the GNU 
-General Public License 2.0 or later if, at the time Intel provides the 
-Software to Recipient, such addition of the Software to the then publicly 
-available versions of such operating systems available under the GNU General 
-Public License 2.0 or later (whether in gold, beta or alpha form) causes 
-such combination to be covered by the Licensed Patents. The patent license 
-shall not apply to any other combinations which include the Software. NO 
-hardware per se is licensed hereunder.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
-IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
-ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY 
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
-(INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
-ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED 
-AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR 
-TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  
+  This program is free software; you can redistribute it and/or modify it 
+  under the terms of the GNU General Public License as published by the Free 
+  Software Foundation; either version 2 of the License, or (at your option) 
+  any later version.
+  
+  This program is distributed in the hope that it will be useful, but WITHOUT 
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
+  more details.
+  
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59 
+  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 *******************************************************************************/
 
 #ifndef E100_VENDOR_ID_INFO
diff -urN linux-2.4.20-pre4/drivers/net/e1000/LICENSE linux-2.4.20-pre5/drivers/net/e1000/LICENSE
--- linux-2.4.20-pre4/drivers/net/e1000/LICENSE	Wed Aug 28 16:36:54 2002
+++ linux-2.4.20-pre5/drivers/net/e1000/LICENSE	Wed Aug 28 16:38:03 2002
@@ -1,68 +1,339 @@
-This software program is available to you under a choice of one of two
-licenses. You may choose to be licensed under either the GNU General Public
-License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html,
-or the Intel BSD + Patent License, the text of which follows:
-
-Recipient has requested a license and Intel Corporation ("Intel") is willing
-to grant a license for the software entitled Linux Base Driver for the
-Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided
-by Intel Corporation. The following definitions apply to this license:
-
-"Licensed Patents" means patent claims licensable by Intel Corporation which
-are necessarily infringed by the use of sale of the Software alone or when
-combined with the operating system referred to below.
-
-"Recipient" means the party to whom Intel delivers this Software.
-
-"Licensee" means Recipient and those third parties that receive a license to
-any operating system available under the GNU General Public License 2.0 or
-later.
-
-Copyright (c) 1999 - 2002 Intel Corporation.
-All rights reserved.
-
-The license is provided to Recipient and Recipient's Licensees under the
-following terms.
-
-Redistribution and use in source and binary forms of the Software, with or
-without modification, are permitted provided that the following conditions
-are met:
-
-Redistributions of source code of the Software may retain the above
-copyright notice, this list of conditions and the following disclaimer.
-
-Redistributions in binary form of the Software may reproduce the above
-copyright notice, this list of conditions and the following disclaimer in
-the documentation and/or materials provided with the distribution.
-
-Neither the name of Intel Corporation nor the names of its contributors
-shall be used to endorse or promote products derived from this Software
-without specific prior written permission.
-
-Intel hereby grants Recipient and Licensees a non-exclusive, worldwide,
-royalty-free patent license under Licensed Patents to make, use, sell, offer
-to sell, import and otherwise transfer the Software, if any, in source code
-and object code form. This license shall include changes to the Software
-that are error corrections or other minor changes to the Software that do
-not add functionality or features when the Software is incorporated in any
-version of an operating system that has been distributed under the GNU
-General Public License 2.0 or later. This patent license shall apply to the
-combination of the Software and any operating system licensed under the GNU
-General Public License 2.0 or later if, at the time Intel provides the
-Software to Recipient, such addition of the Software to the then publicly
-available versions of such operating systems available under the GNU General
-Public License 2.0 or later (whether in gold, beta or alpha form) causes
-such combination to be covered by the Licensed Patents. The patent license
-shall not apply to any other combinations which include the Software. NO
-hardware per se is licensed hereunder.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED
-AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR
-TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"This software program is licensed subject to the GNU General Public License 
+(GPL). Version 2, June 1991, available at 
+<http://www.fsf.org/copyleft/gpl.html>"
+
+GNU General Public License 
+
+Version 2, June 1991
+
+Copyright (C) 1989, 1991 Free Software Foundation, Inc.  
+59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
+
+Everyone is permitted to copy and distribute verbatim copies of this license
+document, but changing it is not allowed.
+
+Preamble
+
+The licenses for most software are designed to take away your freedom to 
+share and change it. By contrast, the GNU General Public License is intended
+to guarantee your freedom to share and change free software--to make sure 
+the software is free for all its users. This General Public License applies 
+to most of the Free Software Foundation's software and to any other program 
+whose authors commit to using it. (Some other Free Software Foundation 
+software is covered by the GNU Library General Public License instead.) You 
+can apply it to your programs, too.
+
+When we speak of free software, we are referring to freedom, not price. Our
+General Public Licenses are designed to make sure that you have the freedom 
+to distribute copies of free software (and charge for this service if you 
+wish), that you receive source code or can get it if you want it, that you 
+can change the software or use pieces of it in new free programs; and that 
+you know you can do these things.
+
+To protect your rights, we need to make restrictions that forbid anyone to 
+deny you these rights or to ask you to surrender the rights. These 
+restrictions translate to certain responsibilities for you if you distribute
+copies of the software, or if you modify it.
+
+For example, if you distribute copies of such a program, whether gratis or 
+for a fee, you must give the recipients all the rights that you have. You 
+must make sure that they, too, receive or can get the source code. And you 
+must show them these terms so they know their rights.
+ 
+We protect your rights with two steps: (1) copyright the software, and (2) 
+offer you this license which gives you legal permission to copy, distribute 
+and/or modify the software. 
+
+Also, for each author's protection and ours, we want to make certain that 
+everyone understands that there is no warranty for this free software. If 
+the software is modified by someone else and passed on, we want its 
+recipients to know that what they have is not the original, so that any 
+problems introduced by others will not reflect on the original authors' 
+reputations. 
+
+Finally, any free program is threatened constantly by software patents. We 
+wish to avoid the danger that redistributors of a free program will 
+individually obtain patent licenses, in effect making the program 
+proprietary. To prevent this, we have made it clear that any patent must be 
+licensed for everyone's free use or not licensed at all. 
+
+The precise terms and conditions for copying, distribution and modification 
+follow. 
+
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+0. This License applies to any program or other work which contains a notice
+   placed by the copyright holder saying it may be distributed under the 
+   terms of this General Public License. The "Program", below, refers to any
+   such program or work, and a "work based on the Program" means either the 
+   Program or any derivative work under copyright law: that is to say, a 
+   work containing the Program or a portion of it, either verbatim or with 
+   modifications and/or translated into another language. (Hereinafter, 
+   translation is included without limitation in the term "modification".) 
+   Each licensee is addressed as "you". 
+
+   Activities other than copying, distribution and modification are not 
+   covered by this License; they are outside its scope. The act of running 
+   the Program is not restricted, and the output from the Program is covered 
+   only if its contents constitute a work based on the Program (independent 
+   of having been made by running the Program). Whether that is true depends
+   on what the Program does. 
+
+1. You may copy and distribute verbatim copies of the Program's source code 
+   as you receive it, in any medium, provided that you conspicuously and 
+   appropriately publish on each copy an appropriate copyright notice and 
+   disclaimer of warranty; keep intact all the notices that refer to this 
+   License and to the absence of any warranty; and give any other recipients 
+   of the Program a copy of this License along with the Program. 
+
+   You may charge a fee for the physical act of transferring a copy, and you 
+   may at your option offer warranty protection in exchange for a fee. 
+
+2. You may modify your copy or copies of the Program or any portion of it, 
+   thus forming a work based on the Program, and copy and distribute such 
+   modifications or work under the terms of Section 1 above, provided that 
+   you also meet all of these conditions: 
+
+   * a) You must cause the modified files to carry prominent notices stating 
+        that you changed the files and the date of any change. 
+
+   * b) You must cause any work that you distribute or publish, that in 
+        whole or in part contains or is derived from the Program or any part 
+        thereof, to be licensed as a whole at no charge to all third parties
+        under the terms of this License. 
+
+   * c) If the modified program normally reads commands interactively when 
+        run, you must cause it, when started running for such interactive 
+        use in the most ordinary way, to print or display an announcement 
+        including an appropriate copyright notice and a notice that there is
+        no warranty (or else, saying that you provide a warranty) and that 
+        users may redistribute the program under these conditions, and 
+        telling the user how to view a copy of this License. (Exception: if 
+        the Program itself is interactive but does not normally print such 
+        an announcement, your work based on the Program is not required to 
+        print an announcement.) 
+
+   These requirements apply to the modified work as a whole. If identifiable 
+   sections of that work are not derived from the Program, and can be 
+   reasonably considered independent and separate works in themselves, then 
+   this License, and its terms, do not apply to those sections when you 
+   distribute them as separate works. But when you distribute the same 
+   sections as part of a whole which is a work based on the Program, the 
+   distribution of the whole must be on the terms of this License, whose 
+   permissions for other licensees extend to the entire whole, and thus to 
+   each and every part regardless of who wrote it. 
+
+   Thus, it is not the intent of this section to claim rights or contest 
+   your rights to work written entirely by you; rather, the intent is to 
+   exercise the right to control the distribution of derivative or 
+   collective works based on the Program. 
+
+   In addition, mere aggregation of another work not based on the Program 
+   with the Program (or with a work based on the Program) on a volume of a 
+   storage or distribution medium does not bring the other work under the 
+   scope of this License. 
+
+3. You may copy and distribute the Program (or a work based on it, under 
+   Section 2) in object code or executable form under the terms of Sections 
+   1 and 2 above provided that you also do one of the following: 
+
+   * a) Accompany it with the complete corresponding machine-readable source 
+        code, which must be distributed under the terms of Sections 1 and 2 
+        above on a medium customarily used for software interchange; or, 
+
+   * b) Accompany it with a written offer, valid for at least three years, 
+        to give any third party, for a charge no more than your cost of 
+        physically performing source distribution, a complete machine-
+        readable copy of the corresponding source code, to be distributed 
+        under the terms of Sections 1 and 2 above on a medium customarily 
+        used for software interchange; or, 
+
+   * c) Accompany it with the information you received as to the offer to 
+        distribute corresponding source code. (This alternative is allowed 
+        only for noncommercial distribution and only if you received the 
+        program in object code or executable form with such an offer, in 
+        accord with Subsection b above.) 
+
+   The source code for a work means the preferred form of the work for 
+   making modifications to it. For an executable work, complete source code 
+   means all the source code for all modules it contains, plus any 
+   associated interface definition files, plus the scripts used to control 
+   compilation and installation of the executable. However, as a special 
+   exception, the source code distributed need not include anything that is 
+   normally distributed (in either source or binary form) with the major 
+   components (compiler, kernel, and so on) of the operating system on which
+   the executable runs, unless that component itself accompanies the 
+   executable. 
+
+   If distribution of executable or object code is made by offering access 
+   to copy from a designated place, then offering equivalent access to copy 
+   the source code from the same place counts as distribution of the source 
+   code, even though third parties are not compelled to copy the source 
+   along with the object code. 
+
+4. You may not copy, modify, sublicense, or distribute the Program except as
+   expressly provided under this License. Any attempt otherwise to copy, 
+   modify, sublicense or distribute the Program is void, and will 
+   automatically terminate your rights under this License. However, parties 
+   who have received copies, or rights, from you under this License will not
+   have their licenses terminated so long as such parties remain in full 
+   compliance. 
+
+5. You are not required to accept this License, since you have not signed 
+   it. However, nothing else grants you permission to modify or distribute 
+   the Program or its derivative works. These actions are prohibited by law 
+   if you do not accept this License. Therefore, by modifying or 
+   distributing the Program (or any work based on the Program), you 
+   indicate your acceptance of this License to do so, and all its terms and
+   conditions for copying, distributing or modifying the Program or works 
+   based on it. 
+
+6. Each time you redistribute the Program (or any work based on the 
+   Program), the recipient automatically receives a license from the 
+   original licensor to copy, distribute or modify the Program subject to 
+   these terms and conditions. You may not impose any further restrictions 
+   on the recipients' exercise of the rights granted herein. You are not 
+   responsible for enforcing compliance by third parties to this License. 
+
+7. If, as a consequence of a court judgment or allegation of patent 
+   infringement or for any other reason (not limited to patent issues), 
+   conditions are imposed on you (whether by court order, agreement or 
+   otherwise) that contradict the conditions of this License, they do not 
+   excuse you from the conditions of this License. If you cannot distribute 
+   so as to satisfy simultaneously your obligations under this License and 
+   any other pertinent obligations, then as a consequence you may not 
+   distribute the Program at all. For example, if a patent license would 
+   not permit royalty-free redistribution of the Program by all those who 
+   receive copies directly or indirectly through you, then the only way you 
+   could satisfy both it and this License would be to refrain entirely from 
+   distribution of the Program. 
+
+   If any portion of this section is held invalid or unenforceable under any
+   particular circumstance, the balance of the section is intended to apply
+   and the section as a whole is intended to apply in other circumstances. 
+
+   It is not the purpose of this section to induce you to infringe any 
+   patents or other property right claims or to contest validity of any 
+   such claims; this section has the sole purpose of protecting the 
+   integrity of the free software distribution system, which is implemented 
+   by public license practices. Many people have made generous contributions
+   to the wide range of software distributed through that system in 
+   reliance on consistent application of that system; it is up to the 
+   author/donor to decide if he or she is willing to distribute software 
+   through any other system and a licensee cannot impose that choice. 
+
+   This section is intended to make thoroughly clear what is believed to be 
+   a consequence of the rest of this License. 
+
+8. If the distribution and/or use of the Program is restricted in certain 
+   countries either by patents or by copyrighted interfaces, the original 
+   copyright holder who places the Program under this License may add an 
+   explicit geographical distribution limitation excluding those countries, 
+   so that distribution is permitted only in or among countries not thus 
+   excluded. In such case, this License incorporates the limitation as if 
+   written in the body of this License. 
+
+9. The Free Software Foundation may publish revised and/or new versions of 
+   the General Public License from time to time. Such new versions will be 
+   similar in spirit to the present version, but may differ in detail to 
+   address new problems or concerns. 
+
+   Each version is given a distinguishing version number. If the Program 
+   specifies a version number of this License which applies to it and "any 
+   later version", you have the option of following the terms and 
+   conditions either of that version or of any later version published by 
+   the Free Software Foundation. If the Program does not specify a version 
+   number of this License, you may choose any version ever published by the 
+   Free Software Foundation. 
+
+10. If you wish to incorporate parts of the Program into other free programs
+    whose distribution conditions are different, write to the author to ask 
+    for permission. For software which is copyrighted by the Free Software 
+    Foundation, write to the Free Software Foundation; we sometimes make 
+    exceptions for this. Our decision will be guided by the two goals of 
+    preserving the free status of all derivatives of our free software and 
+    of promoting the sharing and reuse of software generally. 
+
+   NO WARRANTY
+
+11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 
+    FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 
+    OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 
+    PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER 
+    EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
+    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE 
+    ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH 
+    YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL 
+    NECESSARY SERVICING, REPAIR OR CORRECTION. 
+
+12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 
+    WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 
+    REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR 
+    DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL 
+    DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM 
+    (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED 
+    INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF 
+    THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR 
+    OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 
+
+END OF TERMS AND CONDITIONS
+
+How to Apply These Terms to Your New Programs
+
+If you develop a new program, and you want it to be of the greatest 
+possible use to the public, the best way to achieve this is to make it free 
+software which everyone can redistribute and change under these terms. 
+
+To do so, attach the following notices to the program. It is safest to 
+attach them to the start of each source file to most effectively convey the
+exclusion of warranty; and each file should have at least the "copyright" 
+line and a pointer to where the full notice is found. 
+
+one line to give the program's name and an idea of what it does.
+Copyright (C) yyyy  name of author
+
+This program is free software; you can redistribute it and/or modify it 
+under the terms of the GNU General Public License as published by the Free 
+Software Foundation; either version 2 of the License, or (at your option) 
+any later version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT 
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
+more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 
+Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Also add information on how to contact you by electronic and paper mail. 
+
+If the program is interactive, make it output a short notice like this when 
+it starts in an interactive mode: 
+
+Gnomovision version 69, Copyright (C) year name of author Gnomovision comes 
+with ABSOLUTELY NO WARRANTY; for details type 'show w'.  This is free 
+software, and you are welcome to redistribute it under certain conditions; 
+type 'show c' for details.
+
+The hypothetical commands 'show w' and 'show c' should show the appropriate 
+parts of the General Public License. Of course, the commands you use may be 
+called something other than 'show w' and 'show c'; they could even be 
+mouse-clicks or menu items--whatever suits your program. 
+
+You should also get your employer (if you work as a programmer) or your 
+school, if any, to sign a "copyright disclaimer" for the program, if 
+necessary. Here is a sample; alter the names: 
+
+Yoyodyne, Inc., hereby disclaims all copyright interest in the program 
+'Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+signature of Ty Coon, 1 April 1989
+Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into 
+proprietary programs. If your program is a subroutine library, you may 
+consider it more useful to permit linking proprietary applications with the 
+library. If this is what you want to do, use the GNU Library General Public 
+License instead of this License.
diff -urN linux-2.4.20-pre4/drivers/net/e1000/Makefile linux-2.4.20-pre5/drivers/net/e1000/Makefile
--- linux-2.4.20-pre4/drivers/net/e1000/Makefile	Wed Aug 28 16:36:54 2002
+++ linux-2.4.20-pre5/drivers/net/e1000/Makefile	Wed Aug 28 16:38:03 2002
@@ -1,73 +1,28 @@
 ################################################################################
 #
-# This software program is available to you under a choice of one of two
-# licenses. You may choose to be licensed under either the GNU General Public
-# License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html,
-# or the Intel BSD + Patent License, the text of which follows:
-# 
-# Recipient has requested a license and Intel Corporation ("Intel") is willing
-# to grant a license for the software entitled Linux Base Driver for the
-# Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided
-# by Intel Corporation. The following definitions apply to this license:
-# 
-# "Licensed Patents" means patent claims licensable by Intel Corporation which
-# are necessarily infringed by the use of sale of the Software alone or when
-# combined with the operating system referred to below.
-# 
-# "Recipient" means the party to whom Intel delivers this Software.
-# 
-# "Licensee" means Recipient and those third parties that receive a license to
-# any operating system available under the GNU General Public License 2.0 or
-# later.
-# 
-# Copyright (c) 1999 - 2002 Intel Corporation.
-# All rights reserved.
-# 
-# The license is provided to Recipient and Recipient's Licensees under the
-# following terms.
-# 
-# Redistribution and use in source and binary forms of the Software, with or
-# without modification, are permitted provided that the following conditions
-# are met:
-# 
-# Redistributions of source code of the Software may retain the above
-# copyright notice, this list of conditions and the following disclaimer.
-# 
-# Redistributions in binary form of the Software may reproduce the above
-# copyright notice, this list of conditions and the following disclaimer in
-# the documentation and/or materials provided with the distribution.
-# 
-# Neither the name of Intel Corporation nor the names of its contributors
-# shall be used to endorse or promote products derived from this Software
-# without specific prior written permission.
-# 
-# Intel hereby grants Recipient and Licensees a non-exclusive, worldwide,
-# royalty-free patent license under Licensed Patents to make, use, sell, offer
-# to sell, import and otherwise transfer the Software, if any, in source code
-# and object code form. This license shall include changes to the Software
-# that are error corrections or other minor changes to the Software that do
-# not add functionality or features when the Software is incorporated in any
-# version of an operating system that has been distributed under the GNU
-# General Public License 2.0 or later. This patent license shall apply to the
-# combination of the Software and any operating system licensed under the GNU
-# General Public License 2.0 or later if, at the time Intel provides the
-# Software to Recipient, such addition of the Software to the then publicly
-# available versions of such operating systems available under the GNU General
-# Public License 2.0 or later (whether in gold, beta or alpha form) causes
-# such combination to be covered by the Licensed Patents. The patent license
-# shall not apply to any other combinations which include the Software. NO
-# hardware per se is licensed hereunder.
-# 
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY
-# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-# (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-# ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED
-# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR
-# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# 
+# Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+# 
+# This program is free software; you can redistribute it and/or modify it 
+# under the terms of the GNU General Public License as published by the Free 
+# Software Foundation; either version 2 of the License, or (at your option) 
+# any later version.
+# 
+# This program is distributed in the hope that it will be useful, but WITHOUT 
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
+# more details.
+# 
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 59 
+# Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+# 
+# The full GNU General Public License is included in this distribution in the
+# file called LICENSE.
+# 
+# Contact Information:
+# Linux NICS <linux.nics@intel.com>
+# Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 #
 ################################################################################
 
diff -urN linux-2.4.20-pre4/drivers/net/e1000/e1000.h linux-2.4.20-pre5/drivers/net/e1000/e1000.h
--- linux-2.4.20-pre4/drivers/net/e1000/e1000.h	Wed Aug 28 16:36:54 2002
+++ linux-2.4.20-pre5/drivers/net/e1000/e1000.h	Wed Aug 28 16:38:03 2002
@@ -1,73 +1,28 @@
 /*******************************************************************************
 
-  This software program is available to you under a choice of one of two
-  licenses. You may choose to be licensed under either the GNU General Public
-  License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html,
-  or the Intel BSD + Patent License, the text of which follows:
-  
-  Recipient has requested a license and Intel Corporation ("Intel") is willing
-  to grant a license for the software entitled Linux Base Driver for the
-  Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided
-  by Intel Corporation. The following definitions apply to this license:
-  
-  "Licensed Patents" means patent claims licensable by Intel Corporation which
-  are necessarily infringed by the use of sale of the Software alone or when
-  combined with the operating system referred to below.
-  
-  "Recipient" means the party to whom Intel delivers this Software.
-  
-  "Licensee" means Recipient and those third parties that receive a license to
-  any operating system available under the GNU General Public License 2.0 or
-  later.
-  
-  Copyright (c) 1999 - 2002 Intel Corporation.
-  All rights reserved.
-  
-  The license is provided to Recipient and Recipient's Licensees under the
-  following terms.
-  
-  Redistribution and use in source and binary forms of the Software, with or
-  without modification, are permitted provided that the following conditions
-  are met:
-  
-  Redistributions of source code of the Software may retain the above
-  copyright notice, this list of conditions and the following disclaimer.
-  
-  Redistributions in binary form of the Software may reproduce the above
-  copyright notice, this list of conditions and the following disclaimer in
-  the documentation and/or materials provided with the distribution.
-  
-  Neither the name of Intel Corporation nor the names of its contributors
-  shall be used to endorse or promote products derived from this Software
-  without specific prior written permission.
-  
-  Intel hereby grants Recipient and Licensees a non-exclusive, worldwide,
-  royalty-free patent license under Licensed Patents to make, use, sell, offer
-  to sell, import and otherwise transfer the Software, if any, in source code
-  and object code form. This license shall include changes to the Software
-  that are error corrections or other minor changes to the Software that do
-  not add functionality or features when the Software is incorporated in any
-  version of an operating system that has been distributed under the GNU
-  General Public License 2.0 or later. This patent license shall apply to the
-  combination of the Software and any operating system licensed under the GNU
-  General Public License 2.0 or later if, at the time Intel provides the
-  Software to Recipient, such addition of the Software to the then publicly
-  available versions of such operating systems available under the GNU General
-  Public License 2.0 or later (whether in gold, beta or alpha form) causes
-  such combination to be covered by the Licensed Patents. The patent license
-  shall not apply to any other combinations which include the Software. NO
-  hardware per se is licensed hereunder.
-  
-  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-  IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-  ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY
-  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-  (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-  ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED
-  AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR
-  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  
+  This program is free software; you can redistribute it and/or modify it 
+  under the terms of the GNU General Public License as published by the Free 
+  Software Foundation; either version 2 of the License, or (at your option) 
+  any later version.
+  
+  This program is distributed in the hope that it will be useful, but WITHOUT 
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
+  more details.
+  
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59 
+  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
 *******************************************************************************/
 
@@ -108,6 +63,7 @@
 #include <net/pkt_sched.h>
 #include <linux/list.h>
 #include <linux/reboot.h>
+#include <linux/tqueue.h>
 #include <linux/ethtool.h>
 #include <linux/if_vlan.h>
 
@@ -130,11 +86,7 @@
 
 #define E1000_ERR(args...) printk(KERN_ERR "e1000: " args)
 
-#ifdef CONFIG_PPC
-#define E1000_MAX_INTR 1
-#else
 #define E1000_MAX_INTR 10
-#endif
 
 /* Supported Rx Buffer Sizes */
 #define E1000_RXBUFFER_2048  2048
@@ -207,6 +159,7 @@
 	uint16_t link_duplex;
 	spinlock_t stats_lock;
 	atomic_t irq_sem;
+	struct tq_struct tx_timeout_task;
 
 	struct timer_list blink_timer;
 	unsigned long led_status;
@@ -214,6 +167,8 @@
 	/* TX */
 	struct e1000_desc_ring tx_ring;
 	uint32_t txd_cmd;
+	uint32_t tx_int_delay;
+	uint32_t tx_abs_int_delay;
 	int max_data_per_txd;
 
 	/* RX */
@@ -221,6 +176,7 @@
 	uint64_t hw_csum_err;
 	uint64_t hw_csum_good;
 	uint32_t rx_int_delay;
+	uint32_t rx_abs_int_delay;
 	boolean_t rx_csum;
 
 	/* OS defined structs */
diff -urN linux-2.4.20-pre4/drivers/net/e1000/e1000_ethtool.c linux-2.4.20-pre5/drivers/net/e1000/e1000_ethtool.c
--- linux-2.4.20-pre4/drivers/net/e1000/e1000_ethtool.c	Wed Aug 28 16:36:54 2002
+++ linux-2.4.20-pre5/drivers/net/e1000/e1000_ethtool.c	Wed Aug 28 16:38:03 2002
@@ -1,73 +1,28 @@
 /*******************************************************************************
 
-  This software program is available to you under a choice of one of two
-  licenses. You may choose to be licensed under either the GNU General Public
-  License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html,
-  or the Intel BSD + Patent License, the text of which follows:
   
-  Recipient has requested a license and Intel Corporation ("Intel") is willing
-  to grant a license for the software entitled Linux Base Driver for the
-  Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided
-  by Intel Corporation. The following definitions apply to this license:
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
   
-  "Licensed Patents" means patent claims licensable by Intel Corporation which
-  are necessarily infringed by the use of sale of the Software alone or when
-  combined with the operating system referred to below.
-  
-  "Recipient" means the party to whom Intel delivers this Software.
-  
-  "Licensee" means Recipient and those third parties that receive a license to
-  any operating system available under the GNU General Public License 2.0 or
-  later.
-  
-  Copyright (c) 1999 - 2002 Intel Corporation.
-  All rights reserved.
-  
-  The license is provided to Recipient and Recipient's Licensees under the
-  following terms.
-  
-  Redistribution and use in source and binary forms of the Software, with or
-  without modification, are permitted provided that the following conditions
-  are met:
-  
-  Redistributions of source code of the Software may retain the above
-  copyright notice, this list of conditions and the following disclaimer.
-  
-  Redistributions in binary form of the Software may reproduce the above
-  copyright notice, this list of conditions and the following disclaimer in
-  the documentation and/or materials provided with the distribution.
-  
-  Neither the name of Intel Corporation nor the names of its contributors
-  shall be used to endorse or promote products derived from this Software
-  without specific prior written permission.
-  
-  Intel hereby grants Recipient and Licensees a non-exclusive, worldwide,
-  royalty-free patent license under Licensed Patents to make, use, sell, offer
-  to sell, import and otherwise transfer the Software, if any, in source code
-  and object code form. This license shall include changes to the Software
-  that are error corrections or other minor changes to the Software that do
-  not add functionality or features when the Software is incorporated in any
-  version of an operating system that has been distributed under the GNU
-  General Public License 2.0 or later. This patent license shall apply to the
-  combination of the Software and any operating system licensed under the GNU
-  General Public License 2.0 or later if, at the time Intel provides the
-  Software to Recipient, such addition of the Software to the then publicly
-  available versions of such operating systems available under the GNU General
-  Public License 2.0 or later (whether in gold, beta or alpha form) causes
-  such combination to be covered by the Licensed Patents. The patent license
-  shall not apply to any other combinations which include the Software. NO
-  hardware per se is licensed hereunder.
-  
-  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-  IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-  ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY
-  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-  (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-  ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED
-  AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR
-  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  This program is free software; you can redistribute it and/or modify it 
+  under the terms of the GNU General Public License as published by the Free 
+  Software Foundation; either version 2 of the License, or (at your option) 
+  any later version.
+  
+  This program is distributed in the hope that it will be useful, but WITHOUT 
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
+  more details.
+  
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59 
+  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
 *******************************************************************************/
 
@@ -82,6 +37,7 @@
 
 extern int e1000_up(struct e1000_adapter *adapter);
 extern void e1000_down(struct e1000_adapter *adapter);
+extern void e1000_reset(struct e1000_adapter *adapter);
 
 static void
 e1000_ethtool_gset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd)
@@ -189,8 +145,11 @@
 
 	/* reset the link */
 
-	e1000_down(adapter);
-	e1000_up(adapter);
+	if(netif_running(adapter->netdev)) {
+		e1000_down(adapter);
+		e1000_up(adapter);
+	} else
+		e1000_reset(adapter);
 
 	return 0;
 }
@@ -211,7 +170,7 @@
 {
 	strncpy(drvinfo->driver,  e1000_driver_name, 32);
 	strncpy(drvinfo->version, e1000_driver_version, 32);
-	strncpy(drvinfo->fw_version, "", 32);
+	strncpy(drvinfo->fw_version, "N/A", 32);
 	strncpy(drvinfo->bus_info, adapter->pdev->slot_name, 32);
 #define E1000_REGS_LEN 32
 	drvinfo->regdump_len  = E1000_REGS_LEN * sizeof(uint32_t);
@@ -251,7 +210,8 @@
 	struct e1000_hw *hw = &adapter->hw;
 	int i, max_len, first_word, last_word;
 
-	if(eeprom->len == 0) return;
+	if(eeprom->len == 0)
+		return -EOPNOTSUPP;
 
 	eeprom->magic = hw->vendor_id | (hw->device_id << 16);
 
@@ -280,11 +240,12 @@
 	int i, max_len, first_word, last_word;
 	void *ptr;
 
+	if(eeprom->len == 0)
+		return -EOPNOTSUPP;
+
 	if(eeprom->magic != (hw->vendor_id | (hw->device_id << 16)))
 		return -EFAULT;
 
-	if(eeprom->len == 0) return 0;
-
 	max_len = e1000_eeprom_size(hw);
 
 	if((eeprom->offset + eeprom->len) > max_len)
@@ -514,8 +475,10 @@
 	case ETHTOOL_NWAY_RST: {
 		if(!capable(CAP_NET_ADMIN))
 			return -EPERM;
-		e1000_down(adapter);
-		e1000_up(adapter);
+		if(netif_running(netdev)) {
+			e1000_down(adapter);
+			e1000_up(adapter);
+		}
 		return 0;
 	}
 	case ETHTOOL_PHYS_ID: {
diff -urN linux-2.4.20-pre4/drivers/net/e1000/e1000_hw.c linux-2.4.20-pre5/drivers/net/e1000/e1000_hw.c
--- linux-2.4.20-pre4/drivers/net/e1000/e1000_hw.c	Wed Aug 28 16:36:54 2002
+++ linux-2.4.20-pre5/drivers/net/e1000/e1000_hw.c	Wed Aug 28 16:38:03 2002
@@ -1,73 +1,28 @@
 /*******************************************************************************
 
-  This software program is available to you under a choice of one of two
-  licenses. You may choose to be licensed under either the GNU General Public
-  License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html,
-  or the Intel BSD + Patent License, the text of which follows:
   
-  Recipient has requested a license and Intel Corporation ("Intel") is willing
-  to grant a license for the software entitled Linux Base Driver for the
-  Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided
-  by Intel Corporation. The following definitions apply to this license:
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
   
-  "Licensed Patents" means patent claims licensable by Intel Corporation which
-  are necessarily infringed by the use of sale of the Software alone or when
-  combined with the operating system referred to below.
+  This program is free software; you can redistribute it and/or modify it 
+  under the terms of the GNU General Public License as published by the Free 
+  Software Foundation; either version 2 of the License, or (at your option) 
+  any later version.
   
-  "Recipient" means the party to whom Intel delivers this Software.
+  This program is distributed in the hope that it will be useful, but WITHOUT 
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
+  more details.
   
-  "Licensee" means Recipient and those third parties that receive a license to
-  any operating system available under the GNU General Public License 2.0 or
-  later.
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59 
+  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
   
-  Copyright (c) 1999 - 2002 Intel Corporation.
-  All rights reserved.
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
   
-  The license is provided to Recipient and Recipient's Licensees under the
-  following terms.
-  
-  Redistribution and use in source and binary forms of the Software, with or
-  without modification, are permitted provided that the following conditions
-  are met:
-  
-  Redistributions of source code of the Software may retain the above
-  copyright notice, this list of conditions and the following disclaimer.
-  
-  Redistributions in binary form of the Software may reproduce the above
-  copyright notice, this list of conditions and the following disclaimer in
-  the documentation and/or materials provided with the distribution.
-  
-  Neither the name of Intel Corporation nor the names of its contributors
-  shall be used to endorse or promote products derived from this Software
-  without specific prior written permission.
-  
-  Intel hereby grants Recipient and Licensees a non-exclusive, worldwide,
-  royalty-free patent license under Licensed Patents to make, use, sell, offer
-  to sell, import and otherwise transfer the Software, if any, in source code
-  and object code form. This license shall include changes to the Software
-  that are error corrections or other minor changes to the Software that do
-  not add functionality or features when the Software is incorporated in any
-  version of an operating system that has been distributed under the GNU
-  General Public License 2.0 or later. This patent license shall apply to the
-  combination of the Software and any operating system licensed under the GNU
-  General Public License 2.0 or later if, at the time Intel provides the
-  Software to Recipient, such addition of the Software to the then publicly
-  available versions of such operating systems available under the GNU General
-  Public License 2.0 or later (whether in gold, beta or alpha form) causes
-  such combination to be covered by the Licensed Patents. The patent license
-  shall not apply to any other combinations which include the Software. NO
-  hardware per se is licensed hereunder.
-  
-  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-  IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-  ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY
-  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-  (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-  ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED
-  AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR
-  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
 *******************************************************************************/
 
@@ -93,9 +48,63 @@
 static uint16_t e1000_shift_in_ee_bits(struct e1000_hw *hw);
 static void e1000_setup_eeprom(struct e1000_hw *hw);
 static void e1000_standby_eeprom(struct e1000_hw *hw);
+static void e1000_clock_eeprom(struct e1000_hw *hw);
+static void e1000_cleanup_eeprom(struct e1000_hw *hw);
 static int32_t e1000_id_led_init(struct e1000_hw * hw);
 
 /******************************************************************************
+ * Set the mac type member in the hw struct.
+ * 
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+e1000_set_mac_type(struct e1000_hw *hw)
+{
+    DEBUGFUNC("e1000_set_mac_type");
+
+    switch (hw->device_id) {
+    case E1000_DEV_ID_82542:
+        switch (hw->revision_id) {
+        case E1000_82542_2_0_REV_ID:
+            hw->mac_type = e1000_82542_rev2_0;
+            break;
+        case E1000_82542_2_1_REV_ID:
+            hw->mac_type = e1000_82542_rev2_1;
+            break;
+        default:
+            /* Invalid 82542 revision ID */
+            return -E1000_ERR_MAC_TYPE;
+        }
+        break;
+    case E1000_DEV_ID_82543GC_FIBER:
+    case E1000_DEV_ID_82543GC_COPPER:
+        hw->mac_type = e1000_82543;
+        break;
+    case E1000_DEV_ID_82544EI_COPPER:
+    case E1000_DEV_ID_82544EI_FIBER:
+    case E1000_DEV_ID_82544GC_COPPER:
+    case E1000_DEV_ID_82544GC_LOM:
+        hw->mac_type = e1000_82544;
+        break;
+    case E1000_DEV_ID_82540EM:
+    case E1000_DEV_ID_82540EM_LOM:
+        hw->mac_type = e1000_82540;
+        break;
+    case E1000_DEV_ID_82545EM_COPPER:
+    case E1000_DEV_ID_82545EM_FIBER:
+        hw->mac_type = e1000_82545;
+        break;
+    case E1000_DEV_ID_82546EB_COPPER:
+    case E1000_DEV_ID_82546EB_FIBER:
+        hw->mac_type = e1000_82546;
+        break;
+    default:
+        /* Should never have loaded on this device */
+        return -E1000_ERR_MAC_TYPE;
+    }
+    return E1000_SUCCESS;
+}
+/******************************************************************************
  * Reset the transmit and receive units; mask and clear all interrupts.
  *
  * hw - Struct containing variables accessed by shared code
@@ -209,8 +218,8 @@
     /* Initialize Identification LED */
     ret_val = e1000_id_led_init(hw);
     if(ret_val < 0) {
-	DEBUGOUT("Error Initializing Identification LED\n");
-	return ret_val;
+        DEBUGOUT("Error Initializing Identification LED\n");
+        return ret_val;
     }
     
     /* Set the Media Type and exit with error if it is not valid. */
@@ -284,6 +293,8 @@
             PCIX_COMMAND_MMRBC_SHIFT;
         stat_mmrbc = (pcix_stat_hi_word & PCIX_STATUS_HI_MMRBC_MASK) >>
             PCIX_STATUS_HI_MMRBC_SHIFT;
+        if(stat_mmrbc == PCIX_STATUS_HI_MMRBC_4K)
+            stat_mmrbc = PCIX_STATUS_HI_MMRBC_2K;
         if(cmd_mmrbc > stat_mmrbc) {
             pcix_cmd_word &= ~PCIX_COMMAND_MMRBC_MASK;
             pcix_cmd_word |= stat_mmrbc << PCIX_COMMAND_MMRBC_SHIFT;
@@ -294,6 +305,13 @@
     /* Call a subroutine to configure the link and setup flow control. */
     ret_val = e1000_setup_link(hw);
 
+    /* Set the transmit descriptor write-back policy */
+    if(hw->mac_type > e1000_82544) {
+        ctrl = E1000_READ_REG(hw, TXDCTL);
+        ctrl = (ctrl & ~E1000_TXDCTL_WTHRESH) | E1000_TXDCTL_FULL_TX_DESC_WB;
+        E1000_WRITE_REG(hw, TXDCTL, ctrl);
+    }
+
     /* Clear all of the statistics registers (clear on read).  It is
      * important that we do this after we have tried to establish link
      * because the symbol error count will increment wildly if there
@@ -419,7 +437,6 @@
  * Sets up link for a fiber based adapter
  *
  * hw - Struct containing variables accessed by shared code
- * ctrl - Current value of the device control register
  *
  * Manipulates Physical Coding Sublayer functions in order to configure
  * link. Assumes the hardware has been previously reset and the transmitter
@@ -550,7 +567,6 @@
 * Detects which PHY is present and the speed and duplex
 *
 * hw - Struct containing variables accessed by shared code
-* ctrl - current value of the device control register
 ******************************************************************************/
 static int32_t 
 e1000_setup_copper_link(struct e1000_hw *hw)
@@ -3031,12 +3047,12 @@
     const uint32_t ledctl_off = E1000_LEDCTL_MODE_LED_OFF;
     uint16_t eeprom_data, i, temp;
     const uint16_t led_mask = 0x0F;
-	
+        
     DEBUGFUNC("e1000_id_led_init");
     
     if(hw->mac_type < e1000_82540) {
-	/* Nothing to do */
-	return 0;
+        /* Nothing to do */
+        return 0;
     }
     
     ledctl = E1000_READ_REG(hw, LEDCTL);
@@ -3053,39 +3069,39 @@
     for(i = 0; i < 4; i++) {
         temp = (eeprom_data >> (i << 2)) & led_mask;
         switch(temp) {
-	case ID_LED_ON1_DEF2:
-	case ID_LED_ON1_ON2:
-	case ID_LED_ON1_OFF2:
+        case ID_LED_ON1_DEF2:
+        case ID_LED_ON1_ON2:
+        case ID_LED_ON1_OFF2:
             hw->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
             hw->ledctl_mode1 |= ledctl_on << (i << 3);
             break;
-	case ID_LED_OFF1_DEF2:
-	case ID_LED_OFF1_ON2:
-	case ID_LED_OFF1_OFF2:
+        case ID_LED_OFF1_DEF2:
+        case ID_LED_OFF1_ON2:
+        case ID_LED_OFF1_OFF2:
             hw->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
             hw->ledctl_mode1 |= ledctl_off << (i << 3);
             break;
-	default:
-	    /* Do nothing */
-	    break;
-	}
-	switch(temp) {
-	case ID_LED_DEF1_ON2:
-	case ID_LED_ON1_ON2:
-	case ID_LED_OFF1_ON2:
+        default:
+            /* Do nothing */
+            break;
+        }
+        switch(temp) {
+        case ID_LED_DEF1_ON2:
+        case ID_LED_ON1_ON2:
+        case ID_LED_OFF1_ON2:
             hw->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
             hw->ledctl_mode2 |= ledctl_on << (i << 3);
             break;
-	case ID_LED_DEF1_OFF2:
-	case ID_LED_ON1_OFF2:
-	case ID_LED_OFF1_OFF2:
+        case ID_LED_DEF1_OFF2:
+        case ID_LED_ON1_OFF2:
+        case ID_LED_OFF1_OFF2:
             hw->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
             hw->ledctl_mode2 |= ledctl_off << (i << 3);
             break;
-	default:
-	    /* Do nothing */
-	    break;
-	}
+        default:
+            /* Do nothing */
+            break;
+        }
     }
     return 0;
 }
diff -urN linux-2.4.20-pre4/drivers/net/e1000/e1000_hw.h linux-2.4.20-pre5/drivers/net/e1000/e1000_hw.h
--- linux-2.4.20-pre4/drivers/net/e1000/e1000_hw.h	Wed Aug 28 16:36:54 2002
+++ linux-2.4.20-pre5/drivers/net/e1000/e1000_hw.h	Wed Aug 28 16:38:03 2002
@@ -1,73 +1,28 @@
 /*******************************************************************************
 
-  This software program is available to you under a choice of one of two
-  licenses. You may choose to be licensed under either the GNU General Public
-  License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html,
-  or the Intel BSD + Patent License, the text of which follows:
   
-  Recipient has requested a license and Intel Corporation ("Intel") is willing
-  to grant a license for the software entitled Linux Base Driver for the
-  Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided
-  by Intel Corporation. The following definitions apply to this license:
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
   
-  "Licensed Patents" means patent claims licensable by Intel Corporation which
-  are necessarily infringed by the use of sale of the Software alone or when
-  combined with the operating system referred to below.
+  This program is free software; you can redistribute it and/or modify it 
+  under the terms of the GNU General Public License as published by the Free 
+  Software Foundation; either version 2 of the License, or (at your option) 
+  any later version.
   
-  "Recipient" means the party to whom Intel delivers this Software.
+  This program is distributed in the hope that it will be useful, but WITHOUT 
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
+  more details.
   
-  "Licensee" means Recipient and those third parties that receive a license to
-  any operating system available under the GNU General Public License 2.0 or
-  later.
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59 
+  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
   
-  Copyright (c) 1999 - 2002 Intel Corporation.
-  All rights reserved.
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
   
-  The license is provided to Recipient and Recipient's Licensees under the
-  following terms.
-  
-  Redistribution and use in source and binary forms of the Software, with or
-  without modification, are permitted provided that the following conditions
-  are met:
-  
-  Redistributions of source code of the Software may retain the above
-  copyright notice, this list of conditions and the following disclaimer.
-  
-  Redistributions in binary form of the Software may reproduce the above
-  copyright notice, this list of conditions and the following disclaimer in
-  the documentation and/or materials provided with the distribution.
-  
-  Neither the name of Intel Corporation nor the names of its contributors
-  shall be used to endorse or promote products derived from this Software
-  without specific prior written permission.
-  
-  Intel hereby grants Recipient and Licensees a non-exclusive, worldwide,
-  royalty-free patent license under Licensed Patents to make, use, sell, offer
-  to sell, import and otherwise transfer the Software, if any, in source code
-  and object code form. This license shall include changes to the Software
-  that are error corrections or other minor changes to the Software that do
-  not add functionality or features when the Software is incorporated in any
-  version of an operating system that has been distributed under the GNU
-  General Public License 2.0 or later. This patent license shall apply to the
-  combination of the Software and any operating system licensed under the GNU
-  General Public License 2.0 or later if, at the time Intel provides the
-  Software to Recipient, such addition of the Software to the then publicly
-  available versions of such operating systems available under the GNU General
-  Public License 2.0 or later (whether in gold, beta or alpha form) causes
-  such combination to be covered by the Licensed Patents. The patent license
-  shall not apply to any other combinations which include the Software. NO
-  hardware per se is licensed hereunder.
-  
-  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-  IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-  ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY
-  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-  (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-  ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED
-  AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR
-  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
 *******************************************************************************/
 
@@ -87,7 +42,8 @@
 /* Enumerated types specific to the e1000 hardware */
 /* Media Access Controlers */
 typedef enum {
-    e1000_82542_rev2_0 = 0,
+    e1000_undefined = 0,
+    e1000_82542_rev2_0,
     e1000_82542_rev2_1,
     e1000_82543,
     e1000_82544,
@@ -204,16 +160,18 @@
 
 
 /* Error Codes */
-#define E1000_SUCCESS    0
-#define E1000_ERR_EEPROM 1
-#define E1000_ERR_PHY    2
-#define E1000_ERR_CONFIG 3
-#define E1000_ERR_PARAM  4
+#define E1000_SUCCESS      0
+#define E1000_ERR_EEPROM   1
+#define E1000_ERR_PHY      2
+#define E1000_ERR_CONFIG   3
+#define E1000_ERR_PARAM    4
+#define E1000_ERR_MAC_TYPE 5
 
 /* Function prototypes */
 /* Initialization */
 void e1000_reset_hw(struct e1000_hw *hw);
 int32_t e1000_init_hw(struct e1000_hw *hw);
+int32_t e1000_set_mac_type(struct e1000_hw *hw);
 
 /* Link Configuration */
 int32_t e1000_setup_link(struct e1000_hw *hw);
@@ -1230,6 +1188,7 @@
 #define E1000_TXDCTL_WTHRESH 0x00FF0000 /* TXDCTL Writeback Threshold */
 #define E1000_TXDCTL_GRAN    0x01000000 /* TXDCTL Granularity */
 #define E1000_TXDCTL_LWTHRESH 0xFE000000 /* TXDCTL Low Threshold */
+#define E1000_TXDCTL_FULL_TX_DESC_WB 0x01010000 /* GRAN=1, WTHRESH=1 */
 
 /* Transmit Configuration Word */
 #define E1000_TXCW_FD         0x00000020        /* TXCW full duplex */
@@ -1469,6 +1428,8 @@
 #define PCIX_COMMAND_MMRBC_SHIFT     0x2
 #define PCIX_STATUS_HI_MMRBC_MASK    0x0060
 #define PCIX_STATUS_HI_MMRBC_SHIFT   0x5
+#define PCIX_STATUS_HI_MMRBC_4K      0x3
+#define PCIX_STATUS_HI_MMRBC_2K      0x2
 
 
 /* The number of bits that we need to shift right to move the "pause"
diff -urN linux-2.4.20-pre4/drivers/net/e1000/e1000_main.c linux-2.4.20-pre5/drivers/net/e1000/e1000_main.c
--- linux-2.4.20-pre4/drivers/net/e1000/e1000_main.c	Wed Aug 28 16:36:54 2002
+++ linux-2.4.20-pre5/drivers/net/e1000/e1000_main.c	Wed Aug 28 16:38:03 2002
@@ -1,80 +1,50 @@
 /*******************************************************************************
 
-  This software program is available to you under a choice of one of two
-  licenses. You may choose to be licensed under either the GNU General Public
-  License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html,
-  or the Intel BSD + Patent License, the text of which follows:
   
-  Recipient has requested a license and Intel Corporation ("Intel") is willing
-  to grant a license for the software entitled Linux Base Driver for the
-  Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided
-  by Intel Corporation. The following definitions apply to this license:
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
   
-  "Licensed Patents" means patent claims licensable by Intel Corporation which
-  are necessarily infringed by the use of sale of the Software alone or when
-  combined with the operating system referred to below.
+  This program is free software; you can redistribute it and/or modify it 
+  under the terms of the GNU General Public License as published by the Free 
+  Software Foundation; either version 2 of the License, or (at your option) 
+  any later version.
   
-  "Recipient" means the party to whom Intel delivers this Software.
+  This program is distributed in the hope that it will be useful, but WITHOUT 
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
+  more details.
   
-  "Licensee" means Recipient and those third parties that receive a license to
-  any operating system available under the GNU General Public License 2.0 or
-  later.
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59 
+  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
   
-  Copyright (c) 1999 - 2002 Intel Corporation.
-  All rights reserved.
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
   
-  The license is provided to Recipient and Recipient's Licensees under the
-  following terms.
-  
-  Redistribution and use in source and binary forms of the Software, with or
-  without modification, are permitted provided that the following conditions
-  are met:
-  
-  Redistributions of source code of the Software may retain the above
-  copyright notice, this list of conditions and the following disclaimer.
-  
-  Redistributions in binary form of the Software may reproduce the above
-  copyright notice, this list of conditions and the following disclaimer in
-  the documentation and/or materials provided with the distribution.
-  
-  Neither the name of Intel Corporation nor the names of its contributors
-  shall be used to endorse or promote products derived from this Software
-  without specific prior written permission.
-  
-  Intel hereby grants Recipient and Licensees a non-exclusive, worldwide,
-  royalty-free patent license under Licensed Patents to make, use, sell, offer
-  to sell, import and otherwise transfer the Software, if any, in source code
-  and object code form. This license shall include changes to the Software
-  that are error corrections or other minor changes to the Software that do
-  not add functionality or features when the Software is incorporated in any
-  version of an operating system that has been distributed under the GNU
-  General Public License 2.0 or later. This patent license shall apply to the
-  combination of the Software and any operating system licensed under the GNU
-  General Public License 2.0 or later if, at the time Intel provides the
-  Software to Recipient, such addition of the Software to the then publicly
-  available versions of such operating systems available under the GNU General
-  Public License 2.0 or later (whether in gold, beta or alpha form) causes
-  such combination to be covered by the Licensed Patents. The patent license
-  shall not apply to any other combinations which include the Software. NO
-  hardware per se is licensed hereunder.
-  
-  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-  IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-  ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY
-  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-  (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-  ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED
-  AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR
-  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
 *******************************************************************************/
+
 #define __E1000_MAIN__
 #include "e1000.h"
 
 /* Change Log
  *
+ * 4.3.15      8/9/02
+ *   o Converted from Dual BSD/GPL license to GPL license.
+ *   o Clean up: use pci_[clear|set]_mwi rather than direct calls to
+ *     pci_write_config_word.
+ *   o Bug fix: added read-behind-write calls to post writes before delays.
+ *   o Bug fix: removed mdelay busy-waits in interrupt context.
+ *   o Clean up: direct clear of descriptor bits rather than using memset.
+ *   o Bug fix: added wmb() for ia-64 between descritor writes and advancing
+ *     descriptor tail.
+ *   o Feature: added locking mechanism for asf functionality.
+ *   o Feature: exposed two Tx and one Rx interrupt delay knobs for finer
+ *     control over interurpt rate tuning.
+ *   o Misc ethtool bug fixes.
+ *         
  * 4.3.2       7/5/02
  *   o Bug fix: perform controller reset using I/O rather than mmio because
  *     some chipsets try to perform a 64-bit write, but the controller ignores
@@ -95,10 +65,10 @@
  *
  * 4.2.17      5/30/02
  */
-
+ 
 char e1000_driver_name[] = "e1000";
 char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
-char e1000_driver_version[] = "4.3.2-k1";
+char e1000_driver_version[] = "4.3.15-k1";
 char e1000_copyright[] = "Copyright (c) 1999-2002 Intel Corporation.";
 
 /* e1000_pci_tbl - PCI Device ID Table
@@ -195,6 +165,7 @@
                                      struct e1000_rx_desc *rx_desc,
                                      struct sk_buff *skb);
 static void e1000_tx_timeout(struct net_device *dev);
+static void e1000_tx_timeout_task(struct net_device *dev);
 
 static void e1000_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp);
 static void e1000_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid);
@@ -233,7 +204,7 @@
 
 MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
 MODULE_DESCRIPTION("Intel(R) PRO/1000 Network Driver");
-MODULE_LICENSE("Dual BSD/GPL");
+MODULE_LICENSE("GPL");
 
 /**
  * e1000_init_module - Driver Registration Routine
@@ -483,6 +454,9 @@
 	adapter->phy_info_timer.function = &e1000_update_phy_info;
 	adapter->phy_info_timer.data = (unsigned long) adapter;
 
+	INIT_TQUEUE(&adapter->tx_timeout_task, 
+		(void (*)(void *))e1000_tx_timeout_task, netdev);
+
 	register_netdev(netdev);
 
 	/* we're going to reset, so assume we have no link for now */
@@ -589,43 +563,8 @@
 
 	/* identify the MAC */
 
-	switch (hw->device_id) {
-	case E1000_DEV_ID_82542:
-		switch (hw->revision_id) {
-		case E1000_82542_2_0_REV_ID:
-			hw->mac_type = e1000_82542_rev2_0;
-			break;
-		case E1000_82542_2_1_REV_ID:
-			hw->mac_type = e1000_82542_rev2_1;
-			break;
-		default:
-			hw->mac_type = e1000_82542_rev2_0;
-			E1000_ERR("Could not identify 82542 revision\n");
-		}
-		break;
-	case E1000_DEV_ID_82543GC_FIBER:
-	case E1000_DEV_ID_82543GC_COPPER:
-		hw->mac_type = e1000_82543;
-		break;
-	case E1000_DEV_ID_82544EI_COPPER:
-	case E1000_DEV_ID_82544EI_FIBER:
-	case E1000_DEV_ID_82544GC_COPPER:
-	case E1000_DEV_ID_82544GC_LOM:
-		hw->mac_type = e1000_82544;
-		break;
-	case E1000_DEV_ID_82540EM:
-		hw->mac_type = e1000_82540;
-		break;
-	case E1000_DEV_ID_82545EM_COPPER:
-	case E1000_DEV_ID_82545EM_FIBER:
-		hw->mac_type = e1000_82545;
-		break;
-	case E1000_DEV_ID_82546EB_COPPER:
-	case E1000_DEV_ID_82546EB_FIBER:
-		hw->mac_type = e1000_82546;
-		break;
-	default:
-		E1000_ERR("Should never have loaded on this device\n");
+	if (e1000_set_mac_type(hw)) {
+		E1000_ERR("Unknown MAC Type\n");
 		BUG();
 	}
 
@@ -821,7 +760,9 @@
 
 	/* Set the Tx Interrupt Delay register */
 
-	E1000_WRITE_REG(&adapter->hw, TIDV, 64);
+	E1000_WRITE_REG(&adapter->hw, TIDV, adapter->tx_int_delay);
+	if(adapter->hw.mac_type >= e1000_82540)
+		E1000_WRITE_REG(&adapter->hw, TADV, adapter->tx_abs_int_delay);
 
 	/* Program the Transmit Control Register */
 
@@ -951,8 +892,8 @@
 	/* set the Receive Delay Timer Register */
 
 	if(adapter->hw.mac_type >= e1000_82540) {
-		E1000_WRITE_REG(&adapter->hw, RADV, adapter->rx_int_delay);
-		E1000_WRITE_REG(&adapter->hw, RDTR, 64);
+		E1000_WRITE_REG(&adapter->hw, RDTR, adapter->rx_int_delay);
+		E1000_WRITE_REG(&adapter->hw, RADV, adapter->rx_abs_int_delay);
 
 		/* Set the interrupt throttling rate.  Value is calculated
 		 * as DEFAULT_ITR = 1/(MAX_INTS_PER_SEC * 256ns) */
@@ -1457,9 +1398,14 @@
 
 	tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP);
 
+	/* Force memory writes to complete before letting h/w
+	 * know there are new descriptors to fetch.  (Only
+	 * applicable for weak-ordered memory model archs,
+	 * such as IA-64). */
+	wmb();
+
 	tx_ring->next_to_use = i;
 	E1000_WRITE_REG(&adapter->hw, TDT, i);
-	E1000_WRITE_FLUSH(&adapter->hw);
 }
 
 #define TXD_USE_COUNT(S, X) (((S) / (X)) + (((S) % (X)) ? 1 : 0))
@@ -1513,8 +1459,19 @@
 {
 	struct e1000_adapter *adapter = netdev->priv;
 
+	/* Do the reset outside of interrupt context */
+	schedule_task(&adapter->tx_timeout_task);
+}
+
+static void
+e1000_tx_timeout_task(struct net_device *netdev)
+{
+	struct e1000_adapter *adapter = netdev->priv;
+
+	netif_device_detach(netdev);
 	e1000_down(adapter);
 	e1000_up(adapter);
+	netif_device_attach(netdev);
 }
 
 /**
@@ -1979,8 +1936,15 @@
 
 		rx_desc->buffer_addr = cpu_to_le64(rx_ring->buffer_info[i].dma);
 
-		if(!(i % E1000_RX_BUFFER_WRITE))
+		if(!(i % E1000_RX_BUFFER_WRITE)) {
+			/* Force memory writes to complete before letting h/w
+			 * know there are new descriptors to fetch.  (Only
+			 * applicable for weak-ordered memory model archs,
+			 * such as IA-64). */
+			wmb();
+
 			E1000_WRITE_REG(&adapter->hw, RDT, i);
+		}
 
 		i = (i + 1) % rx_ring->count;
 	}
diff -urN linux-2.4.20-pre4/drivers/net/e1000/e1000_osdep.h linux-2.4.20-pre5/drivers/net/e1000/e1000_osdep.h
--- linux-2.4.20-pre4/drivers/net/e1000/e1000_osdep.h	Wed Aug 28 16:36:54 2002
+++ linux-2.4.20-pre5/drivers/net/e1000/e1000_osdep.h	Wed Aug 28 16:38:03 2002
@@ -1,73 +1,28 @@
 /*******************************************************************************
 
-  This software program is available to you under a choice of one of two
-  licenses. You may choose to be licensed under either the GNU General Public
-  License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html,
-  or the Intel BSD + Patent License, the text of which follows:
-  
-  Recipient has requested a license and Intel Corporation ("Intel") is willing
-  to grant a license for the software entitled Linux Base Driver for the
-  Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided
-  by Intel Corporation. The following definitions apply to this license:
-  
-  "Licensed Patents" means patent claims licensable by Intel Corporation which
-  are necessarily infringed by the use of sale of the Software alone or when
-  combined with the operating system referred to below.
-  
-  "Recipient" means the party to whom Intel delivers this Software.
-  
-  "Licensee" means Recipient and those third parties that receive a license to
-  any operating system available under the GNU General Public License 2.0 or
-  later.
-  
-  Copyright (c) 1999 - 2002 Intel Corporation.
-  All rights reserved.
-  
-  The license is provided to Recipient and Recipient's Licensees under the
-  following terms.
-  
-  Redistribution and use in source and binary forms of the Software, with or
-  without modification, are permitted provided that the following conditions
-  are met:
-  
-  Redistributions of source code of the Software may retain the above
-  copyright notice, this list of conditions and the following disclaimer.
-  
-  Redistributions in binary form of the Software may reproduce the above
-  copyright notice, this list of conditions and the following disclaimer in
-  the documentation and/or materials provided with the distribution.
-  
-  Neither the name of Intel Corporation nor the names of its contributors
-  shall be used to endorse or promote products derived from this Software
-  without specific prior written permission.
-  
-  Intel hereby grants Recipient and Licensees a non-exclusive, worldwide,
-  royalty-free patent license under Licensed Patents to make, use, sell, offer
-  to sell, import and otherwise transfer the Software, if any, in source code
-  and object code form. This license shall include changes to the Software
-  that are error corrections or other minor changes to the Software that do
-  not add functionality or features when the Software is incorporated in any
-  version of an operating system that has been distributed under the GNU
-  General Public License 2.0 or later. This patent license shall apply to the
-  combination of the Software and any operating system licensed under the GNU
-  General Public License 2.0 or later if, at the time Intel provides the
-  Software to Recipient, such addition of the Software to the then publicly
-  available versions of such operating systems available under the GNU General
-  Public License 2.0 or later (whether in gold, beta or alpha form) causes
-  such combination to be covered by the Licensed Patents. The patent license
-  shall not apply to any other combinations which include the Software. NO
-  hardware per se is licensed hereunder.
-  
-  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-  IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-  ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY
-  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-  (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-  ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED
-  AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR
-  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  
+  This program is free software; you can redistribute it and/or modify it 
+  under the terms of the GNU General Public License as published by the Free 
+  Software Foundation; either version 2 of the License, or (at your option) 
+  any later version.
+  
+  This program is distributed in the hope that it will be useful, but WITHOUT 
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
+  more details.
+  
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59 
+  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
 *******************************************************************************/
 
@@ -141,6 +96,6 @@
         readl((a)->hw_addr + E1000_##reg + ((offset) << 2)) : \
         readl((a)->hw_addr + E1000_82542_##reg + ((offset) << 2)))
 
-#define E1000_WRITE_FLUSH(a) E1000_READ_REG(a, STATUS);
+#define E1000_WRITE_FLUSH(a) ((void)E1000_READ_REG(a, STATUS))
 
 #endif /* _E1000_OSDEP_H_ */
diff -urN linux-2.4.20-pre4/drivers/net/e1000/e1000_param.c linux-2.4.20-pre5/drivers/net/e1000/e1000_param.c
--- linux-2.4.20-pre4/drivers/net/e1000/e1000_param.c	Wed Aug 28 16:36:54 2002
+++ linux-2.4.20-pre5/drivers/net/e1000/e1000_param.c	Wed Aug 28 16:38:03 2002
@@ -1,73 +1,28 @@
 /*******************************************************************************
 
-  This software program is available to you under a choice of one of two
-  licenses. You may choose to be licensed under either the GNU General Public
-  License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html,
-  or the Intel BSD + Patent License, the text of which follows:
   
-  Recipient has requested a license and Intel Corporation ("Intel") is willing
-  to grant a license for the software entitled Linux Base Driver for the
-  Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided
-  by Intel Corporation. The following definitions apply to this license:
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
   
-  "Licensed Patents" means patent claims licensable by Intel Corporation which
-  are necessarily infringed by the use of sale of the Software alone or when
-  combined with the operating system referred to below.
-  
-  "Recipient" means the party to whom Intel delivers this Software.
-  
-  "Licensee" means Recipient and those third parties that receive a license to
-  any operating system available under the GNU General Public License 2.0 or
-  later.
-  
-  Copyright (c) 1999 - 2002 Intel Corporation.
-  All rights reserved.
-  
-  The license is provided to Recipient and Recipient's Licensees under the
-  following terms.
-  
-  Redistribution and use in source and binary forms of the Software, with or
-  without modification, are permitted provided that the following conditions
-  are met:
-  
-  Redistributions of source code of the Software may retain the above
-  copyright notice, this list of conditions and the following disclaimer.
-  
-  Redistributions in binary form of the Software may reproduce the above
-  copyright notice, this list of conditions and the following disclaimer in
-  the documentation and/or materials provided with the distribution.
-  
-  Neither the name of Intel Corporation nor the names of its contributors
-  shall be used to endorse or promote products derived from this Software
-  without specific prior written permission.
-  
-  Intel hereby grants Recipient and Licensees a non-exclusive, worldwide,
-  royalty-free patent license under Licensed Patents to make, use, sell, offer
-  to sell, import and otherwise transfer the Software, if any, in source code
-  and object code form. This license shall include changes to the Software
-  that are error corrections or other minor changes to the Software that do
-  not add functionality or features when the Software is incorporated in any
-  version of an operating system that has been distributed under the GNU
-  General Public License 2.0 or later. This patent license shall apply to the
-  combination of the Software and any operating system licensed under the GNU
-  General Public License 2.0 or later if, at the time Intel provides the
-  Software to Recipient, such addition of the Software to the then publicly
-  available versions of such operating systems available under the GNU General
-  Public License 2.0 or later (whether in gold, beta or alpha form) causes
-  such combination to be covered by the Licensed Patents. The patent license
-  shall not apply to any other combinations which include the Software. NO
-  hardware per se is licensed hereunder.
-  
-  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-  IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-  ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY
-  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-  (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-  ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED
-  AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR
-  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  This program is free software; you can redistribute it and/or modify it 
+  under the terms of the GNU General Public License as published by the Free 
+  Software Foundation; either version 2 of the License, or (at your option) 
+  any later version.
+  
+  This program is distributed in the hope that it will be useful, but WITHOUT 
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
+  more details.
+  
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59 
+  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
 *******************************************************************************/
 
@@ -192,6 +147,24 @@
 
 E1000_PARAM(XsumRX, "Disable or enable Receive Checksum offload");
 
+/* Transmit Interrupt Delay in units of 1.024 microseconds
+ *
+ * Valid Range: 0-65535
+ *
+ * Default Value: 64
+ */
+
+E1000_PARAM(TxIntDelay, "Transmit Interrupt Delay");
+
+/* Transmit Absolute Interrupt Delay in units of 1.024 microseconds
+ *
+ * Valid Range: 0-65535
+ *
+ * Default Value: 0
+ */
+
+E1000_PARAM(TxAbsIntDelay, "Transmit Absolute Interrupt Delay");
+
 /* Receive Interrupt Delay in units of 1.024 microseconds
  *
  * Valid Range: 0-65535
@@ -201,6 +174,15 @@
 
 E1000_PARAM(RxIntDelay, "Receive Interrupt Delay");
 
+/* Receive Absolute Interrupt Delay in units of 1.024 microseconds
+ *
+ * Valid Range: 0-65535
+ *
+ * Default Value: 128
+ */
+
+E1000_PARAM(RxAbsIntDelay, "Receive Absolute Interrupt Delay");
+
 #define AUTONEG_ADV_DEFAULT  0x2F
 #define AUTONEG_ADV_MASK     0x2F
 #define FLOW_CONTROL_DEFAULT FLOW_CONTROL_FULL
@@ -215,11 +197,23 @@
 #define MIN_RXD                       80
 #define MAX_82544_RXD               4096
 
-#define DEFAULT_RDTR                   0
-#define DEFAULT_RADV                 128
+#define DEFAULT_RDTR                 128
+#define DEFAULT_RDTR_82544             0
 #define MAX_RXDELAY               0xFFFF
 #define MIN_RXDELAY                    0
 
+#define DEFAULT_RADV                 128
+#define MAX_RXABSDELAY            0xFFFF
+#define MIN_RXABSDELAY                 0
+
+#define DEFAULT_TIDV                  64
+#define MAX_TXDELAY               0xFFFF
+#define MIN_TXDELAY                    0
+
+#define DEFAULT_TADV                  64
+#define MAX_TXABSDELAY            0xFFFF
+#define MIN_TXABSDELAY                 0
+
 struct e1000_option {
 	enum { enable_option, range_option, list_option } type;
 	char *name;
@@ -376,21 +370,61 @@
 		e1000_validate_option(&fc, &opt);
 		adapter->hw.fc = adapter->hw.original_fc = fc;
 	}
+	{ /* Transmit Interrupt Delay */
+		char *tidv = "using default of " __MODULE_STRING(DEFAULT_TIDV);
+		struct e1000_option opt = {
+			type: range_option,
+			name: "Transmit Interrupt Delay",
+			arg: { r: { min: MIN_TXDELAY, max: MAX_TXDELAY }}
+		};
+		opt.def = DEFAULT_TIDV;
+		opt.err = tidv;
+
+		adapter->tx_int_delay = TxIntDelay[bd];
+		e1000_validate_option(&adapter->tx_int_delay, &opt);
+	}
+	{ /* Transmit Absolute Interrupt Delay */
+		char *tadv = "using default of " __MODULE_STRING(DEFAULT_TADV);
+		struct e1000_option opt = {
+			type: range_option,
+			name: "Transmit Absolute Interrupt Delay",
+			arg: { r: { min: MIN_TXABSDELAY, max: MAX_TXABSDELAY }}
+		};
+		opt.def = DEFAULT_TADV;
+		opt.err = tadv;
+
+		adapter->tx_abs_int_delay = TxAbsIntDelay[bd];
+		e1000_validate_option(&adapter->tx_abs_int_delay, &opt);
+	}
 	{ /* Receive Interrupt Delay */
 		char *rdtr = "using default of " __MODULE_STRING(DEFAULT_RDTR);
-		char *radv = "using default of " __MODULE_STRING(DEFAULT_RADV);
+		char *rdtr_82544 = "using default of "
+				   __MODULE_STRING(DEFAULT_RDTR_82544);
 		struct e1000_option opt = {
 			type: range_option,
 			name: "Receive Interrupt Delay",
 			arg: { r: { min: MIN_RXDELAY, max: MAX_RXDELAY }}
 		};
 		e1000_mac_type mac_type = adapter->hw.mac_type;
-		opt.def = mac_type < e1000_82540 ? DEFAULT_RDTR : DEFAULT_RADV;
-		opt.err = mac_type < e1000_82540 ? rdtr : radv;
+		opt.def = mac_type > e1000_82544 ? DEFAULT_RDTR : 0;
+		opt.err = mac_type > e1000_82544 ? rdtr : rdtr_82544;
 
 		adapter->rx_int_delay = RxIntDelay[bd];
 		e1000_validate_option(&adapter->rx_int_delay, &opt);
 	}
+	{ /* Receive Absolute Interrupt Delay */
+		char *radv = "using default of " __MODULE_STRING(DEFAULT_RADV);
+		struct e1000_option opt = {
+			type: range_option,
+			name: "Receive Absolute Interrupt Delay",
+			arg: { r: { min: MIN_RXABSDELAY, max: MAX_RXABSDELAY }}
+		};
+		opt.def = DEFAULT_RADV;
+		opt.err = radv;
+
+		adapter->rx_abs_int_delay = RxAbsIntDelay[bd];
+		e1000_validate_option(&adapter->rx_abs_int_delay, &opt);
+	}
 	
 	switch(adapter->hw.media_type) {
 	case e1000_media_type_fiber:
diff -urN linux-2.4.20-pre4/drivers/net/e1000/e1000_proc.c linux-2.4.20-pre5/drivers/net/e1000/e1000_proc.c
--- linux-2.4.20-pre4/drivers/net/e1000/e1000_proc.c	Wed Aug 28 16:36:54 2002
+++ linux-2.4.20-pre5/drivers/net/e1000/e1000_proc.c	Wed Aug 28 16:38:03 2002
@@ -1,73 +1,28 @@
 /*******************************************************************************
 
-  This software program is available to you under a choice of one of two
-  licenses. You may choose to be licensed under either the GNU General Public
-  License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html,
-  or the Intel BSD + Patent License, the text of which follows:
-  
-  Recipient has requested a license and Intel Corporation ("Intel") is willing
-  to grant a license for the software entitled Linux Base Driver for the
-  Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided
-  by Intel Corporation. The following definitions apply to this license:
-  
-  "Licensed Patents" means patent claims licensable by Intel Corporation which
-  are necessarily infringed by the use of sale of the Software alone or when
-  combined with the operating system referred to below.
-  
-  "Recipient" means the party to whom Intel delivers this Software.
-  
-  "Licensee" means Recipient and those third parties that receive a license to
-  any operating system available under the GNU General Public License 2.0 or
-  later.
-  
-  Copyright (c) 1999 - 2002 Intel Corporation.
-  All rights reserved.
-  
-  The license is provided to Recipient and Recipient's Licensees under the
-  following terms.
-  
-  Redistribution and use in source and binary forms of the Software, with or
-  without modification, are permitted provided that the following conditions
-  are met:
-  
-  Redistributions of source code of the Software may retain the above
-  copyright notice, this list of conditions and the following disclaimer.
-  
-  Redistributions in binary form of the Software may reproduce the above
-  copyright notice, this list of conditions and the following disclaimer in
-  the documentation and/or materials provided with the distribution.
-  
-  Neither the name of Intel Corporation nor the names of its contributors
-  shall be used to endorse or promote products derived from this Software
-  without specific prior written permission.
-  
-  Intel hereby grants Recipient and Licensees a non-exclusive, worldwide,
-  royalty-free patent license under Licensed Patents to make, use, sell, offer
-  to sell, import and otherwise transfer the Software, if any, in source code
-  and object code form. This license shall include changes to the Software
-  that are error corrections or other minor changes to the Software that do
-  not add functionality or features when the Software is incorporated in any
-  version of an operating system that has been distributed under the GNU
-  General Public License 2.0 or later. This patent license shall apply to the
-  combination of the Software and any operating system licensed under the GNU
-  General Public License 2.0 or later if, at the time Intel provides the
-  Software to Recipient, such addition of the Software to the then publicly
-  available versions of such operating systems available under the GNU General
-  Public License 2.0 or later (whether in gold, beta or alpha form) causes
-  such combination to be covered by the Licensed Patents. The patent license
-  shall not apply to any other combinations which include the Software. NO
-  hardware per se is licensed hereunder.
-  
-  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-  IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-  ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY
-  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-  (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-  ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED
-  AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR
-  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  
+  This program is free software; you can redistribute it and/or modify it 
+  under the terms of the GNU General Public License as published by the Free 
+  Software Foundation; either version 2 of the License, or (at your option) 
+  any later version.
+  
+  This program is distributed in the hope that it will be useful, but WITHOUT 
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
+  more details.
+  
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59 
+  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
 *******************************************************************************/
 
diff -urN linux-2.4.20-pre4/drivers/net/hamradio/soundmodem/sm_sbc.c linux-2.4.20-pre5/drivers/net/hamradio/soundmodem/sm_sbc.c
--- linux-2.4.20-pre4/drivers/net/hamradio/soundmodem/sm_sbc.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre5/drivers/net/hamradio/soundmodem/sm_sbc.c	Wed Aug 28 16:38:04 2002
@@ -47,36 +47,7 @@
  */
 #include <linux/version.h>
 
-#if LINUX_VERSION_CODE >= 0x20100
 #include <asm/uaccess.h>
-#else
-#include <asm/segment.h>
-#include <linux/mm.h>
-
-#undef put_user
-#undef get_user
-
-#define put_user(x,ptr) ({ __put_user((unsigned long)(x),(ptr),sizeof(*(ptr))); 0; })
-#define get_user(x,ptr) ({ x = ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr)))); 0; })
-
-static inline int copy_from_user(void *to, const void *from, unsigned long n)
-{
-        int i = verify_area(VERIFY_READ, from, n);
-        if (i)
-                return i;
-        memcpy_fromfs(to, from, n);
-        return 0;
-}
-
-static inline int copy_to_user(void *to, const void *from, unsigned long n)
-{
-        int i = verify_area(VERIFY_WRITE, to, n);
-        if (i)
-                return i;
-        memcpy_tofs(to, from, n);
-        return 0;
-}
-#endif
 
 /* --------------------------------------------------------------------- */
 
diff -urN linux-2.4.20-pre4/drivers/net/hamradio/soundmodem/sm_wss.c linux-2.4.20-pre5/drivers/net/hamradio/soundmodem/sm_wss.c
--- linux-2.4.20-pre4/drivers/net/hamradio/soundmodem/sm_wss.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre5/drivers/net/hamradio/soundmodem/sm_wss.c	Wed Aug 28 16:38:04 2002
@@ -45,37 +45,7 @@
  * This will go in 2.2
  */
 #include <linux/version.h>
-
-#if LINUX_VERSION_CODE >= 0x20100
 #include <asm/uaccess.h>
-#else
-#include <asm/segment.h>
-#include <linux/mm.h>
-
-#undef put_user
-#undef get_user
-
-#define put_user(x,ptr) ({ __put_user((unsigned long)(x),(ptr),sizeof(*(ptr))); 0; })
-#define get_user(x,ptr) ({ x = ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr)))); 0; })
-
-static inline int copy_from_user(void *to, const void *from, unsigned long n)
-{
-        int i = verify_area(VERIFY_READ, from, n);
-        if (i)
-                return i;
-        memcpy_fromfs(to, from, n);
-        return 0;
-}
-
-static inline int copy_to_user(void *to, const void *from, unsigned long n)
-{
-        int i = verify_area(VERIFY_WRITE, to, n);
-        if (i)
-                return i;
-        memcpy_tofs(to, from, n);
-        return 0;
-}
-#endif
 
 /* --------------------------------------------------------------------- */
 
diff -urN linux-2.4.20-pre4/drivers/net/irda/irda-usb.c linux-2.4.20-pre5/drivers/net/irda/irda-usb.c
--- linux-2.4.20-pre4/drivers/net/irda/irda-usb.c	Wed Aug 28 16:36:54 2002
+++ linux-2.4.20-pre5/drivers/net/irda/irda-usb.c	Wed Aug 28 16:38:05 2002
@@ -160,12 +160,12 @@
 		    (!force) && (self->speed != -1)) {
 			/* No speed and xbofs change here
 			 * (we'll do it later in the write callback) */
-			IRDA_DEBUG(2, __FUNCTION__ "(), not changing speed yet\n");
+			IRDA_DEBUG(2, "%s(), not changing speed yet\n", __FUNCTION__);
 			*header = 0;
 			return;
 		}
 
-		IRDA_DEBUG(2, __FUNCTION__ "(), changing speed to %d\n", self->new_speed);
+		IRDA_DEBUG(2, "%s(), changing speed to %d\n", __FUNCTION__, self->new_speed);
 		self->speed = self->new_speed;
 		self->new_speed = -1;
 
@@ -206,7 +206,7 @@
 	
 	/* Set the negotiated additional XBOFS */
 	if (self->new_xbofs != -1) {
-		IRDA_DEBUG(2, __FUNCTION__ "(), changing xbofs to %d\n", self->new_xbofs);
+		IRDA_DEBUG(2, "%s(), changing xbofs to %d\n", __FUNCTION__, self->new_xbofs);
 		self->xbofs = self->new_xbofs;
 		self->new_xbofs = -1;
 
@@ -250,16 +250,16 @@
 static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self)
 {
 	__u8 *frame;
-	struct urb *purb;
 	int ret;
+	struct urb *purb;
 
-	IRDA_DEBUG(2, __FUNCTION__ "(), speed=%d, xbofs=%d\n",
-		   self->new_speed, self->new_xbofs);
+	IRDA_DEBUG(2, "%s(), speed=%d, xbofs=%d\n",
+		__FUNCTION__, self->new_speed, self->new_xbofs);
 
 	/* Grab the speed URB */
 	purb = &self->speed_urb;
 	if (purb->status != USB_ST_NOERROR) {
-		WARNING(__FUNCTION__ "(), URB still in use!\n");
+		WARNING("%s(), URB still in use!\n", __FUNCTION__);
 		return;
 	}
 
@@ -279,7 +279,7 @@
 	purb->timeout = MSECS_TO_JIFFIES(100);
 
 	if ((ret = usb_submit_urb(purb))) {
-		WARNING(__FUNCTION__ "(), failed Speed URB\n");
+		WARNING("%s(), failed Speed URB\n", __FUNCTION__);
 	}
 }
 
@@ -291,18 +291,18 @@
 {
 	struct irda_usb_cb *self = purb->context;
 	
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
 	/* We should always have a context */
 	if (self == NULL) {
-		WARNING(__FUNCTION__ "(), Bug : self == NULL\n");
+		WARNING("%s(), Bug : self == NULL\n", __FUNCTION__);
 		return;
 	}
 
 	/* Check for timeout and other USB nasties */
 	if(purb->status != USB_ST_NOERROR) {
 		/* I get a lot of -ECONNABORTED = -103 here - Jean II */
-		IRDA_DEBUG(0, __FUNCTION__ "(), URB complete status %d, transfer_flags 0x%04X\n", purb->status, purb->transfer_flags);
+		IRDA_DEBUG(0, "%s(), URB complete status %d, transfer_flags 0x%04X\n", __FUNCTION__, purb->status, purb->transfer_flags);
 
 		/* Don't do anything here, that might confuse the USB layer.
 		 * Instead, we will wait for irda_usb_net_timeout(), the
@@ -343,7 +343,7 @@
 	 * We need to check self->present under the spinlock because
 	 * of irda_usb_disconnect() is synchronous - Jean II */
 	if ((!self) || (!self->present)) {
-		IRDA_DEBUG(0, __FUNCTION__ "(), Device is gone...\n");
+		IRDA_DEBUG(0, "%s(), Device is gone...\n", __FUNCTION__);
 		spin_unlock_irqrestore(&self->lock, flags);
 		return 1;	/* Failed */
 	}
@@ -377,7 +377,7 @@
 	}
 
 	if (purb->status != USB_ST_NOERROR) {
-		WARNING(__FUNCTION__ "(), URB still in use!\n");
+		WARNING("%s(), URB still in use!\n", __FUNCTION__);
 		goto drop;
 	}
 
@@ -386,9 +386,9 @@
 	 * Also, we don't use directly skb_cow(), because it require
 	 * headroom >= 16, which force unnecessary copies - Jean II */
 	if (skb_headroom(skb) < USB_IRDA_HEADER) {
-		IRDA_DEBUG(0, __FUNCTION__ "(), Insuficient skb headroom.\n");
+		IRDA_DEBUG(0, "%s(), Insuficient skb headroom.\n", __FUNCTION__);
 		if (skb_cow(skb, USB_IRDA_HEADER)) {
-			WARNING(__FUNCTION__ "(), failed skb_cow() !!!\n");
+			WARNING("%s(), failed skb_cow() !!!\n", __FUNCTION__);
 			goto drop;
 		}
 	}
@@ -459,7 +459,7 @@
 	
 	/* Ask USB to send the packet */
 	if ((res = usb_submit_urb(purb))) {
-		WARNING(__FUNCTION__ "(), failed Tx URB\n");
+		WARNING("%s(), failed Tx URB\n", __FUNCTION__);
 		self->stats.tx_errors++;
 		/* Let USB recover : We will catch that in the watchdog */
 		/*netif_start_queue(netdev);*/
@@ -491,11 +491,11 @@
 	struct sk_buff *skb = purb->context;
 	struct irda_usb_cb *self = ((struct irda_skb_cb *) skb->cb)->context;
 	
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
 	/* We should always have a context */
 	if (self == NULL) {
-		WARNING(__FUNCTION__ "(), Bug : self == NULL\n");
+		WARNING("%s(), Bug : self == NULL\n", __FUNCTION__);
 		return;
 	}
 
@@ -506,7 +506,7 @@
 	/* Check for timeout and other USB nasties */
 	if(purb->status != USB_ST_NOERROR) {
 		/* I get a lot of -ECONNABORTED = -103 here - Jean II */
-		IRDA_DEBUG(0, __FUNCTION__ "(), URB complete status %d, transfer_flags 0x%04X\n", purb->status, purb->transfer_flags);
+		IRDA_DEBUG(0, "%s(), URB complete status %d, transfer_flags 0x%04X\n", __FUNCTION__, purb->status, purb->transfer_flags);
 
 		/* Don't do anything here, that might confuse the USB layer,
 		 * and we could go in recursion and blow the kernel stack...
@@ -525,14 +525,14 @@
 
 	/* If the network is closed, stop everything */
 	if ((!self->netopen) || (!self->present)) {
-		IRDA_DEBUG(0, __FUNCTION__ "(), Network is gone...\n");
+		IRDA_DEBUG(0, "%s(), Network is gone...\n", __FUNCTION__);
 		spin_unlock_irqrestore(&self->lock, flags);
 		return;
 	}
 
 	/* If we need to change the speed or xbofs, do it now */
 	if ((self->new_speed != -1) || (self->new_xbofs != -1)) {
-		IRDA_DEBUG(1, __FUNCTION__ "(), Changing speed now...\n");
+		IRDA_DEBUG(1, "%s(), Changing speed now...\n", __FUNCTION__);
 		irda_usb_change_speed_xbofs(self);
 	} else {
 		/* Otherwise, allow the stack to send more packets */
@@ -557,13 +557,13 @@
 	struct urb *purb;
 	int	done = 0;	/* If we have made any progress */
 
-	IRDA_DEBUG(0, __FUNCTION__ "(), Network layer thinks we timed out!\n");
+	IRDA_DEBUG(0, "%s(), Network layer thinks we timed out!\n", __FUNCTION__);
 
 	/* Protect us from USB callbacks, net Tx and else. */
 	spin_lock_irqsave(&self->lock, flags);
 
 	if ((!self) || (!self->present)) {
-		WARNING(__FUNCTION__ "(), device not present!\n");
+		WARNING("%s(), device not present!\n", __FUNCTION__);
 		netif_stop_queue(netdev);
 		spin_unlock_irqrestore(&self->lock, flags);
 		return;
@@ -715,11 +715,11 @@
 	struct irda_skb_cb *cb;
 	int ret;
 
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
 	/* Check that we have an urb */
 	if (!purb) {
-		WARNING(__FUNCTION__ "(), Bug : purb == NULL\n");
+		WARNING("%s(), Bug : purb == NULL\n", __FUNCTION__);
 		return;
 	}
 
@@ -729,7 +729,7 @@
 		if (!skb) {
 			/* If this ever happen, we are in deep s***.
 			 * Basically, the Rx path will stop... */
-			WARNING(__FUNCTION__ "(), Failed to allocate Rx skb\n");
+			WARNING("%s(), Failed to allocate Rx skb\n", __FUNCTION__);
 			return;
 		}
 	} else  {
@@ -759,7 +759,7 @@
 	if (ret) {
 		/* If this ever happen, we are in deep s***.
 		 * Basically, the Rx path will stop... */
-		WARNING(__FUNCTION__ "(), Failed to submit Rx URB %d\n", ret);
+		WARNING("%s(), Failed to submit Rx URB %d\n", __FUNCTION__, ret);
 	}
 }
 
@@ -777,7 +777,7 @@
 	struct irda_skb_cb *cb;
 	struct sk_buff *new;
 	
-	IRDA_DEBUG(2, __FUNCTION__ "(), len=%d\n", purb->actual_length);
+	IRDA_DEBUG(2, "%s(), len=%d\n", __FUNCTION__, purb->actual_length);
 	
 	/* Find ourselves */
 	cb = (struct irda_skb_cb *) skb->cb;
@@ -787,7 +787,7 @@
 
 	/* If the network is closed or the device gone, stop everything */
 	if ((!self->netopen) || (!self->present)) {
-		IRDA_DEBUG(0, __FUNCTION__ "(), Network is gone!\n");
+		IRDA_DEBUG(0, "%s(), Network is gone!\n", __FUNCTION__);
 		/* Don't re-submit the URB : will stall the Rx path */
 		return;
 	}
@@ -800,13 +800,13 @@
 			self->stats.rx_crc_errors++;	
 			break;
 		case -ECONNRESET:		/* -104 */
-			IRDA_DEBUG(0, __FUNCTION__ "(), Connection Reset (-104), transfer_flags 0x%04X \n", purb->transfer_flags);
+			IRDA_DEBUG(0, "%s(), Connection Reset (-104), transfer_flags 0x%04X \n", __FUNCTION__, purb->transfer_flags);
 			/* uhci_cleanup_unlink() is going to kill the Rx
 			 * URB just after we return. No problem, at this
 			 * point the URB will be idle ;-) - Jean II */
 			break;
 		default:
-			IRDA_DEBUG(0, __FUNCTION__ "(), RX status %d,transfer_flags 0x%04X \n", purb->status, purb->transfer_flags);
+			IRDA_DEBUG(0, "%s(), RX status %d,transfer_flags 0x%04X \n", __FUNCTION__, purb->status, purb->transfer_flags);
 			break;
 		}
 		goto done;
@@ -814,7 +814,7 @@
 	
 	/* Check for empty frames */
 	if (purb->actual_length <= USB_IRDA_HEADER) {
-		WARNING(__FUNCTION__ "(), empty frame!\n");
+		WARNING("%s(), empty frame!\n", __FUNCTION__);
 		goto done;
 	}
 
@@ -918,7 +918,7 @@
  */
 static int irda_usb_net_init(struct net_device *dev)
 {
-	IRDA_DEBUG(1, __FUNCTION__ "()\n");
+	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
 	
 	/* Set up to be a normal IrDA network device driver */
 	irda_device_setup(dev);
@@ -942,7 +942,7 @@
 	char	hwname[16];
 	int i;
 	
-	IRDA_DEBUG(1, __FUNCTION__ "()\n");
+	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
 
 	ASSERT(netdev != NULL, return -1;);
 	self = (struct irda_usb_cb *) netdev->priv;
@@ -950,7 +950,7 @@
 
 	/* Can only open the device if it's there */
 	if(!self->present) {
-		WARNING(__FUNCTION__ "(), device not present!\n");
+		WARNING("%s(), device not present!\n", __FUNCTION__);
 		return -1;
 	}
 
@@ -1006,7 +1006,7 @@
 	struct irda_usb_cb *self;
 	int	i;
 
-	IRDA_DEBUG(1, __FUNCTION__ "()\n");
+	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
 
 	ASSERT(netdev != NULL, return -1;);
 	self = (struct irda_usb_cb *) netdev->priv;
@@ -1062,7 +1062,7 @@
 	self = dev->priv;
 	ASSERT(self != NULL, return -1;);
 
-	IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd);
+	IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd);
 
 	switch (cmd) {
 	case SIOCSBANDWIDTH: /* Set bandwidth */
@@ -1120,7 +1120,7 @@
 {
 	struct irda_class_desc *desc;
 
-	IRDA_DEBUG(3, __FUNCTION__ "()\n");
+	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
 	
 	desc = self->irda_desc;
 	
@@ -1133,7 +1133,8 @@
 	self->qos.window_size.bits     = desc->bmWindowSize;
 	self->qos.data_size.bits       = desc->bmDataSize;
 
-	IRDA_DEBUG(0, __FUNCTION__ "(), dongle says speed=0x%X, size=0x%X, window=0x%X, bofs=0x%X, turn=0x%X\n", self->qos.baud_rate.bits, self->qos.data_size.bits, self->qos.window_size.bits, self->qos.additional_bofs.bits, self->qos.min_turn_time.bits);
+	IRDA_DEBUG(0, "%s(), dongle says speed=0x%X, size=0x%X, window=0x%X, bofs=0x%X, turn=0x%X\n", 
+		__FUNCTION__, self->qos.baud_rate.bits, self->qos.data_size.bits, self->qos.window_size.bits, self->qos.additional_bofs.bits, self->qos.min_turn_time.bits);
 
 	/* Don't always trust what the dongle tell us */
 	if(self->capability & IUC_SIR_ONLY)
@@ -1177,7 +1178,7 @@
 	struct net_device *netdev;
 	int err;
 
-	IRDA_DEBUG(1, __FUNCTION__ "()\n");
+	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
 
 	spin_lock_init(&self->lock);
 
@@ -1197,7 +1198,7 @@
 
 	/* Create a network device for us */
 	if (!(netdev = dev_alloc("irda%d", &err))) {
-		ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
+		ERROR("%s(), dev_alloc() failed!\n", __FUNCTION__);
 		return -1;
 	}
 	self->netdev = netdev;
@@ -1217,7 +1218,7 @@
 	err = register_netdevice(netdev);
 	rtnl_unlock();
 	if (err) {
-		ERROR(__FUNCTION__ "(), register_netdev() failed!\n");
+		ERROR("%s(), register_netdev() failed!\n", __FUNCTION__);
 		return -1;
 	}
 	MESSAGE("IrDA: Registered device %s\n", netdev->name);
@@ -1232,7 +1233,7 @@
  */
 static inline int irda_usb_close(struct irda_usb_cb *self)
 {
-	IRDA_DEBUG(1, __FUNCTION__ "()\n");
+	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
 
 	ASSERT(self != NULL, return -1;);
 
@@ -1314,12 +1315,13 @@
 				/* This is our interrupt endpoint */
 				self->bulk_int_ep = ep;
 			} else {
-				ERROR(__FUNCTION__ "(), Unrecognised endpoint %02X.\n", ep);
+				ERROR("%s(), Unrecognised endpoint %02X.\n", __FUNCTION__, ep);
 			}
 		}
 	}
 
-	IRDA_DEBUG(0, __FUNCTION__ "(), And our endpoints are : in=%02X, out=%02X (%d), int=%02X\n", self->bulk_in_ep, self->bulk_out_ep, self->bulk_out_mtu, self->bulk_int_ep);
+	IRDA_DEBUG(0, "%s(), And our endpoints are : in=%02X, out=%02X (%d), int=%02X\n",
+		__FUNCTION__, self->bulk_in_ep, self->bulk_out_ep, self->bulk_out_mtu, self->bulk_int_ep);
 	/* Should be 8, 16, 32 or 64 bytes */
 	ASSERT(self->bulk_out_mtu == 64, ;);
 
@@ -1381,7 +1383,7 @@
 		USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
 		0, ifnum, desc, sizeof(*desc), MSECS_TO_JIFFIES(500));
 	
-	IRDA_DEBUG(1, __FUNCTION__ "(), ret=%d\n", ret);
+	IRDA_DEBUG(1, "%s(), ret=%d\n", __FUNCTION__, ret);
 	if (ret < sizeof(*desc)) {
 		WARNING("usb-irda: class_descriptor read %s (%d)\n",
 			(ret<0) ? "failed" : "too short", ret);
@@ -1440,7 +1442,7 @@
 		if((irda->usbdev != NULL) &&
 		   (irda->present == 0) &&
 		   (irda->netopen == 0)) {
-			IRDA_DEBUG(0, __FUNCTION__ "(), found a zombie instance !!!\n");
+			IRDA_DEBUG(0, "%s(), found a zombie instance !!!\n", __FUNCTION__);
 			irda_usb_disconnect(irda->usbdev, (void *) irda);
 		}
 	}
@@ -1480,10 +1482,10 @@
 			break;
 		case USB_ST_STALL:		/* -EPIPE = -32 */
 			usb_clear_halt(dev, usb_sndctrlpipe(dev, 0));
-			IRDA_DEBUG(0, __FUNCTION__ "(), Clearing stall on control interface\n" );
+			IRDA_DEBUG(0, "%s(), Clearing stall on control interface\n", __FUNCTION__);
 			break;
 		default:
-			IRDA_DEBUG(0, __FUNCTION__ "(), Unknown error %d\n", ret);
+			IRDA_DEBUG(0, "%s(), Unknown error %d\n", __FUNCTION__, ret);
 			return NULL;
 			break;
 	}
@@ -1492,7 +1494,7 @@
 	interface = &dev->actconfig->interface[ifnum].altsetting[0];
 	if(!irda_usb_parse_endpoints(self, interface->endpoint,
 				     interface->bNumEndpoints)) {
-		ERROR(__FUNCTION__ "(), Bogus endpoints...\n");
+		ERROR("%s(), Bogus endpoints...\n", __FUNCTION__);
 		return NULL;
 	}
 
@@ -1531,7 +1533,7 @@
 	struct irda_usb_cb *self = (struct irda_usb_cb *) ptr;
 	int i;
 
-	IRDA_DEBUG(1, __FUNCTION__ "()\n");
+	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
 
 	/* Make sure that the Tx path is not executing. - Jean II */
 	spin_lock_irqsave(&self->lock, flags);
@@ -1564,7 +1566,7 @@
 	irda_usb_close(self);
 	/* No longer attached to USB bus */
 	self->usbdev = NULL;
-	IRDA_DEBUG(0, __FUNCTION__ "(), USB IrDA Disconnected\n");
+	IRDA_DEBUG(0, "%s(), USB IrDA Disconnected\n", __FUNCTION__);
 }
 
 /*------------------------------------------------------------------*/
@@ -1613,7 +1615,7 @@
 		irda = &irda_instance[i];
 		/* If the Device is zombie */
 		if((irda->usbdev != NULL) && (irda->present == 0)) {
-			IRDA_DEBUG(0, __FUNCTION__ "(), disconnect zombie now !\n");
+			IRDA_DEBUG(0, "%s(), disconnect zombie now !\n", __FUNCTION__);
 			irda_usb_disconnect(irda->usbdev, (void *) irda);
 		}
 	}
diff -urN linux-2.4.20-pre4/drivers/net/pcmcia/3c574_cs.c linux-2.4.20-pre5/drivers/net/pcmcia/3c574_cs.c
--- linux-2.4.20-pre4/drivers/net/pcmcia/3c574_cs.c	Wed Aug 28 16:36:54 2002
+++ linux-2.4.20-pre5/drivers/net/pcmcia/3c574_cs.c	Wed Aug 28 16:38:05 2002
@@ -86,6 +86,8 @@
 #include <linux/skbuff.h>
 #include <linux/if_arp.h>
 #include <linux/ioport.h>
+#include <linux/ethtool.h>
+#include <asm/uaccess.h>
 
 #include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
@@ -1189,6 +1191,26 @@
 	return worklimit;
 }
 
+static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+	u32 ethcmd;
+		
+	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
+		return -EFAULT;
+	
+	switch (ethcmd) {
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
+		strncpy(info.driver, "3c574_cs", sizeof(info.driver)-1);
+		if (copy_to_user(useraddr, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+	}
+	
+	return -EOPNOTSUPP;
+}
+
 /* Provide ioctl() calls to examine the MII xcvr state. */
 static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
@@ -1202,6 +1224,8 @@
 		  data[0], data[1], data[2], data[3]);
 
     switch(cmd) {
+	case SIOCETHTOOL:
+		return netdev_ethtool_ioctl(dev, (void *)rq->ifr_data);
 	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
 		data[0] = phy;
 	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */
diff -urN linux-2.4.20-pre4/drivers/net/pcmcia/axnet_cs.c linux-2.4.20-pre5/drivers/net/pcmcia/axnet_cs.c
--- linux-2.4.20-pre4/drivers/net/pcmcia/axnet_cs.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.20-pre5/drivers/net/pcmcia/axnet_cs.c	Wed Aug 28 16:38:05 2002
@@ -34,9 +34,11 @@
 #include <linux/timer.h>
 #include <linux/delay.h>
 #include <linux/spinlock.h>
+#include <linux/ethtool.h>
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/byteorder.h>
+#include <asm/uaccess.h>
 
 #include <linux/netdevice.h>
 #include "../8390.h"
@@ -790,6 +792,26 @@
     add_timer(&info->watchdog);
 }
 
+static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+	u32 ethcmd;
+		
+	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
+		return -EFAULT;
+	
+	switch (ethcmd) {
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
+		strncpy(info.driver, "axnet_cs", sizeof(info.driver)-1);
+		if (copy_to_user(useraddr, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+	}
+	
+	return -EOPNOTSUPP;
+}
+
 /*====================================================================*/
 
 static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
@@ -798,6 +820,8 @@
     u16 *data = (u16 *)&rq->ifr_data;
     ioaddr_t mii_addr = dev->base_addr + AXNET_MII_EEP;
     switch (cmd) {
+    case SIOCETHTOOL:
+        return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
     case SIOCDEVPRIVATE:
 	data[0] = info->phy_id;
     case SIOCDEVPRIVATE+1:
diff -urN linux-2.4.20-pre4/drivers/net/pcmcia/ibmtr_cs.c linux-2.4.20-pre5/drivers/net/pcmcia/ibmtr_cs.c
--- linux-2.4.20-pre4/drivers/net/pcmcia/ibmtr_cs.c	Sun Sep 30 12:26:07 2001
+++ linux-2.4.20-pre5/drivers/net/pcmcia/ibmtr_cs.c	Wed Aug 28 16:38:06 2002
@@ -53,6 +53,8 @@
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/module.h>
+#include <linux/ethtool.h>
+#include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/system.h>
 
@@ -164,6 +166,37 @@
     CardServices(ReportError, handle, &err);
 }
 
+static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+	u32 ethcmd;
+		
+	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
+		return -EFAULT;
+	
+	switch (ethcmd) {
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
+		strncpy(info.driver, "ibmtr_cs", sizeof(info.driver)-1);
+		if (copy_to_user(useraddr, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+	}
+	
+	return -EOPNOTSUPP;
+}
+
+static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+
+       switch(cmd) {
+       case SIOCETHTOOL:
+	       return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+	default:
+	    return -EOPNOTSUPP;
+	}
+}
+
 /*======================================================================
 
     ibmtr_attach() creates an "instance" of the driver, allocating
@@ -216,6 +249,7 @@
     link->irq.Instance = info->dev = dev;
     
     dev->init = &ibmtr_probe;
+    dev->do_ioctl = &private_ioctl;
 
     /* Register with Card Services */
     link->next = dev_list;
diff -urN linux-2.4.20-pre4/drivers/net/pcmcia/pcnet_cs.c linux-2.4.20-pre5/drivers/net/pcmcia/pcnet_cs.c
--- linux-2.4.20-pre4/drivers/net/pcmcia/pcnet_cs.c	Tue Nov 13 09:02:30 2001
+++ linux-2.4.20-pre5/drivers/net/pcmcia/pcnet_cs.c	Wed Aug 28 16:38:06 2002
@@ -37,9 +37,11 @@
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/delay.h>
+#include <linux/ethtool.h>
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/byteorder.h>
+#include <asm/uaccess.h>
 
 #include <linux/netdevice.h>
 #include <../drivers/net/8390.h>
@@ -115,6 +117,7 @@
 static int pcnet_open(struct net_device *dev);
 static int pcnet_close(struct net_device *dev);
 static int ei_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static int do_ioctl_light(struct net_device *dev, struct ifreq *rq, int cmd);
 static void ei_irq_wrapper(int irq, void *dev_id, struct pt_regs *regs);
 static void ei_watchdog(u_long arg);
 static void pcnet_reset_8390(struct net_device *dev);
@@ -772,8 +775,10 @@
 	       dev->name, ((info->flags & IS_DL10022) ? 22 : 19), id);
 	if (info->pna_phy)
 	    printk("PNA, ");
-    } else
+    } else {
 	printk(KERN_INFO "%s: NE2000 Compatible: ", dev->name);
+ 	dev->do_ioctl = &do_ioctl_light;	
+    }
     printk("io %#3lx, irq %d,", dev->base_addr, dev->irq);
     if (info->flags & USE_SHMEM)
 	printk (" mem %#5lx,", dev->mem_start);
@@ -1206,12 +1211,37 @@
 
 /*====================================================================*/
 
+static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+	u32 ethcmd;
+	
+	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
+		return -EFAULT;
+	
+	switch (ethcmd) {
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
+		strncpy(info.driver, "pcnet_cs", sizeof(info.driver)-1);
+		if (copy_to_user(useraddr, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+	}
+	
+	return -EOPNOTSUPP;
+}
+
+/*====================================================================*/
+
+
 static int ei_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
     pcnet_dev_t *info = (pcnet_dev_t *)dev;
     u16 *data = (u16 *)&rq->ifr_data;
     ioaddr_t mii_addr = dev->base_addr + DLINK_GPIO;
     switch (cmd) {
+    case SIOCETHTOOL:
+        return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
     case SIOCDEVPRIVATE:
 	data[0] = info->phy_id;
     case SIOCDEVPRIVATE+1:
@@ -1227,6 +1257,17 @@
 }
 
 /*====================================================================*/
+
+static int do_ioctl_light(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+    switch (cmd) {
+        case SIOCETHTOOL:
+            return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+    }	    
+    return -EOPNOTSUPP;    
+}
+
+/*====================================================================*/
 
 static void dma_get_8390_hdr(struct net_device *dev,
 			     struct e8390_pkt_hdr *hdr,
diff -urN linux-2.4.20-pre4/drivers/net/pcmcia/ray_cs.c linux-2.4.20-pre5/drivers/net/pcmcia/ray_cs.c
--- linux-2.4.20-pre4/drivers/net/pcmcia/ray_cs.c	Wed Aug 28 16:36:54 2002
+++ linux-2.4.20-pre5/drivers/net/pcmcia/ray_cs.c	Wed Aug 28 16:38:06 2002
@@ -48,6 +48,8 @@
 #include <linux/if_arp.h>
 #include <linux/ioport.h>
 #include <linux/skbuff.h>
+#include <linux/ethtool.h>
+#include <asm/uaccess.h>
 
 #include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
@@ -1224,7 +1226,32 @@
         }
     }
 } /* end encapsulate_frame */
+
+
 /*===========================================================================*/
+
+static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+	u32 ethcmd;
+		
+	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
+		return -EFAULT;
+	
+	switch (ethcmd) {
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
+		strncpy(info.driver, "ray_cs", sizeof(info.driver)-1);
+		if (copy_to_user(useraddr, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+	}
+	
+	return -EOPNOTSUPP;
+}
+
+/*====================================================================*/
+
 static int ray_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
     ray_dev_t *local = (ray_dev_t *)dev->priv;
@@ -1242,6 +1269,10 @@
     /* Validate the command */
     switch (cmd)
     {
+    case SIOCETHTOOL:
+      err = netdev_ethtool_ioctl(dev, (void *) ifr->ifr_data);
+      break;
+
 #if WIRELESS_EXT > 7
       /* --------------- WIRELESS EXTENSIONS --------------- */
       /* Get name */
diff -urN linux-2.4.20-pre4/drivers/net/pcmcia/wavelan_cs.c linux-2.4.20-pre5/drivers/net/pcmcia/wavelan_cs.c
--- linux-2.4.20-pre4/drivers/net/pcmcia/wavelan_cs.c	Wed Aug 28 16:36:54 2002
+++ linux-2.4.20-pre5/drivers/net/pcmcia/wavelan_cs.c	Wed Aug 28 16:38:06 2002
@@ -63,6 +63,8 @@
  *
  */
 
+#include <linux/ethtool.h>
+#include <asm/uaccess.h>
 #include "wavelan_cs.h"		/* Private header */
 
 /************************* MISC SUBROUTINES **************************/
@@ -1889,6 +1891,26 @@
 }
 #endif	/* HISTOGRAM */
 
+static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+	u32 ethcmd;
+		
+	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
+		return -EFAULT;
+	
+	switch (ethcmd) {
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
+		strncpy(info.driver, "wavelan_cs", sizeof(info.driver)-1);
+		if (copy_to_user(useraddr, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+	}
+	
+	return -EOPNOTSUPP;
+}
+
 /*------------------------------------------------------------------*/
 /*
  * Perform ioctl : config & info stuff
@@ -1911,6 +1933,9 @@
   printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, cmd);
 #endif
 
+  if (cmd == SIOCETHTOOL)
+    return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+
   /* Disable interrupts & save flags */
   wv_splhi(lp, &flags);
 
diff -urN linux-2.4.20-pre4/drivers/net/pcmcia/xirc2ps_cs.c linux-2.4.20-pre5/drivers/net/pcmcia/xirc2ps_cs.c
--- linux-2.4.20-pre4/drivers/net/pcmcia/xirc2ps_cs.c	Wed Aug 28 16:36:54 2002
+++ linux-2.4.20-pre5/drivers/net/pcmcia/xirc2ps_cs.c	Wed Aug 28 16:38:08 2002
@@ -74,9 +74,11 @@
 #include <linux/interrupt.h>
 #include <linux/in.h>
 #include <linux/delay.h>
+#include <linux/ethtool.h>
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
+#include <asm/uaccess.h>
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -1715,6 +1717,26 @@
     return 0;
 }
 
+static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+	u32 ethcmd;
+		
+	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
+		return -EFAULT;
+	
+	switch (ethcmd) {
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
+		strncpy(info.driver, "xirc2ps_cs", sizeof(info.driver)-1);
+		if (copy_to_user(useraddr, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+	}
+	
+	return -EOPNOTSUPP;
+}
+
 static int
 do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
@@ -1730,6 +1752,8 @@
 	return -EOPNOTSUPP;
 
     switch(cmd) {
+      case SIOCETHTOOL:
+        return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
       case SIOCDEVPRIVATE:	/* Get the address of the PHY in use. */
 	data[0] = 0;		/* we have only this address */
 	/* fall trough */
diff -urN linux-2.4.20-pre4/drivers/net/pcmcia/xircom_cb.c linux-2.4.20-pre5/drivers/net/pcmcia/xircom_cb.c
--- linux-2.4.20-pre4/drivers/net/pcmcia/xircom_cb.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre5/drivers/net/pcmcia/xircom_cb.c	Wed Aug 28 16:38:08 2002
@@ -29,6 +29,8 @@
 #include <linux/skbuff.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/ethtool.h>
+#include <asm/uaccess.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
 
@@ -174,6 +176,37 @@
 }
 #endif
 
+static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+	u32 ethcmd;
+		
+	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
+		return -EFAULT;
+	
+	switch (ethcmd) {
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
+		strncpy(info.driver, "xircom_cb", sizeof(info.driver)-1);
+		if (copy_to_user(useraddr, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+	}
+	
+	return -EOPNOTSUPP;
+}
+
+static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+
+       switch(cmd) {
+       case SIOCETHTOOL:
+	       return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
 /* xircom_probe is the code that gets called on device insertion.
    it sets up the hardware and registers the device to the networklayer.
    
@@ -263,6 +296,7 @@
 	dev->stop = &xircom_close;
 	dev->get_stats = &xircom_get_stats;
 	dev->priv = private;
+	dev->do_ioctl = &private_ioctl;
 	pdev->driver_data = dev;
 
 	
@@ -1008,7 +1042,7 @@
 
 
 /* 
-link_status() checks the the links status and will return 0 for no link, 10 for 10mbit link and 100 for.. guess what.
+link_status() checks the link's status and will return 0 for no link, 10 for 10mbit link and 100 for.. guess what.
 
 Must be called in locked state with interrupts disabled
 */
diff -urN linux-2.4.20-pre4/drivers/net/rcpci45.c linux-2.4.20-pre5/drivers/net/rcpci45.c
--- linux-2.4.20-pre4/drivers/net/rcpci45.c	Wed Aug 28 16:36:54 2002
+++ linux-2.4.20-pre5/drivers/net/rcpci45.c	Wed Aug 28 16:38:08 2002
@@ -165,7 +165,7 @@
 	 * API private area, which requires a minimum of 16KB.  The top 
 	 * of the allocated area will be assigned to struct net_device; 
 	 * the next chunk will be assigned to DPA; and finally, the rest 
-	 * will be assigned to the the LAN API layer.
+	 * will be assigned to the LAN API layer.
 	 */
 
 	dev = init_etherdev (NULL, sizeof (*pDpa));
diff -urN linux-2.4.20-pre4/drivers/net/tg3.c linux-2.4.20-pre5/drivers/net/tg3.c
--- linux-2.4.20-pre4/drivers/net/tg3.c	Wed Aug 28 16:36:54 2002
+++ linux-2.4.20-pre5/drivers/net/tg3.c	Wed Aug 28 16:38:09 2002
@@ -3337,8 +3337,10 @@
 	/* Clear statistics/status block in chip, and status block in ram. */
 	for (i = NIC_SRAM_STATS_BLK;
 	     i < NIC_SRAM_STATUS_BLK + TG3_HW_STATUS_SIZE;
-	     i += sizeof(u32))
+	     i += sizeof(u32)) {
 		tg3_write_mem(tp, i, 0);
+		udelay(40);
+	}
 	memset(tp->hw_status, 0, TG3_HW_STATUS_SIZE);
 
 	/* This value is determined during the probe time DMA
diff -urN linux-2.4.20-pre4/drivers/net/via-rhine.c linux-2.4.20-pre5/drivers/net/via-rhine.c
--- linux-2.4.20-pre4/drivers/net/via-rhine.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre5/drivers/net/via-rhine.c	Wed Aug 28 16:38:09 2002
@@ -93,6 +93,10 @@
 	- transmit frame queue message is off by one - fixed
 	- adds IntrNormalSummary to "Something Wicked" exclusion list
 	  so normal interrupts will not trigger the message (src: Donald Becker)
+ 	(Roger Luethi)
+ 	- show confused chip where to continue after Tx error
+ 	- location of collision counter is chip specific
+ 	- allow selecting backoff algorithm (module parameter)
 
 */
 
@@ -111,6 +115,9 @@
    Setting to > 1518 effectively disables this feature. */
 static int rx_copybreak;
 
+/* Select a backoff algorithm (Ethernet capture effect) */
+static int backoff;
+
 /* Used to pass the media type, etc.
    Both 'options[]' and 'full_duplex[]' should exist for driver
    interoperability.
@@ -213,11 +220,13 @@
 MODULE_PARM(max_interrupt_work, "i");
 MODULE_PARM(debug, "i");
 MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(backoff, "i");
 MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
 MODULE_PARM_DESC(max_interrupt_work, "VIA Rhine maximum events handled per interrupt");
 MODULE_PARM_DESC(debug, "VIA Rhine debug level (0-7)");
 MODULE_PARM_DESC(rx_copybreak, "VIA Rhine copy breakpoint for copy-only-tiny-frames");
+MODULE_PARM_DESC(backoff, "VIA Rhine: Bits 0-3: backoff algorithm");
 MODULE_PARM_DESC(options, "VIA Rhine: Bits 0-3: media type, bit 17: full duplex");
 MODULE_PARM_DESC(full_duplex, "VIA Rhine full duplex setting(s) (1)");
 
@@ -234,7 +243,8 @@
 Boards with this chip are functional only in a bus-master PCI slot.
 
 Many operational settings are loaded from the EEPROM to the Config word at
-offset 0x78.  This driver assumes that they are correct.
+offset 0x78. For most of these settings, this driver assumes that they are
+correct.
 If this driver is compiled to use PCI memory space operations the EEPROM
 must be configured to enable memory ops.
 
@@ -386,9 +396,10 @@
 	StickyHW=0x83, WOLcrClr=0xA4, WOLcgClr=0xA7, PwrcsrClr=0xAC,
 };
 
-/* Bits in ConfigD (select backoff algorithm (Ethernet capture effect)) */
+/* Bits in ConfigD */
 enum backoff_bits {
-	BackOpt=0x01, BackAMD=0x02, BackDEC=0x04, BackRandom=0x08
+	BackOptional=0x01, BackModify=0x02,
+	BackCaptureEffect=0x04, BackRandom=0x08
 };
 
 #ifdef USE_MEM
@@ -402,7 +413,7 @@
 /* Bits in the interrupt status/mask registers. */
 enum intr_status_bits {
 	IntrRxDone=0x0001, IntrRxErr=0x0004, IntrRxEmpty=0x0020,
-	IntrTxDone=0x0002, IntrTxAbort=0x0008, IntrTxUnderrun=0x0010,
+	IntrTxDone=0x0002, IntrTxError=0x0008, IntrTxUnderrun=0x0010,
 	IntrPCIErr=0x0040,
 	IntrStatsMax=0x0080, IntrRxEarly=0x0100, IntrMIIChange=0x0200,
 	IntrRxOverflow=0x0400, IntrRxDropped=0x0800, IntrRxNoBuf=0x1000,
@@ -428,24 +439,27 @@
 /* The Rx and Tx buffer descriptors. */
 struct rx_desc {
 	s32 rx_status;
-	u32 desc_length;
+	u32 desc_length; /* Chain flag, Buffer/frame length */
 	u32 addr;
 	u32 next_desc;
 };
 struct tx_desc {
 	s32 tx_status;
-	u32 desc_length;
+	u32 desc_length; /* Chain flag, Tx Config, Frame length */
 	u32 addr;
 	u32 next_desc;
 };
 
+/* Initial value for tx_desc.desc_length, Buffer size goes to bits 0-10 */
+#define TXDESC 0x00e08000
+
 enum rx_status_bits {
 	RxOK=0x8000, RxWholePkt=0x0300, RxErr=0x008F
 };
 
-/* Bits in *_desc.status */
+/* Bits in *_desc.*_status */
 enum desc_status_bits {
-	DescOwn=0x80000000, DescEndPacket=0x4000, DescIntr=0x1000,
+	DescOwn=0x80000000
 };
 
 /* Bits in ChipCmd. */
@@ -517,6 +531,7 @@
 static int via_rhine_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static int  via_rhine_close(struct net_device *dev);
 static inline void clear_tally_counters(long ioaddr);
+static inline void via_restart_tx(struct net_device *dev);
 
 static void wait_for_reset(struct net_device *dev, int chip_id, char *name)
 {
@@ -703,6 +718,11 @@
 		writeb(readb(ioaddr + ConfigA) & 0xFE, ioaddr + ConfigA);
 	}
 
+	/* Select backoff algorithm */
+	if (backoff)
+		writeb(readb(ioaddr + ConfigD) & (0xF0 | backoff),
+			ioaddr + ConfigD);
+
 	dev->irq = pdev->irq;
 
 	np = dev->priv;
@@ -937,7 +957,7 @@
 	for (i = 0; i < TX_RING_SIZE; i++) {
 		np->tx_skbuff[i] = 0;
 		np->tx_ring[i].tx_status = 0;
-		np->tx_ring[i].desc_length = cpu_to_le32(0x00e08000);
+		np->tx_ring[i].desc_length = cpu_to_le32(TXDESC);
 		next += sizeof(struct tx_desc);
 		np->tx_ring[i].next_desc = cpu_to_le32(next);
 		np->tx_buf[i] = &np->tx_bufs[i * PKT_BUF_SZ];
@@ -953,7 +973,7 @@
 
 	for (i = 0; i < TX_RING_SIZE; i++) {
 		np->tx_ring[i].tx_status = 0;
-		np->tx_ring[i].desc_length = cpu_to_le32(0x00e08000);
+		np->tx_ring[i].desc_length = cpu_to_le32(TXDESC);
 		np->tx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */
 		if (np->tx_skbuff[i]) {
 			if (np->tx_skbuff_dma[i]) {
@@ -978,7 +998,7 @@
 		writeb(dev->dev_addr[i], ioaddr + StationAddr + i);
 
 	/* Initialize other registers. */
-	writew(0x0006, ioaddr + PCIBusConfig);	/* Store & forward */
+	writew(0x0006, ioaddr + PCIBusConfig);	/* Tune configuration??? */
 	/* Configure initial FIFO thresholds. */
 	writeb(0x20, ioaddr + TxConfig);
 	np->tx_thresh = 0x20;
@@ -993,8 +1013,9 @@
 	via_rhine_set_rx_mode(dev);
 
 	/* Enable interrupts by setting the interrupt mask. */
-	writew(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow| IntrRxDropped|
-		   IntrTxDone | IntrTxAbort | IntrTxUnderrun |
+	writew(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow |
+		   IntrRxDropped | IntrRxNoBuf | IntrTxAborted |
+		   IntrTxDone | IntrTxError | IntrTxUnderrun |
 		   IntrPCIErr | IntrStatsMax | IntrLinkChange | IntrMIIChange,
 		   ioaddr + IntrEnable);
 
@@ -1237,7 +1258,7 @@
 	}
 
 	np->tx_ring[entry].desc_length = 
-		cpu_to_le32(0x00E08000 | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN));
+		cpu_to_le32(TXDESC | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN));
 
 	/* lock eth irq */
 	spin_lock_irq (&np->lock);
@@ -1289,13 +1310,14 @@
 						   IntrRxWakeUp | IntrRxEmpty | IntrRxNoBuf))
 			via_rhine_rx(dev);
 
-		if (intr_status & (IntrTxDone | IntrTxAbort | IntrTxUnderrun |
+		if (intr_status & (IntrTxDone | IntrTxError | IntrTxUnderrun |
 						   IntrTxAborted))
 			via_rhine_tx(dev);
 
 		/* Abnormal error summary/uncommon events handlers. */
 		if (intr_status & (IntrPCIErr | IntrLinkChange | IntrMIIChange |
-						   IntrStatsMax | IntrTxAbort | IntrTxUnderrun))
+				   IntrStatsMax | IntrTxError | IntrTxAborted |
+				   IntrTxUnderrun))
 			via_rhine_error(dev, intr_status);
 
 		if (--boguscnt < 0) {
@@ -1307,7 +1329,7 @@
 	}
 
 	if (debug > 3)
-		printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
+		printk(KERN_DEBUG "%s: exiting interrupt, status=%4.4x.\n",
 			   dev->name, readw(ioaddr + IntrStatus));
 }
 
@@ -1323,11 +1345,11 @@
 	/* find and cleanup dirty tx descriptors */
 	while (np->dirty_tx != np->cur_tx) {
 		txstatus = le32_to_cpu(np->tx_ring[entry].tx_status);
-		if (txstatus & DescOwn)
-			break;
 		if (debug > 6)
 			printk(KERN_DEBUG " Tx scavenge %d status %8.8x.\n",
 				   entry, txstatus);
+		if (txstatus & DescOwn)
+			break;
 		if (txstatus & 0x8000) {
 			if (debug > 1)
 				printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
@@ -1337,10 +1359,22 @@
 			if (txstatus & 0x0200) np->stats.tx_window_errors++;
 			if (txstatus & 0x0100) np->stats.tx_aborted_errors++;
 			if (txstatus & 0x0080) np->stats.tx_heartbeat_errors++;
-			if (txstatus & 0x0002) np->stats.tx_fifo_errors++;
+			if (((np->chip_id == VT86C100A) && txstatus & 0x0002) ||
+				(txstatus & 0x0800) || (txstatus & 0x1000)) {
+				np->stats.tx_fifo_errors++;
+				np->tx_ring[entry].tx_status = cpu_to_le32(DescOwn);
+				break; /* Keep the skb - we try again */
+			}
 			/* Transmitter restarted in 'abnormal' handler. */
 		} else {
-			np->stats.collisions += (txstatus >> 3) & 15;
+			if (np->chip_id == VT86C100A)
+				np->stats.collisions += (txstatus >> 3) & 0x0F;
+			else
+				np->stats.collisions += txstatus & 0x0F;
+			if (debug > 6)
+				printk(KERN_DEBUG "collisions: %1.1x:%1.1x\n",
+					(txstatus >> 3) & 0xF,
+					txstatus & 0xF);
 			np->stats.tx_bytes += np->tx_skbuff[entry]->len;
 			np->stats.tx_packets++;
 		}
@@ -1476,6 +1510,17 @@
 	writew(CmdRxDemand | np->chip_cmd, dev->base_addr + ChipCmd);
 }
 
+static inline void via_restart_tx(struct net_device *dev) {
+	struct netdev_private *np = dev->priv;
+	int entry = np->dirty_tx % TX_RING_SIZE;
+
+	/* We know better than the chip where it should continue */
+	writel(np->tx_ring_dma + entry * sizeof(struct tx_desc),
+		   dev->base_addr + TxRingPtr);
+
+	writew(CmdTxDemand | np->chip_cmd, dev->base_addr + ChipCmd);
+}
+
 static void via_rhine_error(struct net_device *dev, int intr_status)
 {
 	struct netdev_private *np = dev->priv;
@@ -1501,19 +1546,23 @@
 		np->stats.rx_missed_errors	+= readw(ioaddr + RxMissed);
 		clear_tally_counters(ioaddr);
 	}
-	if (intr_status & IntrTxAbort) {
-		/* Stats counted in Tx-done handler, just restart Tx. */
-		writew(CmdTxDemand | np->chip_cmd, dev->base_addr + ChipCmd);
+	if (intr_status & IntrTxError) {
+		if (debug > 1)
+			printk(KERN_INFO "%s: Abort %4.4x, frame dropped.\n",
+				   dev->name, intr_status);
+		via_restart_tx(dev);
 	}
 	if (intr_status & IntrTxUnderrun) {
 		if (np->tx_thresh < 0xE0)
 			writeb(np->tx_thresh += 0x20, ioaddr + TxConfig);
 		if (debug > 1)
-			printk(KERN_INFO "%s: Transmitter underrun, increasing Tx "
-				   "threshold setting to %2.2x.\n", dev->name, np->tx_thresh);
+			printk(KERN_INFO "%s: Transmitter underrun, Tx "
+				   "threshold now %2.2x.\n",
+				   dev->name, np->tx_thresh);
+		via_restart_tx(dev);
 	}
 	if (intr_status & ~( IntrLinkChange | IntrStatsMax |
- 						 IntrTxAbort | IntrTxAborted | IntrNormalSummary)) {
+ 						 IntrTxError | IntrTxAborted | IntrNormalSummary)) {
 		if (debug > 1)
 			printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n",
 			   dev->name, intr_status);
diff -urN linux-2.4.20-pre4/drivers/net/winbond-840.c linux-2.4.20-pre5/drivers/net/winbond-840.c
--- linux-2.4.20-pre4/drivers/net/winbond-840.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre5/drivers/net/winbond-840.c	Wed Aug 28 16:38:12 2002
@@ -1078,7 +1078,7 @@
 		np->tx_ring[entry].length |= DescEndRing;
 
 	/* Now acquire the irq spinlock.
-	 * The difficult race is the the ordering between
+	 * The difficult race is the ordering between
 	 * increasing np->cur_tx and setting DescOwn:
 	 * - if np->cur_tx is increased first the interrupt
 	 *   handler could consider the packet as transmitted
diff -urN linux-2.4.20-pre4/drivers/pci/pci.c linux-2.4.20-pre5/drivers/pci/pci.c
--- linux-2.4.20-pre4/drivers/pci/pci.c	Wed Aug 28 16:36:57 2002
+++ linux-2.4.20-pre5/drivers/pci/pci.c	Wed Aug 28 16:38:13 2002
@@ -479,6 +479,69 @@
 }
 
 /**
+ *	pci_release_region - Release a PCI bar
+ *	@pdev: PCI device whose resources were previously reserved by pci_request_region
+ *	@bar: BAR to release
+ *
+ *	Releases the PCI I/O and memory resources previously reserved by a
+ *	successful call to pci_request_region.  Call this function only
+ *	after all use of the PCI regions has ceased.
+ */
+void pci_release_region(struct pci_dev *pdev, int bar)
+{
+	if (pci_resource_len(pdev, bar) == 0)
+		return;
+	if (pci_resource_flags(pdev, bar) & IORESOURCE_IO)
+		release_region(pci_resource_start(pdev, bar),
+				pci_resource_len(pdev, bar));
+	else if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM)
+		release_mem_region(pci_resource_start(pdev, bar),
+				pci_resource_len(pdev, bar));
+}
+
+/**
+ *	pci_request_region - Reserved PCI I/O and memory resource
+ *	@pdev: PCI device whose resources are to be reserved
+ *	@bar: BAR to be reserved
+ *	@res_name: Name to be associated with resource.
+ *
+ *	Mark the PCI region associated with PCI device @pdev BR @bar as
+ *	being reserved by owner @res_name.  Do not access any
+ *	address inside the PCI regions unless this call returns
+ *	successfully.
+ *
+ *	Returns 0 on success, or %EBUSY on error.  A warning
+ *	message is also printed on failure.
+ */
+int pci_request_region(struct pci_dev *pdev, int bar, char *res_name)
+{
+	if (pci_resource_len(pdev, bar) == 0)
+		return 0;
+		
+	if (pci_resource_flags(pdev, bar) & IORESOURCE_IO) {
+		if (!request_region(pci_resource_start(pdev, bar),
+			    pci_resource_len(pdev, bar), res_name))
+			goto err_out;
+	}
+	else if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM) {
+		if (!request_mem_region(pci_resource_start(pdev, bar),
+				        pci_resource_len(pdev, bar), res_name))
+			goto err_out;
+	}
+	
+	return 0;
+
+err_out:
+	printk (KERN_WARNING "PCI: Unable to reserve %s region #%d:%lx@%lx for device %s\n",
+		pci_resource_flags(pdev, bar) & IORESOURCE_IO ? "I/O" : "mem",
+		bar + 1, /* PCI BAR # */
+		pci_resource_len(pdev, bar), pci_resource_start(pdev, bar),
+		pdev->slot_name);
+	return -EBUSY;
+}
+
+
+/**
  *	pci_release_regions - Release reserved PCI I/O and memory resources
  *	@pdev: PCI device whose resources were previously reserved by pci_request_regions
  *
@@ -486,22 +549,13 @@
  *	successful call to pci_request_regions.  Call this function only
  *	after all use of the PCI regions has ceased.
  */
+
 void pci_release_regions(struct pci_dev *pdev)
 {
 	int i;
 	
-	for (i = 0; i < 6; i++) {
-		if (pci_resource_len(pdev, i) == 0)
-			continue;
-
-		if (pci_resource_flags(pdev, i) & IORESOURCE_IO)
-			release_region(pci_resource_start(pdev, i),
-				       pci_resource_len(pdev, i));
-
-		else if (pci_resource_flags(pdev, i) & IORESOURCE_MEM)
-			release_mem_region(pci_resource_start(pdev, i),
-					   pci_resource_len(pdev, i));
-	}
+	for (i = 0; i < 6; i++)
+		pci_release_region(pdev, i);
 }
 
 /**
@@ -521,23 +575,9 @@
 {
 	int i;
 	
-	for (i = 0; i < 6; i++) {
-		if (pci_resource_len(pdev, i) == 0)
-			continue;
-
-		if (pci_resource_flags(pdev, i) & IORESOURCE_IO) {
-			if (!request_region(pci_resource_start(pdev, i),
-					    pci_resource_len(pdev, i), res_name))
-				goto err_out;
-		}
-		
-		else if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) {
-			if (!request_mem_region(pci_resource_start(pdev, i),
-					        pci_resource_len(pdev, i), res_name))
-				goto err_out;
-		}
-	}
-	
+	for (i = 0; i < 6; i++)
+		if(pci_request_region(pdev, i, res_name))
+			goto err_out;
 	return 0;
 
 err_out:
@@ -546,7 +586,9 @@
 		i + 1, /* PCI BAR # */
 		pci_resource_len(pdev, i), pci_resource_start(pdev, i),
 		pdev->slot_name);
-	pci_release_regions(pdev);
+	while(--i <= 0)
+		pci_release_region(pdev, i);
+		
 	return -EBUSY;
 }
 
@@ -1658,7 +1700,7 @@
 	return 0;
 }
 
-static int pci_pm_resume(void)
+int pci_pm_resume(void)
 {
 	struct list_head *list;
 	struct pci_bus *bus;
@@ -2088,6 +2130,8 @@
 EXPORT_SYMBOL(pci_find_capability);
 EXPORT_SYMBOL(pci_release_regions);
 EXPORT_SYMBOL(pci_request_regions);
+EXPORT_SYMBOL(pci_release_region);
+EXPORT_SYMBOL(pci_request_region);
 EXPORT_SYMBOL(pci_find_class);
 EXPORT_SYMBOL(pci_find_device);
 EXPORT_SYMBOL(pci_find_slot);
diff -urN linux-2.4.20-pre4/drivers/scsi/aic7xxx/aic7xxx_core.c linux-2.4.20-pre5/drivers/scsi/aic7xxx/aic7xxx_core.c
--- linux-2.4.20-pre4/drivers/scsi/aic7xxx/aic7xxx_core.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre5/drivers/scsi/aic7xxx/aic7xxx_core.c	Wed Aug 28 16:38:15 2002
@@ -4367,7 +4367,7 @@
 	/*
 	 * DMA tag for our command fifos and other data in system memory
 	 * the card's sequencer must be able to access.  For initiator
-	 * roles, we need to allocate space for the the qinfifo and qoutfifo.
+	 * roles, we need to allocate space for the qinfifo and qoutfifo.
 	 * The qinfifo and qoutfifo are composed of 256 1 byte elements. 
 	 * When providing for the target mode role, we must additionally
 	 * provide space for the incoming target command fifo and an extra
@@ -6928,7 +6928,7 @@
 		panic("ahc_update_scsiid called on non-multitid unit\n");
 
 	/*
-	 * Since we will rely on the the TARGID mask
+	 * Since we will rely on the TARGID mask
 	 * for selection enables, ensure that OID
 	 * in SCSIID is not set to some other ID
 	 * that we don't want to allow selections on.
diff -urN linux-2.4.20-pre4/drivers/scsi/imm.c linux-2.4.20-pre5/drivers/scsi/imm.c
--- linux-2.4.20-pre4/drivers/scsi/imm.c	Sun Sep 30 12:26:07 2001
+++ linux-2.4.20-pre5/drivers/scsi/imm.c	Wed Aug 28 16:38:18 2002
@@ -1120,7 +1120,7 @@
 }
 
 /*
- * Apparently the the disk->capacity attribute is off by 1 sector 
+ * Apparently the disk->capacity attribute is off by 1 sector 
  * for all disk drives.  We add the one here, but it should really
  * be done in sd.c.  Even if it gets fixed there, this will still
  * work.
diff -urN linux-2.4.20-pre4/drivers/scsi/ppa.c linux-2.4.20-pre5/drivers/scsi/ppa.c
--- linux-2.4.20-pre4/drivers/scsi/ppa.c	Sun Sep 30 12:26:07 2001
+++ linux-2.4.20-pre5/drivers/scsi/ppa.c	Wed Aug 28 16:38:19 2002
@@ -995,7 +995,7 @@
 }
 
 /*
- * Apparently the the disk->capacity attribute is off by 1 sector 
+ * Apparently the disk->capacity attribute is off by 1 sector 
  * for all disk drives.  We add the one here, but it should really
  * be done in sd.c.  Even if it gets fixed there, this will still
  * work.
diff -urN linux-2.4.20-pre4/drivers/scsi/sym53c8xx.c linux-2.4.20-pre5/drivers/scsi/sym53c8xx.c
--- linux-2.4.20-pre4/drivers/scsi/sym53c8xx.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre5/drivers/scsi/sym53c8xx.c	Wed Aug 28 16:38:19 2002
@@ -2651,7 +2651,7 @@
 	**	The below GETJOB_BEGIN to GETJOB_END section of SCRIPTS 
 	**	is a critical path. If it is partially executed, it then 
 	**	may happen that the job address is not yet in the DSA 
-	**	and the the next queue position points to the next JOB.
+	**	and the next queue position points to the next JOB.
 	*/
 	SCR_LOAD_ABS (dsa, 4),
 		PADDRH (startpos),
@@ -12880,7 +12880,7 @@
 **    differ and attach them using the order in the NVRAM.
 **
 **    If no NVRAM is found or data appears invalid attach boards in 
-**    the the order they are detected.
+**    the order they are detected.
 **===================================================================
 */
 int __init sym53c8xx_detect(Scsi_Host_Template *tpnt)
diff -urN linux-2.4.20-pre4/drivers/scsi/sym53c8xx_2/sym_fw1.h linux-2.4.20-pre5/drivers/scsi/sym53c8xx_2/sym_fw1.h
--- linux-2.4.20-pre4/drivers/scsi/sym53c8xx_2/sym_fw1.h	Fri Nov  9 15:22:54 2001
+++ linux-2.4.20-pre5/drivers/scsi/sym53c8xx_2/sym_fw1.h	Wed Aug 28 16:38:20 2002
@@ -283,7 +283,7 @@
 	 *  The below GETJOB_BEGIN to GETJOB_END section of SCRIPTS 
 	 *  is a critical path. If it is partially executed, it then 
 	 *  may happen that the job address is not yet in the DSA 
-	 *  and the the next queue position points to the next JOB.
+	 *  and the next queue position points to the next JOB.
 	 */
 }/*-------------------------< GETJOB_BEGIN >---------------------*/,{
 	/*
diff -urN linux-2.4.20-pre4/drivers/scsi/sym53c8xx_2/sym_fw2.h linux-2.4.20-pre5/drivers/scsi/sym53c8xx_2/sym_fw2.h
--- linux-2.4.20-pre4/drivers/scsi/sym53c8xx_2/sym_fw2.h	Fri Nov  9 15:22:54 2001
+++ linux-2.4.20-pre5/drivers/scsi/sym53c8xx_2/sym_fw2.h	Wed Aug 28 16:38:20 2002
@@ -280,7 +280,7 @@
 	 *  The below GETJOB_BEGIN to GETJOB_END section of SCRIPTS 
 	 *  is a critical path. If it is partially executed, it then 
 	 *  may happen that the job address is not yet in the DSA 
-	 *  and the the next queue position points to the next JOB.
+	 *  and the next queue position points to the next JOB.
 	 */
 	SCR_LOAD_ABS (dsa, 4),
 		PADDR_B (startpos),
diff -urN linux-2.4.20-pre4/drivers/scsi/sym53c8xx_2/sym_glue.c linux-2.4.20-pre5/drivers/scsi/sym53c8xx_2/sym_glue.c
--- linux-2.4.20-pre4/drivers/scsi/sym53c8xx_2/sym_glue.c	Wed Aug 28 16:36:58 2002
+++ linux-2.4.20-pre5/drivers/scsi/sym53c8xx_2/sym_glue.c	Wed Aug 28 16:38:20 2002
@@ -2715,7 +2715,7 @@
  *  differ and attach them using the order in the NVRAM.
  *
  *  If no NVRAM is found or data appears invalid attach boards in 
- *  the the order they are detected.
+ *  the order they are detected.
  */
 int __init sym53c8xx_detect(Scsi_Host_Template *tpnt)
 {
diff -urN linux-2.4.20-pre4/drivers/scsi/sym53c8xx_comm.h linux-2.4.20-pre5/drivers/scsi/sym53c8xx_comm.h
--- linux-2.4.20-pre4/drivers/scsi/sym53c8xx_comm.h	Fri Dec 21 09:41:55 2001
+++ linux-2.4.20-pre5/drivers/scsi/sym53c8xx_comm.h	Wed Aug 28 16:38:20 2002
@@ -2509,7 +2509,7 @@
 **    differ and attach them using the order in the NVRAM.
 **
 **    If no NVRAM is found or data appears invalid attach boards in 
-**    the the order they are detected.
+**    the order they are detected.
 **
 **===================================================================
 */
diff -urN linux-2.4.20-pre4/drivers/telephony/ixj.c linux-2.4.20-pre5/drivers/telephony/ixj.c
--- linux-2.4.20-pre4/drivers/telephony/ixj.c	Wed Aug 28 16:36:59 2002
+++ linux-2.4.20-pre5/drivers/telephony/ixj.c	Wed Aug 28 16:38:20 2002
@@ -5950,7 +5950,7 @@
 	lcp = kmalloc(sizeof(IXJ_CADENCE), GFP_KERNEL);
 	if (lcp == NULL)
 		return -ENOMEM;
-	if (copy_from_user(lcp, (char *) cp, sizeof(IXJ_CADENCE)) || (unsigned)lcp->elements_used >= ~0U/sizeof(IXJ_CADENCE) )
+	if (copy_from_user(lcp, (char *) cp, sizeof(IXJ_CADENCE)) || (unsigned)lcp->elements_used >= ~0U/sizeof(IXJ_CADENCE_ELEMENT) )
         {
                 kfree(lcp);
                 return -EFAULT;
diff -urN linux-2.4.20-pre4/drivers/usb/auerswald.c linux-2.4.20-pre5/drivers/usb/auerswald.c
--- linux-2.4.20-pre4/drivers/usb/auerswald.c	Wed Aug 28 16:37:00 2002
+++ linux-2.4.20-pre5/drivers/usb/auerswald.c	Wed Aug 28 16:38:21 2002
@@ -2,7 +2,7 @@
 /*
  *      auerswald.c  --  Auerswald PBX/System Telephone usb driver.
  *
- *      Copyright (C) 2001  Wolfgang Mües (wmues@nexgo.de)
+ *      Copyright (C) 2001  Wolfgang Mües (wolfgang@iksw-muees.de)
  *
  *      Very much code of this driver is borrowed from dabusb.c (Deti Fliegl)
  *      and from the USB Skeleton driver (Greg Kroah-Hartman). Thank you.
@@ -50,7 +50,7 @@
 /*-------------------------------------------------------------------*/
 /* Version Information */
 #define DRIVER_VERSION "0.9.11"
-#define DRIVER_AUTHOR  "Wolfgang Mües <wmues@nexgo.de>"
+#define DRIVER_AUTHOR  "Wolfgang Mües <wolfgang@iksw-muees.de>"
 #define DRIVER_DESC    "Auerswald PBX/System Telephone usb driver"
 
 /*-------------------------------------------------------------------*/
@@ -1327,7 +1327,7 @@
 }
 
 
-/* remove a service from the the device
+/* remove a service from the device
    scp->id must be set! */
 static void auerswald_removeservice (pauerswald_t cp, pauerscon_t scp)
 {
diff -urN linux-2.4.20-pre4/drivers/usb/brlvger.c linux-2.4.20-pre5/drivers/usb/brlvger.c
--- linux-2.4.20-pre4/drivers/usb/brlvger.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre5/drivers/usb/brlvger.c	Wed Aug 28 16:38:21 2002
@@ -208,8 +208,8 @@
 #define err(args...) \
     ({ printk(KERN_ERR "Voyager: " args); \
        printk("\n"); })
-#define dbgprint(args...) \
-    ({ printk(KERN_DEBUG "Voyager: " __FUNCTION__ ": " args); \
+#define dbgprint(fmt, args...) \
+    ({ printk(KERN_DEBUG "Voyager: %s: " fmt, __FUNCTION__, ##args); \
        printk("\n"); })
 #define dbg(args...) \
     ({ if(debug >= 1) dbgprint(args); })
diff -urN linux-2.4.20-pre4/drivers/usb/hcd/ehci-hcd.c linux-2.4.20-pre5/drivers/usb/hcd/ehci-hcd.c
--- linux-2.4.20-pre4/drivers/usb/hcd/ehci-hcd.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre5/drivers/usb/hcd/ehci-hcd.c	Wed Aug 28 16:38:21 2002
@@ -434,10 +434,6 @@
 	scan_async (ehci);
 	if (ehci->next_uframe != -1)
 		scan_periodic (ehci);
-
-	// FIXME:  when nothing is connected to the root hub,
-	// turn off the RUN bit so the host can enter C3 "sleep" power
-	// saving mode; make root hub code scan memory less often.
 }
 
 /*-------------------------------------------------------------------------*/
@@ -582,7 +578,10 @@
 		return 0;
 
 	case PIPE_INTERRUPT:
-		intr_deschedule (ehci, urb->start_frame, qh, urb->interval);
+		intr_deschedule (ehci, urb->start_frame, qh,
+			(urb->dev->speed == USB_SPEED_HIGH)
+			    ? urb->interval
+			    : (urb->interval << 3));
 		if (ehci->hcd.state == USB_STATE_HALT)
 			urb->status = -ESHUTDOWN;
 		qh_completions (ehci, qh, 1);
diff -urN linux-2.4.20-pre4/drivers/usb/hcd/ehci-q.c linux-2.4.20-pre5/drivers/usb/hcd/ehci-q.c
--- linux-2.4.20-pre4/drivers/usb/hcd/ehci-q.c	Wed Aug 28 16:37:00 2002
+++ linux-2.4.20-pre5/drivers/usb/hcd/ehci-q.c	Wed Aug 28 16:38:21 2002
@@ -681,6 +681,8 @@
 	default:
 #ifdef DEBUG
 		BUG ();
+#else
+		;
 #endif
 	}
 
@@ -817,9 +819,9 @@
 		} else {
 			// dbg_qh ("empty qh", ehci, qh);
 
-// FIXME:  how handle usb_clear_halt() for an EP with queued URBs?
-// usbcore may not let us handle that cleanly...
-// likely must cancel them all first!
+			/* NOTE: we already canceled any queued URBs
+			 * when the endpoint halted.
+			 */
 
 			/* usb_clear_halt() means qh data toggle gets reset */
 			if (usb_pipebulk (urb->pipe)
diff -urN linux-2.4.20-pre4/drivers/usb/hcd/ehci-sched.c linux-2.4.20-pre5/drivers/usb/hcd/ehci-sched.c
--- linux-2.4.20-pre4/drivers/usb/hcd/ehci-sched.c	Wed Aug 28 16:37:00 2002
+++ linux-2.4.20-pre5/drivers/usb/hcd/ehci-sched.c	Wed Aug 28 16:38:21 2002
@@ -919,17 +919,9 @@
 		return flags;
 
 	/*
-	 * For now, always give the urb back to the driver ... expect it
-	 * to submit a new urb (or resubmit this), and to have another
-	 * already queued when un-interrupted transfers are needed.
-	 * No, that's not what OHCI or UHCI are now doing.
-	 *
-	 * FIXME Revisit the ISO URB model.  It's cleaner not to have all
-	 * the special case magic, but it'd be faster to reuse existing
-	 * ITD/DMA setup and schedule state.  Easy to dma_sync/complete(),
-	 * then either reschedule or, if unlinking, free and giveback().
-	 * But we can't overcommit like the full and low speed HCs do, and
-	 * there's no clean way to report an error when rescheduling...
+	 * Always give the urb back to the driver ... expect it to submit
+	 * a new urb (or resubmit this), and to have another already queued
+	 * when un-interrupted transfers are needed.
 	 *
 	 * NOTE that for now we don't accelerate ISO unlinks; they just
 	 * happen according to the current schedule.  Means a delay of
@@ -964,15 +956,6 @@
 	if (urb->iso_frame_desc [0].offset != 0)
 		return -EINVAL;
 	
-	/*
-	 * NOTE doing this for now, anticipating periodic URB models
-	 * get updated to be "explicit resubmit".
-	 */
-	if (urb->next) {
-		dbg ("use explicit resubmit for ISO");
-		return -EINVAL;
-	}
-
 	/* allocate ITDs w/o locking anything */
 	status = itd_urb_transaction (ehci, urb, mem_flags);
 	if (status < 0)
diff -urN linux-2.4.20-pre4/drivers/usb/hub.c linux-2.4.20-pre5/drivers/usb/hub.c
--- linux-2.4.20-pre4/drivers/usb/hub.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre5/drivers/usb/hub.c	Wed Aug 28 16:38:21 2002
@@ -155,7 +155,7 @@
 static int usb_hub_configure(struct usb_hub *hub, struct usb_endpoint_descriptor *endpoint)
 {
 	struct usb_device *dev = hub->dev;
-	struct usb_hub_status hubstatus;
+	struct usb_hub_status *hubstatus;
 	char portstr[USB_MAXCHILDREN + 1];
 	unsigned int pipe;
 	int i, maxp, ret;
@@ -258,20 +258,29 @@
 
 	dbg("port removable status: %s", portstr);
 
-	ret = usb_get_hub_status(dev, &hubstatus);
+	hubstatus = kmalloc(sizeof *hubstatus, GFP_KERNEL);
+	if (!hubstatus) {
+		err("Unable to allocate hubstatus");
+		kfree(hub->descriptor);
+		return -1;
+	}
+	ret = usb_get_hub_status(dev, hubstatus);
 	if (ret < 0) {
 		err("Unable to get hub status (err = %d)", ret);
+		kfree(hubstatus);
 		kfree(hub->descriptor);
 		return -1;
 	}
 
-	le16_to_cpus(&hubstatus.wHubStatus);
+	le16_to_cpus(&hubstatus->wHubStatus);
 
 	dbg("local power source is %s",
-		(hubstatus.wHubStatus & HUB_STATUS_LOCAL_POWER) ? "lost (inactive)" : "good");
+		(hubstatus->wHubStatus & HUB_STATUS_LOCAL_POWER) ? "lost (inactive)" : "good");
 
 	dbg("%sover-current condition exists",
-		(hubstatus.wHubStatus & HUB_STATUS_OVERCURRENT) ? "" : "no ");
+		(hubstatus->wHubStatus & HUB_STATUS_OVERCURRENT) ? "" : "no ");
+
+	kfree(hubstatus);
 
 	/* Start the interrupt endpoint */
 	pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
@@ -287,8 +296,11 @@
 		return -1;
 	}
 
-	FILL_INT_URB(hub->urb, dev, pipe, hub->buffer, maxp, hub_irq,
-		hub, endpoint->bInterval);
+	FILL_INT_URB(hub->urb, dev, pipe, hub->buffer, maxp, hub_irq, hub,
+		/* NOTE:  in 2.5 fill_int_urb() converts the encoding */
+		(dev->speed == USB_SPEED_HIGH)
+			? 1 << (endpoint->bInterval - 1)
+			: endpoint->bInterval);
 	ret = usb_submit_urb(hub->urb);
 	if (ret) {
 		err("usb_submit_urb failed (%d)", ret);
@@ -782,7 +794,7 @@
 	struct list_head *tmp;
 	struct usb_device *dev;
 	struct usb_hub *hub;
-	struct usb_hub_status hubsts;
+	struct usb_hub_status *hubsts;
 	u16 hubstatus;
 	u16 hubchange;
 	u16 portstatus;
@@ -872,21 +884,27 @@
 		} /* end for i */
 
 		/* deal with hub status changes */
-		if (usb_get_hub_status(dev, &hubsts) < 0)
-			err("get_hub_status failed");
-		else {
-			hubstatus = le16_to_cpup(&hubsts.wHubStatus);
-			hubchange = le16_to_cpup(&hubsts.wHubChange);
-			if (hubchange & HUB_CHANGE_LOCAL_POWER) {
-				dbg("hub power change");
-				usb_clear_hub_feature(dev, C_HUB_LOCAL_POWER);
-			}
-			if (hubchange & HUB_CHANGE_OVERCURRENT) {
-				dbg("hub overcurrent change");
-				wait_ms(500);	/* Cool down */
-				usb_clear_hub_feature(dev, C_HUB_OVER_CURRENT);
-                        	usb_hub_power_on(hub);
+		hubsts = kmalloc(sizeof *hubsts, GFP_KERNEL);
+		if (!hubsts) {
+			err("couldn't allocate hubsts");
+		} else {
+			if (usb_get_hub_status(dev, hubsts) < 0)
+				err("get_hub_status failed");
+			else {
+				hubstatus = le16_to_cpup(&hubsts->wHubStatus);
+				hubchange = le16_to_cpup(&hubsts->wHubChange);
+				if (hubchange & HUB_CHANGE_LOCAL_POWER) {
+					dbg("hub power change");
+					usb_clear_hub_feature(dev, C_HUB_LOCAL_POWER);
+				}
+				if (hubchange & HUB_CHANGE_OVERCURRENT) {
+					dbg("hub overcurrent change");
+					wait_ms(500);	/* Cool down */
+					usb_clear_hub_feature(dev, C_HUB_OVER_CURRENT);
+					usb_hub_power_on(hub);
+				}
 			}
+			kfree(hubsts);
 		}
 		up(&hub->khubd_sem);
         } /* end while (1) */
@@ -995,7 +1013,7 @@
 int usb_reset_device(struct usb_device *dev)
 {
 	struct usb_device *parent = dev->parent;
-	struct usb_device_descriptor descriptor;
+	struct usb_device_descriptor *descriptor;
 	int i, ret, port = -1;
 
 	if (!parent) {
@@ -1044,17 +1062,22 @@
 	 * If nothing changed, we reprogram the configuration and then
 	 * the alternate settings.
 	 */
+	descriptor = kmalloc(sizeof *descriptor, GFP_NOIO);
+	if (!descriptor) {
+		return -ENOMEM;
+	}
 	ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &descriptor,
 			sizeof(descriptor));
 	if (ret < 0)
 		return ret;
 
-	le16_to_cpus(&descriptor.bcdUSB);
-	le16_to_cpus(&descriptor.idVendor);
-	le16_to_cpus(&descriptor.idProduct);
-	le16_to_cpus(&descriptor.bcdDevice);
+	le16_to_cpus(&descriptor->bcdUSB);
+	le16_to_cpus(&descriptor->idVendor);
+	le16_to_cpus(&descriptor->idProduct);
+	le16_to_cpus(&descriptor->bcdDevice);
 
-	if (memcmp(&dev->descriptor, &descriptor, sizeof(descriptor))) {
+	if (memcmp(&dev->descriptor, descriptor, sizeof(descriptor))) {
+		kfree(descriptor);
 		usb_destroy_configuration(dev);
 
 		ret = usb_get_device_descriptor(dev);
@@ -1084,6 +1107,8 @@
 		return 1;
 	}
 
+	kfree(descriptor);
+
 	ret = usb_set_configuration(dev, dev->actconfig->bConfigurationValue);
 	if (ret < 0) {
 		err("failed to set active configuration (error=%d)", ret);
diff -urN linux-2.4.20-pre4/drivers/usb/kaweth.c linux-2.4.20-pre5/drivers/usb/kaweth.c
--- linux-2.4.20-pre4/drivers/usb/kaweth.c	Wed Aug 28 16:37:00 2002
+++ linux-2.4.20-pre5/drivers/usb/kaweth.c	Wed Aug 28 16:38:21 2002
@@ -54,6 +54,8 @@
 #include <linux/etherdevice.h>
 #include <linux/usb.h>
 #include <linux/types.h>
+#include <linux/ethtool.h>
+#include <asm/uaccess.h>
 #include <asm/semaphore.h>
 
 #define DEBUG
@@ -573,11 +575,35 @@
 	return 0;
 }
 
+static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+	u32 ethcmd;
+	
+	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
+		return -EFAULT;
+	
+	switch (ethcmd) {
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
+		strncpy(info.driver, "kaweth", sizeof(info.driver)-1);
+		if (copy_to_user(useraddr, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+	}
+	
+	return -EOPNOTSUPP;
+}
+
 /****************************************************************
  *     kaweth_ioctl
  ****************************************************************/
 static int kaweth_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
 {
+	switch (cmd) {
+	case SIOCETHTOOL:
+		return netdev_ethtool_ioctl(net, (void *) rq->ifr_data);
+	}
 	return -EOPNOTSUPP;
 }
 
diff -urN linux-2.4.20-pre4/drivers/usb/microtek.c linux-2.4.20-pre5/drivers/usb/microtek.c
--- linux-2.4.20-pre4/drivers/usb/microtek.c	Fri Oct  5 12:04:51 2001
+++ linux-2.4.20-pre5/drivers/usb/microtek.c	Wed Aug 28 16:38:21 2002
@@ -117,6 +117,8 @@
  *	20010320 Version 0.4.3
  *	20010408 Identify version on module load.
  *	20011003 Fix multiple requests
+ *	20020618 Version 0.4.4
+ *	20020618 Confirm to utterly stupid rules about io_request_lock
  */
 
 #include <linux/module.h>
@@ -144,7 +146,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.4.3"
+#define DRIVER_VERSION "v0.4.4"
 #define DRIVER_AUTHOR "John Fremlin <vii@penguinpowered.com>, Oliver Neukum <Oliver.Neukum@lrz.uni-muenchen.de>"
 #define DRIVER_DESC "Microtek Scanmaker X6 USB scanner driver"
 
@@ -326,10 +328,12 @@
 }  */
 
 static inline void mts_urb_abort(struct mts_desc* desc) {
+	spin_unlock_irq(&io_request_lock);
 	MTS_DEBUG_GOT_HERE();
 	mts_debug_dump(desc);
 
 	usb_unlink_urb( &desc->urb );
+	spin_lock_irq(&io_request_lock);
 }
 
 static struct mts_desc * mts_list; /* list of active scanners */
@@ -414,12 +418,14 @@
 
 static int mts_scsi_host_reset (Scsi_Cmnd *srb)
 {
-	struct mts_desc* desc = (struct mts_desc*)(srb->host->hostdata[0]);
 
+	struct mts_desc* desc = (struct mts_desc*)(srb->host->hostdata[0]);
+	spin_unlock_irq(&io_request_lock);
 	MTS_DEBUG_GOT_HERE();
 	mts_debug_dump(desc);
 
 	usb_reset_device(desc->usb_dev); /*FIXME: untested on new reset code */
+	spin_lock_irq(&io_request_lock);
 	return 0;  /* RANT why here 0 and not SUCCESS */
 }
 
@@ -435,6 +441,7 @@
 	/* What a hideous hack! */
 
 	char local_name[48];
+	spin_unlock_irq(&io_request_lock);
 
 	MTS_DEBUG_GOT_HERE();
 
@@ -445,6 +452,7 @@
 
 	if (!sht->proc_name) {
 		MTS_ERROR( "unable to allocate memory for proc interface!!\n" );
+		spin_lock_irq(&io_request_lock);
 		return 0;
 	}
 
@@ -457,11 +465,12 @@
 	if (desc->host == NULL) {
 		MTS_ERROR("Cannot register due to low memory");
 		kfree(sht->proc_name);
+		spin_lock_irq(&io_request_lock);
 		return 0;
 	}
 	desc->host->hostdata[0] = (unsigned long)desc;
 /* FIXME: what if sizeof(void*) != sizeof(unsigned long)? */
-
+	spin_lock_irq(&io_request_lock);
 	return 1;
 }
 
diff -urN linux-2.4.20-pre4/drivers/usb/ov511.c linux-2.4.20-pre5/drivers/usb/ov511.c
--- linux-2.4.20-pre4/drivers/usb/ov511.c	Wed Aug 28 16:37:00 2002
+++ linux-2.4.20-pre5/drivers/usb/ov511.c	Wed Aug 28 16:38:21 2002
@@ -9,7 +9,8 @@
  * OV7620 fixes by Charl P. Botha <cpbotha@ieee.org>
  * Changes by Claudio Matsuoka <claudio@conectiva.com>
  * Original SAA7111A code by Dave Perks <dperks@ibm.net>
- * Kernel I2C interface adapted from nt1003 driver
+ * URB error messages from pwc driver by Nemosoft
+ * generic_ioctl() code from videodev.c by Gerd Knorr and Alan Cox
  *
  * Based on the Linux CPiA driver written by Peter Pregler,
  * Scott J. Bertin and Johannes Erdfelt.
@@ -57,19 +58,22 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.50 for Linux 2.4"
-#define EMAIL "mmcclell@bigfoot.com"
+#define DRIVER_VERSION "v1.61 for Linux 2.4"
+#define EMAIL "mark@alpha.dyndns.org"
 #define DRIVER_AUTHOR "Mark McClelland <mmcclell@bigfoot.com> & Bret Wallach \
 	& Orion Sky Lawlor <olawlor@acm.org> & Kevin Moore & Charl P. Botha \
 	<cpbotha@ieee.org> & Claudio Matsuoka <claudio@conectiva.com>"
-#define DRIVER_DESC "OV511 USB Camera Driver"
+#define DRIVER_DESC "ov511 USB Camera Driver"
 
 #define OV511_I2C_RETRIES 3
 #define ENABLE_Y_QUANTABLE 1
 #define ENABLE_UV_QUANTABLE 1
 
+#define OV511_MAX_UNIT_VIDEO 16
+
 /* Pixel count * 3 bytes for RGB */
 #define MAX_FRAME_SIZE(w, h) ((w) * (h) * 3)
+
 #define MAX_DATA_SIZE(w, h) (MAX_FRAME_SIZE(w, h) + sizeof(struct timeval))
 
 /* Max size * bytes per YUV420 pixel (1.5) + one extra isoc frame for safety */
@@ -77,128 +81,47 @@
 
 #define FATAL_ERROR(rc) ((rc) < 0 && (rc) != -EPERM)
 
-/* PARAMETER VARIABLES: */
-/* (See ov511.txt for detailed descriptions of these.) */
-
-/* Sensor automatically changes brightness */
-static int autobright = 1;
-
-/* Sensor automatically changes gain */
-static int autogain = 1;
-
-/* Sensor automatically changes exposure */
-static int autoexp = 1;
-
-/* 0=no debug messages
- * 1=init/detection/unload and other significant messages,
- * 2=some warning messages
- * 3=config/control function calls
- * 4=most function calls and data parsing messages
- * 5=highly repetitive mesgs
- * NOTE: This should be changed to 0, 1, or 2 for production kernels
- */
-static int debug; /* = 0 */
-
-/* Fix vertical misalignment of red and blue at 640x480 */
-static int fix_rgb_offset; /* = 0 */
-
-/* Snapshot mode enabled flag */
-static int snapshot; /* = 0 */
-
-/* Force image to be read in RGB instead of BGR. This option allow
- * programs that expect RGB data (e.g. gqcam) to work with this driver. */
-static int force_rgb; /* = 0 */
-
-/* Number of seconds before inactive buffers are deallocated */
-static int buf_timeout = 5;
-
-/* Number of cameras to stream from simultaneously */
-static int cams = 1;
-
-/* Enable compression. Needs a fast (>300 MHz) CPU. */
-static int compress; /* = 0 */
-
-/* Display test pattern - doesn't work yet either */
-static int testpat; /* = 0 */
-
-/* Setting this to 1 will make the sensor output GBR422 instead of YUV420. Only
- * affects RGB24 mode. */
-static int sensor_gbr; /* = 0 */
-
-/* Dump raw pixel data. */
-static int dumppix; /* = 0 */
-
-/* LED policy. Only works on some OV511+ cameras. 0=off, 1=on (default), 2=auto
- * (on when open) */
-static int led = 1;
-
-/* Set this to 1 to dump the bridge register contents after initialization */
-static int dump_bridge; /* = 0 */
-
-/* Set this to 1 to dump the sensor register contents after initialization */
-static int dump_sensor; /* = 0 */
-
-/* Temporary option for debugging "works, but no image" problem. Prints the
- * first 12 bytes of data (potentially a packet header) in each isochronous
- * data frame. */
-static int printph; /* = 0 */
-
-/* Compression parameters - I'm not exactly sure what these do yet */
-static int phy = 0x1f;
-static int phuv = 0x05;
-static int pvy = 0x06;
-static int pvuv = 0x06;
-static int qhy = 0x14;
-static int qhuv = 0x03;
-static int qvy = 0x04;
-static int qvuv = 0x04;
-
-/* Light frequency. Set to 50 or 60 (Hz), or zero for default settings */
-static int lightfreq; /* = 0 */
-
-/* Set this to 1 to enable banding filter by default. Compensates for
- * alternating horizontal light/dark bands caused by (usually fluorescent)
- * lights */
-static int bandingfilter; /* = 0 */
-
-/* Pixel clock divisor */
-static int clockdiv = -1;
-
-/* Isoc packet size */
-static int packetsize = -1;
-
-/* Frame drop register (16h) */
-static int framedrop = -1;
-
-/* Allows picture settings (brightness, hue, etc...) to take effect immediately,
- * even in the middle of a frame. This reduces the time to change settings, but
- * can ruin frames during the change. Only affects OmniVision sensors. */
-static int fastset; /* = 0 */
-
-/* Forces the palette to a specific value. If an application requests a
- * different palette, it will be rejected. */
-static int force_palette; /* = 0 */
-
-/* Set tuner type, if not autodetected */
-static int tuner = -1;
-
-/* Allows proper exposure of objects that are illuminated from behind. Only
- * affects OmniVision sensors. */
-static int backlight; /* = 0 */
-
-/* If you change this, you must also change the MODULE_PARM definition */
-#define OV511_MAX_UNIT_VIDEO 16
+/**********************************************************************
+ * Module Parameters
+ * (See ov511.txt for detailed descriptions of these)
+ **********************************************************************/
 
-/* Allows specified minor numbers to be forced. They will be assigned in the
- * order that devices are detected. Note that you cannot specify 0 as a minor
- * number. If you do not specify any, the next available one will be used. This
- * requires kernel 2.4.5 or later. */
+/* These variables (and all static globals) default to zero */
+static int autobright		= 1;
+static int autogain		= 1;
+static int autoexp		= 1;
+static int debug;
+static int snapshot;
+static int fix_rgb_offset;
+static int force_rgb;
+static int cams			= 1;
+static int compress;
+static int testpat;
+static int sensor_gbr;
+static int dumppix;
+static int led 			= 1;
+static int dump_bridge;
+static int dump_sensor;
+static int printph;
+static int phy			= 0x1f;
+static int phuv			= 0x05;
+static int pvy			= 0x06;
+static int pvuv			= 0x06;
+static int qhy			= 0x14;
+static int qhuv			= 0x03;
+static int qvy			= 0x04;
+static int qvuv			= 0x04;
+static int lightfreq;
+static int bandingfilter;
+static int clockdiv		= -1;
+static int packetsize		= -1;
+static int framedrop		= -1;
+static int fastset;
+static int force_palette;
+static int backlight;
 static int unit_video[OV511_MAX_UNIT_VIDEO];
-
-/* Remove zero-padding from uncompressed incoming data. This will compensate for
- * the blocks of corruption that appear when the camera cannot keep up with the
- * speed of the USB bus (eg. at low frame resolutions) */
-static int remove_zeros; /* = 0 */
+static int remove_zeros;
+static int mirror;
 
 MODULE_PARM(autobright, "i");
 MODULE_PARM_DESC(autobright, "Sensor automatically changes brightness");
@@ -209,15 +132,13 @@
 MODULE_PARM(debug, "i");
 MODULE_PARM_DESC(debug,
   "Debug level: 0=none, 1=inits, 2=warning, 3=config, 4=functions, 5=max");
+MODULE_PARM(snapshot, "i");
+MODULE_PARM_DESC(snapshot, "Enable snapshot mode");
 MODULE_PARM(fix_rgb_offset, "i");
 MODULE_PARM_DESC(fix_rgb_offset,
   "Fix vertical misalignment of red and blue at 640x480");
-MODULE_PARM(snapshot, "i");
-MODULE_PARM_DESC(snapshot, "Enable snapshot mode");
 MODULE_PARM(force_rgb, "i");
 MODULE_PARM_DESC(force_rgb, "Read RGB instead of BGR");
-MODULE_PARM(buf_timeout, "i");
-MODULE_PARM_DESC(buf_timeout, "Number of seconds before buffer deallocation");
 MODULE_PARM(cams, "i");
 MODULE_PARM_DESC(cams, "Number of simultaneous cameras");
 MODULE_PARM(compress, "i");
@@ -225,11 +146,6 @@
 MODULE_PARM(testpat, "i");
 MODULE_PARM_DESC(testpat,
   "Replace image with vertical bar testpattern (only partially working)");
-
-// Temporarily removed (needs to be rewritten for new format conversion code)
-// MODULE_PARM(sensor_gbr, "i");
-// MODULE_PARM_DESC(sensor_gbr, "Make sensor output GBR422 rather than YUV420");
-
 MODULE_PARM(dumppix, "i");
 MODULE_PARM_DESC(dumppix, "Dump raw pixel data");
 MODULE_PARM(led, "i");
@@ -273,21 +189,25 @@
 MODULE_PARM_DESC(fastset, "Allows picture settings to take effect immediately");
 MODULE_PARM(force_palette, "i");
 MODULE_PARM_DESC(force_palette, "Force the palette to a specific value");
-MODULE_PARM(tuner, "i");
-MODULE_PARM_DESC(tuner, "Set tuner type, if not autodetected");
 MODULE_PARM(backlight, "i");
 MODULE_PARM_DESC(backlight, "For objects that are lit from behind");
-MODULE_PARM(unit_video, "0-16i");
+MODULE_PARM(unit_video, "1-" __MODULE_STRING(OV511_MAX_UNIT_VIDEO) "i");
 MODULE_PARM_DESC(unit_video,
   "Force use of specific minor number(s). 0 is not allowed.");
 MODULE_PARM(remove_zeros, "i");
 MODULE_PARM_DESC(remove_zeros,
   "Remove zero-padding from uncompressed incoming data");
+MODULE_PARM(mirror, "i");
+MODULE_PARM_DESC(mirror, "Reverse image horizontally");
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
+/**********************************************************************
+ * Miscellaneous Globals
+ **********************************************************************/
+
 static struct usb_driver ov511_driver;
 
 static struct ov51x_decomp_ops *ov511_decomp_ops;
@@ -302,20 +222,28 @@
 /* MMX support is present in kernel and CPU. Checked upon decomp module load. */
 static int ov51x_mmx_available;
 
-/* Function prototypes */
-static void ov51x_clear_snapshot(struct usb_ov511 *);
-static int ov51x_check_snapshot(struct usb_ov511 *);
-static inline int sensor_get_picture(struct usb_ov511 *, 
-				     struct video_picture *);
-static int sensor_get_exposure(struct usb_ov511 *, unsigned char *);
-static int ov51x_control_ioctl(struct inode *, struct file *, unsigned int,
-			       unsigned long);
+static __devinitdata struct usb_device_id device_table [] = {
+	{ USB_DEVICE(VEND_OMNIVISION, PROD_OV511) },
+	{ USB_DEVICE(VEND_OMNIVISION, PROD_OV511PLUS) },
+	{ USB_DEVICE(VEND_OMNIVISION, PROD_OV518) },
+	{ USB_DEVICE(VEND_OMNIVISION, PROD_OV518PLUS) },
+	{ USB_DEVICE(VEND_MATTEL, PROD_ME2CAM) },
+	{ }  /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, device_table);
+
+static unsigned char yQuanTable511[] = OV511_YQUANTABLE;
+static unsigned char uvQuanTable511[] = OV511_UVQUANTABLE;
+static unsigned char yQuanTable518[] = OV518_YQUANTABLE;
+static unsigned char uvQuanTable518[] = OV518_UVQUANTABLE;
 
 /**********************************************************************
- * List of known OV511-based cameras
+ * Symbolic Names
  **********************************************************************/
 
-static struct cam_list clist[] = {
+/* Known OV511-based cameras */
+static struct symbolic_list camlist[] = {
 	{   0, "Generic Camera (no ID)" },
 	{   1, "Mustek WCam 3X" },
 	{   3, "D-Link DSB-C300" },
@@ -323,11 +251,13 @@
 	{   5, "Puretek PT-6007" },
 	{   6, "Lifeview USB Life TV (NTSC)" },
 	{  21, "Creative Labs WebCam 3" },
+	{  22, "Lifeview USB Life TV (PAL D/K+B/G)" },
 	{  36, "Koala-Cam" },
-	{  38, "Lifeview USB Life TV" },
+	{  38, "Lifeview USB Life TV (PAL)" },
 	{  41, "Samsung Anycam MPC-M10" },
 	{  43, "Mtekvision Zeca MV402" },
 	{  46, "Suma eON" },
+	{  70, "Lifeview USB Life TV (PAL/SECAM)" },
 	{ 100, "Lifeview RoboCam" },
 	{ 102, "AverMedia InterCam Elite" },
 	{ 112, "MediaForte MV300" },	/* or OV7110 evaluation kit */
@@ -335,54 +265,84 @@
 	{  -1, NULL }
 };
 
-static __devinitdata struct usb_device_id device_table [] = {
-	{ USB_DEVICE(VEND_OMNIVISION, PROD_OV511) },
-	{ USB_DEVICE(VEND_OMNIVISION, PROD_OV511PLUS) },
-	{ USB_DEVICE(VEND_OMNIVISION, PROD_OV518) },
-	{ USB_DEVICE(VEND_OMNIVISION, PROD_OV518PLUS) },
-	{ USB_DEVICE(VEND_MATTEL, PROD_ME2CAM) },
-	{ }  /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, device_table);
-
-#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
-static struct palette_list plist[] = {
+/* Video4Linux1 Palettes */
+static struct symbolic_list v4l1_plist[] = {
 	{ VIDEO_PALETTE_GREY,	"GREY" },
-	{ VIDEO_PALETTE_HI240,  "HI240" },
-	{ VIDEO_PALETTE_RGB565, "RGB565" },
+	{ VIDEO_PALETTE_HI240,	"HI240" },
+	{ VIDEO_PALETTE_RGB565,	"RGB565" },
 	{ VIDEO_PALETTE_RGB24,	"RGB24" },
 	{ VIDEO_PALETTE_RGB32,	"RGB32" },
-	{ VIDEO_PALETTE_RGB555, "RGB555" },
-	{ VIDEO_PALETTE_YUV422, "YUV422" },
-	{ VIDEO_PALETTE_YUYV,   "YUYV" },
-	{ VIDEO_PALETTE_UYVY,   "UYVY" },
-	{ VIDEO_PALETTE_YUV420, "YUV420" },
-	{ VIDEO_PALETTE_YUV411, "YUV411" },
-	{ VIDEO_PALETTE_RAW,    "RAW" },
+	{ VIDEO_PALETTE_RGB555,	"RGB555" },
+	{ VIDEO_PALETTE_YUV422,	"YUV422" },
+	{ VIDEO_PALETTE_YUYV,	"YUYV" },
+	{ VIDEO_PALETTE_UYVY,	"UYVY" },
+	{ VIDEO_PALETTE_YUV420,	"YUV420" },
+	{ VIDEO_PALETTE_YUV411,	"YUV411" },
+	{ VIDEO_PALETTE_RAW,	"RAW" },
 	{ VIDEO_PALETTE_YUV422P,"YUV422P" },
 	{ VIDEO_PALETTE_YUV411P,"YUV411P" },
 	{ VIDEO_PALETTE_YUV420P,"YUV420P" },
 	{ VIDEO_PALETTE_YUV410P,"YUV410P" },
 	{ -1, NULL }
 };
-#endif
 
-static unsigned char yQuanTable511[] = OV511_YQUANTABLE;
-static unsigned char uvQuanTable511[] = OV511_UVQUANTABLE;
-static unsigned char yQuanTable518[] = OV518_YQUANTABLE;
-static unsigned char uvQuanTable518[] = OV518_UVQUANTABLE;
+static struct symbolic_list brglist[] = {
+	{ BRG_OV511,		"OV511" },
+	{ BRG_OV511PLUS,	"OV511+" },
+	{ BRG_OV518,		"OV518" },
+	{ BRG_OV518PLUS,	"OV518+" },
+	{ -1, NULL }
+};
+
+static struct symbolic_list senlist[] = {
+	{ SEN_OV76BE,	"OV76BE" },
+	{ SEN_OV7610,	"OV7610" },
+	{ SEN_OV7620,	"OV7620" },
+	{ SEN_OV7620AE,	"OV7620AE" },
+	{ SEN_OV6620,	"OV6620" },
+	{ SEN_OV6630,	"OV6630" },
+	{ SEN_OV6630AE,	"OV6630AE" },
+	{ SEN_OV6630AF,	"OV6630AF" },
+	{ SEN_OV8600,	"OV8600" },
+	{ SEN_KS0127,	"KS0127" },
+	{ SEN_KS0127B,	"KS0127B" },
+	{ SEN_SAA7111A,	"SAA7111A" },
+	{ -1, NULL }
+};
+
+/* URB error codes: */
+static struct symbolic_list urb_errlist[] = {
+	{ -ENOSR,	"Buffer error (overrun)" },
+	{ -EPIPE,	"Stalled (device not responding)" },
+	{ -EOVERFLOW,	"Babble (bad cable?)" },
+	{ -EPROTO,	"Bit-stuff error (bad cable?)" },
+	{ -EILSEQ,	"CRC/Timeout" },
+	{ -ETIMEDOUT,	"NAK (device does not respond)" },
+	{ -1, NULL }
+};
+
+/**********************************************************************
+ * Prototypes
+ **********************************************************************/
+
+static void ov51x_clear_snapshot(struct usb_ov511 *);
+static inline int sensor_get_picture(struct usb_ov511 *,
+				     struct video_picture *);
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+static int sensor_get_exposure(struct usb_ov511 *, unsigned char *);
+static int ov51x_control_ioctl(struct inode *, struct file *, unsigned int,
+			       unsigned long);
+static int ov51x_check_snapshot(struct usb_ov511 *);
+#endif
 
 /**********************************************************************
- *
  * Memory management
- *
  **********************************************************************/
 
 /* Here we want the physical address of the memory.
  * This is used when initializing the contents of the area.
  */
-static inline unsigned long 
+static inline unsigned long
 kvirt_to_pa(unsigned long adr)
 {
 	unsigned long kva, ret;
@@ -415,7 +375,7 @@
 	return mem;
 }
 
-static void 
+static void
 rvfree(void *mem, unsigned long size)
 {
 	unsigned long adr;
@@ -449,12 +409,12 @@
 #define YES_NO(x) ((x) ? "yes" : "no")
 
 /* /proc/video/ov511/<minor#>/info */
-static int 
+static int
 ov511_read_proc_info(char *page, char **start, off_t off, int count, int *eof,
 		     void *data)
 {
 	char *out = page;
-	int i, j, len;
+	int i, len;
 	struct usb_ov511 *ov = data;
 	struct video_picture p;
 	unsigned char exp;
@@ -470,8 +430,7 @@
 
 	out += sprintf(out, "driver_version  : %s\n", DRIVER_VERSION);
 	out += sprintf(out, "custom_id       : %d\n", ov->customid);
-	out += sprintf(out, "model           : %s\n", ov->desc ?
-		       clist[ov->desc].description : "unknown");
+	out += sprintf(out, "model           : %s\n", ov->desc);
 	out += sprintf(out, "streaming       : %s\n", YES_NO(ov->streaming));
 	out += sprintf(out, "grabbing        : %s\n", YES_NO(ov->grabbing));
 	out += sprintf(out, "compress        : %s\n", YES_NO(ov->compress));
@@ -492,36 +451,16 @@
 			       ov->frame[i].depth);
 		out += sprintf(out, "  size          : %d %d\n",
 			       ov->frame[i].width, ov->frame[i].height);
-		out += sprintf(out, "  format        : ");
-		for (j = 0; plist[j].num >= 0; j++) {
-			if (plist[j].num == ov->frame[i].format) {
-				out += sprintf(out, "%s\n", plist[j].name);
-				break;
-			}
-		}
-		if (plist[j].num < 0)
-			out += sprintf(out, "unknown\n");
+		out += sprintf(out, "  format        : %s\n",
+			       symbolic(v4l1_plist, ov->frame[i].format));
 		out += sprintf(out, "  data_buffer   : 0x%p\n",
 			       ov->frame[i].data);
 	}
 	out += sprintf(out, "snap_enabled    : %s\n", YES_NO(ov->snap_enabled));
 	out += sprintf(out, "bridge          : %s\n",
-		       ov->bridge == BRG_OV511 ? "OV511" :
-			ov->bridge == BRG_OV511PLUS ? "OV511+" :
-			ov->bridge == BRG_OV518 ? "OV518" :
-			ov->bridge == BRG_OV518PLUS ? "OV518+" :
-			"unknown");
+		       symbolic(brglist, ov->bridge));
 	out += sprintf(out, "sensor          : %s\n",
-		       ov->sensor == SEN_OV6620 ? "OV6620" :
-			ov->sensor == SEN_OV6630 ? "OV6630" :
-			ov->sensor == SEN_OV7610 ? "OV7610" :
-			ov->sensor == SEN_OV7620 ? "OV7620" :
-			ov->sensor == SEN_OV7620AE ? "OV7620AE" :
-			ov->sensor == SEN_OV8600 ? "OV8600" :
-			ov->sensor == SEN_KS0127 ? "KS0127" :
-			ov->sensor == SEN_KS0127B ? "KS0127B" :
-			ov->sensor == SEN_SAA7111A ? "SAA7111A" :
-			"unknown");
+		       symbolic(senlist, ov->sensor));
 	out += sprintf(out, "packet_size     : %d\n", ov->packet_size);
 	out += sprintf(out, "framebuffer     : 0x%p\n", ov->fbuf);
 
@@ -544,13 +483,13 @@
  * When the camera's button is pressed, the output of this will change from a
  * 0 to a 1 (ASCII). It will retain this value until it is read, after which
  * it will reset to zero.
- * 
+ *
  * SECURITY NOTE: Since reading this file can change the state of the snapshot
  * status, it is important for applications that open it to keep it locked
  * against access by other processes, using flock() or a similar mechanism. No
  * locking is provided by this driver.
  */
-static int 
+static int
 ov511_read_proc_button(char *page, char **start, off_t off, int count, int *eof,
 		       void *data)
 {
@@ -582,97 +521,95 @@
 	return len;
 }
 
-static void 
-create_proc_ov511_cam(struct usb_ov511 *ov511)
+static void
+create_proc_ov511_cam(struct usb_ov511 *ov)
 {
 	char dirname[10];
 
-	if (!ov511_proc_entry || !ov511)
+	if (!ov511_proc_entry || !ov)
 		return;
 
 	/* Create per-device directory */
-	snprintf(dirname, 10, "%d", ov511->vdev.minor);
+	snprintf(dirname, 10, "%d", ov->vdev.minor);
 	PDEBUG(4, "creating /proc/video/ov511/%s/", dirname);
-	ov511->proc_devdir = create_proc_entry(dirname, S_IFDIR,
-		ov511_proc_entry);
-	if (!ov511->proc_devdir)
+	ov->proc_devdir = create_proc_entry(dirname, S_IFDIR, ov511_proc_entry);
+	if (!ov->proc_devdir)
 		return;
-	ov511->proc_devdir->owner = THIS_MODULE;
+	ov->proc_devdir->owner = THIS_MODULE;
 
 	/* Create "info" entry (human readable device information) */
 	PDEBUG(4, "creating /proc/video/ov511/%s/info", dirname);
-	ov511->proc_info = create_proc_read_entry("info",
-		S_IFREG|S_IRUGO|S_IWUSR, ov511->proc_devdir,
-		ov511_read_proc_info, ov511);
-	if (!ov511->proc_info)
+	ov->proc_info = create_proc_read_entry("info", S_IFREG|S_IRUGO|S_IWUSR,
+		ov->proc_devdir, ov511_read_proc_info, ov);
+	if (!ov->proc_info)
 		return;
-	ov511->proc_info->owner = THIS_MODULE;
+	ov->proc_info->owner = THIS_MODULE;
 
 	/* Don't create it if old snapshot mode on (would cause race cond.) */
 	if (!snapshot) {
 		/* Create "button" entry (snapshot button status) */
 		PDEBUG(4, "creating /proc/video/ov511/%s/button", dirname);
-		ov511->proc_button = create_proc_read_entry("button",
-			S_IFREG|S_IRUGO|S_IWUSR, ov511->proc_devdir,
-			ov511_read_proc_button, ov511);
-		if (!ov511->proc_button)
+		ov->proc_button = create_proc_read_entry("button",
+			S_IFREG|S_IRUGO|S_IWUSR, ov->proc_devdir,
+			ov511_read_proc_button, ov);
+		if (!ov->proc_button)
 			return;
 	}
-	ov511->proc_button->owner = THIS_MODULE;
+	ov->proc_button->owner = THIS_MODULE;
 
 	/* Create "control" entry (ioctl() interface) */
 	PDEBUG(4, "creating /proc/video/ov511/%s/control", dirname);
 	lock_kernel();
-	ov511->proc_control = create_proc_entry("control",
-		S_IFREG|S_IRUGO|S_IWUSR, ov511->proc_devdir);
-	if (!ov511->proc_control) {
+	ov->proc_control = create_proc_entry("control",	S_IFREG|S_IRUGO|S_IWUSR,
+		ov->proc_devdir);
+	if (!ov->proc_control) {
 		unlock_kernel();
 		return;
 	}
-	ov511->proc_control->owner = THIS_MODULE;
-	ov511->proc_control->data = ov511;
-	ov511->proc_control->proc_fops = &ov511_control_fops;
+	ov->proc_control->owner = THIS_MODULE;
+	ov->proc_control->data = ov;
+	ov->proc_control->proc_fops = &ov511_control_fops;
 	unlock_kernel();
 }
 
-static void 
-destroy_proc_ov511_cam(struct usb_ov511 *ov511)
+static void
+destroy_proc_ov511_cam(struct usb_ov511 *ov)
 {
 	char dirname[10];
-	
-	if (!ov511 || !ov511->proc_devdir)
+
+	if (!ov || !ov->proc_devdir)
 		return;
 
-	snprintf(dirname, 10, "%d", ov511->vdev.minor);
+	snprintf(dirname, 10, "%d", ov->vdev.minor);
 
 	/* Destroy "control" entry */
-	if (ov511->proc_control) {
+	if (ov->proc_control) {
 		PDEBUG(4, "destroying /proc/video/ov511/%s/control", dirname);
-		remove_proc_entry("control", ov511->proc_devdir);
-		ov511->proc_control = NULL;
+		remove_proc_entry("control", ov->proc_devdir);
+		ov->proc_control = NULL;
 	}
 
 	/* Destroy "button" entry */
-	if (ov511->proc_button) {
+	if (ov->proc_button) {
 		PDEBUG(4, "destroying /proc/video/ov511/%s/button", dirname);
-		remove_proc_entry("button", ov511->proc_devdir);
-		ov511->proc_button = NULL;
+		remove_proc_entry("button", ov->proc_devdir);
+		ov->proc_button = NULL;
 	}
 
 	/* Destroy "info" entry */
-	if (ov511->proc_info) {
+	if (ov->proc_info) {
 		PDEBUG(4, "destroying /proc/video/ov511/%s/info", dirname);
-		remove_proc_entry("info", ov511->proc_devdir);
-		ov511->proc_info = NULL;
+		remove_proc_entry("info", ov->proc_devdir);
+		ov->proc_info = NULL;
 	}
 
 	/* Destroy per-device directory */
 	PDEBUG(4, "destroying /proc/video/ov511/%s/", dirname);
 	remove_proc_entry(dirname, ov511_proc_entry);
-	ov511->proc_devdir = NULL;
+	ov->proc_devdir = NULL;
 }
 
-static void 
+static void
 proc_ov511_create(void)
 {
 	/* No current standard here. Alan prefers /proc/video/ as it keeps
@@ -693,7 +630,7 @@
 		err("Unable to create /proc/video/ov511");
 }
 
-static void 
+static void
 proc_ov511_destroy(void)
 {
 	PDEBUG(3, "removing /proc/video/ov511");
@@ -712,7 +649,7 @@
  **********************************************************************/
 
 /* Write an OV51x register */
-static int 
+static int
 reg_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value)
 {
 	int rc;
@@ -723,20 +660,20 @@
 	ov->cbuf[0] = value;
 	rc = usb_control_msg(ov->dev,
 			     usb_sndctrlpipe(ov->dev, 0),
-			     2 /* REG_IO */,
-			     USB_TYPE_CLASS | USB_RECIP_DEVICE,
-			     0, (__u16)reg, &ov->cbuf[0], 1, HZ);	
+			     (ov->bclass == BCL_OV518)?1:2 /* REG_IO */,
+			     USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			     0, (__u16)reg, &ov->cbuf[0], 1, HZ);
 	up(&ov->cbuf_lock);
 
 	if (rc < 0)
-		err("reg write: error %d", rc);
+		err("reg write: error %d: %s", rc, symbolic(urb_errlist, rc));
 
 	return rc;
 }
 
 /* Read from an OV51x register */
 /* returns: negative is error, pos or zero is data */
-static int 
+static int
 reg_r(struct usb_ov511 *ov, unsigned char reg)
 {
 	int rc;
@@ -744,16 +681,16 @@
 	down(&ov->cbuf_lock);
 	rc = usb_control_msg(ov->dev,
 			     usb_rcvctrlpipe(ov->dev, 0),
-			     2 /* REG_IO */,
-			     USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE,
+			     (ov->bclass == BCL_OV518)?1:3 /* REG_IO */,
+			     USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 			     0, (__u16)reg, &ov->cbuf[0], 1, HZ);
-                               
-	PDEBUG(5, "0x%02X:0x%02X", reg, ov->cbuf[0]);
-	
-	if (rc < 0)
-		err("reg read: error %d", rc);
-	else
-		rc = ov->cbuf[0];	
+
+	if (rc < 0) {
+		err("reg read: error %d: %s", rc, symbolic(urb_errlist, rc));
+	} else {
+		rc = ov->cbuf[0];
+		PDEBUG(5, "0x%02X:0x%02X", reg, ov->cbuf[0]);
+	}
 
 	up(&ov->cbuf_lock);
 
@@ -763,10 +700,10 @@
 /*
  * Writes bits at positions specified by mask to an OV51x reg. Bits that are in
  * the same position as 1's in "mask" are cleared and set to "value". Bits
- * that are in the same position as 0's in "mask" are preserved, regardless 
+ * that are in the same position as 0's in "mask" are preserved, regardless
  * of their respective state in "value".
  */
-static int 
+static int
 reg_w_mask(struct usb_ov511 *ov,
 	   unsigned char reg,
 	   unsigned char value,
@@ -791,7 +728,7 @@
  * Writes multiple (n) byte value to a single register. Only valid with certain
  * registers (0x30 and 0xc4 - 0xce).
  */
-static int 
+static int
 ov518_reg_w32(struct usb_ov511 *ov, unsigned char reg, u32 val, int n)
 {
 	int rc;
@@ -804,18 +741,19 @@
 
 	rc = usb_control_msg(ov->dev,
 			     usb_sndctrlpipe(ov->dev, 0),
-			     2 /* REG_IO */,
-			     USB_TYPE_CLASS | USB_RECIP_DEVICE,
+			     1 /* REG_IO */,
+			     USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 			     0, (__u16)reg, ov->cbuf, n, HZ);
 	up(&ov->cbuf_lock);
 
 	if (rc < 0)
-		err("reg write multiple: error %d", rc);
+		err("reg write multiple: error %d: %s", rc,
+		    symbolic(urb_errlist, rc));
 
 	return rc;
 }
 
-static int 
+static int
 ov511_upload_quan_tables(struct usb_ov511 *ov)
 {
 	unsigned char *pYTable = yQuanTable511;
@@ -825,10 +763,8 @@
 
 	PDEBUG(4, "Uploading quantization tables");
 
-	for (i = 0; i < OV511_QUANTABLESIZE / 2; i++)
-	{
-		if (ENABLE_Y_QUANTABLE)
-		{
+	for (i = 0; i < OV511_QUANTABLESIZE / 2; i++) {
+		if (ENABLE_Y_QUANTABLE)	{
 			val0 = *pYTable++;
 			val1 = *pYTable++;
 			val0 &= 0x0f;
@@ -839,8 +775,7 @@
 				return rc;
 		}
 
-		if (ENABLE_UV_QUANTABLE)
-		{
+		if (ENABLE_UV_QUANTABLE) {
 			val0 = *pUVTable++;
 			val1 = *pUVTable++;
 			val0 &= 0x0f;
@@ -858,7 +793,7 @@
 }
 
 /* OV518 quantization tables are 8x4 (instead of 8x8) */
-static int 
+static int
 ov518_upload_quan_tables(struct usb_ov511 *ov)
 {
 	unsigned char *pYTable = yQuanTable518;
@@ -868,10 +803,8 @@
 
 	PDEBUG(4, "Uploading quantization tables");
 
-	for (i = 0; i < OV518_QUANTABLESIZE / 2; i++)
-	{
-		if (ENABLE_Y_QUANTABLE)
-		{
+	for (i = 0; i < OV518_QUANTABLESIZE / 2; i++) {
+		if (ENABLE_Y_QUANTABLE) {
 			val0 = *pYTable++;
 			val1 = *pYTable++;
 			val0 &= 0x0f;
@@ -882,8 +815,7 @@
 				return rc;
 		}
 
-		if (ENABLE_UV_QUANTABLE)
-		{
+		if (ENABLE_UV_QUANTABLE) {
 			val0 = *pUVTable++;
 			val1 = *pUVTable++;
 			val0 &= 0x0f;
@@ -900,16 +832,16 @@
 	return 0;
 }
 
-static int 
+static int
 ov51x_reset(struct usb_ov511 *ov, unsigned char reset_type)
 {
 	int rc;
-		
+
 	/* Setting bit 0 not allowed on 518/518Plus */
 	if (ov->bclass == BCL_OV518)
 		reset_type &= 0xfe;
 
-	PDEBUG(4, "Reset: type=0x%X", reset_type);
+	PDEBUG(4, "Reset: type=0x%02X", reset_type);
 
 	rc = reg_w(ov, R51x_SYS_RESET, reset_type);
 	rc = reg_w(ov, R51x_SYS_RESET, 0);
@@ -922,7 +854,7 @@
 
 /**********************************************************************
  *
- * I2C (sensor) I/O
+ * Low-level I2C I/O functions
  *
  **********************************************************************/
 
@@ -931,7 +863,7 @@
  * This is normally only called from i2c_w(). Note that this function
  * always succeeds regardless of whether the sensor is present and working.
  */
-static int 
+static int
 ov518_i2c_write_internal(struct usb_ov511 *ov,
 			 unsigned char reg,
 			 unsigned char value)
@@ -942,25 +874,21 @@
 
 	/* Select camera register */
 	rc = reg_w(ov, R51x_I2C_SADDR_3, reg);
-	if (rc < 0) goto error;
+	if (rc < 0) return rc;
 
 	/* Write "value" to I2C data port of OV511 */
 	rc = reg_w(ov, R51x_I2C_DATA, value);
-	if (rc < 0) goto error;
+	if (rc < 0) return rc;
 
 	/* Initiate 3-byte write cycle */
 	rc = reg_w(ov, R518_I2C_CTL, 0x01);
-	if (rc < 0) goto error;
+	if (rc < 0) return rc;
 
 	return 0;
-
-error:
-	err("ov518 i2c write: error %d", rc);
-	return rc;
 }
 
 /* NOTE: Do not call this function directly! */
-static int 
+static int
 ov511_i2c_write_internal(struct usb_ov511 *ov,
 			 unsigned char reg,
 			 unsigned char value)
@@ -973,38 +901,33 @@
 	for (retries = OV511_I2C_RETRIES; ; ) {
 		/* Select camera register */
 		rc = reg_w(ov, R51x_I2C_SADDR_3, reg);
-		if (rc < 0) goto error;
+		if (rc < 0) return rc;
 
 		/* Write "value" to I2C data port of OV511 */
-		rc = reg_w(ov, R51x_I2C_DATA, value);	
-		if (rc < 0) goto error;
+		rc = reg_w(ov, R51x_I2C_DATA, value);
+		if (rc < 0) return rc;
 
 		/* Initiate 3-byte write cycle */
 		rc = reg_w(ov, R511_I2C_CTL, 0x01);
-		if (rc < 0) goto error;
+		if (rc < 0) return rc;
 
 		do rc = reg_r(ov, R511_I2C_CTL);
 		while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */
-		if (rc < 0) goto error;
+		if (rc < 0) return rc;
 
 		if ((rc&2) == 0) /* Ack? */
 			break;
 #if 0
-		/* I2C abort */	
+		/* I2C abort */
 		reg_w(ov, R511_I2C_CTL, 0x10);
 #endif
 		if (--retries < 0) {
 			err("i2c write retries exhausted");
-			rc = -1;
-			goto error;
+			return -1;
 		}
 	}
 
 	return 0;
-
-error:
-	err("i2c write: error %d", rc);
-	return rc;
 }
 
 /* NOTE: Do not call this function directly!
@@ -1012,37 +935,33 @@
  * This is normally only called from i2c_r(). Note that this function
  * always succeeds regardless of whether the sensor is present and working.
  */
-static int 
+static int
 ov518_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg)
 {
 	int rc, value;
 
 	/* Select camera register */
 	rc = reg_w(ov, R51x_I2C_SADDR_2, reg);
-	if (rc < 0) goto error;
+	if (rc < 0) return rc;
 
 	/* Initiate 2-byte write cycle */
 	rc = reg_w(ov, R518_I2C_CTL, 0x03);
-	if (rc < 0) goto error;
+	if (rc < 0) return rc;
 
 	/* Initiate 2-byte read cycle */
 	rc = reg_w(ov, R518_I2C_CTL, 0x05);
-	if (rc < 0) goto error;
+	if (rc < 0) return rc;
 
 	value = reg_r(ov, R51x_I2C_DATA);
 
 	PDEBUG(5, "0x%02X:0x%02X", reg, value);
 
 	return value;
-
-error:
-	err("ov518 i2c read: error %d", rc);
-	return rc;
 }
 
 /* NOTE: Do not call this function directly!
  * returns: negative is error, pos or zero is data */
-static int 
+static int
 ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg)
 {
 	int rc, value, retries;
@@ -1051,26 +970,25 @@
 	for (retries = OV511_I2C_RETRIES; ; ) {
 		/* Select camera register */
 		rc = reg_w(ov, R51x_I2C_SADDR_2, reg);
-		if (rc < 0) goto error;
+		if (rc < 0) return rc;
 
 		/* Initiate 2-byte write cycle */
 		rc = reg_w(ov, R511_I2C_CTL, 0x03);
-		if (rc < 0) goto error;
+		if (rc < 0) return rc;
 
 		do rc = reg_r(ov, R511_I2C_CTL);
 		while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */
-		if (rc < 0) goto error;
+		if (rc < 0) return rc;
 
 		if ((rc&2) == 0) /* Ack? */
 			break;
 
-		/* I2C abort */	
+		/* I2C abort */
 		reg_w(ov, R511_I2C_CTL, 0x10);
 
 		if (--retries < 0) {
 			err("i2c write retries exhausted");
-			rc = -1;
-			goto error;
+			return -1;
 		}
 	}
 
@@ -1078,44 +996,39 @@
 	for (retries = OV511_I2C_RETRIES; ; ) {
 		/* Initiate 2-byte read cycle */
 		rc = reg_w(ov, R511_I2C_CTL, 0x05);
-		if (rc < 0) goto error;
+		if (rc < 0) return rc;
 
 		do rc = reg_r(ov, R511_I2C_CTL);
 		while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */
-		if (rc < 0) goto error;
+		if (rc < 0) return rc;
 
 		if ((rc&2) == 0) /* Ack? */
 			break;
 
-		/* I2C abort */	
+		/* I2C abort */
 		rc = reg_w(ov, R511_I2C_CTL, 0x10);
-		if (rc < 0) goto error;
+		if (rc < 0) return rc;
 
 		if (--retries < 0) {
 			err("i2c read retries exhausted");
-			rc = -1;
-			goto error;
+			return -1;
 		}
 	}
 
 	value = reg_r(ov, R51x_I2C_DATA);
 
 	PDEBUG(5, "0x%02X:0x%02X", reg, value);
-		
+
 	/* This is needed to make i2c_w() work */
 	rc = reg_w(ov, R511_I2C_CTL, 0x05);
 	if (rc < 0)
-		goto error;
-	
-	return value;
+		return rc;
 
-error:
-	err("i2c read: error %d", rc);
-	return rc;
+	return value;
 }
 
 /* returns: negative is error, pos or zero is data */
-static int 
+static int
 i2c_r(struct usb_ov511 *ov, unsigned char reg)
 {
 	int rc;
@@ -1132,7 +1045,7 @@
 	return rc;
 }
 
-static int 
+static int
 i2c_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value)
 {
 	int rc;
@@ -1150,7 +1063,7 @@
 }
 
 /* Do not call this function directly! */
-static int 
+static int
 ov51x_i2c_write_mask_internal(struct usb_ov511 *ov,
 			      unsigned char reg,
 			      unsigned char value,
@@ -1183,10 +1096,10 @@
 
 /* Writes bits at positions specified by mask to an I2C reg. Bits that are in
  * the same position as 1's in "mask" are cleared and set to "value". Bits
- * that are in the same position as 0's in "mask" are preserved, regardless 
+ * that are in the same position as 0's in "mask" are preserved, regardless
  * of their respective state in "value".
  */
-static int 
+static int
 i2c_w_mask(struct usb_ov511 *ov,
 	   unsigned char reg,
 	   unsigned char value,
@@ -1201,8 +1114,29 @@
 	return rc;
 }
 
+/* Set the read and write slave IDs. The "slave" argument is the write slave,
+ * and the read slave will be set to (slave + 1). ov->i2c_lock should be held
+ * when calling this. This should not be called from outside the i2c I/O
+ * functions.
+ */
+static inline int
+i2c_set_slave_internal(struct usb_ov511 *ov, unsigned char slave)
+{
+	int rc;
+
+	rc = reg_w(ov, R51x_I2C_W_SID, slave);
+	if (rc < 0) return rc;
+
+	rc = reg_w(ov, R51x_I2C_R_SID, slave + 1);
+	if (rc < 0) return rc;
+
+	return 0;
+}
+
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+
 /* Write to a specific I2C slave ID and register, using the specified mask */
-static int 
+static int
 i2c_w_slave(struct usb_ov511 *ov,
 	    unsigned char slave,
 	    unsigned char reg,
@@ -1214,38 +1148,22 @@
 	down(&ov->i2c_lock);
 
 	/* Set new slave IDs */
-	if (reg_w(ov, R51x_I2C_W_SID, slave) < 0) {
-		rc = -EIO;
-		goto out;
-	}
-
-	if (reg_w(ov, R51x_I2C_R_SID, slave + 1) < 0) {
-		rc = -EIO;
-		goto out;
-	}
+	rc = i2c_set_slave_internal(ov, slave);
+	if (rc < 0) goto out;
 
 	rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask);
-	/* Don't bail out yet if error; IDs must be restored */
 
+out:
 	/* Restore primary IDs */
-	slave = ov->primary_i2c_slave;
-	if (reg_w(ov, R51x_I2C_W_SID, slave) < 0) {
-		rc = -EIO;
-		goto out;
-	}
-
-	if (reg_w(ov, R51x_I2C_R_SID, slave + 1) < 0) {
-		rc = -EIO;
-		goto out;
-	}
+	if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0)
+		err("Couldn't restore primary I2C slave");
 
-out:
 	up(&ov->i2c_lock);
 	return rc;
 }
 
 /* Read from a specific I2C slave ID and register */
-static int 
+static int
 i2c_r_slave(struct usb_ov511 *ov,
 	    unsigned char slave,
 	    unsigned char reg)
@@ -1255,60 +1173,46 @@
 	down(&ov->i2c_lock);
 
 	/* Set new slave IDs */
-	if (reg_w(ov, R51x_I2C_W_SID, slave) < 0) {
-		rc = -EIO;
-		goto out;
-	}
-
-	if (reg_w(ov, R51x_I2C_R_SID, slave + 1) < 0) {
-		rc = -EIO;
-		goto out;
-	}
+	rc = i2c_set_slave_internal(ov, slave);
+	if (rc < 0) goto out;
 
 	if (ov->bclass == BCL_OV518)
 		rc = ov518_i2c_read_internal(ov, reg);
 	else
 		rc = ov511_i2c_read_internal(ov, reg);
-	/* Don't bail out yet if error; IDs must be restored */
 
+out:
 	/* Restore primary IDs */
-	slave = ov->primary_i2c_slave;
-	if (reg_w(ov, R51x_I2C_W_SID, slave) < 0) {
-		rc = -EIO;
-		goto out;
-	}
+	if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0)
+		err("Couldn't restore primary I2C slave");
 
-	if (reg_w(ov, R51x_I2C_R_SID, slave + 1) < 0) {
-		rc = -EIO;
-		goto out;
-	}
-
-out:
 	up(&ov->i2c_lock);
 	return rc;
 }
 
+#endif /* defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) */
+
 /* Sets I2C read and write slave IDs. Returns <0 for error */
-static int 
+static int
 ov51x_set_slave_ids(struct usb_ov511 *ov, unsigned char sid)
 {
-	down(&ov->i2c_lock);
+	int rc;
 
-	if (reg_w(ov, R51x_I2C_W_SID, sid) < 0)
-		return -EIO;
+	down(&ov->i2c_lock);
 
-	if (reg_w(ov, R51x_I2C_R_SID, sid + 1) < 0)
-		return -EIO;
+	rc = i2c_set_slave_internal(ov, sid);
+	if (rc < 0) goto out;
 
-	if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0)
-		return -EIO;
+	// FIXME: Is this actually necessary?
+	rc = ov51x_reset(ov, OV511_RESET_NOREGS);
+	if (rc < 0) goto out;
 
+out:
 	up(&ov->i2c_lock);
-
-	return 0;
+	return rc;
 }
 
-static int 
+static int
 write_regvals(struct usb_ov511 *ov, struct ov511_regvals * pRegvals)
 {
 	int rc;
@@ -1316,26 +1220,21 @@
 	while (pRegvals->bus != OV511_DONE_BUS) {
 		if (pRegvals->bus == OV511_REG_BUS) {
 			if ((rc = reg_w(ov, pRegvals->reg, pRegvals->val)) < 0)
-				goto error;
+				return rc;
 		} else if (pRegvals->bus == OV511_I2C_BUS) {
 			if ((rc = i2c_w(ov, pRegvals->reg, pRegvals->val)) < 0)
-				goto error;
+				return rc;
 		} else {
 			err("Bad regval array");
-			rc = -1;
-			goto error;
+			return -1;
 		}
 		pRegvals++;
 	}
 	return 0;
-
-error:
-	err("write regvals: error %d", rc);
-	return rc;
 }
 
-#ifdef OV511_DEBUG 
-static void 
+#ifdef OV511_DEBUG
+static void
 dump_i2c_range(struct usb_ov511 *ov, int reg1, int regn)
 {
 	int i;
@@ -1343,18 +1242,18 @@
 
 	for (i = reg1; i <= regn; i++) {
 		rc = i2c_r(ov, i);
-		info("OV7610[0x%X] = 0x%X", i, rc);
+		info("Sensor[0x%02X] = 0x%02X", i, rc);
 	}
 }
 
-static void 
+static void
 dump_i2c_regs(struct usb_ov511 *ov)
 {
 	info("I2C REGS");
 	dump_i2c_range(ov, 0x00, 0x7C);
 }
 
-static void 
+static void
 dump_reg_range(struct usb_ov511 *ov, int reg1, int regn)
 {
 	int i;
@@ -1362,12 +1261,12 @@
 
 	for (i = reg1; i <= regn; i++) {
 		rc = reg_r(ov, i);
-		info("OV511[0x%X] = 0x%X", i, rc);
+		info("OV511[0x%02X] = 0x%02X", i, rc);
 	}
 }
 
 /* FIXME: Should there be an OV518 version of this? */
-static void 
+static void
 ov511_dump_regs(struct usb_ov511 *ov)
 {
 	info("CAMERA INTERFACE REGS");
@@ -1394,43 +1293,29 @@
 }
 #endif
 
-/**********************************************************************
- *
- * Kernel I2C Interface
- *
- **********************************************************************/
-
-/* For as-yet unimplemented I2C interface */
-static void 
-call_i2c_clients(struct usb_ov511 *ov, unsigned int cmd,
-		 void *arg)
-{
-	/* Do nothing */
-}
-
 /*****************************************************************************/
 
 /* Temporarily stops OV511 from functioning. Must do this before changing
  * registers while the camera is streaming */
-static inline int 
+static inline int
 ov51x_stop(struct usb_ov511 *ov)
 {
 	PDEBUG(4, "stopping");
-	ov->stopped = 1;	
+	ov->stopped = 1;
 	if (ov->bclass == BCL_OV518)
-		return (reg_w(ov, R51x_SYS_RESET, 0x3a));
+		return (reg_w_mask(ov, R51x_SYS_RESET, 0x3a, 0x3a));
 	else
 		return (reg_w(ov, R51x_SYS_RESET, 0x3d));
 }
 
 /* Restarts OV511 after ov511_stop() is called. Has no effect if it is not
  * actually stopped (for performance). */
-static inline int 
+static inline int
 ov51x_restart(struct usb_ov511 *ov)
 {
 	if (ov->stopped) {
 		PDEBUG(4, "restarting");
-		ov->stopped = 0;	
+		ov->stopped = 0;
 
 		/* Reinitialize the stream */
 		if (ov->bclass == BCL_OV518)
@@ -1443,7 +1328,7 @@
 }
 
 /* Resets the hardware snapshot button */
-static void 
+static void
 ov51x_clear_snapshot(struct usb_ov511 *ov)
 {
 	if (ov->bclass == BCL_OV511) {
@@ -1455,12 +1340,12 @@
 	} else {
 		err("clear snap: invalid bridge type");
 	}
-	
 }
 
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
 /* Checks the status of the snapshot button. Returns 1 if it was pressed since
  * it was last cleared, and zero in all other cases (including errors) */
-static int 
+static int
 ov51x_check_snapshot(struct usb_ov511 *ov)
 {
 	int ret, status = 0;
@@ -1480,19 +1365,20 @@
 
 	return status;
 }
+#endif
 
 /* This does an initial reset of an OmniVision sensor and ensures that I2C
  * is synchronized. Returns <0 for failure.
  */
-static int 
+static int
 init_ov_sensor(struct usb_ov511 *ov)
 {
 	int i, success;
 
-	/* Reset the sensor */ 
+	/* Reset the sensor */
 	if (i2c_w(ov, 0x12, 0x80) < 0) return -EIO;
 
-	/* Wait for it to initialize */ 
+	/* Wait for it to initialize */
 	schedule_timeout (1 + 150 * HZ / 1000);
 
 	for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) {
@@ -1502,9 +1388,9 @@
 			continue;
 		}
 
-		/* Reset the sensor */ 
+		/* Reset the sensor */
 		if (i2c_w(ov, 0x12, 0x80) < 0) return -EIO;
-		/* Wait for it to initialize */ 
+		/* Wait for it to initialize */
 		schedule_timeout(1 + 150 * HZ / 1000);
 		/* Dummy read to sync I2C */
 		if (i2c_r(ov, 0x00) < 0) return -EIO;
@@ -1512,14 +1398,14 @@
 
 	if (!success)
 		return -EIO;
-	
+
 	PDEBUG(1, "I2C synced in %d attempt(s)", i);
 
 	return 0;
 }
 
-static int 
-ov51x_set_packet_size(struct usb_ov511 *ov, int size)
+static int
+ov511_set_packet_size(struct usb_ov511 *ov, int size)
 {
 	int alt, mult;
 
@@ -1551,7 +1437,44 @@
 			err("Set packet size: invalid size (%d)", size);
 			return -EINVAL;
 		}
-	} else if (ov->bclass == BCL_OV518) {
+	} else {
+		err("Set packet size: Invalid bridge type");
+		return -EINVAL;
+	}
+
+	PDEBUG(3, "%d, mult=%d, alt=%d", size, mult, alt);
+
+	if (reg_w(ov, R51x_FIFO_PSIZE, mult) < 0)
+		return -EIO;
+
+	if (usb_set_interface(ov->dev, ov->iface, alt) < 0) {
+		err("Set packet size: set interface error");
+		return -EBUSY;
+	}
+
+	if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0)
+		return -EIO;
+
+	ov->packet_size = size;
+
+	if (ov51x_restart(ov) < 0)
+		return -EIO;
+
+	return 0;
+}
+
+/* Note: Unlike the OV511/OV511+, the size argument does NOT include the
+ * optional packet number byte. The actual size *is* stored in ov->packet_size,
+ * though. */
+static int
+ov518_set_packet_size(struct usb_ov511 *ov, int size)
+{
+	int alt;
+
+	if (ov51x_stop(ov) < 0)
+		return -EIO;
+
+	if (ov->bclass == BCL_OV518) {
 		if (size == 0) alt = OV518_ALT_SIZE_0;
 		else if (size == 128) alt = OV518_ALT_SIZE_128;
 		else if (size == 256) alt = OV518_ALT_SIZE_256;
@@ -1569,35 +1492,32 @@
 		return -EINVAL;
 	}
 
-	PDEBUG(3, "set packet size: %d, mult=%d, alt=%d", size, mult, alt);
+	PDEBUG(3, "%d, alt=%d", size, alt);
 
-	// FIXME: Don't know how to do this on OV518 yet
-	if (ov->bclass == BCL_OV511) {
-		if (reg_w(ov, R51x_FIFO_PSIZE,
-				    mult) < 0) {
-			return -EIO;
-		}
+	ov->packet_size = size;
+	if (size > 0) {
+		/* Program ISO FIFO size reg (packet number isn't included) */
+		ov518_reg_w32(ov, 0x30, size, 2);
+
+		if (ov->packet_numbering)
+			++ov->packet_size;
 	}
-	
+
 	if (usb_set_interface(ov->dev, ov->iface, alt) < 0) {
 		err("Set packet size: set interface error");
 		return -EBUSY;
 	}
 
 	/* Initialize the stream */
-	if (ov->bclass == BCL_OV518)
-		if (reg_w(ov, 0x2f, 0x80) < 0)
-			return -EIO;
-
-	// FIXME - Should we only reset the FIFO?
-	if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0)
+	if (reg_w(ov, 0x2f, 0x80) < 0)
 		return -EIO;
 
-	ov->packet_size = size;
-
 	if (ov51x_restart(ov) < 0)
 		return -EIO;
 
+	if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0)
+		return -EIO;
+
 	return 0;
 }
 
@@ -1608,7 +1528,6 @@
 	int rc = 0;
 
 	if (!ov->compress_inited) {
-
 		reg_w(ov, 0x70, phy);
 		reg_w(ov, 0x71, phuv);
 		reg_w(ov, 0x72, pvy);
@@ -1626,7 +1545,7 @@
 	}
 
 	ov->compress_inited = 1;
-out:	
+out:
 	return rc;
 }
 
@@ -1637,7 +1556,6 @@
 	int rc = 0;
 
 	if (!ov->compress_inited) {
-
 		if (ov518_upload_quan_tables(ov) < 0) {
 			err("Error uploading quantization tables");
 			rc = -EIO;
@@ -1646,7 +1564,7 @@
 	}
 
 	ov->compress_inited = 1;
-out:	
+out:
 	return rc;
 }
 
@@ -1667,13 +1585,19 @@
 	switch (ov->sensor) {
 	case SEN_OV7610:
 	case SEN_OV6620:
-	case SEN_OV6630:
 	{
 		rc = i2c_w(ov, OV7610_REG_CNT, val >> 8);
 		if (rc < 0)
 			goto out;
 		break;
 	}
+	case SEN_OV6630:
+	{
+		rc = i2c_w_mask(ov, OV7610_REG_CNT, val >> 12, 0x0f);
+		if (rc < 0)
+			goto out;
+		break;
+	}
 	case SEN_OV7620:
 	{
 		unsigned char ctab[] = {
@@ -1720,13 +1644,19 @@
 	switch (ov->sensor) {
 	case SEN_OV7610:
 	case SEN_OV6620:
-	case SEN_OV6630:
 		rc = i2c_r(ov, OV7610_REG_CNT);
 		if (rc < 0)
 			return rc;
 		else
 			*val = rc << 8;
 		break;
+	case SEN_OV6630:
+		rc = i2c_r(ov, OV7610_REG_CNT);
+		if (rc < 0)
+			return rc;
+		else
+			*val = rc << 12;
+		break;
 	case SEN_OV7620:
 		/* Use Y gamma reg instead. Bit 0 is the enable bit. */
 		rc = i2c_r(ov, 0x64);
@@ -1765,7 +1695,7 @@
 
 	switch (ov->sensor) {
 	case SEN_OV7610:
-	case SEN_OV7620AE:
+	case SEN_OV76BE:
 	case SEN_OV6620:
 	case SEN_OV6630:
 		rc = i2c_w(ov, OV7610_REG_BRT, val >> 8);
@@ -1808,7 +1738,7 @@
 
 	switch (ov->sensor) {
 	case SEN_OV7610:
-	case SEN_OV7620AE:
+	case SEN_OV76BE:
 	case SEN_OV7620:
 	case SEN_OV6620:
 	case SEN_OV6630:
@@ -1848,7 +1778,7 @@
 
 	switch (ov->sensor) {
 	case SEN_OV7610:
-	case SEN_OV7620AE:
+	case SEN_OV76BE:
 	case SEN_OV6620:
 	case SEN_OV6630:
 		rc = i2c_w(ov, OV7610_REG_SAT, val >> 8);
@@ -1892,7 +1822,7 @@
 
 	switch (ov->sensor) {
 	case SEN_OV7610:
-	case SEN_OV7620AE:
+	case SEN_OV76BE:
 	case SEN_OV6620:
 	case SEN_OV6630:
 		rc = i2c_r(ov, OV7610_REG_SAT);
@@ -2091,6 +2021,7 @@
 	return 0;
 }
 
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
 // FIXME: Exposure range is only 0x00-0x7f in interlace mode
 /* Sets current exposure for sensor. This only has an effect if auto-exposure
  * is off */
@@ -2110,7 +2041,7 @@
 	case SEN_OV6630:
 	case SEN_OV7610:
 	case SEN_OV7620:
-	case SEN_OV7620AE:
+	case SEN_OV76BE:
 	case SEN_OV8600:
 		rc = i2c_w(ov, 0x10, val);
 		if (rc < 0)
@@ -2148,7 +2079,7 @@
 	case SEN_OV6620:
 	case SEN_OV6630:
 	case SEN_OV7620:
-	case SEN_OV7620AE:
+	case SEN_OV76BE:
 	case SEN_OV8600:
 		rc = i2c_r(ov, 0x10);
 		if (rc < 0)
@@ -2172,9 +2103,10 @@
 
 	return 0;
 }
+#endif /* CONFIG_PROC_FS && CONFIG_VIDEO_PROC_FS */
 
 /* Turns on or off the LED. Only has an effect with OV511+/OV518(+) */
-static inline void 
+static inline void
 ov51x_led_control(struct usb_ov511 *ov, int enable)
 {
 	PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
@@ -2192,7 +2124,7 @@
  *	50 - 50Hz, for European and Asian lighting
  *	60 - 60Hz, for American lighting
  *
- * Tested with: OV7610, OV7620, OV7620AE, OV6620
+ * Tested with: OV7610, OV7620, OV76BE, OV6620
  * Unsupported: KS0127, KS0127B, SAA7111A
  * Returns: 0 for success
  */
@@ -2220,12 +2152,12 @@
 		i2c_w_mask(ov, 0x13, 0x00, 0x10);
 		break;
 	case SEN_OV7620:
-	case SEN_OV7620AE:
+	case SEN_OV76BE:
 	case SEN_OV8600:
 		i2c_w_mask(ov, 0x2a, sixty?0x00:0x80, 0x80);
 		i2c_w(ov, 0x2b, sixty?0x00:0xac);
 		i2c_w_mask(ov, 0x76, 0x01, 0x01);
-		break;		
+		break;
 	case SEN_OV6620:
 	case SEN_OV6630:
 		i2c_w(ov, 0x2b, sixty?0xa8:0x28);
@@ -2251,7 +2183,7 @@
  * caused by some (usually fluorescent) lighting. The light frequency must be
  * set either before or after enabling it with ov51x_set_light_freq().
  *
- * Tested with: OV7610, OV7620, OV7620AE, OV6620.
+ * Tested with: OV7610, OV7620, OV76BE, OV6620.
  * Unsupported: KS0127, KS0127B, SAA7111A
  * Returns: 0 for success
  */
@@ -2313,7 +2245,7 @@
  */
 static inline int
 sensor_set_auto_exposure(struct usb_ov511 *ov, int enable)
-{	
+{
 	PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
 
 	switch (ov->sensor) {
@@ -2322,10 +2254,10 @@
 		break;
 	case SEN_OV6620:
 	case SEN_OV7620:
-	case SEN_OV7620AE:
+	case SEN_OV76BE:
 	case SEN_OV8600:
 		i2c_w_mask(ov, 0x13, enable?0x01:0x00, 0x01);
-		break;		
+		break;
 	case SEN_OV6630:
 		i2c_w_mask(ov, 0x28, enable?0x00:0x10, 0x10);
 		break;
@@ -2348,13 +2280,12 @@
  * that are illuminated from behind.
  *
  * Tested with: OV6620, OV7620
- * Unsupported: OV7610, OV7620AE, KS0127, KS0127B, SAA7111A
+ * Unsupported: OV7610, OV76BE, KS0127, KS0127B, SAA7111A
  * Returns: 0 for success
  */
 static int
 sensor_set_backlight(struct usb_ov511 *ov, int enable)
 {
-
 	PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
 
 	switch (ov->sensor) {
@@ -2363,7 +2294,7 @@
 		i2c_w_mask(ov, 0x68, enable?0xe0:0xc0, 0xe0);
 		i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08);
 		i2c_w_mask(ov, 0x28, enable?0x02:0x00, 0x02);
-		break;		
+		break;
 	case SEN_OV6620:
 		i2c_w_mask(ov, 0x4e, enable?0xe0:0xc0, 0xe0);
 		i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08);
@@ -2375,7 +2306,7 @@
 		i2c_w_mask(ov, 0x28, enable?0x02:0x00, 0x02);
 		break;
 	case SEN_OV7610:
-	case SEN_OV7620AE:
+	case SEN_OV76BE:
 	case SEN_KS0127:
 	case SEN_KS0127B:
 	case SEN_SAA7111A:
@@ -2391,27 +2322,56 @@
 	return 0;
 }
 
+static inline int
+sensor_set_mirror(struct usb_ov511 *ov, int enable)
+{
+	PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
+
+	switch (ov->sensor) {
+	case SEN_OV6620:
+	case SEN_OV6630:
+	case SEN_OV7610:
+	case SEN_OV7620:
+	case SEN_OV76BE:
+	case SEN_OV8600:
+		i2c_w_mask(ov, 0x12, enable?0x40:0x00, 0x40);
+		break;
+	case SEN_KS0127:
+	case SEN_KS0127B:
+	case SEN_SAA7111A:
+		PDEBUG(5, "Unsupported with this sensor");
+		return -EPERM;
+	default:
+		err("Sensor not supported for set_mirror");
+		return -EINVAL;
+	}
+
+	ov->mirror = enable;
+
+	return 0;
+}
+
 /* Returns number of bits per pixel (regardless of where they are located;
  * planar or not), or zero for unsupported format.
  */
-static inline int 
+static inline int
 get_depth(int palette)
 {
 	switch (palette) {
 	case VIDEO_PALETTE_GREY:    return 8;
+	case VIDEO_PALETTE_YUV420:  return 12;
+	case VIDEO_PALETTE_YUV420P: return 12; /* Planar */
 	case VIDEO_PALETTE_RGB565:  return 16;
-	case VIDEO_PALETTE_RGB24:   return 24;  
+	case VIDEO_PALETTE_RGB24:   return 24;
 	case VIDEO_PALETTE_YUV422:  return 16;
 	case VIDEO_PALETTE_YUYV:    return 16;
-	case VIDEO_PALETTE_YUV420:  return 12;
 	case VIDEO_PALETTE_YUV422P: return 16; /* Planar */
-	case VIDEO_PALETTE_YUV420P: return 12; /* Planar */
 	default:		    return 0;  /* Invalid format */
 	}
 }
 
 /* Bytes per frame. Used by read(). Return of 0 indicates error */
-static inline long int 
+static inline long int
 get_frame_length(struct ov511_frame *frame)
 {
 	if (!frame)
@@ -2451,7 +2411,7 @@
 		i2c_w_mask(ov, 0x67, qvga?0xf0:0x90, 0xf0);
 		i2c_w_mask(ov, 0x74, qvga?0x20:0x00, 0x20);
 		break;
-	case SEN_OV7620AE:
+	case SEN_OV76BE:
 //		i2c_w(ov, 0x2b, 0x00);
 		i2c_w(ov, 0x14, qvga?0xa4:0x84);
 // FIXME: Enable this once 7620AE uses 7620 initial settings
@@ -2477,13 +2437,13 @@
 	/******** Palette-specific regs ********/
 
 	if (mode == VIDEO_PALETTE_GREY) {
-		if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV7620AE) {
+		if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) {
 			/* these aren't valid on the OV6620/OV7620/6630? */
 			i2c_w_mask(ov, 0x0e, 0x40, 0x40);
 		}
 		i2c_w_mask(ov, 0x13, 0x20, 0x20);
 	} else {
-		if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV7620AE) {
+		if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) {
 			/* not valid on the OV6620/OV7620/6630? */
 			i2c_w_mask(ov, 0x0e, 0x00, 0x40);
 		}
@@ -2545,8 +2505,7 @@
 	if (framedrop >= 0)
 		i2c_w(ov, 0x16, framedrop);
 
-	/* We only have code to convert GBR -> RGB24 */
-	if ((mode == VIDEO_PALETTE_RGB24) && sensor_gbr)
+	if (sensor_gbr)
 		i2c_w_mask(ov, 0x12, 0x08, 0x08);
 	else
 		i2c_w_mask(ov, 0x12, 0x00, 0x08);
@@ -2563,7 +2522,7 @@
 	// This will go away as soon as ov51x_mode_init_sensor_regs()
 	// is fully tested.
 	/* 7620/6620/6630? don't have register 0x35, so play it safe */
-	if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV7620AE) {
+	if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) {
 		if (width == 640 && height == 480)
 			i2c_w(ov, 0x35, 0x9e);
 		else
@@ -2585,13 +2544,13 @@
 	 * IF YOU SET IT WRONG, YOU WILL GET ALL ZERO ISOC DATA FROM OV51x!!! */
 	switch (ov->sensor) {
 	case SEN_OV7610:
-	case SEN_OV7620AE:
+	case SEN_OV76BE:
 		hwsbase = 0x38;
 		hwebase = 0x3a;
 		vwsbase = vwebase = 0x05;
 		break;
 	case SEN_OV6620:
-	case SEN_OV6630:	// FIXME: Is this right?
+	case SEN_OV6630:
 		hwsbase = 0x38;
 		hwebase = 0x3a;
 		vwsbase = 0x05;
@@ -2608,7 +2567,9 @@
 	}
 
 	if (ov->sensor == SEN_OV6620 || ov->sensor == SEN_OV6630) {
-		if (width > 176 && height > 144) {  /* CIF */
+		/* Note: OV518(+) does downsample on its own) */
+		if ((width > 176 && height > 144)
+		    || ov->bclass == BCL_OV518) {  /* CIF */
 			ret = mode_init_ov_sensor_regs(ov, width, height,
 				mode, sub_flag, 0);
 			if (ret < 0)
@@ -2685,7 +2646,7 @@
 ov511_mode_init_regs(struct usb_ov511 *ov,
 		     int width, int height, int mode, int sub_flag)
 {
-	int lncnt, pxcnt, rc = 0;
+	int hsegs, vsegs;
 
 	if (sub_flag) {
 		width = ov->subw;
@@ -2701,11 +2662,11 @@
 		if (width == 320 && height == 240) {
 			/* No need to do anything special */
 		} else if (width == 640 && height == 480) {
-			/* Set the OV511 up as 320x480, but keep the V4L
-			 * resolution as 640x480 */
+			/* Set the OV511 up as 320x480, but keep the
+			 * V4L resolution as 640x480 */
 			width = 320;
 		} else {
-			err("SAA7111A only supports 320x240 or 640x480");
+			err("SAA7111A only allows 320x240 or 640x480");
 			return -EINVAL;
 		}
 	}
@@ -2737,11 +2698,11 @@
 	/* Here I'm assuming that snapshot size == image size.
 	 * I hope that's always true. --claudio
 	 */
-	pxcnt = (width >> 3) - 1;
-	lncnt = (height >> 3) - 1;
+	hsegs = (width >> 3) - 1;
+	vsegs = (height >> 3) - 1;
 
-	reg_w(ov, R511_CAM_PXCNT, pxcnt);
-	reg_w(ov, R511_CAM_LNCNT, lncnt);
+	reg_w(ov, R511_CAM_PXCNT, hsegs);
+	reg_w(ov, R511_CAM_LNCNT, vsegs);
 	reg_w(ov, R511_CAM_PXDIV, 0x00);
 	reg_w(ov, R511_CAM_LNDIV, 0x00);
 
@@ -2749,8 +2710,8 @@
 	reg_w(ov, R511_CAM_OPTS, 0x03);
 
 	/* Snapshot additions */
-	reg_w(ov, R511_SNAP_PXCNT, pxcnt);
-	reg_w(ov, R511_SNAP_LNCNT, lncnt);
+	reg_w(ov, R511_SNAP_PXCNT, hsegs);
+	reg_w(ov, R511_SNAP_LNCNT, vsegs);
 	reg_w(ov, R511_SNAP_PXDIV, 0x00);
 	reg_w(ov, R511_SNAP_LNDIV, 0x00);
 
@@ -2760,27 +2721,17 @@
 		reg_w(ov, R511_COMP_LUT_EN, 0x03);
 		ov51x_reset(ov, OV511_RESET_OMNICE);
 	}
-//out:
+
 	if (ov51x_restart(ov) < 0)
 		return -EIO;
 
-	return rc;
+	return 0;
 }
 
-static struct mode_list_518 mlist518[] = {
-	/* W    H   reg28 reg29 reg2a reg2c reg2e reg24 reg25 */
-	{ 352, 288, 0x00, 0x16, 0x48, 0x00, 0x00, 0x9f, 0x90 },
-	{ 320, 240, 0x00, 0x14, 0x3c, 0x10, 0x18, 0x9f, 0x90 },
-	{ 176, 144, 0x05, 0x0b, 0x24, 0x00, 0x00, 0xff, 0xf0 },
-	{ 160, 120, 0x05, 0x0a, 0x1e, 0x08, 0x0c, 0xff, 0xf0 },
-	{ 0, 0 }
-};
-
 /* Sets up the OV518/OV518+ with the given image parameters
  *
  * OV518 needs a completely different approach, until we can figure out what
- * the individual registers do. Many register ops are commented out until we
- * can find out if they are still valid. Also, only 15 FPS is supported now.
+ * the individual registers do. Also, only 15 FPS is supported now.
  *
  * Do not put any sensor-specific code in here (including I2C I/O functions)
  */
@@ -2788,112 +2739,110 @@
 ov518_mode_init_regs(struct usb_ov511 *ov,
 		     int width, int height, int mode, int sub_flag)
 {
-	int i;
+	int hsegs, vsegs, hi_res;
+
+	if (sub_flag) {
+		width = ov->subw;
+		height = ov->subh;
+	}
 
 	PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d",
 	       width, height, mode, sub_flag);
 
+	if (width % 16 || height % 8) {
+		err("Invalid size (%d, %d)", width, height);
+		return -EINVAL;
+	}
+
+	if (width < ov->minwidth || height < ov->minheight) {
+		err("Requested dimensions are too small");
+		return -EINVAL;
+	}
+
+	if (width >= 320 && height >= 240) {
+		hi_res = 1;
+	} else if (width >= 320 || height >= 240) {
+		err("Invalid width/height combination (%d, %d)", width, height);
+		return -EINVAL;
+	} else {
+		hi_res = 0;
+	}
+
 	if (ov51x_stop(ov) < 0)
 		return -EIO;
 
-	for (i = 0; mlist518[i].width; i++) {
-//		int lncnt, pxcnt;
+	/******** Set the mode ********/
 
-		if (width != mlist518[i].width || height != mlist518[i].height)
-			continue;
+	reg_w(ov, 0x2b, 0);
+	reg_w(ov, 0x2c, 0);
+	reg_w(ov, 0x2d, 0);
+	reg_w(ov, 0x2e, 0);
+	reg_w(ov, 0x3b, 0);
+	reg_w(ov, 0x3c, 0);
+	reg_w(ov, 0x3d, 0);
+	reg_w(ov, 0x3e, 0);
 
-// FIXME: Subcapture won't be possible until we know what the registers do
-// FIXME: We can't handle anything but YUV420 so far
+	reg_w(ov, 0x28, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80);
+	reg_w(ov, 0x38, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80);
 
-//		/* Here I'm assuming that snapshot size == image size.
-//		 * I hope that's always true. --claudio
-//		 */
-//		pxcnt = sub_flag ? (ov511->subw >> 3) - 1 : mlist[i].pxcnt;
-//		lncnt = sub_flag ? (ov511->subh >> 3) - 1 : mlist[i].lncnt;
-//
-//		reg_w(ov511, 0x12, pxcnt);
-//		reg_w(ov511, 0x13, lncnt);
-
-		/******** Set the mode ********/		
-
-		/* Mode independent regs */
-		reg_w(ov, 0x2b, 0x00);
-		reg_w(ov, 0x2d, 0x00);
-		reg_w(ov, 0x3b, 0x00);
-		reg_w(ov, 0x3d, 0x00);
-
-		/* Mode dependent regs. Regs 38 - 3e are always the same as
-		 * regs 28 - 2e */
-		reg_w_mask(ov, 0x28, mlist518[i].reg28
-			| (mode == VIDEO_PALETTE_GREY) ? 0x80:0x00, 0x8f);
-		reg_w(ov, 0x29, mlist518[i].reg29);
-		reg_w(ov, 0x2a, mlist518[i].reg2a);
-		reg_w(ov, 0x2c, mlist518[i].reg2c);
-		reg_w(ov, 0x2e, mlist518[i].reg2e);
-		reg_w_mask(ov, 0x38, mlist518[i].reg28 
-			| (mode == VIDEO_PALETTE_GREY) ? 0x80:0x00, 0x8f);
-		reg_w(ov, 0x39, mlist518[i].reg29);
-		reg_w(ov, 0x3a, mlist518[i].reg2a);
-		reg_w(ov, 0x3c, mlist518[i].reg2c);
-		reg_w(ov, 0x3e, mlist518[i].reg2e);
-		reg_w(ov, 0x24, mlist518[i].reg24);
-		reg_w(ov, 0x25, mlist518[i].reg25);
-
-		/* Windows driver does this here; who knows why */
-		reg_w(ov, 0x2f, 0x80);
-
-		/******** Set the framerate (to 15 FPS) ********/		
-
-		/* Mode independent, but framerate dependent, regs */
-		/* These are for 15 FPS only */
-		reg_w(ov, 0x51, 0x08);
-		reg_w(ov, 0x22, 0x18);
-		reg_w(ov, 0x23, 0xff);
-		reg_w(ov, 0x71, 0x19);  /* Compression-related? */
-
-		// FIXME: Sensor-specific
-		/* Bit 5 is what matters here. Of course, it is "reserved" */
-		i2c_w(ov, 0x54, 0x23);
-
-		reg_w(ov, 0x2f, 0x80);
-
-		/* Mode dependent regs */
-		if ((width == 352 && height == 288) ||
-		    (width == 320 && height == 240)) {
-			/*  640 (280h) byte iso packets */
-			ov518_reg_w32(ov, 0x30,    640, 2);	/* 280h   */
-			ov518_reg_w32(ov, 0xc4,    400, 2);	/* 190h   */
-			ov518_reg_w32(ov, 0xc6,    500, 2);	/* 1f4h   */
-			ov518_reg_w32(ov, 0xc7,    500, 2);	/* 1f4h   */
-			ov518_reg_w32(ov, 0xc8,    142, 2);	/* 8eh    */
-			ov518_reg_w32(ov, 0xca, 131098, 3);	/* 2001ah */
-			ov518_reg_w32(ov, 0xcb,    532, 2);	/* 214h   */
-			ov518_reg_w32(ov, 0xcc,   2000, 2);	/* 7d0h   */
-			ov518_reg_w32(ov, 0xcd,     32, 2);	/* 20h    */
-			ov518_reg_w32(ov, 0xce,    608, 2);	/* 260h   */
-		} else if ((width == 176 && height == 144) ||
-			   (width == 160 && height == 120)) {
-			/*  384 (180h) byte iso packets */
-			ov518_reg_w32(ov, 0x30,    384, 2);	/* 180h   */
-			ov518_reg_w32(ov, 0xc4,    200, 2);	/* c8h    */
-			ov518_reg_w32(ov, 0xc6,    320, 2);	/* 140h   */
-			ov518_reg_w32(ov, 0xc7,    320, 2);	/* 140h   */
-			ov518_reg_w32(ov, 0xc8,     96, 2);	/* 60h    */
-			ov518_reg_w32(ov, 0xca,  78607, 3);	/* 1330fh */
-			ov518_reg_w32(ov, 0xcb,    320, 2);	/* 140h   */
-			ov518_reg_w32(ov, 0xcc,   1260, 2);	/* 4ech   */
-			ov518_reg_w32(ov, 0xcd,     19, 2);	/* 13h    */
-			ov518_reg_w32(ov, 0xce,    365, 2);	/* 16dh   */
-		} else {
-			/* Can't happen, since we already handled this case */
-			err("ov518_mode_init_regs(): **** logic error ****");
-		}
+	hsegs = width / 16;
+	vsegs = height / 4;
 
-		reg_w(ov, 0x2f, 0x80);
+	reg_w(ov, 0x29, hsegs);
+	reg_w(ov, 0x2a, vsegs);
 
-		break;
+	reg_w(ov, 0x39, hsegs);
+	reg_w(ov, 0x3a, vsegs);
+
+	/* Windows driver does this here; who knows why */
+	reg_w(ov, 0x2f, 0x80);
+
+	/******** Set the framerate (to 15 FPS) ********/
+
+	/* Mode independent, but framerate dependent, regs */
+	reg_w(ov, 0x51, 0x02);	/* Clock divider; lower==faster */
+	reg_w(ov, 0x22, 0x18);
+	reg_w(ov, 0x23, 0xff);
+
+	if (ov->bridge == BRG_OV518PLUS)
+		reg_w(ov, 0x21, 0x19);
+	else
+		reg_w(ov, 0x71, 0x19);	/* Compression-related? */
+
+	// FIXME: Sensor-specific
+	/* Bit 5 is what matters here. Of course, it is "reserved" */
+	i2c_w(ov, 0x54, 0x23);
+
+	reg_w(ov, 0x2f, 0x80);
+
+	if (ov->bridge == BRG_OV518PLUS) {
+		reg_w(ov, 0x24, 0x94);
+		reg_w(ov, 0x25, 0x90);
+		ov518_reg_w32(ov, 0xc4,    400, 2);	/* 190h   */
+		ov518_reg_w32(ov, 0xc6,    540, 2);	/* 21ch   */
+		ov518_reg_w32(ov, 0xc7,    540, 2);	/* 21ch   */
+		ov518_reg_w32(ov, 0xc8,    108, 2);	/* 6ch    */
+		ov518_reg_w32(ov, 0xca, 131098, 3);	/* 2001ah */
+		ov518_reg_w32(ov, 0xcb,    532, 2);	/* 214h   */
+		ov518_reg_w32(ov, 0xcc,   2400, 2);	/* 960h   */
+		ov518_reg_w32(ov, 0xcd,     32, 2);	/* 20h    */
+		ov518_reg_w32(ov, 0xce,    608, 2);	/* 260h   */
+	} else {
+		reg_w(ov, 0x24, 0x9f);
+		reg_w(ov, 0x25, 0x90);
+		ov518_reg_w32(ov, 0xc4,    400, 2);	/* 190h   */
+		ov518_reg_w32(ov, 0xc6,    500, 2);	/* 1f4h   */
+		ov518_reg_w32(ov, 0xc7,    500, 2);	/* 1f4h   */
+		ov518_reg_w32(ov, 0xc8,    142, 2);	/* 8eh    */
+		ov518_reg_w32(ov, 0xca, 131098, 3);	/* 2001ah */
+		ov518_reg_w32(ov, 0xcb,    532, 2);	/* 214h   */
+		ov518_reg_w32(ov, 0xcc,   2000, 2);	/* 7d0h   */
+		ov518_reg_w32(ov, 0xcd,     32, 2);	/* 20h    */
+		ov518_reg_w32(ov, 0xce,    608, 2);	/* 260h   */
 	}
 
+	reg_w(ov, 0x2f, 0x80);
+
 	if (ov51x_restart(ov) < 0)
 		return -EIO;
 
@@ -2901,11 +2850,6 @@
 	if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0)
 		return -EIO;
 
-	if (mlist518[i].width == 0) {
-		err("Unknown mode (%d, %d): %d", width, height, mode);
-		return -EINVAL;
-	}
-
 	return 0;
 }
 
@@ -2931,7 +2875,7 @@
 	switch (ov->sensor) {
 	case SEN_OV7610:
 	case SEN_OV7620:
-	case SEN_OV7620AE:
+	case SEN_OV76BE:
 	case SEN_OV8600:
 	case SEN_OV6620:
 	case SEN_OV6630:
@@ -2943,10 +2887,10 @@
 		rc = -EINVAL;
 		break;
 	case SEN_SAA7111A:
-//		rc = mode_init_saa_sensor_regs(ov, width, height, mode, 
+//		rc = mode_init_saa_sensor_regs(ov, width, height, mode,
 //					       sub_flag);
 
-		PDEBUG(1, "SAA status = 0X%x", i2c_r(ov, 0x1f));
+		PDEBUG(1, "SAA status = 0x%02X", i2c_r(ov, 0x1f));
 		break;
 	default:
 		err("Unknown sensor");
@@ -2979,19 +2923,21 @@
 	if (FATAL_ERROR(rc))
 		return rc;
 
+	rc = sensor_set_mirror(ov, ov->mirror);
+	if (FATAL_ERROR(rc))
+		return rc;
+
 	return 0;
 }
 
-/* This sets the default image parameters (Size = max, RGB24). This is
- * useful for apps that use read() and do not set these.
+/* This sets the default image parameters. This is useful for apps that use
+ * read() and do not set these.
  */
-static int 
+static int
 ov51x_set_default_params(struct usb_ov511 *ov)
 {
 	int i;
 
-	PDEBUG(3, "%dx%d, RGB24", ov->maxwidth, ov->maxheight);
-
 	/* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used
 	 * (using read() instead). */
 	for (i = 0; i < OV511_NUMFRAMES; i++) {
@@ -3002,10 +2948,14 @@
 			ov->frame[i].format = force_palette;
 		else
 			ov->frame[i].format = VIDEO_PALETTE_RGB24;
+
 		ov->frame[i].depth = get_depth(ov->frame[i].format);
 	}
 
-	/* Initialize to max width/height, RGB24 */
+	PDEBUG(3, "%dx%d, %s", ov->maxwidth, ov->maxheight,
+	       symbolic(v4l1_plist, ov->frame[0].format));
+
+	/* Initialize to max width/height, YUV420 or RGB24 (if supported) */
 	if (mode_init_regs(ov, ov->maxwidth, ov->maxheight,
 			   ov->frame[0].format, 0) < 0)
 		return -EINVAL;
@@ -3020,7 +2970,7 @@
  **********************************************************************/
 
 /* Set analog input port of decoder */
-static int 
+static int
 decoder_set_input(struct usb_ov511 *ov, int input)
 {
 	PDEBUG(4, "port %d", input);
@@ -3042,7 +2992,7 @@
 }
 
 /* Get ASCII name of video input */
-static int 
+static int
 decoder_get_input_name(struct usb_ov511 *ov, int input, char *name)
 {
 	switch (ov->sensor) {
@@ -3054,7 +3004,6 @@
 			sprintf(name, "CVBS-%d", input);
 		else // if (input < 8)
 			sprintf(name, "S-Video-%d", input - 4);
-
 		break;
 	}
 	default:
@@ -3065,7 +3014,7 @@
 }
 
 /* Set norm (NTSC, PAL, SECAM, AUTO) */
-static int 
+static int
 decoder_set_norm(struct usb_ov511 *ov, int norm)
 {
 	PDEBUG(4, "%d", norm);
@@ -3080,7 +3029,7 @@
 			reg_e = 0x00;	/* NTSC M / PAL BGHI */
 		} else if (norm == VIDEO_MODE_PAL) {
 			reg_8 = 0x00;	/* 50 Hz */
-			reg_e = 0x00;	/* NTSC M / PAL BGHI */	
+			reg_e = 0x00;	/* NTSC M / PAL BGHI */
 		} else if (norm == VIDEO_MODE_AUTO) {
 			reg_8 = 0x80;	/* Auto field detect */
 			reg_e = 0x00;	/* NTSC M / PAL BGHI */
@@ -3102,7 +3051,6 @@
 	return 0;
 }
 
-
 /**********************************************************************
  *
  * Color correction functions
@@ -3125,21 +3073,21 @@
  * coefficients are scaled into 16.16 fixed-point integers.
  * They were determined as follows:
  *
- *	double brightness = 1.0;  (0->black; 1->full scale) 
+ *	double brightness = 1.0;  (0->black; 1->full scale)
  *	double saturation = 1.0;  (0->greyscale; 1->full color)
  *	double fixScale = brightness * 256 * 256;
  *	int rvScale = (int)(1.402 * saturation * fixScale);
  *	int guScale = (int)(-0.344136 * saturation * fixScale);
  *	int gvScale = (int)(-0.714136 * saturation * fixScale);
  *	int buScale = (int)(1.772 * saturation * fixScale);
- *	int yScale = (int)(fixScale);	
+ *	int yScale = (int)(fixScale);
  */
 
 /* LIMIT: convert a 16.16 fixed-point value to a byte, with clipping. */
 #define LIMIT(x) ((x)>0xffffff?0xff: ((x)<=0xffff?0:((x)>>16)))
 
 static inline void
-move_420_block(int yTL, int yTR, int yBL, int yBR, int u, int v, 
+move_420_block(int yTL, int yTR, int yBL, int yBR, int u, int v,
 	       int rowPixels, unsigned char * rgb, int bits)
 {
 	const int rvScale = 91881;
@@ -3178,14 +3126,14 @@
 		rgb[5] = LIMIT(r+yBR);
 	} else if (bits == 16) {
 		/* Write out top two pixels */
-		rgb[0] = ((LIMIT(b+yTL) >> 3) & 0x1F) 
+		rgb[0] = ((LIMIT(b+yTL) >> 3) & 0x1F)
 			| ((LIMIT(g+yTL) << 3) & 0xE0);
 		rgb[1] = ((LIMIT(g+yTL) >> 5) & 0x07)
 			| (LIMIT(r+yTL) & 0xF8);
 
-		rgb[2] = ((LIMIT(b+yTR) >> 3) & 0x1F) 
+		rgb[2] = ((LIMIT(b+yTR) >> 3) & 0x1F)
 			| ((LIMIT(g+yTR) << 3) & 0xE0);
-		rgb[3] = ((LIMIT(g+yTR) >> 5) & 0x07) 
+		rgb[3] = ((LIMIT(g+yTR) >> 5) & 0x07)
 			| (LIMIT(r+yTR) & 0xF8);
 
 		/* Skip down to next line to write out bottom two pixels */
@@ -3212,7 +3160,7 @@
 /* Copies a 64-byte segment at pIn to an 8x8 block at pOut. The width of the
  * image at pOut is specified by w.
  */
-static inline void 
+static inline void
 make_8x8(unsigned char *pIn, unsigned char *pOut, int w)
 {
 	unsigned char *pOut1 = pOut;
@@ -3225,7 +3173,6 @@
 		}
 		pOut += w;
 	}
-		
 }
 
 /*
@@ -3343,7 +3290,7 @@
  * low, and the blue channel about 1 pixel high. After YUV->RGB
  * conversion, we can correct this easily. OSL 2/24/2000.
  */
-static void 
+static void
 fixFrameRGBoffset(struct ov511_frame *frame)
 {
 	int x, y;
@@ -3352,7 +3299,7 @@
 	const int shift = 1;  /* Distance to shift pixels by, vertically */
 
 	/* Don't bother with little images */
-	if (frame->width < 400) 
+	if (frame->width < 400)
 		return;
 
 	/* This only works with RGB24 */
@@ -3386,7 +3333,7 @@
  * accordingly. Returns -ENXIO if decompressor is not available, otherwise
  * returns 0 if no other error.
  */
-static int 
+static int
 request_decompressor(struct usb_ov511 *ov)
 {
 	if (!ov)
@@ -3425,24 +3372,24 @@
 	}
 
 	if (ov->decomp_ops) {
-		if (!ov->decomp_ops->decomp_lock) {
+		if (!ov->decomp_ops->owner) {
 			ov->decomp_ops = NULL;
 			unlock_kernel();
 			return -ENOSYS;
 		}
-		ov->decomp_ops->decomp_lock();
+		__MOD_INC_USE_COUNT(ov->decomp_ops->owner);
 		unlock_kernel();
 		return 0;
 	} else {
 		unlock_kernel();
-		return -ENXIO;
+		return -ENOSYS;
 	}
 }
 
 /* Unlocks decompression module and nulls ov->decomp_ops. Safe to call even
  * if ov->decomp_ops is NULL.
  */
-static void 
+static void
 release_decompressor(struct usb_ov511 *ov)
 {
 	int released = 0;	/* Did we actually do anything? */
@@ -3452,20 +3399,20 @@
 
 	lock_kernel();
 
-	if (ov->decomp_ops && ov->decomp_ops->decomp_unlock) {
-		ov->decomp_ops->decomp_unlock();
+	if (ov->decomp_ops && ov->decomp_ops->owner) {
+		__MOD_DEC_USE_COUNT(ov->decomp_ops->owner);
 		released = 1;
 	}
 
 	ov->decomp_ops = NULL;
-	
+
 	unlock_kernel();
 
 	if (released)
 		PDEBUG(3, "Decompressor released");
 }
 
-static void 
+static void
 decompress(struct usb_ov511 *ov, struct ov511_frame *frame,
 	   unsigned char *pIn0, unsigned char *pOut0)
 {
@@ -3475,19 +3422,22 @@
 
 	PDEBUG(4, "Decompressing %d bytes", frame->bytes_recvd);
 
-	if (frame->format == VIDEO_PALETTE_GREY 
+	if (frame->format == VIDEO_PALETTE_GREY
 	    && ov->decomp_ops->decomp_400) {
 		int ret = ov->decomp_ops->decomp_400(
 			pIn0,
 			pOut0,
+			frame->compbuf,
 			frame->rawwidth,
 			frame->rawheight,
 			frame->bytes_recvd);
 		PDEBUG(4, "DEBUG: decomp_400 returned %d", ret);
-	} else if (ov->decomp_ops->decomp_420) {
+	} else if (frame->format != VIDEO_PALETTE_GREY
+		   && ov->decomp_ops->decomp_420) {
 		int ret = ov->decomp_ops->decomp_420(
 			pIn0,
 			pOut0,
+			frame->compbuf,
 			frame->rawwidth,
 			frame->rawheight,
 			frame->bytes_recvd);
@@ -3504,7 +3454,7 @@
  **********************************************************************/
 
 /* Converts from planar YUV420 to RGB24. */
-static void 
+static void
 yuv420p_to_rgb(struct ov511_frame *frame,
 	       unsigned char *pIn0, unsigned char *pOut0, int bits)
 {
@@ -3527,10 +3477,9 @@
 
 			move_420_block(y00, y01, y10, y11, u, v,
 				       frame->width, pOut, bits);
-	
+
 			pY += 2;
 			pOut += 2 * bytes;
-
 		}
 		pY += frame->width;
 		pOut += frame->width * bytes;
@@ -3559,7 +3508,7 @@
 		for (i = 0; i <= frame->width - 2; i += 2) {
 			int u = *pU++;
 			int v = *pV++;
-			
+
 			*pOut = u;
 			*(pOut+2) = v;
 			*(pOut+frame->width*2) = u;
@@ -3674,27 +3623,11 @@
 	}
 }
 
-/* Post-processes the specified frame. This consists of:
- * 	1. Decompress frame, if necessary
- *	2. Deinterlace frame and scale to proper size, if necessary
- * 	3. Convert from YUV planar to destination format, if necessary
- * 	4. Fix the RGB offset, if necessary
- */
-static void 
-ov51x_postprocess(struct usb_ov511 *ov, struct ov511_frame *frame)
+static void
+ov51x_postprocess_grey(struct usb_ov511 *ov, struct ov511_frame *frame)
 {
-	if (dumppix) {
-		memset(frame->data, 0, 
-			MAX_DATA_SIZE(ov->maxwidth, ov->maxheight));
-		PDEBUG(4, "Dumping %d bytes", frame->bytes_recvd);
-		memmove(frame->data, frame->rawdata, frame->bytes_recvd);
-		return;
-	}
-
-	/* YUV400 must be handled separately */
-	if (frame->format == VIDEO_PALETTE_GREY) {
 		/* Deinterlace frame, if necessary */
-		if (ov->sensor == SEN_SAA7111A && frame->rawheight == 480) {
+		if (ov->sensor == SEN_SAA7111A && frame->rawheight >= 480) {
 			if (frame->compressed)
 				decompress(ov, frame, frame->rawdata,
 						 frame->tempdata);
@@ -3712,19 +3645,23 @@
 				yuv400raw_to_yuv400p(frame, frame->rawdata,
 						     frame->data);
 		}
+}
 
-		return;
-	}
-
-	/* Process frame->data to frame->rawdata */
+/* Process raw YUV420 data into the format requested by the app. Conversion
+ * between V4L formats is allowed.
+ */
+static void
+ov51x_postprocess_yuv420(struct usb_ov511 *ov, struct ov511_frame *frame)
+{
+	/* Process frame->rawdata to frame->tempdata */
 	if (frame->compressed)
 		decompress(ov, frame, frame->rawdata, frame->tempdata);
 	else
 		yuv420raw_to_yuv420p(frame, frame->rawdata, frame->tempdata);
 
 	/* Deinterlace frame, if necessary */
-	if (ov->sensor == SEN_SAA7111A && frame->rawheight == 480) {
-		memmove(frame->rawdata, frame->tempdata,
+	if (ov->sensor == SEN_SAA7111A && frame->rawheight >= 480) {
+		memcpy(frame->rawdata, frame->tempdata,
 			MAX_RAW_DATA_SIZE(frame->width, frame->height));
 		deinterlace(frame, RAWFMT_YUV420, frame->rawdata,
 		            frame->tempdata);
@@ -3733,11 +3670,6 @@
 	/* Frame should be (width x height) and not (rawwidth x rawheight) at
          * this point. */
 
-#if 0
-	/* Clear output buffer for testing purposes */
-	memset(frame->data, 0, MAX_DATA_SIZE(frame->width, frame->height));
-#endif
-
 	/* Process frame->tempdata to frame->data */
 	switch (frame->format) {
 	case VIDEO_PALETTE_RGB565:
@@ -3752,467 +3684,408 @@
 		break;
 	case VIDEO_PALETTE_YUV420:
 	case VIDEO_PALETTE_YUV420P:
-		memmove(frame->data, frame->tempdata,
+		memcpy(frame->data, frame->tempdata,
 			MAX_RAW_DATA_SIZE(frame->width, frame->height));
 		break;
 	case VIDEO_PALETTE_YUV422P:
 		/* Data is converted in place, so copy it in advance */
-		memmove(frame->data, frame->tempdata,
+		memcpy(frame->data, frame->tempdata,
 			MAX_RAW_DATA_SIZE(frame->width, frame->height));
 
 		yuv420p_to_yuv422p(frame, frame->data);
 		break;
 	default:
-		err("Cannot convert data to this format");
+		err("Cannot convert YUV420 to %s",
+		    symbolic(v4l1_plist, frame->format));
 	}
 
 	if (fix_rgb_offset)
 		fixFrameRGBoffset(frame);
 }
 
+/* Post-processes the specified frame. This consists of:
+ * 	1. Decompress frame, if necessary
+ *	2. Deinterlace frame and scale to proper size, if necessary
+ * 	3. Convert from YUV planar to destination format, if necessary
+ * 	4. Fix the RGB offset, if necessary
+ */
+static void
+ov51x_postprocess(struct usb_ov511 *ov, struct ov511_frame *frame)
+{
+	if (dumppix) {
+		memset(frame->data, 0,
+			MAX_DATA_SIZE(ov->maxwidth, ov->maxheight));
+		PDEBUG(4, "Dumping %d bytes", frame->bytes_recvd);
+		memcpy(frame->data, frame->rawdata, frame->bytes_recvd);
+	} else {
+		switch (frame->format) {
+		case VIDEO_PALETTE_GREY:
+			ov51x_postprocess_grey(ov, frame);
+			break;
+		case VIDEO_PALETTE_YUV420:
+		case VIDEO_PALETTE_YUV420P:
+		case VIDEO_PALETTE_RGB565:
+		case VIDEO_PALETTE_RGB24:
+		case VIDEO_PALETTE_YUV422:
+		case VIDEO_PALETTE_YUYV:
+		case VIDEO_PALETTE_YUV422P:
+			ov51x_postprocess_yuv420(ov, frame);
+			break;
+		default:
+			err("Cannot convert data to %s",
+			    symbolic(v4l1_plist, frame->format));
+		}
+	}
+}
+
 /**********************************************************************
  *
  * OV51x data transfer, IRQ handler
  *
  **********************************************************************/
 
-static int 
-ov511_move_data(struct usb_ov511 *ov, struct urb *urb)
+static inline void
+ov511_move_data(struct usb_ov511 *ov, unsigned char *in, int n)
 {
-	unsigned char *cdata;
-	int data_size, num, offset, i, totlen = 0;
-	int aPackNum[FRAMES_PER_DESC];
-	struct ov511_frame *frame;
+	int num, offset;
+	int pnum = in[ov->packet_size - 1];		/* Get packet number */
+	int max_raw = MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight);
+	struct ov511_frame *frame = &ov->frame[ov->curframe];
 	struct timeval *ts;
 
-	PDEBUG(5, "Moving %d packets", urb->number_of_packets);
+	/* SOF/EOF packets have 1st to 8th bytes zeroed and the 9th
+	 * byte non-zero. The EOF packet has image width/height in the
+	 * 10th and 11th bytes. The 9th byte is given as follows:
+	 *
+	 * bit 7: EOF
+	 *     6: compression enabled
+	 *     5: 422/420/400 modes
+	 *     4: 422/420/400 modes
+	 *     3: 1
+	 *     2: snapshot button on
+	 *     1: snapshot frame
+	 *     0: even/odd field
+	 */
 
-	data_size = ov->packet_size - 1;
+	if (printph) {
+		info("ph(%3d): %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x",
+		     pnum, in[0], in[1], in[2], in[3], in[4], in[5], in[6],
+		     in[7], in[8], in[9], in[10], in[11]);
+	}
 
-	for (i = 0; i < urb->number_of_packets; i++) {
-		int n = urb->iso_frame_desc[i].actual_length;
-		int st = urb->iso_frame_desc[i].status;
+	/* Check for SOF/EOF packet */
+	if ((in[0] | in[1] | in[2] | in[3] | in[4] | in[5] | in[6] | in[7]) ||
+	    (~in[8] & 0x08))
+		goto check_middle;
 
-		urb->iso_frame_desc[i].actual_length = 0;
-		urb->iso_frame_desc[i].status = 0;
+	/* Frame end */
+	if (in[8] & 0x80) {
+		ts = (struct timeval *)(frame->data
+		      + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight));
+		do_gettimeofday(ts);
 
-		cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+		/* Get the actual frame size from the EOF header */
+		frame->rawwidth = ((int)(in[9]) + 1) * 8;
+		frame->rawheight = ((int)(in[10]) + 1) * 8;
 
-		aPackNum[i] = n ? cdata[ov->packet_size - 1] : -1;
+ 		PDEBUG(4, "Frame end, frame=%d, pnum=%d, w=%d, h=%d, recvd=%d",
+			ov->curframe, pnum, frame->rawwidth, frame->rawheight,
+			frame->bytes_recvd);
 
-		if (!n || ov->curframe == -1)
-			continue;
+		/* Validate the header data */
+		RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth);
+		RESTRICT_TO_RANGE(frame->rawheight, ov->minheight,
+				  ov->maxheight);
 
-		if (st)
-			PDEBUG(2, "data error: [%d] len=%d, status=%d", i, n, st);
+		/* Don't allow byte count to exceed buffer size */
+		RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw);
 
-		frame = &ov->frame[ov->curframe];
+		if (frame->scanstate == STATE_LINES) {
+	    		int nextf;
 
-		/* SOF/EOF packets have 1st to 8th bytes zeroed and the 9th
-		 * byte non-zero. The EOF packet has image width/height in the
-		 * 10th and 11th bytes. The 9th byte is given as follows:
-		 *
-		 * bit 7: EOF
-		 *     6: compression enabled
-		 *     5: 422/420/400 modes
-		 *     4: 422/420/400 modes
-		 *     3: 1
-		 *     2: snapshot button on
-		 *     1: snapshot frame
-		 *     0: even/odd field
-		 */
+			frame->grabstate = FRAME_DONE;	// FIXME: Is this right?
 
-		if (printph) {
-			info("packet header (%3d): %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x",
-				cdata[ov->packet_size - 1],
-				cdata[0], cdata[1], cdata[2], cdata[3], cdata[4], cdata[5],
-				cdata[6], cdata[7], cdata[8], cdata[9], cdata[10], cdata[11]);
-		}
-
-		/* Check for SOF/EOF packet */
-		if ((cdata[0] | cdata[1] | cdata[2] | cdata[3] |
-		     cdata[4] | cdata[5] | cdata[6] | cdata[7]) ||
-		     (~cdata[8] & 0x08))
-			goto check_middle;
-
-		/* Frame end */
-		if (cdata[8] & 0x80) {
-			ts = (struct timeval *)(frame->data 
-			      + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight));
-			do_gettimeofday(ts);
-
-			/* Get the actual frame size from the EOF header */
-			frame->rawwidth = ((int)(cdata[9]) + 1) * 8;
-			frame->rawheight = ((int)(cdata[10]) + 1) * 8;
-
-	 		PDEBUG(4, "Frame end, curframe = %d, packnum=%d, hw=%d, vw=%d, recvd=%d",
-				ov->curframe,
-				(int)(cdata[ov->packet_size - 1]),
-				frame->rawwidth,
-				frame->rawheight,
-				frame->bytes_recvd);
-
-			/* Validate the header data */
-			RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth);
-			RESTRICT_TO_RANGE(frame->rawheight, ov->minheight, ov->maxheight);
-
-			/* Don't allow byte count to exceed buffer size */
-			RESTRICT_TO_RANGE(frame->bytes_recvd,
-					  8, 
-					  MAX_RAW_DATA_SIZE(ov->maxwidth,
-					                    ov->maxheight));
-
-			if (frame->scanstate == STATE_LINES) {
-		    		int iFrameNext;
-
-				frame->grabstate = FRAME_DONE;	// FIXME: Is this right?
-
-				if (waitqueue_active(&frame->wq)) {
-					frame->grabstate = FRAME_DONE;
-					wake_up_interruptible(&frame->wq);
-				}
+			if (waitqueue_active(&frame->wq)) {
+				frame->grabstate = FRAME_DONE;
+				wake_up_interruptible(&frame->wq);
+			}
 
-				/* If next frame is ready or grabbing,
-                                 * point to it */
-				iFrameNext = (ov->curframe + 1) % OV511_NUMFRAMES;
-				if (ov->frame[iFrameNext].grabstate == FRAME_READY
-				    || ov->frame[iFrameNext].grabstate == FRAME_GRABBING) {
-					ov->curframe = iFrameNext;
-					ov->frame[iFrameNext].scanstate = STATE_SCANNING;
+			/* If next frame is ready or grabbing,
+			 * point to it */
+			nextf = (ov->curframe + 1) % OV511_NUMFRAMES;
+			if (ov->frame[nextf].grabstate == FRAME_READY
+			    || ov->frame[nextf].grabstate == FRAME_GRABBING) {
+				ov->curframe = nextf;
+				ov->frame[nextf].scanstate = STATE_SCANNING;
+			} else {
+				if (frame->grabstate == FRAME_DONE) {
+					PDEBUG(4, "** Frame done **");
 				} else {
-					if (frame->grabstate == FRAME_DONE) {
-						PDEBUG(4, "Frame done! congratulations");
-					} else {
-						PDEBUG(4, "Frame not ready? state = %d",
-							ov->frame[iFrameNext].grabstate);
-					}
-
-					ov->curframe = -1;
+					PDEBUG(4, "Frame not ready? state = %d",
+						ov->frame[nextf].grabstate);
 				}
-			} else {
-				PDEBUG(5, "Frame done, but not scanning");
-			}
-			/* Image corruption caused by misplaced frame->segment = 0
-			 * fixed by carlosf@conectiva.com.br
-			 */
-		} else {
-			/* Frame start */
-			PDEBUG(4, "Frame start, framenum = %d", ov->curframe);
 
-			/* Check to see if it's a snapshot frame */
-			/* FIXME?? Should the snapshot reset go here? Performance? */
-			if (cdata[8] & 0x02) {
-				frame->snapshot = 1;
-				PDEBUG(3, "snapshot detected");
+				ov->curframe = -1;
 			}
-
-			frame->scanstate = STATE_LINES;
-			frame->bytes_recvd = 0;
-			frame->compressed = cdata[8] & 0x40;
+		} else {
+			PDEBUG(5, "Frame done, but not scanning");
 		}
+		/* Image corruption caused by misplaced frame->segment = 0
+		 * fixed by carlosf@conectiva.com.br
+		 */
+	} else {
+		/* Frame start */
+		PDEBUG(4, "Frame start, framenum = %d", ov->curframe);
 
-check_middle:
-		/* Are we in a frame? */
-		if (frame->scanstate != STATE_LINES) {
-			PDEBUG(5, "Not in a frame; packet skipped");
-			continue;
+		/* Check to see if it's a snapshot frame */
+		/* FIXME?? Should the snapshot reset go here? Performance? */
+		if (in[8] & 0x02) {
+			frame->snapshot = 1;
+			PDEBUG(3, "snapshot detected");
 		}
 
-#if 0
-		/* Skip packet if first 9 bytes are zero. These are common, so
-		 * we use a less expensive test here instead of later */
-		if (frame->compressed) {
-			int b, skip = 1;
-
-			for (b = 0; b < 9; b++) { 
-				if (cdata[b])
-					skip=0;
-			}
+		frame->scanstate = STATE_LINES;
+		frame->bytes_recvd = 0;
+		frame->compressed = in[8] & 0x40;
+	}
 
-			if (skip) {
-				PDEBUG(5, "Skipping packet (all zero)");
-				continue;
-			}
-		}
-#endif
-		/* If frame start, skip header */
-		if (frame->bytes_recvd == 0)
-			offset = 9;
-		else
-			offset = 0;
+check_middle:
+	/* Are we in a frame? */
+	if (frame->scanstate != STATE_LINES) {
+		PDEBUG(5, "Not in a frame; packet skipped");
+		return;
+	}
 
-		num = n - offset - 1;
+	/* If frame start, skip header */
+	if (frame->bytes_recvd == 0)
+		offset = 9;
+	else
+		offset = 0;
 
-		/* Dump all data exactly as received */
-		if (dumppix == 2) {
-			frame->bytes_recvd += n - 1;
-			if (frame->bytes_recvd <= MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight))
-				memmove(frame->rawdata + frame->bytes_recvd - (n - 1),
-					&cdata[0], n - 1);
-			else
-				PDEBUG(3, "Raw data buffer overrun!! (%d)",
-					frame->bytes_recvd
-					- MAX_RAW_DATA_SIZE(ov->maxwidth,
-							    ov->maxheight));
-		} else if (!frame->compressed && !remove_zeros) {
-			frame->bytes_recvd += num;
-			if (frame->bytes_recvd <= MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight))
-				memmove(frame->rawdata + frame->bytes_recvd - num,
-					&cdata[offset], num);
-			else
-				PDEBUG(3, "Raw data buffer overrun!! (%d)",
-					frame->bytes_recvd
-					- MAX_RAW_DATA_SIZE(ov->maxwidth,
-							    ov->maxheight));
-		} else { /* Remove all-zero FIFO lines (aligned 32-byte blocks) */
-			int b, in = 0, allzero, copied=0;
-			if (offset) {
-				frame->bytes_recvd += 32 - offset;	// Bytes out
-				memmove(frame->rawdata,
-					&cdata[offset], 32 - offset);
-				in += 32;
-			}
+	num = n - offset - 1;
 
-			while (in < n - 1) {
-				allzero = 1;
-				for (b = 0; b < 32; b++) {
-					if (cdata[in + b]) {
-						allzero = 0;
-						break;
-					}
+	/* Dump all data exactly as received */
+	if (dumppix == 2) {
+		frame->bytes_recvd += n - 1;
+		if (frame->bytes_recvd <= max_raw)
+			memcpy(frame->rawdata + frame->bytes_recvd - (n - 1),
+				in, n - 1);
+		else
+			PDEBUG(3, "Raw data buffer overrun!! (%d)",
+				frame->bytes_recvd - max_raw);
+	} else if (!frame->compressed && !remove_zeros) {
+		frame->bytes_recvd += num;
+		if (frame->bytes_recvd <= max_raw)
+			memcpy(frame->rawdata + frame->bytes_recvd - num,
+				in + offset, num);
+		else
+			PDEBUG(3, "Raw data buffer overrun!! (%d)",
+				frame->bytes_recvd - max_raw);
+	} else { /* Remove all-zero FIFO lines (aligned 32-byte blocks) */
+		int b, read = 0, allzero, copied = 0;
+		if (offset) {
+			frame->bytes_recvd += 32 - offset;	// Bytes out
+			memcpy(frame->rawdata,	in + offset, 32 - offset);
+			read += 32;
+		}
+
+		while (read < n - 1) {
+			allzero = 1;
+			for (b = 0; b < 32; b++) {
+				if (in[read + b]) {
+					allzero = 0;
+					break;
 				}
+			}
 
-				if (allzero) {
-					/* Don't copy it */
+			if (allzero) {
+				/* Don't copy it */
+			} else {
+				if (frame->bytes_recvd + copied + 32 <= max_raw)
+				{
+					memcpy(frame->rawdata
+						+ frame->bytes_recvd + copied,
+						in + read, 32);
+					copied += 32;
 				} else {
-					if (frame->bytes_recvd + copied + 32
-					    <= MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight)) {
-						memmove(frame->rawdata + frame->bytes_recvd + copied,
-							&cdata[in], 32);
-						copied += 32;
-					} else {
-						PDEBUG(3, "Raw data buffer overrun!!");
-					}
+					PDEBUG(3, "Raw data buffer overrun!!");
 				}
-				in += 32;
 			}
-
-			frame->bytes_recvd += copied;
+			read += 32;
 		}
 
+		frame->bytes_recvd += copied;
 	}
-
-	PDEBUG(5, "pn: %d %d %d %d %d %d %d %d %d %d",
-		aPackNum[0], aPackNum[1], aPackNum[2], aPackNum[3], aPackNum[4],
-		aPackNum[5],aPackNum[6], aPackNum[7], aPackNum[8], aPackNum[9]);
-
-	return totlen;
 }
 
-static int 
-ov518_move_data(struct usb_ov511 *ov, struct urb *urb)
+static inline void
+ov518_move_data(struct usb_ov511 *ov, unsigned char *in, int n)
 {
-	unsigned char *cdata;
-	int i, data_size, totlen = 0;
-	struct ov511_frame *frame;
+	int max_raw = MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight);
+	struct ov511_frame *frame = &ov->frame[ov->curframe];
 	struct timeval *ts;
 
-	PDEBUG(5, "Moving %d packets", urb->number_of_packets);
-
-	/* OV518(+) has no packet numbering */
-	data_size = ov->packet_size;
-
-	for (i = 0; i < urb->number_of_packets; i++) {
-		int n = urb->iso_frame_desc[i].actual_length;
-		int st = urb->iso_frame_desc[i].status;
-
-		urb->iso_frame_desc[i].actual_length = 0;
-		urb->iso_frame_desc[i].status = 0;
-
-		cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
-
-		if (!n) {
-			PDEBUG(4, "Zero-length packet");
-			continue;
-		}
-
-		if (ov->curframe == -1) {
-			PDEBUG(4, "No frame currently active");
-			continue;
-		}
-
-		if (st)
-			PDEBUG(2, "data error: [%d] len=%d, status=%d", i, n, st);
-
-		frame = &ov->frame[ov->curframe];
-
+	/* Don't copy the packet number byte */
+	if (ov->packet_numbering)
+		--n;
+
+	/* A false positive here is likely, until OVT gives me
+	 * the definitive SOF/EOF format */
+	if ((!(in[0] | in[1] | in[2] | in[3] | in[5])) && in[6]) {
 		if (printph) {
-			info("packet header: %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x",
-				cdata[0], cdata[1], cdata[2], cdata[3], cdata[4], cdata[5],
-				cdata[6], cdata[7], cdata[8], cdata[9], cdata[10], cdata[11]);
-		}
-
-		/* A false positive here is likely, until OVT gives me
-		 * the definitive SOF/EOF format */
-		if ((!(cdata[0] | cdata[1] | cdata[2] | cdata[3] |
-		      cdata[5])) && cdata[6]) {
-			
-			if (frame->scanstate == STATE_LINES) {
-				PDEBUG(4, "Detected frame end/start");
-				goto eof;
-			} else { //scanstate == STATE_SCANNING
-				/* Frame start */
-				PDEBUG(4, "Frame start, framenum = %d", ov->curframe);
-				goto sof;
-			}
-		} else {
-			goto check_middle;
+			info("ph: %2x %2x %2x %2x %2x %2x %2x %2x", in[0],
+			     in[1], in[2], in[3], in[4], in[5], in[6], in[7]);
 		}
-	
-eof:
-		ts = (struct timeval *)(frame->data
-		      + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight));
-		do_gettimeofday(ts);
-
- 		PDEBUG(4, "Frame end, curframe = %d, hw=%d, vw=%d, recvd=%d",
-			ov->curframe,
-			(int)(cdata[9]), (int)(cdata[10]), frame->bytes_recvd);
-
-		// FIXME: Since we don't know the header formats yet,
-		// there is no way to know what the actual image size is
-		frame->rawwidth = frame->width;
-		frame->rawheight = frame->height;
-
-		/* Validate the header data */
-		RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth);
-		RESTRICT_TO_RANGE(frame->rawheight, ov->minheight, ov->maxheight);
-
-		/* Don't allow byte count to exceed buffer size */
-		RESTRICT_TO_RANGE(frame->bytes_recvd,
-				  8, 
-				  MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight));
 
 		if (frame->scanstate == STATE_LINES) {
-	    		int iFrameNext;
-
-			frame->grabstate = FRAME_DONE;	// FIXME: Is this right?
-
-			if (waitqueue_active(&frame->wq)) {
-				frame->grabstate = FRAME_DONE;
-				wake_up_interruptible(&frame->wq);
-			}
+			PDEBUG(4, "Detected frame end/start");
+			goto eof;
+		} else { //scanstate == STATE_SCANNING
+			/* Frame start */
+			PDEBUG(4, "Frame start, framenum = %d", ov->curframe);
+			goto sof;
+		}
+	} else {
+		goto check_middle;
+	}
 
-			/* If next frame is ready or grabbing,
-			 * point to it */
-			iFrameNext = (ov->curframe + 1) % OV511_NUMFRAMES;
-			if (ov->frame[iFrameNext].grabstate == FRAME_READY
-			    || ov->frame[iFrameNext].grabstate == FRAME_GRABBING) {
-				ov->curframe = iFrameNext;
-				ov->frame[iFrameNext].scanstate = STATE_SCANNING;
-				frame = &ov->frame[iFrameNext];
+eof:
+	ts = (struct timeval *)(frame->data
+	      + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight));
+	do_gettimeofday(ts);
+
+	PDEBUG(4, "Frame end, curframe = %d, hw=%d, vw=%d, recvd=%d",
+		ov->curframe,
+		(int)(in[9]), (int)(in[10]), frame->bytes_recvd);
+
+	// FIXME: Since we don't know the header formats yet,
+	// there is no way to know what the actual image size is
+	frame->rawwidth = frame->width;
+	frame->rawheight = frame->height;
+
+	/* Validate the header data */
+	RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth);
+	RESTRICT_TO_RANGE(frame->rawheight, ov->minheight, ov->maxheight);
+
+	/* Don't allow byte count to exceed buffer size */
+	RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw);
+
+	if (frame->scanstate == STATE_LINES) {
+    		int nextf;
+
+		frame->grabstate = FRAME_DONE;	// FIXME: Is this right?
+
+		if (waitqueue_active(&frame->wq)) {
+			frame->grabstate = FRAME_DONE;
+			wake_up_interruptible(&frame->wq);
+		}
+
+		/* If next frame is ready or grabbing,
+		 * point to it */
+		nextf = (ov->curframe + 1) % OV511_NUMFRAMES;
+		if (ov->frame[nextf].grabstate == FRAME_READY
+		    || ov->frame[nextf].grabstate == FRAME_GRABBING) {
+			ov->curframe = nextf;
+			ov->frame[nextf].scanstate = STATE_SCANNING;
+			frame = &ov->frame[nextf];
+		} else {
+			if (frame->grabstate == FRAME_DONE) {
+				PDEBUG(4, "** Frame done **");
 			} else {
-				if (frame->grabstate == FRAME_DONE) {
-					PDEBUG(4, "Frame done! congratulations");
-				} else {
-					PDEBUG(4, "Frame not ready? state = %d",
-						ov->frame[iFrameNext].grabstate);
-				}
-
-				ov->curframe = -1;
-				PDEBUG(4, "SOF dropped (no active frame)");
-				continue;  /* Nowhere to store this frame */
+				PDEBUG(4, "Frame not ready? state = %d",
+				       ov->frame[nextf].grabstate);
 			}
+
+			ov->curframe = -1;
+			PDEBUG(4, "SOF dropped (no active frame)");
+			return;  /* Nowhere to store this frame */
 		}
-		/* Image corruption caused by misplaced frame->segment = 0
-		 * fixed by carlosf@conectiva.com.br
-		 */
+	}
 sof:
-		PDEBUG(4, "Starting capture on frame %d", frame->framenum);
+	PDEBUG(4, "Starting capture on frame %d", frame->framenum);
+
 // Snapshot not reverse-engineered yet.
 #if 0
-		/* Check to see if it's a snapshot frame */
-		/* FIXME?? Should the snapshot reset go here? Performance? */
-		if (cdata[8] & 0x02) {
-			frame->snapshot = 1;
-			PDEBUG(3, "snapshot detected");
-		}
+	/* Check to see if it's a snapshot frame */
+	/* FIXME?? Should the snapshot reset go here? Performance? */
+	if (in[8] & 0x02) {
+		frame->snapshot = 1;
+		PDEBUG(3, "snapshot detected");
+	}
 #endif
-		frame->scanstate = STATE_LINES;
-		frame->bytes_recvd = 0;
-//		frame->compressed = 1;
+	frame->scanstate = STATE_LINES;
+	frame->bytes_recvd = 0;
+	frame->compressed = 1;
 
 check_middle:
-		/* Are we in a frame? */
-		if (frame->scanstate != STATE_LINES) {
-			PDEBUG(4, "scanstate: no SOF yet");
-			continue;
-		}
+	/* Are we in a frame? */
+	if (frame->scanstate != STATE_LINES) {
+		PDEBUG(4, "scanstate: no SOF yet");
+		return;
+	}
 
-		/* Dump all data exactly as received */
-		if (dumppix == 2) {
-			frame->bytes_recvd += n;
-			if (frame->bytes_recvd <= MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight))
-				memmove(frame->rawdata + frame->bytes_recvd - n,
-					&cdata[0], n);
-			else
-				PDEBUG(3, "Raw data buffer overrun!! (%d)",
-					frame->bytes_recvd
-					- MAX_RAW_DATA_SIZE(ov->maxwidth,
-							    ov->maxheight));
-		} else {
-			/* All incoming data are divided into 8-byte segments. If the
-			 * segment contains all zero bytes, it must be skipped. These
-			 * zero-segments allow the OV518 to mainain a constant data rate
-			 * regardless of the effectiveness of the compression. Segments
-			 * are aligned relative to the beginning of each isochronous
-			 * packet. The first segment is a header (the decompressor
-			 * skips it later).
-			 */
-
-			int b, in = 0, allzero, copied=0;
-
-			while (in < n) {
-				allzero = 1;
-				for (b = 0; b < 8; b++) {
-					if (cdata[in + b]) {
-						allzero = 0;
-						break;
-					}
+	/* Dump all data exactly as received */
+	if (dumppix == 2) {
+		frame->bytes_recvd += n;
+		if (frame->bytes_recvd <= max_raw)
+			memcpy(frame->rawdata + frame->bytes_recvd - n, in, n);
+		else
+			PDEBUG(3, "Raw data buffer overrun!! (%d)",
+				frame->bytes_recvd - max_raw);
+	} else {
+		/* All incoming data are divided into 8-byte segments. If the
+		 * segment contains all zero bytes, it must be skipped. These
+		 * zero-segments allow the OV518 to mainain a constant data rate
+		 * regardless of the effectiveness of the compression. Segments
+		 * are aligned relative to the beginning of each isochronous
+		 * packet. The first segment in each image is a header (the
+		 * decompressor skips it later).
+		 */
+
+		int b, read = 0, allzero, copied = 0;
+
+		while (read < n) {
+			allzero = 1;
+			for (b = 0; b < 8; b++) {
+				if (in[read + b]) {
+					allzero = 0;
+					break;
 				}
+			}
 
-				if (allzero) {
-				/* Don't copy it */
+			if (allzero) {
+			/* Don't copy it */
+			} else {
+				if (frame->bytes_recvd + copied + 8 <= max_raw)
+				{
+					memcpy(frame->rawdata
+						+ frame->bytes_recvd + copied,
+						in + read, 8);
+					copied += 8;
 				} else {
-					if (frame->bytes_recvd + copied + 8
-					    <= MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight)) {
-						memmove(frame->rawdata + frame->bytes_recvd + copied,
-							&cdata[in], 8);
-						copied += 8;
-					} else {
-						PDEBUG(3, "Raw data buffer overrun!!");
-					}
+					PDEBUG(3, "Raw data buffer overrun!!");
 				}
-				in += 8;
 			}
-			frame->bytes_recvd += copied;
+			read += 8;
 		}
+		frame->bytes_recvd += copied;
 	}
-
-	return totlen;
 }
 
-static void 
+static void
 ov51x_isoc_irq(struct urb *urb)
 {
-	int len;
+	int i;
 	struct usb_ov511 *ov;
+	struct ov511_sbuf *sbuf;
 
 	if (!urb->context) {
 		PDEBUG(4, "no context");
 		return;
 	}
 
-	ov = (struct usb_ov511 *) urb->context;
+	sbuf = urb->context;
+	ov = sbuf->ov;
 
 	if (!ov || !ov->dev || !ov->user) {
 		PDEBUG(4, "no device, or not open");
@@ -4224,16 +4097,51 @@
 		return;
 	}
 
+        if (urb->status == -ENOENT || urb->status == -ECONNRESET) {
+                PDEBUG(4, "URB unlinked");
+                return;
+        }
+
+	if (urb->status != -EINPROGRESS && urb->status != 0) {
+		err("ERROR: urb->status=%d: %s", urb->status,
+		    symbolic(urb_errlist, urb->status));
+	}
+
 	/* Copy the data received into our frame buffer */
-	if (ov->curframe >= 0) {
-		if (ov->bclass == BCL_OV511)
-			len = ov511_move_data(ov, urb);
-		else if (ov->bclass == BCL_OV518)
-			len = ov518_move_data(ov, urb);
-		else
-			err("Unknown bridge device (%d)", ov->bridge);
-	} else if (waitqueue_active(&ov->wq)) {
-		wake_up_interruptible(&ov->wq);
+	PDEBUG(5, "sbuf[%d]: Moving %d packets", sbuf->n,
+	       urb->number_of_packets);
+	for (i = 0; i < urb->number_of_packets; i++) {
+		/* Warning: Don't call *_move_data() if no frame active! */
+		if (ov->curframe >= 0) {
+			int n = urb->iso_frame_desc[i].actual_length;
+			int st = urb->iso_frame_desc[i].status;
+			unsigned char *cdata;
+
+			urb->iso_frame_desc[i].actual_length = 0;
+			urb->iso_frame_desc[i].status = 0;
+
+			cdata = urb->transfer_buffer
+				+ urb->iso_frame_desc[i].offset;
+
+			if (!n) {
+				PDEBUG(4, "Zero-length packet");
+				continue;
+			}
+
+			if (st)
+				PDEBUG(2, "data error: [%d] len=%d, status=%d",
+				       i, n, st);
+
+			if (ov->bclass == BCL_OV511)
+				ov511_move_data(ov, cdata, n);
+			else if (ov->bclass == BCL_OV518)
+				ov518_move_data(ov, cdata, n);
+			else
+				err("Unknown bridge device (%d)", ov->bridge);
+
+		} else if (waitqueue_active(&ov->wq)) {
+			wake_up_interruptible(&ov->wq);
+		}
 	}
 
 	urb->dev = ov->dev;
@@ -4247,7 +4155,7 @@
  *
  ***************************************************************************/
 
-static int 
+static int
 ov51x_init_isoc(struct usb_ov511 *ov)
 {
 	struct urb *urb;
@@ -4289,27 +4197,32 @@
 		return -1;
 	}
 
-	if (packetsize == -1) {
-		// FIXME: OV518 is hardcoded to 15 FPS (alternate 5) for now
-		if (ov->bclass == BCL_OV518)
-			ov51x_set_packet_size(ov, 640);
-		else
-			ov51x_set_packet_size(ov, size);
+	// FIXME: OV518 is hardcoded to 15 FPS (alternate 5) for now
+	if (ov->bclass == BCL_OV518) {
+		if (packetsize == -1) {
+			ov518_set_packet_size(ov, 640);
+		} else {
+			info("Forcing packet size to %d", packetsize);
+			ov518_set_packet_size(ov, packetsize);
+		}
 	} else {
+		if (packetsize == -1) {
+			ov511_set_packet_size(ov, size);
+		} else {
 			info("Forcing packet size to %d", packetsize);
-			ov51x_set_packet_size(ov, packetsize);
+			ov511_set_packet_size(ov, packetsize);
+		}
 	}
 
 	for (n = 0; n < OV511_NUMSBUF; n++) {
 		urb = usb_alloc_urb(FRAMES_PER_DESC);
-	
 		if (!urb) {
 			err("init isoc: usb_alloc_urb ret. NULL");
 			return -ENOMEM;
 		}
 		ov->sbuf[n].urb = urb;
 		urb->dev = ov->dev;
-		urb->context = ov;
+		urb->context = &ov->sbuf[n];
 		urb->pipe = usb_rcvisocpipe(ov->dev, OV511_ENDPOINT_ADDRESS);
 		urb->transfer_flags = USB_ISO_ASAP;
 		urb->transfer_buffer = ov->sbuf[n].data;
@@ -4331,31 +4244,23 @@
 	for (n = 0; n < OV511_NUMSBUF; n++) {
 		ov->sbuf[n].urb->dev = ov->dev;
 		err = usb_submit_urb(ov->sbuf[n].urb);
-		if (err)
+		if (err) {
 			err("init isoc: usb_submit_urb(%d) ret %d", n, err);
+			return err;
+		}
 	}
 
 	return 0;
 }
 
-static void 
-ov51x_stop_isoc(struct usb_ov511 *ov)
+static void
+ov51x_unlink_isoc(struct usb_ov511 *ov)
 {
 	int n;
 
-	if (!ov->streaming || !ov->dev)
-		return;
-
-	PDEBUG(3, "*** Stopping capture ***");
-
-	ov51x_set_packet_size(ov, 0);
-
-	ov->streaming = 0;
-
 	/* Unschedule all of the iso td's */
 	for (n = OV511_NUMSBUF - 1; n >= 0; n--) {
 		if (ov->sbuf[n].urb) {
-			ov->sbuf[n].urb->next = NULL;
 			usb_unlink_urb(ov->sbuf[n].urb);
 			usb_free_urb(ov->sbuf[n].urb);
 			ov->sbuf[n].urb = NULL;
@@ -4363,7 +4268,25 @@
 	}
 }
 
-static int 
+static void
+ov51x_stop_isoc(struct usb_ov511 *ov)
+{
+	if (!ov->streaming || !ov->dev)
+		return;
+
+	PDEBUG(3, "*** Stopping capture ***");
+
+	if (ov->bclass == BCL_OV518)
+		ov518_set_packet_size(ov, 0);
+	else
+		ov511_set_packet_size(ov, 0);
+
+	ov->streaming = 0;
+
+	ov51x_unlink_isoc(ov);
+}
+
+static int
 ov51x_new_frame(struct usb_ov511 *ov, int framenum)
 {
 	struct ov511_frame *frame;
@@ -4385,7 +4308,7 @@
 
 	frame = &ov->frame[framenum];
 
-	PDEBUG(4, "framenum = %d, width = %d, height = %d", framenum, 
+	PDEBUG(4, "framenum = %d, width = %d, height = %d", framenum,
 	       frame->width, frame->height);
 
 	frame->grabstate = FRAME_GRABBING;
@@ -4414,172 +4337,133 @@
  *
  ***************************************************************************/
 
-static int 
-ov51x_alloc(struct usb_ov511 *ov)
+/*
+ * - You must acquire buf_lock before entering this function.
+ * - Because this code will free any non-null pointer, you must be sure to null
+ *   them if you explicitly free them somewhere else!
+ */
+static void
+ov51x_do_dealloc(struct usb_ov511 *ov)
 {
 	int i;
-	const int w = ov->maxwidth;
-	const int h = ov->maxheight;
-	const int data_bufsize = OV511_NUMFRAMES * MAX_DATA_SIZE(w, h);
-	const int raw_bufsize = OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h);
-
 	PDEBUG(4, "entered");
-	down(&ov->buf_lock);
-
-	if (ov->buf_state == BUF_PEND_DEALLOC) {
-		ov->buf_state = BUF_ALLOCATED;
-		del_timer(&ov->buf_timer);
-	}
 
-	if (ov->buf_state == BUF_ALLOCATED)
-		goto out;
-
-	ov->fbuf = rvmalloc(data_bufsize);
-	if (!ov->fbuf)
-		goto error;
-
-	ov->rawfbuf = vmalloc(raw_bufsize);
-	if (!ov->rawfbuf) {
-		rvfree(ov->fbuf, data_bufsize);
+	if (ov->fbuf) {
+		rvfree(ov->fbuf, OV511_NUMFRAMES
+		       * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight));
 		ov->fbuf = NULL;
-		goto error;
 	}
-	memset(ov->rawfbuf, 0, raw_bufsize);
 
-	ov->tempfbuf = vmalloc(raw_bufsize);
-	if (!ov->tempfbuf) {
+	if (ov->rawfbuf) {
 		vfree(ov->rawfbuf);
 		ov->rawfbuf = NULL;
-		rvfree(ov->fbuf, data_bufsize);
-		ov->fbuf = NULL;
-		goto error;
 	}
-	memset(ov->tempfbuf, 0, raw_bufsize);
 
-	for (i = 0; i < OV511_NUMSBUF; i++) {
-		ov->sbuf[i].data = kmalloc(FRAMES_PER_DESC *
-			MAX_FRAME_SIZE_PER_DESC, GFP_KERNEL);
-		if (!ov->sbuf[i].data) {
-			while (--i) {
-				kfree(ov->sbuf[i].data);
-				ov->sbuf[i].data = NULL;
-			}
-			vfree(ov->tempfbuf);
-			ov->tempfbuf = NULL;
-			vfree(ov->rawfbuf);
-			ov->rawfbuf = NULL;
-			rvfree(ov->fbuf, data_bufsize);
-			ov->fbuf = NULL;
+	if (ov->tempfbuf) {
+		vfree(ov->tempfbuf);
+		ov->tempfbuf = NULL;
+	}
 
-			goto error;
+	for (i = 0; i < OV511_NUMSBUF; i++) {
+		if (ov->sbuf[i].data) {
+			kfree(ov->sbuf[i].data);
+			ov->sbuf[i].data = NULL;
 		}
-		PDEBUG(4, "sbuf[%d] @ %p", i, ov->sbuf[i].data);
 	}
 
 	for (i = 0; i < OV511_NUMFRAMES; i++) {
-		ov->frame[i].data = ov->fbuf + i * MAX_DATA_SIZE(w, h);
-		ov->frame[i].rawdata = ov->rawfbuf 
-		 + i * MAX_RAW_DATA_SIZE(w, h);
-		ov->frame[i].tempdata = ov->tempfbuf 
-		 + i * MAX_RAW_DATA_SIZE(w, h);
-		PDEBUG(4, "frame[%d] @ %p", i, ov->frame[i].data);
+		ov->frame[i].data = NULL;
+		ov->frame[i].rawdata = NULL;
+		ov->frame[i].tempdata = NULL;
+		if (ov->frame[i].compbuf) {
+			free_page((unsigned long) ov->frame[i].compbuf);
+			ov->frame[i].compbuf = NULL;
+		}
 	}
 
-	ov->buf_state = BUF_ALLOCATED;
-out:
-	up(&ov->buf_lock);
-	PDEBUG(4, "leaving");
-	return 0;
-error:
+	PDEBUG(4, "buffer memory deallocated");
 	ov->buf_state = BUF_NOT_ALLOCATED;
-	up(&ov->buf_lock);
-	PDEBUG(4, "errored");
-	return -ENOMEM;
+	PDEBUG(4, "leaving");
 }
 
-/* 
- * - You must acquire buf_lock before entering this function.
- * - Because this code will free any non-null pointer, you must be sure to null
- *   them if you explicitly free them somewhere else!
- */
-static void 
-ov51x_do_dealloc(struct usb_ov511 *ov)
+static int
+ov51x_alloc(struct usb_ov511 *ov)
 {
 	int i;
+	const int w = ov->maxwidth;
+	const int h = ov->maxheight;
+	const int data_bufsize = OV511_NUMFRAMES * MAX_DATA_SIZE(w, h);
+	const int raw_bufsize = OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h);
+
 	PDEBUG(4, "entered");
+	down(&ov->buf_lock);
 
-	if (ov->fbuf) {
-		rvfree(ov->fbuf, OV511_NUMFRAMES
-		       * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight));
-		ov->fbuf = NULL;
+	if (ov->buf_state == BUF_PEND_DEALLOC) {
+		ov->buf_state = BUF_ALLOCATED;
+		del_timer(&ov->buf_timer);
 	}
 
-	if (ov->rawfbuf) {
-		vfree(ov->rawfbuf);
-		ov->rawfbuf = NULL;
-	}
+	if (ov->buf_state == BUF_ALLOCATED)
+		goto out;
+
+	ov->fbuf = rvmalloc(data_bufsize);
+	if (!ov->fbuf)
+		goto error;
+
+	ov->rawfbuf = vmalloc(raw_bufsize);
+	if (!ov->rawfbuf)
+		goto error;
+
+	memset(ov->rawfbuf, 0, raw_bufsize);
 
-	if (ov->tempfbuf) {
-		vfree(ov->tempfbuf);
-		ov->tempfbuf = NULL;
-	}
+	ov->tempfbuf = vmalloc(raw_bufsize);
+	if (!ov->tempfbuf)
+		goto error;
+
+	memset(ov->tempfbuf, 0, raw_bufsize);
 
 	for (i = 0; i < OV511_NUMSBUF; i++) {
-		if (ov->sbuf[i].data) {
-			kfree(ov->sbuf[i].data);
-			ov->sbuf[i].data = NULL;
-		}
-	}
+		ov->sbuf[i].data = kmalloc(FRAMES_PER_DESC *
+			MAX_FRAME_SIZE_PER_DESC, GFP_KERNEL);
+		if (!ov->sbuf[i].data)
+			goto error;
 
-	for (i = 0; i < OV511_NUMFRAMES; i++) {
-		ov->frame[i].data = NULL;
-		ov->frame[i].rawdata = NULL;
-		ov->frame[i].tempdata = NULL;
+		PDEBUG(4, "sbuf[%d] @ %p", i, ov->sbuf[i].data);
 	}
 
-	PDEBUG(4, "buffer memory deallocated");
-	ov->buf_state = BUF_NOT_ALLOCATED;
-	PDEBUG(4, "leaving");
-}
+	for (i = 0; i < OV511_NUMFRAMES; i++) {
+		ov->frame[i].data = ov->fbuf + i * MAX_DATA_SIZE(w, h);
+		ov->frame[i].rawdata = ov->rawfbuf
+		 + i * MAX_RAW_DATA_SIZE(w, h);
+		ov->frame[i].tempdata = ov->tempfbuf
+		 + i * MAX_RAW_DATA_SIZE(w, h);
 
-static void 
-ov51x_buf_callback(unsigned long data)
-{
-	struct usb_ov511 *ov = (struct usb_ov511 *)data;
-	PDEBUG(4, "entered");
-	down(&ov->buf_lock);
+		ov->frame[i].compbuf =
+		 (unsigned char *) __get_free_page(GFP_KERNEL);
+		if (!ov->frame[i].compbuf)
+			goto error;
 
-	if (ov->buf_state == BUF_PEND_DEALLOC)
-		ov51x_do_dealloc(ov);
+		PDEBUG(4, "frame[%d] @ %p", i, ov->frame[i].data);
+	}
 
+	ov->buf_state = BUF_ALLOCATED;
+out:
 	up(&ov->buf_lock);
 	PDEBUG(4, "leaving");
+	return 0;
+error:
+	ov51x_do_dealloc(ov);
+	up(&ov->buf_lock);
+	PDEBUG(4, "errored");
+	return -ENOMEM;
 }
 
-static void 
+static void
 ov51x_dealloc(struct usb_ov511 *ov, int now)
 {
-	struct timer_list *bt = &(ov->buf_timer);
 	PDEBUG(4, "entered");
 	down(&ov->buf_lock);
-
-	PDEBUG(4, "deallocating buffer memory %s", now ? "now" : "later");
-
-	if (ov->buf_state == BUF_PEND_DEALLOC) {
-		ov->buf_state = BUF_ALLOCATED;
-		del_timer(bt);
-	}
-
-	if (now)
-		ov51x_do_dealloc(ov);
-	else {
-		ov->buf_state = BUF_PEND_DEALLOC;
-		init_timer(bt);
-		bt->function = ov51x_buf_callback;
-		bt->data = (unsigned long)ov;
-		bt->expires = jiffies + buf_timeout * HZ;
-		add_timer(bt);
-	}
+	ov51x_do_dealloc(ov);
 	up(&ov->buf_lock);
 	PDEBUG(4, "leaving");
 }
@@ -4590,7 +4474,7 @@
  *
  ***************************************************************************/
 
-static int 
+static int
 ov51x_v4l1_open(struct video_device *vdev, int flags)
 {
 	struct usb_ov511 *ov = vdev->priv;
@@ -4601,17 +4485,18 @@
 	down(&ov->lock);
 
 	err = -EBUSY;
-	if (ov->user) 
+	if (ov->user)
 		goto out;
 
-	err = -ENOMEM;
-	if (ov51x_alloc(ov))
+	err = ov51x_alloc(ov);
+	if (err < 0)
 		goto out;
 
 	ov->sub_flag = 0;
 
 	/* In case app doesn't set them... */
-	if (ov51x_set_default_params(ov) < 0)
+	err = ov51x_set_default_params(ov);
+	if (err < 0)
 		goto out;
 
 	/* Make sure frames are reset */
@@ -4620,7 +4505,7 @@
 		ov->frame[i].bytes_read = 0;
 	}
 
-	/* If compression is on, make sure now that a 
+	/* If compression is on, make sure now that a
 	 * decompressor can be loaded */
 	if (ov->compress && !ov->decomp_ops) {
 		err = request_decompressor(ov);
@@ -4635,23 +4520,22 @@
 	}
 
 	ov->user++;
-	
+
 	if (ov->led_policy == LED_AUTO)
 		ov51x_led_control(ov, 1);
 
 out:
 	up(&ov->lock);
-
 	return err;
 }
 
-static void 
+static void
 ov51x_v4l1_close(struct video_device *vdev)
 {
 	struct usb_ov511 *ov = vdev->priv;
 
 	PDEBUG(4, "ov511_close");
-	
+
 	down(&ov->lock);
 
 	ov->user--;
@@ -4680,129 +4564,93 @@
 		kfree(ov);
 		ov = NULL;
 	}
-}
-
-static int 
-ov51x_v4l1_init_done(struct video_device *vdev)
-{
-#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
-	create_proc_ov511_cam(vdev->priv);
-#endif
-
-	return 0;
-}
 
-static long 
-ov51x_v4l1_write(struct video_device *vdev, const char *buf,
-		 unsigned long count, int noblock)
-{
-	return -EINVAL;
+	return;
 }
 
 /* Do not call this function directly! */
-static int 
-ov51x_v4l1_ioctl_internal(struct video_device *vdev, unsigned int cmd,
+static int
+ov51x_v4l1_ioctl_internal(struct usb_ov511 *ov, unsigned int cmd,
 			  void *arg)
 {
-	struct usb_ov511 *ov = vdev->priv;
-
 	PDEBUG(5, "IOCtl: 0x%X", cmd);
 
 	if (!ov->dev)
-		return -EIO;	
+		return -EIO;
 
 	switch (cmd) {
 	case VIDIOCGCAP:
 	{
-		struct video_capability b;
+		struct video_capability *b = arg;
 
 		PDEBUG(4, "VIDIOCGCAP");
 
-		memset(&b, 0, sizeof(b));
-		sprintf(b.name, "%s USB Camera",
-			ov->bridge == BRG_OV511 ? "OV511" :
-			ov->bridge == BRG_OV511PLUS ? "OV511+" :
-			ov->bridge == BRG_OV518 ? "OV518" :
-			ov->bridge == BRG_OV518PLUS ? "OV518+" :
-			"unknown");
-		b.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
-		if (ov->has_tuner)
-			b.type |= VID_TYPE_TUNER;
-		b.channels = ov->num_inputs;
-		b.audios = ov->has_audio_proc ? 1:0;
-		b.maxwidth = ov->maxwidth;
-		b.maxheight = ov->maxheight;
-		b.minwidth = ov->minwidth;
-		b.minheight = ov->minheight;
+		memset(b, 0, sizeof(struct video_capability));
+		sprintf(b->name, "%s USB Camera",
+			symbolic(brglist, ov->bridge));
+		b->type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
+		b->channels = ov->num_inputs;
+		b->audios = 0;
+		b->maxwidth = ov->maxwidth;
+		b->maxheight = ov->maxheight;
+		b->minwidth = ov->minwidth;
+		b->minheight = ov->minheight;
 
-		if (copy_to_user(arg, &b, sizeof(b)))
-			return -EFAULT;
-				
 		return 0;
 	}
 	case VIDIOCGCHAN:
 	{
-		struct video_channel v;
+		struct video_channel *v = arg;
 
 		PDEBUG(4, "VIDIOCGCHAN");
 
-		if (copy_from_user(&v, arg, sizeof(v)))
-			return -EFAULT;
-
-		if ((unsigned)(v.channel) >= ov->num_inputs) {
-			err("Invalid channel (%d)", v.channel);
+		if ((unsigned)(v->channel) >= ov->num_inputs) {
+			err("Invalid channel (%d)", v->channel);
 			return -EINVAL;
 		}
 
-		v.norm = ov->norm;
-		v.type = (ov->has_tuner) ? VIDEO_TYPE_TV : VIDEO_TYPE_CAMERA;
-		v.flags = (ov->has_tuner) ? VIDEO_VC_TUNER : 0;
-		v.flags |= (ov->has_audio_proc) ? VIDEO_VC_AUDIO : 0;
-//		v.flags |= (ov->has_decoder) ? VIDEO_VC_NORM : 0;
-		v.tuners = (ov->has_tuner) ? 1:0;
-		decoder_get_input_name(ov, v.channel, v.name);
+		v->norm = ov->norm;
+		v->type = VIDEO_TYPE_CAMERA;
+		v->flags = 0;
+//		v->flags |= (ov->has_decoder) ? VIDEO_VC_NORM : 0;
+		v->tuners = 0;
+		decoder_get_input_name(ov, v->channel, v->name);
 
-		if (copy_to_user(arg, &v, sizeof(v)))
-			return -EFAULT;
-				
 		return 0;
 	}
 	case VIDIOCSCHAN:
 	{
-		struct video_channel v;
+		struct video_channel *v = arg;
 		int err;
 
 		PDEBUG(4, "VIDIOCSCHAN");
 
-		if (copy_from_user(&v, arg, sizeof(v)))
-			return -EFAULT;
-
 		/* Make sure it's not a camera */
 		if (!ov->has_decoder) {
-			if (v.channel == 0)
+			if (v->channel == 0)
 				return 0;
 			else
 				return -EINVAL;
 		}
 
-		if (v.norm != VIDEO_MODE_PAL &&
-		    v.norm != VIDEO_MODE_NTSC &&
-		    v.norm != VIDEO_MODE_SECAM &&
-		    v.norm != VIDEO_MODE_AUTO) {
-			err("Invalid norm (%d)", v.norm);
+		if (v->norm != VIDEO_MODE_PAL &&
+		    v->norm != VIDEO_MODE_NTSC &&
+		    v->norm != VIDEO_MODE_SECAM &&
+		    v->norm != VIDEO_MODE_AUTO) {
+			err("Invalid norm (%d)", v->norm);
 			return -EINVAL;
 		}
 
-		if ((unsigned)(v.channel) >= ov->num_inputs) {
-			err("Invalid channel (%d)", v.channel);
+		if ((unsigned)(v->channel) >= ov->num_inputs) {
+			err("Invalid channel (%d)", v->channel);
 			return -EINVAL;
 		}
 
-		err = decoder_set_input(ov, v.channel);
+		err = decoder_set_input(ov, v->channel);
 		if (err)
 			return err;
 
-		err = decoder_set_norm(ov, v.norm);
+		err = decoder_set_norm(ov, v->norm);
 		if (err)
 			return err;
 
@@ -4810,43 +4658,37 @@
 	}
 	case VIDIOCGPICT:
 	{
-		struct video_picture p;
+		struct video_picture *p = arg;
 
 		PDEBUG(4, "VIDIOCGPICT");
 
-		memset(&p, 0, sizeof(p));
-
-		if (sensor_get_picture(ov, &p))
+		memset(p, 0, sizeof(struct video_picture));
+		if (sensor_get_picture(ov, p))
 			return -EIO;
 
-		if (copy_to_user(arg, &p, sizeof(p)))
-			return -EFAULT;
-
 		return 0;
 	}
 	case VIDIOCSPICT:
 	{
-		struct video_picture p;
+		struct video_picture *p = arg;
 		int i;
 
 		PDEBUG(4, "VIDIOCSPICT");
 
-		if (copy_from_user(&p, arg, sizeof(p)))
-			return -EFAULT;
-
-		if (!get_depth(p.palette))
+		if (!get_depth(p->palette))
 			return -EINVAL;
 
-		if (sensor_set_picture(ov, &p))
+		if (sensor_set_picture(ov, p))
 			return -EIO;
 
-		if (force_palette && p.palette != force_palette) {
-			info("Palette rejected (%d)", p.palette);
+		if (force_palette && p->palette != force_palette) {
+			info("Palette rejected (%s)",
+			     symbolic(v4l1_plist, p->palette));
 			return -EINVAL;
 		}
 
 		// FIXME: Format should be independent of frames
-		if (p.palette != ov->frame[0].format) {
+		if (p->palette != ov->frame[0].format) {
 			PDEBUG(4, "Detected format change");
 
 			/* If we're collecting previous frame wait
@@ -4855,79 +4697,73 @@
 			if (signal_pending(current)) return -EINTR;
 
 			mode_init_regs(ov, ov->frame[0].width,
-				ov->frame[0].height, p.palette, ov->sub_flag);
+				ov->frame[0].height, p->palette, ov->sub_flag);
 		}
 
-		PDEBUG(4, "Setting depth=%d, palette=%d", p.depth, p.palette);
+		PDEBUG(4, "Setting depth=%d, palette=%s",
+		       p->depth, symbolic(v4l1_plist, p->palette));
+
 		for (i = 0; i < OV511_NUMFRAMES; i++) {
-			ov->frame[i].depth = p.depth;
-			ov->frame[i].format = p.palette;
+			ov->frame[i].depth = p->depth;
+			ov->frame[i].format = p->palette;
 		}
 
 		return 0;
 	}
 	case VIDIOCGCAPTURE:
 	{
-		int vf;
+		int *vf = arg;
 
 		PDEBUG(4, "VIDIOCGCAPTURE");
 
-		if (copy_from_user(&vf, arg, sizeof(vf)))
-			return -EFAULT;
-		ov->sub_flag = vf;
+		ov->sub_flag = *vf;
 		return 0;
 	}
 	case VIDIOCSCAPTURE:
 	{
-		struct video_capture vc;
+		struct video_capture *vc = arg;
 
 		PDEBUG(4, "VIDIOCSCAPTURE");
 
-		if (copy_from_user(&vc, arg, sizeof(vc)))
-			return -EFAULT;
-		if (vc.flags)
+		if (vc->flags)
 			return -EINVAL;
-		if (vc.decimation)
+		if (vc->decimation)
 			return -EINVAL;
 
-		vc.x &= ~3L;
-		vc.y &= ~1L;
-		vc.y &= ~31L;
-
-		if (vc.width == 0)
-			vc.width = 32;
-
-		vc.height /= 16;
-		vc.height *= 16;
-		if (vc.height == 0)
-			vc.height = 16;
-
-		ov->subx = vc.x;
-		ov->suby = vc.y;
-		ov->subw = vc.width;
-		ov->subh = vc.height;
+		vc->x &= ~3L;
+		vc->y &= ~1L;
+		vc->y &= ~31L;
+
+		if (vc->width == 0)
+			vc->width = 32;
+
+		vc->height /= 16;
+		vc->height *= 16;
+		if (vc->height == 0)
+			vc->height = 16;
+
+		ov->subx = vc->x;
+		ov->suby = vc->y;
+		ov->subw = vc->width;
+		ov->subh = vc->height;
 
 		return 0;
 	}
 	case VIDIOCSWIN:
 	{
-		struct video_window vw;
+		struct video_window *vw = arg;
 		int i, result;
 
-		if (copy_from_user(&vw, arg, sizeof(vw)))
-			return -EFAULT;
-
-		PDEBUG(4, "VIDIOCSWIN: width=%d, height=%d",
-			vw.width, vw.height);
+		PDEBUG(4, "VIDIOCSWIN: %dx%d", vw->width, vw->height);
 
 #if 0
-		if (vw.flags)
+		if (vw->flags)
 			return -EINVAL;
-		if (vw.clipcount)
+		if (vw->clipcount)
 			return -EINVAL;
-		if (vw.height != ov->maxheight)
+		if (vw->height != ov->maxheight)
 			return -EINVAL;
-		if (vw.width != ov->maxwidth)
+		if (vw->width != ov->maxwidth)
 			return -EINVAL;
 #endif
 
@@ -4936,140 +4772,131 @@
 		interruptible_sleep_on(&ov->wq);
 		if (signal_pending(current)) return -EINTR;
 
-		result = mode_init_regs(ov, vw.width, vw.height,
+		result = mode_init_regs(ov, vw->width, vw->height,
 			ov->frame[0].format, ov->sub_flag);
 		if (result < 0)
 			return result;
 
 		for (i = 0; i < OV511_NUMFRAMES; i++) {
-			ov->frame[i].width = vw.width;
-			ov->frame[i].height = vw.height;
+			ov->frame[i].width = vw->width;
+			ov->frame[i].height = vw->height;
 		}
 
 		return 0;
 	}
 	case VIDIOCGWIN:
 	{
-		struct video_window vw;
-
-		memset(&vw, 0, sizeof(vw));
-		vw.x = 0;		/* FIXME */
-		vw.y = 0;
-		vw.width = ov->frame[0].width;
-		vw.height = ov->frame[0].height;
-		vw.flags = 30;
+		struct video_window *vw = arg;
 
-		PDEBUG(4, "VIDIOCGWIN: %dx%d", vw.width, vw.height);
+		memset(vw, 0, sizeof(struct video_window));
+		vw->x = 0;		/* FIXME */
+		vw->y = 0;
+		vw->width = ov->frame[0].width;
+		vw->height = ov->frame[0].height;
+		vw->flags = 30;
 
-		if (copy_to_user(arg, &vw, sizeof(vw)))
-			return -EFAULT;
+		PDEBUG(4, "VIDIOCGWIN: %dx%d", vw->width, vw->height);
 
 		return 0;
 	}
 	case VIDIOCGMBUF:
 	{
-		struct video_mbuf vm;
+		struct video_mbuf *vm = arg;
 		int i;
 
 		PDEBUG(4, "VIDIOCGMBUF");
 
-		memset(&vm, 0, sizeof(vm));
-		vm.size = OV511_NUMFRAMES
-			* MAX_DATA_SIZE(ov->maxwidth, ov->maxheight);
-		vm.frames = OV511_NUMFRAMES;
+		memset(vm, 0, sizeof(struct video_mbuf));
+		vm->size = OV511_NUMFRAMES
+			   * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight);
+		vm->frames = OV511_NUMFRAMES;
 
-		vm.offsets[0] = 0;
+		vm->offsets[0] = 0;
 		for (i = 1; i < OV511_NUMFRAMES; i++) {
-			vm.offsets[i] = vm.offsets[i-1]
+			vm->offsets[i] = vm->offsets[i-1]
 			   + MAX_DATA_SIZE(ov->maxwidth, ov->maxheight);
 		}
 
-		if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
-			return -EFAULT;
-
 		return 0;
 	}
 	case VIDIOCMCAPTURE:
 	{
-		struct video_mmap vm;
+		struct video_mmap *vm = arg;
 		int ret, depth;
+		unsigned int f = vm->frame;
 
-		if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm)))
-			return -EFAULT;
-
-		PDEBUG(4, "CMCAPTURE");
-		PDEBUG(4, "frame: %d, size: %dx%d, format: %d",
-			vm.frame, vm.width, vm.height, vm.format);
+		PDEBUG(4, "VIDIOCMCAPTURE: frame: %d, %dx%d, %s", f, vm->width,
+			vm->height, symbolic(v4l1_plist, vm->format));
 
-		depth = get_depth(vm.format);
+		depth = get_depth(vm->format);
 		if (!depth) {
-			err("VIDIOCMCAPTURE: invalid format (%d)", vm.format);
+			err("VIDIOCMCAPTURE: invalid format (%s)",
+			    symbolic(v4l1_plist, vm->format));
 			return -EINVAL;
 		}
 
-		if ((unsigned)vm.frame >= OV511_NUMFRAMES) {
-			err("VIDIOCMCAPTURE: invalid frame (%d)", vm.frame);
+		if (f >= OV511_NUMFRAMES) {
+			err("VIDIOCMCAPTURE: invalid frame (%d)", f);
 			return -EINVAL;
 		}
 
-		if (vm.width > ov->maxwidth 
-		    || vm.height > ov->maxheight) {
+		if (vm->width > ov->maxwidth
+		    || vm->height > ov->maxheight) {
 			err("VIDIOCMCAPTURE: requested dimensions too big");
 			return -EINVAL;
 		}
 
-		if (ov->frame[vm.frame].grabstate == FRAME_GRABBING) {
+		if (ov->frame[f].grabstate == FRAME_GRABBING) {
 			PDEBUG(4, "VIDIOCMCAPTURE: already grabbing");
 			return -EBUSY;
 		}
 
-		if (force_palette && vm.format != force_palette) {
-			info("palette rejected (%d)", vm.format);
+		if (force_palette && (vm->format != force_palette)) {
+			info("palette rejected (%s)",
+			     symbolic(v4l1_plist, vm->format));
 			return -EINVAL;
 		}
 
-		if ((ov->frame[vm.frame].width != vm.width) ||
-		    (ov->frame[vm.frame].height != vm.height) ||
-		    (ov->frame[vm.frame].format != vm.format) ||
-		    (ov->frame[vm.frame].sub_flag != ov->sub_flag) ||
-		    (ov->frame[vm.frame].depth != depth)) {
+		if ((ov->frame[f].width != vm->width) ||
+		    (ov->frame[f].height != vm->height) ||
+		    (ov->frame[f].format != vm->format) ||
+		    (ov->frame[f].sub_flag != ov->sub_flag) ||
+		    (ov->frame[f].depth != depth)) {
 			PDEBUG(4, "VIDIOCMCAPTURE: change in image parameters");
 
 			/* If we're collecting previous frame wait
 			   before changing modes */
 			interruptible_sleep_on(&ov->wq);
 			if (signal_pending(current)) return -EINTR;
-			ret = mode_init_regs(ov, vm.width, vm.height,
-				vm.format, ov->sub_flag);
+			ret = mode_init_regs(ov, vm->width, vm->height,
+				vm->format, ov->sub_flag);
 #if 0
 			if (ret < 0) {
 				PDEBUG(1, "Got error while initializing regs ");
 				return ret;
 			}
 #endif
-			ov->frame[vm.frame].width = vm.width;
-			ov->frame[vm.frame].height = vm.height;
-			ov->frame[vm.frame].format = vm.format;
-			ov->frame[vm.frame].sub_flag = ov->sub_flag;
-			ov->frame[vm.frame].depth = depth;
+			ov->frame[f].width = vm->width;
+			ov->frame[f].height = vm->height;
+			ov->frame[f].format = vm->format;
+			ov->frame[f].sub_flag = ov->sub_flag;
+			ov->frame[f].depth = depth;
 		}
 
 		/* Mark it as ready */
-		ov->frame[vm.frame].grabstate = FRAME_READY;
+		ov->frame[f].grabstate = FRAME_READY;
 
-		PDEBUG(4, "VIDIOCMCAPTURE: renewing frame %d", vm.frame);
+		PDEBUG(4, "VIDIOCMCAPTURE: renewing frame %d", f);
 
-		return ov51x_new_frame(ov, vm.frame);
+		return ov51x_new_frame(ov, f);
 	}
 	case VIDIOCSYNC:
 	{
-		int fnum, rc;
+		unsigned int fnum = *((unsigned int *) arg);
 		struct ov511_frame *frame;
+		int rc;
 
-		if (copy_from_user((void *)&fnum, arg, sizeof(int)))
-			return -EFAULT;
-
-		if ((unsigned)fnum >= OV511_NUMFRAMES) {
+		if (fnum >= OV511_NUMFRAMES) {
 			err("VIDIOCSYNC: invalid frame (%d)", fnum);
 			return -EINVAL;
 		}
@@ -5103,7 +4930,7 @@
 					return ret;
 				goto redo;
 			}
-			/* Fall through */			
+			/* Fall through */
 		case FRAME_DONE:
 			if (ov->snap_enabled && !frame->snapshot) {
 				int ret;
@@ -5131,159 +4958,109 @@
 	}
 	case VIDIOCGFBUF:
 	{
-		struct video_buffer vb;
-
-		PDEBUG(4, "VIDIOCSCHAN");
+		struct video_buffer *vb = arg;
 
-		memset(&vb, 0, sizeof(vb));
-		vb.base = NULL;	/* frame buffer not supported, not used */
+		PDEBUG(4, "VIDIOCGFBUF");
 
-		if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb)))
-			return -EFAULT;
+		memset(vb, 0, sizeof(struct video_buffer));
 
 		return 0;
 	}
 	case VIDIOCGUNIT:
 	{
-		struct video_unit vu;
+		struct video_unit *vu = arg;
 
 		PDEBUG(4, "VIDIOCGUNIT");
 
-		memset(&vu, 0, sizeof(vu));
-
-		vu.video = ov->vdev.minor;	/* Video minor */
-		vu.vbi = VIDEO_NO_UNIT;		/* VBI minor */
-		vu.radio = VIDEO_NO_UNIT;	/* Radio minor */
-		vu.audio = VIDEO_NO_UNIT;	/* Audio minor */
-		vu.teletext = VIDEO_NO_UNIT;	/* Teletext minor */
-
-		if (copy_to_user((void *)arg, (void *)&vu, sizeof(vu)))
-			return -EFAULT;
-
-		return 0;
-	}
-	case VIDIOCGTUNER:
-	{
-		struct video_tuner v;
-
-		PDEBUG(4, "VIDIOCGTUNER");
-
-		if (copy_from_user(&v, arg, sizeof(v)))
-			return -EFAULT;
-
-		if (!ov->has_tuner || v.tuner)	// Only tuner 0
-			return -EINVAL;
-
-		strcpy(v.name, "Television");
-
-		// FIXME: Need a way to get the real values
-		v.rangelow = 0;
-		v.rangehigh = ~0;
-
-		v.flags = VIDEO_TUNER_PAL | VIDEO_TUNER_NTSC |
-		    VIDEO_TUNER_SECAM;
-		v.mode = 0; 		/* FIXME:  Not sure what this is yet */
-		v.signal = 0xFFFF;	/* unknown */
-
-		call_i2c_clients(ov, cmd, &v);
-
-		if (copy_to_user(arg, &v, sizeof(v)))
-			return -EFAULT;
-
-		return 0;
-	}
-	case VIDIOCSTUNER:
-	{
-		struct video_tuner v;
-		int err;
-
-		PDEBUG(4, "VIDIOCSTUNER");
-
-		if (copy_from_user(&v, arg, sizeof(v)))
-			return -EFAULT;
-
-		/* Only no or one tuner for now */
-		if (!ov->has_tuner || v.tuner)
-			return -EINVAL;
-
-		/* and it only has certain valid modes */
-		if (v.mode != VIDEO_MODE_PAL &&
-		    v.mode != VIDEO_MODE_NTSC &&
-		    v.mode != VIDEO_MODE_SECAM) return -EOPNOTSUPP;
-
-		/* Is this right/necessary? */
-		err = decoder_set_norm(ov, v.mode);
-		if (err)
-			return err;
+		memset(vu, 0, sizeof(struct video_unit));
 
-		call_i2c_clients(ov, cmd, &v);
+		vu->video = ov->vdev.minor;
+		vu->vbi = VIDEO_NO_UNIT;
+		vu->radio = VIDEO_NO_UNIT;
+		vu->audio = VIDEO_NO_UNIT;
+		vu->teletext = VIDEO_NO_UNIT;
 
 		return 0;
 	}
-	case VIDIOCGFREQ:
-	{
-		unsigned long v = ov->freq;
+	default:
+		PDEBUG(3, "Unsupported IOCtl: 0x%X", cmd);
+		return -ENOIOCTLCMD;
+	} /* end switch */
 
-		PDEBUG(4, "VIDIOCGFREQ");
+	return 0;
+}
 
-		if (!ov->has_tuner)
-			return -EINVAL;
-#if 0
-		/* FIXME: this is necessary for testing */
-		v = 46*16;
-#endif
-		if (copy_to_user(arg, &v, sizeof(v)))
-			return -EFAULT;
+/* This is implemented as video_generic_ioctl() in the new V4L's videodev.c */
+static int
+ov51x_v4l1_generic_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
+{
+	char	sbuf[128];
+	void    *mbuf = NULL;
+	void	*parg = NULL;
+	int	err  = -EINVAL;
+
+	/*  Copy arguments into temp kernel buffer  */
+	switch (_IOC_DIR(cmd)) {
+	case _IOC_NONE:
+		parg = arg;
+		break;
+	case _IOC_READ: /* some v4l ioctls are marked wrong ... */
+	case _IOC_WRITE:
+	case (_IOC_WRITE | _IOC_READ):
+		if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
+			parg = sbuf;
+		} else {
+			/* too big to allocate from stack */
+			mbuf = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL);
+			if (NULL == mbuf)
+				return -ENOMEM;
+			parg = mbuf;
+		}
 
-		return 0;
+		err = -EFAULT;
+		if (copy_from_user(parg, arg, _IOC_SIZE(cmd)))
+			goto out;
+		break;
 	}
-	case VIDIOCSFREQ:
-	{
-		unsigned long v;
-
-		if (!ov->has_tuner)
-			return -EINVAL;
-
-		if (copy_from_user(&v, arg, sizeof(v)))
-			return -EFAULT;
-
-		PDEBUG(4, "VIDIOCSFREQ: %lx", v);
 
-		ov->freq = v;
-		call_i2c_clients(ov, cmd, &v);
+	err = ov51x_v4l1_ioctl_internal(vdev->priv, cmd, parg);
+	if (err == -ENOIOCTLCMD)
+		err = -EINVAL;
+	if (err < 0)
+		goto out;
 
-		return 0;
-	}
-	case VIDIOCGAUDIO:
-	case VIDIOCSAUDIO:
+	/*  Copy results into user buffer  */
+	switch (_IOC_DIR(cmd))
 	{
-		/* FIXME: Implement this... */
-		return 0;
+	case _IOC_READ:
+	case (_IOC_WRITE | _IOC_READ):
+		if (copy_to_user(arg, parg, _IOC_SIZE(cmd)))
+			err = -EFAULT;
+		break;
 	}
-	default:
-		PDEBUG(3, "Unsupported IOCtl: 0x%X", cmd);
-		return -ENOIOCTLCMD;
-	} /* end switch */
 
-	return 0;
+out:
+	if (mbuf)
+		kfree(mbuf);
+	return err;
 }
 
-static int 
+static int
 ov51x_v4l1_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
 {
-	int rc;
 	struct usb_ov511 *ov = vdev->priv;
+	int rc;
 
 	if (down_interruptible(&ov->lock))
 		return -EINTR;
 
-	rc = ov51x_v4l1_ioctl_internal(vdev, cmd, arg);
+	rc = ov51x_v4l1_generic_ioctl(vdev, cmd, arg);
 
 	up(&ov->lock);
 	return rc;
 }
 
-static inline long 
+static inline long
 ov51x_v4l1_read(struct video_device *vdev, char *buf, unsigned long count,
 		int noblock)
 {
@@ -5346,7 +5123,7 @@
 
 	/* Wait while we're grabbing the image */
 	PDEBUG(4, "Waiting image grabbing");
-	rc = wait_event_interruptible(frame->wq, 
+	rc = wait_event_interruptible(frame->wq,
 		(frame->grabstate == FRAME_DONE)
 		|| (frame->grabstate == FRAME_ERROR));
 
@@ -5393,7 +5170,7 @@
 		get_frame_length(frame));
 
 	/* copy bytes to user space; we allow for partials reads */
-//	if ((count + frame->bytes_read) 
+//	if ((count + frame->bytes_read)
 //	    > get_frame_length((struct ov511_frame *)frame))
 //		count = frame->scanlength - frame->bytes_read;
 
@@ -5435,11 +5212,11 @@
 	return rc;
 }
 
-static int 
+static int
 ov51x_v4l1_mmap(struct video_device *vdev, const char *adr, unsigned long size)
 {
-	struct usb_ov511 *ov = vdev->priv;
 	unsigned long start = (unsigned long)adr;
+	struct usb_ov511 *ov = vdev->priv;
 	unsigned long page, pos;
 
 	if (ov->dev == NULL)
@@ -5482,14 +5259,12 @@
 	open:		ov51x_v4l1_open,
 	close:		ov51x_v4l1_close,
 	read:		ov51x_v4l1_read,
-	write:		ov51x_v4l1_write,
 	ioctl:		ov51x_v4l1_ioctl,
 	mmap:		ov51x_v4l1_mmap,
-	initialize:	ov51x_v4l1_init_done,
 };
 
 #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
-static int 
+static int
 ov51x_control_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
 		    unsigned long ularg)
 {
@@ -5710,10 +5485,10 @@
  *
  ***************************************************************************/
 
-/* This initializes the OV7610, OV7620, or OV7620AE sensor. The OV7620AE uses
+/* This initializes the OV7610, OV7620, or OV76BE sensor. The OV76BE uses
  * the same register settings as the OV7610, since they are very similar.
  */
-static int 
+static int
 ov7xx0_configure(struct usb_ov511 *ov)
 {
 	int i, success;
@@ -5864,7 +5639,7 @@
 			err("this to " EMAIL);
 			err("This is only a warning. You can attempt to use");
 			err("your camera anyway");
-// Only issue a warning for now  
+// Only issue a warning for now
 //			return -1;
 		} else {
 			PDEBUG(1, "OV7xx0 initialized (method 2, %dx)", i+1);
@@ -5881,20 +5656,23 @@
 		info("Sensor is an OV7610");
 		ov->sensor = SEN_OV7610;
 	} else if ((rc & 3) == 1) {
-		/* I don't know what's different about the 76BE yet */
-		if (i2c_r(ov, 0x15) & 1)
+		/* I don't know what's different about the 76BE yet. */
+		if (i2c_r(ov, 0x15) & 1) {
 			info("Sensor is an OV7620AE");
-		else
+			info("PLEASE REPORT THE EXISTENCE OF THIS SENSOR TO");
+			info("THE DRIVER AUTHOR");
+		} else {
 			info("Sensor is an OV76BE");
+		}
 
 		/* OV511+ will return all zero isoc data unless we
 		 * configure the sensor as a 7620. Someone needs to
 		 * find the exact reg. setting that causes this. */
 		if (ov->bridge == BRG_OV511PLUS) {
-			info("Enabling 511+/7620AE workaround");
+			info("Enabling 511+/76BE workaround");
 			ov->sensor = SEN_OV7620;
 		} else {
-			ov->sensor = SEN_OV7620AE;
+			ov->sensor = SEN_OV76BE;
 		}
 	} else if ((rc & 3) == 0) {
 		info("Sensor is an OV7620");
@@ -5930,7 +5708,7 @@
 }
 
 /* This initializes the OV6620, OV6630, OV6630AE, or OV6630AF sensor. */
-static int 
+static int
 ov6xx0_configure(struct usb_ov511 *ov)
 {
 	int rc;
@@ -5944,6 +5722,8 @@
 		/* The ratio of 0x0c and 0x0d  controls the white point */
 		{ OV511_I2C_BUS, 0x0c, 0x24 },
 		{ OV511_I2C_BUS, 0x0d, 0x24 },
+		{ OV511_I2C_BUS, 0x0f, 0x15 }, /* COMS */
+		{ OV511_I2C_BUS, 0x10, 0x75 }, /* AEC Exposure time */
 		{ OV511_I2C_BUS, 0x12, 0x24 }, /* Enable AGC */
 		{ OV511_I2C_BUS, 0x14, 0x04 },
 		/* 0x16: 0x06 helps frame stability with moving objects */
@@ -5955,10 +5735,11 @@
 		{ OV511_I2C_BUS, 0x2a, 0x04 }, /* Disable framerate adjust */
 //		{ OV511_I2C_BUS, 0x2b, 0xac }, /* Framerate; Set 2a[7] first */
 		{ OV511_I2C_BUS, 0x2d, 0x99 },
+		{ OV511_I2C_BUS, 0x33, 0xa0 }, /* Color Procesing Parameter */
 		{ OV511_I2C_BUS, 0x34, 0xd2 }, /* Max A/D range */
 		{ OV511_I2C_BUS, 0x38, 0x8b },
 		{ OV511_I2C_BUS, 0x39, 0x40 },
-		
+
 		{ OV511_I2C_BUS, 0x3c, 0x39 }, /* Enable AEC mode changing */
 		{ OV511_I2C_BUS, 0x3c, 0x3c }, /* Change AEC mode */
 		{ OV511_I2C_BUS, 0x3c, 0x24 }, /* Disable AEC mode changing */
@@ -6038,7 +5819,7 @@
 		 * control the color balance */
 //	/*OK?*/	{ OV511_I2C_BUS, 0x4a, 0x80 }, // Check these
 //	/*OK?*/	{ OV511_I2C_BUS, 0x4b, 0x80 },
-//	/*U*/	{ OV511_I2C_BUS, 0x4c, 0xd0 }, 
+//	/*U*/	{ OV511_I2C_BUS, 0x4c, 0xd0 },
 	/*d2?*/	{ OV511_I2C_BUS, 0x4d, 0x10 }, /* This reduces noise a bit */
 	/*c1?*/	{ OV511_I2C_BUS, 0x4e, 0x40 },
 	/*04?*/	{ OV511_I2C_BUS, 0x4f, 0x07 },
@@ -6056,7 +5837,7 @@
 	};
 
 	PDEBUG(4, "starting sensor configuration");
-	
+
 	if (init_ov_sensor(ov) < 0) {
 		err("Failed to read sensor ID. You might not have an OV6xx0,");
 		err("or it may be not responding. Report this to " EMAIL);
@@ -6071,19 +5852,18 @@
 	if (rc < 0) {
 		err("Error detecting sensor type");
 		return -1;
-	} else if ((rc & 3) == 0) {
-		info("Sensor is an OV6630");
+	}
+
+	if ((rc & 3) == 0)
 		ov->sensor = SEN_OV6630;
-	} else if ((rc & 3) == 1) {
-		info("Sensor is an OV6620");
+	else if ((rc & 3) == 1)
 		ov->sensor = SEN_OV6620;
-	} else if ((rc & 3) == 2) {
-		info("Sensor is an OV6630AE");
+	else if ((rc & 3) == 2)
 		ov->sensor = SEN_OV6630;
-	} else if ((rc & 3) == 3) {
-		info("Sensor is an OV6630AF");
+	else if ((rc & 3) == 3)
 		ov->sensor = SEN_OV6630;
-	} 
+
+	info("Sensor is an %s", symbolic(senlist, ov->sensor));
 
 	/* Set sensor-specific vars */
 	ov->maxwidth = 352;
@@ -6106,7 +5886,7 @@
 		if (write_regvals(ov, aRegvalsNorm6x30))
 			return -1;
 	}
-	
+
 	return 0;
 }
 
@@ -6168,8 +5948,8 @@
 }
 
 /* This initializes the SAA7111A video decoder. */
-static int 
-saa7111a_configure(struct usb_ov511 *ov511)
+static int
+saa7111a_configure(struct usb_ov511 *ov)
 {
 	int rc;
 
@@ -6213,45 +5993,51 @@
 	}
 #endif
 
-	/* Set sensor-specific vars */
-	ov511->maxwidth = 640;
-	ov511->maxheight = 480;		/* Even/Odd fields */
-	ov511->minwidth = 320;
-	ov511->minheight = 240;		/* Even field only */
-
-	ov511->has_decoder = 1;
-	ov511->num_inputs = 8;
-	ov511->norm = VIDEO_MODE_AUTO;
-	ov511->stop_during_set = 0;	/* Decoder guarantees stable image */
+	/* 640x480 not supported with PAL */
+	if (ov->pal) {
+		ov->maxwidth = 320;
+		ov->maxheight = 240;		/* Even field only */
+	} else {
+		ov->maxwidth = 640;
+		ov->maxheight = 480;		/* Even/Odd fields */
+	}
+
+	ov->minwidth = 320;
+	ov->minheight = 240;		/* Even field only */
+
+	ov->has_decoder = 1;
+	ov->num_inputs = 8;
+	ov->norm = VIDEO_MODE_AUTO;
+	ov->stop_during_set = 0;	/* Decoder guarantees stable image */
 
 	/* Decoder doesn't change these values, so we use these instead of
 	 * acutally reading the registers (which doesn't work) */
-	ov511->brightness = 0x80 << 8;
-	ov511->contrast = 0x40 << 9;
-	ov511->colour = 0x40 << 9;
-	ov511->hue = 32768;
+	ov->brightness = 0x80 << 8;
+	ov->contrast = 0x40 << 9;
+	ov->colour = 0x40 << 9;
+	ov->hue = 32768;
 
 	PDEBUG(4, "Writing SAA7111A registers");
-	if (write_regvals(ov511, aRegvalsNormSAA7111A))
+	if (write_regvals(ov, aRegvalsNormSAA7111A))
 		return -1;
 
 	/* Detect version of decoder. This must be done after writing the
          * initial regs or the decoder will lock up. */
-	rc = i2c_r(ov511, 0x00);
+	rc = i2c_r(ov, 0x00);
 
 	if (rc < 0) {
 		err("Error detecting sensor version");
 		return -1;
 	} else {
 		info("Sensor is an SAA7111A (version 0x%x)", rc);
-		ov511->sensor = SEN_SAA7111A;
+		ov->sensor = SEN_SAA7111A;
 	}
 
 	// FIXME: Fix this for OV518(+)
 	/* Latch to negative edge of clock. Otherwise, we get incorrect
 	 * colors and jitter in the digital signal. */
-	if (ov511->bclass == BCL_OV511)
-		reg_w(ov511, 0x11, 0x00);
+	if (ov->bclass == BCL_OV511)
+		reg_w(ov, 0x11, 0x00);
 	else
 		warn("SAA7111A not yet supported with OV518/OV518+");
 
@@ -6262,8 +6048,6 @@
 static int 
 ov511_configure(struct usb_ov511 *ov)
 {
-	int i;
-
 	static struct ov511_regvals aRegvalsInit511[] = {
 		{ OV511_REG_BUS, R51x_SYS_RESET,	0x7f },
 	 	{ OV511_REG_BUS, R51x_SYS_INIT,		0x01 },
@@ -6305,26 +6089,19 @@
 		goto error;
 	}
 
-	ov->desc = -1;
 	PDEBUG (1, "CustomID = %d", ov->customid);
-	for (i = 0; clist[i].id >= 0; i++) {
-		if (ov->customid == clist[i].id) {
-			info("model: %s", clist[i].description);
-			ov->desc = i;
-			break;
-		}
-	}
+	ov->desc = symbolic(camlist, ov->customid);
+	info("model: %s", ov->desc);
 
-	if (clist[i].id == -1) {
+	if (0 == strcmp(ov->desc, NOT_DEFINED_STR)) {
 		err("Camera type (%d) not recognized", ov->customid);
 		err("Please notify " EMAIL " of the name,");
 		err("manufacturer, model, and this number of your camera.");
 		err("Also include the output of the detection process.");
 	} 
 
-	if (clist[i].id == 6) {	/* USB Life TV (NTSC) */
-		ov->tuner_type = 8;		/* Temic 4036FY5 3X 1981 */
-	}
+	if (ov->customid == 70)		/* USB Life TV (PAL/SECAM) */
+		ov->pal = 1;
 
 	if (write_regvals(ov, aRegvalsInit511)) goto error;
 
@@ -6343,9 +6120,10 @@
 
 	if (ov511_init_compression(ov)) goto error;
 
-	ov51x_set_packet_size(ov, 0);
+	ov->packet_numbering = 1;
+	ov511_set_packet_size(ov, 0);
 
-	ov->snap_enabled = snapshot;	
+	ov->snap_enabled = snapshot;
 
 	/* Test for 7xx0 */
 	PDEBUG(3, "Testing for 0V7xx0");
@@ -6364,21 +6142,21 @@
 			/* Test for 8xx0 */
 			PDEBUG(3, "Testing for 0V8xx0");
 			ov->primary_i2c_slave = OV8xx0_SID;
-			if (ov51x_set_slave_ids(ov, OV8xx0_SID))
+			if (ov51x_set_slave_ids(ov, OV8xx0_SID) < 0)
 				goto error;
 
 			if (i2c_w(ov, 0x12, 0x80) < 0) {
 				/* Test for SAA7111A */
 				PDEBUG(3, "Testing for SAA7111A");
 				ov->primary_i2c_slave = SAA7111A_SID;
-				if (ov51x_set_slave_ids(ov, SAA7111A_SID))
+				if (ov51x_set_slave_ids(ov, SAA7111A_SID) < 0)
 					goto error;
 
 				if (i2c_w(ov, 0x0d, 0x00) < 0) {
 					/* Test for KS0127 */
 					PDEBUG(3, "Testing for KS0127");
 					ov->primary_i2c_slave = KS0127_SID;
-					if (ov51x_set_slave_ids(ov, KS0127_SID))
+					if (ov51x_set_slave_ids(ov, KS0127_SID) < 0)
 						goto error;
 
 					if (i2c_w(ov, 0x10, 0x00) < 0) {
@@ -6422,9 +6200,10 @@
 }
 
 /* This initializes the OV518/OV518+ and the sensor */
-static int 
+static int
 ov518_configure(struct usb_ov511 *ov)
 {
+	/* For 518 and 518+ */
 	static struct ov511_regvals aRegvalsInit518[] = {
 		{ OV511_REG_BUS, R51x_SYS_RESET,	0x40 },
 	 	{ OV511_REG_BUS, R51x_SYS_INIT,		0xe1 },
@@ -6437,8 +6216,6 @@
 		{ OV511_DONE_BUS, 0x0, 0x00},
 	};
 
-	/* New values, based on Windows driver. Since what they do is not
-	 * known yet, this may be incorrect. */
 	static struct ov511_regvals aRegvalsNorm518[] = {
 		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x02 }, /* Reset */
 		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x01 }, /* Enable */
@@ -6452,11 +6229,33 @@
 		{ OV511_DONE_BUS, 0x0, 0x00 },
 	};
 
+	static struct ov511_regvals aRegvalsNorm518Plus[] = {
+		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x02 }, /* Reset */
+		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x01 }, /* Enable */
+		{ OV511_REG_BUS, 0x31, 			0x0f },
+		{ OV511_REG_BUS, 0x5d,			0x03 },
+		{ OV511_REG_BUS, 0x24,			0x9f },
+		{ OV511_REG_BUS, 0x25,			0x90 },
+		{ OV511_REG_BUS, 0x20,			0x60 }, /* Was 0x08 */
+		{ OV511_REG_BUS, 0x51,			0x02 },
+		{ OV511_REG_BUS, 0x71,			0x19 },
+		{ OV511_REG_BUS, 0x40,			0xff },
+		{ OV511_REG_BUS, 0x41,			0x42 },
+		{ OV511_REG_BUS, 0x46,			0x00 },
+		{ OV511_REG_BUS, 0x33,			0x04 },
+		{ OV511_REG_BUS, 0x21,			0x19 },
+		{ OV511_REG_BUS, 0x3f,			0x10 },
+		{ OV511_DONE_BUS, 0x0, 0x00 },
+	};
+
 	PDEBUG(4, "");
 
 	/* First 5 bits of custom ID reg are a revision ID on OV518 */
 	info("Device revision %d", 0x1F & reg_r(ov, R511_SYS_CUST_ID));
 
+	/* Give it the default description */
+	ov->desc = symbolic(camlist, 0);
+
 	if (write_regvals(ov, aRegvalsInit518)) goto error;
 
 	/* Set LED GPIO pin to output mode */
@@ -6475,13 +6274,25 @@
 		warn("Compression required with OV518...enabling");
 	}
 
-	if (write_regvals(ov, aRegvalsNorm518)) goto error;
+	if (ov->bridge == BRG_OV518) {
+		if (write_regvals(ov, aRegvalsNorm518)) goto error;
+	} else if (ov->bridge == BRG_OV518PLUS) {
+		if (write_regvals(ov, aRegvalsNorm518Plus)) goto error;
+	} else {
+		err("Invalid bridge");
+	}
 
 	if (reg_w(ov, 0x2f, 0x80) < 0) goto error;
 
 	if (ov518_init_compression(ov)) goto error;
 
-	ov51x_set_packet_size(ov, 0);
+	/* OV518+ has packet numbering turned on by default */
+	if (ov->bridge == BRG_OV518)
+		ov->packet_numbering = 0;
+	else
+		ov->packet_numbering = 1;
+
+	ov518_set_packet_size(ov, 0);
 
 	ov->snap_enabled = snapshot;
 
@@ -6526,9 +6337,8 @@
 		}
 	}
 
-	// FIXME: Sizes > 320x240 are not working yet
-	ov->maxwidth = 320;
-	ov->maxheight = 240;
+	ov->maxwidth = 352;
+	ov->maxheight = 288;
 
 	// The OV518 cannot go as low as the sensor can
 	ov->minwidth = 160;
@@ -6589,46 +6399,42 @@
 	ov->lightfreq = lightfreq;
 	ov->num_inputs = 1;	   /* Video decoder init functs. change this */
 	ov->stop_during_set = !fastset;
-	ov->tuner_type = tuner;
 	ov->backlight = backlight;
-
+	ov->mirror = mirror;
 	ov->auto_brt = autobright;
 	ov->auto_gain = autogain;
 	ov->auto_exp = autoexp;
 
 	switch (dev->descriptor.idProduct) {
 	case PROD_OV511:
-		info("USB OV511 camera found");
 		ov->bridge = BRG_OV511;
 		ov->bclass = BCL_OV511;
 		break;
 	case PROD_OV511PLUS:
-		info("USB OV511+ camera found");
 		ov->bridge = BRG_OV511PLUS;
 		ov->bclass = BCL_OV511;
 		break;
 	case PROD_OV518:
-		info("USB OV518 camera found");
 		ov->bridge = BRG_OV518;
 		ov->bclass = BCL_OV518;
 		break;
 	case PROD_OV518PLUS:
-		info("USB OV518+ camera found");
 		ov->bridge = BRG_OV518PLUS;
 		ov->bclass = BCL_OV518;
 		break;
 	case PROD_ME2CAM:
 		if (dev->descriptor.idVendor != VEND_MATTEL)
 			goto error;
-		info("Intel Play Me2Cam (OV511+) found");
 		ov->bridge = BRG_OV511PLUS;
 		ov->bclass = BCL_OV511;
 		break;
 	default:
-		err("Unknown product ID 0x%x", dev->descriptor.idProduct);
+		err("Unknown product ID 0x%04x", dev->descriptor.idProduct);
 		goto error_dealloc;
 	}
 
+	info("USB %s video device found", symbolic(brglist, ov->bridge));
+
 	/* Workaround for some applications that want data in RGB
 	 * instead of BGR. */
 	if (force_rgb)
@@ -6662,6 +6468,12 @@
 		init_waitqueue_head(&ov->frame[i].wq);
 	}
 
+	for (i = 0; i < OV511_NUMSBUF; i++) {
+		ov->sbuf[i].ov = ov;
+		spin_lock_init(&ov->sbuf[i].lock);
+		ov->sbuf[i].n = i;
+	}
+
 	/* Unnecessary? (This is done on open(). Need to make sure variables
 	 * are properly initialized without this before removing it, though). */
 	if (ov51x_set_default_params(ov) < 0)
@@ -6696,12 +6508,14 @@
 
 	info("Device registered on minor %d", ov->vdev.minor);
 
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+	create_proc_ov511_cam(ov);
+#endif
+
 	MOD_DEC_USE_COUNT;
      	return ov;
 
 error:
-	err("Camera initialization failed");
-
 #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
 	/* Safe to call even if entry doesn't exist */
 	destroy_proc_ov511_cam(ov);
@@ -6714,9 +6528,6 @@
 		up(&ov->cbuf_lock);
 	}
 
-	usb_driver_release_interface(&ov511_driver,
-		&dev->actconfig->interface[ov->iface]);
-
 error_dealloc:
 	if (ov) {
 		kfree(ov);
@@ -6725,6 +6536,7 @@
 
 error_out:
 	MOD_DEC_USE_COUNT;
+	err("Camera initialization failed");
 	return NULL;
 }
 
@@ -6759,22 +6571,12 @@
 
 	ov->streaming = 0;
 
-	/* Unschedule all of the iso td's */
-	for (n = OV511_NUMSBUF - 1; n >= 0; n--) {
-		if (ov->sbuf[n].urb) {
-			ov->sbuf[n].urb->next = NULL;
-			usb_unlink_urb(ov->sbuf[n].urb);
-			usb_free_urb(ov->sbuf[n].urb);
-			ov->sbuf[n].urb = NULL;
-		}
-	}
+	ov51x_unlink_isoc(ov);
 
 #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
         destroy_proc_ov511_cam(ov);
 #endif
 
-	usb_driver_release_interface(&ov511_driver,
-		&ov->dev->actconfig->interface[ov->iface]);
 	ov->dev = NULL;
 
 	/* Free the memory */
@@ -6807,7 +6609,7 @@
  ***************************************************************************/
 
 /* Returns 0 for success */
-int 
+int
 ov511_register_decomp_module(int ver, struct ov51x_decomp_ops *ops, int ov518,
 			     int mmx)
 {
@@ -6864,7 +6666,7 @@
 	return -EBUSY;
 }
 
-void 
+void
 ov511_deregister_decomp_module(int ov518, int mmx)
 {
 	lock_kernel();
@@ -6880,13 +6682,13 @@
 		else
 			ov511_decomp_ops = NULL;
 	}
-	
+
 	MOD_DEC_USE_COUNT;
 
 	unlock_kernel();
 }
 
-static int __init 
+static int __init
 usb_ov511_init(void)
 {
 #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
@@ -6896,11 +6698,8 @@
 	if (usb_register(&ov511_driver) < 0)
 		return -1;
 
-	// FIXME: Don't know how to determine this yet
-	ov51x_mmx_available = 0;
-
 #if defined (__i386__)
-	if (test_bit(X86_FEATURE_MMX, &boot_cpu_data.x86_capability))
+	if (test_bit(X86_FEATURE_MMX, boot_cpu_data.x86_capability))
 		ov51x_mmx_available = 1;
 #endif
 
@@ -6909,7 +6708,7 @@
 	return 0;
 }
 
-static void __exit 
+static void __exit
 usb_ov511_exit(void)
 {
 	usb_deregister(&ov511_driver);
@@ -6923,6 +6722,5 @@
 module_init(usb_ov511_init);
 module_exit(usb_ov511_exit);
 
-/* No version, for compatibility with binary-only modules */
-EXPORT_SYMBOL_NOVERS(ov511_register_decomp_module);
-EXPORT_SYMBOL_NOVERS(ov511_deregister_decomp_module);
+EXPORT_SYMBOL(ov511_register_decomp_module);
+EXPORT_SYMBOL(ov511_deregister_decomp_module);
diff -urN linux-2.4.20-pre4/drivers/usb/ov511.h linux-2.4.20-pre5/drivers/usb/ov511.h
--- linux-2.4.20-pre4/drivers/usb/ov511.h	Wed Aug 28 16:37:00 2002
+++ linux-2.4.20-pre5/drivers/usb/ov511.h	Wed Aug 28 16:38:21 2002
@@ -10,9 +10,8 @@
 
 #ifdef OV511_DEBUG
 	#define PDEBUG(level, fmt, args...) \
-		if (debug >= (level)) info("[%s:%d] " fmt,\
-		__PRETTY_FUNCTION__, \
-		__LINE__ , ## args)
+		if (debug >= (level)) info("[%s:%d] " fmt, \
+		__PRETTY_FUNCTION__, __LINE__ , ## args)
 #else
 	#define PDEBUG(level, fmt, args...) do {} while(0)
 #endif
@@ -244,6 +243,16 @@
 
 #define OV511_ENDPOINT_ADDRESS	1	/* Isoc endpoint number */
 
+#define OV511_NUMFRAMES	2
+#if OV511_NUMFRAMES > VIDEO_MAX_FRAME
+	#error "OV511_NUMFRAMES is too high"
+#endif
+
+#define OV511_NUMSBUF		2
+
+/* Control transfers use up to 4 bytes */
+#define OV511_CBUF_SIZE		4
+
 /* Bridge types */
 enum {
 	BRG_UNKNOWN,
@@ -377,9 +386,14 @@
 			       struct ov511_i2c_struct)
 /* ------------- End IOCTL interface -------------- */
 
+struct usb_ov511;		/* Forward declaration */
+
 struct ov511_sbuf {
-	char *data;
+	struct usb_ov511 *ov;
+	unsigned char *data;
 	struct urb *urb;
+	spinlock_t lock;
+	int n;
 };
 
 enum {
@@ -402,9 +416,10 @@
 
 struct ov511_frame {
 	int framenum;		/* Index of this frame */
-	char *data;		/* Frame buffer */
-	char *tempdata;		/* Temp buffer for multi-stage conversions */
-	char *rawdata;		/* Raw camera data buffer */
+	unsigned char *data;	/* Frame buffer */
+	unsigned char *tempdata; /* Temp buffer for multi-stage conversions */
+	unsigned char *rawdata;	/* Raw camera data buffer */
+	unsigned char *compbuf;	/* Temp buffer for decompressor */
 
 	int depth;		/* Bytes per pixel */
 	int width;		/* Width application is expecting */
@@ -429,27 +444,19 @@
 	int snapshot;		/* True if frame was a snapshot */
 };
 
-#define DECOMP_INTERFACE_VER 2
+#define DECOMP_INTERFACE_VER 4
 
 /* Compression module operations */
 struct ov51x_decomp_ops {
-	int (*decomp_400)(unsigned char *, unsigned char *, int, int, int);
-	int (*decomp_420)(unsigned char *, unsigned char *, int, int, int);
-	int (*decomp_422)(unsigned char *, unsigned char *, int, int, int);
-	void (*decomp_lock)(void);
-	void (*decomp_unlock)(void);
+	int (*decomp_400)(unsigned char *, unsigned char *, unsigned char *,
+			  int, int, int);
+	int (*decomp_420)(unsigned char *, unsigned char *, unsigned char *,
+			  int, int, int);
+	int (*decomp_422)(unsigned char *, unsigned char *, unsigned char *,
+			  int, int, int);
+	struct module *owner;
 };
 
-#define OV511_NUMFRAMES	2
-#if OV511_NUMFRAMES > VIDEO_MAX_FRAME
-	#error "OV511_NUMFRAMES is too high"
-#endif
-
-#define OV511_NUMSBUF		2
-
-/* Control transfers use up to 4 bytes */
-#define OV511_CBUF_SIZE		4
-
 struct usb_ov511 {
 	struct video_device vdev;
 
@@ -457,7 +464,7 @@
 	struct usb_device *dev;
 
 	int customid;
-	int desc;
+	char *desc;
 	unsigned char iface;
 
 	/* Determined by sensor type */
@@ -476,6 +483,7 @@
 	int auto_gain;		/* Auto gain control enabled flag */
 	int auto_exp;		/* Auto exposure enabled flag */
 	int backlight;		/* Backlight exposure algorithm flag */
+	int mirror;		/* Image is reversed horizontally */
 
 	int led_policy;		/* LED: off|on|auto; OV511+ only */
 
@@ -491,9 +499,9 @@
 	int lightfreq;		/* Power (lighting) frequency */
 	int bandfilt;		/* Banding filter enabled flag */
 
-	char *fbuf;		/* Videodev buffer area */
-	char *tempfbuf;		/* Temporary (intermediate) buffer area */
-	char *rawfbuf;		/* Raw camera data buffer area */
+	unsigned char *fbuf;	/* Videodev buffer area */
+	unsigned char *tempfbuf; /* Temporary (intermediate) buffer area */
+	unsigned char *rawfbuf;	/* Raw camera data buffer area */
 
 	int sub_flag;		/* Pix Array subcapture on flag */
 	int subx;		/* Pix Array subcapture x offset */
@@ -514,9 +522,9 @@
 	int bclass;		/* Class of bridge (BCL_*) */
 	int sensor;		/* Type of image sensor chip (SEN_*) */
 	int sclass;		/* Type of image sensor chip (SCL_*) */
-	int tuner;		/* Type of TV tuner */
 
 	int packet_size;	/* Frame size per isoc desc */
+	int packet_numbering;	/* Is ISO frame numbering enabled? */
 
 	struct semaphore param_lock;	/* params lock for this camera */
 
@@ -543,12 +551,9 @@
 	int num_inputs;		/* Number of inputs */
 	int norm; 		/* NTSC / PAL / SECAM */
 	int has_decoder;	/* Device has a video decoder */
-	int has_tuner;		/* Device has a TV tuner */
-	int has_audio_proc;	/* Device has an audio processor */
-	int freq;		/* Current tuner frequency */
-	int tuner_type;		/* Specific tuner model */
+	int pal;		/* Device is designed for PAL resolution */
 
-	/* I2C interface to kernel */
+	/* I2C interface */
 	struct semaphore i2c_lock;	  /* Protect I2C controller regs */
 	unsigned char primary_i2c_slave;  /* I2C write id of sensor */
 
@@ -557,27 +562,28 @@
 	struct semaphore cbuf_lock;
 };
 
-struct cam_list {
-	int id;
-	char *description;
-};
-
-struct palette_list {
+/* Used to represent a list of values and their respective symbolic names */
+struct symbolic_list {
 	int num;
 	char *name;
 };
 
-struct mode_list_518 {
-	int width;
-	int height;
-	u8 reg28;
-	u8 reg29;
-	u8 reg2a;
-	u8 reg2c;
-	u8 reg2e;
-	u8 reg24;
-	u8 reg25;
-};
+#define NOT_DEFINED_STR "Unknown"
+
+/* Returns the name of the matching element in the symbolic_list array. The
+ * end of the list must be marked with an element that has a NULL name.
+ */
+static inline char * 
+symbolic(struct symbolic_list list[], int num)
+{
+	int i;
+
+	for (i = 0; list[i].name != NULL; i++)
+			if (list[i].num == num)
+				return (list[i].name);
+
+	return (NOT_DEFINED_STR);
+}
 
 /* Compression stuff */
 
diff -urN linux-2.4.20-pre4/drivers/usb/pegasus.c linux-2.4.20-pre5/drivers/usb/pegasus.c
--- linux-2.4.20-pre4/drivers/usb/pegasus.c	Wed Aug 28 16:37:00 2002
+++ linux-2.4.20-pre5/drivers/usb/pegasus.c	Wed Aug 28 16:38:21 2002
@@ -1,46 +1,31 @@
 /*
-**	Pegasus: USB 10/100Mbps/HomePNA (1Mbps) Controller
-**
-**	Copyright (c) 1999-2002 Petko Manolov (petkan@users.sourceforge.net)
-**	
-**
-**	ChangeLog:
-**		....	Most of the time spend reading sources & docs.
-**		v0.2.x	First official release for the Linux kernel.
-**		v0.3.0	Beutified and structured, some bugs fixed.
-**		v0.3.x	URBifying bulk requests and bugfixing. First relatively
-**			stable release. Still can touch device's registers only
-**			from top-halves.
-**		v0.4.0	Control messages remained unurbified are now URBs.
-**			Now we can touch the HW at any time.
-**		v0.4.9	Control urbs again use process context to wait. Argh...
-**			Some long standing bugs (enable_net_traffic) fixed.
-**			Also nasty trick about resubmiting control urb from
-**			interrupt context used. Please let me know how it
-**			behaves. Pegasus II support added since this version.
-**			TODO: suppressing HCD warnings spewage on disconnect.
-**		v0.4.13	Ethernet address is now set at probe(), not at open()
-**			time as this seems to break dhcpd. 
-**		v0.4.25	ethtool support added.
-*/
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ *  Copyright (c) 1999-2002 Petko Manolov (petkan@users.sourceforge.net)
  *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *	
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *	ChangeLog:
+ *		....	Most of the time spend reading sources & docs.
+ *		v0.2.x	First official release for the Linux kernel.
+ *		v0.3.0	Beutified and structured, some bugs fixed.
+ *		v0.3.x	URBifying bulk requests and bugfixing. First relatively
+ *			stable release. Still can touch device's registers only
+ *			from top-halves.
+ *		v0.4.0	Control messages remained unurbified are now URBs.
+ *			Now we can touch the HW at any time.
+ *		v0.4.9	Control urbs again use process context to wait. Argh...
+ *			Some long standing bugs (enable_net_traffic) fixed.
+ *			Also nasty trick about resubmiting control urb from
+ *			interrupt context used. Please let me know how it
+ *			behaves. Pegasus II support added since this version.
+ *			TODO: suppressing HCD warnings spewage on disconnect.
+ *		v0.4.13	Ethernet address is now set at probe(), not at open()
+ *			time as this seems to break dhcpd. 
+ *		v0.4.25	ethtool support added.
  */
 
-
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/init.h>
@@ -69,7 +54,6 @@
 static int loopback = 0;
 static int mii_mode = 1;
 static int multicast_filter_limit = 32;
-static DECLARE_MUTEX(gsem);
 
 static struct usb_eth_dev usb_dev_id[] = {
 #define	PEGASUS_DEV(pn, vid, pid, flags)	\
@@ -84,104 +68,102 @@
 	{match_flags: USB_DEVICE_ID_MATCH_DEVICE, idVendor:vid, idProduct:pid},
 #include "pegasus.h"
 #undef	PEGASUS_DEV
-	{ }
+	{}
 };
 
-
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 MODULE_PARM(loopback, "i");
 MODULE_PARM(mii_mode, "i");
 MODULE_PARM_DESC(loopback, "Enable MAC loopback mode (bit 0)");
 MODULE_PARM_DESC(mii_mode, "Enable HomePNA mode (bit 0),default=MII mode = 0");
 
-MODULE_DEVICE_TABLE (usb, pegasus_ids);
-
+MODULE_DEVICE_TABLE(usb, pegasus_ids);
 
-static int update_eth_regs_async( pegasus_t * );
+static int update_eth_regs_async(pegasus_t *);
 /* Aargh!!! I _really_ hate such tweaks */
-static void ctrl_callback( struct urb *urb )
+static void ctrl_callback(struct urb *urb)
 {
-	pegasus_t	*pegasus = urb->context;
+	pegasus_t *pegasus = urb->context;
 
-	if ( !pegasus )
+	if (!pegasus)
 		return;
 
-	switch ( urb->status ) {
-		case 0:
-			if ( pegasus->flags & ETH_REGS_CHANGE ) {
-				pegasus->flags &= ~ETH_REGS_CHANGE;
-				pegasus->flags |= ETH_REGS_CHANGED;
-				update_eth_regs_async( pegasus );
-				return;
-			}
-			break;
-		case -EINPROGRESS:
+	switch (urb->status) {
+	case 0:
+		if (pegasus->flags & ETH_REGS_CHANGE) {
+			pegasus->flags &= ~ETH_REGS_CHANGE;
+			pegasus->flags |= ETH_REGS_CHANGED;
+			update_eth_regs_async(pegasus);
 			return;
-		case -ENOENT:
-			break;
-		default:
-			warn("%s: status %d", __FUNCTION__, urb->status);
+		}
+		break;
+	case -EINPROGRESS:
+		return;
+	case -ENOENT:
+		break;
+	default:
+		warn("%s: status %d", __FUNCTION__, urb->status);
 	}
 	pegasus->flags &= ~ETH_REGS_CHANGED;
-	wake_up(&pegasus->ctrl_wait );
+	wake_up(&pegasus->ctrl_wait);
 }
 
-
-static int get_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)
+static int get_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
+			 void *data)
 {
-	int	ret;
+	int ret;
 	unsigned char *buffer;
 	DECLARE_WAITQUEUE(wait, current);
 
-	buffer = kmalloc(size,GFP_KERNEL);
+	buffer = kmalloc(size, GFP_KERNEL);
 	if (!buffer) {
 		err("unable to allocate memory for configuration descriptors");
 		return 0;
 	}
-	memcpy(buffer,data,size);
+	memcpy(buffer, data, size);
 
 	add_wait_queue(&pegasus->ctrl_wait, &wait);
 	set_current_state(TASK_UNINTERRUPTIBLE);
-	while ( pegasus->flags & ETH_REGS_CHANGED )
+	while (pegasus->flags & ETH_REGS_CHANGED)
 		schedule();
 	remove_wait_queue(&pegasus->ctrl_wait, &wait);
 	set_current_state(TASK_RUNNING);
 
 	pegasus->dr.bRequestType = PEGASUS_REQT_READ;
 	pegasus->dr.bRequest = PEGASUS_REQ_GET_REGS;
-	pegasus->dr.wValue = cpu_to_le16 (0);
+	pegasus->dr.wValue = cpu_to_le16(0);
 	pegasus->dr.wIndex = cpu_to_le16p(&indx);
 	pegasus->dr.wLength = cpu_to_le16p(&size);
 	pegasus->ctrl_urb->transfer_buffer_length = size;
 
-	FILL_CONTROL_URB( pegasus->ctrl_urb, pegasus->usb,
-			  usb_rcvctrlpipe(pegasus->usb,0),
-			  (char *)&pegasus->dr,
-			  buffer, size, ctrl_callback, pegasus );
+	FILL_CONTROL_URB(pegasus->ctrl_urb, pegasus->usb,
+			 usb_rcvctrlpipe(pegasus->usb, 0),
+			 (char *) &pegasus->dr,
+			 buffer, size, ctrl_callback, pegasus);
 
-	add_wait_queue( &pegasus->ctrl_wait, &wait );
-	set_current_state( TASK_UNINTERRUPTIBLE );
+	add_wait_queue(&pegasus->ctrl_wait, &wait);
+	set_current_state(TASK_UNINTERRUPTIBLE);
 
-	if ( (ret = usb_submit_urb( pegasus->ctrl_urb )) ) {
+	if ((ret = usb_submit_urb(pegasus->ctrl_urb))) {
 		err("%s: BAD CTRLs %d", __FUNCTION__, ret);
 		goto out;
 	}
 
 	schedule();
 out:
-	remove_wait_queue( &pegasus->ctrl_wait, &wait );
-	memcpy(data,buffer,size);
+	remove_wait_queue(&pegasus->ctrl_wait, &wait);
+	memcpy(data, buffer, size);
 	kfree(buffer);
 
 	return ret;
 }
 
-
-static int set_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)
+static int set_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
+			 void *data)
 {
-	int	ret;
+	int ret;
 	unsigned char *buffer;
 	DECLARE_WAITQUEUE(wait, current);
 
@@ -194,47 +176,46 @@
 
 	add_wait_queue(&pegasus->ctrl_wait, &wait);
 	set_current_state(TASK_UNINTERRUPTIBLE);
-	while ( pegasus->flags & ETH_REGS_CHANGED )
+	while (pegasus->flags & ETH_REGS_CHANGED)
 		schedule();
 	remove_wait_queue(&pegasus->ctrl_wait, &wait);
 	set_current_state(TASK_RUNNING);
 
 	pegasus->dr.bRequestType = PEGASUS_REQT_WRITE;
 	pegasus->dr.bRequest = PEGASUS_REQ_SET_REGS;
-	pegasus->dr.wValue = cpu_to_le16 (0);
-	pegasus->dr.wIndex = cpu_to_le16p( &indx );
-	pegasus->dr.wLength = cpu_to_le16p( &size );
+	pegasus->dr.wValue = cpu_to_le16(0);
+	pegasus->dr.wIndex = cpu_to_le16p(&indx);
+	pegasus->dr.wLength = cpu_to_le16p(&size);
 	pegasus->ctrl_urb->transfer_buffer_length = size;
 
-	FILL_CONTROL_URB( pegasus->ctrl_urb, pegasus->usb,
-			  usb_sndctrlpipe(pegasus->usb,0),
-			  (char *)&pegasus->dr,
-			  buffer, size, ctrl_callback, pegasus );
-			  
-	add_wait_queue( &pegasus->ctrl_wait, &wait );
-	set_current_state( TASK_UNINTERRUPTIBLE );
+	FILL_CONTROL_URB(pegasus->ctrl_urb, pegasus->usb,
+			 usb_sndctrlpipe(pegasus->usb, 0),
+			 (char *) &pegasus->dr,
+			 buffer, size, ctrl_callback, pegasus);
 
-	if ( (ret = usb_submit_urb( pegasus->ctrl_urb )) ) {
+	add_wait_queue(&pegasus->ctrl_wait, &wait);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+
+	if ((ret = usb_submit_urb(pegasus->ctrl_urb))) {
 		err("%s: BAD CTRL %d", __FUNCTION__, ret);
 		goto out;
 	}
-	
+
 	schedule();
 out:
-	remove_wait_queue( &pegasus->ctrl_wait, &wait );
+	remove_wait_queue(&pegasus->ctrl_wait, &wait);
 	kfree(buffer);
-	
+
 	return ret;
 }
 
-
-static int set_register( pegasus_t *pegasus, __u16 indx, __u8 data )
+static int set_register(pegasus_t * pegasus, __u16 indx, __u8 data)
 {
-	int	ret;
+	int ret;
 	unsigned char *buffer;
 	__u16 dat = data;
 	DECLARE_WAITQUEUE(wait, current);
-	
+
 	buffer = kmalloc(1, GFP_KERNEL);
 	if (!buffer) {
 		err("unable to allocate memory for configuration descriptors");
@@ -244,129 +225,126 @@
 
 	add_wait_queue(&pegasus->ctrl_wait, &wait);
 	set_current_state(TASK_UNINTERRUPTIBLE);
-	while ( pegasus->flags & ETH_REGS_CHANGED )
+	while (pegasus->flags & ETH_REGS_CHANGED)
 		schedule();
 	remove_wait_queue(&pegasus->ctrl_wait, &wait);
 	set_current_state(TASK_RUNNING);
 
 	pegasus->dr.bRequestType = PEGASUS_REQT_WRITE;
 	pegasus->dr.bRequest = PEGASUS_REQ_SET_REG;
-	pegasus->dr.wValue = cpu_to_le16p( &dat);
-	pegasus->dr.wIndex = cpu_to_le16p( &indx );
-	pegasus->dr.wLength = cpu_to_le16( 1 );
+	pegasus->dr.wValue = cpu_to_le16p(&dat);
+	pegasus->dr.wIndex = cpu_to_le16p(&indx);
+	pegasus->dr.wLength = cpu_to_le16(1);
 	pegasus->ctrl_urb->transfer_buffer_length = 1;
 
-	FILL_CONTROL_URB( pegasus->ctrl_urb, pegasus->usb,
-			  usb_sndctrlpipe(pegasus->usb,0),
-			  (char *)&pegasus->dr,
-			  buffer, 1, ctrl_callback, pegasus );
+	FILL_CONTROL_URB(pegasus->ctrl_urb, pegasus->usb,
+			 usb_sndctrlpipe(pegasus->usb, 0),
+			 (char *) &pegasus->dr,
+			 buffer, 1, ctrl_callback, pegasus);
 
-	add_wait_queue( &pegasus->ctrl_wait, &wait );
-	set_current_state( TASK_UNINTERRUPTIBLE );
+	add_wait_queue(&pegasus->ctrl_wait, &wait);
+	set_current_state(TASK_UNINTERRUPTIBLE);
 
-	if ( (ret = usb_submit_urb( pegasus->ctrl_urb )) ) {
+	if ((ret = usb_submit_urb(pegasus->ctrl_urb))) {
 		err("%s: BAD CTRL %d", __FUNCTION__, ret);
 		goto out;
 	}
 
 	schedule();
 out:
-	remove_wait_queue( &pegasus->ctrl_wait, &wait );
+	remove_wait_queue(&pegasus->ctrl_wait, &wait);
 	kfree(buffer);
 
 	return ret;
 }
 
-
-static int update_eth_regs_async( pegasus_t *pegasus )
+static int update_eth_regs_async(pegasus_t * pegasus)
 {
-	int	ret;
+	int ret;
 
 	pegasus->dr.bRequestType = PEGASUS_REQT_WRITE;
 	pegasus->dr.bRequest = PEGASUS_REQ_SET_REGS;
 	pegasus->dr.wValue = 0;
-	pegasus->dr.wIndex =  cpu_to_le16(EthCtrl0);
+	pegasus->dr.wIndex = cpu_to_le16(EthCtrl0);
 	pegasus->dr.wLength = cpu_to_le16(3);
 	pegasus->ctrl_urb->transfer_buffer_length = 3;
 
-	FILL_CONTROL_URB( pegasus->ctrl_urb, pegasus->usb,
-			  usb_sndctrlpipe(pegasus->usb,0),
-			  (char *)&pegasus->dr,
-			  pegasus->eth_regs, 3, ctrl_callback, pegasus );
+	FILL_CONTROL_URB(pegasus->ctrl_urb, pegasus->usb,
+			 usb_sndctrlpipe(pegasus->usb, 0),
+			 (char *) &pegasus->dr,
+			 pegasus->eth_regs, 3, ctrl_callback, pegasus);
+
+	if ((ret = usb_submit_urb(pegasus->ctrl_urb)))
+		err("%s: BAD CTRL %d, flgs %x", __FUNCTION__, ret,
+		    pegasus->flags);
 
-	if ( (ret = usb_submit_urb( pegasus->ctrl_urb )) )
-		err("%s: BAD CTRL %d, flgs %x",__FUNCTION__,ret,pegasus->flags);
-
-	return	ret;
+	return ret;
 }
 
-
-static int read_mii_word( pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 *regd )
+static int read_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 * regd)
 {
-	int	i;
-	__u8	data[4] = { phy, 0, 0, indx };
-	__u16  regdi;
-	
-	set_register( pegasus, PhyCtrl, 0 );
-	set_registers( pegasus, PhyAddr, sizeof(data), data );
-	set_register( pegasus, PhyCtrl, (indx | PHY_READ) );
+	int i;
+	__u8 data[4] = { phy, 0, 0, indx };
+	__u16 regdi;
+
+	set_register(pegasus, PhyCtrl, 0);
+	set_registers(pegasus, PhyAddr, sizeof(data), data);
+	set_register(pegasus, PhyCtrl, (indx | PHY_READ));
 	for (i = 0; i < REG_TIMEOUT; i++) {
 		get_registers(pegasus, PhyCtrl, 1, data);
-		if ( data[0] & PHY_DONE ) 
+		if (data[0] & PHY_DONE)
 			break;
 	}
-	if ( i < REG_TIMEOUT ) {
-		get_registers( pegasus, PhyData, 2, &regdi );
+	if (i < REG_TIMEOUT) {
+		get_registers(pegasus, PhyData, 2, &regdi);
 		*regd = le16_to_cpu(regdi);
-		return	0;
+		return 0;
 	}
 	warn("%s: failed", __FUNCTION__);
-	
+
 	return 1;
 }
 
-
-static int write_mii_word( pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 regd )
+static int write_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 regd)
 {
-	int	i;
-	__u8	data[4] = { phy, 0, 0, indx };
-	
-	*(data + 1) = cpu_to_le16p( &regd );
-	set_register( pegasus, PhyCtrl, 0 );
-	set_registers( pegasus, PhyAddr, 4, data );
-	set_register( pegasus, PhyCtrl, (indx | PHY_WRITE) );
+	int i;
+	__u8 data[4] = { phy, 0, 0, indx };
+
+	*(data + 1) = cpu_to_le16p(&regd);
+	set_register(pegasus, PhyCtrl, 0);
+	set_registers(pegasus, PhyAddr, 4, data);
+	set_register(pegasus, PhyCtrl, (indx | PHY_WRITE));
 	for (i = 0; i < REG_TIMEOUT; i++) {
 		get_registers(pegasus, PhyCtrl, 1, data);
-		if ( data[0] & PHY_DONE ) 
+		if (data[0] & PHY_DONE)
 			break;
 	}
-	if ( i < REG_TIMEOUT )
-		return	0;
+	if (i < REG_TIMEOUT)
+		return 0;
 	warn("%s: failed", __FUNCTION__);
 
 	return 1;
 }
 
-
-static int read_eprom_word( pegasus_t *pegasus, __u8 index, __u16 *retdata )
+static int read_eprom_word(pegasus_t * pegasus, __u8 index, __u16 * retdata)
 {
-	int	i;
+	int i;
 	__u8 tmp;
 	__u16 retdatai;
-	
-	set_register( pegasus, EpromCtrl, 0 );
-	set_register( pegasus, EpromOffset, index );
-	set_register( pegasus, EpromCtrl, EPROM_READ); 
-
-	for ( i=0; i < REG_TIMEOUT; i++ ) {
-		get_registers( pegasus, EpromCtrl, 1, &tmp );
-		if ( tmp & EPROM_DONE )
+
+	set_register(pegasus, EpromCtrl, 0);
+	set_register(pegasus, EpromOffset, index);
+	set_register(pegasus, EpromCtrl, EPROM_READ);
+
+	for (i = 0; i < REG_TIMEOUT; i++) {
+		get_registers(pegasus, EpromCtrl, 1, &tmp);
+		if (tmp & EPROM_DONE)
 			break;
 	}
-	if ( i < REG_TIMEOUT ) {
-		get_registers( pegasus, EpromData, 2, &retdatai );
-		*retdata = le16_to_cpu (retdatai);
-		return	0;
+	if (i < REG_TIMEOUT) {
+		get_registers(pegasus, EpromData, 2, &retdatai);
+		*retdata = le16_to_cpu(retdatai);
+		return 0;
 	}
 	warn("%s: failed", __FUNCTION__);
 
@@ -374,199 +352,188 @@
 }
 
 #ifdef	PEGASUS_WRITE_EEPROM
-static inline void enable_eprom_write( pegasus_t *pegasus )
+static inline void enable_eprom_write(pegasus_t * pegasus)
 {
-	__u8	tmp;
+	__u8 tmp;
 
-	get_registers( pegasus, EthCtrl2, 1, &tmp );
-	set_register( pegasus, EthCtrl2, tmp | EPROM_WR_ENABLE );
+	get_registers(pegasus, EthCtrl2, 1, &tmp);
+	set_register(pegasus, EthCtrl2, tmp | EPROM_WR_ENABLE);
 }
 
-
-static inline void disable_eprom_write( pegasus_t *pegasus )
+static inline void disable_eprom_write(pegasus_t * pegasus)
 {
-	__u8 	tmp;
+	__u8 tmp;
 
-	get_registers( pegasus, EthCtrl2, 1, &tmp );
-	set_register( pegasus, EpromCtrl, 0 );
-	set_register( pegasus, EthCtrl2, tmp & ~EPROM_WR_ENABLE );
+	get_registers(pegasus, EthCtrl2, 1, &tmp);
+	set_register(pegasus, EpromCtrl, 0);
+	set_register(pegasus, EthCtrl2, tmp & ~EPROM_WR_ENABLE);
 }
 
-
-static int write_eprom_word( pegasus_t *pegasus, __u8 index, __u16 data )
+static int write_eprom_word(pegasus_t * pegasus, __u8 index, __u16 data)
 {
-	int	i, tmp;
-	__u8	d[4] = {0x3f, 0, 0, EPROM_WRITE};
+	int i, tmp;
+	__u8 d[4] = { 0x3f, 0, 0, EPROM_WRITE };
 
-	set_registers( pegasus, EpromOffset, 4, d );
-	enable_eprom_write( pegasus );
-	set_register( pegasus, EpromOffset, index );
-	set_registers( pegasus, EpromData, 2, &data );
-	set_register( pegasus, EpromCtrl, EPROM_WRITE );
+	set_registers(pegasus, EpromOffset, 4, d);
+	enable_eprom_write(pegasus);
+	set_register(pegasus, EpromOffset, index);
+	set_registers(pegasus, EpromData, 2, &data);
+	set_register(pegasus, EpromCtrl, EPROM_WRITE);
 
-	for ( i=0; i < REG_TIMEOUT; i++ ) {
-		get_registers( pegasus, EpromCtrl, 1, &tmp );
-		if ( tmp & EPROM_DONE )
+	for (i = 0; i < REG_TIMEOUT; i++) {
+		get_registers(pegasus, EpromCtrl, 1, &tmp);
+		if (tmp & EPROM_DONE)
 			break;
 	}
-	disable_eprom_write( pegasus );
-	if ( i < REG_TIMEOUT )
-		return	0;
+	disable_eprom_write(pegasus);
+	if (i < REG_TIMEOUT)
+		return 0;
 	warn("%s: failed", __FUNCTION__);
-	return	-1;
+	return -1;
 }
-#endif	/* PEGASUS_WRITE_EEPROM */
+#endif				/* PEGASUS_WRITE_EEPROM */
 
-static inline void get_node_id( pegasus_t *pegasus, __u8 *id )
+static inline void get_node_id(pegasus_t * pegasus, __u8 * id)
 {
-	int	i;
+	int i;
 	__u16 w16;
-	
+
 	for (i = 0; i < 3; i++) {
-		read_eprom_word( pegasus, i, &w16);
-		((__u16 *) id)[i] = cpu_to_le16p (&w16);
+		read_eprom_word(pegasus, i, &w16);
+		((__u16 *) id)[i] = cpu_to_le16p(&w16);
 	}
 }
 
-
-static void set_ethernet_addr( pegasus_t *pegasus )
+static void set_ethernet_addr(pegasus_t * pegasus)
 {
-	__u8	node_id[6];
+	__u8 node_id[6];
 
 	get_node_id(pegasus, node_id);
-	set_registers( pegasus, EthID, sizeof(node_id), node_id );
-	memcpy( pegasus->net->dev_addr, node_id, sizeof(node_id) );
+	set_registers(pegasus, EthID, sizeof(node_id), node_id);
+	memcpy(pegasus->net->dev_addr, node_id, sizeof(node_id));
 }
 
-
-static inline int reset_mac( pegasus_t *pegasus )
+static inline int reset_mac(pegasus_t * pegasus)
 {
-	__u8	data = 0x8;
-	int	i;
+	__u8 data = 0x8;
+	int i;
 
 	set_register(pegasus, EthCtrl1, data);
 	for (i = 0; i < REG_TIMEOUT; i++) {
 		get_registers(pegasus, EthCtrl1, 1, &data);
 		if (~data & 0x08) {
-			if (loopback & 1) 
+			if (loopback & 1)
 				break;
-			if ( mii_mode && (pegasus->features & HAS_HOME_PNA) )
-				set_register( pegasus, Gpio1, 0x34 );
+			if (mii_mode && (pegasus->features & HAS_HOME_PNA))
+				set_register(pegasus, Gpio1, 0x34);
 			else
-				set_register( pegasus, Gpio1, 0x26 );
-			set_register( pegasus, Gpio0, pegasus->features );
-			set_register( pegasus, Gpio0, DEFAULT_GPIO_SET );
+				set_register(pegasus, Gpio1, 0x26);
+			set_register(pegasus, Gpio0, pegasus->features);
+			set_register(pegasus, Gpio0, DEFAULT_GPIO_SET);
 			break;
 		}
 	}
-	if ( i == REG_TIMEOUT )
+	if (i == REG_TIMEOUT)
 		return 1;
 
 	if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS ||
 	    usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK) {
-		__u16	auxmode;
+		__u16 auxmode;
 
 		read_mii_word(pegasus, 1, 0x1b, &auxmode);
 		write_mii_word(pegasus, 1, 0x1b, auxmode | 4);
 	}
 	if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_ELCON) {
-		__u16	auxmode;
+		__u16 auxmode;
 		read_mii_word(pegasus, 3, 0x1b, &auxmode);
 		write_mii_word(pegasus, 3, 0x1b, auxmode | 4);
 	}
-	return	0;
+	return 0;
 }
 
-
-static int enable_net_traffic( struct net_device *dev, struct usb_device *usb )
+static int enable_net_traffic(struct net_device *dev, struct usb_device *usb)
 {
-	__u16	linkpart, bmsr;
-	__u8	data[4];
+	__u16 linkpart, bmsr;
+	__u8 data[4];
 	pegasus_t *pegasus = dev->priv;
 
 	/* read twice 'cos this is a latch bit */
 	read_mii_word(pegasus, pegasus->phy, MII_BMSR, &bmsr);
 	read_mii_word(pegasus, pegasus->phy, MII_BMSR, &bmsr);
-	if ( !(bmsr & 4) && !loopback ) 
-		warn( "%s: link NOT established (0x%x) - check the cable.",
-			dev->name, bmsr );
-	if ( read_mii_word(pegasus, pegasus->phy, MII_LPA, &linkpart) )
+	if (read_mii_word(pegasus, pegasus->phy, MII_LPA, &linkpart))
 		return 2;
-	if ( !(linkpart & 1) )
-		warn( "link partner stat %x", linkpart );
+	if (!(linkpart & 1))
+		warn("link partner stat %x", linkpart);
 
 	data[0] = 0xc9;
 	data[1] = 0;
-	if ( linkpart & (ADVERTISE_100FULL | ADVERTISE_10FULL) )
-		data[1] |= 0x20; /* set full duplex */
-	if ( linkpart & (ADVERTISE_100FULL | ADVERTISE_100HALF) )
-		data[1] |= 0x10; /* set 100 Mbps */
-	if ( mii_mode )
+	if (linkpart & (ADVERTISE_100FULL | ADVERTISE_10FULL))
+		data[1] |= 0x20;	/* set full duplex */
+	if (linkpart & (ADVERTISE_100FULL | ADVERTISE_100HALF))
+		data[1] |= 0x10;	/* set 100 Mbps */
+	if (mii_mode)
 		data[1] = 0;
 	data[2] = (loopback & 1) ? 0x09 : 0x01;
-
-	memcpy( pegasus->eth_regs, data, sizeof(data) );
-
-	set_registers( pegasus, EthCtrl0, 3, data );
+	memcpy(pegasus->eth_regs, data, sizeof(data));
+	set_registers(pegasus, EthCtrl0, 3, data);
 
 	return 0;
 }
 
-
-static void read_bulk_callback( struct urb *urb )
+static void read_bulk_callback(struct urb *urb)
 {
 	pegasus_t *pegasus = urb->context;
 	struct net_device *net;
 	int count = urb->actual_length, res;
 	int rx_status;
-	struct sk_buff	*skb;
+	struct sk_buff *skb;
 	__u16 pkt_len;
 
-	if ( !pegasus || !(pegasus->flags & PEGASUS_RUNNING) )
+	if (!pegasus || !(pegasus->flags & PEGASUS_RUNNING))
 		return;
 
 	net = pegasus->net;
-	if ( !netif_device_present(net) )
+	if (!netif_device_present(net))
 		return;
 
-	if ( pegasus->flags & PEGASUS_RX_BUSY ) {
+	if (pegasus->flags & PEGASUS_RX_BUSY) {
 		pegasus->stats.rx_errors++;
 		dbg("pegasus Rx busy");
 		return;
 	}
 	pegasus->flags |= PEGASUS_RX_BUSY;
 
-	switch ( urb->status ) {
-		case 0:
-			break;
-		case -ETIMEDOUT:
-			dbg( "reset MAC" );
-			pegasus->flags &= ~PEGASUS_RX_BUSY;
-			break;
-		default:
-			dbg( "%s: RX status %d", net->name, urb->status );
-			goto goon;
+	switch (urb->status) {
+	case 0:
+		break;
+	case -ETIMEDOUT:
+		dbg("reset MAC");
+		pegasus->flags &= ~PEGASUS_RX_BUSY;
+		break;
+	default:
+		dbg("%s: RX status %d", net->name, urb->status);
+		goto goon;
 	}
 
-	if ( !count )
+	if (!count)
 		goto goon;
 
-	rx_status = le32_to_cpu(*(int *)(pegasus->rx_buff + count - 4));
-	if ( rx_status & 0x000e0000 ) {
+	rx_status = le32_to_cpu(*(int *) (pegasus->rx_buff + count - 4));
+	if (rx_status & 0x000e0000) {
 		dbg("%s: RX packet error %x", net->name, rx_status & 0xe0000);
 		pegasus->stats.rx_errors++;
-		if ( rx_status & 0x060000 )
+		if (rx_status & 0x060000)
 			pegasus->stats.rx_length_errors++;
-		if ( rx_status & 0x080000 )
+		if (rx_status & 0x080000)
 			pegasus->stats.rx_crc_errors++;
-		if ( rx_status & 0x100000 )
+		if (rx_status & 0x100000)
 			pegasus->stats.rx_frame_errors++;
 		goto goon;
 	}
 
 	pkt_len = (rx_status & 0xfff) - 8;
 
-	if ( !(skb = dev_alloc_skb(pkt_len+2)) )
+	if (!(skb = dev_alloc_skb(pkt_len + 2)))
 		goto goon;
 
 	skb->dev = net;
@@ -580,102 +547,100 @@
 	pegasus->stats.rx_bytes += pkt_len;
 
 goon:
-	FILL_BULK_URB( pegasus->rx_urb, pegasus->usb,
-			usb_rcvbulkpipe(pegasus->usb, 1),
-			pegasus->rx_buff, PEGASUS_MAX_MTU, 
-			read_bulk_callback, pegasus );
-	if ( (res = usb_submit_urb(pegasus->rx_urb)) )
+	FILL_BULK_URB(pegasus->rx_urb, pegasus->usb,
+		      usb_rcvbulkpipe(pegasus->usb, 1),
+		      pegasus->rx_buff, PEGASUS_MAX_MTU,
+		      read_bulk_callback, pegasus);
+	if ((res = usb_submit_urb(pegasus->rx_urb)))
 		warn("%s: failed submint rx_urb %d", __FUNCTION__, res);
 	pegasus->flags &= ~PEGASUS_RX_BUSY;
 }
 
-
-static void write_bulk_callback( struct urb *urb )
+static void write_bulk_callback(struct urb *urb)
 {
 	pegasus_t *pegasus = urb->context;
 
-	if ( !pegasus || !(pegasus->flags & PEGASUS_RUNNING) )
+	if (!pegasus || !(pegasus->flags & PEGASUS_RUNNING))
 		return;
 
-	if ( !netif_device_present(pegasus->net) )
+	if (!netif_device_present(pegasus->net))
 		return;
-		
-	if ( urb->status )
+
+	if (urb->status)
 		info("%s: TX status %d", pegasus->net->name, urb->status);
 
 	pegasus->net->trans_start = jiffies;
-	netif_wake_queue( pegasus->net );
+	netif_wake_queue(pegasus->net);
 }
 
 #ifdef	PEGASUS_USE_INTR
-static void intr_callback( struct urb *urb )
+static void intr_callback(struct urb *urb)
 {
 	pegasus_t *pegasus = urb->context;
 	struct net_device *net;
-	__u8	*d;
+	__u8 *d;
 
-	if ( !pegasus )
+	if (!pegasus)
 		return;
-		
-	switch ( urb->status ) {
-		case 0:
-			break;
-		case -ENOENT:
-			return;
-		default:
-			info("intr status %d", urb->status);
+
+	switch (urb->status) {
+	case 0:
+		break;
+	case -ENOENT:
+		return;
+	default:
+		info("intr status %d", urb->status);
 	}
 
 	d = urb->transfer_buffer;
 	net = pegasus->net;
-	if ( d[0] & 0xfc ) {
+	if (d[0] & 0xfc) {
 		pegasus->stats.tx_errors++;
-		if ( d[0] & TX_UNDERRUN )
+		if (d[0] & TX_UNDERRUN)
 			pegasus->stats.tx_fifo_errors++;
-		if ( d[0] & (EXCESSIVE_COL | JABBER_TIMEOUT) )
+		if (d[0] & (EXCESSIVE_COL | JABBER_TIMEOUT))
 			pegasus->stats.tx_aborted_errors++;
-		if ( d[0] & LATE_COL )
+		if (d[0] & LATE_COL)
 			pegasus->stats.tx_window_errors++;
-		if ( d[0] & (NO_CARRIER | LOSS_CARRIER) )
+		if (d[0] & (NO_CARRIER | LOSS_CARRIER))
 			pegasus->stats.tx_carrier_errors++;
 	}
 }
 #endif
 
-static void pegasus_tx_timeout( struct net_device *net )
+static void pegasus_tx_timeout(struct net_device *net)
 {
 	pegasus_t *pegasus = net->priv;
 
-	if ( !pegasus )
+	if (!pegasus)
 		return;
-		
+
 	warn("%s: Tx timed out.", net->name);
 	pegasus->tx_urb->transfer_flags |= USB_ASYNC_UNLINK;
-	usb_unlink_urb( pegasus->tx_urb );
+	usb_unlink_urb(pegasus->tx_urb);
 	pegasus->stats.tx_errors++;
 }
 
-
-static int pegasus_start_xmit( struct sk_buff *skb, struct net_device *net )
+static int pegasus_start_xmit(struct sk_buff *skb, struct net_device *net)
 {
-	pegasus_t	*pegasus = net->priv;
-	int 	count = ((skb->len+2) & 0x3f) ? skb->len+2 : skb->len+3;
-	int 	res;
+	pegasus_t *pegasus = net->priv;
+	int count = ((skb->len + 2) & 0x3f) ? skb->len + 2 : skb->len + 3;
+	int res;
 	__u16 l16 = skb->len;
-	
-	netif_stop_queue( net );
-		
-	((__u16 *)pegasus->tx_buff)[0] = cpu_to_le16( l16 );
-	memcpy(pegasus->tx_buff+2, skb->data, skb->len);
-	FILL_BULK_URB( pegasus->tx_urb, pegasus->usb,
-			usb_sndbulkpipe(pegasus->usb, 2),
-			pegasus->tx_buff, PEGASUS_MAX_MTU, 
-			write_bulk_callback, pegasus );
+
+	netif_stop_queue(net);
+
+	((__u16 *) pegasus->tx_buff)[0] = cpu_to_le16(l16);
+	memcpy(pegasus->tx_buff + 2, skb->data, skb->len);
+	FILL_BULK_URB(pegasus->tx_urb, pegasus->usb,
+		      usb_sndbulkpipe(pegasus->usb, 2),
+		      pegasus->tx_buff, PEGASUS_MAX_MTU,
+		      write_bulk_callback, pegasus);
 	pegasus->tx_urb->transfer_buffer_length = count;
 	if ((res = usb_submit_urb(pegasus->tx_urb))) {
 		warn("failed tx_urb %d", res);
 		pegasus->stats.tx_errors++;
-		netif_start_queue( net );
+		netif_start_queue(net);
 	} else {
 		pegasus->stats.tx_packets++;
 		pegasus->stats.tx_bytes += skb->len;
@@ -687,42 +652,38 @@
 	return 0;
 }
 
-
-static struct net_device_stats *pegasus_netdev_stats( struct net_device *dev )
+static struct net_device_stats *pegasus_netdev_stats(struct net_device *dev)
 {
-	return &((pegasus_t *)dev->priv)->stats;
+	return &((pegasus_t *) dev->priv)->stats;
 }
 
-
-static inline void disable_net_traffic( pegasus_t *pegasus )
+static inline void disable_net_traffic(pegasus_t * pegasus)
 {
-	int 	tmp=0;
+	int tmp = 0;
 
-	set_registers( pegasus, EthCtrl0, 2, &tmp );
+	set_registers(pegasus, EthCtrl0, 2, &tmp);
 }
 
-
-static inline void get_interrupt_interval( pegasus_t *pegasus )
+static inline void get_interrupt_interval(pegasus_t * pegasus)
 {
-	__u8	data[2];
+	__u8 data[2];
 
-	read_eprom_word( pegasus, 4, (__u16 *)data );
-	if ( data[1] < 0x80 ) {
-		info( "intr interval will be changed from %ums to %ums",
-		     data[1], 0x80 );
+	read_eprom_word(pegasus, 4, (__u16 *) data);
+	if (data[1] < 0x80) {
+		info("intr interval will be changed from %ums to %ums",
+		     data[1], 0x80);
 		data[1] = 0x80;
 #ifdef	PEGASUS_WRITE_EEPROM
-		write_eprom_word( pegasus, 4, *(__u16 *)data );
+		write_eprom_word(pegasus, 4, *(__u16 *) data);
 #endif
 	}
 	pegasus->intr_interval = data[1];
 }
 
-
 static void set_carrier(struct net_device *net)
 {
-	pegasus_t	*pegasus;
-	short		tmp;
+	pegasus_t *pegasus;
+	short tmp;
 
 	pegasus = net->priv;
 	read_mii_word(pegasus, pegasus->phy, MII_BMSR, &tmp);
@@ -730,34 +691,32 @@
 		netif_carrier_on(net);
 	else
 		netif_carrier_off(net);
-	
-}
 
+}
 
 static int pegasus_open(struct net_device *net)
 {
-	pegasus_t *pegasus = (pegasus_t *)net->priv;
-	int	res;
-
+	pegasus_t *pegasus = (pegasus_t *) net->priv;
+	int res;
 
 	down(&pegasus->sem);
-	FILL_BULK_URB( pegasus->rx_urb, pegasus->usb,
-			usb_rcvbulkpipe(pegasus->usb, 1),
-			pegasus->rx_buff, PEGASUS_MAX_MTU, 
-			read_bulk_callback, pegasus );
-	if ( (res = usb_submit_urb(pegasus->rx_urb)) )
+	FILL_BULK_URB(pegasus->rx_urb, pegasus->usb,
+		      usb_rcvbulkpipe(pegasus->usb, 1),
+		      pegasus->rx_buff, PEGASUS_MAX_MTU,
+		      read_bulk_callback, pegasus);
+	if ((res = usb_submit_urb(pegasus->rx_urb)))
 		warn("%s: failed rx_urb %d", __FUNCTION__, res);
 #ifdef	PEGASUS_USE_INTR
-	FILL_INT_URB( pegasus->intr_urb, pegasus->usb,
-			usb_rcvintpipe(pegasus->usb, 3),
-			pegasus->intr_buff, sizeof(pegasus->intr_buff),
-			intr_callback, pegasus, pegasus->intr_interval );
-	if ( (res = usb_submit_urb(pegasus->intr_urb)) )
+	FILL_INT_URB(pegasus->intr_urb, pegasus->usb,
+		     usb_rcvintpipe(pegasus->usb, 3),
+		     pegasus->intr_buff, sizeof(pegasus->intr_buff),
+		     intr_callback, pegasus, pegasus->intr_interval);
+	if ((res = usb_submit_urb(pegasus->intr_urb)))
 		warn("%s: failed intr_urb %d", __FUNCTION__, res);
 #endif
-	netif_start_queue( net );
+	netif_start_queue(net);
 	pegasus->flags |= PEGASUS_RUNNING;
-	if ( (res = enable_net_traffic(net, pegasus->usb)) ) {
+	if ((res = enable_net_traffic(net, pegasus->usb))) {
 		err("can't enable_net_traffic() - %d", res);
 		res = -EIO;
 		goto exit;
@@ -767,129 +726,126 @@
 	res = 0;
 exit:
 	up(&pegasus->sem);
-	
+
 	return res;
 }
 
-
-static int pegasus_close( struct net_device *net )
+static int pegasus_close(struct net_device *net)
 {
-	pegasus_t	*pegasus = net->priv;
+	pegasus_t *pegasus = net->priv;
 
 	down(&pegasus->sem);
 	pegasus->flags &= ~PEGASUS_RUNNING;
-	netif_stop_queue( net );
-	if ( !(pegasus->flags & PEGASUS_UNPLUG) )
-		disable_net_traffic( pegasus );
-
-	usb_unlink_urb( pegasus->rx_urb );
-	usb_unlink_urb( pegasus->tx_urb );
-	usb_unlink_urb( pegasus->ctrl_urb );
+	netif_stop_queue(net);
+	if (!(pegasus->flags & PEGASUS_UNPLUG))
+		disable_net_traffic(pegasus);
+
+	usb_unlink_urb(pegasus->rx_urb);
+	usb_unlink_urb(pegasus->tx_urb);
+	usb_unlink_urb(pegasus->ctrl_urb);
 #ifdef	PEGASUS_USE_INTR
-	usb_unlink_urb( pegasus->intr_urb );
+	usb_unlink_urb(pegasus->intr_urb);
 #endif
 	up(&pegasus->sem);
-	
+
 	return 0;
 }
 
-
 static int pegasus_ethtool_ioctl(struct net_device *net, void *uaddr)
 {
-	pegasus_t	*pegasus;
-	int		cmd;
-	char		tmp[128];
+	pegasus_t *pegasus;
+	int cmd;
+	char tmp[128];
 
 	pegasus = net->priv;
-	if (get_user(cmd, (int *)uaddr))
+	if (get_user(cmd, (int *) uaddr))
 		return -EFAULT;
 	switch (cmd) {
-	case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
-		strncpy(info.driver, DRIVER_DESC, ETHTOOL_BUSINFO_LEN);
-		strncpy(info.version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);
-		sprintf(tmp, "usb%d:%d", pegasus->usb->bus->busnum,
-		        pegasus->usb->devnum);
-		strncpy(info.bus_info, tmp, ETHTOOL_BUSINFO_LEN);
-		if (copy_to_user(uaddr, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-	case ETHTOOL_GSET: {
-		struct ethtool_cmd ecmd;
-		short	lpa, bmcr;
-
-		if (copy_from_user(&ecmd, uaddr, sizeof(ecmd)))
-			return -EFAULT;
-		ecmd.supported = (SUPPORTED_10baseT_Half |
-		                 SUPPORTED_10baseT_Full |
-		                 SUPPORTED_100baseT_Half |
-		                 SUPPORTED_100baseT_Full |
-		                 SUPPORTED_Autoneg |
-		                 SUPPORTED_TP |
-		                 SUPPORTED_MII);
-		ecmd.port = PORT_TP;
-		ecmd.transceiver = XCVR_INTERNAL;
-		ecmd.phy_address = pegasus->phy;
-		read_mii_word(pegasus, pegasus->phy, MII_BMCR, &bmcr);
-		read_mii_word(pegasus, pegasus->phy, MII_LPA, &lpa);
-		if (bmcr & BMCR_ANENABLE) {
-			ecmd.autoneg = AUTONEG_ENABLE;
-			ecmd.speed = lpa & (LPA_100HALF|LPA_100FULL) ?
-		                     SPEED_100 : SPEED_10;
-			if (ecmd.speed == SPEED_100)
-				ecmd.duplex = lpa & LPA_100FULL ?
-				              DUPLEX_FULL : DUPLEX_HALF;
-			else
-				ecmd.duplex = lpa & LPA_10FULL ?
-				              DUPLEX_FULL : DUPLEX_HALF;
-		} else {
-			ecmd.autoneg = AUTONEG_DISABLE;
-			ecmd.speed = bmcr & BMCR_SPEED100 ? 
-			             SPEED_100 : SPEED_10;
-			ecmd.duplex = bmcr & BMCR_FULLDPLX ?
-			              DUPLEX_FULL : DUPLEX_HALF;
+	case ETHTOOL_GDRVINFO:{
+			struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+			strncpy(info.driver, DRIVER_DESC, ETHTOOL_BUSINFO_LEN);
+			strncpy(info.version, DRIVER_VERSION,
+				ETHTOOL_BUSINFO_LEN);
+			sprintf(tmp, "usb%d:%d", pegasus->usb->bus->busnum,
+				pegasus->usb->devnum);
+			strncpy(info.bus_info, tmp, ETHTOOL_BUSINFO_LEN);
+			if (copy_to_user(uaddr, &info, sizeof(info)))
+				return -EFAULT;
+			return 0;
+		}
+	case ETHTOOL_GSET:{
+			struct ethtool_cmd ecmd;
+			short lpa, bmcr;
+
+			if (copy_from_user(&ecmd, uaddr, sizeof(ecmd)))
+				return -EFAULT;
+			ecmd.supported = (SUPPORTED_10baseT_Half |
+					  SUPPORTED_10baseT_Full |
+					  SUPPORTED_100baseT_Half |
+					  SUPPORTED_100baseT_Full |
+					  SUPPORTED_Autoneg |
+					  SUPPORTED_TP | SUPPORTED_MII);
+			ecmd.port = PORT_TP;
+			ecmd.transceiver = XCVR_INTERNAL;
+			ecmd.phy_address = pegasus->phy;
+			read_mii_word(pegasus, pegasus->phy, MII_BMCR, &bmcr);
+			read_mii_word(pegasus, pegasus->phy, MII_LPA, &lpa);
+			if (bmcr & BMCR_ANENABLE) {
+				ecmd.autoneg = AUTONEG_ENABLE;
+				ecmd.speed = lpa & (LPA_100HALF | LPA_100FULL) ?
+				    SPEED_100 : SPEED_10;
+				if (ecmd.speed == SPEED_100)
+					ecmd.duplex = lpa & LPA_100FULL ?
+					    DUPLEX_FULL : DUPLEX_HALF;
+				else
+					ecmd.duplex = lpa & LPA_10FULL ?
+					    DUPLEX_FULL : DUPLEX_HALF;
+			} else {
+				ecmd.autoneg = AUTONEG_DISABLE;
+				ecmd.speed = bmcr & BMCR_SPEED100 ?
+				    SPEED_100 : SPEED_10;
+				ecmd.duplex = bmcr & BMCR_FULLDPLX ?
+				    DUPLEX_FULL : DUPLEX_HALF;
+			}
+			if (copy_to_user(uaddr, &ecmd, sizeof(ecmd)))
+				return -EFAULT;
+
+			return 0;
+		}
+	case ETHTOOL_SSET:{
+			return -EOPNOTSUPP;
+		}
+	case ETHTOOL_GLINK:{
+			struct ethtool_value edata = { ETHTOOL_GLINK };
+			edata.data = netif_carrier_ok(net);
+			if (copy_to_user(uaddr, &edata, sizeof(edata)))
+				return -EFAULT;
+			return 0;
 		}
-		if (copy_to_user(uaddr, &ecmd, sizeof(ecmd)))
-			return -EFAULT;
-		
-		return 0;
-	}
-	case ETHTOOL_SSET: {
-		return -EOPNOTSUPP;
-	}
-	case ETHTOOL_GLINK: {
-		struct ethtool_value edata = {ETHTOOL_GLINK};
-		edata.data = netif_carrier_ok(net);
-		if (copy_to_user(uaddr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
 	default:
 		return -EOPNOTSUPP;
 	}
 }
 
-
-static int pegasus_ioctl( struct net_device *net, struct ifreq *rq, int cmd )
+static int pegasus_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
 {
-	__u16 *data = (__u16 *)&rq->ifr_data;
-	pegasus_t	*pegasus = net->priv;
-	int	res;
+	__u16 *data = (__u16 *) & rq->ifr_data;
+	pegasus_t *pegasus = net->priv;
+	int res;
 
 	down(&pegasus->sem);
-	switch(cmd) {
+	switch (cmd) {
 	case SIOCETHTOOL:
 		res = pegasus_ethtool_ioctl(net, rq->ifr_data);
 		break;
 	case SIOCDEVPRIVATE:
 		data[0] = pegasus->phy;
-	case SIOCDEVPRIVATE+1:
-		read_mii_word(pegasus, data[0], data[1]&0x1f, &data[3]);
+	case SIOCDEVPRIVATE + 1:
+		read_mii_word(pegasus, data[0], data[1] & 0x1f, &data[3]);
 		res = 0;
 		break;
-	case SIOCDEVPRIVATE+2:
-		if ( !capable(CAP_NET_ADMIN) ) {
+	case SIOCDEVPRIVATE + 2:
+		if (!capable(CAP_NET_ADMIN)) {
 			up(&pegasus->sem);
 			return -EPERM;
 		}
@@ -904,8 +860,7 @@
 	return res;
 }
 
-
-static void pegasus_set_multicast( struct net_device *net )
+static void pegasus_set_multicast(struct net_device *net)
 {
 	pegasus_t *pegasus = net->priv;
 
@@ -915,7 +870,7 @@
 		pegasus->eth_regs[EthCtrl2] |= RX_PROMISCUOUS;
 		info("%s: Promiscuous mode enabled", net->name);
 	} else if ((net->mc_count > multicast_filter_limit) ||
-			(net->flags & IFF_ALLMULTI)) {
+		   (net->flags & IFF_ALLMULTI)) {
 		pegasus->eth_regs[EthCtrl0] |= RX_MULTICAST;
 		pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS;
 		info("%s set allmulti", net->name);
@@ -925,100 +880,92 @@
 	}
 
 	pegasus->flags |= ETH_REGS_CHANGE;
-	ctrl_callback( pegasus->ctrl_urb );
+	ctrl_callback(pegasus->ctrl_urb);
 
 	netif_wake_queue(net);
 }
 
-
-static __u8 mii_phy_probe( pegasus_t *pegasus )
+static __u8 mii_phy_probe(pegasus_t * pegasus)
 {
-	int	i;
-	__u16	tmp;
+	int i;
+	__u16 tmp;
 
-	for ( i=0; i < 32; i++ ) {
-		read_mii_word( pegasus, i, MII_BMSR, &tmp );
-		if ( tmp == 0 || tmp == 0xffff || (tmp & BMSR_MEDIA) == 0 )
+	for (i = 0; i < 32; i++) {
+		read_mii_word(pegasus, i, MII_BMSR, &tmp);
+		if (tmp == 0 || tmp == 0xffff || (tmp & BMSR_MEDIA) == 0)
 			continue;
 		else
-			return	i;
+			return i;
 	}
 
-	return	0xff;
+	return 0xff;
 }
 
-
-static inline void setup_pegasus_II( pegasus_t *pegasus )
+static inline void setup_pegasus_II(pegasus_t * pegasus)
 {
-	set_register( pegasus, Reg1d, 0 );
-	set_register( pegasus, Reg7b, 2 );
-	if ( pegasus->features & HAS_HOME_PNA  && mii_mode )
-		set_register( pegasus, Reg81, 6 );
+	set_register(pegasus, Reg1d, 0);
+	set_register(pegasus, Reg7b, 2);
+	if (pegasus->features & HAS_HOME_PNA && mii_mode)
+		set_register(pegasus, Reg81, 6);
 	else
-		set_register( pegasus, Reg81, 2 );
+		set_register(pegasus, Reg81, 2);
 }
 
-
-static void * pegasus_probe( struct usb_device *dev, unsigned int ifnum,
-			     const struct usb_device_id *id)
+static void *pegasus_probe(struct usb_device *dev, unsigned int ifnum,
+			   const struct usb_device_id *id)
 {
-	struct net_device	*net;
-	pegasus_t		*pegasus;
-	int			dev_index = id - pegasus_ids;
+	struct net_device *net;
+	pegasus_t *pegasus;
+	int dev_index = id - pegasus_ids;
 
 	if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) {
 		err("usb_set_configuration() failed");
 		return NULL;
 	}
 
-	down(&gsem);
-	if(!(pegasus = kmalloc(sizeof(struct pegasus), GFP_KERNEL))) {
+	if (!(pegasus = kmalloc(sizeof(struct pegasus), GFP_KERNEL))) {
 		err("out of memory allocating device structure");
-		goto exit;
+		return NULL;
 	}
 
-	usb_inc_dev_use( dev );
+	usb_inc_dev_use(dev);
 	memset(pegasus, 0, sizeof(struct pegasus));
 	pegasus->dev_index = dev_index;
-	init_waitqueue_head( &pegasus->ctrl_wait );
+	init_waitqueue_head(&pegasus->ctrl_wait);
 
 	pegasus->ctrl_urb = usb_alloc_urb(0);
 	if (!pegasus->ctrl_urb) {
-		kfree (pegasus);
-		pegasus = NULL;
-		goto exit;
+		kfree(pegasus);
+		return NULL;
 	}
 	pegasus->rx_urb = usb_alloc_urb(0);
 	if (!pegasus->rx_urb) {
-		usb_free_urb (pegasus->ctrl_urb);
-		kfree (pegasus);
-		pegasus = NULL;
-		goto exit;
+		usb_free_urb(pegasus->ctrl_urb);
+		kfree(pegasus);
+		return NULL;
 	}
 	pegasus->tx_urb = usb_alloc_urb(0);
 	if (!pegasus->tx_urb) {
-		usb_free_urb (pegasus->rx_urb);
-		usb_free_urb (pegasus->ctrl_urb);
-		kfree (pegasus);
-		pegasus = NULL;
-		goto exit;
+		usb_free_urb(pegasus->rx_urb);
+		usb_free_urb(pegasus->ctrl_urb);
+		kfree(pegasus);
+		return NULL;
 	}
 	pegasus->intr_urb = usb_alloc_urb(0);
 	if (!pegasus->intr_urb) {
-		usb_free_urb (pegasus->tx_urb);
-		usb_free_urb (pegasus->rx_urb);
-		usb_free_urb (pegasus->ctrl_urb);
-		kfree (pegasus);
-		pegasus = NULL;
-		goto exit;
+		usb_free_urb(pegasus->tx_urb);
+		usb_free_urb(pegasus->rx_urb);
+		usb_free_urb(pegasus->ctrl_urb);
+		kfree(pegasus);
+		return NULL;
 	}
 
-	net = init_etherdev( NULL, 0 );
-	if ( !net ) {
-		usb_free_urb (pegasus->tx_urb);
-		usb_free_urb (pegasus->rx_urb);
-		usb_free_urb (pegasus->ctrl_urb);
-		kfree( pegasus );
+	net = init_etherdev(NULL, 0);
+	if (!net) {
+		usb_free_urb(pegasus->tx_urb);
+		usb_free_urb(pegasus->rx_urb);
+		usb_free_urb(pegasus->ctrl_urb);
+		kfree(pegasus);
 		return NULL;
 	}
 
@@ -1040,32 +987,32 @@
 
 	pegasus->features = usb_dev_id[dev_index].private;
 #ifdef	PEGASUS_USE_INTR
-	get_interrupt_interval( pegasus );
+	get_interrupt_interval(pegasus);
 #endif
-	if ( reset_mac(pegasus) ) {
+	if (reset_mac(pegasus)) {
 		err("can't reset MAC");
-		unregister_netdev( pegasus->net );
-		usb_free_urb (pegasus->tx_urb);
-		usb_free_urb (pegasus->rx_urb);
-		usb_free_urb (pegasus->ctrl_urb);
+		unregister_netdev(pegasus->net);
+		usb_free_urb(pegasus->tx_urb);
+		usb_free_urb(pegasus->rx_urb);
+		usb_free_urb(pegasus->ctrl_urb);
 		kfree(pegasus->net);
 		kfree(pegasus);
 		pegasus = NULL;
 		goto exit;
 	}
 
-	info( "%s: %s", net->name, usb_dev_id[dev_index].name );
+	info("%s: %s", net->name, usb_dev_id[dev_index].name);
 
-	set_ethernet_addr( pegasus );
+	set_ethernet_addr(pegasus);
 
-	if ( pegasus->features & PEGASUS_II ) {
-		info( "setup Pegasus II specific registers" );
-		setup_pegasus_II( pegasus );
-	}
-	
-	pegasus->phy = mii_phy_probe( pegasus );
-	if ( pegasus->phy == 0xff ) {
-		warn( "can't locate MII phy, using default" );
+	if (pegasus->features & PEGASUS_II) {
+		info("setup Pegasus II specific registers");
+		setup_pegasus_II(pegasus);
+	}
+
+	pegasus->phy = mii_phy_probe(pegasus);
+	if (pegasus->phy == 0xff) {
+		warn("can't locate MII phy, using default");
 		pegasus->phy = 1;
 	}
 
@@ -1074,19 +1021,18 @@
 	return pegasus;
 }
 
-
-static void pegasus_disconnect( struct usb_device *dev, void *ptr )
+static void pegasus_disconnect(struct usb_device *dev, void *ptr)
 {
 	struct pegasus *pegasus = ptr;
 
-	if ( !pegasus ) {
+	if (!pegasus) {
 		warn("unregistering non-existant device");
 		return;
 	}
 
 	pegasus->flags |= PEGASUS_UNPLUG;
-	unregister_netdev( pegasus->net );
-	usb_dec_dev_use( dev );
+	unregister_netdev(pegasus->net);
+	usb_dec_dev_use(dev);
 	usb_unlink_urb(pegasus->intr_urb);
 	usb_unlink_urb(pegasus->tx_urb);
 	usb_unlink_urb(pegasus->rx_urb);
@@ -1095,12 +1041,11 @@
 	usb_free_urb(pegasus->tx_urb);
 	usb_free_urb(pegasus->rx_urb);
 	usb_free_urb(pegasus->ctrl_urb);
-	kfree( pegasus->net );
-	kfree( pegasus );
+	kfree(pegasus->net);
+	kfree(pegasus);
 	pegasus = NULL;
 }
 
-
 static struct usb_driver pegasus_driver = {
 	name:		"pegasus",
 	probe:		pegasus_probe,
@@ -1111,13 +1056,13 @@
 int __init pegasus_init(void)
 {
 	info(DRIVER_VERSION ":" DRIVER_DESC);
-	return usb_register( &pegasus_driver );
+	return usb_register(&pegasus_driver);
 }
 
 void __exit pegasus_exit(void)
 {
-	usb_deregister( &pegasus_driver );
+	usb_deregister(&pegasus_driver);
 }
 
-module_init( pegasus_init );
-module_exit( pegasus_exit );
+module_init(pegasus_init);
+module_exit(pegasus_exit);
diff -urN linux-2.4.20-pre4/drivers/usb/pegasus.h linux-2.4.20-pre5/drivers/usb/pegasus.h
--- linux-2.4.20-pre4/drivers/usb/pegasus.h	Wed Aug 28 16:37:00 2002
+++ linux-2.4.20-pre5/drivers/usb/pegasus.h	Wed Aug 28 16:38:21 2002
@@ -122,6 +122,7 @@
 #define	VENDOR_ABOCOM		0x07b8
 #define	VENDOR_ACCTON		0x083a
 #define	VENDOR_ADMTEK		0x07a6
+#define	VENDOR_AEILAB		0x3334
 #define	VENDOR_ALLIEDTEL	0x07c9
 #define	VENDOR_BELKIN		0x050d
 #define	VENDOR_BILLIONTON	0x08dd
@@ -177,6 +178,8 @@
 		DEFAULT_GPIO_RESET | HAS_HOME_PNA )
 PEGASUS_DEV( "ADMtek AN986A USB MAC", VENDOR_ADMTEK, 0x1986,
 		DEFAULT_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "AEI USB Fast Ethernet Adapter", VENDOR_AEILAB, 0x1701,
+		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "Allied Telesyn Int. AT-USB100", VENDOR_ALLIEDTEL, 0xb100,
 		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "Belkin F5D5050 USB Ethernet", VENDOR_BELKIN, 0x0121,
diff -urN linux-2.4.20-pre4/drivers/usb/printer.c linux-2.4.20-pre5/drivers/usb/printer.c
--- linux-2.4.20-pre4/drivers/usb/printer.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/drivers/usb/printer.c	Wed Aug 28 16:38:21 2002
@@ -388,7 +388,8 @@
 {
 	struct usblp *usblp = file->private_data;
 	int length, err, i;
-	unsigned char status, newChannel;
+	unsigned char lpstatus, newChannel;
+	int status;
 	int twoints[2];
 	int retval = 0;
 
@@ -539,12 +540,13 @@
 		switch (cmd) {
 
 			case LPGETSTATUS:
-				if (usblp_read_status(usblp, &status)) {
+				if (usblp_read_status(usblp, &lpstatus)) {
 					err("usblp%d: failed reading printer status", usblp->minor);
 					retval = -EIO;
 					goto done;
 				}
-				if (copy_to_user ((unsigned char *)arg, &status, 1))
+				status = lpstatus;
+				if (copy_to_user ((int *)arg, &status, sizeof(int)))
 					retval = -EFAULT;
 				break;
 
@@ -616,10 +618,9 @@
 							 (count - writecount) : USBLP_BUF_SIZE;
 
 		if (copy_from_user(usblp->writeurb.transfer_buffer, buffer + writecount,
-				usblp->writeurb.transfer_buffer_length))
-		{
+				usblp->writeurb.transfer_buffer_length)) {
 			up(&usblp->sem);
-			return writecount?writecount:-EFAULT;
+			return writecount ? writecount : -EFAULT;
 		}
 
 		usblp->writeurb.dev = usblp->dev;
diff -urN linux-2.4.20-pre4/drivers/usb/pwc-if.c linux-2.4.20-pre5/drivers/usb/pwc-if.c
--- linux-2.4.20-pre4/drivers/usb/pwc-if.c	Wed Aug 28 16:37:00 2002
+++ linux-2.4.20-pre5/drivers/usb/pwc-if.c	Wed Aug 28 16:38:21 2002
@@ -65,7 +65,7 @@
 /* Function prototypes and driver templates */
 
 /* hotplug device table support */
-static __devinitdata struct usb_device_id pwc_device_table [] = {
+static struct usb_device_id pwc_device_table [] = {
 	{ USB_DEVICE(0x0471, 0x0302) }, /* Philips models */
 	{ USB_DEVICE(0x0471, 0x0303) },
 	{ USB_DEVICE(0x0471, 0x0304) },
diff -urN linux-2.4.20-pre4/drivers/usb/rtl8150.c linux-2.4.20-pre5/drivers/usb/rtl8150.c
--- linux-2.4.20-pre4/drivers/usb/rtl8150.c	Wed Aug 28 16:37:00 2002
+++ linux-2.4.20-pre5/drivers/usb/rtl8150.c	Wed Aug 28 16:38:21 2002
@@ -1,11 +1,9 @@
 /*
- * Copyright (c) 2002 Petko Manolov (petkan@users.sourceforge.net)
- *
- *	This program is free software; you can redistribute it and/or
- *	modify it under the terms of the GNU General Public License as
- *	published by the Free Software Foundation; either version 2 of
- *	the License, or (at your option) any later version.
+ *  Copyright (c) 2002 Petko Manolov (petkan@users.sourceforge.net)
  *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * version 2 as published by the Free Software Foundation.
  */
 
 #include <linux/config.h>
@@ -19,17 +17,13 @@
 #include <linux/ethtool.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/usb.h>
-#include <linux/init.h>
 #include <asm/uaccess.h>
 
-
-
 /* Version Information */
-#define DRIVER_VERSION "v0.4.0 (2002/03/28)"
+#define DRIVER_VERSION "v0.4.1 (2002/07/22)"
 #define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
 #define DRIVER_DESC "rtl8150 based usb-ethernet driver"
 
-
 #define	IRD			0x0120
 #define	MAR			0x0126
 #define	CR			0x012e
@@ -69,49 +63,48 @@
 #define	RX_REG_SET		1
 #define	RTL8150_UNPLUG		2
 
-
 /* Define these values to match your device */
 #define VENDOR_ID_REALTEK		0x0bda
+#define	VENDOR_ID_MELCO			0x0411
+
 #define PRODUCT_ID_RTL8150		0x8150
+#define	PRODUCT_ID_LUAKTX		0x0012
 
 /* table of devices that work with this driver */
-static struct usb_device_id rtl8150_table [] = {
-	{ USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8150) },
-	{ }				
+static struct usb_device_id rtl8150_table[] = {
+	{USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8150)},
+	{USB_DEVICE(VENDOR_ID_MELCO, PRODUCT_ID_LUAKTX)},
+	{}
 };
 
-MODULE_DEVICE_TABLE (usb, rtl8150_table);
-
+MODULE_DEVICE_TABLE(usb, rtl8150_table);
 
 struct rtl8150 {
-	unsigned long		flags;
-	struct usb_device	*udev;
-	struct usb_interface	*interface;
-	struct semaphore	sem;
-	struct net_device_stats	stats;
-	struct net_device	*netdev;
-	struct urb		*rx_urb, *tx_urb, *intr_urb, *ctrl_urb;
-	struct usb_ctrlrequest	dr;
-	int			intr_interval;
-	u16			rx_creg;
-	u8			rx_buff[RTL8150_MAX_MTU];
-	u8			tx_buff[RTL8150_MAX_MTU];
-	u8			intr_buff[8];
-	u8			phy;
+	unsigned int flags;
+	struct usb_device *udev;
+	struct usb_interface *interface;
+	struct semaphore sem;
+	struct net_device_stats stats;
+	struct net_device *netdev;
+	struct urb *rx_urb, *tx_urb, *intr_urb, *ctrl_urb;
+	struct usb_ctrlrequest dr;
+	int intr_interval;
+	u16 rx_creg;
+	u8 rx_buff[RTL8150_MAX_MTU];
+	u8 tx_buff[RTL8150_MAX_MTU];
+	u8 intr_buff[8];
+	u8 phy;
 };
 
-typedef	struct rtl8150	rtl8150_t;
-
+typedef struct rtl8150 rtl8150_t;
 
 /* the global usb devfs handle */
 extern devfs_handle_t usb_devfs_handle;
 unsigned long multicast_filter_limit = 32;
 
-
 static void rtl8150_disconnect(struct usb_device *dev, void *ptr);
-static void * rtl8150_probe(struct usb_device *dev, unsigned int ifnum,
-			    const struct usb_device_id *id);
-
+static void *rtl8150_probe(struct usb_device *dev, unsigned int ifnum,
+			   const struct usb_device_id *id);
 
 static struct usb_driver rtl8150_driver = {
 	name:		"rtl8150",
@@ -120,33 +113,29 @@
 	id_table:	rtl8150_table,
 };
 
-
-
 /*
 **
 **	device related part of the code
 **
 */
-static int get_registers(rtl8150_t *dev, u16 indx, u16 size, void *data)
+static int get_registers(rtl8150_t * dev, u16 indx, u16 size, void *data)
 {
-	return usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev,0),
-				RTL8150_REQ_GET_REGS, RTL8150_REQT_READ,
-				indx, 0, data, size, HZ/2);
+	return usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
+			       RTL8150_REQ_GET_REGS, RTL8150_REQT_READ,
+			       indx, 0, data, size, HZ / 2);
 }
 
-
-static int set_registers(rtl8150_t *dev, u16 indx, u16 size, void *data)
+static int set_registers(rtl8150_t * dev, u16 indx, u16 size, void *data)
 {
-	return usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev,0),
-				RTL8150_REQ_SET_REGS, RTL8150_REQT_WRITE,
-				indx, 0, data, size, HZ/2);
+	return usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
+			       RTL8150_REQ_SET_REGS, RTL8150_REQT_WRITE,
+			       indx, 0, data, size, HZ / 2);
 }
 
-
 static void ctrl_callback(struct urb *urb)
 {
-	rtl8150_t	*dev;
-	
+	rtl8150_t *dev;
+
 	switch (urb->status) {
 	case 0:
 		break;
@@ -161,22 +150,22 @@
 	clear_bit(RX_REG_SET, &dev->flags);
 }
 
-
-static int async_set_registers(rtl8150_t *dev, u16 indx, u16 size, void *data)
+static int async_set_registers(rtl8150_t * dev, u16 indx, u16 size, void *data)
 {
-	int	ret;
+	int ret;
 
 	if (test_bit(RX_REG_SET, &dev->flags))
 		return -EAGAIN;
-	
+
 	dev->dr.bRequestType = RTL8150_REQT_WRITE;
 	dev->dr.bRequest = RTL8150_REQ_SET_REGS;
 	dev->dr.wValue = cpu_to_le16(indx);
 	dev->dr.wIndex = 0;
 	dev->dr.wLength = cpu_to_le16(2);
 	dev->ctrl_urb->transfer_buffer_length = 2;
-	FILL_CONTROL_URB(dev->ctrl_urb, dev->udev, usb_sndctrlpipe(dev->udev,0),
-	                 (char*)&dev->dr, &dev->rx_creg, 2, ctrl_callback, dev);
+	FILL_CONTROL_URB(dev->ctrl_urb, dev->udev,
+			 usb_sndctrlpipe(dev->udev, 0), (char *) &dev->dr,
+			 &dev->rx_creg, 2, ctrl_callback, dev);
 	if ((ret = usb_submit_urb(dev->ctrl_urb)))
 		err("control request submission failed: %d", ret);
 	else
@@ -185,11 +174,10 @@
 	return ret;
 }
 
-
-static int read_mii_word(rtl8150_t *dev, u8 phy, __u8 indx, u16 *reg)
+static int read_mii_word(rtl8150_t * dev, u8 phy, __u8 indx, u16 * reg)
 {
-	int	i;
-	u8	data[3], tmp;
+	int i;
+	u8 data[3], tmp;
 
 	data[0] = phy;
 	data[1] = data[2] = 0;
@@ -204,17 +192,16 @@
 
 	if (i < HZ) {
 		get_registers(dev, PHYDAT, 2, data);
-		*reg = le16_to_cpup(data);
+		*reg = le16_to_cpup((u16 *)data);
 		return 0;
 	} else
 		return 1;
 }
 
-
-static int write_mii_word(rtl8150_t *dev, u8 phy, __u8 indx, u16 reg)
+static int write_mii_word(rtl8150_t * dev, u8 phy, __u8 indx, u16 reg)
 {
-	int	i;
-	u8	data[3], tmp;
+	int i;
+	u8 data[3], tmp;
 
 	data[0] = phy;
 	*(data + 1) = cpu_to_le16p(&reg);
@@ -225,7 +212,7 @@
 	set_registers(dev, PHYCNT, 1, &tmp);
 	do {
 		get_registers(dev, PHYCNT, 1, data);
-	} while((data[0] & PHY_GO) && (i++ < HZ));
+	} while ((data[0] & PHY_GO) && (i++ < HZ));
 
 	if (i < HZ)
 		return 0;
@@ -233,31 +220,28 @@
 		return 1;
 }
 
-
-static inline void set_ethernet_addr(rtl8150_t *dev)
+static inline void set_ethernet_addr(rtl8150_t * dev)
 {
-	u8	node_id[6];
+	u8 node_id[6];
 
 	get_registers(dev, IRD, sizeof(node_id), node_id);
 	memcpy(dev->netdev->dev_addr, node_id, sizeof(node_id));
 }
 
-
-static int rtl8150_reset(rtl8150_t *dev)
+static int rtl8150_reset(rtl8150_t * dev)
 {
-	u8	data=0x10;
-	int	i=HZ;
+	u8 data = 0x10;
+	int i = HZ;
 
 	set_registers(dev, CR, 1, &data);
 	do {
 		get_registers(dev, CR, 1, &data);
 	} while ((data & 0x10) && --i);
-	
+
 	return (i > 0) ? 0 : -1;
 }
 
-
-static int alloc_all_urbs(rtl8150_t *dev)
+static int alloc_all_urbs(rtl8150_t * dev)
 {
 	dev->rx_urb = usb_alloc_urb(0);
 	if (!dev->rx_urb)
@@ -284,8 +268,7 @@
 	return 1;
 }
 
-
-static void free_all_urbs(rtl8150_t *dev)
+static void free_all_urbs(rtl8150_t * dev)
 {
 	usb_free_urb(dev->rx_urb);
 	usb_free_urb(dev->tx_urb);
@@ -293,8 +276,7 @@
 	usb_free_urb(dev->ctrl_urb);
 }
 
-
-static void unlink_all_urbs(rtl8150_t *dev)
+static void unlink_all_urbs(rtl8150_t * dev)
 {
 	usb_unlink_urb(dev->rx_urb);
 	usb_unlink_urb(dev->tx_urb);
@@ -302,14 +284,13 @@
 	usb_unlink_urb(dev->ctrl_urb);
 }
 
-
 static void read_bulk_callback(struct urb *urb)
 {
-	rtl8150_t	*dev;
-	int		pkt_len, res;
-	struct sk_buff	*skb;
+	rtl8150_t *dev;
+	int pkt_len, res;
+	struct sk_buff *skb;
 	struct net_device *netdev;
-	u16		rx_stat;
+	u16 rx_stat;
 
 	dev = urb->context;
 	if (!dev) {
@@ -333,11 +314,11 @@
 		warn("Rx status %d", urb->status);
 		goto goon;
 	}
-	
+
 	pkt_len = urb->actual_length - 4;
-	rx_stat = le16_to_cpu(*(u16 *)(dev->rx_buff + pkt_len));
+	rx_stat = le16_to_cpu(*(u16 *) (dev->rx_buff + pkt_len));
 
-	if (!(skb = dev_alloc_skb(pkt_len + 2))) 
+	if (!(skb = dev_alloc_skb(pkt_len + 2)))
 		goto goon;
 	skb->dev = netdev;
 	skb_reserve(skb, 2);
@@ -348,16 +329,15 @@
 	dev->stats.rx_packets++;
 	dev->stats.rx_bytes += pkt_len;
 goon:
-	FILL_BULK_URB(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev,1),
-	              dev->rx_buff, RTL8150_MAX_MTU, read_bulk_callback, dev);
-	if ((res=usb_submit_urb(dev->rx_urb)))
+	FILL_BULK_URB(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
+		      dev->rx_buff, RTL8150_MAX_MTU, read_bulk_callback, dev);
+	if ((res = usb_submit_urb(dev->rx_urb)))
 		warn("%s: Rx urb submission failed %d", netdev->name, res);
 }
 
-
 static void write_bulk_callback(struct urb *urb)
 {
-	rtl8150_t	*dev;
+	rtl8150_t *dev;
 
 	dev = urb->context;
 	if (!dev)
@@ -370,36 +350,32 @@
 	netif_wake_queue(dev->netdev);
 }
 
-
 void intr_callback(struct urb *urb)
 {
-	rtl8150_t	*dev;
+	rtl8150_t *dev;
 
 	dev = urb->context;
 	if (!dev)
 		return;
 	switch (urb->status) {
-		case 0:
-			break;
-		case -ENOENT:
-			return;
-		default:
-			info("%s: intr status %d", dev->netdev->name,
-			     urb->status);
+	case 0:
+		break;
+	case -ENOENT:
+		return;
+	default:
+		info("%s: intr status %d", dev->netdev->name, urb->status);
 	}
 }
 
-
 /*
 **
 **	network related part of the code
 **
 */
 
-
-static int enable_net_traffic(rtl8150_t *dev)
+static int enable_net_traffic(rtl8150_t * dev)
 {
-	u8	cr, tcr, rcr, msr;
+	u8 cr, tcr, rcr, msr;
 
 	if (rtl8150_reset(dev)) {
 		warn("%s - device reset failed", __FUNCTION__);
@@ -415,26 +391,23 @@
 	return 0;
 }
 
-
-static void disable_net_traffic(rtl8150_t *dev)
+static void disable_net_traffic(rtl8150_t * dev)
 {
-	u8	cr;
+	u8 cr;
 
 	get_registers(dev, CR, 1, &cr);
 	cr &= 0xf3;
 	set_registers(dev, CR, 1, &cr);
 }
 
-
 static struct net_device_stats *rtl8150_netdev_stats(struct net_device *dev)
 {
-	return &((rtl8150_t *)dev->priv)->stats;
+	return &((rtl8150_t *) dev->priv)->stats;
 }
 
-
 static void rtl8150_tx_timeout(struct net_device *netdev)
 {
-	rtl8150_t	*dev;
+	rtl8150_t *dev;
 
 	dev = netdev->priv;
 	if (!dev)
@@ -445,10 +418,9 @@
 	dev->stats.tx_errors++;
 }
 
-
 static void rtl8150_set_multicast(struct net_device *netdev)
 {
-	rtl8150_t	*dev;
+	rtl8150_t *dev;
 
 	dev = netdev->priv;
 	netif_stop_queue(netdev);
@@ -456,7 +428,7 @@
 		dev->rx_creg |= 0x0001;
 		info("%s: promiscuous mode", netdev->name);
 	} else if ((netdev->mc_count > multicast_filter_limit) ||
-	           (netdev->flags & IFF_ALLMULTI)) {
+		   (netdev->flags & IFF_ALLMULTI)) {
 		dev->rx_creg &= 0xfffe;
 		dev->rx_creg |= 0x0002;
 		info("%s: allmulti set", netdev->name);
@@ -468,18 +440,17 @@
 	netif_wake_queue(netdev);
 }
 
-
 static int rtl8150_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 {
-	rtl8150_t	*dev;
-	int		count, res;
+	rtl8150_t *dev;
+	int count, res;
 
 	netif_stop_queue(netdev);
 	dev = netdev->priv;
 	count = (skb->len < 60) ? 60 : skb->len;
 	count = (count & 0x3f) ? count : count + 1;
 	memcpy(dev->tx_buff, skb->data, skb->len);
-	FILL_BULK_URB(dev->tx_urb, dev->udev, usb_sndbulkpipe(dev->udev,2),
+	FILL_BULK_URB(dev->tx_urb, dev->udev, usb_sndbulkpipe(dev->udev, 2),
 		      dev->tx_buff, RTL8150_MAX_MTU, write_bulk_callback, dev);
 	dev->tx_urb->transfer_buffer_length = count;
 
@@ -497,26 +468,25 @@
 	return 0;
 }
 
-
 static int rtl8150_open(struct net_device *netdev)
 {
-	rtl8150_t	*dev;
-	int		res;
-	
+	rtl8150_t *dev;
+	int res;
+
 	dev = netdev->priv;
 	if (dev == NULL) {
 		return -ENODEV;
 	}
 
 	down(&dev->sem);
-	FILL_BULK_URB(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev,1),
-			dev->rx_buff, RTL8150_MAX_MTU, read_bulk_callback, dev);
-	if ((res=usb_submit_urb(dev->rx_urb)))
+	FILL_BULK_URB(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
+		      dev->rx_buff, RTL8150_MAX_MTU, read_bulk_callback, dev);
+	if ((res = usb_submit_urb(dev->rx_urb)))
 		warn("%s: rx_urb submit failed: %d", __FUNCTION__, res);
-	FILL_INT_URB(dev->intr_urb, dev->udev, usb_rcvintpipe(dev->udev,3),
-			dev->intr_buff, sizeof(dev->intr_buff), intr_callback,
-			dev, dev->intr_interval);
-	if ((res=usb_submit_urb(dev->intr_urb)))
+	FILL_INT_URB(dev->intr_urb, dev->udev, usb_rcvintpipe(dev->udev, 3),
+		     dev->intr_buff, sizeof(dev->intr_buff), intr_callback,
+		     dev, dev->intr_interval);
+	if ((res = usb_submit_urb(dev->intr_urb)))
 		warn("%s: intr_urb submit failed: %d", __FUNCTION__, res);
 	netif_start_queue(netdev);
 	enable_net_traffic(dev);
@@ -525,7 +495,6 @@
 	return res;
 }
 
-
 static int rtl8150_close(struct net_device *netdev)
 {
 	rtl8150_t *dev;
@@ -545,93 +514,92 @@
 	return res;
 }
 
-
 static int rtl8150_ethtool_ioctl(struct net_device *netdev, void *uaddr)
 {
-	rtl8150_t	*dev;
-	int		cmd;
-	char		tmp[128];
+	rtl8150_t *dev;
+	int cmd;
+	char tmp[128];
 
 	dev = netdev->priv;
-	if (get_user(cmd, (int *)uaddr))
+	if (get_user(cmd, (int *) uaddr))
 		return -EFAULT;
 
 	switch (cmd) {
-	case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
-		
-		strncpy(info.driver, DRIVER_DESC, ETHTOOL_BUSINFO_LEN);
-		strncpy(info.version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);
-		sprintf(tmp, "usb%d:%d", dev->udev->bus->busnum,
-		        dev->udev->devnum);
-		strncpy(info.bus_info, tmp, ETHTOOL_BUSINFO_LEN);
-		if (copy_to_user(uaddr, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-	case ETHTOOL_GSET: {
-		struct ethtool_cmd ecmd;
-		short   lpa, bmcr;
-
-		if (copy_from_user(&ecmd, uaddr, sizeof(ecmd)))
-			return -EFAULT;
-		ecmd.supported = (SUPPORTED_10baseT_Half |
-		                  SUPPORTED_10baseT_Full |
-		                  SUPPORTED_100baseT_Half |
-		                  SUPPORTED_100baseT_Full |
-		                  SUPPORTED_Autoneg |
-		                  SUPPORTED_TP |
-		                  SUPPORTED_MII);
-		ecmd.port = PORT_TP;
-		ecmd.transceiver = XCVR_INTERNAL;
-		ecmd.phy_address = dev->phy;
-		get_registers(dev, BMCR, 2, &bmcr);
-		get_registers(dev, ANLP, 2, &lpa);
-		if (bmcr & BMCR_ANENABLE) {
-			ecmd.autoneg = AUTONEG_ENABLE;
-			ecmd.speed = (lpa & (LPA_100HALF | LPA_100FULL)) ?
-			             SPEED_100 : SPEED_10;
-			if (ecmd.speed == SPEED_100)
-				ecmd.duplex = (lpa & LPA_100FULL) ?
-				              DUPLEX_FULL : DUPLEX_HALF;
-			else
-				ecmd.duplex = (lpa & LPA_10FULL) ?
-				              DUPLEX_FULL : DUPLEX_HALF;
-		} else {
-			ecmd.autoneg = AUTONEG_DISABLE;
-			ecmd.speed = (bmcr & BMCR_SPEED100) ?
-			             SPEED_100 : SPEED_10;
-			ecmd.duplex = (bmcr & BMCR_FULLDPLX) ?
-			              DUPLEX_FULL : DUPLEX_HALF;
+	case ETHTOOL_GDRVINFO:{
+			struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+
+			strncpy(info.driver, DRIVER_DESC, ETHTOOL_BUSINFO_LEN);
+			strncpy(info.version, DRIVER_VERSION,
+				ETHTOOL_BUSINFO_LEN);
+			sprintf(tmp, "usb%d:%d", dev->udev->bus->busnum,
+				dev->udev->devnum);
+			strncpy(info.bus_info, tmp, ETHTOOL_BUSINFO_LEN);
+			if (copy_to_user(uaddr, &info, sizeof(info)))
+				return -EFAULT;
+			return 0;
+		}
+	case ETHTOOL_GSET:{
+			struct ethtool_cmd ecmd;
+			short lpa, bmcr;
+
+			if (copy_from_user(&ecmd, uaddr, sizeof(ecmd)))
+				return -EFAULT;
+			ecmd.supported = (SUPPORTED_10baseT_Half |
+					  SUPPORTED_10baseT_Full |
+					  SUPPORTED_100baseT_Half |
+					  SUPPORTED_100baseT_Full |
+					  SUPPORTED_Autoneg |
+					  SUPPORTED_TP | SUPPORTED_MII);
+			ecmd.port = PORT_TP;
+			ecmd.transceiver = XCVR_INTERNAL;
+			ecmd.phy_address = dev->phy;
+			get_registers(dev, BMCR, 2, &bmcr);
+			get_registers(dev, ANLP, 2, &lpa);
+			if (bmcr & BMCR_ANENABLE) {
+				ecmd.autoneg = AUTONEG_ENABLE;
+				ecmd.speed =
+				    (lpa & (LPA_100HALF | LPA_100FULL)) ?
+				    SPEED_100 : SPEED_10;
+				if (ecmd.speed == SPEED_100)
+					ecmd.duplex = (lpa & LPA_100FULL) ?
+					    DUPLEX_FULL : DUPLEX_HALF;
+				else
+					ecmd.duplex = (lpa & LPA_10FULL) ?
+					    DUPLEX_FULL : DUPLEX_HALF;
+			} else {
+				ecmd.autoneg = AUTONEG_DISABLE;
+				ecmd.speed = (bmcr & BMCR_SPEED100) ?
+				    SPEED_100 : SPEED_10;
+				ecmd.duplex = (bmcr & BMCR_FULLDPLX) ?
+				    DUPLEX_FULL : DUPLEX_HALF;
+			}
+			if (copy_to_user(uaddr, &ecmd, sizeof(ecmd)))
+				return -EFAULT;
+			return 0;
 		}
-		if (copy_to_user(uaddr, &ecmd, sizeof(ecmd)))
-			return -EFAULT;
-		return 0;
-	}
 	case ETHTOOL_SSET:
 		return -ENOTSUPP;
-	case ETHTOOL_GLINK: {
-		struct ethtool_value edata = {ETHTOOL_GLINK};
+	case ETHTOOL_GLINK:{
+			struct ethtool_value edata = { ETHTOOL_GLINK };
 
-		edata.data = netif_carrier_ok(netdev);
-		if (copy_to_user(uaddr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
+			edata.data = netif_carrier_ok(netdev);
+			if (copy_to_user(uaddr, &edata, sizeof(edata)))
+				return -EFAULT;
+			return 0;
+		}
 	default:
 		return -EOPNOTSUPP;
 	}
 }
 
-
-static int rtl8150_ioctl (struct net_device *netdev, struct ifreq *rq, int cmd)
+static int rtl8150_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
 {
 	rtl8150_t *dev;
-	u16	*data;
-	int	res;
+	u16 *data;
+	int res;
 
 	dev = netdev->priv;
-	data = (u16 *)&rq->ifr_data;
+	data = (u16 *) & rq->ifr_data;
 	res = 0;
 
 	down(&dev->sem);
@@ -641,10 +609,10 @@
 		break;
 	case SIOCDEVPRIVATE:
 		data[0] = dev->phy;
-	case SIOCDEVPRIVATE+1:
+	case SIOCDEVPRIVATE + 1:
 		read_mii_word(dev, dev->phy, (data[1] & 0x1f), &data[3]);
 		break;
-	case SIOCDEVPRIVATE+2:
+	case SIOCDEVPRIVATE + 2:
 		if (!capable(CAP_NET_ADMIN)) {
 			up(&dev->sem);
 			return -EPERM;
@@ -659,9 +627,8 @@
 	return res;
 }
 
-
-static void * rtl8150_probe(struct usb_device *udev, unsigned int ifnum,
-			    const struct usb_device_id *id)
+static void *rtl8150_probe(struct usb_device *udev, unsigned int ifnum,
+			   const struct usb_device_id *id)
 {
 	rtl8150_t *dev;
 	struct net_device *netdev;
@@ -671,14 +638,9 @@
 		err("usb_set_configuration() failed");
 		return NULL;
 	}
-	if ((udev->descriptor.idVendor != VENDOR_ID_REALTEK) ||
-	    (udev->descriptor.idProduct != PRODUCT_ID_RTL8150)) {
-	    	err("Not the one we are interested about");
-		return NULL;
-	}
 	dev = kmalloc(sizeof(rtl8150_t), GFP_KERNEL);
 	if (!dev) {
-		err ("Out of memory");
+		err("Out of memory");
 		goto exit;
 	} else
 		memset(dev, 0, sizeof(rtl8150_t));
@@ -690,7 +652,7 @@
 		dev = NULL;
 		goto exit;
 	}
-		
+
 	init_MUTEX(&dev->sem);
 	dev->udev = udev;
 	dev->netdev = netdev;
@@ -724,7 +686,6 @@
 	return dev;
 }
 
-
 static void rtl8150_disconnect(struct usb_device *udev, void *ptr)
 {
 	rtl8150_t *dev;
@@ -740,21 +701,17 @@
 	dev = NULL;
 }
 
-
-
 static int __init usb_rtl8150_init(void)
 {
 	info(DRIVER_DESC " " DRIVER_VERSION);
 	return usb_register(&rtl8150_driver);
 }
 
-
 static void __exit usb_rtl8150_exit(void)
 {
 	usb_deregister(&rtl8150_driver);
 }
 
-
 module_init(usb_rtl8150_init);
 module_exit(usb_rtl8150_exit);
 
diff -urN linux-2.4.20-pre4/drivers/usb/scanner.h linux-2.4.20-pre5/drivers/usb/scanner.h
--- linux-2.4.20-pre4/drivers/usb/scanner.h	Wed Aug 28 16:37:00 2002
+++ linux-2.4.20-pre5/drivers/usb/scanner.h	Wed Aug 28 16:38:21 2002
@@ -113,6 +113,7 @@
 	{ USB_DEVICE(0x03f0, 0x0105) },	/* 4200C */
 	{ USB_DEVICE(0x03f0, 0x0305) }, /* 4300C */
 	{ USB_DEVICE(0x03f0, 0x0102) },	/* PhotoSmart S20 */
+	{ USB_DEVICE(0x03f0, 0x0705) }, /* 4400C */
 	{ USB_DEVICE(0x03f0, 0x0401) },	/* 5200C */
 	//	{ USB_DEVICE(0x03f0, 0x0701) },	/* 5300C - NOT SUPPORTED - see http://www.neatech.nl/oss/HP5300C/ */
 	{ USB_DEVICE(0x03f0, 0x0201) },	/* 6200C */
@@ -184,8 +185,12 @@
 	{ USB_DEVICE(0x04b8, 0x010b) }, /* Perfection 1240U */
 	{ USB_DEVICE(0x04b8, 0x010c) }, /* Perfection 640U */
 	{ USB_DEVICE(0x04b8, 0x010e) }, /* Expression 1680 */
+	{ USB_DEVICE(0x04b8, 0x010f) }, /* Perfection 1250U */
 	{ USB_DEVICE(0x04b8, 0x0110) }, /* Perfection 1650 */
 	{ USB_DEVICE(0x04b8, 0x0112) }, /* Perfection 2450 - GT-9700 for the Japanese mkt */
+	{ USB_DEVICE(0x04b8, 0x0114) }, /* Perfection 660 */
+	{ USB_DEVICE(0x04b8, 0x011b) }, /* Perfection 2400 Photo */
+	{ USB_DEVICE(0x04b8, 0x011e) }, /* Perfection 1660 Photo */
 	/* Umax */
 	{ USB_DEVICE(0x1606, 0x0010) },	/* Astra 1220U */
 	{ USB_DEVICE(0x1606, 0x0030) },	/* Astra 2000U */
diff -urN linux-2.4.20-pre4/drivers/usb/se401.c linux-2.4.20-pre5/drivers/usb/se401.c
--- linux-2.4.20-pre4/drivers/usb/se401.c	Wed Aug 28 16:37:00 2002
+++ linux-2.4.20-pre5/drivers/usb/se401.c	Wed Aug 28 16:38:21 2002
@@ -41,18 +41,12 @@
 #include <asm/semaphore.h>
 #include <linux/wrapper.h>
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0)
-#define virt_to_page(arg)	MAP_NR(arg)
-#define vmalloc_32		vmalloc
-#endif
-
 #include "se401.h"
 
 static int flickerless=0;
 static int video_nr = -1;
 
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 3, 0)
-static __devinitdata struct usb_device_id device_table [] = {
+static struct usb_device_id device_table [] = {
 	{ USB_DEVICE(0x03e8, 0x0004) },/* Endpoints/Aox SE401 */
 	{ USB_DEVICE(0x0471, 0x030b) },/* Philips PCVC665K */
 	{ USB_DEVICE(0x047d, 0x5001) },/* Kensington 67014 */
@@ -62,7 +56,6 @@
 };
 
 MODULE_DEVICE_TABLE(usb, device_table);
-#endif
 
 MODULE_AUTHOR("Jeroen Vreeken <pe1rxq@amsat.org>");
 MODULE_DESCRIPTION("SE401 USB Camera Driver");
@@ -1448,12 +1441,8 @@
         return 0;
 }
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0)
-static void* se401_probe(struct usb_device *dev, unsigned int ifnum)
-#else
-static void* __devinit se401_probe(struct usb_device *dev, unsigned int ifnum,
+static void* se401_probe(struct usb_device *dev, unsigned int ifnum,
 	const struct usb_device_id *id)
-#endif
 {
         struct usb_interface_descriptor *interface;
         struct usb_se401 *se401;
@@ -1582,9 +1571,7 @@
 
 static struct usb_driver se401_driver = {
         name:		"se401",
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 3, 0)
         id_table:	device_table,
-#endif
 	probe:		se401_probe,
         disconnect:	se401_disconnect
 };
diff -urN linux-2.4.20-pre4/drivers/usb/se401.h linux-2.4.20-pre5/drivers/usb/se401.h
--- linux-2.4.20-pre4/drivers/usb/se401.h	Wed Aug 28 16:37:01 2002
+++ linux-2.4.20-pre5/drivers/usb/se401.h	Wed Aug 28 16:38:21 2002
@@ -10,7 +10,7 @@
 
 #ifdef se401_DEBUG
 #  define PDEBUG(level, fmt, args...) \
-if (debug >= level) info("[" __PRETTY_FUNCTION__ ":%d] " fmt, __LINE__ , ## args)
+if (debug >= level) info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ , ## args)
 #else
 #  define PDEBUG(level, fmt, args...) do {} while(0)
 #endif
diff -urN linux-2.4.20-pre4/drivers/usb/storage/unusual_devs.h linux-2.4.20-pre5/drivers/usb/storage/unusual_devs.h
--- linux-2.4.20-pre4/drivers/usb/storage/unusual_devs.h	Wed Aug 28 16:37:07 2002
+++ linux-2.4.20-pre5/drivers/usb/storage/unusual_devs.h	Wed Aug 28 16:38:23 2002
@@ -65,6 +65,17 @@
 		US_SC_8070, US_PR_SCM_ATAPI, init_8200e, 0), 
 #endif
 
+/* Deduced by Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
+ * Entry needed for flags: US_FL_FIX_INQUIRY because initial inquiry message
+ * always fails and confuses drive; without US_FL_START_STOP, drive accesses
+ * (read or write) all fail.
+ */
+UNUSUAL_DEV(  0x0411, 0x001c, 0x0113, 0x0113,
+		"Buffalo",
+		"DUB-P40G HDD",
+		US_SC_SCSI, US_PR_BULK, NULL,
+		US_FL_FIX_INQUIRY | US_FL_START_STOP),
+
 #ifdef CONFIG_USB_STORAGE_DPCM
 UNUSUAL_DEV(  0x0436, 0x0005, 0x0100, 0x0100,
 		"Microtech",
diff -urN linux-2.4.20-pre4/drivers/usb/stv680.c linux-2.4.20-pre5/drivers/usb/stv680.c
--- linux-2.4.20-pre4/drivers/usb/stv680.c	Wed Aug 28 16:37:07 2002
+++ linux-2.4.20-pre5/drivers/usb/stv680.c	Wed Aug 28 16:38:23 2002
@@ -1072,6 +1072,9 @@
 			errors++;
 		}
 		wait_event_interruptible (stv680->wq, (stv680->scratch[stv680->scratch_use].state == BUFFER_READY));
+		
+		if (stv680->removed)
+			return -ENODEV;
 
 		if (stv680->nullpackets > STV680_MAX_NULLPACKETS) {
 			stv680->nullpackets = 0;
@@ -1140,10 +1143,10 @@
 
 	for (i = 0; i < STV680_NUMFRAMES; i++)
 		stv680->frame[i].grabstate = FRAME_UNUSED;
-	if (stv680->streaming)
+	if (stv680->streaming && !stv680->removed)
 		stv680_stop_stream (stv680);
 
-	if ((i = stv_stop_video (stv680)) < 0)
+	if ((!stv680->removed) && (i = stv_stop_video (stv680)) < 0)
 		PDEBUG (1, "STV(e): stop_video failed in stv_close");
 
 	rvfree (stv680->fbuf, stv680->maxframesize * STV680_NUMFRAMES);
@@ -1169,6 +1172,9 @@
 
 	if (!stv680->udev)
 		return -EIO;
+		
+	if (stv680->removed)
+		return -ENODEV;
 
 	switch (cmd) {
 	case VIDIOCGCAP:{
@@ -1494,7 +1500,7 @@
 	initialize:	stv_init_done,
 };
 
-static void *__devinit stv680_probe (struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id)
+static void *stv680_probe (struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id)
 {
 	struct usb_interface_descriptor *interface;
 	struct usb_stv *stv680;
@@ -1578,6 +1584,7 @@
 static void stv680_disconnect (struct usb_device *dev, void *ptr)
 {
 	struct usb_stv *stv680 = (struct usb_stv *) ptr;
+	int i;
 
 	lock_kernel ();
 	/* We don't want people trying to open up the device */
@@ -1586,6 +1593,9 @@
 		usb_stv680_remove_disconnected (stv680);
 	} else {
 		stv680->removed = 1;
+		for( i = 0; i < STV680_NUMSBUF; i++)
+			usb_unlink_urb(stv680->urb[i]);
+		wake_up_interruptible (&stv680->wq);
 	}
 	unlock_kernel ();
 }
diff -urN linux-2.4.20-pre4/drivers/usb/stv680.h linux-2.4.20-pre5/drivers/usb/stv680.h
--- linux-2.4.20-pre4/drivers/usb/stv680.h	Wed Aug 28 16:37:07 2002
+++ linux-2.4.20-pre5/drivers/usb/stv680.h	Wed Aug 28 16:38:23 2002
@@ -45,7 +45,7 @@
 /* fmt 4 */
 #define STV_VIDEO_PALETTE       VIDEO_PALETTE_RGB24
 
-static __devinitdata struct usb_device_id device_table[] = {
+static struct usb_device_id device_table[] = {
 	{USB_DEVICE (USB_PENCAM_VENDOR_ID, USB_PENCAM_PRODUCT_ID)},
 	{}
 };
diff -urN linux-2.4.20-pre4/drivers/usb/uhci.c linux-2.4.20-pre5/drivers/usb/uhci.c
--- linux-2.4.20-pre4/drivers/usb/uhci.c	Wed Aug 28 16:37:08 2002
+++ linux-2.4.20-pre5/drivers/usb/uhci.c	Wed Aug 28 16:38:23 2002
@@ -100,6 +100,11 @@
 #define IDLE_TIMEOUT	(HZ / 20)	/* 50 ms */
 #define FSBR_DELAY	(HZ / 20)	/* 50 ms */
 
+/* When we timeout an idle transfer for FSBR, we'll switch it over to */
+/* depth first traversal. We'll do it in groups of this number of TD's */
+/* to make sure it doesn't hog all of the bandwidth */
+#define DEPTH_INTERVAL	5
+
 #define MAX_URB_LOOP	2048		/* Maximum number of linked URB's */
 
 /*
@@ -115,12 +120,20 @@
 	return 0;
 }
 
+/*
+ * Technically, updating td->status here is a race, but it's not really a
+ * problem. The worst that can happen is that we set the IOC bit again
+ * generating a spurios interrupt. We could fix this by creating another
+ * QH and leaving the IOC bit always set, but then we would have to play
+ * games with the FSBR code to make sure we get the correct order in all
+ * the cases. I don't think it's worth the effort
+ */
 static inline void uhci_set_next_interrupt(struct uhci *uhci)
 {
 	unsigned long flags;
 
 	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-	set_bit(TD_CTRL_IOC_BIT, &uhci->skel_term_td->status);
+	uhci->skel_term_td->status |= TD_CTRL_IOC;
 	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
 }
 
@@ -129,7 +142,7 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-	clear_bit(TD_CTRL_IOC_BIT, &uhci->skel_term_td->status);
+	uhci->skel_term_td->status &= ~TD_CTRL_IOC;
 	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
 }
 
@@ -474,9 +487,9 @@
 		tmp = tmp->next;
 
 		if (toggle)
-			set_bit(TD_TOKEN_TOGGLE, &td->info);
+			td->info |= TD_TOKEN_TOGGLE;
 		else
-			clear_bit(TD_TOKEN_TOGGLE, &td->info);
+			td->info &= ~TD_TOKEN_TOGGLE;
 
 		toggle ^= 1;
 	}
@@ -857,7 +870,7 @@
 			return -ENOMEM;
 
 		/* Alternate Data0/1 (start with Data1) */
-		destination ^= 1 << TD_TOKEN_TOGGLE;
+		destination ^= TD_TOKEN_TOGGLE;
 	
 		uhci_add_td_to_urb(urb, td);
 		uhci_fill_td(td, status, destination | ((pktsze - 1) << 21),
@@ -884,7 +897,7 @@
 	else
 		destination |= USB_PID_OUT;
 
-	destination |= 1 << TD_TOKEN_TOGGLE;		/* End in Data1 */
+	destination |= TD_TOKEN_TOGGLE;		/* End in Data1 */
 
 	status &= ~TD_CTRL_SPD;
 
@@ -953,14 +966,6 @@
 
 		tmp = tmp->next;
 
-		if (urbp->fsbr_timeout && (td->status & TD_CTRL_IOC) &&
-		    !(td->status & TD_CTRL_ACTIVE)) {
-			uhci_inc_fsbr(urb->dev->bus->hcpriv, urb);
-			urbp->fsbr_timeout = 0;
-			urbp->fsbrtime = jiffies;
-			clear_bit(TD_CTRL_IOC_BIT, &td->status);
-		}
-
 		status = uhci_status_bits(td->status);
 		if (status & TD_CTRL_ACTIVE)
 			return -EINPROGRESS;
@@ -1097,7 +1102,7 @@
 	if (!td)
 		return -ENOMEM;
 
-	destination |= (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE);
+	destination |= (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT);
 	destination |= ((urb->transfer_buffer_length - 1) << 21);
 
 	usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
@@ -1127,14 +1132,6 @@
 
 		tmp = tmp->next;
 
-		if (urbp->fsbr_timeout && (td->status & TD_CTRL_IOC) &&
-		    !(td->status & TD_CTRL_ACTIVE)) {
-			uhci_inc_fsbr(urb->dev->bus->hcpriv, urb);
-			urbp->fsbr_timeout = 0;
-			urbp->fsbrtime = jiffies;
-			clear_bit(TD_CTRL_IOC_BIT, &td->status);
-		}
-
 		status = uhci_status_bits(td->status);
 		if (status & TD_CTRL_ACTIVE)
 			return -EINPROGRESS;
@@ -1198,8 +1195,8 @@
 	td = list_entry(urbp->td_list.next, struct uhci_td, list);
 
 	td->status = (td->status & 0x2F000000) | TD_CTRL_ACTIVE | TD_CTRL_IOC;
-	td->info &= ~(1 << TD_TOKEN_TOGGLE);
-	td->info |= (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE);
+	td->info &= ~TD_TOKEN_TOGGLE;
+	td->info |= (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT);
 	usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
 
 out:
@@ -1255,7 +1252,7 @@
 		uhci_fill_td(td, status, destination |
 			(((pktsze - 1) & UHCI_NULL_DATA_SIZE) << 21) |
 			(usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
-			 usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE),
+			 usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT),
 			data);
 
 		data += pktsze;
@@ -1283,7 +1280,7 @@
 		uhci_fill_td(td, status, destination |
 			(UHCI_NULL_DATA_SIZE << 21) |
 			(usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
-			 usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE),
+			 usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT),
 			data);
 
 		usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),
@@ -1830,11 +1827,18 @@
 {
 	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
 	struct list_head *head, *tmp;
+	int count = 0;
 
 	uhci_dec_fsbr(uhci, urb);
 
 	urbp->fsbr_timeout = 1;
 
+	/*
+	 * Ideally we would want to fix qh->element as well, but it's
+	 * read/write by the HC, so that can introduce a race. It's not
+	 * really worth the hassle
+	 */
+
 	head = &urbp->td_list;
 	tmp = head->next;
 	while (tmp != head) {
@@ -1842,10 +1846,15 @@
 
 		tmp = tmp->next;
 
-		if (td->status & TD_CTRL_ACTIVE) {
-			set_bit(TD_CTRL_IOC_BIT, &td->status);
-			break;
-		}
+		/*
+		 * Make sure we don't do the last one (since it'll have the
+		 * TERM bit set) as well as we skip every so many TD's to
+		 * make sure it doesn't hog the bandwidth
+		 */
+		if (tmp != head && (count % DEPTH_INTERVAL) == (DEPTH_INTERVAL - 1))
+			td->link |= UHCI_PTR_DEPTH;
+
+		count++;
 	}
 
 	return 0;
diff -urN linux-2.4.20-pre4/drivers/usb/uhci.h linux-2.4.20-pre5/drivers/usb/uhci.h
--- linux-2.4.20-pre4/drivers/usb/uhci.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/drivers/usb/uhci.h	Wed Aug 28 16:38:23 2002
@@ -100,7 +100,6 @@
 #define TD_CTRL_C_ERR_SHIFT	27
 #define TD_CTRL_LS		(1 << 26)	/* Low Speed Device */
 #define TD_CTRL_IOS		(1 << 25)	/* Isochronous Select */
-#define TD_CTRL_IOC_BIT		24
 #define TD_CTRL_IOC		(1 << 24)	/* Interrupt on Complete */
 #define TD_CTRL_ACTIVE		(1 << 23)	/* TD Active */
 #define TD_CTRL_STALLED		(1 << 22)	/* TD Stalled */
@@ -120,13 +119,14 @@
 /*
  * for TD <info>: (a.k.a. Token)
  */
-#define TD_TOKEN_TOGGLE		19
+#define TD_TOKEN_TOGGLE_SHIFT	19
+#define TD_TOKEN_TOGGLE		(1 << 19)
 #define TD_TOKEN_PID_MASK	0xFF
 #define TD_TOKEN_EXPLEN_MASK	0x7FF		/* expected length, encoded as n - 1 */
 
 #define uhci_maxlen(token)	((token) >> 21)
 #define uhci_expected_length(info) (((info >> 21) + 1) & TD_TOKEN_EXPLEN_MASK) /* 1-based */
-#define uhci_toggle(token)	(((token) >> TD_TOKEN_TOGGLE) & 1)
+#define uhci_toggle(token)	(((token) >> TD_TOKEN_TOGGLE_SHIFT) & 1)
 #define uhci_endpoint(token)	(((token) >> 15) & 0xf)
 #define uhci_devaddr(token)	(((token) >> 8) & 0x7f)
 #define uhci_devep(token)	(((token) >> 8) & 0x7ff)
diff -urN linux-2.4.20-pre4/drivers/usb/usb-ohci.c linux-2.4.20-pre5/drivers/usb/usb-ohci.c
--- linux-2.4.20-pre4/drivers/usb/usb-ohci.c	Wed Aug 28 16:37:09 2002
+++ linux-2.4.20-pre5/drivers/usb/usb-ohci.c	Wed Aug 28 16:38:23 2002
@@ -384,6 +384,8 @@
 	__u32			temp, ndp, i;
 
 	temp = roothub_a (controller);
+	if (temp == ~(u32)0)
+		return;
 	ndp = (temp & RH_A_NDP);
 
 	if (verbose) {
@@ -1626,11 +1628,6 @@
 			if (tdHeadP == tdTailP) {
 				if (ed->state == ED_OPER)
 					ep_unlink(ohci, ed);
-				td_free (ohci, tdTailP);
-				ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP);
-				ed->state = ED_NEW;
-				hash_free_ed(ohci, ed);
-				--(usb_to_ohci (ohci->dev[edINFO & 0x7F]))->ed_cnt;
 			} else
    	 			ed->hwINFO &= ~cpu_to_le32 (OHCI_ED_SKIP);
    	 	}
@@ -2301,9 +2298,19 @@
 	struct ohci_regs * regs = ohci->regs;
  	int ints; 
 
-	if ((ohci->hcca->done_head != 0) && !(le32_to_cpup (&ohci->hcca->done_head) & 0x01)) {
+	/* avoid (slow) readl if only WDH happened */
+	if ((ohci->hcca->done_head != 0)
+			&& !(le32_to_cpup (&ohci->hcca->done_head) & 0x01)) {
 		ints =  OHCI_INTR_WDH;
-	} else if ((ints = (readl (&regs->intrstatus) & readl (&regs->intrenable))) == 0) {
+
+	/* cardbus/... hardware gone before remove() */
+	} else if ((ints = readl (&regs->intrstatus)) == ~(u32)0) {
+		ohci->disabled++;
+		err ("%s device removed!", ohci->ohci_dev->slot_name);
+		return;
+
+	/* interrupt for some other device? */
+	} else if ((ints &= readl (&regs->intrenable)) == 0) {
 		return;
 	} 
 
diff -urN linux-2.4.20-pre4/drivers/usb/usb-uhci.c linux-2.4.20-pre5/drivers/usb/usb-uhci.c
--- linux-2.4.20-pre4/drivers/usb/usb-uhci.c	Wed Aug 28 16:37:10 2002
+++ linux-2.4.20-pre5/drivers/usb/usb-uhci.c	Wed Aug 28 16:38:23 2002
@@ -1176,7 +1176,7 @@
 
 	if (urb->status == -EINPROGRESS) {
 
-		// move descriptors out the the running chains, dequeue urb
+		// move descriptors out of the running chains, dequeue urb
 		uhci_unlink_urb_async(s, urb, UNLINK_ASYNC_DONT_STORE);
 
 		urb_priv = urb->hcpriv;
diff -urN linux-2.4.20-pre4/drivers/usb/usb.c linux-2.4.20-pre5/drivers/usb/usb.c
--- linux-2.4.20-pre4/drivers/usb/usb.c	Wed Aug 28 16:37:10 2002
+++ linux-2.4.20-pre5/drivers/usb/usb.c	Wed Aug 28 16:38:23 2002
@@ -1145,7 +1145,8 @@
  *	This function sends a simple control message to a specified endpoint
  *	and waits for the message to complete, or timeout.
  *	
- *	If successful, it returns 0, othwise a negative error number.
+ *	If successful, it returns the number of bytes transferred; 
+ *	otherwise, it returns a negative error number.
  *
  *	Don't use this function from within an interrupt context, like a
  *	bottom half handler.  If you need a asyncronous message, or need to send
@@ -1188,9 +1189,9 @@
  *	This function sends a simple bulk message to a specified endpoint
  *	and waits for the message to complete, or timeout.
  *	
- *	If successful, it returns 0, othwise a negative error number.
- *	The number of actual bytes transferred will be plaed in the 
- *	actual_timeout paramater.
+ *	If successful, it returns 0, otherwise a negative error number.
+ *	The number of actual bytes transferred will be stored in the 
+ *	actual_length paramater.
  *
  *	Don't use this function from within an interrupt context, like a
  *	bottom half handler.  If you need a asyncronous message, or need to
diff -urN linux-2.4.20-pre4/drivers/usb/vicam.c linux-2.4.20-pre5/drivers/usb/vicam.c
--- linux-2.4.20-pre4/drivers/usb/vicam.c	Wed Aug 28 16:37:10 2002
+++ linux-2.4.20-pre5/drivers/usb/vicam.c	Wed Aug 28 16:38:24 2002
@@ -809,7 +809,7 @@
 	return 1;
 }
 
-static void * __devinit vicam_probe(struct usb_device *udev, unsigned int ifnum,
+static void * vicam_probe(struct usb_device *udev, unsigned int ifnum,
 	const struct usb_device_id *id)
 {
 	struct usb_vicam *vicam;
diff -urN linux-2.4.20-pre4/drivers/usb/vicamurbs.h linux-2.4.20-pre5/drivers/usb/vicamurbs.h
--- linux-2.4.20-pre4/drivers/usb/vicamurbs.h	Mon Feb 25 11:38:07 2002
+++ linux-2.4.20-pre5/drivers/usb/vicamurbs.h	Wed Aug 28 16:38:24 2002
@@ -17,12 +17,6 @@
 
 /* Request 0x51 Image Setup */
 
-/* 128x98 ? 0x3180 size */
-static unsigned char s128x98bw[] = {
-  0,    0x34, 0xC4, 0x00, 0x00, 0x00, 0,    0,
-  0x18, 0x02, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00
-};
-
 /* 128x122 3D80 size */
 static unsigned char s128x122bw[] = {
   0,    0x34, 0xF4, 0x00, 0x00, 0x00, 0,    0,
diff -urN linux-2.4.20-pre4/drivers/usb/wacom.c linux-2.4.20-pre5/drivers/usb/wacom.c
--- linux-2.4.20-pre4/drivers/usb/wacom.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/drivers/usb/wacom.c	Wed Aug 28 16:38:24 2002
@@ -111,7 +111,6 @@
 	struct wacom_features *features;
 	int tool[2];
 	int open;
-	int x, y;
 	__u32 serial[2];
 };
 
@@ -209,16 +208,16 @@
 			input_report_abs(dev, ABS_DISTANCE, data[7]);
 			input_report_rel(dev, REL_WHEEL, (signed char) data[6]);
 
-			input_report_abs(dev, ABS_X, wacom->x = x);
-			input_report_abs(dev, ABS_Y, wacom->y = y);
+			input_report_abs(dev, ABS_X, x);
+			input_report_abs(dev, ABS_Y, y);
 
 			input_event(dev, EV_MSC, MSC_SERIAL, data[1] & 0x01);
 			return;
 	}
 
 	if (data[1] & 0x80) {
-		input_report_abs(dev, ABS_X, wacom->x = x);
-		input_report_abs(dev, ABS_Y, wacom->y = y);
+		input_report_abs(dev, ABS_X, x);
+		input_report_abs(dev, ABS_Y, y);
 	}
 
 	input_report_abs(dev, ABS_PRESSURE, data[6] | ((__u32)data[7] << 8));
@@ -236,7 +235,6 @@
 	struct input_dev *dev = &wacom->dev;
 	unsigned int t;
 	int idx;
-	int x, y; 
 
 	if (urb->status) return;
 
@@ -285,11 +283,8 @@
 		return;
 	}
 
-	x = ((__u32)data[2] << 8) | data[3];
-	y = ((__u32)data[4] << 8) | data[5];
-	
-	input_report_abs(dev, ABS_X, wacom->x);
-	input_report_abs(dev, ABS_Y, wacom->y);
+	input_report_abs(dev, ABS_X, ((__u32)data[2] << 8) | data[3]);
+	input_report_abs(dev, ABS_Y, ((__u32)data[4] << 8) | data[5]);
 	input_report_abs(dev, ABS_DISTANCE, data[9] >> 4);
 	
 	if ((data[1] & 0xb8) == 0xa0) {						/* general pen packet */
diff -urN linux-2.4.20-pre4/drivers/video/Config.in linux-2.4.20-pre5/drivers/video/Config.in
--- linux-2.4.20-pre4/drivers/video/Config.in	Wed Aug 28 16:37:10 2002
+++ linux-2.4.20-pre5/drivers/video/Config.in	Wed Aug 28 16:38:24 2002
@@ -267,7 +267,7 @@
 	   "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \
            "$CONFIG_FB_IGA" = "y" -o "$CONFIG_FB_MATROX" = "y" -o \
 	   "$CONFIG_FB_CT65550" = "y" -o "$CONFIG_FB_PM2" = "y" -o \
-           "$CONFIG_FB_PM3" = "y" -o \
+           "$CONFIG_FB_PM3" = "y" -o "$CONFIG_FB_TRIDENT" = "y" -o \
 	   "$CONFIG_FB_P9100" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \
 	   "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_RADEON" = "y" -o \
 	   "$CONFIG_FB_SGIVW" = "y" -o "$CONFIG_FB_CYBER2000" = "y" -o \
@@ -289,7 +289,7 @@
 	      "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
               "$CONFIG_FB_IGA" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \
 	      "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
-              "$CONFIG_FB_PM3" = "m" -o \
+              "$CONFIG_FB_PM3" = "m" -o "$CONFIG_FB_TRIDENT" = "y" -o \
 	      "$CONFIG_FB_P9100" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \
 	      "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_3DFX" = "m" -o \
 	      "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_CYBER2000" = "m" -o \
@@ -310,7 +310,7 @@
 	   "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \
 	   "$CONFIG_FB_CT65550" = "y" -o "$CONFIG_FB_MATROX" = "y" -o \
 	   "$CONFIG_FB_PM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \
-           "$CONFIG_FB_PM3" = "y" -o \
+           "$CONFIG_FB_PM3" = "y" -o "$CONFIG_FB_TRIDENT" = "y" -o \
 	   "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \
 	   "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_3DFX" = "y"  -o \
 	   "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_SA1100" = "y" -o \
@@ -327,7 +327,7 @@
 	      "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
 	      "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \
 	      "$CONFIG_FB_PM2" = "m" -o "$CONFIG_FB_SGIVW" = "m" -o \
-              "$CONFIG_FB_PM3" = "m" -o \
+              "$CONFIG_FB_PM3" = "m" -o "$CONFIG_FB_TRIDENT" = "y" -o \
 	      "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \
 	      "$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_SIS" = "m" -o \
 	      "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
@@ -358,7 +358,7 @@
 	   "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \
 	   "$CONFIG_FB_TGA" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \
 	   "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \
-           "$CONFIG_FB_PM3" = "y" -o \
+           "$CONFIG_FB_PM3" = "y" -o "$CONFIG_FB_TRIDENT" = "y" -o \
 	   "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \
 	   "$CONFIG_FB_FM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \
 	   "$CONFIG_FB_RADEON" = "y" -o "$CONFIG_FB_PVR2" = "y" -o \
@@ -372,7 +372,7 @@
 	      "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \
 	      "$CONFIG_FB_TGA" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
 	      "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
-              "$CONFIG_FB_PM3" = "m" -o \
+              "$CONFIG_FB_PM3" = "m" -o "$CONFIG_FB_TRIDENT" = "y" -o \
 	      "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \
 	      "$CONFIG_FB_3DFX" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
 	      "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_SIS" = "m" -o \
diff -urN linux-2.4.20-pre4/drivers/zorro/proc.c linux-2.4.20-pre5/drivers/zorro/proc.c
--- linux-2.4.20-pre4/drivers/zorro/proc.c	Tue Mar  7 10:52:41 2000
+++ linux-2.4.20-pre5/drivers/zorro/proc.c	Wed Aug 28 16:38:24 2002
@@ -48,7 +48,7 @@
 	struct proc_dir_entry *dp = ino->u.generic_ip;
 	struct zorro_dev *dev = dp->data;
 	struct ConfigDev cd;
-	int pos = *ppos;
+	loff_t pos = *ppos;
 
 	if (pos >= sizeof(struct ConfigDev))
 		return 0;
diff -urN linux-2.4.20-pre4/fs/buffer.c linux-2.4.20-pre5/fs/buffer.c
--- linux-2.4.20-pre4/fs/buffer.c	Wed Aug 28 16:37:15 2002
+++ linux-2.4.20-pre5/fs/buffer.c	Wed Aug 28 16:38:24 2002
@@ -1748,9 +1748,14 @@
 	}
 
 	/* Stage 3: start the IO */
-	for (i = 0; i < nr; i++)
-		submit_bh(READ, arr[i]);
-
+	for (i = 0; i < nr; i++) {
+		struct buffer_head * bh = arr[i];
+		if (buffer_uptodate(bh))
+			end_buffer_io_async(bh, 1);
+		else
+			submit_bh(READ, bh);
+	}
+	
 	return 0;
 }
 
diff -urN linux-2.4.20-pre4/fs/efs/super.c linux-2.4.20-pre5/fs/efs/super.c
--- linux-2.4.20-pre4/fs/efs/super.c	Mon Feb 25 11:38:08 2002
+++ linux-2.4.20-pre5/fs/efs/super.c	Wed Aug 28 16:38:24 2002
@@ -141,7 +141,13 @@
 	s->s_magic		= EFS_SUPER_MAGIC;
 	s->s_blocksize		= EFS_BLOCKSIZE;
 	s->s_blocksize_bits	= EFS_BLOCKSIZE_BITS;
-	set_blocksize(dev, EFS_BLOCKSIZE);
+	
+	if( set_blocksize(dev, EFS_BLOCKSIZE) < 0)
+	{
+		printk(KERN_ERR "EFS: device does not support %d byte blocks\n",
+			EFS_BLOCKSIZE);
+		goto out_no_fs_ul;
+	}
   
 	/* read the vh (volume header) block */
 	bh = sb_bread(s, 0);
diff -urN linux-2.4.20-pre4/fs/exec.c linux-2.4.20-pre5/fs/exec.c
--- linux-2.4.20-pre4/fs/exec.c	Wed Aug 28 16:37:15 2002
+++ linux-2.4.20-pre5/fs/exec.c	Wed Aug 28 16:38:24 2002
@@ -364,8 +364,7 @@
 	struct file *file;
 	int err = 0;
 
-	if (path_init(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd))
-		err = path_walk(name, &nd);
+	err = path_lookup(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd);
 	file = ERR_PTR(err);
 	if (!err) {
 		inode = nd.dentry->d_inode;
diff -urN linux-2.4.20-pre4/fs/ext3/file.c linux-2.4.20-pre5/fs/ext3/file.c
--- linux-2.4.20-pre4/fs/ext3/file.c	Thu Nov 15 13:37:55 2001
+++ linux-2.4.20-pre5/fs/ext3/file.c	Wed Aug 28 16:38:24 2002
@@ -61,19 +61,52 @@
 static ssize_t
 ext3_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
 {
+	int ret, err;
 	struct inode *inode = file->f_dentry->d_inode;
 
-	/*
-	 * Nasty: if the file is subject to synchronous writes then we need
-	 * to force generic_osync_inode() to call ext3_write_inode().
-	 * We do that by marking the inode dirty.  This adds much more
-	 * computational expense than we need, but we're going to sync
-	 * anyway.
-	 */
-	if (IS_SYNC(inode) || (file->f_flags & O_SYNC))
-		mark_inode_dirty(inode);
+	ret = generic_file_write(file, buf, count, ppos);
 
-	return generic_file_write(file, buf, count, ppos);
+	/* Skip file flushing code if there was an error, or if nothing
+	   was written. */
+	if (ret <= 0)
+		return ret;
+	
+	/* If the inode is IS_SYNC, or is O_SYNC and we are doing
+           data-journaling, then we need to make sure that we force the
+           transaction to disk to keep all metadata uptodate
+           synchronously. */
+
+	if (file->f_flags & O_SYNC) {
+		/* If we are non-data-journaled, then the dirty data has
+                   already been flushed to backing store by
+                   generic_osync_inode, and the inode has been flushed
+                   too if there have been any modifications other than
+                   mere timestamp updates.
+		   
+		   Open question --- do we care about flushing
+		   timestamps too if the inode is IS_SYNC? */
+		if (!ext3_should_journal_data(inode))
+			return ret;
+
+		goto force_commit;
+	}
+
+	/* So we know that there has been no forced data flush.  If the
+           inode is marked IS_SYNC, we need to force one ourselves. */
+	if (!IS_SYNC(inode))
+		return ret;
+	
+	/* Open question #2 --- should we force data to disk here too?
+           If we don't, the only impact is that data=writeback
+           filesystems won't flush data to disk automatically on
+           IS_SYNC, only metadata (but historically, that is what ext2
+           has done.) */
+	
+force_commit:
+	err = ext3_force_commit(inode->i_sb);
+	if (err) 
+		return err;
+	return ret;
 }
 
 struct file_operations ext3_file_operations = {
diff -urN linux-2.4.20-pre4/fs/ext3/fsync.c linux-2.4.20-pre5/fs/ext3/fsync.c
--- linux-2.4.20-pre4/fs/ext3/fsync.c	Tue Nov 20 21:34:13 2001
+++ linux-2.4.20-pre5/fs/ext3/fsync.c	Wed Aug 28 16:38:24 2002
@@ -62,7 +62,12 @@
 	 * we'll end up waiting on them in commit.
 	 */
 	ret = fsync_inode_buffers(inode);
-	ret |= fsync_inode_data_buffers(inode);
+
+	/* In writeback mode, we need to force out data buffers too.  In
+	 * the other modes, ext3_force_commit takes care of forcing out
+	 * just the right data blocks. */
+	if (test_opt(inode->i_sb, DATA_FLAGS) == EXT3_MOUNT_WRITEBACK_DATA)
+		ret |= fsync_inode_data_buffers(inode);
 
 	ext3_force_commit(inode->i_sb);
 
diff -urN linux-2.4.20-pre4/fs/ext3/ialloc.c linux-2.4.20-pre5/fs/ext3/ialloc.c
--- linux-2.4.20-pre4/fs/ext3/ialloc.c	Mon Feb 25 11:38:08 2002
+++ linux-2.4.20-pre5/fs/ext3/ialloc.c	Wed Aug 28 16:38:24 2002
@@ -392,7 +392,7 @@
 
 	err = -ENOSPC;
 	if (!gdp)
-		goto fail;
+		goto out;
 
 	err = -EIO;
 	bitmap_nr = load_inode_bitmap (sb, i);
@@ -523,9 +523,10 @@
 	return inode;
 
 fail:
+	ext3_std_error(sb, err);
+out:
 	unlock_super(sb);
 	iput(inode);
-	ext3_std_error(sb, err);
 	return ERR_PTR(err);
 }
 
diff -urN linux-2.4.20-pre4/fs/ext3/inode.c linux-2.4.20-pre5/fs/ext3/inode.c
--- linux-2.4.20-pre4/fs/ext3/inode.c	Wed Aug 28 16:37:15 2002
+++ linux-2.4.20-pre5/fs/ext3/inode.c	Wed Aug 28 16:38:24 2002
@@ -412,6 +412,7 @@
 	return NULL;
 
 changed:
+	brelse(bh);
 	*err = -EAGAIN;
 	goto no_block;
 failure:
@@ -1579,8 +1580,10 @@
 		}
 		ext3_mark_inode_dirty(handle, inode);
 		ext3_journal_test_restart(handle, inode);
-		BUFFER_TRACE(bh, "get_write_access");
-		ext3_journal_get_write_access(handle, bh);
+		if (bh) {
+			BUFFER_TRACE(bh, "retaking write access");
+			ext3_journal_get_write_access(handle, bh);
+		}
 	}
 
 	/*
diff -urN linux-2.4.20-pre4/fs/jbd/commit.c linux-2.4.20-pre5/fs/jbd/commit.c
--- linux-2.4.20-pre4/fs/jbd/commit.c	Mon Feb 25 11:38:08 2002
+++ linux-2.4.20-pre5/fs/jbd/commit.c	Wed Aug 28 16:38:24 2002
@@ -663,6 +663,20 @@
 		 * there's no point in keeping a checkpoint record for
 		 * it. */
 		bh = jh2bh(jh);
+
+		/* A buffer which has been freed while still being
+		 * journaled by a previous transaction may end up still
+		 * being dirty here, but we want to avoid writing back
+		 * that buffer in the future now that the last use has
+		 * been committed.  That's not only a performance gain,
+		 * it also stops aliasing problems if the buffer is left
+		 * behind for writeback and gets reallocated for another
+		 * use in a different page. */
+		if (__buffer_state(bh, Freed)) {
+			clear_bit(BH_Freed, &bh->b_state);
+			clear_bit(BH_JBDDirty, &bh->b_state);
+		}
+			
 		if (buffer_jdirty(bh)) {
 			JBUFFER_TRACE(jh, "add to new checkpointing trans");
 			__journal_insert_checkpoint(jh, commit_transaction);
diff -urN linux-2.4.20-pre4/fs/jbd/journal.c linux-2.4.20-pre5/fs/jbd/journal.c
--- linux-2.4.20-pre4/fs/jbd/journal.c	Wed Aug 28 16:37:15 2002
+++ linux-2.4.20-pre5/fs/jbd/journal.c	Wed Aug 28 16:38:24 2002
@@ -1485,6 +1485,49 @@
 	unlock_journal(journal);
 }
 
+
+/*
+ * Report any unexpected dirty buffers which turn up.  Normally those
+ * indicate an error, but they can occur if the user is running (say)
+ * tune2fs to modify the live filesystem, so we need the option of
+ * continuing as gracefully as possible.  #
+ *
+ * The caller should already hold the journal lock and
+ * journal_datalist_lock spinlock: most callers will need those anyway
+ * in order to probe the buffer's journaling state safely.
+ */
+void __jbd_unexpected_dirty_buffer(char *function, int line, 
+				 struct journal_head *jh)
+{
+	struct buffer_head *bh = jh2bh(jh);
+	int jlist;
+	
+	if (buffer_dirty(bh)) {
+		printk ("%sUnexpected dirty buffer encountered at "
+			"%s:%d (%s blocknr %lu)\n",
+			KERN_WARNING, function, line,
+			kdevname(bh->b_dev), bh->b_blocknr);
+#ifdef JBD_PARANOID_WRITES
+		J_ASSERT_BH (bh, !buffer_dirty(bh));
+#endif	
+		
+		/* If this buffer is one which might reasonably be dirty
+		 * --- ie. data, or not part of this journal --- then
+		 * we're OK to leave it alone, but otherwise we need to
+		 * move the dirty bit to the journal's own internal
+		 * JBDDirty bit. */
+		jlist = jh->b_jlist;
+		
+		if (jlist == BJ_Metadata || jlist == BJ_Reserved || 
+		    jlist == BJ_Shadow || jlist == BJ_Forget) {
+			if (atomic_set_buffer_clean(jh2bh(jh))) {
+				set_bit(BH_JBDDirty, &jh2bh(jh)->b_state);
+			}
+		}
+	}
+}
+
+
 int journal_blocks_per_page(struct inode *inode)
 {
 	return 1 << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits);
diff -urN linux-2.4.20-pre4/fs/jbd/transaction.c linux-2.4.20-pre5/fs/jbd/transaction.c
--- linux-2.4.20-pre4/fs/jbd/transaction.c	Wed Aug 28 16:37:15 2002
+++ linux-2.4.20-pre5/fs/jbd/transaction.c	Wed Aug 28 16:38:24 2002
@@ -539,76 +539,67 @@
 static int
 do_get_write_access(handle_t *handle, struct journal_head *jh, int force_copy) 
 {
+	struct buffer_head *bh;
 	transaction_t *transaction = handle->h_transaction;
 	journal_t *journal = transaction->t_journal;
 	int error;
 	char *frozen_buffer = NULL;
 	int need_copy = 0;
-
+	int locked;
+	
 	jbd_debug(5, "buffer_head %p, force_copy %d\n", jh, force_copy);
 
 	JBUFFER_TRACE(jh, "entry");
 repeat:
+	bh = jh2bh(jh);
+
 	/* @@@ Need to check for errors here at some point. */
 
 	/*
-	 * AKPM: neither bdflush nor kupdate run with the BKL.   There's
-	 * nothing we can do to prevent them from starting writeout of a
-	 * BUF_DIRTY buffer at any time.  And checkpointing buffers are on
-	 * BUF_DIRTY.  So.  We no longer assert that the buffer is unlocked.
-	 *
-	 * However.  It is very wrong for us to allow ext3 to start directly
-	 * altering the ->b_data of buffers which may at that very time be
-	 * undergoing writeout to the client filesystem.  This can leave
-	 * the filesystem in an inconsistent, transient state if we crash.
-	 * So what we do is to steal the buffer if it is in checkpoint
-	 * mode and dirty.  The journal lock will keep out checkpoint-mode
-	 * state transitions within journal_remove_checkpoint() and the buffer
-	 * is locked to keep bdflush/kupdate/whoever away from it as well.
-	 *
 	 * AKPM: we have replaced all the lock_journal_bh_wait() stuff with a
 	 * simple lock_journal().  This code here will care for locked buffers.
 	 */
-	/*
-	 * The buffer_locked() || buffer_dirty() tests here are simply an
-	 * optimisation tweak.  If anyone else in the system decides to
-	 * lock this buffer later on, we'll blow up.  There doesn't seem
-	 * to be a good reason why they should do this.
-	 */
-	if (jh->b_cp_transaction &&
-	    (buffer_locked(jh2bh(jh)) || buffer_dirty(jh2bh(jh)))) {
+	locked = test_and_set_bit(BH_Lock, &bh->b_state);
+	if (locked) {
+		/* We can't reliably test the buffer state if we found
+		 * it already locked, so just wait for the lock and
+		 * retry. */
 		unlock_journal(journal);
-		lock_buffer(jh2bh(jh));
-		spin_lock(&journal_datalist_lock);
-		if (jh->b_cp_transaction && buffer_dirty(jh2bh(jh))) {
-			/* OK, we need to steal it */
-			JBUFFER_TRACE(jh, "stealing from checkpoint mode");
-			J_ASSERT_JH(jh, jh->b_next_transaction == NULL);
-			J_ASSERT_JH(jh, jh->b_frozen_data == NULL);
-
-			J_ASSERT(handle->h_buffer_credits > 0);
-			handle->h_buffer_credits--;
-
-			/* This will clear BH_Dirty and set BH_JBDDirty. */
-			JBUFFER_TRACE(jh, "file as BJ_Reserved");
-			__journal_file_buffer(jh, transaction, BJ_Reserved);
-
-			/* And pull it off BUF_DIRTY, onto BUF_CLEAN */
-			refile_buffer(jh2bh(jh));
+		__wait_on_buffer(bh);
+		lock_journal(journal);
+		goto repeat;
+	}
+	
+	/* We now hold the buffer lock so it is safe to query the buffer
+	 * state.  Is the buffer dirty? 
+	 * 
+	 * If so, there are two possibilities.  The buffer may be
+	 * non-journaled, and undergoing a quite legitimate writeback.
+	 * Otherwise, it is journaled, and we don't expect dirty buffers
+	 * in that state (the buffers should be marked JBD_Dirty
+	 * instead.)  So either the IO is being done under our own
+	 * control and this is a bug, or it's a third party IO such as
+	 * dump(8) (which may leave the buffer scheduled for read ---
+	 * ie. locked but not dirty) or tune2fs (which may actually have
+	 * the buffer dirtied, ugh.)  */
 
-			/*
-			 * The buffer is now hidden from bdflush.   It is
-			 * metadata against the current transaction.
-			 */
-			JBUFFER_TRACE(jh, "steal from cp mode is complete");
+	if (buffer_dirty(bh)) {
+		spin_lock(&journal_datalist_lock);
+		/* First question: is this buffer already part of the
+		 * current transaction or the existing committing
+		 * transaction? */
+		if (jh->b_transaction) {
+			J_ASSERT_JH(jh, jh->b_transaction == transaction || 
+				    jh->b_transaction == journal->j_committing_transaction);
+			if (jh->b_next_transaction)
+				J_ASSERT_JH(jh, jh->b_next_transaction == transaction);
+			JBUFFER_TRACE(jh, "Unexpected dirty buffer");
+			jbd_unexpected_dirty_buffer(jh);
 		}
 		spin_unlock(&journal_datalist_lock);
-		unlock_buffer(jh2bh(jh));
-		lock_journal(journal);
-		goto repeat;
 	}
 
-	J_ASSERT_JH(jh, !buffer_locked(jh2bh(jh)));
+	unlock_buffer(bh);
 
 	error = -EROFS;
 	if (is_handle_aborted(handle)) 
@@ -1842,6 +1833,7 @@
 		 * running transaction if that is set, but nothing
 		 * else. */
 		JBUFFER_TRACE(jh, "on committing transaction");
+		set_bit(BH_Freed, &bh->b_state);
 		if (jh->b_next_transaction) {
 			J_ASSERT(jh->b_next_transaction ==
 					journal->j_running_transaction);
@@ -1925,6 +1917,7 @@
 			transaction_t *transaction, int jlist)
 {
 	struct journal_head **list = 0;
+	int was_dirty = 0;
 
 	assert_spin_locked(&journal_datalist_lock);
 	
@@ -1935,13 +1928,24 @@
 	J_ASSERT_JH(jh, jh->b_transaction == transaction ||
 				jh->b_transaction == 0);
 
-	if (jh->b_transaction) {
-		if (jh->b_jlist == jlist)
-			return;
+	if (jh->b_transaction && jh->b_jlist == jlist)
+		return;
+	
+	/* The following list of buffer states needs to be consistent
+	 * with __jbd_unexpected_dirty_buffer()'s handling of dirty
+	 * state. */
+
+	if (jlist == BJ_Metadata || jlist == BJ_Reserved || 
+	    jlist == BJ_Shadow || jlist == BJ_Forget) {
+		if (atomic_set_buffer_clean(jh2bh(jh)) ||
+		    test_and_clear_bit(BH_JBDDirty, &jh2bh(jh)->b_state))
+			was_dirty = 1;
+	}
+
+	if (jh->b_transaction)
 		__journal_unfile_buffer(jh);
-	} else {
+	else
 		jh->b_transaction = transaction;
-	}
 
 	switch (jlist) {
 	case BJ_None:
@@ -1978,12 +1982,8 @@
 	__blist_add_buffer(list, jh);
 	jh->b_jlist = jlist;
 
-	if (jlist == BJ_Metadata || jlist == BJ_Reserved || 
-	    jlist == BJ_Shadow || jlist == BJ_Forget) {
-		if (atomic_set_buffer_clean(jh2bh(jh))) {
-			set_bit(BH_JBDDirty, &jh2bh(jh)->b_state);
-		}
-	}
+	if (was_dirty)
+		set_bit(BH_JBDDirty, &jh2bh(jh)->b_state);
 }
 
 void journal_file_buffer(struct journal_head *jh,
@@ -2003,26 +2003,36 @@
 
 void __journal_refile_buffer(struct journal_head *jh)
 {
+	int was_dirty = 0;
+
 	assert_spin_locked(&journal_datalist_lock);
 #ifdef __SMP__
 	J_ASSERT_JH(jh, current->lock_depth >= 0);
 #endif
-	__journal_unfile_buffer(jh);
+	/* If the buffer is now unused, just drop it. */
+	if (jh->b_next_transaction == NULL) {
+		__journal_unfile_buffer(jh);
+		jh->b_transaction = NULL;
+		/* Onto BUF_DIRTY for writeback */
+		refile_buffer(jh2bh(jh));
+		return;
+	}
+	
+	/* It has been modified by a later transaction: add it to the
+	 * new transaction's metadata list. */
 
-	/* If the buffer is now unused, just drop it.  If it has been
-	   modified by a later transaction, add it to the new
-	   transaction's metadata list. */
+	if (test_and_clear_bit(BH_JBDDirty, &jh2bh(jh)->b_state))
+			was_dirty = 1;
 
+	__journal_unfile_buffer(jh);
 	jh->b_transaction = jh->b_next_transaction;
 	jh->b_next_transaction = NULL;
+	__journal_file_buffer(jh, jh->b_transaction, BJ_Metadata);
+	J_ASSERT_JH(jh, jh->b_transaction->t_state == T_RUNNING);
+
+	if (was_dirty)
+		set_bit(BH_JBDDirty, &jh2bh(jh)->b_state);
 
-	if (jh->b_transaction != NULL) {
-		__journal_file_buffer(jh, jh->b_transaction, BJ_Metadata);
-		J_ASSERT_JH(jh, jh->b_transaction->t_state == T_RUNNING);
-	} else {
-		/* Onto BUF_DIRTY for writeback */
-		refile_buffer(jh2bh(jh));
-	}
 }
 
 /*
diff -urN linux-2.4.20-pre4/fs/jffs2/dir.c linux-2.4.20-pre5/fs/jffs2/dir.c
--- linux-2.4.20-pre4/fs/jffs2/dir.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/fs/jffs2/dir.c	Wed Aug 28 16:38:24 2002
@@ -31,7 +31,7 @@
  * provisions above, a recipient may use your version of this file
  * under either the RHEPL or the GPL.
  *
- * $Id: dir.c,v 1.45.2.6 2002/06/20 23:54:48 dwmw2 Exp $
+ * $Id: dir.c,v 1.45.2.7 2002/08/26 15:30:18 dwmw2 Exp $
  *
  */
 
@@ -404,8 +404,9 @@
 			jffs2_mark_node_obsolete(c, fd->raw);
 			jffs2_free_full_dirent(fd);
 		}
-
-		f->inocache->nlink--;
+		/* Don't oops on unlinking a bad inode */
+		if (f->inocache)
+			f->inocache->nlink--;
 		dentry->d_inode->i_nlink--;
 		up(&f->sem);
 	}
@@ -489,6 +490,10 @@
 {
 	int ret;
 
+	/* Can't link a bad inode. */
+	if (!JFFS2_INODE_INFO(old_dentry->d_inode)->inocache)
+		return -EIO;
+
 	if (S_ISDIR(old_dentry->d_inode->i_mode))
 		return -EPERM;
 
@@ -991,7 +996,8 @@
 		/* Oh shit. We really ought to make a single node which can do both atomically */
 		struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode);
 		down(&f->sem);
-		old_dentry->d_inode->i_nlink = f->inocache->nlink++;
+		if (f->inocache)
+			old_dentry->d_inode->i_nlink = f->inocache->nlink++;
 		up(&f->sem);
 		       
 		printk(KERN_NOTICE "jffs2_rename(): Link succeeded, unlink failed (err %d). You now have a hard link\n", ret);
diff -urN linux-2.4.20-pre4/fs/namei.c linux-2.4.20-pre5/fs/namei.c
--- linux-2.4.20-pre4/fs/namei.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/fs/namei.c	Wed Aug 28 16:38:24 2002
@@ -739,6 +739,16 @@
 }
 
 /* SMP-safe */
+int path_lookup(const char *path, unsigned flags, struct nameidata *nd)
+{
+	int error = 0;
+	if (path_init(path, flags, nd))
+		error = path_walk(path, nd);
+	return error;
+}
+
+
+/* SMP-safe */
 int path_init(const char *name, unsigned int flags, struct nameidata *nd)
 {
 	nd->last_type = LAST_ROOT; /* if there are only slashes... */
@@ -844,8 +854,7 @@
 	err = PTR_ERR(tmp);
 	if (!IS_ERR(tmp)) {
 		err = 0;
-		if (path_init(tmp, flags, nd))
-			err = path_walk(tmp, nd);
+		err = path_lookup(tmp, flags, nd);
 		putname(tmp);
 	}
 	return err;
@@ -1001,8 +1010,7 @@
 	 * The simplest case - just a plain lookup.
 	 */
 	if (!(flag & O_CREAT)) {
-		if (path_init(pathname, lookup_flags(flag), nd))
-			error = path_walk(pathname, nd);
+		error = path_lookup(pathname, lookup_flags(flag), nd);
 		if (error)
 			return error;
 		dentry = nd->dentry;
@@ -1012,8 +1020,7 @@
 	/*
 	 * Create - we need to know the parent.
 	 */
-	if (path_init(pathname, LOOKUP_PARENT, nd))
-		error = path_walk(pathname, nd);
+	error = path_lookup(pathname, LOOKUP_PARENT, nd);
 	if (error)
 		return error;
 
@@ -1265,8 +1272,7 @@
 	if (IS_ERR(tmp))
 		return PTR_ERR(tmp);
 
-	if (path_init(tmp, LOOKUP_PARENT, &nd))
-		error = path_walk(tmp, &nd);
+	error = path_lookup(tmp, LOOKUP_PARENT, &nd);
 	if (error)
 		goto out;
 	dentry = lookup_create(&nd, 0);
@@ -1334,8 +1340,7 @@
 		struct dentry *dentry;
 		struct nameidata nd;
 
-		if (path_init(tmp, LOOKUP_PARENT, &nd))
-			error = path_walk(tmp, &nd);
+		error = path_lookup(tmp, LOOKUP_PARENT, &nd);
 		if (error)
 			goto out;
 		dentry = lookup_create(&nd, 1);
@@ -1431,8 +1436,7 @@
 	if(IS_ERR(name))
 		return PTR_ERR(name);
 
-	if (path_init(name, LOOKUP_PARENT, &nd))
-		error = path_walk(name, &nd);
+	error = path_lookup(name, LOOKUP_PARENT, &nd);
 	if (error)
 		goto exit;
 
@@ -1500,8 +1504,7 @@
 	if(IS_ERR(name))
 		return PTR_ERR(name);
 
-	if (path_init(name, LOOKUP_PARENT, &nd))
-		error = path_walk(name, &nd);
+	error = path_lookup(name, LOOKUP_PARENT, &nd);
 	if (error)
 		goto exit;
 	error = -EISDIR;
@@ -1572,8 +1575,7 @@
 		struct dentry *dentry;
 		struct nameidata nd;
 
-		if (path_init(to, LOOKUP_PARENT, &nd))
-			error = path_walk(to, &nd);
+		error = path_lookup(to, LOOKUP_PARENT, &nd);
 		if (error)
 			goto out;
 		dentry = lookup_create(&nd, 0);
@@ -1643,25 +1645,18 @@
 asmlinkage long sys_link(const char * oldname, const char * newname)
 {
 	int error;
-	char * from;
 	char * to;
 
-	from = getname(oldname);
-	if(IS_ERR(from))
-		return PTR_ERR(from);
 	to = getname(newname);
 	error = PTR_ERR(to);
 	if (!IS_ERR(to)) {
 		struct dentry *new_dentry;
 		struct nameidata nd, old_nd;
 
-		error = 0;
-		if (path_init(from, LOOKUP_POSITIVE, &old_nd))
-			error = path_walk(from, &old_nd);
+		error = __user_walk(oldname, LOOKUP_POSITIVE, &old_nd);
 		if (error)
 			goto exit;
-		if (path_init(to, LOOKUP_PARENT, &nd))
-			error = path_walk(to, &nd);
+		error = path_lookup(to, LOOKUP_PARENT, &nd);
 		if (error)
 			goto out;
 		error = -EXDEV;
@@ -1681,8 +1676,6 @@
 exit:
 		putname(to);
 	}
-	putname(from);
-
 	return error;
 }
 
@@ -1859,14 +1852,11 @@
 	struct dentry * old_dentry, *new_dentry;
 	struct nameidata oldnd, newnd;
 
-	if (path_init(oldname, LOOKUP_PARENT, &oldnd))
-		error = path_walk(oldname, &oldnd);
-
+	error = path_lookup(oldname, LOOKUP_PARENT, &oldnd);
 	if (error)
 		goto exit;
 
-	if (path_init(newname, LOOKUP_PARENT, &newnd))
-		error = path_walk(newname, &newnd);
+	error = path_lookup(newname, LOOKUP_PARENT, &newnd);
 	if (error)
 		goto exit1;
 
diff -urN linux-2.4.20-pre4/fs/namespace.c linux-2.4.20-pre5/fs/namespace.c
--- linux-2.4.20-pre4/fs/namespace.c	Wed Aug 28 16:37:15 2002
+++ linux-2.4.20-pre5/fs/namespace.c	Wed Aug 28 16:38:24 2002
@@ -361,17 +361,9 @@
 asmlinkage long sys_umount(char * name, int flags)
 {
 	struct nameidata nd;
-	char *kname;
 	int retval;
 
-	kname = getname(name);
-	retval = PTR_ERR(kname);
-	if (IS_ERR(kname))
-		goto out;
-	retval = 0;
-	if (path_init(kname, LOOKUP_POSITIVE|LOOKUP_FOLLOW, &nd))
-		retval = path_walk(kname, &nd);
-	putname(kname);
+	retval = __user_walk(name, LOOKUP_POSITIVE|LOOKUP_FOLLOW, &nd);
 	if (retval)
 		goto out;
 	retval = -EINVAL;
@@ -498,8 +490,7 @@
 		return err;
 	if (!old_name || !*old_name)
 		return -EINVAL;
-	if (path_init(old_name, LOOKUP_POSITIVE|LOOKUP_FOLLOW, &old_nd))
-		err = path_walk(old_name, &old_nd);
+	err = path_lookup(old_name, LOOKUP_POSITIVE|LOOKUP_FOLLOW, &old_nd);
 	if (err)
 		return err;
 
@@ -565,8 +556,7 @@
 		return -EPERM;
 	if (!old_name || !*old_name)
 		return -EINVAL;
-	if (path_init(old_name, LOOKUP_POSITIVE|LOOKUP_FOLLOW, &old_nd))
-		err = path_walk(old_name, &old_nd);
+	err = path_lookup(old_name, LOOKUP_POSITIVE|LOOKUP_FOLLOW, &old_nd);
 	if (err)
 		return err;
 
@@ -732,8 +722,7 @@
 	flags &= ~(MS_NOSUID|MS_NOEXEC|MS_NODEV);
 
 	/* ... and get the mountpoint */
-	if (path_init(dir_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd))
-		retval = path_walk(dir_name, &nd);
+	retval = path_lookup(dir_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd);
 	if (retval)
 		return retval;
 
@@ -912,7 +901,6 @@
 {
 	struct vfsmount *tmp;
 	struct nameidata new_nd, old_nd, parent_nd, root_parent, user_nd;
-	char *name;
 	int error;
 
 	if (!capable(CAP_SYS_ADMIN))
@@ -920,28 +908,14 @@
 
 	lock_kernel();
 
-	name = getname(new_root);
-	error = PTR_ERR(name);
-	if (IS_ERR(name))
-		goto out0;
-	error = 0;
-	if (path_init(name, LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &new_nd))
-		error = path_walk(name, &new_nd);
-	putname(name);
+	error = __user_walk(new_root, LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &new_nd);
 	if (error)
 		goto out0;
 	error = -EINVAL;
 	if (!check_mnt(new_nd.mnt))
 		goto out1;
 
-	name = getname(put_old);
-	error = PTR_ERR(name);
-	if (IS_ERR(name))
-		goto out1;
-	error = 0;
-	if (path_init(name, LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &old_nd))
-		error = path_walk(name, &old_nd);
-	putname(name);
+	error = __user_walk(put_old, LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &old_nd);
 	if (error)
 		goto out1;
 
diff -urN linux-2.4.20-pre4/fs/open.c linux-2.4.20-pre5/fs/open.c
--- linux-2.4.20-pre4/fs/open.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/fs/open.c	Wed Aug 28 16:38:24 2002
@@ -385,17 +385,8 @@
 {
 	int error;
 	struct nameidata nd;
-	char *name;
 
-	name = getname(filename);
-	error = PTR_ERR(name);
-	if (IS_ERR(name))
-		goto out;
-
-	error = 0;
-	if (path_init(name,LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY,&nd))
-		error = path_walk(name, &nd);
-	putname(name);
+	error = __user_walk(filename,LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY,&nd);
 	if (error)
 		goto out;
 
@@ -445,17 +436,9 @@
 {
 	int error;
 	struct nameidata nd;
-	char *name;
-
-	name = getname(filename);
-	error = PTR_ERR(name);
-	if (IS_ERR(name))
-		goto out;
 
-	path_init(name, LOOKUP_POSITIVE | LOOKUP_FOLLOW |
+	error = __user_walk(filename, LOOKUP_POSITIVE | LOOKUP_FOLLOW |
 		      LOOKUP_DIRECTORY | LOOKUP_NOALT, &nd);
-	error = path_walk(name, &nd);	
-	putname(name);
 	if (error)
 		goto out;
 
diff -urN linux-2.4.20-pre4/fs/super.c linux-2.4.20-pre5/fs/super.c
--- linux-2.4.20-pre4/fs/super.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/fs/super.c	Wed Aug 28 16:38:24 2002
@@ -659,8 +659,7 @@
 	/* What device it is? */
 	if (!dev_name || !*dev_name)
 		return ERR_PTR(-EINVAL);
-	if (path_init(dev_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd))
-		error = path_walk(dev_name, &nd);
+	error = path_lookup(dev_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd);
 	if (error)
 		return ERR_PTR(error);
 	inode = nd.dentry->d_inode;
diff -urN linux-2.4.20-pre4/include/asm-i386/pgtable.h linux-2.4.20-pre5/include/asm-i386/pgtable.h
--- linux-2.4.20-pre4/include/asm-i386/pgtable.h	Wed Aug 28 16:37:15 2002
+++ linux-2.4.20-pre5/include/asm-i386/pgtable.h	Wed Aug 28 16:38:24 2002
@@ -82,11 +82,19 @@
 	} while (0)
 #endif
 
-#ifndef CONFIG_X86_INVLPG
-#define __flush_tlb_one(addr) __flush_tlb()
+#define __flush_tlb_single(addr) \
+	__asm__ __volatile__("invlpg %0": :"m" (*(char *) addr))
+
+#ifdef CONFIG_X86_INVLPG
+# define __flush_tlb_one(addr) __flush_tlb_single(addr)
 #else
-#define __flush_tlb_one(addr) \
-__asm__ __volatile__("invlpg %0": :"m" (*(char *) addr))
+# define __flush_tlb_one(addr)						\
+	do {								\
+		if (cpu_has_pge)					\
+			__flush_tlb_single(addr);			\
+		else							\
+			__flush_tlb();					\
+	} while (0)
 #endif
 
 /*
diff -urN linux-2.4.20-pre4/include/asm-i386/rwsem.h linux-2.4.20-pre5/include/asm-i386/rwsem.h
--- linux-2.4.20-pre4/include/asm-i386/rwsem.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/include/asm-i386/rwsem.h	Wed Aug 28 16:38:24 2002
@@ -4,6 +4,8 @@
  *
  * Derived from asm-i386/semaphore.h
  *
+ * Trylock by Brian Watson (Brian.J.Watson@compaq.com).
+ *
  *
  * The MSW of the count is the negated number of active writers and waiting
  * lockers, and the LSW is the total number of active locks
@@ -117,6 +119,29 @@
 }
 
 /*
+ * trylock for reading -- returns 1 if successful, 0 if contention
+ */
+static inline int __down_read_trylock(struct rw_semaphore *sem)
+{
+	__s32 result, tmp;
+	__asm__ __volatile__(
+		"# beginning __down_read_trylock\n\t"
+		"  movl      %0,%1\n\t"
+		"1:\n\t"
+		"  movl	     %1,%2\n\t"
+		"  addl      %3,%2\n\t"
+		"  jle	     2f\n\t"
+LOCK_PREFIX	"  cmpxchgl  %2,%0\n\t"
+		"  jnz	     1b\n\t"
+		"2:\n\t"
+		"# ending __down_read_trylock\n\t"
+		: "+m"(sem->count), "=&a"(result), "=&r"(tmp)
+		: "i"(RWSEM_ACTIVE_READ_BIAS)
+		: "memory", "cc");
+	return result>=0 ? 1 : 0;
+}
+
+/*
  * lock for writing
  */
 static inline void __down_write(struct rw_semaphore *sem)
@@ -144,6 +169,19 @@
 }
 
 /*
+ * trylock for writing -- returns 1 if successful, 0 if contention
+ */
+static inline int __down_write_trylock(struct rw_semaphore *sem)
+{
+	signed long ret = cmpxchg(&sem->count,
+				  RWSEM_UNLOCKED_VALUE, 
+				  RWSEM_ACTIVE_WRITE_BIAS);
+	if (ret == RWSEM_UNLOCKED_VALUE)
+		return 1;
+	return 0;
+}
+
+/*
  * unlock after reading
  */
 static inline void __up_read(struct rw_semaphore *sem)
diff -urN linux-2.4.20-pre4/include/asm-ppc/amigaints.h linux-2.4.20-pre5/include/asm-ppc/amigaints.h
--- linux-2.4.20-pre4/include/asm-ppc/amigaints.h	Mon May 21 15:02:06 2001
+++ linux-2.4.20-pre5/include/asm-ppc/amigaints.h	Wed Aug 28 16:38:25 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.amigaints.h 1.5 05/17/01 18:14:24 cort
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
 ** amigaints.h -- Amiga Linux interrupt handling structs and prototypes
@@ -110,12 +110,8 @@
 #define IF_DSKBLK   0x0002	/* diskblock DMA finished */
 #define IF_TBE	    0x0001	/* serial transmit buffer empty interrupt */
 
-struct irq_server {
-	unsigned short count, reentrance;
-};
-
 extern void amiga_do_irq(int irq, struct pt_regs *fp);
-extern void amiga_do_irq_list(int irq, struct pt_regs *fp, struct irq_server *server);
+extern void amiga_do_irq_list(int irq, struct pt_regs *fp);
 
 /* CIA interrupt control register bits */
 
diff -urN linux-2.4.20-pre4/include/asm-ppc/bootinfo.h linux-2.4.20-pre5/include/asm-ppc/bootinfo.h
--- linux-2.4.20-pre4/include/asm-ppc/bootinfo.h	Tue Aug 28 06:58:33 2001
+++ linux-2.4.20-pre5/include/asm-ppc/bootinfo.h	Wed Aug 28 16:38:25 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.bootinfo.h 1.11 08/17/01 15:23:17 paulus
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  * Non-machine dependent bootinfo structure.  Basic idea
@@ -33,6 +33,10 @@
 #define BI_MACHTYPE		0x1016
 #define BI_MEMSIZE		0x1017
 
+extern struct bi_record *find_bootinfo(void);
+extern void parse_bootinfo(struct bi_record *rec);
+extern unsigned long boot_mem_size;
+
 #endif /* CONFIG_APUS */
 
 
diff -urN linux-2.4.20-pre4/include/asm-ppc/keyboard.h linux-2.4.20-pre5/include/asm-ppc/keyboard.h
--- linux-2.4.20-pre4/include/asm-ppc/keyboard.h	Wed Aug 29 20:49:36 2001
+++ linux-2.4.20-pre5/include/asm-ppc/keyboard.h	Wed Aug 28 16:38:25 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.keyboard.h 1.11 08/29/01 10:07:29 paulus
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  *  linux/include/asm-ppc/keyboard.h
@@ -25,8 +25,14 @@
 #include <linux/ioport.h>
 #include <linux/kd.h>
 #include <asm/io.h>
+/* IBM Spruce platform is different. */
+#ifdef CONFIG_SPRUCE
+#include <platforms/spruce.h>
+#endif
 
+#ifndef KEYBOARD_IRQ
 #define KEYBOARD_IRQ			1
+#endif
 #define DISABLE_KBD_DURING_INTERRUPTS	0
 #define INIT_KBD
 
@@ -85,10 +91,12 @@
                                              "keyboard", NULL)
 
 /* How to access the keyboard macros on this platform.  */
+#ifndef kbd_read_input
 #define kbd_read_input() inb(KBD_DATA_REG)
 #define kbd_read_status() inb(KBD_STATUS_REG)
 #define kbd_write_output(val) outb(val, KBD_DATA_REG)
 #define kbd_write_command(val) outb(val, KBD_CNTL_REG)
+#endif
 
 /* Some stoneage hardware needs delays after some operations.  */
 #define kbd_pause() do { } while(0)
@@ -96,8 +104,9 @@
 /*
  * Machine specific bits for the PS/2 driver
  */
-
+#ifndef AUX_IRQ	
 #define AUX_IRQ 12
+#endif
 
 #define aux_request_irq(hand, dev_id)					\
 	request_irq(AUX_IRQ, hand, SA_SHIRQ, "PS/2 Mouse", dev_id)
@@ -105,5 +114,4 @@
 #define aux_free_irq(dev_id) free_irq(AUX_IRQ, dev_id)
 
 #endif /* __KERNEL__ */
-
 #endif /* __ASMPPC_KEYBOARD_H */
diff -urN linux-2.4.20-pre4/include/asm-ppc/pci-bridge.h linux-2.4.20-pre5/include/asm-ppc/pci-bridge.h
--- linux-2.4.20-pre4/include/asm-ppc/pci-bridge.h	Wed Aug 28 16:37:15 2002
+++ linux-2.4.20-pre5/include/asm-ppc/pci-bridge.h	Wed Aug 28 16:38:25 2002
@@ -22,6 +22,10 @@
 /* Allocate a new PCI host bridge structure */
 extern struct pci_controller* pcibios_alloc_controller(void);
 
+/* Helper function for setting up resources */
+extern void pci_init_resource(struct resource *res, unsigned long start,
+			      unsigned long end, int flags, char *name);
+
 /*
  * PCI <-> OF matching functions 
  */
@@ -71,6 +75,12 @@
 	struct resource	io_resource;
 	struct resource mem_resources[3];
 	int mem_resource_count;
+
+	/* Host bridge I/O and Memory space
+	 * Used for BAR placement algorithms
+	 */
+	struct resource io_space;
+	struct resource mem_space;
 };
 
 /* These are used for config access before all the PCI probing
@@ -86,5 +96,37 @@
 		u32 cfg_data);
 extern void setup_grackle(struct pci_controller *hose);
 
+extern unsigned char common_swizzle(struct pci_dev *, unsigned char *);
+
+/*
+ *   The following code swizzles for exactly one bridge.  The routine
+ *   common_swizzle below handles multiple bridges.  But there are a
+ *   some boards that don't follow the PCI spec's suggestion so we
+ *   break this piece out separately.
+ */
+static inline unsigned char bridge_swizzle(unsigned char pin,
+		unsigned char idsel) 
+{
+	return (((pin-1) + idsel) % 4) + 1;
+}
+
+/*
+ * The following macro is used to lookup irqs in a standard table
+ * format for those PPC systems that do not already have PCI
+ * interrupts properly routed.
+ */
+/* FIXME - double check this */
+#define PCI_IRQ_TABLE_LOOKUP						    \
+({ long _ctl_ = -1; 							    \
+   if (idsel >= min_idsel && idsel <= max_idsel && pin <= irqs_per_slot)    \
+     _ctl_ = pci_irq_table[idsel - min_idsel][pin-1];			    \
+   _ctl_; })
+
+/*
+ * Scan the buses below a given PCI host bridge and assign suitable
+ * resources to all devices found.
+ */
+extern int pciauto_bus_scan(struct pci_controller *, int);
+
 #endif
 #endif /* __KERNEL__ */
diff -urN linux-2.4.20-pre4/include/asm-ppc/serial.h linux-2.4.20-pre5/include/asm-ppc/serial.h
--- linux-2.4.20-pre4/include/asm-ppc/serial.h	Wed Aug 28 16:37:15 2002
+++ linux-2.4.20-pre5/include/asm-ppc/serial.h	Wed Aug 28 16:38:25 2002
@@ -13,6 +13,8 @@
 
 #if defined(CONFIG_GEMINI)
 #include <platforms/gemini_serial.h>
+#elif defined(CONFIG_SPRUCE)
+#include <platforms/spruce.h>
 #elif defined(CONFIG_4xx)
 #include <asm/ppc4xx_serial.h>
 #else
diff -urN linux-2.4.20-pre4/include/asm-ppc/todc.h linux-2.4.20-pre5/include/asm-ppc/todc.h
--- linux-2.4.20-pre4/include/asm-ppc/todc.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre5/include/asm-ppc/todc.h	Wed Aug 28 16:38:25 2002
@@ -0,0 +1,452 @@
+/*
+ * include/asm-ppc/todc.h
+ *
+ * Definitions for the M48Txx and mc146818 series of Time of day/Real Time
+ * Clock chips.
+ *
+ * Author: Mark A. Greer
+ *         mgreer@mvista.com
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+/*
+ * Support for the M48T37/M48T59/.../mc146818 Real Time Clock chips.
+ * Purpose is to make one generic file that handles all of these chips instead
+ * of every platform implementing the same code over & over again.
+ */
+
+#ifndef __PPC_KERNEL_TODC_H
+#define __PPC_KERNEL_TODC_H
+
+typedef struct {
+	uint rtc_type;		/* your particular chip */
+
+	/*
+	 * Following are the addresses of the AS0, AS1, and DATA registers
+	 * of these chips.  Note that these are board-specific.
+	 */
+	unsigned char *nvram_as0;
+	unsigned char *nvram_as1;
+	unsigned char *nvram_data;
+
+	/*
+	 * Define bits to stop external set of regs from changing so
+	 * the chip can be read/written reliably.
+	 */
+	unsigned char enable_read;
+	unsigned char enable_write;
+
+	/*
+	 * Following is the number of AS0 address bits.  This is normally
+	 * 8 but some bad hardware routes address lines incorrectly.
+	 */
+	int as0_bits;
+
+	int nvram_size;	/* Size of NVRAM on chip */
+	int sw_flags;	/* Software control flags */
+
+	/* Following are the register offsets for the particular chip */
+	int year;
+	int month;
+	int day_of_month;
+	int day_of_week;
+	int hours;
+	int minutes;
+	int seconds;
+	int control_b;
+	int control_a;
+	int watchdog;
+	int interrupts;
+	int alarm_date;
+	int alarm_hour;
+	int alarm_minutes;
+	int alarm_seconds;
+	int century;
+	int flags;
+
+	/*
+	 * Some RTC chips have their NVRAM buried behind a addr/data pair of
+	 * regs on the first level/clock registers.  The following fields
+	 * are the addresses for those addr/data regs.
+	 */
+	int nvram_addr_reg;
+	int nvram_data_reg;
+} todc_info_t;
+
+/*
+ * Define the types of TODC/RTC variants that are supported in
+ * arch/ppc/kernel/todc_time.c
+ * Make a new one of these for any chip somehow differs from what's already
+ * defined.  That way, if you ever need to put in code to touch those
+ * bits/registers in todc_time.c, you can put it inside an
+ * 'if (todc_info->rtc_type ==  TODC_TYPE_XXX)' so you won't break
+ * anyone else.
+ */
+#define	TODC_TYPE_MK48T35		1
+#define	TODC_TYPE_MK48T37		2
+#define	TODC_TYPE_MK48T59		3
+#define	TODC_TYPE_DS1693		4	/* Dallas DS1693 RTC */
+#define	TODC_TYPE_DS1743		5	/* Dallas DS1743 RTC */
+#define	TODC_TYPE_DS1746		6	/* Dallas DS1746 RTC */
+#define	TODC_TYPE_DS1747		7	/* Dallas DS1747 RTC */
+#define	TODC_TYPE_DS1501		8	/* Dallas DS1501 RTC */
+#define TODC_TYPE_DS1643		9	/* Dallas DS1643 RTC */
+#define TODC_TYPE_PC97307		10	/* PC97307 internal RTC */
+#define TODC_TYPE_DS1557		11	/* Dallas DS1557 RTC */
+#define	TODC_TYPE_MC146818		100	/* Leave room for m48txx's */
+
+/*
+ * Bit to clear/set to enable reads/writes to the chip
+ */
+#define	TODC_MK48TXX_CNTL_A_R		0x40
+#define	TODC_MK48TXX_CNTL_A_W		0x80
+#define	TODC_MK48TXX_DAY_CB		0x80
+
+#define	TODC_DS1501_CNTL_B_TE		0x80
+
+/*
+ * Define flag bits used by todc routines.
+ */
+#define	TODC_FLAG_2_LEVEL_NVRAM		0x00000001
+
+/*
+ * Define the values for the various RTC's that should to into the todc_info
+ * table.
+ * Note: The XXX_NVRAM_SIZE, XXX_NVRAM_ADDR_REG, and XXX_NVRAM_DATA_REG only
+ * matter if XXX_SW_FLAGS has TODC_FLAG_2_LEVEL_NVRAM set.
+ */
+#define	TODC_TYPE_MK48T35_NVRAM_SIZE		0x7ff8
+#define	TODC_TYPE_MK48T35_SW_FLAGS		0
+#define	TODC_TYPE_MK48T35_YEAR			0x7fff
+#define	TODC_TYPE_MK48T35_MONTH			0x7ffe
+#define	TODC_TYPE_MK48T35_DOM			0x7ffd	/* Day of Month */
+#define	TODC_TYPE_MK48T35_DOW			0x7ffc	/* Day of Week */
+#define	TODC_TYPE_MK48T35_HOURS			0x7ffb
+#define	TODC_TYPE_MK48T35_MINUTES		0x7ffa
+#define	TODC_TYPE_MK48T35_SECONDS		0x7ff9
+#define	TODC_TYPE_MK48T35_CNTL_B		0x7ff9
+#define	TODC_TYPE_MK48T35_CNTL_A		0x7ff8
+#define	TODC_TYPE_MK48T35_WATCHDOG		0x0000
+#define	TODC_TYPE_MK48T35_INTERRUPTS		0x0000
+#define	TODC_TYPE_MK48T35_ALARM_DATE		0x0000
+#define	TODC_TYPE_MK48T35_ALARM_HOUR		0x0000
+#define	TODC_TYPE_MK48T35_ALARM_MINUTES		0x0000
+#define	TODC_TYPE_MK48T35_ALARM_SECONDS		0x0000
+#define	TODC_TYPE_MK48T35_CENTURY		0x0000
+#define	TODC_TYPE_MK48T35_FLAGS			0x0000
+#define	TODC_TYPE_MK48T35_NVRAM_ADDR_REG	0
+#define	TODC_TYPE_MK48T35_NVRAM_DATA_REG	0
+
+#define	TODC_TYPE_MK48T37_NVRAM_SIZE		0x7ff0
+#define	TODC_TYPE_MK48T37_SW_FLAGS		0
+#define	TODC_TYPE_MK48T37_YEAR			0x7fff
+#define	TODC_TYPE_MK48T37_MONTH			0x7ffe
+#define	TODC_TYPE_MK48T37_DOM			0x7ffd	/* Day of Month */
+#define	TODC_TYPE_MK48T37_DOW			0x7ffc	/* Day of Week */
+#define	TODC_TYPE_MK48T37_HOURS			0x7ffb
+#define	TODC_TYPE_MK48T37_MINUTES		0x7ffa
+#define	TODC_TYPE_MK48T37_SECONDS		0x7ff9
+#define	TODC_TYPE_MK48T37_CNTL_B		0x7ff9
+#define	TODC_TYPE_MK48T37_CNTL_A		0x7ff8
+#define	TODC_TYPE_MK48T37_WATCHDOG		0x7ff7
+#define	TODC_TYPE_MK48T37_INTERRUPTS		0x7ff6
+#define	TODC_TYPE_MK48T37_ALARM_DATE		0x7ff5
+#define	TODC_TYPE_MK48T37_ALARM_HOUR		0x7ff4
+#define	TODC_TYPE_MK48T37_ALARM_MINUTES		0x7ff3
+#define	TODC_TYPE_MK48T37_ALARM_SECONDS		0x7ff2
+#define	TODC_TYPE_MK48T37_CENTURY		0x7ff1
+#define	TODC_TYPE_MK48T37_FLAGS			0x7ff0
+#define	TODC_TYPE_MK48T37_NVRAM_ADDR_REG	0
+#define	TODC_TYPE_MK48T37_NVRAM_DATA_REG	0
+
+#define	TODC_TYPE_MK48T59_NVRAM_SIZE		0x1ff0
+#define	TODC_TYPE_MK48T59_SW_FLAGS		0
+#define	TODC_TYPE_MK48T59_YEAR			0x1fff
+#define	TODC_TYPE_MK48T59_MONTH			0x1ffe
+#define	TODC_TYPE_MK48T59_DOM			0x1ffd	/* Day of Month */
+#define	TODC_TYPE_MK48T59_DOW			0x1ffc	/* Day of Week */
+#define	TODC_TYPE_MK48T59_HOURS			0x1ffb
+#define	TODC_TYPE_MK48T59_MINUTES		0x1ffa
+#define	TODC_TYPE_MK48T59_SECONDS		0x1ff9
+#define	TODC_TYPE_MK48T59_CNTL_B		0x1ff9
+#define	TODC_TYPE_MK48T59_CNTL_A		0x1ff8
+#define	TODC_TYPE_MK48T59_WATCHDOG		0x1fff
+#define	TODC_TYPE_MK48T59_INTERRUPTS		0x1fff
+#define	TODC_TYPE_MK48T59_ALARM_DATE		0x1fff
+#define	TODC_TYPE_MK48T59_ALARM_HOUR		0x1fff
+#define	TODC_TYPE_MK48T59_ALARM_MINUTES		0x1fff
+#define	TODC_TYPE_MK48T59_ALARM_SECONDS		0x1fff
+#define	TODC_TYPE_MK48T59_CENTURY		0x1fff
+#define	TODC_TYPE_MK48T59_FLAGS			0x1fff
+#define	TODC_TYPE_MK48T59_NVRAM_ADDR_REG	0
+#define	TODC_TYPE_MK48T59_NVRAM_DATA_REG	0
+
+#define	TODC_TYPE_DS1501_NVRAM_SIZE	0x100
+#define	TODC_TYPE_DS1501_SW_FLAGS	TODC_FLAG_2_LEVEL_NVRAM
+#define	TODC_TYPE_DS1501_YEAR		(TODC_TYPE_DS1501_NVRAM_SIZE + 0x06)
+#define	TODC_TYPE_DS1501_MONTH		(TODC_TYPE_DS1501_NVRAM_SIZE + 0x05)
+#define	TODC_TYPE_DS1501_DOM		(TODC_TYPE_DS1501_NVRAM_SIZE + 0x04)
+#define	TODC_TYPE_DS1501_DOW		(TODC_TYPE_DS1501_NVRAM_SIZE + 0x03)
+#define	TODC_TYPE_DS1501_HOURS		(TODC_TYPE_DS1501_NVRAM_SIZE + 0x02)
+#define	TODC_TYPE_DS1501_MINUTES	(TODC_TYPE_DS1501_NVRAM_SIZE + 0x01)
+#define	TODC_TYPE_DS1501_SECONDS	(TODC_TYPE_DS1501_NVRAM_SIZE + 0x00)
+#define	TODC_TYPE_DS1501_CNTL_B		(TODC_TYPE_DS1501_NVRAM_SIZE + 0x0f)
+#define	TODC_TYPE_DS1501_CNTL_A		(TODC_TYPE_DS1501_NVRAM_SIZE + 0x0f)
+#define	TODC_TYPE_DS1501_WATCHDOG	(TODC_TYPE_DS1501_NVRAM_SIZE + 0xff)
+#define	TODC_TYPE_DS1501_INTERRUPTS	(TODC_TYPE_DS1501_NVRAM_SIZE + 0xff)
+#define	TODC_TYPE_DS1501_ALARM_DATE	(TODC_TYPE_DS1501_NVRAM_SIZE + 0x0b)
+#define	TODC_TYPE_DS1501_ALARM_HOUR	(TODC_TYPE_DS1501_NVRAM_SIZE + 0x0a)
+#define	TODC_TYPE_DS1501_ALARM_MINUTES	(TODC_TYPE_DS1501_NVRAM_SIZE + 0x09)
+#define	TODC_TYPE_DS1501_ALARM_SECONDS	(TODC_TYPE_DS1501_NVRAM_SIZE + 0x08)
+#define	TODC_TYPE_DS1501_CENTURY	(TODC_TYPE_DS1501_NVRAM_SIZE + 0x07)
+#define	TODC_TYPE_DS1501_FLAGS		(TODC_TYPE_DS1501_NVRAM_SIZE + 0xff)
+#define	TODC_TYPE_DS1501_NVRAM_ADDR_REG	0x10
+#define	TODC_TYPE_DS1501_NVRAM_DATA_REG	0x13
+
+#define	TODC_TYPE_DS1557_NVRAM_SIZE		0x7fff0
+#define	TODC_TYPE_DS1557_SW_FLAGS		0
+#define	TODC_TYPE_DS1557_YEAR			0x7ffff
+#define	TODC_TYPE_DS1557_MONTH			0x7fffe
+#define	TODC_TYPE_DS1557_DOM			0x7fffd	/* Day of Month */
+#define	TODC_TYPE_DS1557_DOW			0x7fffc	/* Day of Week */
+#define	TODC_TYPE_DS1557_HOURS			0x7fffb
+#define	TODC_TYPE_DS1557_MINUTES		0x7fffa
+#define	TODC_TYPE_DS1557_SECONDS		0x7fff9
+#define	TODC_TYPE_DS1557_CNTL_B			0x7fff9
+#define	TODC_TYPE_DS1557_CNTL_A			0x7fff8	/* control_a R/W regs */
+#define	TODC_TYPE_DS1557_WATCHDOG		0x7fff7
+#define	TODC_TYPE_DS1557_INTERRUPTS		0x7fff6
+#define	TODC_TYPE_DS1557_ALARM_DATE		0x7fff5
+#define	TODC_TYPE_DS1557_ALARM_HOUR		0x7fff4
+#define	TODC_TYPE_DS1557_ALARM_MINUTES		0x7fff3
+#define	TODC_TYPE_DS1557_ALARM_SECONDS		0x7fff2
+#define	TODC_TYPE_DS1557_CENTURY		0x7fff8
+#define	TODC_TYPE_DS1557_FLAGS			0x7fff0
+#define	TODC_TYPE_DS1557_NVRAM_ADDR_REG		0
+#define	TODC_TYPE_DS1557_NVRAM_DATA_REG		0
+
+#define	TODC_TYPE_DS1643_NVRAM_SIZE		0x1ff8
+#define	TODC_TYPE_DS1643_SW_FLAGS		0
+#define	TODC_TYPE_DS1643_YEAR			0x1fff
+#define	TODC_TYPE_DS1643_MONTH			0x1ffe
+#define	TODC_TYPE_DS1643_DOM			0x1ffd	/* Day of Month */
+#define	TODC_TYPE_DS1643_DOW			0x1ffc	/* Day of Week */
+#define	TODC_TYPE_DS1643_HOURS			0x1ffb
+#define	TODC_TYPE_DS1643_MINUTES		0x1ffa
+#define	TODC_TYPE_DS1643_SECONDS		0x1ff9
+#define	TODC_TYPE_DS1643_CNTL_B			0x1ff9
+#define	TODC_TYPE_DS1643_CNTL_A			0x1ff8	/* control_a R/W regs */
+#define	TODC_TYPE_DS1643_WATCHDOG		0x1fff
+#define	TODC_TYPE_DS1643_INTERRUPTS		0x1fff
+#define	TODC_TYPE_DS1643_ALARM_DATE		0x1fff
+#define	TODC_TYPE_DS1643_ALARM_HOUR		0x1fff
+#define	TODC_TYPE_DS1643_ALARM_MINUTES		0x1fff
+#define	TODC_TYPE_DS1643_ALARM_SECONDS		0x1fff
+#define	TODC_TYPE_DS1643_CENTURY		0x1ff8
+#define	TODC_TYPE_DS1643_FLAGS			0x1fff
+#define	TODC_TYPE_DS1643_NVRAM_ADDR_REG		0
+#define	TODC_TYPE_DS1643_NVRAM_DATA_REG		0
+
+#define	TODC_TYPE_DS1693_NVRAM_SIZE		0 /* Not handled yet */
+#define	TODC_TYPE_DS1693_SW_FLAGS		0
+#define	TODC_TYPE_DS1693_YEAR			0x09
+#define	TODC_TYPE_DS1693_MONTH			0x08
+#define	TODC_TYPE_DS1693_DOM			0x07	/* Day of Month */
+#define	TODC_TYPE_DS1693_DOW			0x06	/* Day of Week */
+#define	TODC_TYPE_DS1693_HOURS			0x04
+#define	TODC_TYPE_DS1693_MINUTES		0x02
+#define	TODC_TYPE_DS1693_SECONDS		0x00
+#define	TODC_TYPE_DS1693_CNTL_B			0x0b
+#define	TODC_TYPE_DS1693_CNTL_A			0x0a
+#define	TODC_TYPE_DS1693_WATCHDOG		0xff
+#define	TODC_TYPE_DS1693_INTERRUPTS		0xff
+#define	TODC_TYPE_DS1693_ALARM_DATE		0x49
+#define	TODC_TYPE_DS1693_ALARM_HOUR		0x05
+#define	TODC_TYPE_DS1693_ALARM_MINUTES		0x03
+#define	TODC_TYPE_DS1693_ALARM_SECONDS		0x01
+#define	TODC_TYPE_DS1693_CENTURY		0x48
+#define	TODC_TYPE_DS1693_FLAGS			0xff
+#define	TODC_TYPE_DS1693_NVRAM_ADDR_REG		0
+#define	TODC_TYPE_DS1693_NVRAM_DATA_REG		0
+
+#define	TODC_TYPE_DS1743_NVRAM_SIZE		0x1ff8
+#define	TODC_TYPE_DS1743_SW_FLAGS		0
+#define	TODC_TYPE_DS1743_YEAR			0x1fff
+#define	TODC_TYPE_DS1743_MONTH			0x1ffe
+#define	TODC_TYPE_DS1743_DOM			0x1ffd	/* Day of Month */
+#define	TODC_TYPE_DS1743_DOW			0x1ffc	/* Day of Week */
+#define	TODC_TYPE_DS1743_HOURS			0x1ffb
+#define	TODC_TYPE_DS1743_MINUTES		0x1ffa
+#define	TODC_TYPE_DS1743_SECONDS		0x1ff9
+#define	TODC_TYPE_DS1743_CNTL_B			0x1ff9
+#define	TODC_TYPE_DS1743_CNTL_A			0x1ff8	/* control_a R/W regs */
+#define	TODC_TYPE_DS1743_WATCHDOG		0x1fff
+#define	TODC_TYPE_DS1743_INTERRUPTS		0x1fff
+#define	TODC_TYPE_DS1743_ALARM_DATE		0x1fff
+#define	TODC_TYPE_DS1743_ALARM_HOUR		0x1fff
+#define	TODC_TYPE_DS1743_ALARM_MINUTES		0x1fff
+#define	TODC_TYPE_DS1743_ALARM_SECONDS		0x1fff
+#define	TODC_TYPE_DS1743_CENTURY		0x1ff8
+#define	TODC_TYPE_DS1743_FLAGS			0x1fff
+#define	TODC_TYPE_DS1743_NVRAM_ADDR_REG		0
+#define	TODC_TYPE_DS1743_NVRAM_DATA_REG		0
+
+#define	TODC_TYPE_DS1746_NVRAM_SIZE		0x1fff8
+#define	TODC_TYPE_DS1746_SW_FLAGS		0
+#define	TODC_TYPE_DS1746_YEAR			0x1ffff
+#define	TODC_TYPE_DS1746_MONTH			0x1fffe
+#define	TODC_TYPE_DS1746_DOM			0x1fffd	/* Day of Month */
+#define	TODC_TYPE_DS1746_DOW			0x1fffc	/* Day of Week */
+#define	TODC_TYPE_DS1746_HOURS			0x1fffb
+#define	TODC_TYPE_DS1746_MINUTES		0x1fffa
+#define	TODC_TYPE_DS1746_SECONDS		0x1fff9
+#define	TODC_TYPE_DS1746_CNTL_B			0x1fff9
+#define	TODC_TYPE_DS1746_CNTL_A			0x1fff8	/* control_a R/W regs */
+#define	TODC_TYPE_DS1746_WATCHDOG		0x00000
+#define	TODC_TYPE_DS1746_INTERRUPTS		0x00000
+#define	TODC_TYPE_DS1746_ALARM_DATE		0x00000
+#define	TODC_TYPE_DS1746_ALARM_HOUR		0x00000
+#define	TODC_TYPE_DS1746_ALARM_MINUTES		0x00000
+#define	TODC_TYPE_DS1746_ALARM_SECONDS		0x00000
+#define	TODC_TYPE_DS1746_CENTURY		0x00000
+#define	TODC_TYPE_DS1746_FLAGS			0x00000
+#define	TODC_TYPE_DS1746_NVRAM_ADDR_REG		0
+#define	TODC_TYPE_DS1746_NVRAM_DATA_REG		0
+
+#define	TODC_TYPE_DS1747_NVRAM_SIZE		0x7fff8
+#define	TODC_TYPE_DS1747_SW_FLAGS		0
+#define	TODC_TYPE_DS1747_YEAR			0x7ffff
+#define	TODC_TYPE_DS1747_MONTH			0x7fffe
+#define	TODC_TYPE_DS1747_DOM			0x7fffd	/* Day of Month */
+#define	TODC_TYPE_DS1747_DOW			0x7fffc	/* Day of Week */
+#define	TODC_TYPE_DS1747_HOURS			0x7fffb
+#define	TODC_TYPE_DS1747_MINUTES		0x7fffa
+#define	TODC_TYPE_DS1747_SECONDS		0x7fff9
+#define	TODC_TYPE_DS1747_CNTL_B			0x7fff9
+#define	TODC_TYPE_DS1747_CNTL_A			0x7fff8	/* control_a R/W regs */
+#define	TODC_TYPE_DS1747_WATCHDOG		0x00000
+#define	TODC_TYPE_DS1747_INTERRUPTS		0x00000
+#define	TODC_TYPE_DS1747_ALARM_DATE		0x00000
+#define	TODC_TYPE_DS1747_ALARM_HOUR		0x00000
+#define	TODC_TYPE_DS1747_ALARM_MINUTES		0x00000
+#define	TODC_TYPE_DS1747_ALARM_SECONDS		0x00000
+#define	TODC_TYPE_DS1747_CENTURY		0x00000
+#define	TODC_TYPE_DS1747_FLAGS			0x00000
+#define	TODC_TYPE_DS1747_NVRAM_ADDR_REG		0
+#define	TODC_TYPE_DS1747_NVRAM_DATA_REG		0
+
+#define	TODC_TYPE_MC146818_NVRAM_SIZE		0	/* XXXX */
+#define	TODC_TYPE_MC146818_SW_FLAGS		0
+#define	TODC_TYPE_MC146818_YEAR			0x09
+#define	TODC_TYPE_MC146818_MONTH		0x08
+#define	TODC_TYPE_MC146818_DOM			0x07	/* Day of Month */
+#define	TODC_TYPE_MC146818_DOW			0x06	/* Day of Week */
+#define	TODC_TYPE_MC146818_HOURS		0x04
+#define	TODC_TYPE_MC146818_MINUTES		0x02
+#define	TODC_TYPE_MC146818_SECONDS		0x00
+#define	TODC_TYPE_MC146818_CNTL_B		0x0a
+#define	TODC_TYPE_MC146818_CNTL_A		0x0b	/* control_a R/W regs */
+#define	TODC_TYPE_MC146818_WATCHDOG		0x0c
+#define	TODC_TYPE_MC146818_INTERRUPTS		0x0d
+#define	TODC_TYPE_MC146818_ALARM_DATE		0xff
+#define	TODC_TYPE_MC146818_ALARM_HOUR		0x05
+#define	TODC_TYPE_MC146818_ALARM_MINUTES	0x03
+#define	TODC_TYPE_MC146818_ALARM_SECONDS	0x01
+#define	TODC_TYPE_MC146818_CENTURY		0xff
+#define	TODC_TYPE_MC146818_FLAGS		0xff
+#define	TODC_TYPE_MC146818_NVRAM_ADDR_REG	0
+#define	TODC_TYPE_MC146818_NVRAM_DATA_REG	0
+
+#define	TODC_TYPE_PC97307_NVRAM_SIZE		0	/* No NVRAM? */
+#define	TODC_TYPE_PC97307_SW_FLAGS		0
+#define	TODC_TYPE_PC97307_YEAR			0x09
+#define	TODC_TYPE_PC97307_MONTH			0x08
+#define	TODC_TYPE_PC97307_DOM			0x07	/* Day of Month */
+#define	TODC_TYPE_PC97307_DOW			0x06	/* Day of Week */
+#define	TODC_TYPE_PC97307_HOURS			0x04
+#define	TODC_TYPE_PC97307_MINUTES		0x02
+#define	TODC_TYPE_PC97307_SECONDS		0x00
+#define	TODC_TYPE_PC97307_CNTL_B		0x0a
+#define	TODC_TYPE_PC97307_CNTL_A		0x0b	/* control_a R/W regs */
+#define	TODC_TYPE_PC97307_WATCHDOG		0x0c
+#define	TODC_TYPE_PC97307_INTERRUPTS		0x0d
+#define	TODC_TYPE_PC97307_ALARM_DATE		0xff
+#define	TODC_TYPE_PC97307_ALARM_HOUR		0x05
+#define	TODC_TYPE_PC97307_ALARM_MINUTES		0x03
+#define	TODC_TYPE_PC97307_ALARM_SECONDS		0x01
+#define	TODC_TYPE_PC97307_CENTURY		0xff
+#define	TODC_TYPE_PC97307_FLAGS			0xff
+#define	TODC_TYPE_PC97307_NVRAM_ADDR_REG	0
+#define	TODC_TYPE_PC97307_NVRAM_DATA_REG	0
+
+/*
+ * Define macros to allocate and init the todc_info_t table that will
+ * be used by the todc_time.c routines.
+ */
+#define	TODC_ALLOC()							\
+	static todc_info_t todc_info_alloc;				\
+	todc_info_t *todc_info = &todc_info_alloc;
+
+#define	TODC_INIT(clock_type, as0, as1, data, bits) {			\
+	todc_info->rtc_type = clock_type;				\
+									\
+	todc_info->nvram_as0  = (unsigned char *)(as0);			\
+	todc_info->nvram_as1  = (unsigned char *)(as1);			\
+	todc_info->nvram_data = (unsigned char *)(data);		\
+									\
+	todc_info->as0_bits = (bits);					\
+									\
+	todc_info->nvram_size     = clock_type ##_NVRAM_SIZE;		\
+	todc_info->sw_flags       = clock_type ##_SW_FLAGS;		\
+									\
+	todc_info->year           = clock_type ##_YEAR;			\
+	todc_info->month          = clock_type ##_MONTH;		\
+	todc_info->day_of_month   = clock_type ##_DOM;			\
+	todc_info->day_of_week    = clock_type ##_DOW;			\
+	todc_info->hours          = clock_type ##_HOURS;		\
+	todc_info->minutes        = clock_type ##_MINUTES;		\
+	todc_info->seconds        = clock_type ##_SECONDS;		\
+	todc_info->control_b      = clock_type ##_CNTL_B;		\
+	todc_info->control_a      = clock_type ##_CNTL_A;		\
+	todc_info->watchdog       = clock_type ##_WATCHDOG;		\
+	todc_info->interrupts     = clock_type ##_INTERRUPTS;		\
+	todc_info->alarm_date     = clock_type ##_ALARM_DATE;		\
+	todc_info->alarm_hour     = clock_type ##_ALARM_HOUR;		\
+	todc_info->alarm_minutes  = clock_type ##_ALARM_MINUTES;	\
+	todc_info->alarm_seconds  = clock_type ##_ALARM_SECONDS;	\
+	todc_info->century        = clock_type ##_CENTURY;		\
+	todc_info->flags          = clock_type ##_FLAGS;		\
+									\
+	todc_info->nvram_addr_reg = clock_type ##_NVRAM_ADDR_REG;	\
+	todc_info->nvram_data_reg = clock_type ##_NVRAM_DATA_REG;	\
+}
+
+#ifndef BCD_TO_BIN
+#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
+#endif
+
+#ifndef BIN_TO_BCD
+#define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)
+#endif
+
+extern todc_info_t *todc_info;
+
+unsigned char todc_direct_read_val(int addr);
+void todc_direct_write_val(int addr, unsigned char val);
+unsigned char todc_m48txx_read_val(int addr);
+void todc_m48txx_write_val(int addr, unsigned char val);
+unsigned char todc_mc146818_read_val(int addr);
+void todc_mc146818_write_val(int addr, unsigned char val);
+
+long todc_time_init(void);
+unsigned long todc_get_rtc_time(void);
+int todc_set_rtc_time(unsigned long nowtime);
+void todc_calibrate_decr(void);
+
+#endif				/* __PPC_KERNEL_TODC_H */
diff -urN linux-2.4.20-pre4/include/asm-ppc64/byteorder.h linux-2.4.20-pre5/include/asm-ppc64/byteorder.h
--- linux-2.4.20-pre4/include/asm-ppc64/byteorder.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/include/asm-ppc64/byteorder.h	Wed Aug 28 16:38:25 2002
@@ -2,8 +2,6 @@
 #define _PPC64_BYTEORDER_H
 
 /*
- *  
- *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version
diff -urN linux-2.4.20-pre4/include/asm-ppc64/delay.h linux-2.4.20-pre5/include/asm-ppc64/delay.h
--- linux-2.4.20-pre4/include/asm-ppc64/delay.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/include/asm-ppc64/delay.h	Wed Aug 28 16:38:25 2002
@@ -13,6 +13,7 @@
  * Anton Blanchard.
  */
 
+#ifndef __ASSEMBLY__
 extern unsigned long tb_ticks_per_usec;
 
 /* define these here to prevent circular dependencies */ 
@@ -42,5 +43,6 @@
 	__delay(loops);
 	__HMT_medium();
 }
+#endif /* !__ASSEMBLY__ */
 
 #endif /* _PPC64_DELAY_H */
diff -urN linux-2.4.20-pre4/include/asm-ppc64/dump.h linux-2.4.20-pre5/include/asm-ppc64/dump.h
--- linux-2.4.20-pre4/include/asm-ppc64/dump.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre5/include/asm-ppc64/dump.h	Wed Aug 28 16:38:25 2002
@@ -0,0 +1,112 @@
+/*
+ * Kernel header file for Linux crash dumps.
+ *
+ * Created by: Todd Inglett <tinglett@vnet.ibm.com>
+ *
+ * Copyright 2002 International Business Machines
+ *
+ * This code is released under version 2 of the GNU GPL.
+ */
+
+/* This header file holds the architecture specific crash dump header */
+#ifndef _ASM_DUMP_H
+#define _ASM_DUMP_H
+
+/* necessary header files */
+#include <asm/ptrace.h>                          /* for pt_regs             */
+#include <linux/threads.h>
+
+/* definitions */
+#define DUMP_ASM_MAGIC_NUMBER     0xdeaddeadULL  /* magic number            */
+#define DUMP_ASM_VERSION_NUMBER   0x1            /* version number          */
+
+
+/*
+ * Structure: dump_header_asm_t
+ *  Function: This is the header for architecture-specific stuff.  It
+ *            follows right after the dump header.
+ */
+typedef struct _dump_header_asm_s {
+
+        /* the dump magic number -- unique to verify dump is valid */
+        uint64_t             dha_magic_number;
+
+        /* the version number of this dump */
+        uint32_t             dha_version;
+
+        /* the size of this header (in case we can't read it) */
+        uint32_t             dha_header_size;
+
+	/* the dump registers */
+	struct pt_regs       dha_regs;
+
+	/* smp specific */
+	uint32_t	     dha_smp_num_cpus;
+	int		     dha_dumping_cpu;	
+	struct pt_regs	     dha_smp_regs[NR_CPUS];
+	void *		     dha_smp_current_task[NR_CPUS];
+	void *		     dha_stack[NR_CPUS];
+} dump_header_asm_t;
+
+#ifdef __KERNEL__
+static inline void get_current_regs(struct pt_regs *regs)
+{
+	__asm__ __volatile__ (
+		"std	0,0(%0)\n"
+		"std	1,8(%0)\n"
+		"std	2,16(%0)\n"
+		"std	3,24(%0)\n"
+		"std	4,32(%0)\n"
+		"std	5,40(%0)\n"
+		"std	6,48(%0)\n"
+		"std	7,56(%0)\n"
+		"std	8,64(%0)\n"
+		"std	9,72(%0)\n"
+		"std	10,80(%0)\n"
+		"std	11,88(%0)\n"
+		"std	12,96(%0)\n"
+		"std	13,104(%0)\n"
+		"std	14,112(%0)\n"
+		"std	15,120(%0)\n"
+		"std	16,128(%0)\n"
+		"std	17,136(%0)\n"
+		"std	18,144(%0)\n"
+		"std	19,152(%0)\n"
+		"std	20,160(%0)\n"
+		"std	21,168(%0)\n"
+		"std	22,176(%0)\n"
+		"std	23,184(%0)\n"
+		"std	24,192(%0)\n"
+		"std	25,200(%0)\n"
+		"std	26,208(%0)\n"
+		"std	27,216(%0)\n"
+		"std	28,224(%0)\n"
+		"std	29,232(%0)\n"
+		"std	30,240(%0)\n"
+		"std	31,248(%0)\n"
+		"mfmsr	0\n"
+		"std	0, 264(%0)\n"
+		"mfctr	0\n"
+		"std	0, 280(%0)\n"
+		"mflr	0\n"
+		"std	0, 288(%0)\n"
+		"bl	1f\n"
+	"1:	 mflr	5\n"
+		"std	5, 256(%0)\n"
+		"mtlr	0\n"
+		"mfxer	0\n"
+		"std	0, 296(%0)\n"
+			      : : "b" (&regs));
+}
+
+extern volatile int dump_in_progress;
+extern dump_header_asm_t dump_header_asm;
+
+#ifdef CONFIG_SMP
+extern void dump_send_ipi(int (*dump_ipi_callback)(struct pt_regs *));
+#else
+#define dump_send_ipi()
+#endif
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_DUMP_H */
diff -urN linux-2.4.20-pre4/include/asm-ppc64/eeh.h linux-2.4.20-pre5/include/asm-ppc64/eeh.h
--- linux-2.4.20-pre4/include/asm-ppc64/eeh.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/include/asm-ppc64/eeh.h	Wed Aug 28 16:38:25 2002
@@ -149,4 +149,38 @@
 	memcpy(vdest, src, n);
 }
 
+static inline void eeh_insb(volatile u8 *addr, void *buf, int n) {
+	volatile u8 *vaddr = (volatile u8 *)IO_TOKEN_TO_ADDR(addr);
+	_insb(vaddr, buf, n);
+	/* ToDo: look for ff's in buf[n] */
+}
+
+static inline void eeh_outsb(volatile u8 *addr, const void *buf, int n) {
+	volatile u8 *vaddr = (volatile u8 *)IO_TOKEN_TO_ADDR(addr);
+	_outsb(vaddr, buf, n);
+}
+
+static inline void eeh_insw_ns(volatile u16 *addr, void *buf, int n) {
+	volatile u16 *vaddr = (volatile u16 *)IO_TOKEN_TO_ADDR(addr);
+	_insw_ns(vaddr, buf, n);
+	/* ToDo: look for ffff's in buf[n] */
+}
+
+static inline void eeh_outsw_ns(volatile u16 *addr, const void *buf, int n) {
+	volatile u16 *vaddr = (volatile u16 *)IO_TOKEN_TO_ADDR(addr);
+	_outsw_ns(vaddr, buf, n);
+}
+
+static inline void eeh_insl_ns(volatile u32 *addr, void *buf, int n) {
+	volatile u32 *vaddr = (volatile u32 *)IO_TOKEN_TO_ADDR(addr);
+	_insl_ns(vaddr, buf, n);
+	/* ToDo: look for ffffffff's in buf[n] */
+}
+
+static inline void eeh_outsl_ns(volatile u32 *addr, const void *buf, int n) {
+	volatile u32 *vaddr = (volatile u32 *)IO_TOKEN_TO_ADDR(addr);
+	_outsl_ns(vaddr, buf, n);
+}
+
+
 #endif /* _EEH_H */
diff -urN linux-2.4.20-pre4/include/asm-ppc64/fcntl.h linux-2.4.20-pre5/include/asm-ppc64/fcntl.h
--- linux-2.4.20-pre4/include/asm-ppc64/fcntl.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/include/asm-ppc64/fcntl.h	Wed Aug 28 16:38:25 2002
@@ -26,7 +26,7 @@
 #define O_DIRECTORY      040000	/* must be a directory */
 #define O_NOFOLLOW      0100000	/* don't follow links */
 #define O_LARGEFILE     0200000
-#define O_DIRECT	0400000	/* direct disk access hint - currently ignored */
+#define O_DIRECT	0400000	/* direct disk access hint */
 
 #define F_DUPFD		0	/* dup */
 #define F_GETFD		1	/* get close_on_exec */
diff -urN linux-2.4.20-pre4/include/asm-ppc64/hvcall.h linux-2.4.20-pre5/include/asm-ppc64/hvcall.h
--- linux-2.4.20-pre4/include/asm-ppc64/hvcall.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre5/include/asm-ppc64/hvcall.h	Wed Aug 28 16:38:25 2002
@@ -0,0 +1,85 @@
+
+#define H_Success	0
+#define H_Busy		1	/* Hardware busy -- retry later */
+#define H_Hardware	-1	/* Hardware error */
+#define H_Function	-2	/* Function not supported */
+#define H_Privilege	-3	/* Caller not privileged */
+#define H_Parameter	-4	/* Parameter invalid, out-of-range or conflicting */
+#define H_Bad_Mode	-5	/* Illegal msr value */
+#define H_PTEG_Full	-6	/* PTEG is full */
+#define H_Not_Found	-7	/* PTE was not found" */
+#define H_Reserved_DABR	-8	/* DABR address is reserved by the hypervisor on this processor" */
+
+/* Flags */
+#define H_LARGE_PAGE		(1UL<<(63-16))
+#define H_EXACT		    (1UL<<(63-24))	/* Use exact PTE or return H_PTEG_FULL */
+#define H_R_XLATE		(1UL<<(63-25))	/* include a valid logical page num in the pte if the valid bit is set */
+#define H_READ_4		(1UL<<(63-26))	/* Return 4 PTEs */
+#define H_AVPN			(1UL<<(63-32))	/* An avpn is provided as a sanity test */
+#define H_ANDCOND		(1UL<<(63-33))
+#define H_ICACHE_INVALIDATE	(1UL<<(63-40))	/* icbi, etc.  (ignored for IO pages) */
+#define H_ICACHE_SYNCHRONIZE	(1UL<<(63-41))	/* dcbst, icbi, etc (ignored for IO pages */
+#define H_ZERO_PAGE		(1UL<<(63-48))	/* zero the page before mapping (ignored for IO pages) */
+#define H_COPY_PAGE		(1UL<<(63-49))
+#define H_N			(1UL<<(63-61))
+#define H_PP1			(1UL<<(63-62))
+#define H_PP2			(1UL<<(63-63))
+
+
+
+/* pSeries hypervisor opcodes */
+#define H_REMOVE		0x04
+#define H_ENTER			0x08
+#define H_READ			0x0c
+#define H_CLEAR_MOD		0x10
+#define H_CLEAR_REF		0x14
+#define H_PROTECT		0x18
+#define H_GET_TCE		0x1c
+#define H_PUT_TCE		0x20
+#define H_SET_SPRG0		0x24
+#define H_SET_DABR		0x28
+#define H_PAGE_INIT		0x2c
+#define H_SET_ASR		0x30
+#define H_ASR_ON		0x34
+#define H_ASR_OFF		0x38
+#define H_LOGICAL_CI_LOAD	0x3c
+#define H_LOGICAL_CI_STORE	0x40
+#define H_LOGICAL_CACHE_LOAD	0x44
+#define H_LOGICAL_CACHE_STORE	0x48
+#define H_LOGICAL_ICBI		0x4c
+#define H_LOGICAL_DCBF		0x50
+#define H_GET_TERM_CHAR		0x54
+#define H_PUT_TERM_CHAR		0x58
+#define H_REAL_TO_LOGICAL	0x5c
+#define H_HYPERVISOR_DATA	0x60
+#define H_EOI			0x64
+#define H_CPPR			0x68
+#define H_IPI			0x6c
+#define H_IPOLL			0x70
+#define H_XIRR			0x74
+
+#define HSC			".long 0x44000022\n"
+#define H_ENTER_r3		"li	3, 0x08\n"
+
+/* plpar_hcall() -- Generic call interface using above opcodes
+ *
+ * The actual call interface is a hypervisor call instruction with
+ * the opcode in R3 and input args in R4-R7.
+ * Status is returned in R3 with variable output values in R4-R11.
+ * Only H_PTE_READ with H_READ_4 uses R6-R11 so we ignore it for now
+ * and return only two out args which MUST ALWAYS BE PROVIDED.
+ */
+long plpar_hcall(unsigned long opcode,
+		 unsigned long arg1,
+		 unsigned long arg2,
+		 unsigned long arg3,
+		 unsigned long arg4,
+		 unsigned long *out1,
+		 unsigned long *out2,
+		 unsigned long *out3);
+
+/* Same as plpar_hcall but for those opcodes that return no values
+ * other than status.  Slightly more efficient.
+ */
+long plpar_hcall_norets(unsigned long opcode, ...);
+
diff -urN linux-2.4.20-pre4/include/asm-ppc64/iSeries/HvCall.h linux-2.4.20-pre5/include/asm-ppc64/iSeries/HvCall.h
--- linux-2.4.20-pre4/include/asm-ppc64/iSeries/HvCall.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/include/asm-ppc64/iSeries/HvCall.h	Wed Aug 28 16:38:25 2002
@@ -130,6 +130,9 @@
 #define HvCallBaseRouter28				HvCallBase + 28
 #define HvCallBaseRouter29				HvCallBase + 29
 #define HvCallBaseRouter30				HvCallBase + 30
+
+#define HvCallCcSetDABR  				HvCallCc + 7
+
 //=====================================================================================
 static inline void		HvCall_setVirtualDecr(void)
 {
@@ -197,6 +200,10 @@
 	HvCall0( HvCallBaseTerminateMachineSrc );
 }
 
+static inline void HvCall_setDABR(unsigned long val)
+{
+	HvCall1(HvCallCcSetDABR, val);
+}
 
 #endif // _HVCALL_H
 
diff -urN linux-2.4.20-pre4/include/asm-ppc64/iSeries/HvCallSc.h linux-2.4.20-pre5/include/asm-ppc64/iSeries/HvCallSc.h
--- linux-2.4.20-pre4/include/asm-ppc64/iSeries/HvCallSc.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/include/asm-ppc64/iSeries/HvCallSc.h	Wed Aug 28 16:38:25 2002
@@ -25,6 +25,7 @@
 #define _HVCALLSC_H
 
 #define HvCallBase		0x8000000000000000
+#define HvCallCc		0x8001000000000000
 #define HvCallCfg		0x8002000000000000
 #define HvCallEvent		0x8003000000000000
 #define HvCallHpt		0x8004000000000000
diff -urN linux-2.4.20-pre4/include/asm-ppc64/iSeries/ItExtVpdPanel.h linux-2.4.20-pre5/include/asm-ppc64/iSeries/ItExtVpdPanel.h
--- linux-2.4.20-pre4/include/asm-ppc64/iSeries/ItExtVpdPanel.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre5/include/asm-ppc64/iSeries/ItExtVpdPanel.h	Wed Aug 28 16:38:25 2002
@@ -0,0 +1,60 @@
+/*
+ * ItExtVpdPanel.h
+ * Copyright (C) 2002  Dave Boutcher IBM Corporation
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+/*
+ *
+ *	This struct maps the panel information 
+ *
+ * Warning:
+ *	This data must match the architecture for the panel information
+ *
+ */
+
+
+/*-------------------------------------------------------------------
+ * Standard Includes
+ *------------------------------------------------------------------- 
+*/
+#ifndef	_PPC_TYPES_H
+#include	<asm/types.h>
+#endif
+
+#ifndef _ITEXTVPDPANEL_H
+#define _ITEXTVPDPANEL_H
+struct ItExtVpdPanel
+{
+  // Definition of the Extended Vpd On Panel Data Area
+  char                      systemSerial[8];
+  char                      mfgID[4];
+  char                      reserved1[24];
+  char                      machineType[4];
+  char                      systemID[6];
+  char                      somUniqueCnt[4];
+  char                      serialNumberCount;
+  char                      reserved2[7];
+  u16                       bbu3;
+  u16                       bbu2;
+  u16                       bbu1;
+  char                      xLocationLabel[8];
+  u8                        xRsvd1[6];
+  u16                       xFrameId;
+  u8                        xRsvd2[48];
+};
+
+#endif /* _ITEXTVPDPANEL_H  */
diff -urN linux-2.4.20-pre4/include/asm-ppc64/iSeries/LparData.h linux-2.4.20-pre5/include/asm-ppc64/iSeries/LparData.h
--- linux-2.4.20-pre4/include/asm-ppc64/iSeries/LparData.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/include/asm-ppc64/iSeries/LparData.h	Wed Aug 28 16:38:25 2002
@@ -37,6 +37,7 @@
 #include <asm/iSeries/LparMap.h>
 #include <asm/iSeries/ItVpdAreas.h>
 #include <asm/iSeries/ItIplParmsReal.h>
+#include <asm/iSeries/ItExtVpdPanel.h>
 #include <asm/iSeries/ItLpQueue.h>
 #include <asm/iSeries/IoHriProcessorVpd.h>
 #include <asm/page.h>
@@ -45,6 +46,7 @@
 extern struct HvReleaseData hvReleaseData;
 extern struct ItLpNaca	itLpNaca;
 extern struct ItIplParmsReal xItIplParmsReal;
+extern struct ItExtVpdPanel xItExtVpdPanel;
 extern struct IoHriProcessorVpd xIoHriProcessorVpd[];
 extern struct ItLpQueue xItLpQueue;
 extern struct ItVpdAreas itVpdAreas;
diff -urN linux-2.4.20-pre4/include/asm-ppc64/iSeries/iSeries_pci.h linux-2.4.20-pre5/include/asm-ppc64/iSeries/iSeries_pci.h
--- linux-2.4.20-pre4/include/asm-ppc64/iSeries/iSeries_pci.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/include/asm-ppc64/iSeries/iSeries_pci.h	Wed Aug 28 16:38:25 2002
@@ -89,7 +89,8 @@
 	int              Flags;          /* Possible flags(disable/bist)*/
 	u16              Vendor;         /* Vendor ID                   */
 	u8               LogicalSlot;    /* Hv Slot Index for Tces      */
-	struct TceTable* DevTceTable;    /* Device TCE Table            */ 
+	struct TceTable* DevTceTable;    /* Device TCE Table            */
+	spinlock_t       IoLock;	 /* Lock to single thread device*/
 	u8               PhbId;          /* Phb Card is on.             */
 	u16              Board;          /* Board Number                */
 	u8               FrameId;	 /* iSeries spcn Frame Id       */
diff -urN linux-2.4.20-pre4/include/asm-ppc64/io.h linux-2.4.20-pre5/include/asm-ppc64/io.h
--- linux-2.4.20-pre4/include/asm-ppc64/io.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/include/asm-ppc64/io.h	Wed Aug 28 16:38:25 2002
@@ -40,7 +40,7 @@
 #define writeb(data, addr)	iSeries_Write_Byte(data,((void*)(addr)))
 #define writew(data, addr)	iSeries_Write_Word(data,((void*)(addr)))
 #define writel(data, addr)	iSeries_Write_Long(data,((void*)(addr)))
-#define memset_io(a,b,c)	iSeries_memset((void *)(a),(b),(c))
+#define memset_io(a,b,c)	iSeries_memset_io((void *)(a),(b),(c))
 #define memcpy_fromio(a,b,c)	iSeries_memcpy_fromio((void *)(a), (void *)(b), (c))
 #define memcpy_toio(a,b,c)	iSeries_memcpy_toio((void *)(a), (void *)(b), (c))
 #define inb(addr)		readb(((unsigned long)(addr)))  
@@ -57,7 +57,7 @@
 #define writeb(data, addr)	eeh_writeb((data), ((void*)(addr)))
 #define writew(data, addr)	eeh_writew((data), ((void*)(addr)))
 #define writel(data, addr)	eeh_writel((data), ((void*)(addr)))
-#define memset_io(a,b,c)	eeh_memset((void *)(a),(b),(c))
+#define memset_io(a,b,c)	eeh_memset_io((void *)(a),(b),(c))
 #define memcpy_fromio(a,b,c)	eeh_memcpy_fromio((a),(void *)(b),(c))
 #define memcpy_toio(a,b,c)	eeh_memcpy_toio((void *)(a),(b),(c))
 #define inb(port)		_inb((unsigned long)port)
@@ -66,6 +66,18 @@
 #define outw(val, port)		_outw(val, (unsigned long)port)
 #define inl(port)		_inl((unsigned long)port)
 #define outl(val, port)		_outl(val, (unsigned long)port)
+
+/*
+ * The insw/outsw/insl/outsl macros don't do byte-swapping.
+ * They are only used in practice for transferring buffers which
+ * are arrays of bytes, and byte-swapping is not appropriate in
+ * that case.  - paulus */
+#define insb(port, buf, ns)	eeh_insb((u8 *)(port), (buf), (ns))
+#define outsb(port, buf, ns)	eeh_outsb((u8 *)(port), (buf), (ns))
+#define insw(port, buf, ns)	eeh_insw_ns((u16 *)(port), (buf), (ns))
+#define outsw(port, buf, ns)	eeh_outsw_ns((u16 *)(port), (buf), (ns))
+#define insl(port, buf, nl)	eeh_insl_ns((u32 *)(port), (buf), (nl))
+#define outsl(port, buf, nl)	eeh_outsl_ns((u32 *)(port), (buf), (nl))
 #endif
 
 
@@ -80,18 +92,6 @@
 #define inl_p(port)             inl(port)
 #define outl_p(val, port)       (udelay(1), outl((val, (port)))
 
-/*
- * The insw/outsw/insl/outsl macros don't do byte-swapping.
- * They are only used in practice for transferring buffers which
- * are arrays of bytes, and byte-swapping is not appropriate in
- * that case.  - paulus */
-#define _IOMAP_VADDR(port) (IS_MAPPED_VADDR(port) ? (port) : (port)+_IO_BASE)
-#define insb(port, buf, ns)	_insb((u8 *)(_IOMAP_VADDR(port)), (buf), (ns))
-#define outsb(port, buf, ns)	_outsb((u8 *)(_IOMAP_VADDR(port)), (buf), (ns))
-#define insw(port, buf, ns)	_insw_ns((u16 *)(_IOMAP_VADDR(port)), (buf), (ns))
-#define outsw(port, buf, ns)	_outsw_ns((u16 *)(_IOMAP_VADDR(port)), (buf), (ns))
-#define insl(port, buf, nl)	_insl_ns((u32 *)(_IOMAP_VADDR(port)), (buf), (nl))
-#define outsl(port, buf, nl)	_outsl_ns((u32 *)(_IOMAP_VADDR(port)), (buf), (nl))
 
 extern void _insb(volatile u8 *port, void *buf, int ns);
 extern void _outsb(volatile u8 *port, const void *buf, int ns);
@@ -109,10 +109,10 @@
  * Neither do the standard versions now, these are just here
  * for older code.
  */
-#define insw_ns(port, buf, ns)	_insw_ns((u16 *)(_IOMAP_VADDR(port)), (buf), (ns))
-#define outsw_ns(port, buf, ns)	_outsw_ns((u16 *)(_IOMAP_VADDR(port)), (buf), (ns))
-#define insl_ns(port, buf, nl)	_insl_ns((u32 *)(_IOMAP_VADDR(port)), (buf), (nl))
-#define outsl_ns(port, buf, nl)	_outsl_ns((u32 *)(_IOMAP_VADDR(port)), (buf), (nl))
+#define insw_ns(port, buf, ns)	insw(port, buf, ns)
+#define outsw_ns(port, buf, ns)	outsw(port, buf, ns)
+#define insl_ns(port, buf, nl)	insl(port, buf, nl)
+#define outsl_ns(port, buf, nl)	outsl(port, buf, nl)
 
 
 #define IO_SPACE_LIMIT ~(0UL)
@@ -134,7 +134,7 @@
  * Change virtual addresses to physical addresses and vv, for
  * addresses in the area where the kernel has the RAM mapped.
  */
-extern inline unsigned long virt_to_phys(volatile void * address)
+static inline unsigned long virt_to_phys(volatile void * address)
 {
 #ifdef __IO_DEBUG
 	printk("virt_to_phys: 0x%08lx -> 0x%08lx\n", 
@@ -144,17 +144,22 @@
 	return __pa((unsigned long)address);
 }
 
-extern inline void * phys_to_virt(unsigned long address)
+static inline void * phys_to_virt(unsigned long address)
 {
 #ifdef __IO_DEBUG
 	printk("phys_to_virt: 0x%08lx -> 0x%08lx\n", address, __va(address));
 #endif
 	return (void *) __va(address);
 }
+ 
+/*
+ * Change "struct page" to physical address.
+ */
+#define page_to_phys(page)	((page - mem_map) << PAGE_SHIFT)
 
 #endif /* __KERNEL__ */
 
-extern inline void iosync(void)
+static inline void iosync(void)
 {
         __asm__ __volatile__ ("sync" : : : "memory");
 }
@@ -172,7 +177,7 @@
  * excess of syncs before the MMIO operations will make things work.  On 
  * sstar, sync time is << than mmio time, so this should not be a big impact.
  */
-extern inline int in_8(volatile unsigned char *addr)
+static inline int in_8(volatile unsigned char *addr)
 {
 	int ret;
 
@@ -180,12 +185,12 @@
 	return ret;
 }
 
-extern inline void out_8(volatile unsigned char *addr, int val)
+static inline void out_8(volatile unsigned char *addr, int val)
 {
 	__asm__ __volatile__("sync; stb%U0%X0 %1,%0; sync" : "=m" (*addr) : "r" (val));
 }
 
-extern inline int in_le16(volatile unsigned short *addr)
+static inline int in_le16(volatile unsigned short *addr)
 {
 	int ret;
 
@@ -194,7 +199,7 @@
 	return ret;
 }
 
-extern inline int in_be16(volatile unsigned short *addr)
+static inline int in_be16(volatile unsigned short *addr)
 {
 	int ret;
 
@@ -202,18 +207,18 @@
 	return ret;
 }
 
-extern inline void out_le16(volatile unsigned short *addr, int val)
+static inline void out_le16(volatile unsigned short *addr, int val)
 {
 	__asm__ __volatile__("sync; sthbrx %1,0,%2; sync" : "=m" (*addr) :
 			      "r" (val), "r" (addr));
 }
 
-extern inline void out_be16(volatile unsigned short *addr, int val)
+static inline void out_be16(volatile unsigned short *addr, int val)
 {
 	__asm__ __volatile__("sync; sth%U0%X0 %1,%0; sync" : "=m" (*addr) : "r" (val));
 }
 
-extern inline unsigned in_le32(volatile unsigned *addr)
+static inline unsigned in_le32(volatile unsigned *addr)
 {
 	unsigned ret;
 
@@ -222,7 +227,7 @@
 	return ret;
 }
 
-extern inline unsigned in_be32(volatile unsigned *addr)
+static inline unsigned in_be32(volatile unsigned *addr)
 {
 	unsigned ret;
 
@@ -230,13 +235,13 @@
 	return ret;
 }
 
-extern inline void out_le32(volatile unsigned *addr, int val)
+static inline void out_le32(volatile unsigned *addr, int val)
 {
 	__asm__ __volatile__("sync; stwbrx %1,0,%2; sync" : "=m" (*addr) :
 			     "r" (val), "r" (addr));
 }
 
-extern inline void out_be32(volatile unsigned *addr, int val)
+static inline void out_be32(volatile unsigned *addr, int val)
 {
 	__asm__ __volatile__("sync; stw%U0%X0 %1,%0; sync" : "=m" (*addr) : "r" (val));
 }
diff -urN linux-2.4.20-pre4/include/asm-ppc64/lmb.h linux-2.4.20-pre5/include/asm-ppc64/lmb.h
--- linux-2.4.20-pre4/include/asm-ppc64/lmb.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/include/asm-ppc64/lmb.h	Wed Aug 28 16:38:25 2002
@@ -27,6 +27,9 @@
 #define LMB_MEMORY_AREA	1
 #define LMB_IO_AREA	2
 
+#define LMB_ALLOC_ANYWHERE	0
+#define LMB_ALLOC_FIRST4GBYTE	(1UL<<32)
+
 struct lmb_property {
 	unsigned long base;
 	unsigned long physbase;
@@ -44,6 +47,7 @@
 
 struct lmb {
 	unsigned long debug;
+	unsigned long rmo_size;
 	struct lmb_region memory;
 	struct lmb_region reserved;
 };
@@ -58,6 +62,7 @@
 #endif /* CONFIG_MSCHUNKS */
 extern long lmb_reserve(unsigned long, unsigned long);
 extern unsigned long lmb_alloc(unsigned long, unsigned long);
+extern unsigned long lmb_alloc_base(unsigned long, unsigned long, unsigned long);
 extern unsigned long lmb_phys_mem_size(void);
 extern unsigned long lmb_end_of_DRAM(void);
 extern unsigned long lmb_abs_to_phys(unsigned long);
diff -urN linux-2.4.20-pre4/include/asm-ppc64/machdep.h linux-2.4.20-pre5/include/asm-ppc64/machdep.h
--- linux-2.4.20-pre4/include/asm-ppc64/machdep.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/include/asm-ppc64/machdep.h	Wed Aug 28 16:38:25 2002
@@ -10,7 +10,6 @@
  */
 
 #include <linux/config.h>
-#include <linux/seq_file.h>
 
 struct pt_regs;
 struct pci_bus;	
@@ -21,29 +20,24 @@
 struct rtc_time;
 
 struct machdep_calls {
-	/* High use functions in the first cachelines, low use functions
-	 * follow.  DRENG collect profile data.
-	 */
-	void            (*hpte_invalidate)(unsigned long slot);
-
-	void            (*hpte_updatepp)(long slot, 
+	void            (*hpte_invalidate)(unsigned long slot,
+					   unsigned long secondary,  
+					   unsigned long va, 
+					   int large, int local);
+	long            (*hpte_updatepp)(unsigned long slot,
+					 unsigned long secondary,  
 					 unsigned long newpp, 
-					 unsigned long va);
+					 unsigned long va,
+					 int large);
 	void            (*hpte_updateboltedpp)(unsigned long newpp, 
 					       unsigned long ea);
-	unsigned long	(*hpte_getword0)(unsigned long slot);
-
-	long		(*hpte_find)( unsigned long vpn );
-
-	long		(*hpte_selectslot)(unsigned long vpn); 
-
-	void		(*hpte_create_valid)(unsigned long slot,
-					     unsigned long vpn,
-					     unsigned long prpn,
-					     unsigned hash, 
-					     void * ptep,
-					     unsigned hpteflags, 
-					     unsigned bolted);
+	long		(*hpte_insert)(unsigned long vpn,
+				       unsigned long prpn,
+				       unsigned long hpteflags, 
+				       int bolted,
+				       int large);
+	long		(*hpte_remove)(unsigned long hpte_group);
+	
 	void		(*tce_build)(struct TceTable * tbl,
 				     long tcenum,
 				     unsigned long uaddr,
@@ -69,7 +63,6 @@
 	void		(*init_IRQ)(void);
 	void		(*init_ras_IRQ)(void);
 	int		(*get_irq)(struct pt_regs *);
-	void		(*post_irq)( struct pt_regs *, int );
 	
 	/* A general init function, called by ppc_init in init/main.c.
 	   May be NULL. */
@@ -87,6 +80,7 @@
 
   	void		(*progress)(char *, unsigned short);
 
+
 	unsigned char 	(*nvram_read_val)(int addr);
 	void		(*nvram_write_val)(int addr, unsigned char val);
 
@@ -146,5 +140,22 @@
 
 extern void setup_pci_ptrs(void);
 
+
+/* Functions to produce codes on the leds.
+ * The SRC code should be unique for the message category and should
+ * be limited to the lower 24 bits (the upper 8 are set by these funcs),
+ * and (for boot & dump) should be sorted numerically in the order
+ * the events occur.
+ */
+/* Print a boot progress message. */
+void ppc64_boot_msg(unsigned int src, const char *msg);
+/* Print a termination message (print only -- does not stop the kernel) */
+void ppc64_terminate_msg(unsigned int src, const char *msg);
+/* Print something that needs attention (device error, etc) */
+void ppc64_attention_msg(unsigned int src, const char *msg);
+/* Print a dump progress message. */
+void ppc64_dump_msg(unsigned int src, const char *msg);
+
+
 #endif /* _PPC_MACHDEP_H */
 #endif /* __KERNEL__ */
diff -urN linux-2.4.20-pre4/include/asm-ppc64/mmu.h linux-2.4.20-pre5/include/asm-ppc64/mmu.h
--- linux-2.4.20-pre4/include/asm-ppc64/mmu.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/include/asm-ppc64/mmu.h	Wed Aug 28 16:38:25 2002
@@ -107,7 +107,7 @@
 	unsigned long avpn:57; /* vsid | api == avpn  */
 	unsigned long :     2; /* Software use */
 	unsigned long bolted: 1; /* HPTE is "bolted" */
-	unsigned long :     1; /* Software use */
+	unsigned long lock: 1; /* lock on pSeries SMP */
 	unsigned long l:    1; /* Virtual page is large (L=1) or 4 KB (L=0) */
 	unsigned long h:    1; /* Hash function identifier */
 	unsigned long v:    1; /* Valid (v=1) or invalid (v=0) */
@@ -128,7 +128,7 @@
 
 typedef struct {
 	unsigned long pp0:  1; /* Page protection bit 0 */
-	unsigned long :     1; /* Reserved */
+	unsigned long ts:   1; /* Tag set bit */
 	unsigned long rpn: 50; /* Real page number */
 	unsigned long :     2; /* Reserved */
 	unsigned long ac:   1; /* Address compare */ 
@@ -156,21 +156,8 @@
 
 	union {
 		unsigned long dword1;
-		struct {
-			unsigned long pp0:  1; /* Page protection bit 0 */
-			unsigned long ts:   1; /* Tag set bit */ 
-			unsigned long rpn: 50; /* Real page number */
-			unsigned long :     2; /* Unused */
-			unsigned long ac:   1; /* Address compare bit */
-			unsigned long r:    1; /* Referenced */
-			unsigned long c:    1; /* Changed */
-			unsigned long w:    1; /* Write-thru cache mode */
-			unsigned long i:    1; /* Cache inhibited */
-			unsigned long m:    1; /* Memory coherence */
-			unsigned long g:    1; /* Guarded */
-			unsigned long n:    1; /* No-execute page if N=1 */
-			unsigned long pp:   2; /* Page protection bit 1:2 */
-		} dw1;
+		Hpte_dword1 dw1;
+		Hpte_dword1_flags flags;
 	} dw1;
 } HPTE; 
 
@@ -204,6 +191,8 @@
 #define PT_SHIFT (12)			/* Page Table */
 #define PT_MASK  0x02FF
 
+#define LARGE_PAGE_SHIFT 24
+
 static inline unsigned long hpt_hash(unsigned long vpn, int large)
 {
 	unsigned long vsid;
@@ -222,16 +211,24 @@
 
 #define PG_SHIFT (12)			/* Page Entry */
 
-extern __inline__ void _tlbie( unsigned long va )
+/*
+ * Invalidate a TLB entry.  Assumes a context syncronizing 
+ * instruction preceeded this call (for example taking the
+ * TLB lock).
+ */
+static inline void _tlbie(unsigned long va, int large)
 {
-	__asm__ __volatile__ ( " \n\
-		clrldi	%0,%0,16 \n\
-		ptesync		 \n\
-		tlbie	%0	 \n\
-		eieio		 \n\
-		tlbsync		 \n\
-		ptesync"
-		: : "r" (va) : "memory" );
+	asm volatile("ptesync": : :"memory");
+
+	if (large) {
+		asm volatile("clrldi	%0,%0,16\n\
+			      tlbie	%0,1" : : "r"(va) : "memory");
+	} else {
+		asm volatile("clrldi	%0,%0,16\n\
+			      tlbie	%0,0" : : "r"(va) : "memory");
+	}
+
+	asm volatile("eieio; tlbsync; ptesync": : :"memory");
 }
  
 #endif /* __ASSEMBLY__ */
diff -urN linux-2.4.20-pre4/include/asm-ppc64/naca.h linux-2.4.20-pre5/include/asm-ppc64/naca.h
--- linux-2.4.20-pre4/include/asm-ppc64/naca.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/include/asm-ppc64/naca.h	Wed Aug 28 16:38:25 2002
@@ -13,28 +13,63 @@
 #include <asm/types.h>
 
 struct naca_struct {
-	void *xItVpdAreas;
-	void *xRamDisk;
-	u64 xRamDiskSize;		/* In pages */
-	struct paca_struct *paca;	/* Ptr to an array of pacas */
-	u64 debug_switch;		/* Bits to control debug printing */
-	u16 processorCount;		/* # of physical processors */
-	u16 dCacheL1LineSize;		/* Line size of L1 DCache in bytes */
-	u16 dCacheL1LogLineSize;	/* Log-2 of DCache line size */
-	u16 dCacheL1LinesPerPage;	/* DCache lines per page */
-	u16 iCacheL1LineSize;		/* Line size of L1 ICache in bytes */
-	u16 iCacheL1LogLineSize;	/* Log-2 of ICache line size */
-	u16 iCacheL1LinesPerPage;	/* ICache lines per page */
-	u16 slb_size;			/* SLB size in entries */
-	u64 physicalMemorySize;		/* Size of real memory in bytes */
-	u64 pftSize;			/* Log base 2 of page table size */
-	u64 serialPortAddr;		/* Phyical address of serial port */
-	u8 interrupt_controller;	/* Type of interrupt controller */ 
-	u8 resv0;    			/* Type of interrupt controller */
-	u16 platform;			/* Platform flags */
-	u8 resv1[12];			/* Padding */
+	/*==================================================================
+	 * Cache line 1: 0x0000 - 0x007F
+	 * Kernel only data - undefined for user space
+	 *==================================================================
+	 */
+	void *xItVpdAreas;              /* VPD Data                  0x00 */
+	void *xRamDisk;                 /* iSeries ramdisk           0x08 */
+	u64   xRamDiskSize;		/* In pages                  0x10 */
+	struct paca_struct *paca;	/* Ptr to an array of pacas  0x18 */
+	u64 debug_switch;		/* Debug print control       0x20 */
+	u64 banner;                     /* Ptr to banner string      0x28 */
+	u64 log;                        /* Ptr to log buffer         0x30 */
+	u64 serialPortAddr;		/* Phy addr of serial port   0x38 */
+	u64 interrupt_controller;	/* Type of int controller    0x40 */ 
+	u64 slb_size;			/* SLB size in entries       0x48 */
+	u64 pftSize;			/* Log 2 of page table size  0x50 */
+	u64 resv0[5];                   /* Reserved           0x58 - 0x7F */
+
+	/*==================================================================
+	 * Cache line 2: 0x0080 - 0x00FF
+	 * Kernel / User data
+	 *==================================================================
+	 */
+	u8  eye_catcher[6];             /* Eyecatcher: PPC64         0x00 */
+	u16 version;                    /* Version number            0x06 */
+	u16 platform;			/* Platform flags            0x08 */
+	u16 processor;			/* Processor type            0x0A */
+	u32 processorCount;		/* # of physical processors  0x0C */
+	u64 physicalMemorySize;		/* Size of real memory(B)    0x10 */
+
+	u16 dCacheL1Size;	        /* L1 d-cache size           0x18 */
+	u16 dCacheL1LineSize;		/* L1 d-cache line size      0x1A */
+	u16 dCacheL1LogLineSize;	/* L1 d-cache line size Log2 0x1C */
+	u16 dCacheL1LinesPerPage;	/* L1 d-cache lines / page   0x1E */
+	u16 dCacheL1Assoc;              /* L1 d-cache associativity  0x20 */
+
+	u16 iCacheL1Size;	        /* L1 i-cache size           0x22 */
+	u16 iCacheL1LineSize;		/* L1 i-cache line size      0x24 */
+	u16 iCacheL1LogLineSize;	/* L1 i-cache line size Log2 0x26 */
+	u16 iCacheL1LinesPerPage;	/* L1 i-cache lines / page   0x28 */
+	u16 iCacheL1Assoc;              /* L1 i-cache associativity  0x2A */
+
+	u16 cacheL2Size;	        /* L2 cache size             0x2C */
+	u16 cacheL2Assoc;	        /* L2 cache associativity    0x2E */
+
+	u64 tb_orig_stamp;              /* Timebase at boot          0x30 */
+	u64 tb_ticks_per_sec;           /* Timebase tics / sec       0x38 */
+	u64 tb_to_xs;                   /* Inverse of TB to 2^20     0x40 */
+	u64 stamp_xsec;                 /*                           0x48 */
+	volatile u64 tb_update_count;   /* Timebase atomicity ctr    0x50 */
+	u32 tz_minuteswest;             /* Minutes west of Greenwich 0x58 */
+	u32 tz_dsttime;                 /* Type of dst correction    0x5C */
+
+	u64 resv1[4];                   /* Reserverd          0x60 - 0x7F */
 };
 
+
 extern struct naca_struct *naca;
 
 #endif /* _NACA_H */
diff -urN linux-2.4.20-pre4/include/asm-ppc64/paca.h linux-2.4.20-pre5/include/asm-ppc64/paca.h
--- linux-2.4.20-pre4/include/asm-ppc64/paca.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/include/asm-ppc64/paca.h	Wed Aug 28 16:38:25 2002
@@ -84,8 +84,7 @@
 	u8 xSegments[STAB_CACHE_SIZE];	/* Cache of used stab entries		0x68,0x70 */
 	u8 xProcEnabled;		/* 1=soft enabled			0x78 */
 	u8 xHrdIntCount;		/* Count of active hardware interrupts  0x79  */
-	u8 prof_enabled;		/* 1=iSeries profiling enabled          0x7A */
-	u8 resv1[5];			/*					0x7B-0x7F */
+	u8 resv1[6];			/*					0x7B-0x7F */
 
 /*=====================================================================================
  * CACHE_LINE_2 0x0080 - 0x00FF
@@ -97,13 +96,7 @@
 	u64 pgtable_cache_sz;		/*					0x18 */
 	u64 next_jiffy_update_tb;	/* TB value for next jiffy update	0x20 */
 	u32 lpEvent_count;		/* lpEvents processed			0x28 */
-	u32 prof_multiplier;		/*					0x2C */
-	u32 prof_counter;		/*					0x30 */
-	u32 prof_shift;			/* iSeries shift for profile bucket size0x34 */
-	u32 *prof_buffer;		/* iSeries profiling buffer		0x38 */
-	u32 *prof_stext;		/* iSeries start of kernel text		0x40 */
-	u32 prof_len;			/* iSeries length of profile buffer -1	0x48 */
-	u8  rsvd2[128-76];		/*					0x4C */
+	u8  rsvd2[128-5*8-1*4];		/*					0x68 */
 
 /*=====================================================================================
  * CACHE_LINE_3 0x0100 - 0x017F
@@ -135,10 +128,29 @@
 	u8 rsvd5[256-16-sizeof(struct rtas_args)];
 
 /*=====================================================================================
- * CACHE_LINE_19-30 0x0800 - 0x0EFF Reserved
+ * CACHE_LINE_19 - 20 Profile Data
  *=====================================================================================
  */
-	u8 rsvd6[0x600];
+	u32 pmc[12];                    /* Default pmc value		*/	
+	u64 pmcc[8];                    /* Cumulative pmc counts        */
+	u64 rsvd5a[2];
+
+	u32 prof_multiplier;		/*					 */
+	u32 prof_shift;			/* iSeries shift for profile bucket size */
+	u32 *prof_buffer;		/* iSeries profiling buffer		 */
+	u32 *prof_stext;		/* iSeries start of kernel text		 */
+	u32 *prof_etext;		/* iSeries start of kernel text		 */
+	u32 prof_len;			/* iSeries length of profile buffer -1	 */
+	u8  prof_mode;                  /* */
+	u8  rsvv5b[3];
+	u64 prof_counter;		/*					 */
+	u8  rsvd5c[128-8*6];
+
+/*=====================================================================================
+ * CACHE_LINE_20-30
+ *=====================================================================================
+ */
+	u8 rsvd6[0x500];
 
 /*=====================================================================================
  * CACHE_LINE_31 0x0F00 - 0x0F7F Exception stack
diff -urN linux-2.4.20-pre4/include/asm-ppc64/page.h linux-2.4.20-pre5/include/asm-ppc64/page.h
--- linux-2.4.20-pre4/include/asm-ppc64/page.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/include/asm-ppc64/page.h	Wed Aug 28 16:38:25 2002
@@ -123,6 +123,14 @@
 	printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
 	xmon(0); \
 } while (0)
+#elif defined(CONFIG_KDB)
+#include <asm/ptrace.h>
+#include <linux/kdb.h>
+/* extern void kdb(kdb_reason_t reason, int error, kdb_eframe_t ef); */
+#define BUG() do { \
+      printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
+      kdb(KDB_REASON_OOPS, 0, (kdb_eframe_t) 0); \
+} while (0)
 #else
 #define BUG() do { \
 	printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
@@ -132,15 +140,8 @@
 
 #define PAGE_BUG(page) do { BUG(); } while (0)
 
-/*
- * XXX A bug in the current ppc64 compiler prevents an optimisation
- * where a divide is replaced by a multiply by shifted inverse. For
- * the moment use page->virtaul
- */
-#define WANT_PAGE_VIRTUAL 1
-
 /* Pure 2^n version of get_order */
-extern __inline__ int get_order(unsigned long size)
+static inline int get_order(unsigned long size)
 {
 	int order;
 
diff -urN linux-2.4.20-pre4/include/asm-ppc64/pci.h linux-2.4.20-pre5/include/asm-ppc64/pci.h
--- linux-2.4.20-pre4/include/asm-ppc64/pci.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/include/asm-ppc64/pci.h	Wed Aug 28 16:38:25 2002
@@ -25,12 +25,12 @@
 #define PCIBIOS_MIN_IO		0x1000
 #define PCIBIOS_MIN_MEM		0x10000000
 
-extern inline void pcibios_set_master(struct pci_dev *dev)
+static inline void pcibios_set_master(struct pci_dev *dev)
 {
 	/* No special bus mastering setup handling */
 }
 
-extern inline void pcibios_penalize_isa_irq(int irq)
+static inline void pcibios_penalize_isa_irq(int irq)
 {
 	/* We don't do dynamic PCI IRQ allocation */
 }
@@ -78,7 +78,7 @@
 
 extern void pSeries_pcibios_init_early(void);
 
-extern inline void pci_dma_sync_single(struct pci_dev *hwdev,
+static inline void pci_dma_sync_single(struct pci_dev *hwdev,
 				       dma_addr_t dma_handle,
 				       size_t size, int direction)
 {
@@ -87,7 +87,7 @@
 	/* nothing to do */
 }
 
-extern inline void pci_dma_sync_sg(struct pci_dev *hwdev,
+static inline void pci_dma_sync_sg(struct pci_dev *hwdev,
 				   struct scatterlist *sg,
 				   int nelems, int direction)
 {
@@ -101,7 +101,7 @@
  * only drive the low 24-bits during PCI bus mastering, then
  * you would pass 0x00ffffff as the mask to this function.
  */
-extern inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask)
+static inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask)
 {
 	return 1;
 }
diff -urN linux-2.4.20-pre4/include/asm-ppc64/perfmon.h linux-2.4.20-pre5/include/asm-ppc64/perfmon.h
--- linux-2.4.20-pre4/include/asm-ppc64/perfmon.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre5/include/asm-ppc64/perfmon.h	Wed Aug 28 16:38:25 2002
@@ -0,0 +1,94 @@
+/*
+ * This file contains the code to configure and utilize the ppc64 pmc hardware
+ * Copyright (C) 2002 David Engebretsen <engebret@us.ibm.com>
+ */
+
+#ifndef __KERNEL__
+#define INLINE_SYSCALL(arg1, arg2)       \
+  ({                                            \
+    register long r0 __asm__ ("r0");     \
+    register long r3 __asm__ ("r3"); \
+    register long r4 __asm__ ("r4"); \
+    long ret, err;                              \
+    r0 = 208; \
+    r3 = (long) (arg1); \
+    r4 = (long) (arg2); \
+    __asm__ ("sc\n\t"                           \
+             "mfcr      %1\n\t"                 \
+             : "=r" (r3), "=r" (err)            \
+             : "r" (r0), "r" (r3), "r" (r4) \
+             : "cc", "memory");                 \
+    ret = r3;                                   \
+  })
+#endif
+
+#ifndef __ASSEMBLY__
+struct perfmon_base_struct {
+	u64 profile_buffer;
+	u64 profile_length;
+	u64 trace_buffer;
+	u64 trace_length;
+	u64 trace_end;
+	u64 state;
+};
+
+struct pmc_header {
+	int type;
+	int pid;
+	int resv[30];
+};
+
+struct pmc_struct {
+        int pmc[11];
+};
+
+struct pmc_info_struct {
+	unsigned int mode, cpu;
+
+	unsigned int  pmc_base[11];
+	unsigned long pmc_cumulative[8];
+};
+
+struct perfmon_struct {
+	struct pmc_header header;
+
+	union {
+		struct pmc_struct      pmc;
+		struct pmc_info_struct pmc_info;
+ 	} vdata;
+};
+
+enum {
+	PMC_OP_ALLOC         = 1,
+	PMC_OP_FREE          = 2,
+	PMC_OP_CLEAR         = 4,
+	PMC_OP_DUMP          = 5,
+	PMC_OP_DUMP_HARDWARE = 6,
+	PMC_OP_DECR_PROFILE  = 20,
+	PMC_OP_PMC_PROFILE   = 21,
+	PMC_OP_SET           = 30,
+	PMC_OP_SET_USER      = 31,
+	PMC_OP_END           = 30
+};
+
+
+#define	PMC_TRACE_CMD 0xFF
+
+enum {
+	PMC_TYPE_DERC_PROFILE  = 1,
+	PMC_TYPE_CYCLE         = 2,
+	PMC_TYPE_PROFILE       = 3,
+	PMC_TYPE_DCACHE        = 4,
+	PMC_TYPE_L2_MISS       = 5,
+	PMC_TYPE_LWARCX        = 6,
+	PMC_TYPE_END           = 6
+};
+#endif
+
+#define	PMC_STATE_INITIAL         0x00
+#define	PMC_STATE_READY           0x01
+#define	PMC_STATE_DECR_PROFILE    0x10
+#define	PMC_STATE_PROFILE_KERN    0x11
+#define	PMC_STATE_TRACE_KERN      0x20
+#define	PMC_STATE_TRACE_USER      0x21
+
diff -urN linux-2.4.20-pre4/include/asm-ppc64/pgtable.h linux-2.4.20-pre5/include/asm-ppc64/pgtable.h
--- linux-2.4.20-pre4/include/asm-ppc64/pgtable.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/include/asm-ppc64/pgtable.h	Wed Aug 28 16:38:25 2002
@@ -12,11 +12,6 @@
 #include <asm/page.h>
 #endif /* __ASSEMBLY__ */
 
-/* Certain architectures need to do special things when pte's
- * within a page table are directly modified.  Thus, the following
- * hook is made available.
- */
-
 /* PMD_SHIFT determines what a second-level page table entry can map */
 #define PMD_SHIFT	(PAGE_SHIFT + PAGE_SHIFT - 3)
 #define PMD_SIZE	(1UL << PMD_SHIFT)
@@ -232,47 +227,41 @@
 /* to find an entry in the ioremap page-table-directory */
 #define pgd_offset_i(address) (ioremap_pgd + pgd_index(address))
 
-/*
- * Given a pointer to an mem_map[] entry, return the kernel virtual
- * address corresponding to that page.
- */
-#define page_address(page) ((page)->virtual)
-
 #define pages_to_mb(x)		((x) >> (20-PAGE_SHIFT))
 
 /*
  * The following only work if pte_present() is true.
  * Undefined behaviour if not..
  */
-extern inline int pte_read(pte_t pte)  { return pte_val(pte) & _PAGE_USER;}
-extern inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_RW;}
-extern inline int pte_exec(pte_t pte)  { return pte_val(pte) & _PAGE_EXEC;}
-extern inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY;}
-extern inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED;}
+static inline int pte_read(pte_t pte)  { return pte_val(pte) & _PAGE_USER;}
+static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_RW;}
+static inline int pte_exec(pte_t pte)  { return pte_val(pte) & _PAGE_EXEC;}
+static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY;}
+static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED;}
 
-extern inline void pte_uncache(pte_t pte) { pte_val(pte) |= _PAGE_NO_CACHE; }
-extern inline void pte_cache(pte_t pte)   { pte_val(pte) &= ~_PAGE_NO_CACHE; }
+static inline void pte_uncache(pte_t pte) { pte_val(pte) |= _PAGE_NO_CACHE; }
+static inline void pte_cache(pte_t pte)   { pte_val(pte) &= ~_PAGE_NO_CACHE; }
 
-extern inline pte_t pte_rdprotect(pte_t pte) {
+static inline pte_t pte_rdprotect(pte_t pte) {
 	pte_val(pte) &= ~_PAGE_USER; return pte; }
-extern inline pte_t pte_exprotect(pte_t pte) {
+static inline pte_t pte_exprotect(pte_t pte) {
 	pte_val(pte) &= ~_PAGE_EXEC; return pte; }
-extern inline pte_t pte_wrprotect(pte_t pte) {
+static inline pte_t pte_wrprotect(pte_t pte) {
 	pte_val(pte) &= ~(_PAGE_RW); return pte; }
-extern inline pte_t pte_mkclean(pte_t pte) {
+static inline pte_t pte_mkclean(pte_t pte) {
 	pte_val(pte) &= ~(_PAGE_DIRTY); return pte; }
-extern inline pte_t pte_mkold(pte_t pte) {
+static inline pte_t pte_mkold(pte_t pte) {
 	pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
 
-extern inline pte_t pte_mkread(pte_t pte) {
+static inline pte_t pte_mkread(pte_t pte) {
 	pte_val(pte) |= _PAGE_USER; return pte; }
-extern inline pte_t pte_mkexec(pte_t pte) {
+static inline pte_t pte_mkexec(pte_t pte) {
 	pte_val(pte) |= _PAGE_USER | _PAGE_EXEC; return pte; }
-extern inline pte_t pte_mkwrite(pte_t pte) {
+static inline pte_t pte_mkwrite(pte_t pte) {
 	pte_val(pte) |= _PAGE_RW; return pte; }
-extern inline pte_t pte_mkdirty(pte_t pte) {
+static inline pte_t pte_mkdirty(pte_t pte) {
 	pte_val(pte) |= _PAGE_DIRTY; return pte; }
-extern inline pte_t pte_mkyoung(pte_t pte) {
+static inline pte_t pte_mkyoung(pte_t pte) {
 	pte_val(pte) |= _PAGE_ACCESSED; return pte; }
 
 /* Atomic PTE updates */
@@ -349,8 +338,8 @@
 #define flush_tlb_page local_flush_tlb_page
 #define flush_tlb_range local_flush_tlb_range
 
-extern inline void flush_tlb_pgtables(struct mm_struct *mm,
-				unsigned long start, unsigned long end)
+static inline void flush_tlb_pgtables(struct mm_struct *mm,
+				      unsigned long start, unsigned long end)
 {
 	/* PPC has hw page tables. */
 }
diff -urN linux-2.4.20-pre4/include/asm-ppc64/pmc.h linux-2.4.20-pre5/include/asm-ppc64/pmc.h
--- linux-2.4.20-pre4/include/asm-ppc64/pmc.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/include/asm-ppc64/pmc.h	Wed Aug 28 16:38:25 2002
@@ -98,18 +98,6 @@
 #define PMC_SW_SYSTEM(F)      do {;} while (0)
 #endif
 
-#define MMCR0 795
-#define MMCR1 798
-#define MMCRA 786
-#define PMC1  787
-#define PMC2  788
-#define PMC3  789
-#define PMC4  790
-#define PMC5  791
-#define PMC6  792
-#define PMC7  793
-#define PMC8  794
-
 #define PMC_CONTROL_CPI 1
 #define PMC_CONTROL_TLB 2
 
diff -urN linux-2.4.20-pre4/include/asm-ppc64/ppcdebug.h linux-2.4.20-pre5/include/asm-ppc64/ppcdebug.h
--- linux-2.4.20-pre4/include/asm-ppc64/ppcdebug.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/include/asm-ppc64/ppcdebug.h	Wed Aug 28 16:38:25 2002
@@ -51,6 +51,8 @@
 #define PPCDBG_SMP           PPCDBG_BITVAL(19)
 #define PPCDBG_BOOT          PPCDBG_BITVAL(20)
 #define PPCDBG_BUSWALK       PPCDBG_BITVAL(21)
+#define PPCDBG_PROM	     PPCDBG_BITVAL(22)
+#define PPCDBG_RTAS	     PPCDBG_BITVAL(23)
 #define PPCDBG_HTABSTRESS    PPCDBG_BITVAL(62)
 #define PPCDBG_HTABSIZE      PPCDBG_BITVAL(63)
 #define PPCDBG_NONE          (0UL)
@@ -74,7 +76,8 @@
 	"signal",	"signal_xmon",
 	"binfmt32",	"binfmt64",	"binfmt_xmon",	"binfmt_32addr",
 	"alignfixup",   "tceinit",      "tce",          "phb_init",     
-	"smp",          "boot",         "buswalk"
+	"smp",          "boot",         "buswalk",	"prom",
+	"rtas"
 };
 #else
 extern char *trace_names[64];
diff -urN linux-2.4.20-pre4/include/asm-ppc64/processor.h linux-2.4.20-pre5/include/asm-ppc64/processor.h
--- linux-2.4.20-pre4/include/asm-ppc64/processor.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/include/asm-ppc64/processor.h	Wed Aug 28 16:38:25 2002
@@ -18,6 +18,7 @@
 #endif
 #include <asm/ptrace.h>
 #include <asm/types.h>
+#include <asm/delay.h>
 
 /*
  * Default implementation of macro that returns current
@@ -97,7 +98,7 @@
 #define FPSCR_VX	0x20000000	/* Invalid operation summary */
 #define FPSCR_OX	0x10000000	/* Overflow exception summary */
 #define FPSCR_UX	0x08000000	/* Underflow exception summary */
-#define FPSCR_ZX	0x04000000	/* Zero-devide exception summary */
+#define FPSCR_ZX	0x04000000	/* Zero-divide exception summary */
 #define FPSCR_XX	0x02000000	/* Inexact exception summary */
 #define FPSCR_VXSNAN	0x01000000	/* Invalid op for SNaN */
 #define FPSCR_VXISI	0x00800000	/* Invalid op for Inv - Inv */
@@ -247,8 +248,6 @@
 #define	SPRN_IMMR	0x27E  	/* Internal Memory Map Register */
 #define	SPRN_L2CR	0x3F9	/* Level 2 Cache Control Regsiter */
 #define	SPRN_LR		0x008	/* Link Register */
-#define	SPRN_MMCR0	0x3B8	/* Monitor Mode Control Register 0 */
-#define	SPRN_MMCR1	0x3BC	/* Monitor Mode Control Register 1 */
 #define	SPRN_PBL1	0x3FC	/* Protection Bound Lower 1 */
 #define	SPRN_PBL2	0x3FE	/* Protection Bound Lower 2 */
 #define	SPRN_PBU1	0x3FD	/* Protection Bound Upper 1 */
@@ -256,18 +255,12 @@
 #define	SPRN_PID	0x3B1	/* Process ID */
 #define	SPRN_PIR	0x3FF	/* Processor Identification Register */
 #define	SPRN_PIT	0x3DB	/* Programmable Interval Timer */
-#define	SPRN_PMC1	0x3B9	/* Performance Counter Register 1 */
-#define	SPRN_PMC2	0x3BA	/* Performance Counter Register 2 */
-#define	SPRN_PMC3	0x3BD	/* Performance Counter Register 3 */
-#define	SPRN_PMC4	0x3BE	/* Performance Counter Register 4 */
 #define	SPRN_PVR	0x11F	/* Processor Version Register */
 #define	SPRN_RPA	0x3D6	/* Required Physical Address Register */
-#define	SPRN_SDA	0x3BF	/* Sampled Data Address Register */
 #define	SPRN_SDR1	0x019	/* MMU Hash Base Register */
 #define	SPRN_SGR	0x3B9	/* Storage Guarded Register */
 #define	  SGR_NORMAL		0
 #define	  SGR_GUARDED		1
-#define	SPRN_SIA	0x3BB	/* Sampled Instruction Address Register */
 #define	SPRN_SPRG0	0x110	/* Special Purpose Register General 0 */
 #define	SPRN_SPRG1	0x111	/* Special Purpose Register General 1 */
 #define	SPRN_SPRG2	0x112	/* Special Purpose Register General 2 */
@@ -324,13 +317,6 @@
 #define	    WRS_SYSTEM		3		/* WDT forced system reset */
 #define	  TSR_PIS		0x08000000	/* PIT Interrupt Status */
 #define	  TSR_FIS		0x04000000	/* FIT Interrupt Status */
-#define	SPRN_UMMCR0	0x3A8	/* User Monitor Mode Control Register 0 */
-#define	SPRN_UMMCR1	0x3AC	/* User Monitor Mode Control Register 0 */
-#define	SPRN_UPMC1	0x3A9	/* User Performance Counter Register 1 */
-#define	SPRN_UPMC2	0x3AA	/* User Performance Counter Register 2 */
-#define	SPRN_UPMC3	0x3AD	/* User Performance Counter Register 3 */
-#define	SPRN_UPMC4	0x3AE	/* User Performance Counter Register 4 */
-#define	SPRN_USIA	0x3AB	/* User Sampled Instruction Address Register */
 #define	SPRN_XER	0x001	/* Fixed Point Exception Register */
 #define	SPRN_ZPR	0x3B0	/* Zone Protection Register */
 
@@ -396,7 +382,19 @@
 #define	THRM2	SPRN_THRM2	/* Thermal Management Register 2 */
 #define	THRM3	SPRN_THRM3	/* Thermal Management Register 3 */
 #define	XER	SPRN_XER
-
+#define PMC1	0x313
+#define PMC2	0x314
+#define PMC3	0x315
+#define PMC4	0x316
+#define PMC5	0x317
+#define PMC6	0x318
+#define PMC7	0x319
+#define PMC8	0x31a
+#define MMCR0	0x31b
+#define MMCR1	0x31e
+#define MMCRA	0x312
+#define SIAR	0x30c
+#define SDAR	0x30d
 
 /* Device Control Registers */
 
@@ -483,10 +481,12 @@
 #define	PVR_REV(pvr)  (((pvr) >>   0) & 0xFFFF)	/* Revison field */
 
 /* Processor Version Numbers */
+#define	PV_NORTHSTAR	0x0033
 #define	PV_PULSAR	0x0034
 #define	PV_POWER4	0x0035
 #define	PV_ICESTAR	0x0036
 #define	PV_SSTAR	0x0037
+#define	PV_POWER4p	0x0038
 #define	PV_630        	0x0040
 #define	PV_630p	        0x0041
 
@@ -717,7 +717,7 @@
 #define init_task	(init_task_union.task)
 #define init_stack	(init_task_union.stack)
 
-#define cpu_relax()     do { } while (0)
+#define cpu_relax()     udelay(1)
 
 /*
  * Prefetch macros.
@@ -726,18 +726,30 @@
 #define ARCH_HAS_PREFETCHW
 #define ARCH_HAS_SPINLOCK_PREFETCH
 
-extern inline void prefetch(const void *x)
+static inline void prefetch(const void *x)
 {
 	__asm__ __volatile__ ("dcbt 0,%0" : : "r" (x));
 }
 
-extern inline void prefetchw(const void *x)
+static inline void prefetchw(const void *x)
 {
 	__asm__ __volatile__ ("dcbtst 0,%0" : : "r" (x));
 }
 
 #define spin_lock_prefetch(x)	prefetchw(x)
 
+#define cpu_has_largepage()	(__is_processor(PV_POWER4) || \
+				 __is_processor(PV_POWER4p))
+
+#define cpu_has_slb()		(__is_processor(PV_POWER4) || \
+				 __is_processor(PV_POWER4p))
+
+#define cpu_has_tlbiel()	(__is_processor(PV_POWER4) || \
+				 __is_processor(PV_POWER4p))
+
+#define cpu_has_noexecute()	(__is_processor(PV_POWER4) || \
+				 __is_processor(PV_POWER4p))
+
 #endif /* ASSEMBLY */
 
 #endif /* __ASM_PPC64_PROCESSOR_H */
diff -urN linux-2.4.20-pre4/include/asm-ppc64/prom.h linux-2.4.20-pre5/include/asm-ppc64/prom.h
--- linux-2.4.20-pre4/include/asm-ppc64/prom.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/include/asm-ppc64/prom.h	Wed Aug 28 16:38:25 2002
@@ -128,7 +128,6 @@
 	int	busno;			/* for pci devices */
 	int	devfn;			/* for pci devices */
 	struct  pci_controller *phb;	/* for pci devices */
-	int	status;			/* current status of device */
 	struct	TceTable *tce_table;	/* for phb's or bridges */
 #define DN_STATUS_BIST_FAILED (1<<0)
 	struct	property *properties;
@@ -195,8 +194,5 @@
 extern int prom_n_addr_cells(struct device_node* np);
 extern int prom_n_size_cells(struct device_node* np);
 extern void prom_get_irq_senses(unsigned char *senses, int off, int max);
-extern void prom_drawstring(const char *c);
-extern void prom_drawhex(unsigned long v);
-extern void prom_drawchar(char c);
 
 #endif /* _PPC64_PROM_H */
diff -urN linux-2.4.20-pre4/include/asm-ppc64/rtas.h linux-2.4.20-pre5/include/asm-ppc64/rtas.h
--- linux-2.4.20-pre4/include/asm-ppc64/rtas.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/include/asm-ppc64/rtas.h	Wed Aug 28 16:38:25 2002
@@ -2,6 +2,7 @@
 #define _PPC64_RTAS_H
 
 #include <linux/spinlock.h>
+#include <asm/page.h>
 
 /*
  * Definitions for talking to the RTAS on CHRP machines.
@@ -16,6 +17,8 @@
  */
 
 #define RTAS_UNKNOWN_SERVICE (-1)
+#define RTAS_INSTANTIATE_MAX (1UL<<30) /* Don't instantiate rtas at/above this value */
+
 /*
  * In general to call RTAS use rtas_token("string") to lookup
  * an RTAS token for the given string (e.g. "event-scan").
@@ -128,6 +131,29 @@
 	unsigned char buffer[1];		/* allocated by klimit bump */
 };
 
+struct flash_block {
+	char *data;
+	unsigned long length;
+};
+
+/* This struct is very similar but not identical to
+ * that needed by the rtas flash update.
+ * All we need to do for rtas is rewrite num_blocks
+ * into a version/length and translate the pointers
+ * to absolute.
+ */
+#define FLASH_BLOCKS_PER_NODE ((PAGE_SIZE - 16) / sizeof(struct flash_block))
+struct flash_block_list {
+	unsigned long num_blocks;
+	struct flash_block_list *next;
+	struct flash_block blocks[FLASH_BLOCKS_PER_NODE];
+};
+struct flash_block_list_header { /* just the header of flash_block_list */
+	unsigned long num_blocks;
+	struct flash_block_list *next;
+};
+extern struct flash_block_list_header rtas_firmware_flash_list;
+
 extern struct rtas_t rtas;
 
 extern void enter_rtas(struct rtas_args *);
@@ -140,4 +166,7 @@
 extern void rtas_power_off(void);
 extern void rtas_halt(void);
 
+extern struct proc_dir_entry *rtas_proc_dir;
+
+
 #endif /* _PPC64_RTAS_H */
diff -urN linux-2.4.20-pre4/include/asm-ppc64/semaphore.h linux-2.4.20-pre5/include/asm-ppc64/semaphore.h
--- linux-2.4.20-pre4/include/asm-ppc64/semaphore.h	Wed Aug 28 16:37:15 2002
+++ linux-2.4.20-pre5/include/asm-ppc64/semaphore.h	Wed Aug 28 16:38:25 2002
@@ -2,14 +2,8 @@
 #define _PPC64_SEMAPHORE_H
 
 /*
- * Swiped from asm-sparc/semaphore.h and modified
- * -- Cort (cort@cs.nmt.edu)
- *
- * Stole some rw spinlock-based semaphore stuff from asm-alpha/semaphore.h
- * -- Ani Joshi (ajoshi@unixbox.com)
- *
  * Remove spinlock-based RW semaphores; RW semaphore definitions are
- * now in rwsem.h and we use the the generic lib/rwsem.c implementation.
+ * now in rwsem.h and we use the generic lib/rwsem.c implementation.
  * Rework semaphores to use atomic_dec_if_positive.
  * -- Paul Mackerras (paulus@samba.org)
  */
@@ -78,7 +72,7 @@
 extern int  __down_interruptible(struct semaphore * sem);
 extern void __up(struct semaphore * sem);
 
-extern inline void down(struct semaphore * sem)
+static inline void down(struct semaphore * sem)
 {
 #if WAITQUEUE_DEBUG
 	CHECK_MAGIC(sem->__magic);
@@ -92,7 +86,7 @@
 	smp_wmb();
 }
 
-extern inline int down_interruptible(struct semaphore * sem)
+static inline int down_interruptible(struct semaphore * sem)
 {
 	int ret = 0;
 
@@ -106,7 +100,7 @@
 	return ret;
 }
 
-extern inline int down_trylock(struct semaphore * sem)
+static inline int down_trylock(struct semaphore * sem)
 {
 	int ret;
 
@@ -119,7 +113,7 @@
 	return ret;
 }
 
-extern inline void up(struct semaphore * sem)
+static inline void up(struct semaphore * sem)
 {
 #if WAITQUEUE_DEBUG
 	CHECK_MAGIC(sem->__magic);
diff -urN linux-2.4.20-pre4/include/asm-ppc64/siginfo.h linux-2.4.20-pre5/include/asm-ppc64/siginfo.h
--- linux-2.4.20-pre4/include/asm-ppc64/siginfo.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/include/asm-ppc64/siginfo.h	Wed Aug 28 16:38:25 2002
@@ -224,7 +224,7 @@
 #ifdef __KERNEL__
 #include <linux/string.h>
 
-extern inline void copy_siginfo(siginfo_t *to, siginfo_t *from)
+static inline void copy_siginfo(siginfo_t *to, siginfo_t *from)
 {
 	if (from->si_code < 0)
 		memcpy(to, from, sizeof(siginfo_t));
diff -urN linux-2.4.20-pre4/include/asm-ppc64/smplock.h linux-2.4.20-pre5/include/asm-ppc64/smplock.h
--- linux-2.4.20-pre4/include/asm-ppc64/smplock.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/include/asm-ppc64/smplock.h	Wed Aug 28 16:38:25 2002
@@ -43,13 +43,13 @@
  * so we only need to worry about other
  * CPU's.
  */
-extern __inline__ void lock_kernel(void)
+static inline void lock_kernel(void)
 {
 	if (!++current->lock_depth)
 		spin_lock(&kernel_flag);
 }
 
-extern __inline__ void unlock_kernel(void)
+static inline void unlock_kernel(void)
 {
 	if (--current->lock_depth < 0)
 		spin_unlock(&kernel_flag);
diff -urN linux-2.4.20-pre4/include/asm-ppc64/softirq.h linux-2.4.20-pre5/include/asm-ppc64/softirq.h
--- linux-2.4.20-pre4/include/asm-ppc64/softirq.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/include/asm-ppc64/softirq.h	Wed Aug 28 16:38:25 2002
@@ -8,22 +8,20 @@
  * 2 of the License, or (at your option) any later version.
  */
 
-#include <asm/atomic.h>
 #include <asm/hardirq.h>
 
-
 #define local_bh_disable()	do { local_bh_count(smp_processor_id())++; barrier(); } while (0)
 #define __local_bh_enable()	do { barrier(); local_bh_count(smp_processor_id())--; } while (0)
 
 #define local_bh_enable()  \
 do {                                                    \
+	barrier();					\
         if (!--local_bh_count(smp_processor_id())       \
             && softirq_pending(smp_processor_id())) {   \
                 do_softirq();                           \
         }                                               \
 } while (0)
 
-
 #define in_softirq() (local_bh_count(smp_processor_id()) != 0)
 
 #endif	/* __ASM_SOFTIRQ_H */
diff -urN linux-2.4.20-pre4/include/asm-ppc64/system.h linux-2.4.20-pre5/include/asm-ppc64/system.h
--- linux-2.4.20-pre4/include/asm-ppc64/system.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/include/asm-ppc64/system.h	Wed Aug 28 16:38:25 2002
@@ -16,13 +16,6 @@
 #include <asm/memory.h>
 
 /*
- * System defines.
- */
-#define KERNEL_START_PHYS	0x800000 
-#define KERNEL_START	        (PAGE_OFFSET+KERNEL_START_PHYS)
-#define START_ADDR	        (PAGE_OFFSET+KERNEL_START_PHYS+0x00000)
-
-/*
  * Memory barrier.
  * The sync instruction guarantees that all memory accesses initiated
  * by this processor have been performed (with respect to all other
@@ -68,13 +61,8 @@
 extern int _get_PVR(void);
 extern long _get_L2CR(void);
 extern void _set_L2CR(unsigned long);
-extern void via_cuda_init(void);
-extern void pmac_nvram_init(void);
-extern void pmac_find_display(void);
 extern void giveup_fpu(struct task_struct *);
 extern void enable_kernel_fp(void);
-extern void giveup_altivec(struct task_struct *);
-extern void load_up_altivec(struct task_struct *);
 extern void cvt_fd(float *from, double *to, unsigned long *fpscr);
 extern void cvt_df(double *from, float *to, unsigned long *fpscr);
 extern int abs(int);
diff -urN linux-2.4.20-pre4/include/asm-ppc64/time.h linux-2.4.20-pre5/include/asm-ppc64/time.h
--- linux-2.4.20-pre4/include/asm-ppc64/time.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/include/asm-ppc64/time.h	Wed Aug 28 16:38:25 2002
@@ -26,33 +26,12 @@
 extern unsigned long tb_ticks_per_usec;
 extern unsigned long tb_ticks_per_sec;
 extern unsigned long tb_to_xs;
-extern unsigned      tb_to_us;
 extern unsigned long tb_last_stamp;
 
 struct rtc_time;
 extern void to_tm(int tim, struct rtc_time * tm);
 extern time_t last_rtc_update;
 
-/*
- * By putting all of this stuff into a single struct we 
- * reduce the number of cache lines touched by do_gettimeofday.
- * Both by collecting all of the data in one cache line and
- * by touching only one TOC entry
- */
-struct gettimeofday_vars {
-	unsigned long tb_to_xs;
-	unsigned long stamp_xsec;
-};
-
-struct gettimeofday_struct {
-	unsigned long tb_orig_stamp;
-	unsigned long tb_ticks_per_sec;
-	struct gettimeofday_vars vars[2];
-	struct gettimeofday_vars * volatile varp;
-	unsigned      var_idx;
-	unsigned      tb_to_us;
-};
-
 struct div_result {
 	unsigned long result_high;
 	unsigned long result_low;
@@ -73,30 +52,28 @@
 
 static __inline__ void set_dec(int val)
 {
+#ifdef CONFIG_PPC_ISERIES
 	struct paca_struct *lpaca = get_paca();
 	int cur_dec;
 
-	if ( lpaca->xLpPaca.xSharedProc ) {
+	if (lpaca->xLpPaca.xSharedProc) {
 		lpaca->xLpPaca.xVirtualDecr = val;
 		cur_dec = get_dec();
-		if ( cur_dec > val )
+		if (cur_dec > val)
 			HvCall_setVirtualDecr();
-	} else {
+	} else
+#endif
 		mtspr(SPRN_DEC, val);
-	}
 }
 
-extern __inline__ unsigned long tb_ticks_since(unsigned long tstamp) {
+static inline unsigned long tb_ticks_since(unsigned long tstamp)
+{
 	return get_tb() - tstamp;
 }
 
-#define mulhwu(x,y) \
-({unsigned z; asm ("mulhwu %0,%1,%2" : "=r" (z) : "r" (x), "r" (y)); z;})
 #define mulhdu(x,y) \
 ({unsigned long z; asm ("mulhdu %0,%1,%2" : "=r" (z) : "r" (x), "r" (y)); z;})
 
-
-unsigned mulhwu_scale_factor(unsigned, unsigned);
 void div128_by_32( unsigned long dividend_high, unsigned long dividend_low,
 		   unsigned divisor, struct div_result *dr );
 #endif /* __KERNEL__ */
diff -urN linux-2.4.20-pre4/include/asm-ppc64/timex.h linux-2.4.20-pre5/include/asm-ppc64/timex.h
--- linux-2.4.20-pre4/include/asm-ppc64/timex.h	Wed Aug 28 16:37:15 2002
+++ linux-2.4.20-pre5/include/asm-ppc64/timex.h	Wed Aug 28 16:38:25 2002
@@ -28,7 +28,7 @@
 	return ret;
 }
 
-#define vxtime_lock()		do {} while (0)
-#define vxtime_unlock()		do {} while (0)
+#define vxtime_lock()          do {} while (0)
+#define vxtime_unlock()                do {} while (0)
 
 #endif
diff -urN linux-2.4.20-pre4/include/asm-ppc64/types.h linux-2.4.20-pre5/include/asm-ppc64/types.h
--- linux-2.4.20-pre4/include/asm-ppc64/types.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/include/asm-ppc64/types.h	Wed Aug 28 16:38:25 2002
@@ -62,6 +62,7 @@
 /* PCI dma addresses are 32-bits wide.  Ignore PCI64 for now, since
    we'll typically be sending it all through iommu tables anyway.  */
 typedef u32 dma_addr_t;
+typedef u64 dma64_addr_t;
 
 #endif /* __KERNEL__ */
 #endif /* __ASSEMBLY__ */
diff -urN linux-2.4.20-pre4/include/asm-ppc64/uaccess.h linux-2.4.20-pre5/include/asm-ppc64/uaccess.h
--- linux-2.4.20-pre4/include/asm-ppc64/uaccess.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/include/asm-ppc64/uaccess.h	Wed Aug 28 16:38:25 2002
@@ -38,7 +38,7 @@
 #define __access_ok(addr,size) (__kernel_ok || __user_ok((addr),(size)))
 #define access_ok(type,addr,size) __access_ok((unsigned long)(addr),(size))
 
-extern inline int verify_area(int type, const void * addr, unsigned long size)
+static inline int verify_area(int type, const void * addr, unsigned long size)
 {
 	return access_ok(type,addr,size) ? 0 : -EFAULT;
 }
@@ -124,9 +124,6 @@
 	}							\
 } while (0)
 
-struct __large_struct { unsigned long buf[100]; };
-#define __m(x) (*(struct __large_struct *)(x))
-
 /*
  * We don't tell gcc that we are accessing memory, but this is OK
  * because we do not write to any memory gcc knows about, so there
@@ -200,7 +197,7 @@
 
 extern unsigned long __copy_tofrom_user(void *to, const void *from, unsigned long size);
 
-extern inline unsigned long
+static inline unsigned long
 copy_from_user(void *to, const void *from, unsigned long n)
 {
 	unsigned long over;
@@ -214,7 +211,7 @@
 	return n;
 }
 
-extern inline unsigned long
+static inline unsigned long
 copy_to_user(void *to, const void *from, unsigned long n)
 {
 	unsigned long over;
@@ -235,17 +232,21 @@
 
 extern unsigned long __clear_user(void *addr, unsigned long size);
 
-extern inline unsigned long
+static inline unsigned long
 clear_user(void *addr, unsigned long size)
 {
 	if (access_ok(VERIFY_WRITE, addr, size))
 		return __clear_user(addr, size);
-	return size? -EFAULT: 0;
+	if ((unsigned long)addr < TASK_SIZE) {
+		unsigned long over = (unsigned long)addr + size - TASK_SIZE;
+		return __clear_user(addr, size - over) + over;
+	}
+	return size;
 }
 
 extern int __strncpy_from_user(char *dst, const char *src, long count);
 
-extern inline long
+static inline long
 strncpy_from_user(char *dst, const char *src, long count)
 {
 	if (access_ok(VERIFY_READ, src, 1))
@@ -269,7 +270,7 @@
  * The `top' parameter to __strnlen_user is to make sure that
  * we can never overflow from the user area into kernel space.
  */
-extern __inline__ int strnlen_user(const char *str, long len)
+static inline int strnlen_user(const char *str, long len)
 {
 	unsigned long top = __kernel_ok? ~0UL: TASK_SIZE - 1;
 
diff -urN linux-2.4.20-pre4/include/asm-ppc64/udbg.h linux-2.4.20-pre5/include/asm-ppc64/udbg.h
--- linux-2.4.20-pre4/include/asm-ppc64/udbg.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/include/asm-ppc64/udbg.h	Wed Aug 28 16:38:25 2002
@@ -17,6 +17,8 @@
 void udbg_puts(const char *s);
 int udbg_write(const char *s, int n);
 int udbg_read(char *buf, int buflen);
+struct console;
+void udbg_console_write(struct console *con, const char *s, unsigned int n);
 void udbg_puthex(unsigned long val);
 void udbg_printSP(const char *s);
 void udbg_printf(const char *fmt, ...);
diff -urN linux-2.4.20-pre4/include/asm-ppc64/user_exports.h linux-2.4.20-pre5/include/asm-ppc64/user_exports.h
--- linux-2.4.20-pre4/include/asm-ppc64/user_exports.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre5/include/asm-ppc64/user_exports.h	Wed Aug 28 16:38:25 2002
@@ -0,0 +1,82 @@
+#ifndef _USER_EXPORTS_H
+#define _USER_EXPORTS_H
+
+/* 
+ * Dave Engebretsen and Mike Corrigan {engebret|mikejc}@us.ibm.com
+ *   Copyright (C) 2002 Dave Engebretsen & Mike Corrigan
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned int u32;
+#ifdef __powerpc64__
+typedef unsigned long u64;
+#else
+typedef unsigned long long u64;
+#endif
+
+struct user_exports {
+	/*==================================================================
+	 * Cache line 1: 0x0000 - 0x007F
+	 * Kernel only data - undefined for user space
+	 *==================================================================
+	 */
+	u64 undefined[16]; 
+
+	/*==================================================================
+	 * Cache line 2: 0x0080 - 0x00FF
+	 * Kernel / User data
+	 *==================================================================
+	 */
+	u8  eye_catcher[6];      /* Eyecatcher: PPC64         0x00 */
+	u16 version;             /* Version number            0x06 */
+	u16 platform;	         /* Platform type             0x08 */
+	u16 processor;		 /* Processor type            0x0A */
+	u32 processorCount;	 /* # of physical processors  0x0C */
+	u64 physicalMemorySize;	 /* Size of real memory(B)    0x10 */
+
+	u16 dCacheL1Size;	 /* L1 d-cache size           0x18 */
+	u16 dCacheL1LineSize;	 /* L1 d-cache line size      0x1A */
+	u16 dCacheL1LogLineSize; /* L1 d-cache line size Log2 0x1C */
+	u16 dCacheL1LinesPerPage;/* L1 d-cache lines / page   0x1E */
+	u16 dCacheL1Assoc;       /* L1 d-cache associativity  0x20 */
+
+	u16 iCacheL1Size;	 /* L1 i-cache size           0x22 */
+	u16 iCacheL1LineSize;	 /* L1 i-cache line size      0x24 */
+	u16 iCacheL1LogLineSize; /* L1 i-cache line size Log2 0x26 */
+	u16 iCacheL1LinesPerPage;/* L1 i-cache lines / page   0x28 */
+	u16 iCacheL1Assoc;       /* L1 i-cache associativity  0x2A */
+
+	u16 cacheL2Size;	 /* L2 cache size             0x2C */
+	u16 cacheL2Assoc;	 /* L2 cache associativity    0x2E */
+
+	u64 tb_orig_stamp;       /* Timebase at boot          0x30 */
+	u64 tb_ticks_per_sec;    /* Timebase tics / sec       0x38 */
+	u64 tb_to_xs;            /* Inverse of TB to 2^20     0x40 */
+	u64 stamp_xsec;          /*                           0x48 */
+	volatile u64 tb_update_count; /* Timebase atomicity   0x50 */
+	u32 tz_minuteswest;      /* Minutes west of Greenwich 0x58 */
+	u32 tz_dsttime;          /* Type of dst correction    0x5C */
+
+	u64 resv1[4];            /* Reserverd          0x60 - 0x7F */
+};
+
+/* Platform types */
+#define PLATFORM_PSERIES      0x0100
+#define PLATFORM_PSERIES_LPAR 0x0101
+#define PLATFORM_ISERIES_LPAR 0x0201
+
+/* Processor types */
+#define PV_PULSAR       0x0034
+#define PV_POWER4       0x0035
+#define PV_ICESTAR      0x0036
+#define PV_SSTAR        0x0037
+#define PV_630          0x0040
+#define PV_630p         0x0041
+
+#endif /* USER_EXPORTS_H */
diff -urN linux-2.4.20-pre4/include/asm-ppc64/vga.h linux-2.4.20-pre5/include/asm-ppc64/vga.h
--- linux-2.4.20-pre4/include/asm-ppc64/vga.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/include/asm-ppc64/vga.h	Wed Aug 28 16:38:25 2002
@@ -26,12 +26,12 @@
  *  <linux/vt_buffer.h> has already done the right job for us.
  */
 
-extern inline void scr_writew(u16 val, volatile u16 *addr)
+static inline void scr_writew(u16 val, volatile u16 *addr)
 {
     st_le16(addr, val);
 }
 
-extern inline u16 scr_readw(volatile const u16 *addr)
+static inline u16 scr_readw(volatile const u16 *addr)
 {
     return ld_le16(addr);
 }
diff -urN linux-2.4.20-pre4/include/asm-sparc/io.h linux-2.4.20-pre5/include/asm-sparc/io.h
--- linux-2.4.20-pre4/include/asm-sparc/io.h	Tue Nov 13 09:16:05 2001
+++ linux-2.4.20-pre5/include/asm-sparc/io.h	Wed Aug 28 16:38:25 2002
@@ -13,6 +13,7 @@
 
 #define virt_to_bus virt_to_phys
 #define bus_to_virt phys_to_virt
+#define page_to_phys(page)     ((((page) - mem_map) << PAGE_SHIFT)+phys_base)
 
 static __inline__ u32 flip_dword (u32 d)
 {
diff -urN linux-2.4.20-pre4/include/asm-sparc/pci.h linux-2.4.20-pre5/include/asm-sparc/pci.h
--- linux-2.4.20-pre4/include/asm-sparc/pci.h	Mon Feb 25 11:38:13 2002
+++ linux-2.4.20-pre5/include/asm-sparc/pci.h	Wed Aug 28 16:38:25 2002
@@ -27,6 +27,12 @@
 /* Dynamic DMA mapping stuff.
  */
 
+/* The PCI address space does not equal the physical memory
+ * address space.  The networking and block device layers use
+ * this boolean for bounce buffer decisions.
+ */
+#define PCI_DMA_BUS_IS_PHYS     (0)
+
 #include <asm/scatterlist.h>
 
 struct pci_dev;
diff -urN linux-2.4.20-pre4/include/asm-sparc/types.h linux-2.4.20-pre5/include/asm-sparc/types.h
--- linux-2.4.20-pre4/include/asm-sparc/types.h	Mon Jan 31 23:37:19 2000
+++ linux-2.4.20-pre5/include/asm-sparc/types.h	Wed Aug 28 16:38:25 2002
@@ -46,6 +46,7 @@
 #define BITS_PER_LONG 32
 
 typedef u32 dma_addr_t;
+typedef u32 dma64_addr_t;
 
 #endif /* __KERNEL__ */
 
diff -urN linux-2.4.20-pre4/include/asm-sparc64/asi.h linux-2.4.20-pre5/include/asm-sparc64/asi.h
--- linux-2.4.20-pre4/include/asm-sparc64/asi.h	Thu Apr 12 12:10:25 2001
+++ linux-2.4.20-pre5/include/asm-sparc64/asi.h	Wed Aug 28 16:38:25 2002
@@ -40,6 +40,7 @@
 #define ASI_WCACHE_DATA		0x39 /* (III) WCache data RAM diag		*/
 #define ASI_WCACHE_TAG		0x3a /* (III) WCache tag RAM diag		*/
 #define ASI_WCACHE_SNOOP_TAG	0x3b /* (III) WCache snoop tag RAM diag		*/
+#define ASI_SRAM_FAST_INIT	0x40 /* (III+) Fast SRAM init			*/
 #define ASI_DCACHE_INVALIDATE	0x42 /* (III) DCache Invalidate diag		*/
 #define ASI_DCACHE_UTAG		0x43 /* (III) DCache uTag diag			*/
 #define ASI_DCACHE_SNOOP_TAG	0x44 /* (III) DCache snoop tag RAM diag		*/
diff -urN linux-2.4.20-pre4/include/asm-sparc64/dcr.h linux-2.4.20-pre5/include/asm-sparc64/dcr.h
--- linux-2.4.20-pre4/include/asm-sparc64/dcr.h	Sun Mar 25 18:14:21 2001
+++ linux-2.4.20-pre5/include/asm-sparc64/dcr.h	Wed Aug 28 16:38:25 2002
@@ -2,11 +2,13 @@
 #ifndef _SPARC64_DCR_H
 #define _SPARC64_DCR_H
 
-/* UltraSparc-III Dispatch Control Register, ASR 0x12 */
+/* UltraSparc-III/III+ Dispatch Control Register, ASR 0x12 */
+#define DCR_DPE		0x0000000000001000 /* III+: D$ Parity Error Enable	*/
 #define DCR_OBS		0x0000000000000fc0 /* Observability Bus Controls	*/
 #define DCR_BPE		0x0000000000000020 /* Branch Predict Enable		*/
 #define DCR_RPE		0x0000000000000010 /* Return Address Prediction Enable	*/
 #define DCR_SI		0x0000000000000008 /* Single Instruction Disable	*/
+#define DCR_IPE		0x0000000000000004 /* III+: I$ Parity Error Enable	*/
 #define DCR_IFPOE	0x0000000000000002 /* IRQ FP Operation Enable		*/
 #define DCR_MS		0x0000000000000001 /* Multi-Scalar dispatch		*/
 
diff -urN linux-2.4.20-pre4/include/asm-sparc64/elf.h linux-2.4.20-pre5/include/asm-sparc64/elf.h
--- linux-2.4.20-pre4/include/asm-sparc64/elf.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/include/asm-sparc64/elf.h	Wed Aug 28 16:38:25 2002
@@ -90,7 +90,8 @@
 #define ELF_HWCAP	((HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | \
 			  HWCAP_SPARC_SWAP | HWCAP_SPARC_MULDIV | \
 			  HWCAP_SPARC_V9) | \
-			 ((tlb_type == cheetah) ? HWCAP_SPARC_ULTRA3 : 0))
+			 ((tlb_type == cheetah || tlb_type == cheetah_plus) ? \
+			  HWCAP_SPARC_ULTRA3 : 0))
 
 /* This yields a string that ld.so will use to load implementation
    specific libraries for optimization.  This is more specific in
diff -urN linux-2.4.20-pre4/include/asm-sparc64/head.h linux-2.4.20-pre5/include/asm-sparc64/head.h
--- linux-2.4.20-pre4/include/asm-sparc64/head.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/include/asm-sparc64/head.h	Wed Aug 28 16:38:25 2002
@@ -8,4 +8,7 @@
 
 #define	PTREGS_OFF	(STACK_BIAS + REGWIN_SZ)
 
+#define CHEETAH_ID	0x003e0014
+#define CHEETAH_PLUS_ID	0x003e0015
+
 #endif /* !(_SPARC64_HEAD_H) */
diff -urN linux-2.4.20-pre4/include/asm-sparc64/smp.h linux-2.4.20-pre5/include/asm-sparc64/smp.h
--- linux-2.4.20-pre4/include/asm-sparc64/smp.h	Fri Dec 21 09:42:03 2001
+++ linux-2.4.20-pre5/include/asm-sparc64/smp.h	Wed Aug 28 16:38:25 2002
@@ -86,7 +86,7 @@
 
 extern __inline__ int hard_smp_processor_id(void)
 {
-	if (tlb_type == cheetah) {
+	if (tlb_type == cheetah || tlb_type == cheetah_plus) {
 		unsigned long safari_config;
 		__asm__ __volatile__("ldxa [%%g0] %1, %0"
 				     : "=r" (safari_config)
diff -urN linux-2.4.20-pre4/include/asm-sparc64/spitfire.h linux-2.4.20-pre5/include/asm-sparc64/spitfire.h
--- linux-2.4.20-pre4/include/asm-sparc64/spitfire.h	Fri Dec 21 09:42:03 2001
+++ linux-2.4.20-pre5/include/asm-sparc64/spitfire.h	Wed Aug 28 16:38:25 2002
@@ -22,6 +22,7 @@
 #define TSB_EXTENSION_P		0x0000000000000048 /* Ultra-III and later		*/
 #define TSB_EXTENSION_S		0x0000000000000050 /* Ultra-III and later, D-TLB only	*/
 #define TSB_EXTENSION_N		0x0000000000000058 /* Ultra-III and later		*/
+#define TLB_TAG_ACCESS_EXT	0x0000000000000060 /* Ultra-III+ and later		*/
 
 /* These registers only exist as one entity, and are accessed
  * via ASI_DMMU only.
@@ -38,12 +39,13 @@
 
 enum ultra_tlb_layout {
 	spitfire = 0,
-	cheetah = 1
+	cheetah = 1,
+	cheetah_plus = 2,
 };
 
 extern enum ultra_tlb_layout tlb_type;
 
-#define SPARC64_USE_STICK	(tlb_type == cheetah)
+#define SPARC64_USE_STICK	(tlb_type != spitfire)
 
 #define CHEETAH_HIGHEST_LOCKED_TLBENT	(16 - 1)
 
@@ -433,35 +435,35 @@
 			       "i" (ASI_ITLB_DATA_ACCESS));
 }
 
-extern __inline__ unsigned long cheetah_get_dtlb_data(int entry)
+extern __inline__ unsigned long cheetah_get_dtlb_data(int entry, int tlb)
 {
 	unsigned long data;
 
 	__asm__ __volatile__("ldxa	[%1] %2, %%g0\n\t"
 			     "ldxa	[%1] %2, %0"
 			     : "=r" (data)
-			     : "r" ((2 << 16) | (entry << 3)), "i" (ASI_DTLB_DATA_ACCESS));
+			     : "r" ((tlb << 16) | (entry << 3)), "i" (ASI_DTLB_DATA_ACCESS));
 
 	return data;
 }
 
-extern __inline__ unsigned long cheetah_get_dtlb_tag(int entry)
+extern __inline__ unsigned long cheetah_get_dtlb_tag(int entry, int tlb)
 {
 	unsigned long tag;
 
 	__asm__ __volatile__("ldxa	[%1] %2, %0"
 			     : "=r" (tag)
-			     : "r" ((2 << 16) | (entry << 3)), "i" (ASI_DTLB_TAG_READ));
+			     : "r" ((tlb << 16) | (entry << 3)), "i" (ASI_DTLB_TAG_READ));
 	return tag;
 }
 
-extern __inline__ void cheetah_put_dtlb_data(int entry, unsigned long data)
+extern __inline__ void cheetah_put_dtlb_data(int entry, unsigned long data, int tlb)
 {
 	__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
 			     "membar	#Sync"
 			     : /* No outputs */
 			     : "r" (data),
-			       "r" ((2 << 16) | (entry << 3)),
+			       "r" ((tlb << 16) | (entry << 3)),
 			       "i" (ASI_DTLB_DATA_ACCESS));
 }
 
diff -urN linux-2.4.20-pre4/include/linux/blkdev.h linux-2.4.20-pre5/include/linux/blkdev.h
--- linux-2.4.20-pre4/include/linux/blkdev.h	Wed Aug 28 16:37:15 2002
+++ linux-2.4.20-pre5/include/linux/blkdev.h	Wed Aug 28 16:38:25 2002
@@ -6,6 +6,7 @@
 #include <linux/genhd.h>
 #include <linux/tqueue.h>
 #include <linux/list.h>
+#include <linux/mm.h>
 
 #include <asm/io.h>
 
diff -urN linux-2.4.20-pre4/include/linux/fs.h linux-2.4.20-pre5/include/linux/fs.h
--- linux-2.4.20-pre4/include/linux/fs.h	Wed Aug 28 16:37:15 2002
+++ linux-2.4.20-pre5/include/linux/fs.h	Wed Aug 28 16:38:25 2002
@@ -997,7 +997,6 @@
 extern struct vfsmount *kern_mount(struct file_system_type *);
 extern int may_umount(struct vfsmount *);
 extern long do_mount(char *, char *, char *, unsigned long, void *);
-extern void umount_tree(struct vfsmount *);
 
 #define kern_umount mntput
 
@@ -1329,6 +1328,7 @@
 extern int FASTCALL(__user_walk(const char *, unsigned, struct nameidata *));
 extern int FASTCALL(path_init(const char *, unsigned, struct nameidata *));
 extern int FASTCALL(path_walk(const char *, struct nameidata *));
+extern int FASTCALL(path_lookup(const char *, unsigned, struct nameidata *));
 extern int FASTCALL(link_path_walk(const char *, struct nameidata *));
 extern void path_release(struct nameidata *);
 extern int follow_down(struct vfsmount **, struct dentry **);
diff -urN linux-2.4.20-pre4/include/linux/hiddev.h linux-2.4.20-pre5/include/linux/hiddev.h
--- linux-2.4.20-pre4/include/linux/hiddev.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/include/linux/hiddev.h	Wed Aug 28 16:38:25 2002
@@ -183,7 +183,7 @@
 int __init hiddev_init(void);
 void __exit hiddev_exit(void);
 #else
-static inline void *hiddev_connect(struct hid_device *hid) { return NULL; }
+static inline int hiddev_connect(struct hid_device *hid) { return -1; }
 static inline void hiddev_disconnect(struct hid_device *hid) { }
 static inline void hiddev_hid_event(struct hid_device *hid, unsigned int usage, int value) { }
 static inline int hiddev_init(void) { return 0; }
diff -urN linux-2.4.20-pre4/include/linux/input.h linux-2.4.20-pre5/include/linux/input.h
--- linux-2.4.20-pre4/include/linux/input.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/include/linux/input.h	Wed Aug 28 16:38:25 2002
@@ -471,6 +471,7 @@
 #define BUS_PCI			0x01
 #define BUS_ISAPNP		0x02
 #define BUS_USB			0x03
+#define BUS_HIL                 0x04
 
 #define BUS_ISA			0x10
 #define BUS_I8042		0x11
diff -urN linux-2.4.20-pre4/include/linux/jbd.h linux-2.4.20-pre5/include/linux/jbd.h
--- linux-2.4.20-pre4/include/linux/jbd.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/include/linux/jbd.h	Wed Aug 28 16:38:25 2002
@@ -32,6 +32,14 @@
 
 #define journal_oom_retry 1
 
+/*
+ * Define JBD_PARANOID_WRITES to cause a kernel BUG() check if ext3
+ * finds a buffer unexpectedly dirty.  This is useful for debugging, but
+ * can cause spurious kernel panics if there are applications such as
+ * tune2fs modifying our buffer_heads behind our backs.
+ */
+#undef JBD_PARANOID_WRITES
+
 #ifdef CONFIG_JBD_DEBUG
 /*
  * Define JBD_EXPENSIVE_CHECKING to enable more expensive internal
@@ -730,6 +738,10 @@
 	schedule();						      \
 } while (1)
 
+extern void __jbd_unexpected_dirty_buffer(char *, int, struct journal_head *);
+#define jbd_unexpected_dirty_buffer(jh) \
+	__jbd_unexpected_dirty_buffer(__FUNCTION__, __LINE__, (jh))
+	
 /*
  * is_journal_abort
  *
diff -urN linux-2.4.20-pre4/include/linux/kernel_stat.h linux-2.4.20-pre5/include/linux/kernel_stat.h
--- linux-2.4.20-pre4/include/linux/kernel_stat.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/include/linux/kernel_stat.h	Wed Aug 28 16:38:25 2002
@@ -26,7 +26,9 @@
 	unsigned int dk_drive_wblk[DK_MAX_MAJOR][DK_MAX_DISK];
 	unsigned int pgpgin, pgpgout;
 	unsigned int pswpin, pswpout;
-#if !defined(CONFIG_ARCH_S390)
+#if defined (__hppa__) 
+	unsigned int irqs[NR_IRQ_REGS][IRQ_PER_REGION];
+#elif !defined(CONFIG_ARCH_S390)
 	unsigned int irqs[NR_CPUS][NR_IRQS];
 #endif
 	unsigned int context_swtch;
@@ -34,12 +36,22 @@
 
 extern struct kernel_stat kstat;
 
-#if !defined(CONFIG_ARCH_S390)
+extern unsigned long nr_context_switches(void);
+
+#if defined (__hppa__) 
 /*
  * Number of interrupts per specific IRQ source, since bootup
  */
 static inline int kstat_irqs (int irq)
 {
+	return kstat.irqs[IRQ_REGION(irq)][IRQ_OFFSET(irq)];
+}
+#elif !defined(CONFIG_ARCH_S390)
+/*
+ * Number of interrupts per specific IRQ source, since bootup
+ */
+extern inline int kstat_irqs (int irq)
+{
 	int i, sum=0;
 
 	for (i = 0 ; i < smp_num_cpus ; i++)
diff -urN linux-2.4.20-pre4/include/linux/list.h linux-2.4.20-pre5/include/linux/list.h
--- linux-2.4.20-pre4/include/linux/list.h	Fri Dec 21 09:42:03 2001
+++ linux-2.4.20-pre5/include/linux/list.h	Wed Aug 28 16:38:25 2002
@@ -172,6 +172,19 @@
         	pos = pos->prev, prefetch(pos->prev))
         	
 
+/**
+ * list_for_each_entry	-	iterate over list of given type
+ * @pos:	the type * to use as a loop counter.
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member)				\
+	for (pos = list_entry((head)->next, typeof(*pos), member),	\
+		     prefetch(pos->member.next);			\
+	     &pos->member != (head); 					\
+	     pos = list_entry(pos->member.next, typeof(*pos), member),	\
+		     prefetch(pos->member.next))
+
 #endif /* __KERNEL__ || _LVM_H_INCLUDE */
 
 #endif
diff -urN linux-2.4.20-pre4/include/linux/namespace.h linux-2.4.20-pre5/include/linux/namespace.h
--- linux-2.4.20-pre4/include/linux/namespace.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/include/linux/namespace.h	Wed Aug 28 16:38:25 2002
@@ -9,6 +9,8 @@
 	struct rw_semaphore	sem;
 };
 
+extern void umount_tree(struct vfsmount *);
+
 static inline void put_namespace(struct namespace *namespace)
 {
 	if (atomic_dec_and_test(&namespace->count)) {
diff -urN linux-2.4.20-pre4/include/linux/parport.h linux-2.4.20-pre5/include/linux/parport.h
--- linux-2.4.20-pre4/include/linux/parport.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre5/include/linux/parport.h	Wed Aug 28 16:38:25 2002
@@ -544,7 +544,7 @@
 extern void inc_parport_count(void);
 
 /* If PC hardware is the only type supported, we can optimise a bit.  */
-#if (defined(CONFIG_PARPORT_PC) || defined(CONFIG_PARPORT_PC_MODULE)) && !(defined(CONFIG_PARPORT_ARC) || defined(CONFIG_PARPORT_ARC_MODULE)) && !(defined(CONFIG_PARPORT_AMIGA) || defined(CONFIG_PARPORT_AMIGA_MODULE)) && !(defined(CONFIG_PARPORT_MFC3) || defined(CONFIG_PARPORT_MFC3_MODULE)) && !(defined(CONFIG_PARPORT_ATARI) || defined(CONFIG_PARPORT_ATARI_MODULE)) && !(defined(CONFIG_USB_USS720) || defined(CONFIG_USB_USS720_MODULE)) && !(defined(CONFIG_PARPORT_SUNBPP) || defined(CONFIG_PARPORT_SUNBPP_MODULE)) && !defined(CONFIG_PARPORT_OTHER)
+#if (defined(CONFIG_PARPORT_PC) || defined(CONFIG_PARPORT_PC_MODULE)) && !(defined(CONFIG_PARPORT_ARC) || defined(CONFIG_PARPORT_ARC_MODULE)) && !(defined(CONFIG_PARPORT_AMIGA) || defined(CONFIG_PARPORT_AMIGA_MODULE)) && !(defined(CONFIG_PARPORT_MFC3) || defined(CONFIG_PARPORT_MFC3_MODULE)) && !(defined(CONFIG_PARPORT_ATARI) || defined(CONFIG_PARPORT_ATARI_MODULE)) && !(defined(CONFIG_USB_USS720) || defined(CONFIG_USB_USS720_MODULE)) && !(defined(CONFIG_PARPORT_SUNBPP) || defined(CONFIG_PARPORT_SUNBPP_MODULE)) && !(defined(CONFIG_PARPORT_GSC) || defined(CONFIG_PARPORT_GSC_MODULE)) && !defined(CONFIG_PARPORT_OTHER)
 
 #undef PARPORT_NEED_GENERIC_OPS
 #include <linux/parport_pc.h>
diff -urN linux-2.4.20-pre4/include/linux/pci.h linux-2.4.20-pre5/include/linux/pci.h
--- linux-2.4.20-pre4/include/linux/pci.h	Wed Aug 28 16:37:15 2002
+++ linux-2.4.20-pre5/include/linux/pci.h	Wed Aug 28 16:38:25 2002
@@ -585,9 +585,11 @@
 unsigned long pci_bridge_check_io(struct pci_dev *);
 void pci_fixup_irqs(u8 (*)(struct pci_dev *, u8 *),
 		    int (*)(struct pci_dev *, u8, u8));
-#define HAVE_PCI_REQ_REGIONS
+#define HAVE_PCI_REQ_REGIONS	2
 int pci_request_regions(struct pci_dev *, char *);
 void pci_release_regions(struct pci_dev *);
+int pci_request_region(struct pci_dev *, int, char *);
+void pci_release_region(struct pci_dev *, int);
 
 /* New-style probing supporting hot-pluggable devices */
 int pci_register_driver(struct pci_driver *);
diff -urN linux-2.4.20-pre4/include/linux/raid/md_compatible.h linux-2.4.20-pre5/include/linux/raid/md_compatible.h
--- linux-2.4.20-pre4/include/linux/raid/md_compatible.h	Wed Aug 28 16:37:15 2002
+++ linux-2.4.20-pre5/include/linux/raid/md_compatible.h	Wed Aug 28 16:38:25 2002
@@ -99,7 +99,6 @@
 #define md_test_and_clear_bit test_and_clear_bit
 
 /* 018 */
-#define md_atomic_read atomic_read
 #define md_atomic_set atomic_set
 
 /* 019 */
diff -urN linux-2.4.20-pre4/include/linux/rwsem-spinlock.h linux-2.4.20-pre5/include/linux/rwsem-spinlock.h
--- linux-2.4.20-pre4/include/linux/rwsem-spinlock.h	Thu Nov 22 11:46:19 2001
+++ linux-2.4.20-pre5/include/linux/rwsem-spinlock.h	Wed Aug 28 16:38:25 2002
@@ -3,6 +3,8 @@
  * Copyright (c) 2001   David Howells (dhowells@redhat.com).
  * - Derived partially from ideas by Andrea Arcangeli <andrea@suse.de>
  * - Derived also from comments by Linus
+ *
+ * Trylock by Brian Watson (Brian.J.Watson@compaq.com).
  */
 
 #ifndef _LINUX_RWSEM_SPINLOCK_H
@@ -54,7 +56,9 @@
 
 extern void FASTCALL(init_rwsem(struct rw_semaphore *sem));
 extern void FASTCALL(__down_read(struct rw_semaphore *sem));
+extern int FASTCALL(__down_read_trylock(struct rw_semaphore *sem));
 extern void FASTCALL(__down_write(struct rw_semaphore *sem));
+extern int FASTCALL(__down_write_trylock(struct rw_semaphore *sem));
 extern void FASTCALL(__up_read(struct rw_semaphore *sem));
 extern void FASTCALL(__up_write(struct rw_semaphore *sem));
 
diff -urN linux-2.4.20-pre4/include/linux/rwsem.h linux-2.4.20-pre5/include/linux/rwsem.h
--- linux-2.4.20-pre4/include/linux/rwsem.h	Thu Nov 22 11:46:19 2001
+++ linux-2.4.20-pre5/include/linux/rwsem.h	Wed Aug 28 16:38:25 2002
@@ -2,6 +2,8 @@
  *
  * Written by David Howells (dhowells@redhat.com).
  * Derived from asm-i386/semaphore.h
+ *
+ * Trylock by Brian Watson (Brian.J.Watson@compaq.com).
  */
 
 #ifndef _LINUX_RWSEM_H
@@ -46,6 +48,18 @@
 }
 
 /*
+ * trylock for reading -- returns 1 if successful, 0 if contention
+ */
+static inline int down_read_trylock(struct rw_semaphore *sem)
+{
+	int ret;
+	rwsemtrace(sem,"Entering down_read_trylock");
+	ret = __down_read_trylock(sem);
+	rwsemtrace(sem,"Leaving down_read_trylock");
+	return ret;
+}
+
+/*
  * lock for writing
  */
 static inline void down_write(struct rw_semaphore *sem)
@@ -56,6 +70,18 @@
 }
 
 /*
+ * trylock for writing -- returns 1 if successful, 0 if contention
+ */
+static inline int down_write_trylock(struct rw_semaphore *sem)
+{
+	int ret;
+	rwsemtrace(sem,"Entering down_write_trylock");
+	ret = __down_write_trylock(sem);
+	rwsemtrace(sem,"Leaving down_write_trylock");
+	return ret;
+}
+
+/*
  * release a read lock
  */
 static inline void up_read(struct rw_semaphore *sem)
diff -urN linux-2.4.20-pre4/include/linux/spinlock.h linux-2.4.20-pre5/include/linux/spinlock.h
--- linux-2.4.20-pre4/include/linux/spinlock.h	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre5/include/linux/spinlock.h	Wed Aug 28 16:38:25 2002
@@ -68,9 +68,10 @@
 /*
  * Your basic spinlocks, allowing only a single CPU anywhere
  *
- * Most gcc versions have a nasty bug with empty initializers.
+ * Some older gcc versions had a nasty bug with empty initializers.
+ * (XXX: could someone please confirm whether egcs 1.1 still has this bug?)
  */
-#if (__GNUC__ > 2)
+#if (__GNUC__ > 2 || __GNUC_MINOR__ > 91)
   typedef struct { } spinlock_t;
   #define SPIN_LOCK_UNLOCKED (spinlock_t) { }
 #else
@@ -131,9 +132,10 @@
  * irq-safe write-lock, but readers can get non-irqsafe
  * read-locks.
  *
- * Most gcc versions have a nasty bug with empty initializers.
+ * Some older gcc versions had a nasty bug with empty initializers.
+ * (XXX: could someone please confirm whether egcs 1.1 still has this bug?)
  */
-#if (__GNUC__ > 2)
+#if (__GNUC__ > 2 || __GNUC_MINOR__ > 91)
   typedef struct { } rwlock_t;
   #define RW_LOCK_UNLOCKED (rwlock_t) { }
 #else
diff -urN linux-2.4.20-pre4/include/linux/sunrpc/svcsock.h linux-2.4.20-pre5/include/linux/sunrpc/svcsock.h
--- linux-2.4.20-pre4/include/linux/sunrpc/svcsock.h	Wed Aug 28 16:37:15 2002
+++ linux-2.4.20-pre5/include/linux/sunrpc/svcsock.h	Wed Aug 28 16:38:25 2002
@@ -22,7 +22,7 @@
 
 	struct svc_serv *	sk_server;	/* service for this socket */
 	unsigned char		sk_inuse;	/* use count */
-	unsigned int		sk_flags;
+	unsigned long		sk_flags;
 #define	SK_BUSY		0			/* enqueued/receiving */
 #define	SK_CONN		1			/* conn pending */
 #define	SK_CLOSE	2			/* dead or dying */
diff -urN linux-2.4.20-pre4/include/linux/sunrpc/xdr.h linux-2.4.20-pre5/include/linux/sunrpc/xdr.h
--- linux-2.4.20-pre4/include/linux/sunrpc/xdr.h	Wed Aug 28 16:37:15 2002
+++ linux-2.4.20-pre5/include/linux/sunrpc/xdr.h	Wed Aug 28 16:38:25 2002
@@ -138,8 +138,7 @@
  */
 extern int xdr_kmap(struct iovec *, struct xdr_buf *, unsigned int);
 extern void xdr_kunmap(struct xdr_buf *, unsigned int);
-extern void xdr_shift_buf(struct xdr_buf *, unsigned int);
-extern void xdr_zero_buf(struct xdr_buf *, unsigned int);
+extern void xdr_shift_buf(struct xdr_buf *, size_t);
 
 /*
  * Helper structure for copying from an sk_buff.
diff -urN linux-2.4.20-pre4/include/video/fbcon.h linux-2.4.20-pre5/include/video/fbcon.h
--- linux-2.4.20-pre4/include/video/fbcon.h	Thu Sep 13 16:25:07 2001
+++ linux-2.4.20-pre5/include/video/fbcon.h	Wed Aug 28 16:38:25 2002
@@ -206,7 +206,8 @@
 #define fb_writel sbus_writel
 #define fb_memset sbus_memset_io
 
-#elif defined(__i386__) || defined(__alpha__) || defined(__x86_64__)
+#elif defined(__i386__) || defined(__alpha__) || \
+      defined(__x86_64__) || defined(__hppa__)
 
 #define fb_readb __raw_readb
 #define fb_readw __raw_readw
diff -urN linux-2.4.20-pre4/ipc/util.c linux-2.4.20-pre5/ipc/util.c
--- linux-2.4.20-pre4/ipc/util.c	Wed Aug 28 16:37:15 2002
+++ linux-2.4.20-pre5/ipc/util.c	Wed Aug 28 16:38:25 2002
@@ -312,7 +312,7 @@
 	out->seq	= in->seq;
 }
 
-#ifndef __ia64__
+#if !defined(__ia64__) && !defined(__hppa__)
 
 /**
  *	ipc_parse_version	-	IPC call version
diff -urN linux-2.4.20-pre4/ipc/util.h linux-2.4.20-pre5/ipc/util.h
--- linux-2.4.20-pre4/ipc/util.h	Mon Feb 19 10:18:18 2001
+++ linux-2.4.20-pre5/ipc/util.h	Wed Aug 28 16:38:25 2002
@@ -99,8 +99,8 @@
 void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out);
 void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out);
 
-#ifdef __ia64__
-  /* On IA-64, we always use the "64-bit version" of the IPC structures.  */ 
+#if defined(__ia64__) || defined(__hppa__)
+  /* On IA-64 and PA-RISC, we always use the "64-bit version" of the IPC structures.  */ 
 # define ipc_parse_version(cmd)	IPC_64
 #else
 int ipc_parse_version (int *cmd);
diff -urN linux-2.4.20-pre4/kernel/sched.c linux-2.4.20-pre5/kernel/sched.c
--- linux-2.4.20-pre4/kernel/sched.c	Wed Aug 28 16:37:15 2002
+++ linux-2.4.20-pre5/kernel/sched.c	Wed Aug 28 16:38:25 2002
@@ -318,13 +318,17 @@
 /*
  * Careful!
  *
- * This has to add the process to the _beginning_ of the
- * run-queue, not the end. See the comment about "This is
- * subtle" in the scheduler proper..
+ * This has to add the process to the _end_ of the 
+ * run-queue, not the beginning. The goodness value will
+ * determine whether this process will run next. This is
+ * important to get SCHED_FIFO and SCHED_RR right, where
+ * a process that is either pre-empted or its time slice
+ * has expired, should be moved to the tail of the run 
+ * queue for its priority - Bhavesh Davda
  */
 static inline void add_to_runqueue(struct task_struct * p)
 {
-	list_add(&p->run_list, &runqueue_head);
+	list_add_tail(&p->run_list, &runqueue_head);
 	nr_running++;
 }
 
@@ -334,12 +338,6 @@
 	list_add_tail(&p->run_list, &runqueue_head);
 }
 
-static inline void move_first_runqueue(struct task_struct * p)
-{
-	list_del(&p->run_list);
-	list_add(&p->run_list, &runqueue_head);
-}
-
 /*
  * Wake up a process. Put it on the run-queue if it's not
  * already there.  The "current" process is always on the
@@ -955,8 +953,6 @@
 	retval = 0;
 	p->policy = policy;
 	p->rt_priority = lp.sched_priority;
-	if (task_on_runqueue(p))
-		move_first_runqueue(p);
 
 	current->need_resched = 1;
 
diff -urN linux-2.4.20-pre4/kernel/softirq.c linux-2.4.20-pre5/kernel/softirq.c
--- linux-2.4.20-pre4/kernel/softirq.c	Wed Aug 28 16:37:15 2002
+++ linux-2.4.20-pre5/kernel/softirq.c	Wed Aug 28 16:38:25 2002
@@ -40,7 +40,7 @@
    - Bottom halves: globally serialized, grr...
  */
 
-irq_cpustat_t irq_stat[NR_CPUS];
+irq_cpustat_t irq_stat[NR_CPUS] ____cacheline_aligned;
 
 static struct softirq_action softirq_vec[32] __cacheline_aligned;
 
diff -urN linux-2.4.20-pre4/kernel/timer.c linux-2.4.20-pre5/kernel/timer.c
--- linux-2.4.20-pre4/kernel/timer.c	Wed Aug 28 16:37:15 2002
+++ linux-2.4.20-pre5/kernel/timer.c	Wed Aug 28 16:38:25 2002
@@ -601,7 +601,14 @@
 	if (p->pid) {
 		if (--p->counter <= 0) {
 			p->counter = 0;
-			p->need_resched = 1;
+			/*
+			 * SCHED_FIFO is priority preemption, so this is 
+			 * not the place to decide whether to reschedule a
+			 * SCHED_FIFO task or not - Bhavesh Davda
+			 */
+			if (p->policy != SCHED_FIFO) {
+				p->need_resched = 1;
+			}
 		}
 		if (p->nice > 0)
 			kstat.per_cpu_nice[cpu] += user_tick;
diff -urN linux-2.4.20-pre4/net/ipv4/ipconfig.c linux-2.4.20-pre5/net/ipv4/ipconfig.c
--- linux-2.4.20-pre4/net/ipv4/ipconfig.c	Wed Aug 28 16:37:15 2002
+++ linux-2.4.20-pre5/net/ipv4/ipconfig.c	Wed Aug 28 16:38:26 2002
@@ -26,6 +26,9 @@
  *
  *  Merged changes from 2.2.19 into 2.4.3
  *              -- Eric Biederman <ebiederman@lnxi.com>, 22 April Aug 2001
+ *
+ *  Multipe Nameservers in /proc/net/pnp
+ *              --  Josef Siemes <jsiemes@web.de>, Aug 2002
  */
 
 #include <linux/config.h>
@@ -90,6 +93,8 @@
 #define CONF_TIMEOUT_RANDOM	(HZ)	/* Maximum amount of randomization */
 #define CONF_TIMEOUT_MULT	*7/4	/* Rate of timeout growth */
 #define CONF_TIMEOUT_MAX	(HZ*30)	/* Maximum allowed timeout */
+#define CONF_NAMESERVERS_MAX   3       /* Maximum number of nameservers  
+                                           - '3' from resolv.h */
 
 
 /*
@@ -131,7 +136,7 @@
 /* Persistent data: */
 
 int ic_proto_used;			/* Protocol used, if any */
-u32 ic_nameserver = INADDR_NONE;	/* DNS Server IP address */
+u32 ic_nameservers[CONF_NAMESERVERS_MAX]; /* DNS Server IP addresses */
 u8 ic_domain[64];		/* DNS (not NIS) domain name */
 
 /*
@@ -624,6 +629,11 @@
  */
 static inline void ic_bootp_init(void)
 {
+	int i;
+
+	for (i = 0; i < CONF_NAMESERVERS_MAX; i++)
+		ic_nameservers[i] = INADDR_NONE;
+
 	dev_add_pack(&bootp_packet_type);
 }
 
@@ -728,6 +738,9 @@
  */
 static void __init ic_do_bootp_ext(u8 *ext)
 {
+	u8 servers;
+	int i;
+
 #ifdef IPCONFIG_DEBUG
 	u8 *c;
 
@@ -747,8 +760,13 @@
 				memcpy(&ic_gateway, ext+1, 4);
 			break;
 		case 6:		/* DNS server */
-			if (ic_nameserver == INADDR_NONE)
-				memcpy(&ic_nameserver, ext+1, 4);
+			servers= *ext/4;
+			if (servers > CONF_NAMESERVERS_MAX)
+				servers = CONF_NAMESERVERS_MAX;
+			for (i = 0; i < servers; i++) {
+				if (ic_nameservers[i] == INADDR_NONE)
+					memcpy(&ic_nameservers[i], ext+1+4*i, 4);
+			}
 			break;
 		case 12:	/* Host name */
 			ic_bootp_string(system_utsname.nodename, ext+1, *ext, __NEW_UTS_LEN);
@@ -913,8 +931,8 @@
 	ic_servaddr = b->server_ip;
 	if (ic_gateway == INADDR_NONE && b->relay_ip)
 		ic_gateway = b->relay_ip;
-	if (ic_nameserver == INADDR_NONE)
-		ic_nameserver = ic_servaddr;
+	if (ic_nameservers[0] == INADDR_NONE)
+		ic_nameservers[0] = ic_servaddr;
 	ic_got_reply = IC_BOOTP;
 
 drop:
@@ -1077,6 +1095,7 @@
 			off_t offset, int length)
 {
 	int len;
+	int i;
 
 	if (ic_proto_used & IC_PROTO)
 	    sprintf(buffer, "#PROTO: %s\n",
@@ -1089,9 +1108,12 @@
 	if (ic_domain[0])
 		len += sprintf(buffer + len,
 			       "domain %s\n", ic_domain);
-	if (ic_nameserver != INADDR_NONE)
-		len += sprintf(buffer + len,
-			       "nameserver %u.%u.%u.%u\n", NIPQUAD(ic_nameserver));
+	for (i = 0; i < CONF_NAMESERVERS_MAX; i++) {
+		if (ic_nameservers[i] != INADDR_NONE)
+			len += sprintf(buffer + len,
+				       "nameserver %u.%u.%u.%u\n",
+				       NIPQUAD(ic_nameservers[i]));
+	}
 
 	if (offset > len)
 		offset = len;
diff -urN linux-2.4.20-pre4/net/ipv4/netfilter/ip_conntrack_core.c linux-2.4.20-pre5/net/ipv4/netfilter/ip_conntrack_core.c
--- linux-2.4.20-pre4/net/ipv4/netfilter/ip_conntrack_core.c	Wed Aug 28 16:37:15 2002
+++ linux-2.4.20-pre5/net/ipv4/netfilter/ip_conntrack_core.c	Wed Aug 28 16:38:26 2002
@@ -463,7 +463,7 @@
 			     &ct->tuplehash[IP_CT_DIR_REPLY]);
 		/* Timer relative to confirmation time, not original
 		   setting time, otherwise we'd get timer wrap in
-		   wierd delay cases. */
+		   weird delay cases. */
 		ct->timeout.expires += jiffies;
 		add_timer(&ct->timeout);
 		atomic_inc(&ct->ct_general.use);
diff -urN linux-2.4.20-pre4/net/ipv4/netfilter/ip_nat_core.c linux-2.4.20-pre5/net/ipv4/netfilter/ip_nat_core.c
--- linux-2.4.20-pre4/net/ipv4/netfilter/ip_nat_core.c	Wed Aug 28 16:37:15 2002
+++ linux-2.4.20-pre5/net/ipv4/netfilter/ip_nat_core.c	Wed Aug 28 16:38:26 2002
@@ -894,7 +894,7 @@
 	/* Note: May not be from a NAT'd host, but probably safest to
 	   do translation always as if it came from the host itself
 	   (even though a "host unreachable" coming from the host
-	   itself is a bit wierd).
+	   itself is a bit weird).
 
 	   More explanation: some people use NAT for anonymizing.
 	   Also, CERT recommends dropping all packets from private IP
diff -urN linux-2.4.20-pre4/net/ipv4/netfilter/ip_queue.c linux-2.4.20-pre5/net/ipv4/netfilter/ip_queue.c
--- linux-2.4.20-pre4/net/ipv4/netfilter/ip_queue.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre5/net/ipv4/netfilter/ip_queue.c	Wed Aug 28 16:38:26 2002
@@ -2,13 +2,14 @@
  * This is a module which is used for queueing IPv4 packets and
  * communicating with userspace via netlink.
  *
- * (C) 2000 James Morris, this code is GPL.
+ * (C) 2000-2002 James Morris, this code is GPL.
  *
  * 2000-03-27: Simplified code (thanks to Andi Kleen for clues).
  * 2000-05-20: Fixed notifier problems (following Miguel Freitas' report).
  * 2000-06-19: Fixed so nfmark is copied to metadata (reported by Sebastian 
  *             Zander).
  * 2000-08-01: Added Nick Williams' MAC support.
+ * 2002-06-25: Code cleanup.
  *
  */
 #include <linux/module.h>
@@ -18,205 +19,310 @@
 #include <linux/notifier.h>
 #include <linux/netdevice.h>
 #include <linux/netfilter.h>
+#include <linux/netfilter_ipv4/ip_queue.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
 #include <linux/netlink.h>
 #include <linux/spinlock.h>
-#include <linux/rtnetlink.h>
+#include <linux/brlock.h>
 #include <linux/sysctl.h>
 #include <linux/proc_fs.h>
 #include <net/sock.h>
 #include <net/route.h>
 
-#include <linux/netfilter_ipv4/ip_queue.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-
 #define IPQ_QMAX_DEFAULT 1024
 #define IPQ_PROC_FS_NAME "ip_queue"
 #define NET_IPQ_QMAX 2088
 #define NET_IPQ_QMAX_NAME "ip_queue_maxlen"
 
-typedef struct ipq_rt_info {
+struct ipq_rt_info {
 	__u8 tos;
 	__u32 daddr;
 	__u32 saddr;
-} ipq_rt_info_t;
+};
 
-typedef struct ipq_queue_element {
-	struct list_head list;		/* Links element into queue */
-	int verdict;			/* Current verdict */
-	struct nf_info *info;		/* Extra info from netfilter */
-	struct sk_buff *skb;		/* Packet inside */
-	ipq_rt_info_t rt_info;		/* May need post-mangle routing */
-} ipq_queue_element_t;
-
-typedef int (*ipq_send_cb_t)(ipq_queue_element_t *e);
-
-typedef struct ipq_peer {
-	pid_t pid;			/* PID of userland peer */
-	unsigned char died;		/* We think the peer died */
-	unsigned char copy_mode;	/* Copy packet as well as metadata? */
-	size_t copy_range;		/* Range past metadata to copy */
-	ipq_send_cb_t send;		/* Callback for sending data to peer */
-} ipq_peer_t;
-
-typedef struct ipq_queue {
- 	int len;			/* Current queue len */
- 	int *maxlen;			/* Maximum queue len, via sysctl */
- 	unsigned char flushing;		/* If queue is being flushed */
- 	unsigned char terminate;	/* If the queue is being terminated */
- 	struct list_head list;		/* Head of packet queue */
- 	spinlock_t lock;		/* Queue spinlock */
- 	ipq_peer_t peer;		/* Userland peer */
-} ipq_queue_t;
+struct ipq_queue_entry {
+	struct list_head list;
+	struct nf_info *info;
+	struct sk_buff *skb;
+	struct ipq_rt_info rt_info;
+};
 
-/****************************************************************************
- *
- * Packet queue
- *
- ****************************************************************************/
-/* Dequeue a packet if matched by cmp, or the next available if cmp is NULL */
-static ipq_queue_element_t *
-ipq_dequeue(ipq_queue_t *q,
-            int (*cmp)(ipq_queue_element_t *, unsigned long),
-            unsigned long data)
-{
-	struct list_head *i;
-
-	spin_lock_bh(&q->lock);
-	for (i = q->list.prev; i != &q->list; i = i->prev) {
-		ipq_queue_element_t *e = (ipq_queue_element_t *)i;
-		
-		if (!cmp || cmp(e, data)) {
-			list_del(&e->list);
-			q->len--;
-			spin_unlock_bh(&q->lock);
-			return e;
-		}
+typedef int (*ipq_cmpfn)(struct ipq_queue_entry *, unsigned long);
+
+static unsigned char copy_mode = IPQ_COPY_NONE;
+static unsigned int queue_maxlen = IPQ_QMAX_DEFAULT;
+static rwlock_t queue_lock = RW_LOCK_UNLOCKED;
+static int peer_pid;
+static unsigned int copy_range;
+static unsigned int queue_total;
+static struct sock *ipqnl;
+static LIST_HEAD(queue_list);
+static DECLARE_MUTEX(ipqnl_sem);
+
+static void
+ipq_issue_verdict(struct ipq_queue_entry *entry, int verdict)
+{
+	nf_reinject(entry->skb, entry->info, verdict);
+	kfree(entry);
+}
+
+static inline int
+__ipq_enqueue_entry(struct ipq_queue_entry *entry)
+{
+       if (queue_total >= queue_maxlen) {
+               if (net_ratelimit()) 
+                       printk(KERN_WARNING "ip_queue: full at %d entries, "
+                              "dropping packet(s).\n", queue_total);
+               return -ENOSPC;
+       }
+       list_add(&entry->list, &queue_list);
+       queue_total++;
+       return 0;
+}
+
+/*
+ * Find and return a queued entry matched by cmpfn, or return the last
+ * entry if cmpfn is NULL.
+ */
+static inline struct ipq_queue_entry *
+__ipq_find_entry(ipq_cmpfn cmpfn, unsigned long data)
+{
+	struct list_head *p;
+
+	list_for_each_prev(p, &queue_list) {
+		struct ipq_queue_entry *entry = (struct ipq_queue_entry *)p;
+		
+		if (!cmpfn || cmpfn(entry, data))
+			return entry;
 	}
-	spin_unlock_bh(&q->lock);
 	return NULL;
 }
 
-/* Flush all packets */
-static void ipq_flush(ipq_queue_t *q)
+static inline void
+__ipq_dequeue_entry(struct ipq_queue_entry *entry)
 {
-	ipq_queue_element_t *e;
-	
-	spin_lock_bh(&q->lock);
-	q->flushing = 1;
-	spin_unlock_bh(&q->lock);
-	while ((e = ipq_dequeue(q, NULL, 0))) {
-		e->verdict = NF_DROP;
-		nf_reinject(e->skb, e->info, e->verdict);
-		kfree(e);
-	}
-	spin_lock_bh(&q->lock);
-	q->flushing = 0;
-	spin_unlock_bh(&q->lock);
-}
-
-static ipq_queue_t *ipq_create_queue(nf_queue_outfn_t outfn,
-                                     ipq_send_cb_t send_cb,
-                                     int *errp, int *sysctl_qmax)
+	list_del(&entry->list);
+	queue_total--;
+}
+
+static inline struct ipq_queue_entry *
+__ipq_find_dequeue_entry(ipq_cmpfn cmpfn, unsigned long data)
 {
-	int status;
-	ipq_queue_t *q;
+	struct ipq_queue_entry *entry;
 
-	*errp = 0;
-	q = kmalloc(sizeof(ipq_queue_t), GFP_KERNEL);
-	if (q == NULL) {
-		*errp = -ENOMEM;
+	entry = __ipq_find_entry(cmpfn, data);
+	if (entry == NULL)
 		return NULL;
+
+	__ipq_dequeue_entry(entry);
+	return entry;
+}
+
+
+static inline void
+__ipq_flush(int verdict)
+{
+	struct ipq_queue_entry *entry;
+	
+	while ((entry = __ipq_find_dequeue_entry(NULL, 0)))
+		ipq_issue_verdict(entry, verdict);
+}
+
+static inline int
+__ipq_set_mode(unsigned char mode, unsigned int range)
+{
+	int status = 0;
+	
+	switch(mode) {
+	case IPQ_COPY_NONE:
+	case IPQ_COPY_META:
+		copy_mode = mode;
+		copy_range = 0;
+		break;
+		
+	case IPQ_COPY_PACKET:
+		copy_mode = mode;
+		copy_range = range;
+		if (copy_range > 0xFFFF)
+			copy_range = 0xFFFF;
+		break;
+		
+	default:
+		status = -EINVAL;
+
 	}
-	q->peer.pid = 0;
-	q->peer.died = 0;
-	q->peer.copy_mode = IPQ_COPY_NONE;
-	q->peer.copy_range = 0;
-	q->peer.send = send_cb;
-	q->len = 0;
-	q->maxlen = sysctl_qmax;
-	q->flushing = 0;
-	q->terminate = 0;
-	INIT_LIST_HEAD(&q->list);
-	spin_lock_init(&q->lock);
-	status = nf_register_queue_handler(PF_INET, outfn, q);
-	if (status < 0) {
-		*errp = -EBUSY;
-		kfree(q);
+	return status;
+}
+
+static inline void
+__ipq_reset(void)
+{
+	peer_pid = 0;
+	__ipq_set_mode(IPQ_COPY_NONE, 0);
+	__ipq_flush(NF_DROP);
+}
+
+static struct ipq_queue_entry *
+ipq_find_dequeue_entry(ipq_cmpfn cmpfn, unsigned long data)
+{
+	struct ipq_queue_entry *entry;
+	
+	write_lock_bh(&queue_lock);
+	entry = __ipq_find_dequeue_entry(cmpfn, data);
+	write_unlock_bh(&queue_lock);
+	return entry;
+}
+
+static void
+ipq_flush(int verdict)
+{
+	write_lock_bh(&queue_lock);
+	__ipq_flush(verdict);
+	write_unlock_bh(&queue_lock);
+}
+
+static struct sk_buff *
+ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp)
+{
+	unsigned char *old_tail;
+	size_t size = 0;
+	size_t data_len = 0;
+	struct sk_buff *skb;
+	struct ipq_packet_msg *pmsg;
+	struct nlmsghdr *nlh;
+
+	read_lock_bh(&queue_lock);
+	
+	switch (copy_mode) {
+	case IPQ_COPY_META:
+	case IPQ_COPY_NONE:
+		size = NLMSG_SPACE(sizeof(*pmsg));
+		data_len = 0;
+		break;
+	
+	case IPQ_COPY_PACKET:
+		if (copy_range == 0 || copy_range > entry->skb->len)
+			data_len = entry->skb->len;
+		else
+			data_len = copy_range;
+		
+		size = NLMSG_SPACE(sizeof(*pmsg) + data_len);
+		break;
+	
+	default:
+		*errp = -EINVAL;
+		read_unlock_bh(&queue_lock);
 		return NULL;
 	}
-	return q;
+
+	read_unlock_bh(&queue_lock);
+
+	skb = alloc_skb(size, GFP_ATOMIC);
+	if (!skb)
+		goto nlmsg_failure;
+		
+	old_tail= skb->tail;
+	nlh = NLMSG_PUT(skb, 0, 0, IPQM_PACKET, size - sizeof(*nlh));
+	pmsg = NLMSG_DATA(nlh);
+	memset(pmsg, 0, sizeof(*pmsg));
+
+	pmsg->packet_id       = (unsigned long )entry;
+	pmsg->data_len        = data_len;
+	pmsg->timestamp_sec   = entry->skb->stamp.tv_sec;
+	pmsg->timestamp_usec  = entry->skb->stamp.tv_usec;
+	pmsg->mark            = entry->skb->nfmark;
+	pmsg->hook            = entry->info->hook;
+	pmsg->hw_protocol     = entry->skb->protocol;
+	
+	if (entry->info->indev)
+		strcpy(pmsg->indev_name, entry->info->indev->name);
+	else
+		pmsg->indev_name[0] = '\0';
+	
+	if (entry->info->outdev)
+		strcpy(pmsg->outdev_name, entry->info->outdev->name);
+	else
+		pmsg->outdev_name[0] = '\0';
+	
+	if (entry->info->indev && entry->skb->dev) {
+		pmsg->hw_type = entry->skb->dev->type;
+		if (entry->skb->dev->hard_header_parse)
+			pmsg->hw_addrlen =
+				entry->skb->dev->hard_header_parse(entry->skb,
+				                                   pmsg->hw_addr);
+	}
+	
+	if (data_len)
+		memcpy(pmsg->payload, entry->skb->data, data_len);
+		
+	nlh->nlmsg_len = skb->tail - old_tail;
+	return skb;
+
+nlmsg_failure:
+	if (skb)
+		kfree_skb(skb);
+	*errp = -EINVAL;
+	printk(KERN_ERR "ip_queue: error creating packet message\n");
+	return NULL;
 }
 
-static int ipq_enqueue(ipq_queue_t *q,
-                       struct sk_buff *skb, struct nf_info *info)
+static int
+ipq_enqueue_packet(struct sk_buff *skb, struct nf_info *info, void *data)
 {
-	ipq_queue_element_t *e;
-	int status;
-	
-	e = kmalloc(sizeof(*e), GFP_ATOMIC);
-	if (e == NULL) {
-		printk(KERN_ERR "ip_queue: OOM in enqueue\n");
+	int status = -EINVAL;
+	struct sk_buff *nskb;
+	struct ipq_queue_entry *entry;
+
+	if (copy_mode == IPQ_COPY_NONE)
+		return -EAGAIN;
+
+	entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
+	if (entry == NULL) {
+		printk(KERN_ERR "ip_queue: OOM in ipq_enqueue_packet()\n");
 		return -ENOMEM;
 	}
 
-	e->verdict = NF_DROP;
-	e->info = info;
-	e->skb = skb;
+	entry->info = info;
+	entry->skb = skb;
 
-	if (e->info->hook == NF_IP_LOCAL_OUT) {
+	if (entry->info->hook == NF_IP_LOCAL_OUT) {
 		struct iphdr *iph = skb->nh.iph;
 
-		e->rt_info.tos = iph->tos;
-		e->rt_info.daddr = iph->daddr;
-		e->rt_info.saddr = iph->saddr;
-	}
-
-	spin_lock_bh(&q->lock);
-	if (q->len >= *q->maxlen) {
-		spin_unlock_bh(&q->lock);
-		if (net_ratelimit()) 
-			printk(KERN_WARNING "ip_queue: full at %d entries, "
-			       "dropping packet(s).\n", q->len);
-		goto free_drop;
-	}
-	if (q->flushing || q->peer.copy_mode == IPQ_COPY_NONE
-	    || q->peer.pid == 0 || q->peer.died || q->terminate) {
-		spin_unlock_bh(&q->lock);
-		goto free_drop;
-	}
-	status = q->peer.send(e);
-	if (status > 0) {
-		list_add(&e->list, &q->list);
-		q->len++;
-		spin_unlock_bh(&q->lock);
-		return status;
-	}
-	spin_unlock_bh(&q->lock);
-	if (status == -ECONNREFUSED) {
-		printk(KERN_INFO "ip_queue: peer %d died, "
-		       "resetting state and flushing queue\n", q->peer.pid);
-			q->peer.died = 1;
-			q->peer.pid = 0;
-			q->peer.copy_mode = IPQ_COPY_NONE;
-			q->peer.copy_range = 0;
-			ipq_flush(q);
-	}
-free_drop:
-	kfree(e);
-	return -EBUSY;
-}
+		entry->rt_info.tos = iph->tos;
+		entry->rt_info.daddr = iph->daddr;
+		entry->rt_info.saddr = iph->saddr;
+	}
 
-static void ipq_destroy_queue(ipq_queue_t *q)
-{
-	nf_unregister_queue_handler(PF_INET);
-	spin_lock_bh(&q->lock);
-	q->terminate = 1;
-	spin_unlock_bh(&q->lock);
-	ipq_flush(q);
-	kfree(q);
+	nskb = ipq_build_packet_message(entry, &status);
+	if (nskb == NULL)
+		goto err_out_free;
+		
+	write_lock_bh(&queue_lock);
+	
+	if (!peer_pid)
+		goto err_out_unlock;
+
+	status = netlink_unicast(ipqnl, nskb, peer_pid, MSG_DONTWAIT);
+	if (status < 0)
+		goto err_out_unlock;
+	
+	status = __ipq_enqueue_entry(entry);
+	if (status < 0)
+		goto err_out_unlock;
+
+	write_unlock_bh(&queue_lock);
+	return status;
+	
+err_out_unlock:
+	write_unlock_bh(&queue_lock);
+
+err_out_free:
+	kfree(entry);
+	return status;
 }
 
-static int ipq_mangle_ipv4(ipq_verdict_msg_t *v, ipq_queue_element_t *e)
+static int
+ipq_mangle_ipv4(ipq_verdict_msg_t *v, struct ipq_queue_entry *e)
 {
 	int diff;
 	struct iphdr *user_iph = (struct iphdr *)v->payload;
@@ -266,296 +372,216 @@
 	return 0;
 }
 
-static inline int id_cmp(ipq_queue_element_t *e, unsigned long id)
+static inline int
+id_cmp(struct ipq_queue_entry *e, unsigned long id)
 {
 	return (id == (unsigned long )e);
 }
 
-static int ipq_set_verdict(ipq_queue_t *q,
-                           ipq_verdict_msg_t *v, unsigned int len)
+static int
+ipq_set_verdict(struct ipq_verdict_msg *vmsg, unsigned int len)
 {
-	ipq_queue_element_t *e;
+	struct ipq_queue_entry *entry;
 
-	if (v->value > NF_MAX_VERDICT)
+	if (vmsg->value > NF_MAX_VERDICT)
 		return -EINVAL;
-	e = ipq_dequeue(q, id_cmp, v->id);
-	if (e == NULL)
+
+	entry = ipq_find_dequeue_entry(id_cmp, vmsg->id);
+	if (entry == NULL)
 		return -ENOENT;
 	else {
-		e->verdict = v->value;
-		if (v->data_len && v->data_len == len)
-			if (ipq_mangle_ipv4(v, e) < 0)
-				e->verdict = NF_DROP;
-		nf_reinject(e->skb, e->info, e->verdict);
-		kfree(e);
+		int verdict = vmsg->value;
+		
+		if (vmsg->data_len && vmsg->data_len == len)
+			if (ipq_mangle_ipv4(vmsg, entry) < 0)
+				verdict = NF_DROP;
+		
+		ipq_issue_verdict(entry, verdict);
 		return 0;
 	}
 }
 
-static int ipq_receive_peer(ipq_queue_t *q, ipq_peer_msg_t *m,
-                            unsigned char type, unsigned int len)
+static int
+ipq_set_mode(unsigned char mode, unsigned int range)
 {
+	int status;
+
+	write_lock_bh(&queue_lock);
+	status = __ipq_set_mode(mode, range);
+	write_unlock_bh(&queue_lock);
+	return status;
+}
 
+static int
+ipq_receive_peer(struct ipq_peer_msg *pmsg,
+                 unsigned char type, unsigned int len)
+{
 	int status = 0;
-	int busy;
-		
-	spin_lock_bh(&q->lock);
-	busy = (q->terminate || q->flushing);
-	spin_unlock_bh(&q->lock);
-	if (busy)
-		return -EBUSY;
-	if (len < sizeof(ipq_peer_msg_t))
+
+	if (len < sizeof(*pmsg))
 		return -EINVAL;
+
 	switch (type) {
-		case IPQM_MODE:
-			switch (m->msg.mode.value) {
-				case IPQ_COPY_META:
-					q->peer.copy_mode = IPQ_COPY_META;
-					q->peer.copy_range = 0;
-					break;
-				case IPQ_COPY_PACKET:
-					q->peer.copy_mode = IPQ_COPY_PACKET;
-					q->peer.copy_range = m->msg.mode.range;
-					if (q->peer.copy_range > 0xFFFF)
-						q->peer.copy_range = 0xFFFF;
-					break;
-				default:
-					status = -EINVAL;
-			}
-			break;
-		case IPQM_VERDICT:
-			if (m->msg.verdict.value > NF_MAX_VERDICT)
-				status = -EINVAL;
-			else
-				status = ipq_set_verdict(q,
-				                         &m->msg.verdict,
-				                         len - sizeof(*m));
+	case IPQM_MODE:
+		status = ipq_set_mode(pmsg->msg.mode.value,
+		                      pmsg->msg.mode.range);
+		break;
+		
+	case IPQM_VERDICT:
+		if (pmsg->msg.verdict.value > NF_MAX_VERDICT)
+			status = -EINVAL;
+		else
+			status = ipq_set_verdict(&pmsg->msg.verdict,
+			                         len - sizeof(*pmsg));
 			break;
-		default:
-			 status = -EINVAL;
+	default:
+		status = -EINVAL;
 	}
 	return status;
 }
 
-static inline int dev_cmp(ipq_queue_element_t *e, unsigned long ifindex)
+static int
+dev_cmp(struct ipq_queue_entry *entry, unsigned long ifindex)
 {
-	if (e->info->indev)
-		if (e->info->indev->ifindex == ifindex)
+	if (entry->info->indev)
+		if (entry->info->indev->ifindex == ifindex)
 			return 1;
-	if (e->info->outdev)
-		if (e->info->outdev->ifindex == ifindex)
+			
+	if (entry->info->outdev)
+		if (entry->info->outdev->ifindex == ifindex)
 			return 1;
+
 	return 0;
 }
 
-/* Drop any queued packets associated with device ifindex */
-static void ipq_dev_drop(ipq_queue_t *q, int ifindex)
+static void
+ipq_dev_drop(int ifindex)
 {
-	ipq_queue_element_t *e;
+	struct ipq_queue_entry *entry;
 	
-	while ((e = ipq_dequeue(q, dev_cmp, ifindex))) {
-		e->verdict = NF_DROP;
-		nf_reinject(e->skb, e->info, e->verdict);
-		kfree(e);
-	}
-}
-
-/****************************************************************************
- *
- * Netfilter interface
- *
- ****************************************************************************/
-
-/*
- * Packets arrive here from netfilter for queuing to userspace.
- * All of them must be fed back via nf_reinject() or Alexey will kill Rusty.
- */
-static int netfilter_receive(struct sk_buff *skb,
-                             struct nf_info *info, void *data)
-{
-	return ipq_enqueue((ipq_queue_t *)data, skb, info);
-}
-
-/****************************************************************************
- *
- * Netlink interface.
- *
- ****************************************************************************/
-
-static struct sock *nfnl = NULL;
-ipq_queue_t *nlq = NULL;
-
-static struct sk_buff *netlink_build_message(ipq_queue_element_t *e, int *errp)
-{
-	unsigned char *old_tail;
-	size_t size = 0;
-	size_t data_len = 0;
-	struct sk_buff *skb;
-	ipq_packet_msg_t *pm;
-	struct nlmsghdr *nlh;
-
-	switch (nlq->peer.copy_mode) {
-		size_t copy_range;
-
-		case IPQ_COPY_META:
-			size = NLMSG_SPACE(sizeof(*pm));
-			data_len = 0;
-			break;
-		case IPQ_COPY_PACKET:
-			copy_range = nlq->peer.copy_range;
-			if (copy_range == 0 || copy_range > e->skb->len)
-				data_len = e->skb->len;
-			else
-				data_len = copy_range;
-			size = NLMSG_SPACE(sizeof(*pm) + data_len);
-			
-			break;
-		case IPQ_COPY_NONE:
-		default:
-			*errp = -EINVAL;
-			return NULL;
-	}
-	skb = alloc_skb(size, GFP_ATOMIC);
-	if (!skb)
-		goto nlmsg_failure;
-	old_tail = skb->tail;
-	nlh = NLMSG_PUT(skb, 0, 0, IPQM_PACKET, size - sizeof(*nlh));
-	pm = NLMSG_DATA(nlh);
-	memset(pm, 0, sizeof(*pm));
-	pm->packet_id = (unsigned long )e;
-	pm->data_len = data_len;
-	pm->timestamp_sec = e->skb->stamp.tv_sec;
-	pm->timestamp_usec = e->skb->stamp.tv_usec;
-	pm->mark = e->skb->nfmark;
-	pm->hook = e->info->hook;
-	if (e->info->indev) strcpy(pm->indev_name, e->info->indev->name);
-	else pm->indev_name[0] = '\0';
-	if (e->info->outdev) strcpy(pm->outdev_name, e->info->outdev->name);
-	else pm->outdev_name[0] = '\0';
-	pm->hw_protocol = e->skb->protocol;
-	if (e->info->indev && e->skb->dev) {
-		pm->hw_type = e->skb->dev->type;
-		if (e->skb->dev->hard_header_parse)
-			pm->hw_addrlen =
-				e->skb->dev->hard_header_parse(e->skb,
-				                               pm->hw_addr);
-	}
-	if (data_len)
-		memcpy(pm->payload, e->skb->data, data_len);
-	nlh->nlmsg_len = skb->tail - old_tail;
-	NETLINK_CB(skb).dst_groups = 0;
-	return skb;
-nlmsg_failure:
-	if (skb)
-		kfree_skb(skb);
-	*errp = 0;
-	printk(KERN_ERR "ip_queue: error creating netlink message\n");
-	return NULL;
-}
-
-static int netlink_send_peer(ipq_queue_element_t *e)
-{
-	int status = 0;
-	struct sk_buff *skb;
-
-	skb = netlink_build_message(e, &status);
-	if (skb == NULL)
-		return status;
-	return netlink_unicast(nfnl, skb, nlq->peer.pid, MSG_DONTWAIT);
+	while ((entry = ipq_find_dequeue_entry(dev_cmp, ifindex)) != NULL)
+		ipq_issue_verdict(entry, NF_DROP);
 }
 
 #define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0)
 
-static __inline__ void netlink_receive_user_skb(struct sk_buff *skb)
+static inline void
+ipq_rcv_skb(struct sk_buff *skb)
 {
-	int status, type;
+	int status, type, pid, flags, nlmsglen, skblen;
 	struct nlmsghdr *nlh;
 
-	if (skb->len < sizeof(struct nlmsghdr))
+	skblen = skb->len;
+	if (skblen < sizeof(*nlh))
 		return;
 
 	nlh = (struct nlmsghdr *)skb->data;
-	if (nlh->nlmsg_len < sizeof(struct nlmsghdr)
-	    || skb->len < nlh->nlmsg_len)
-	    	return;
-
-	if(nlh->nlmsg_pid <= 0
-	    || !(nlh->nlmsg_flags & NLM_F_REQUEST)
-	    || nlh->nlmsg_flags & NLM_F_MULTI)
+	nlmsglen = nlh->nlmsg_len;
+	if (nlmsglen < sizeof(*nlh) || skblen < nlmsglen)
+		return;
+
+	pid = nlh->nlmsg_pid;
+	flags = nlh->nlmsg_flags;
+	
+	if(pid <= 0 || !(flags & NLM_F_REQUEST) || flags & NLM_F_MULTI)
 		RCV_SKB_FAIL(-EINVAL);
-	if (nlh->nlmsg_flags & MSG_TRUNC)
+		
+	if (flags & MSG_TRUNC)
 		RCV_SKB_FAIL(-ECOMM);
+		
 	type = nlh->nlmsg_type;
 	if (type < NLMSG_NOOP || type >= IPQM_MAX)
 		RCV_SKB_FAIL(-EINVAL);
+		
 	if (type <= IPQM_BASE)
 		return;
+		
 	if(!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN))
 		RCV_SKB_FAIL(-EPERM);
-	if (nlq->peer.pid && !nlq->peer.died
-	    && (nlq->peer.pid != nlh->nlmsg_pid)) {
-	    	printk(KERN_WARNING "ip_queue: peer pid changed from %d to "
-	    	      "%d, flushing queue\n", nlq->peer.pid, nlh->nlmsg_pid);
-		ipq_flush(nlq);
-	}	
-	nlq->peer.pid = nlh->nlmsg_pid;
-	nlq->peer.died = 0;
-	status = ipq_receive_peer(nlq, NLMSG_DATA(nlh),
-	                          type, skb->len - NLMSG_LENGTH(0));
+	
+	write_lock_bh(&queue_lock);
+	
+	if (peer_pid) {
+		if (peer_pid != pid) {
+			write_unlock_bh(&queue_lock);
+			RCV_SKB_FAIL(-EBUSY);
+		}
+	}
+	else
+		peer_pid = pid;
+		
+	write_unlock_bh(&queue_lock);
+	
+	status = ipq_receive_peer(NLMSG_DATA(nlh), type,
+	                          skblen - NLMSG_LENGTH(0));
 	if (status < 0)
 		RCV_SKB_FAIL(status);
-	if (nlh->nlmsg_flags & NLM_F_ACK)
+		
+	if (flags & NLM_F_ACK)
 		netlink_ack(skb, nlh, 0);
         return;
 }
 
-/* Note: we are only dealing with single part messages at the moment. */
-static void netlink_receive_user_sk(struct sock *sk, int len)
+static void
+ipq_rcv_sk(struct sock *sk, int len)
 {
 	do {
 		struct sk_buff *skb;
 
-		if (rtnl_shlock_nowait())
+		if (down_trylock(&ipqnl_sem))
 			return;
+			
 		while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
-			netlink_receive_user_skb(skb);
+			ipq_rcv_skb(skb);
 			kfree_skb(skb);
 		}
-		up(&rtnl_sem);
-	} while (nfnl && nfnl->receive_queue.qlen);
-}
+		
+		up(&ipqnl_sem);
 
-/****************************************************************************
- *
- * System events
- *
- ****************************************************************************/
+	} while (ipqnl && ipqnl->receive_queue.qlen);
+}
 
-static int receive_event(struct notifier_block *this,
-                         unsigned long event, void *ptr)
+static int
+ipq_rcv_dev_event(struct notifier_block *this,
+                  unsigned long event, void *ptr)
 {
 	struct net_device *dev = ptr;
 
 	/* Drop any packets associated with the downed device */
 	if (event == NETDEV_DOWN)
-		ipq_dev_drop(nlq, dev->ifindex);
+		ipq_dev_drop(dev->ifindex);
 	return NOTIFY_DONE;
 }
 
-struct notifier_block ipq_dev_notifier = {
-	receive_event,
+static struct notifier_block ipq_dev_notifier = {
+	ipq_rcv_dev_event,
 	NULL,
 	0
 };
 
-/****************************************************************************
- *
- * Sysctl - queue tuning.
- *
- ****************************************************************************/
+static int
+ipq_rcv_nl_event(struct notifier_block *this,
+                 unsigned long event, void *ptr)
+{
+	struct netlink_notify *n = ptr;
+
+	if (event == NETLINK_URELEASE &&
+	    n->protocol == NETLINK_FIREWALL && n->pid) {
+		write_lock_bh(&queue_lock);
+		if (n->pid == peer_pid)
+			__ipq_reset();
+		write_unlock_bh(&queue_lock);
+	}
+	return NOTIFY_DONE;
+}
 
-static int sysctl_maxlen = IPQ_QMAX_DEFAULT;
+static struct notifier_block ipq_nl_notifier = {
+	ipq_rcv_nl_event,
+	NULL,
+	0
+};
 
+static int sysctl_maxlen = IPQ_QMAX_DEFAULT;
 static struct ctl_table_header *ipq_sysctl_header;
 
 static ctl_table ipq_table[] = {
@@ -574,35 +600,27 @@
 	{ 0 }
 };
 
-/****************************************************************************
- *
- * Procfs - debugging info.
- *
- ****************************************************************************/
-
-static int ipq_get_info(char *buffer, char **start, off_t offset, int length)
+static int
+ipq_get_info(char *buffer, char **start, off_t offset, int length)
 {
 	int len;
 
-	spin_lock_bh(&nlq->lock);
+	read_lock_bh(&queue_lock);
+	
 	len = sprintf(buffer,
-	              "Peer pid            : %d\n"
-	              "Peer died           : %d\n"
-	              "Peer copy mode      : %d\n"
-	              "Peer copy range     : %Zu\n"
-	              "Queue length        : %d\n"
-	              "Queue max. length   : %d\n"
-	              "Queue flushing      : %d\n"
-	              "Queue terminate     : %d\n",
-	              nlq->peer.pid,
-	              nlq->peer.died,
-	              nlq->peer.copy_mode,
-	              nlq->peer.copy_range,
-	              nlq->len,
-	              *nlq->maxlen,
-	              nlq->flushing,
-	              nlq->terminate);
-	spin_unlock_bh(&nlq->lock);
+	              "Peer PID          : %d\n"
+	              "Copy mode         : %hu\n"
+	              "Copy range        : %u\n"
+	              "Queue length      : %u\n"
+	              "Queue max. length : %u\n",
+	              peer_pid,
+	              copy_mode,
+	              copy_range,
+	              queue_total,
+	              queue_maxlen);
+
+	read_unlock_bh(&queue_lock);
+	
 	*start = buffer + offset;
 	len -= offset;
 	if (len > length)
@@ -612,53 +630,74 @@
 	return len;
 }
 
-/****************************************************************************
- *
- * Module stuff.
- *
- ****************************************************************************/
-
-static int __init init(void)
+static int
+init_or_cleanup(int init)
 {
-	int status = 0;
+	int status = -ENOMEM;
 	struct proc_dir_entry *proc;
 	
-	nfnl = netlink_kernel_create(NETLINK_FIREWALL, netlink_receive_user_sk);
-	if (nfnl == NULL) {
-		printk(KERN_ERR "ip_queue: initialisation failed: unable to "
-		       "create kernel netlink socket\n");
-		return -ENOMEM;
-	}
-	nlq = ipq_create_queue(netfilter_receive,
-	                       netlink_send_peer, &status, &sysctl_maxlen);
-	if (nlq == NULL) {
-		printk(KERN_ERR "ip_queue: initialisation failed: unable to "
-		       "create queue\n");
-		sock_release(nfnl->socket);
-		return status;
+	if (!init)
+		goto cleanup;
+
+	netlink_register_notifier(&ipq_nl_notifier);
+	ipqnl = netlink_kernel_create(NETLINK_FIREWALL, ipq_rcv_sk);
+	if (ipqnl == NULL) {
+		printk(KERN_ERR "ip_queue: failed to create netlink socket\n");
+		goto cleanup_netlink_notifier;
 	}
+
 	proc = proc_net_create(IPQ_PROC_FS_NAME, 0, ipq_get_info);
-	if (proc) proc->owner = THIS_MODULE;
+	if (proc)
+		proc->owner = THIS_MODULE;
 	else {
-		ipq_destroy_queue(nlq);
-		sock_release(nfnl->socket);
-		return -ENOMEM;
+		printk(KERN_ERR "ip_queue: failed to create proc entry\n");
+		goto cleanup_ipqnl;
 	}
+	
 	register_netdevice_notifier(&ipq_dev_notifier);
 	ipq_sysctl_header = register_sysctl_table(ipq_root_table, 0);
+	
+	status = nf_register_queue_handler(PF_INET, ipq_enqueue_packet, NULL);
+	if (status < 0) {
+		printk(KERN_ERR "ip_queue: failed to register queue handler\n");
+		goto cleanup_sysctl;
+	}
+	return status;
+
+cleanup:
+	nf_unregister_queue_handler(PF_INET);
+	br_write_lock_bh(BR_NETPROTO_LOCK);
+	br_write_unlock_bh(BR_NETPROTO_LOCK);
+	ipq_flush(NF_DROP);
+	
+cleanup_sysctl:
+	unregister_sysctl_table(ipq_sysctl_header);
+	unregister_netdevice_notifier(&ipq_dev_notifier);
+	proc_net_remove(IPQ_PROC_FS_NAME);
+	
+cleanup_ipqnl:
+	sock_release(ipqnl->socket);
+	down(&ipqnl_sem);
+	up(&ipqnl_sem);
+	
+cleanup_netlink_notifier:
+	netlink_unregister_notifier(&ipq_nl_notifier);
 	return status;
 }
 
+static int __init init(void)
+{
+	
+	return init_or_cleanup(1);
+}
+
 static void __exit fini(void)
 {
-	unregister_sysctl_table(ipq_sysctl_header);
-	proc_net_remove(IPQ_PROC_FS_NAME);
-	unregister_netdevice_notifier(&ipq_dev_notifier);
-	ipq_destroy_queue(nlq);
-	sock_release(nfnl->socket);
+	init_or_cleanup(0);
 }
 
 MODULE_DESCRIPTION("IPv4 packet queue handler");
+MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>");
 MODULE_LICENSE("GPL");
 
 module_init(init);
diff -urN linux-2.4.20-pre4/net/ipv4/tcp_diag.c linux-2.4.20-pre5/net/ipv4/tcp_diag.c
--- linux-2.4.20-pre4/net/ipv4/tcp_diag.c	Fri Dec 21 09:42:05 2001
+++ linux-2.4.20-pre5/net/ipv4/tcp_diag.c	Wed Aug 28 16:38:27 2002
@@ -69,7 +69,8 @@
 	r->id.tcpdiag_src[0] = sk->rcv_saddr;
 	r->id.tcpdiag_dst[0] = sk->daddr;
 	r->id.tcpdiag_if = sk->bound_dev_if;
-	*((struct sock **)&r->id.tcpdiag_cookie) = sk;
+	r->id.tcpdiag_cookie[0] = (u32)(unsigned long)sk;
+	r->id.tcpdiag_cookie[1] = (u32)(((unsigned long)sk >> 31) >> 1);
 
 	if (r->tcpdiag_state == TCP_TIME_WAIT) {
 		struct tcp_tw_bucket *tw = (struct tcp_tw_bucket*)sk;
@@ -229,7 +230,8 @@
 	err = -ESTALE;
 	if ((req->id.tcpdiag_cookie[0] != TCPDIAG_NOCOOKIE ||
 	     req->id.tcpdiag_cookie[1] != TCPDIAG_NOCOOKIE) &&
-	    sk != *((struct sock **)&req->id.tcpdiag_cookie[0]))
+	    ((u32)(unsigned long)sk != req->id.tcpdiag_cookie[0] ||
+	     (u32)((((unsigned long)sk) >> 31) >> 1) != req->id.tcpdiag_cookie[1]))
 		goto out;
 
 	err = -ENOMEM;
diff -urN linux-2.4.20-pre4/net/ipv6/netfilter/ip6_queue.c linux-2.4.20-pre5/net/ipv6/netfilter/ip6_queue.c
--- linux-2.4.20-pre4/net/ipv6/netfilter/ip6_queue.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre5/net/ipv6/netfilter/ip6_queue.c	Wed Aug 28 16:38:27 2002
@@ -15,7 +15,7 @@
  *             real coder of this.
  *             Few changes needed, mainly the hard_routing code and
  *             the netlink socket protocol (we're NETLINK_IP6_FW).
- *
+ * 2002-06-25: Code cleanup. [JM: ported cleanup over from ip_queue.c]
  */
 #include <linux/module.h>
 #include <linux/skbuff.h>
@@ -26,18 +26,12 @@
 #include <linux/netfilter.h>
 #include <linux/netlink.h>
 #include <linux/spinlock.h>
-#include <linux/rtnetlink.h>
+#include <linux/brlock.h>
 #include <linux/sysctl.h>
 #include <linux/proc_fs.h>
 #include <net/sock.h>
 #include <net/ipv6.h>
 #include <net/ip6_route.h>
-
-/* We're still usign the following structs. No need to change them: */
-/*   ipq_packet_msg                                                 */
-/*   ipq_mode_msg                                                   */
-/*   ipq_verdict_msg                                                */
-/*   ipq_peer_msg                                                   */
 #include <linux/netfilter_ipv4/ip_queue.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
 #include <linux/netfilter_ipv6/ip6_tables.h>
@@ -47,184 +41,289 @@
 #define NET_IPQ_QMAX 2088
 #define NET_IPQ_QMAX_NAME "ip6_queue_maxlen"
 
-typedef struct ip6q_rt_info {
+struct ipq_rt_info {
 	struct in6_addr daddr;
 	struct in6_addr saddr;
-} ip6q_rt_info_t;
+};
 
-typedef struct ip6q_queue_element {
-	struct list_head list;		/* Links element into queue */
-	int verdict;			/* Current verdict */
-	struct nf_info *info;		/* Extra info from netfilter */
-	struct sk_buff *skb;		/* Packet inside */
-	ip6q_rt_info_t rt_info;		/* May need post-mangle routing */
-} ip6q_queue_element_t;
-
-typedef int (*ip6q_send_cb_t)(ip6q_queue_element_t *e);
-
-typedef struct ip6q_peer {
-	pid_t pid;			/* PID of userland peer */
-	unsigned char died;		/* We think the peer died */
-	unsigned char copy_mode;	/* Copy packet as well as metadata? */
-	size_t copy_range;		/* Range past metadata to copy */
-	ip6q_send_cb_t send;		/* Callback for sending data to peer */
-} ip6q_peer_t;
-
-typedef struct ip6q_queue {
- 	int len;			/* Current queue len */
- 	int *maxlen;			/* Maximum queue len, via sysctl */
- 	unsigned char flushing;		/* If queue is being flushed */
- 	unsigned char terminate;	/* If the queue is being terminated */
- 	struct list_head list;		/* Head of packet queue */
- 	spinlock_t lock;		/* Queue spinlock */
- 	ip6q_peer_t peer;		/* Userland peer */
-} ip6q_queue_t;
+struct ipq_queue_entry {
+	struct list_head list;
+	struct nf_info *info;
+	struct sk_buff *skb;
+	struct ipq_rt_info rt_info;
+};
 
-/****************************************************************************
- *
- * Packet queue
- *
- ****************************************************************************/
-/* Dequeue a packet if matched by cmp, or the next available if cmp is NULL */
-static ip6q_queue_element_t *
-ip6q_dequeue(ip6q_queue_t *q,
-            int (*cmp)(ip6q_queue_element_t *, unsigned long),
-            unsigned long data)
-{
-	struct list_head *i;
-
-	spin_lock_bh(&q->lock);
-	for (i = q->list.prev; i != &q->list; i = i->prev) {
-		ip6q_queue_element_t *e = (ip6q_queue_element_t *)i;
-		
-		if (!cmp || cmp(e, data)) {
-			list_del(&e->list);
-			q->len--;
-			spin_unlock_bh(&q->lock);
-			return e;
-		}
+typedef int (*ipq_cmpfn)(struct ipq_queue_entry *, unsigned long);
+
+static unsigned char copy_mode = IPQ_COPY_NONE;
+static unsigned int queue_maxlen = IPQ_QMAX_DEFAULT;
+static rwlock_t queue_lock = RW_LOCK_UNLOCKED;
+static int peer_pid;
+static unsigned int copy_range;
+static unsigned int queue_total;
+static struct sock *ipqnl;
+static LIST_HEAD(queue_list);
+static DECLARE_MUTEX(ipqnl_sem);
+
+static void
+ipq_issue_verdict(struct ipq_queue_entry *entry, int verdict)
+{
+	nf_reinject(entry->skb, entry->info, verdict);
+	kfree(entry);
+}
+
+static inline int
+__ipq_enqueue_entry(struct ipq_queue_entry *entry)
+{
+       if (queue_total >= queue_maxlen) {
+               if (net_ratelimit()) 
+                       printk(KERN_WARNING "ip6_queue: full at %d entries, "
+                              "dropping packet(s).\n", queue_total);
+               return -ENOSPC;
+       }
+       list_add(&entry->list, &queue_list);
+       queue_total++;
+       return 0;
+}
+
+/*
+ * Find and return a queued entry matched by cmpfn, or return the last
+ * entry if cmpfn is NULL.
+ */
+static inline struct ipq_queue_entry *
+__ipq_find_entry(ipq_cmpfn cmpfn, unsigned long data)
+{
+	struct list_head *p;
+
+	list_for_each_prev(p, &queue_list) {
+		struct ipq_queue_entry *entry = (struct ipq_queue_entry *)p;
+		
+		if (!cmpfn || cmpfn(entry, data))
+			return entry;
 	}
-	spin_unlock_bh(&q->lock);
 	return NULL;
 }
 
-/* Flush all packets */
-static void ip6q_flush(ip6q_queue_t *q)
+static inline void
+__ipq_dequeue_entry(struct ipq_queue_entry *entry)
 {
-	ip6q_queue_element_t *e;
-	
-	spin_lock_bh(&q->lock);
-	q->flushing = 1;
-	spin_unlock_bh(&q->lock);
-	while ((e = ip6q_dequeue(q, NULL, 0))) {
-		e->verdict = NF_DROP;
-		nf_reinject(e->skb, e->info, e->verdict);
-		kfree(e);
-	}
-	spin_lock_bh(&q->lock);
-	q->flushing = 0;
-	spin_unlock_bh(&q->lock);
-}
-
-static ip6q_queue_t *ip6q_create_queue(nf_queue_outfn_t outfn,
-                                     ip6q_send_cb_t send_cb,
-                                     int *errp, int *sysctl_qmax)
+	list_del(&entry->list);
+	queue_total--;
+}
+
+static inline struct ipq_queue_entry *
+__ipq_find_dequeue_entry(ipq_cmpfn cmpfn, unsigned long data)
 {
-	int status;
-	ip6q_queue_t *q;
+	struct ipq_queue_entry *entry;
 
-	*errp = 0;
-	q = kmalloc(sizeof(ip6q_queue_t), GFP_KERNEL);
-	if (q == NULL) {
-		*errp = -ENOMEM;
+	entry = __ipq_find_entry(cmpfn, data);
+	if (entry == NULL)
 		return NULL;
+
+	__ipq_dequeue_entry(entry);
+	return entry;
+}
+
+
+static inline void
+__ipq_flush(int verdict)
+{
+	struct ipq_queue_entry *entry;
+	
+	while ((entry = __ipq_find_dequeue_entry(NULL, 0)))
+		ipq_issue_verdict(entry, verdict);
+}
+
+static inline int
+__ipq_set_mode(unsigned char mode, unsigned int range)
+{
+	int status = 0;
+	
+	switch(mode) {
+	case IPQ_COPY_NONE:
+	case IPQ_COPY_META:
+		copy_mode = mode;
+		copy_range = 0;
+		break;
+		
+	case IPQ_COPY_PACKET:
+		copy_mode = mode;
+		copy_range = range;
+		if (copy_range > 0xFFFF)
+			copy_range = 0xFFFF;
+		break;
+		
+	default:
+		status = -EINVAL;
+
 	}
-	q->peer.pid = 0;
-	q->peer.died = 0;
-	q->peer.copy_mode = IPQ_COPY_NONE;
-	q->peer.copy_range = 0;
-	q->peer.send = send_cb;
-	q->len = 0;
-	q->maxlen = sysctl_qmax;
-	q->flushing = 0;
-	q->terminate = 0;
-	INIT_LIST_HEAD(&q->list);
-	spin_lock_init(&q->lock);
-	status = nf_register_queue_handler(PF_INET6, outfn, q);
-	if (status < 0) {
-		*errp = -EBUSY;
-		kfree(q);
+	return status;
+}
+
+static inline void
+__ipq_reset(void)
+{
+	peer_pid = 0;
+	__ipq_set_mode(IPQ_COPY_NONE, 0);
+	__ipq_flush(NF_DROP);
+}
+
+static struct ipq_queue_entry *
+ipq_find_dequeue_entry(ipq_cmpfn cmpfn, unsigned long data)
+{
+	struct ipq_queue_entry *entry;
+	
+	write_lock_bh(&queue_lock);
+	entry = __ipq_find_dequeue_entry(cmpfn, data);
+	write_unlock_bh(&queue_lock);
+	return entry;
+}
+
+static void
+ipq_flush(int verdict)
+{
+	write_lock_bh(&queue_lock);
+	__ipq_flush(verdict);
+	write_unlock_bh(&queue_lock);
+}
+
+static struct sk_buff *
+ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp)
+{
+	unsigned char *old_tail;
+	size_t size = 0;
+	size_t data_len = 0;
+	struct sk_buff *skb;
+	struct ipq_packet_msg *pmsg;
+	struct nlmsghdr *nlh;
+
+	read_lock_bh(&queue_lock);
+	
+	switch (copy_mode) {
+	case IPQ_COPY_META:
+	case IPQ_COPY_NONE:
+		size = NLMSG_SPACE(sizeof(*pmsg));
+		data_len = 0;
+		break;
+	
+	case IPQ_COPY_PACKET:
+		if (copy_range == 0 || copy_range > entry->skb->len)
+			data_len = entry->skb->len;
+		else
+			data_len = copy_range;
+		
+		size = NLMSG_SPACE(sizeof(*pmsg) + data_len);
+		break;
+	
+	default:
+		*errp = -EINVAL;
+		read_unlock_bh(&queue_lock);
 		return NULL;
 	}
-	return q;
+
+	read_unlock_bh(&queue_lock);
+
+	skb = alloc_skb(size, GFP_ATOMIC);
+	if (!skb)
+		goto nlmsg_failure;
+		
+	old_tail= skb->tail;
+	nlh = NLMSG_PUT(skb, 0, 0, IPQM_PACKET, size - sizeof(*nlh));
+	pmsg = NLMSG_DATA(nlh);
+	memset(pmsg, 0, sizeof(*pmsg));
+
+	pmsg->packet_id       = (unsigned long )entry;
+	pmsg->data_len        = data_len;
+	pmsg->timestamp_sec   = entry->skb->stamp.tv_sec;
+	pmsg->timestamp_usec  = entry->skb->stamp.tv_usec;
+	pmsg->mark            = entry->skb->nfmark;
+	pmsg->hook            = entry->info->hook;
+	pmsg->hw_protocol     = entry->skb->protocol;
+	
+	if (entry->info->indev)
+		strcpy(pmsg->indev_name, entry->info->indev->name);
+	else
+		pmsg->indev_name[0] = '\0';
+	
+	if (entry->info->outdev)
+		strcpy(pmsg->outdev_name, entry->info->outdev->name);
+	else
+		pmsg->outdev_name[0] = '\0';
+	
+	if (entry->info->indev && entry->skb->dev) {
+		pmsg->hw_type = entry->skb->dev->type;
+		if (entry->skb->dev->hard_header_parse)
+			pmsg->hw_addrlen =
+				entry->skb->dev->hard_header_parse(entry->skb,
+				                                   pmsg->hw_addr);
+	}
+	
+	if (data_len)
+		memcpy(pmsg->payload, entry->skb->data, data_len);
+		
+	nlh->nlmsg_len = skb->tail - old_tail;
+	return skb;
+
+nlmsg_failure:
+	if (skb)
+		kfree_skb(skb);
+	*errp = -EINVAL;
+	printk(KERN_ERR "ip6_queue: error creating packet message\n");
+	return NULL;
 }
 
-static int ip6q_enqueue(ip6q_queue_t *q,
-                       struct sk_buff *skb, struct nf_info *info)
+static int
+ipq_enqueue_packet(struct sk_buff *skb, struct nf_info *info, void *data)
 {
-	ip6q_queue_element_t *e;
-	int status;
-	
-	e = kmalloc(sizeof(*e), GFP_ATOMIC);
-	if (e == NULL) {
-		printk(KERN_ERR "ip6_queue: OOM in enqueue\n");
+	int status = -EINVAL;
+	struct sk_buff *nskb;
+	struct ipq_queue_entry *entry;
+
+	if (copy_mode == IPQ_COPY_NONE)
+		return -EAGAIN;
+
+	entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
+	if (entry == NULL) {
+		printk(KERN_ERR "ip6_queue: OOM in ipq_enqueue_packet()\n");
 		return -ENOMEM;
 	}
 
-	e->verdict = NF_DROP;
-	e->info = info;
-	e->skb = skb;
+	entry->info = info;
+	entry->skb = skb;
 
-	if (e->info->hook == NF_IP_LOCAL_OUT) {
+	if (entry->info->hook == NF_IP_LOCAL_OUT) {
 		struct ipv6hdr *iph = skb->nh.ipv6h;
 
-		e->rt_info.daddr = iph->daddr;
-		e->rt_info.saddr = iph->saddr;
+		entry->rt_info.daddr = iph->daddr;
+		entry->rt_info.saddr = iph->saddr;
 	}
 
-	spin_lock_bh(&q->lock);
-	if (q->len >= *q->maxlen) {
-		spin_unlock_bh(&q->lock);
-		if (net_ratelimit()) 
-			printk(KERN_WARNING "ip6_queue: full at %d entries, "
-			       "dropping packet(s).\n", q->len);
-		goto free_drop;
-	}
-	if (q->flushing || q->peer.copy_mode == IPQ_COPY_NONE
-	    || q->peer.pid == 0 || q->peer.died || q->terminate) {
-		spin_unlock_bh(&q->lock);
-		goto free_drop;
-	}
-	status = q->peer.send(e);
-	if (status > 0) {
-		list_add(&e->list, &q->list);
-		q->len++;
-		spin_unlock_bh(&q->lock);
-		return status;
-	}
-	spin_unlock_bh(&q->lock);
-	if (status == -ECONNREFUSED) {
-		printk(KERN_INFO "ip6_queue: peer %d died, "
-		       "resetting state and flushing queue\n", q->peer.pid);
-			q->peer.died = 1;
-			q->peer.pid = 0;
-			q->peer.copy_mode = IPQ_COPY_NONE;
-			q->peer.copy_range = 0;
-			ip6q_flush(q);
-	}
-free_drop:
-	kfree(e);
-	return -EBUSY;
-}
+	nskb = ipq_build_packet_message(entry, &status);
+	if (nskb == NULL)
+		goto err_out_free;
+		
+	write_lock_bh(&queue_lock);
+	
+	if (!peer_pid)
+		goto err_out_unlock;
 
-static void ip6q_destroy_queue(ip6q_queue_t *q)
-{
-	nf_unregister_queue_handler(PF_INET6);
-	spin_lock_bh(&q->lock);
-	q->terminate = 1;
-	spin_unlock_bh(&q->lock);
-	ip6q_flush(q);
-	kfree(q);
+	status = netlink_unicast(ipqnl, nskb, peer_pid, MSG_DONTWAIT);
+	if (status < 0)
+		goto err_out_unlock;
+	
+	status = __ipq_enqueue_entry(entry);
+	if (status < 0)
+		goto err_out_unlock;
+
+	write_unlock_bh(&queue_lock);
+	return status;
+	
+err_out_unlock:
+	write_unlock_bh(&queue_lock);
+
+err_out_free:
+	kfree(entry);
+	return status;
 }
 
 /*
@@ -236,7 +335,8 @@
  *
  * If that one is modified, this one should be modified too.
  */
-static int route6_me_harder(struct sk_buff *skb)
+static int
+route6_me_harder(struct sk_buff *skb)
 {
 	struct ipv6hdr *iph = skb->nh.ipv6h;
 	struct dst_entry *dst;
@@ -264,7 +364,9 @@
 	skb->dst = dst;
 	return 0;
 }
-static int ip6q_mangle_ipv6(ipq_verdict_msg_t *v, ip6q_queue_element_t *e)
+
+static int
+ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct ipq_queue_entry *e)
 {
 	int diff;
 	struct ipv6hdr *user_iph = (struct ipv6hdr *)v->payload;
@@ -319,344 +421,255 @@
 	return 0;
 }
 
-static inline int id_cmp(ip6q_queue_element_t *e, unsigned long id)
+static inline int
+id_cmp(struct ipq_queue_entry *e, unsigned long id)
 {
 	return (id == (unsigned long )e);
 }
 
-static int ip6q_set_verdict(ip6q_queue_t *q,
-                           ipq_verdict_msg_t *v, unsigned int len)
+static int
+ipq_set_verdict(struct ipq_verdict_msg *vmsg, unsigned int len)
 {
-	ip6q_queue_element_t *e;
+	struct ipq_queue_entry *entry;
 
-	if (v->value > NF_MAX_VERDICT)
+	if (vmsg->value > NF_MAX_VERDICT)
 		return -EINVAL;
-	e = ip6q_dequeue(q, id_cmp, v->id);
-	if (e == NULL)
+
+	entry = ipq_find_dequeue_entry(id_cmp, vmsg->id);
+	if (entry == NULL)
 		return -ENOENT;
 	else {
-		e->verdict = v->value;
-		if (v->data_len && v->data_len == len)
-			if (ip6q_mangle_ipv6(v, e) < 0)
-				e->verdict = NF_DROP;
-		nf_reinject(e->skb, e->info, e->verdict);
-		kfree(e);
+		int verdict = vmsg->value;
+		
+		if (vmsg->data_len && vmsg->data_len == len)
+			if (ipq_mangle_ipv6(vmsg, entry) < 0)
+				verdict = NF_DROP;
+		
+		ipq_issue_verdict(entry, verdict);
 		return 0;
 	}
 }
 
-static int ip6q_receive_peer(ip6q_queue_t* q, ipq_peer_msg_t *m,
-                            unsigned char type, unsigned int len)
+static int
+ipq_set_mode(unsigned char mode, unsigned int range)
 {
+	int status;
+
+	write_lock_bh(&queue_lock);
+	status = __ipq_set_mode(mode, range);
+	write_unlock_bh(&queue_lock);
+	return status;
+}
 
+static int
+ipq_receive_peer(struct ipq_peer_msg *pmsg,
+                 unsigned char type, unsigned int len)
+{
 	int status = 0;
-	int busy;
-		
-	spin_lock_bh(&q->lock);
-	busy = (q->terminate || q->flushing);
-	spin_unlock_bh(&q->lock);
-	if (busy)
-		return -EBUSY;
-	if (len < sizeof(ipq_peer_msg_t))
+
+	if (len < sizeof(*pmsg))
 		return -EINVAL;
+
 	switch (type) {
-		case IPQM_MODE:
-			switch (m->msg.mode.value) {
-				case IPQ_COPY_META:
-					q->peer.copy_mode = IPQ_COPY_META;
-					q->peer.copy_range = 0;
-					break;
-				case IPQ_COPY_PACKET:
-					q->peer.copy_mode = IPQ_COPY_PACKET;
-					q->peer.copy_range = m->msg.mode.range;
-					if (q->peer.copy_range > 0xFFFF)
-						q->peer.copy_range = 0xFFFF;
-					break;
-				default:
-					status = -EINVAL;
-			}
-			break;
-		case IPQM_VERDICT:
-			if (m->msg.verdict.value > NF_MAX_VERDICT)
-				status = -EINVAL;
-			else
-				status = ip6q_set_verdict(q,
-				                         &m->msg.verdict,
-				                         len - sizeof(*m));
+	case IPQM_MODE:
+		status = ipq_set_mode(pmsg->msg.mode.value,
+		                      pmsg->msg.mode.range);
+		break;
+		
+	case IPQM_VERDICT:
+		if (pmsg->msg.verdict.value > NF_MAX_VERDICT)
+			status = -EINVAL;
+		else
+			status = ipq_set_verdict(&pmsg->msg.verdict,
+			                         len - sizeof(*pmsg));
 			break;
-		default:
-			 status = -EINVAL;
+	default:
+		status = -EINVAL;
 	}
 	return status;
 }
 
-static inline int dev_cmp(ip6q_queue_element_t *e, unsigned long ifindex)
+static int
+dev_cmp(struct ipq_queue_entry *entry, unsigned long ifindex)
 {
-	if (e->info->indev)
-		if (e->info->indev->ifindex == ifindex)
+	if (entry->info->indev)
+		if (entry->info->indev->ifindex == ifindex)
 			return 1;
-	if (e->info->outdev)
-		if (e->info->outdev->ifindex == ifindex)
+			
+	if (entry->info->outdev)
+		if (entry->info->outdev->ifindex == ifindex)
 			return 1;
+
 	return 0;
 }
 
-/* Drop any queued packets associated with device ifindex */
-static void ip6q_dev_drop(ip6q_queue_t *q, int ifindex)
+static void
+ipq_dev_drop(int ifindex)
 {
-	ip6q_queue_element_t *e;
+	struct ipq_queue_entry *entry;
 	
-	while ((e = ip6q_dequeue(q, dev_cmp, ifindex))) {
-		e->verdict = NF_DROP;
-		nf_reinject(e->skb, e->info, e->verdict);
-		kfree(e);
-	}
-}
-
-/****************************************************************************
- *
- * Netfilter interface
- *
- ****************************************************************************/
-
-/*
- * Packets arrive here from netfilter for queuing to userspace.
- * All of them must be fed back via nf_reinject() or Alexey will kill Rusty.
- */
-static int netfilter6_receive(struct sk_buff *skb,
-                             struct nf_info *info, void *data)
-{
-	return ip6q_enqueue((ip6q_queue_t *)data, skb, info);
-}
-
-/****************************************************************************
- *
- * Netlink interface.
- *
- ****************************************************************************/
-
-static struct sock *nfnl = NULL;
-/* This is not a static one, so we should not repeat its name */
-ip6q_queue_t *nlq6 = NULL;
-
-static struct sk_buff *netlink_build_message(ip6q_queue_element_t *e, int *errp)
-{
-	unsigned char *old_tail;
-	size_t size = 0;
-	size_t data_len = 0;
-	struct sk_buff *skb;
-	ipq_packet_msg_t *pm;
-	struct nlmsghdr *nlh;
-
-	switch (nlq6->peer.copy_mode) {
-		size_t copy_range;
-
-		case IPQ_COPY_META:
-			size = NLMSG_SPACE(sizeof(*pm));
-			data_len = 0;
-			break;
-		case IPQ_COPY_PACKET:
-			copy_range = nlq6->peer.copy_range;
-			if (copy_range == 0 || copy_range > e->skb->len)
-				data_len = e->skb->len;
-			else
-				data_len = copy_range;
-			size = NLMSG_SPACE(sizeof(*pm) + data_len);
-			
-			break;
-		case IPQ_COPY_NONE:
-		default:
-			*errp = -EINVAL;
-			return NULL;
-	}
-	skb = alloc_skb(size, GFP_ATOMIC);
-	if (!skb)
-		goto nlmsg_failure;
-	old_tail = skb->tail;
-	nlh = NLMSG_PUT(skb, 0, 0, IPQM_PACKET, size - sizeof(*nlh));
-	pm = NLMSG_DATA(nlh);
-	memset(pm, 0, sizeof(*pm));
-	pm->packet_id = (unsigned long )e;
-	pm->data_len = data_len;
-	pm->timestamp_sec = e->skb->stamp.tv_sec;
-	pm->timestamp_usec = e->skb->stamp.tv_usec;
-	pm->mark = e->skb->nfmark;
-	pm->hook = e->info->hook;
-	if (e->info->indev) strcpy(pm->indev_name, e->info->indev->name);
-	else pm->indev_name[0] = '\0';
-	if (e->info->outdev) strcpy(pm->outdev_name, e->info->outdev->name);
-	else pm->outdev_name[0] = '\0';
-	pm->hw_protocol = e->skb->protocol;
-	if (e->info->indev && e->skb->dev) {
-		pm->hw_type = e->skb->dev->type;
-		if (e->skb->dev->hard_header_parse)
-			pm->hw_addrlen =
-				e->skb->dev->hard_header_parse(e->skb,
-				                               pm->hw_addr);
-	}
-	if (data_len)
-		memcpy(pm->payload, e->skb->data, data_len);
-	nlh->nlmsg_len = skb->tail - old_tail;
-	NETLINK_CB(skb).dst_groups = 0;
-	return skb;
-nlmsg_failure:
-	if (skb)
-		kfree_skb(skb);
-	*errp = 0;
-	printk(KERN_ERR "ip6_queue: error creating netlink message\n");
-	return NULL;
-}
-
-static int netlink_send_peer(ip6q_queue_element_t *e)
-{
-	int status = 0;
-	struct sk_buff *skb;
-
-	skb = netlink_build_message(e, &status);
-	if (skb == NULL)
-		return status;
-	return netlink_unicast(nfnl, skb, nlq6->peer.pid, MSG_DONTWAIT);
+	while ((entry = ipq_find_dequeue_entry(dev_cmp, ifindex)) != NULL)
+		ipq_issue_verdict(entry, NF_DROP);
 }
 
 #define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0)
 
-static __inline__ void netlink_receive_user_skb(struct sk_buff *skb)
+static inline void
+ipq_rcv_skb(struct sk_buff *skb)
 {
-	int status, type;
+	int status, type, pid, flags, nlmsglen, skblen;
 	struct nlmsghdr *nlh;
 
-	if (skb->len < sizeof(struct nlmsghdr))
+	skblen = skb->len;
+	if (skblen < sizeof(*nlh))
 		return;
 
 	nlh = (struct nlmsghdr *)skb->data;
-	if (nlh->nlmsg_len < sizeof(struct nlmsghdr)
-	    || skb->len < nlh->nlmsg_len)
-	    	return;
-
-	if(nlh->nlmsg_pid <= 0
-	    || !(nlh->nlmsg_flags & NLM_F_REQUEST)
-	    || nlh->nlmsg_flags & NLM_F_MULTI)
+	nlmsglen = nlh->nlmsg_len;
+	if (nlmsglen < sizeof(*nlh) || skblen < nlmsglen)
+		return;
+
+	pid = nlh->nlmsg_pid;
+	flags = nlh->nlmsg_flags;
+	
+	if(pid <= 0 || !(flags & NLM_F_REQUEST) || flags & NLM_F_MULTI)
 		RCV_SKB_FAIL(-EINVAL);
-	if (nlh->nlmsg_flags & MSG_TRUNC)
+		
+	if (flags & MSG_TRUNC)
 		RCV_SKB_FAIL(-ECOMM);
+		
 	type = nlh->nlmsg_type;
 	if (type < NLMSG_NOOP || type >= IPQM_MAX)
 		RCV_SKB_FAIL(-EINVAL);
+		
 	if (type <= IPQM_BASE)
 		return;
+		
 	if(!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN))
 		RCV_SKB_FAIL(-EPERM);
-	if (nlq6->peer.pid && !nlq6->peer.died
-	    && (nlq6->peer.pid != nlh->nlmsg_pid)) {
-	    	printk(KERN_WARNING "ip6_queue: peer pid changed from %d to "
-	    	      "%d, flushing queue\n", nlq6->peer.pid, nlh->nlmsg_pid);
-		ip6q_flush(nlq6);
-	}	
-	nlq6->peer.pid = nlh->nlmsg_pid;
-	nlq6->peer.died = 0;
-	status = ip6q_receive_peer(nlq6, NLMSG_DATA(nlh),
-	                          type, skb->len - NLMSG_LENGTH(0));
+	
+	write_lock_bh(&queue_lock);
+	
+	if (peer_pid) {
+		if (peer_pid != pid) {
+			write_unlock_bh(&queue_lock);
+			RCV_SKB_FAIL(-EBUSY);
+		}
+	}
+	else
+		peer_pid = pid;
+		
+	write_unlock_bh(&queue_lock);
+	
+	status = ipq_receive_peer(NLMSG_DATA(nlh), type,
+	                          skblen - NLMSG_LENGTH(0));
 	if (status < 0)
 		RCV_SKB_FAIL(status);
-	if (nlh->nlmsg_flags & NLM_F_ACK)
+		
+	if (flags & NLM_F_ACK)
 		netlink_ack(skb, nlh, 0);
         return;
 }
 
-/* Note: we are only dealing with single part messages at the moment. */
-static void netlink_receive_user_sk(struct sock *sk, int len)
+static void
+ipq_rcv_sk(struct sock *sk, int len)
 {
 	do {
 		struct sk_buff *skb;
 
-		if (rtnl_shlock_nowait())
+		if (down_trylock(&ipqnl_sem))
 			return;
+			
 		while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
-			netlink_receive_user_skb(skb);
+			ipq_rcv_skb(skb);
 			kfree_skb(skb);
 		}
-		up(&rtnl_sem);
-	} while (nfnl && nfnl->receive_queue.qlen);
-}
+		
+		up(&ipqnl_sem);
 
-/****************************************************************************
- *
- * System events
- *
- ****************************************************************************/
+	} while (ipqnl && ipqnl->receive_queue.qlen);
+}
 
-static int receive_event(struct notifier_block *this,
-                         unsigned long event, void *ptr)
+static int
+ipq_rcv_dev_event(struct notifier_block *this,
+                  unsigned long event, void *ptr)
 {
 	struct net_device *dev = ptr;
 
 	/* Drop any packets associated with the downed device */
 	if (event == NETDEV_DOWN)
-		ip6q_dev_drop(nlq6, dev->ifindex);
+		ipq_dev_drop(dev->ifindex);
 	return NOTIFY_DONE;
 }
 
-struct notifier_block ip6q_dev_notifier = {
-	receive_event,
+static struct notifier_block ipq_dev_notifier = {
+	ipq_rcv_dev_event,
 	NULL,
 	0
 };
 
-/****************************************************************************
- *
- * Sysctl - queue tuning.
- *
- ****************************************************************************/
+static int
+ipq_rcv_nl_event(struct notifier_block *this,
+                 unsigned long event, void *ptr)
+{
+	struct netlink_notify *n = ptr;
+
+	if (event == NETLINK_URELEASE &&
+	    n->protocol == NETLINK_IP6_FW && n->pid) {
+		write_lock_bh(&queue_lock);
+		if (n->pid == peer_pid)
+			__ipq_reset();
+		write_unlock_bh(&queue_lock);
+	}
+	return NOTIFY_DONE;
+}
 
-static int sysctl_maxlen = IPQ_QMAX_DEFAULT;
+static struct notifier_block ipq_nl_notifier = {
+	ipq_rcv_nl_event,
+	NULL,
+	0
+};
 
-static struct ctl_table_header *ip6q_sysctl_header;
+static int sysctl_maxlen = IPQ_QMAX_DEFAULT;
+static struct ctl_table_header *ipq_sysctl_header;
 
-static ctl_table ip6q_table[] = {
+static ctl_table ipq_table[] = {
 	{ NET_IPQ_QMAX, NET_IPQ_QMAX_NAME, &sysctl_maxlen,
 	  sizeof(sysctl_maxlen), 0644,  NULL, proc_dointvec },
  	{ 0 }
 };
 
-static ctl_table ip6q_dir_table[] = {
-	{NET_IPV6, "ipv6", NULL, 0, 0555, ip6q_table, 0, 0, 0, 0, 0},
+static ctl_table ipq_dir_table[] = {
+	{NET_IPV6, "ipv6", NULL, 0, 0555, ipq_table, 0, 0, 0, 0, 0},
 	{ 0 }
 };
 
-static ctl_table ip6q_root_table[] = {
-	{CTL_NET, "net", NULL, 0, 0555, ip6q_dir_table, 0, 0, 0, 0, 0},
+static ctl_table ipq_root_table[] = {
+	{CTL_NET, "net", NULL, 0, 0555, ipq_dir_table, 0, 0, 0, 0, 0},
 	{ 0 }
 };
 
-/****************************************************************************
- *
- * Procfs - debugging info.
- *
- ****************************************************************************/
-
-static int ip6q_get_info(char *buffer, char **start, off_t offset, int length)
+static int
+ipq_get_info(char *buffer, char **start, off_t offset, int length)
 {
 	int len;
 
-	spin_lock_bh(&nlq6->lock);
+	read_lock_bh(&queue_lock);
+	
 	len = sprintf(buffer,
-	              "Peer pid            : %d\n"
-	              "Peer died           : %d\n"
-	              "Peer copy mode      : %d\n"
-	              "Peer copy range     : %Zu\n"
-	              "Queue length        : %d\n"
-	              "Queue max. length   : %d\n"
-	              "Queue flushing      : %d\n"
-	              "Queue terminate     : %d\n",
-	              nlq6->peer.pid,
-	              nlq6->peer.died,
-	              nlq6->peer.copy_mode,
-	              nlq6->peer.copy_range,
-	              nlq6->len,
-	              *nlq6->maxlen,
-	              nlq6->flushing,
-	              nlq6->terminate);
-	spin_unlock_bh(&nlq6->lock);
+	              "Peer PID          : %d\n"
+	              "Copy mode         : %hu\n"
+	              "Copy range        : %u\n"
+	              "Queue length      : %u\n"
+	              "Queue max. length : %u\n",
+	              peer_pid,
+	              copy_mode,
+	              copy_range,
+	              queue_total,
+	              queue_maxlen);
+
+	read_unlock_bh(&queue_lock);
+	
 	*start = buffer + offset;
 	len -= offset;
 	if (len > length)
@@ -666,52 +679,70 @@
 	return len;
 }
 
-/****************************************************************************
- *
- * Module stuff.
- *
- ****************************************************************************/
-
-static int __init init(void)
+static int
+init_or_cleanup(int init)
 {
-	int status = 0;
+	int status = -ENOMEM;
 	struct proc_dir_entry *proc;
 	
-        /* We must create the NETLINK_IP6_FW protocol service */
-	nfnl = netlink_kernel_create(NETLINK_IP6_FW, netlink_receive_user_sk);
-	if (nfnl == NULL) {
-		printk(KERN_ERR "ip6_queue: initialisation failed: unable to "
-		       "create kernel netlink socket\n");
-		return -ENOMEM;
+	if (!init)
+		goto cleanup;
+
+	netlink_register_notifier(&ipq_nl_notifier);
+	ipqnl = netlink_kernel_create(NETLINK_IP6_FW, ipq_rcv_sk);
+	if (ipqnl == NULL) {
+		printk(KERN_ERR "ip6_queue: failed to create netlink socket\n");
+		goto cleanup_netlink_notifier;
 	}
-	nlq6 = ip6q_create_queue(netfilter6_receive,
-	                       netlink_send_peer, &status, &sysctl_maxlen);
-	if (nlq6 == NULL) {
-		printk(KERN_ERR "ip6_queue: initialisation failed: unable to "
-		       "create queue\n");
-		sock_release(nfnl->socket);
-		return status;
-	}
-        /* The file will be /proc/net/ip6_queue */
-	proc = proc_net_create(IPQ_PROC_FS_NAME, 0, ip6q_get_info);
-	if (proc) proc->owner = THIS_MODULE;
+
+	proc = proc_net_create(IPQ_PROC_FS_NAME, 0, ipq_get_info);
+	if (proc)
+		proc->owner = THIS_MODULE;
 	else {
-		ip6q_destroy_queue(nlq6);
-		sock_release(nfnl->socket);
-		return -ENOMEM;
+		printk(KERN_ERR "ip6_queue: failed to create proc entry\n");
+		goto cleanup_ipqnl;
+	}
+	
+	register_netdevice_notifier(&ipq_dev_notifier);
+	ipq_sysctl_header = register_sysctl_table(ipq_root_table, 0);
+	
+	status = nf_register_queue_handler(PF_INET6, ipq_enqueue_packet, NULL);
+	if (status < 0) {
+		printk(KERN_ERR "ip6_queue: failed to register queue handler\n");
+		goto cleanup_sysctl;
 	}
-	register_netdevice_notifier(&ip6q_dev_notifier);
-	ip6q_sysctl_header = register_sysctl_table(ip6q_root_table, 0);
+	return status;
+
+cleanup:
+	nf_unregister_queue_handler(PF_INET6);
+	br_write_lock_bh(BR_NETPROTO_LOCK);
+	br_write_unlock_bh(BR_NETPROTO_LOCK);
+	ipq_flush(NF_DROP);
+	
+cleanup_sysctl:
+	unregister_sysctl_table(ipq_sysctl_header);
+	unregister_netdevice_notifier(&ipq_dev_notifier);
+	proc_net_remove(IPQ_PROC_FS_NAME);
+	
+cleanup_ipqnl:
+	sock_release(ipqnl->socket);
+	down(&ipqnl_sem);
+	up(&ipqnl_sem);
+	
+cleanup_netlink_notifier:
+	netlink_unregister_notifier(&ipq_nl_notifier);
 	return status;
 }
 
+static int __init init(void)
+{
+	
+	return init_or_cleanup(1);
+}
+
 static void __exit fini(void)
 {
-	unregister_sysctl_table(ip6q_sysctl_header);
-	proc_net_remove(IPQ_PROC_FS_NAME);
-	unregister_netdevice_notifier(&ip6q_dev_notifier);
-	ip6q_destroy_queue(nlq6);
-	sock_release(nfnl->socket);
+	init_or_cleanup(0);
 }
 
 MODULE_DESCRIPTION("IPv6 packet queue handler");
diff -urN linux-2.4.20-pre4/net/ipv6/netfilter/ip6_tables.c linux-2.4.20-pre5/net/ipv6/netfilter/ip6_tables.c
--- linux-2.4.20-pre4/net/ipv6/netfilter/ip6_tables.c	Wed Aug 28 16:37:15 2002
+++ linux-2.4.20-pre5/net/ipv6/netfilter/ip6_tables.c	Wed Aug 28 16:38:27 2002
@@ -7,6 +7,8 @@
  * 19 Jan 2002 Harald Welte <laforge@gnumonks.org>
  * 	- increase module usage count as soon as we have rules inside
  * 	  a table
+ * 06 Jun 2002 Andras Kis-Szabo <kisza@sch.bme.hu>
+ *      - new extension header parser code
  */
 #include <linux/config.h>
 #include <linux/skbuff.h>
@@ -25,6 +27,7 @@
 #include <linux/netfilter_ipv6/ip6_tables.h>
 
 #define IPV6_HDR_LEN	(sizeof(struct ipv6hdr))
+#define IPV6_OPTHDR_LEN	(sizeof(struct ipv6_opt_hdr))
 
 /*#define DEBUG_IP_FIREWALL*/
 /*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
@@ -133,43 +136,23 @@
 	return 0;
 }
 
-/* takes in current header and pointer to the header */
-/* if another header exists, sets hdrptr to the next header
-   and returns the new header value, else returns 0 */
-static u_int8_t ip6_nexthdr(u_int8_t currenthdr, u_int8_t *hdrptr)
-{
-	int i;
-	u_int8_t hdrlen, nexthdr = 0;
-	switch(currenthdr){
-		case IPPROTO_AH:
-		/* whoever decided to do the length of AUTH for ipv6
-		in 32bit units unlike other headers should be beaten...
-		repeatedly...with a large stick...no, an even LARGER
-		stick...no, you're still not thinking big enough */
-			nexthdr = *hdrptr;
-			hdrlen = hdrptr[i] * 4 + 8;
-			hdrptr = hdrptr + hdrlen;
-			break;
-		/*stupid rfc2402 */
-		case IPPROTO_DSTOPTS:
-		case IPPROTO_ROUTING:
-		case IPPROTO_HOPOPTS:
-			nexthdr = *hdrptr;
-			hdrlen = hdrptr[1] * 8 + 8;
-			hdrptr = hdrptr + hdrlen;
-			break;
-		case IPPROTO_FRAGMENT:
-			nexthdr = *hdrptr;
-			hdrptr = hdrptr + 8;
-			break;
-	}	
-	return nexthdr;
-
+/* Check for an extension */
+int 
+ip6t_ext_hdr(u8 nexthdr)
+{
+        return ( (nexthdr == IPPROTO_HOPOPTS)   ||
+                 (nexthdr == IPPROTO_ROUTING)   ||
+                 (nexthdr == IPPROTO_FRAGMENT)  ||
+                 (nexthdr == IPPROTO_ESP)       ||
+                 (nexthdr == IPPROTO_AH)        ||
+                 (nexthdr == IPPROTO_NONE)      ||
+                 (nexthdr == IPPROTO_DSTOPTS) );
 }
 
 /* Returns whether matches rule or not. */
 static inline int
-ip6_packet_match(const struct ipv6hdr *ipv6,
+ip6_packet_match(const struct sk_buff *skb,
+		 const struct ipv6hdr *ipv6,
 		 const char *indev,
 		 const char *outdev,
 		 const struct ip6t_ip6 *ip6info,
@@ -227,17 +210,58 @@
 	/* look for the desired protocol header */
 	if((ip6info->flags & IP6T_F_PROTO)) {
 		u_int8_t currenthdr = ipv6->nexthdr;
-		u_int8_t *hdrptr;
-		hdrptr = (u_int8_t *)(ipv6 + 1);
-		do {
-			if (ip6info->proto == currenthdr) {
-				if(ip6info->invflags & IP6T_INV_PROTO)
-					return 0;
-				return 1;
+		struct ipv6_opt_hdr *hdrptr;
+		u_int16_t ptr;		/* Header offset in skb */
+		u_int16_t hdrlen;	/* Header */
+
+		ptr = IPV6_HDR_LEN;
+
+		while (ip6t_ext_hdr(currenthdr)) {
+	                /* Is there enough space for the next ext header? */
+	                if (skb->len - ptr < IPV6_OPTHDR_LEN)
+	                        return 0;
+
+			/* NONE or ESP: there isn't protocol part */
+			/* If we want to count these packets in '-p all',
+			 * we will change the return 0 to 1*/
+			if ((currenthdr == IPPROTO_NONE) || 
+				(currenthdr == IPPROTO_ESP))
+				return 0;
+
+	                hdrptr = (struct ipv6_opt_hdr *)(skb->data + ptr);
+
+			/* Size calculation */
+	                if (currenthdr == IPPROTO_FRAGMENT) {
+	                        hdrlen = 8;
+	                } else if (currenthdr == IPPROTO_AH)
+	                        hdrlen = (hdrptr->hdrlen+2)<<2;
+	                else
+	                        hdrlen = ipv6_optlen(hdrptr);
+
+			currenthdr = hdrptr->nexthdr;
+	                ptr += hdrlen;
+			/* ptr is too large */
+	                if ( ptr > skb->len ) 
+				return 0;
+		}
+
+		/* currenthdr contains the protocol header */
+
+		dprintf("Packet protocol %hi ?= %s%hi.\n",
+				currenthdr, 
+				ip6info->invflags & IP6T_INV_PROTO ? "!":"",
+				ip6info->proto);
+
+		if (ip6info->proto == currenthdr) {
+			if(ip6info->invflags & IP6T_INV_PROTO) {
+				return 0;
 			}
-			currenthdr = ip6_nexthdr(currenthdr, hdrptr);
-		} while(currenthdr);
-		if (!(ip6info->invflags & IP6T_INV_PROTO))
+			return 1;
+		}
+
+		/* We need match for the '-p all', too! */
+		if ((ip6info->proto != 0) &&
+			!(ip6info->invflags & IP6T_INV_PROTO))
 			return 0;
 	}
 	return 1;
@@ -360,7 +384,8 @@
 		IP_NF_ASSERT(e);
 		IP_NF_ASSERT(back);
 		(*pskb)->nfcache |= e->nfcache;
-		if (ip6_packet_match(ipv6, indev, outdev, &e->ipv6, offset)) {
+		if (ip6_packet_match(*pskb, ipv6, indev, outdev, 
+			&e->ipv6, offset)) {
 			struct ip6t_entry_target *t;
 
 			if (IP6T_MATCH_ITERATE(e, do_match,
@@ -1827,6 +1852,7 @@
 EXPORT_SYMBOL(ip6t_unregister_match);
 EXPORT_SYMBOL(ip6t_register_target);
 EXPORT_SYMBOL(ip6t_unregister_target);
+EXPORT_SYMBOL(ip6t_ext_hdr);
 
 module_init(init);
 module_exit(fini);
diff -urN linux-2.4.20-pre4/net/khttpd/security.c linux-2.4.20-pre5/net/khttpd/security.c
--- linux-2.4.20-pre4/net/khttpd/security.c	Fri Feb  9 11:29:44 2001
+++ linux-2.4.20-pre5/net/khttpd/security.c	Wed Aug 28 16:38:28 2002
@@ -83,22 +83,21 @@
 */
 struct file *OpenFileForSecurity(char *Filename)
 {
-	struct file *filp;
+	struct file *filp = NULL;
 	struct DynamicString *List;
 	umode_t permission;
 	
-	
-
 	EnterFunction("OpenFileForSecurity");
 	if (Filename==NULL)
-		return NULL;
+		goto out_error;
 	
-	if (strlen(Filename)>=256 ) return NULL;  /* Sanity check */
+	if (strlen(Filename)>=256 )
+		goto out_error;  /* Sanity check */
 	
 	/* Rule no. 1  -- No "?" characters */
 #ifndef BENCHMARK	
 	if (strchr(Filename,'?')!=NULL)
-		return NULL;
+		goto out_error;
 
 	/* Intermediate step: decode all %hex sequences */
 	
@@ -106,9 +105,8 @@
 
 	/* Rule no. 2  -- Must start with a "/" */
 	
-	
 	if (Filename[0]!='/')
-		return NULL;
+		goto out_error;
 		
 #endif
 	/* Rule no. 3 -- Does the file exist ? */
@@ -116,55 +114,44 @@
 	filp = filp_open(Filename, O_RDONLY, 0);
 	
 	if (IS_ERR(filp))
-		return NULL;
+		goto out_error;
 
 #ifndef BENCHMARK		
 	permission = filp->f_dentry->d_inode->i_mode;
 	
 	/* Rule no. 4 : must have enough permissions */
 	
-	
 	if ((permission & sysctl_khttpd_permreq)==0)
-	{
-		if (filp!=NULL)
-			fput(filp);
-		filp=NULL;
-		return NULL;
-	}
-		
+		goto out_error_put;	
+
 	/* Rule no. 5 : cannot have "forbidden" permission */
 	
-	
 	if ((permission & sysctl_khttpd_permforbid)!=0)
-	{
-		if (filp!=NULL)
-			fput(filp);
-		filp=NULL;
-		return NULL;
-	}
+		goto out_error_put;	
 		
 	/* Rule no. 6 : No string in DynamicList can be a
 			substring of the filename */
-			
 	
 	List = DynamicList;
-	
 	while (List!=NULL)
 	{
 		if (strstr(Filename,List->value)!=NULL)
-		{
-			if (filp!=NULL)
-				fput(filp);
-			filp=NULL;
-			return NULL;
-		}
+			goto out_error_put;	
+
 		List = List->Next;
 	}
 	
 #endif	
 	LeaveFunction("OpenFileForSecurity - success");
-
+out:
 	return filp;
+
+out_error_put:
+	fput(filp);
+out_error:
+	filp=NULL;
+	LeaveFunction("OpenFileForSecurity - fail");
+	goto out;
 }
 
 /* 
diff -urN linux-2.4.20-pre4/net/sunrpc/svcsock.c linux-2.4.20-pre5/net/sunrpc/svcsock.c
--- linux-2.4.20-pre4/net/sunrpc/svcsock.c	Wed Aug 28 16:37:15 2002
+++ linux-2.4.20-pre5/net/sunrpc/svcsock.c	Wed Aug 28 16:38:28 2002
@@ -139,7 +139,7 @@
 	    && !test_bit(SK_CLOSE, &svsk->sk_flags)
 	    && !test_bit(SK_CONN, &svsk->sk_flags)) {
 		/* Don't enqueue while not enough space for reply */
-		dprintk("svc: socket %p  no space, %d > %ld, not enqueued\n",
+		dprintk("svc: socket %p  no space, %d*2 > %ld, not enqueued\n",
 			svsk->sk_sk, svsk->sk_reserved+serv->sv_bufsz,
 			sock_wspace(svsk->sk_sk));
 		goto out_unlock;
@@ -572,6 +572,15 @@
 	svsk->sk_sk->write_space = svc_write_space;
 	svsk->sk_recvfrom = svc_udp_recvfrom;
 	svsk->sk_sendto = svc_udp_sendto;
+
+	/* initialise setting must have enough space to
+	 * receive and respond to one request.  
+	 * svc_udp_recvfrom will re-adjust if necessary
+	 */
+	svc_sock_setbufsize(svsk->sk_sock,
+			    3 * svsk->sk_server->sv_bufsz,
+			    3 * svsk->sk_server->sv_bufsz);
+
 	set_bit(SK_CHNGBUF, &svsk->sk_flags);
 
 	return 0;
@@ -677,6 +686,8 @@
 		goto failed;		/* aborted connection or whatever */
 	}
 	set_bit(SK_CONN, &svsk->sk_flags);
+	svc_sock_enqueue(svsk);
+
 	slen = sizeof(sin);
 	err = ops->getname(newsock, (struct sockaddr *) &sin, &slen, 1);
 	if (err < 0) {
@@ -941,6 +952,14 @@
 		svsk->sk_reclen = 0;
 		svsk->sk_tcplen = 0;
 
+		/* initialise setting must have enough space to
+		 * receive and respond to one request.  
+		 * svc_tcp_recvfrom will re-adjust if necessary
+		 */
+		svc_sock_setbufsize(svsk->sk_sock,
+				    3 * svsk->sk_server->sv_bufsz,
+				    3 * svsk->sk_server->sv_bufsz);
+
 		set_bit(SK_CHNGBUF, &svsk->sk_flags);
 	}
 
@@ -1219,7 +1238,7 @@
 	}
 
 	if (protocol == IPPROTO_TCP) {
-		if ((error = sock->ops->listen(sock, 5)) < 0)
+		if ((error = sock->ops->listen(sock, 64)) < 0)
 			goto bummer;
 	}
 
diff -urN linux-2.4.20-pre4/net/unix/af_unix.c linux-2.4.20-pre5/net/unix/af_unix.c
--- linux-2.4.20-pre4/net/unix/af_unix.c	Wed Aug 28 16:37:15 2002
+++ linux-2.4.20-pre5/net/unix/af_unix.c	Wed Aug 28 16:38:28 2002
@@ -606,6 +606,9 @@
 		if (!u)
 			goto put_fail;
 
+		if (u->type == type)
+			UPDATE_ATIME(nd.dentry->d_inode);
+
 		path_release(&nd);
 
 		err=-EPROTOTYPE;
@@ -616,7 +619,12 @@
 	} else {
 		err = -ECONNREFUSED;
 		u=unix_find_socket_byname(sunname, len, type, hash);
-		if (!u)
+		if (u) {
+			struct dentry *dentry;
+			dentry = u->protinfo.af_unix.dentry;
+			if (dentry)
+				UPDATE_ATIME(dentry->d_inode);
+		} else
 			goto fail;
 	}
 	return u;
@@ -1383,7 +1391,7 @@
 
 static void unix_copy_addr(struct msghdr *msg, struct sock *sk)
 {
-	msg->msg_namelen = sizeof(short);
+	msg->msg_namelen = 0;
 	if (sk->protinfo.af_unix.addr) {
 		msg->msg_namelen=sk->protinfo.af_unix.addr->len;
 		memcpy(msg->msg_name,
@@ -1883,8 +1891,4 @@
 module_init(af_unix_init);
 module_exit(af_unix_exit);
 
-/*
- * Local variables:
- *  compile-command: "gcc -g -D__KERNEL__ -Wall -O6 -I/usr/src/linux/include -c af_unix.c"
- * End:
- */
+MODULE_LICENSE("GPL");
