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

diff -urN linux-2.4.21-pre3/Documentation/Configure.help linux-2.4.21-pre4/Documentation/Configure.help
--- linux-2.4.21-pre3/Documentation/Configure.help	Tue Jan 28 19:44:23 2003
+++ linux-2.4.21-pre4/Documentation/Configure.help	Tue Jan 28 19:44:27 2003
@@ -13925,8 +13925,8 @@
 USB Scanner support
 CONFIG_USB_SCANNER
   Say Y here if you want to connect a USB scanner to your computer's
-  USB port. Please read <file:Documentation/usb/scanner.txt> and
-  <file:Documentation/usb/scanner-hp-sane.txt> for more information.
+  USB port. Please read <file:Documentation/usb/scanner.txt> for more
+  information.
 
   This code is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -14313,6 +14313,21 @@
   you load the module.  Read <file:Documentation/usb/ibmcam.txt> to
   learn more.
 
+CONFIG_USB_KONICAWC
+  Say Y here if you want support for webcams based on a Konica
+  chipset. This is known to work with the Intel YC76 webcam.
+
+  This driver uses the Video For Linux API.  You must enable
+  (Y or M in config) Video For Linux (under Character Devices)
+  to use this driver.  Information on this API and pointers to
+  "v4l" programs may be found on the WWW at
+  <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
+
+  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 konicawc.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
 USB OV511 Camera support
 CONFIG_USB_OV511
   Say Y here if you want to connect this type of camera to your
@@ -14708,8 +14723,18 @@
   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>
 
+USB Auerswald ISDN modem support
+CONFIG_USB_AUERISDN
+  Say Y here if you want to enable the ISDN modem option
+  of your Auerswald ISDN devices. 
+
+  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 
+  If you own a Texas Instruments graphing calculator and use a
   TI-GRAPH LINK USB cable (aka SilverLink), then you might be 
   interested in this driver.
 
@@ -15049,8 +15074,7 @@
 CONFIG_USB_BLUETOOTH
   Say Y here if you want to connect a USB Bluetooth device to your
   computer's USB port. You will need the Bluetooth stack (available
-  at <http://developer.axis.com/software/index.shtml>) to fully use
-  the device.
+  at <http://developer.axis.com/software>) to fully use the device.
 
   This code is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -15288,35 +15312,6 @@
   debugging output from the driver. This is unlike previous versions
   of the driver, where enabling this option would turn on debugging
   output automatically.
-  
-  Example:
-  mount -t befs /dev/hda2 /mnt -o debug
-
-BeOS filesystem support (BeFS) (read only)
-CONFIG_BEFS_FS
-  The BeOS File System (BeFS) is the native file system of Be, Inc's
-  BeOS. Notable features include support for arbitrary attributes
-  on files and directories, and database-like indices on selected
-  attributes. (Also note that this driver doesn't make those features
-  available at this time). It is a 64 bit filesystem, so it supports
-  extremely large volumes and files.
-
-  If you use this filesystem, you should also say Y to at least one
-  of the NLS (native language support) options below.
-
-  If you don't know what this is about, say N.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read Documentation/modules.txt. The module will be
-  called befs.o.
-
-Debug BeFS
-CONFIG_BEFS_DEBUG
-  If you say Y here, you can use the 'debug' mount option to enable
-  debugging output from the driver. This is unlike previous versions
-  of the driver, where enabling this option would turn on debugging
-  output automatically.
 
   Example:
   mount -t befs /dev/hda2 /mnt -o debug
@@ -25631,16 +25626,6 @@
   for the zx1 IOMMU and makes root bus bridges appear in PCI config space
   (required for zx1 agpgart support).
 
-CONFIG_IA64_SGI_SN_SIM
-  Build a kernel that runs on both the SGI simulator AND on hardware.
-  There is a very slight performance penalty on hardware for including this
-  option.
-
-CONFIG_IA64_SGI_SN_DEBUG
-  This enables addition debug code that helps isolate
-  platform/kernel bugs. There is a small but measurable performance
-  degradation when this option is enabled.
-
 # Choice: pagesize
 Kernel page size
 CONFIG_IA64_PAGE_SIZE_4KB
diff -urN linux-2.4.21-pre3/Documentation/IPMI.txt linux-2.4.21-pre4/Documentation/IPMI.txt
--- linux-2.4.21-pre3/Documentation/IPMI.txt	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/Documentation/IPMI.txt	Tue Jan 28 19:44:28 2003
@@ -0,0 +1,341 @@
+
+                          The Linux IPMI Driver
+			  ---------------------
+			      Corey Minyard
+			  <minyard@mvista.com>
+			    <minyard@acm.org>
+
+This document describes how to use the IPMI driver for Linux.  If you
+are not familiar with IPMI itself, see the web site at
+http://www.intel.com/design/servers/ipmi/index.htm.  IPMI is a big
+subject and I can't cover it all here!
+
+Basic Design
+------------
+
+The Linux IPMI driver is designed to be very modular and flexible, you
+only need to take the pieces you need and you can use it in many
+different ways.  Because of that, it's broken into many chunks of
+code.  These chunks are:
+
+ipmi_msghandler - This is the central piece of software for the IPMI
+system.  It handles all messages, message timing, and responses.  The
+IPMI users tie into this, and the IPMI physical interfaces (called
+System Management Interfaces, or SMIs) also tie in here.  This
+provides the kernelland interface for IPMI, but does not provide an
+interface for use by application processes.
+
+ipmi_devintf - This provides a userland IOCTL interface for the IPMI
+driver, each open file for this device ties in to the message handler
+as an IPMI user.
+
+ipmi_kcs_drv - A driver for the KCS SMI.  Most system have a KCS
+interface for IPMI.
+
+
+Much documentation for the interface is in the include files.  The
+IPMI include files are:
+
+ipmi.h - Contains the user interface and IOCTL interface for IPMI.
+
+ipmi_smi.h - Contains the interface for SMI drivers to use.
+
+ipmi_msgdefs.h - General definitions for base IPMI messaging.
+
+
+Addressing
+----------
+
+The IPMI addressing works much like IP addresses, you have an overlay
+to handle the different address types.  The overlay is:
+
+  struct ipmi_addr
+  {
+	int   addr_type;
+	short channel;
+	char  data[IPMI_MAX_ADDR_SIZE];
+  };
+
+The addr_type determines what the address really is.  The driver
+currently understands two different types of addresses.
+
+"System Interface" addresses are defined as:
+
+  struct ipmi_system_interface_addr
+  {
+	int   addr_type;
+	short channel;
+  };
+
+and the type is IPMI_SYSTEM_INTERFACE_ADDR_TYPE.  This is used for talking
+straight to the BMC on the current card.  The channel must be
+IPMI_BMC_CHANNEL.
+
+Messages that are destined to go out on the IPMB bus use the
+IPMI_IPMB_ADDR_TYPE address type.  The format is
+
+  struct ipmi_ipmb_addr
+  {
+	int           addr_type;
+	short         channel;
+	unsigned char slave_addr;
+	unsigned char lun;
+  };
+
+The "channel" here is generally zero, but some devices support more
+than one channel, it corresponds to the channel as defined in the IPMI
+spec.
+
+
+Messages
+--------
+
+Messages are defined as:
+
+struct ipmi_msg
+{
+	unsigned char netfn;
+	unsigned char lun;
+	unsigned char cmd;
+	unsigned char *data;
+	int           data_len;
+};
+
+The driver takes care of adding/stripping the header information.  The
+data portion is just the data to be send (do NOT put addressing info
+here) or the response.  Note that the completion code of a response is
+the first item in "data", it is not stripped out because that is how
+all the messages are defined in the spec (and thus makes counting the
+offsets a little easier :-).
+
+When using the IOCTL interface from userland, you must provide a block
+of data for "data", fill it, and set data_len to the length of the
+block of data, even when receiving messages.  Otherwise the driver
+will have no place to put the message.
+
+Messages coming up from the message handler in kernelland will come in
+as:
+
+  struct ipmi_recv_msg
+  {
+	struct list_head link;
+
+	/* The type of message as defined in the "Receive Types"
+           defines above. */
+	int         recv_type;
+
+	ipmi_user_t      *user;
+	struct ipmi_addr addr;
+	long             msgid;
+	struct ipmi_msg  msg;
+
+	/* Call this when done with the message.  It will presumably free
+	   the message and do any other necessary cleanup. */
+	void (*done)(struct ipmi_recv_msg *msg);
+
+	/* Place-holder for the data, don't make any assumptions about
+	   the size or existence of this, since it may change. */
+	unsigned char   msg_data[IPMI_MAX_MSG_LENGTH];
+  };
+
+You should look at the receive type and handle the message
+appropriately.
+
+
+The Upper Layer Interface (Message Handler)
+-------------------------------------------
+
+The upper layer of the interface provides the users with a consistent
+view of the IPMI interfaces.  It allows multiple SMI interfaces to be
+addressed (because some boards actually have multiple BMCs on them)
+and the user should not have to care what type of SMI is below them.
+
+
+Creating the User
+
+To user the message handler, you must first create a user using
+ipmi_create_user.  The interface number specifies which SMI you want
+to connect to, and you must supply callback functions to be called
+when data comes in.  The callback function can run at interrupt level,
+so be careful using the callbacks.  This also allows to you pass in a
+piece of data, the handler_data, that will be passed back to you on
+all calls.
+
+Once you are done, call ipmi_destroy_user() to get rid of the user.
+
+From userland, opening the device automatically creates a user, and
+closing the device automatically destroys the user.
+
+
+Messaging
+
+To send a message from kernel-land, the ipmi_request() call does
+pretty much all message handling.  Most of the parameter are
+self-explanatory.  However, it takes a "msgid" parameter.  This is NOT
+the sequence number of messages.  It is simply a long value that is
+passed back when the response for the message is returned.  You may
+use it for anything you like.
+
+Responses come back in the function pointed to by the ipmi_recv_hndl
+field of the "handler" that you passed in to ipmi_create_user().
+Remember again, these may be running at interrupt level.  Remember to
+look at the receive type, too.
+
+From userland, you fill out an ipmi_req_t structure and use the
+IPMICTL_SEND_COMMAND ioctl.  For incoming stuff, you can use select()
+or poll() to wait for messages to come in.  However, you cannot use
+read() to get them, you must call the IPMICTL_RECEIVE_MSG with the
+ipmi_recv_t structure to actually get the message.  Remember that you
+must supply a pointer to a block of data in the msg.data field, and
+you must fill in the msg.data_len field with the size of the data.
+This gives the receiver a place to actually put the message.
+
+If the message cannot fit into the data you provide, you will get an
+EMSGSIZE error and the driver will leave the data in the receive
+queue.  If you want to get it and have it truncate the message, us
+the IPMICTL_RECEIVE_MSG_TRUNC ioctl.
+
+When you send a command (which is defined by the lowest-order bit of
+the netfn per the IPMI spec) on the IPMB bus, the driver will
+automatically assign the sequence number to the command and save the
+command.  If the response is not receive in the IPMI-specified 5
+seconds, it will generate a response automatically saying the command
+timed out.  If an unsolicited response comes in (if it was after 5
+seconds, for instance), that response will be ignored.
+
+In kernelland, after you receive a message and are done with it, you
+MUST call ipmi_free_recv_msg() on it, or you will leak messages.  Note
+that you should NEVER mess with the "done" field of a message, that is
+required to properly clean up the message.
+
+Note that when sending, there is an ipmi_request_supply_msgs() call
+that lets you supply the smi and receive message.  This is useful for
+pieces of code that need to work even if the system is out of buffers
+(the watchdog timer uses this, for instance).  You supply your own
+buffer and own free routines.  This is not recommended for normal use,
+though, since it is tricky to manage your own buffers.
+
+
+Events and Incoming Commands
+
+The driver takes care of polling for IPMI events and receiving
+commands (commands are messages that are not responses, they are
+commands that other things on the IPMB bus have sent you).  To receive
+these, you must register for them, they will not automatically be sent
+to you.
+
+To receive events, you must call ipmi_set_gets_events() and set the
+"val" to non-zero.  Any events that have been received by the driver
+since startup will immediately be delivered to the first user that
+registers for events.  After that, if multiple users are registered
+for events, they will all receive all events that come in.
+
+For receiving commands, you have to individually register commands you
+want to receive.  Call ipmi_register_for_cmd() and supply the netfn
+and command name for each command you want to receive.  Only one user
+may be registered for each netfn/cmd, but different users may register
+for different commands.
+
+From userland, equivalent IOCTLs are provided to do these functions.
+
+
+The Lower Layer (SMI) Interface
+-------------------------------
+
+As mentioned before, multiple SMI interfaces may be registered to the
+message handler, each of these is assigned an interface number when
+they register with the message handler.  They are generally assigned
+in the order they register, although if an SMI unregisters and then
+another one registers, all bets are off.
+
+The ipmi_smi.h defines the interface for SMIs, see that for more
+details.
+
+
+The KCS Driver
+--------------
+
+The KCS driver allows up to 4 KCS interfaces to be configured in the
+system.  By default, the driver will register one KCS interface at the
+spec-specified I/O port 0xca2 without interrupts.  You can change this
+at module load time (for a module) with:
+
+  insmod ipmi_kcs_drv.o kcs_ports=<port1>,<port2>... kcs_addrs=<addr1>,<addr2>
+       kcs_irqs=<irq1>,<irq2>... kcs_trydefaults=[0|1]
+
+The KCS driver supports two types of interfaces, ports (for I/O port
+based KCS interfaces) and memory addresses (for KCS interfaces in
+memory).  The driver will support both of them simultaneously, setting
+the port to zero (or just not specifying it) will allow the memory
+address to be used.  The port will override the memory address if it
+is specified and non-zero.  kcs_trydefaults sets whether the standard
+IPMI interface at 0xca2 and any interfaces specified by ACPE are
+tried.  By default, the driver tries it, set this value to zero to
+turn this off.
+
+When compiled into the kernel, the addresses can be specified on the
+kernel command line as:
+
+  ipmi_kcs=<bmc1>:<irq1>,<bmc2>:<irq2>....,[nodefault]
+
+The <bmcx> values is either "p<port>" or "m<addr>" for port or memory
+addresses.  So for instance, a KCS interface at port 0xca2 using
+interrupt 9 and a memory interface at address 0xf9827341 with no
+interrupt would be specified "ipmi_kcs=p0xca2:9,m0xf9827341".
+If you specify zero for in irq or don't specify it, the driver will
+run polled unless the software can detect the interrupt to use in the
+ACPI tables.
+
+By default, the driver will attempt to detect a KCS device at the
+spec-specified 0xca2 address and any address specified by ACPI.  If
+you want to turn this off, use the "nodefault" option.
+
+If you have high-res timers compiled into the kernel, the driver will
+use them to provide much better performance.  Note that if you do not
+have high-res timers enabled in the kernel and you don't have
+interrupts enabled, the driver will run VERY slowly.  Don't blame me,
+the KCS interface sucks.
+
+
+Other Pieces
+------------
+
+Watchdog
+
+A watchdog timer is provided that implements the Linux-standard
+watchdog timer interface.  It has three module parameters that can be
+used to control it:
+
+  insmod ipmi_watchdog timeout=<t> pretimeout=<t> action=<action type>
+      preaction=<preaction type>
+
+The timeout is the number of seconds to the action, and the pretimeout
+is the amount of seconds before the reset that the pre-timeout panic will
+occur (if pretimeout is zero, then pretimeout will not be enabled).
+
+The action may be "reset", "power_cycle", or "power_off", and
+specifies what to do when the timer times out, and defaults to
+"reset".
+
+The preaction may be "pre_smi" for an indication through the SMI
+interface, "pre_int" for an indication through the SMI with an
+interrupts, and "pre_nmi" for a NMI on a preaction.
+
+When compiled into the kernel, the kernel command line is available
+for configuring the watchdog:
+
+  ipmi_wdog=<timeout>[,<pretimeout>[,<option>[,<options>....]]]
+
+The options are the actions and preaction above (if an option
+controlling the same thing is specified twice, the last is taken).  An
+options "start_now" is also there, if included, the watchdog will
+start running immediately when all the drivers are ready, it doesn't
+have to have a user hooked up to start it.
+
+The watchdog will panic and start a 120 second reset timeout if it
+gets a pre-action.  During a panic or a reboot, the watchdog will
+start a 120 timer if it is running to make sure the reboot occurs.
+
+Note that if you use the NMI preaction for the watchdog, you MUST
+NOT use nmi watchdog mode 1.  If you use the NMI watchdog, you
+must use mode 2.
diff -urN linux-2.4.21-pre3/Documentation/filesystems/Locking linux-2.4.21-pre4/Documentation/filesystems/Locking
--- linux-2.4.21-pre3/Documentation/filesystems/Locking	Tue Jan 28 19:44:23 2003
+++ linux-2.4.21-pre4/Documentation/filesystems/Locking	Tue Jan 28 19:44:28 2003
@@ -109,7 +109,7 @@
 clear_inode:	no	
 put_super:	yes	yes	maybe		(see below)
 write_super:	yes	yes	maybe		(see below)
-write_super:	yes	no	maybe		(see below)
+sync_fs:	yes	no	maybe		(see below)
 statfs:		yes	no	no
 remount_fs:	yes	yes	maybe		(see below)
 umount_begin:	yes	no	maybe		(see below)
diff -urN linux-2.4.21-pre3/Documentation/filesystems/proc.txt linux-2.4.21-pre4/Documentation/filesystems/proc.txt
--- linux-2.4.21-pre3/Documentation/filesystems/proc.txt	Thu Nov 28 15:53:08 2002
+++ linux-2.4.21-pre4/Documentation/filesystems/proc.txt	Tue Jan 28 19:44:28 2003
@@ -952,15 +952,14 @@
 Table 2-2: Parameters in /proc/sys/vm/bdflush 
 ..............................................................................
  Value      Meaning                                                            
- nfract     Percentage of buffer cache dirty to  activate bdflush              
+ nfract     Percentage of buffer cache dirty to activate bdflush              
  ndirty     Maximum number of dirty blocks to  write out per wake-cycle        
- nrefill    Number of clean buffers to try to obtain  each time we call refill 
- nref_dirt  buffer threshold for activating bdflush when trying to refill
-            buffers. 
  dummy      Unused                                                             
- age_buffer Time for normal buffer to age before we flush it                   
- age_super  Time for superblock to age before we flush it                      
  dummy      Unused                                                             
+ interval   jiffies delay between kupdate flushes
+ age_buffer Time for normal buffer to age before we flush it                   
+ nfract_sync Percentage of buffer cache dirty to activate bdflush synchronously
+ nfract_stop_bdflush Percetange of buffer cache dirty to stop bdflush
  dummy      Unused                                                             
 ..............................................................................
 
@@ -974,6 +973,12 @@
 long time, but it also means that it will have to do a lot of I/O at once when
 memory becomes short. A lower value will spread out disk I/O more evenly.
 
+interval
+--------
+
+The interval between two kupdate runs. The value is expressed in
+jiffies (clockticks),  the  number of jiffies per second is 100.
+
 ndirty
 ------
 
@@ -981,29 +986,18 @@
 disk at  one  time.  A high value will mean delayed, bursty I/O, while a small
 value can lead to memory shortage when bdflush isn't woken up often enough.
 
-nrefill
--------
-
-This is  the  number  of  buffers  that  bdflush  will add to the list of free
-buffers when  refill_freelist()  is  called.  It is necessary to allocate free
-buffers beforehand,  since  the  buffers  are  often  different sizes than the
-memory pages  and some bookkeeping needs to be done beforehand. The higher the
-number, the  more  memory  will be wasted and the less often refill_freelist()
-will need to run.
-
-nref_dirt
----------
+age_buffer
+----------
 
-When refill_freelist() comes across more than nref_dirt dirty buffers, it will
-wake up bdflush.
+Finally, the age_buffer parameter govern the maximum time Linux
+waits before  writing  out  a  dirty buffer to disk. The value is expressed in
+jiffies (clockticks),  the  number of jiffies per second is 100.
 
-age_buffer and age_super
-------------------------
+nfract_sync
+-----------
 
-Finally, the age_buffer and age_super parameters govern the maximum time Linux
-waits before  writing  out  a  dirty buffer to disk. The value is expressed in
-jiffies (clockticks),  the  number of jiffies per second is 100. Age_buffer is
-the maximum age for data blocks, while age_super is for filesystems meta data.
+nfract_stop_bdflush
+-------------------
 
 buffermem
 ---------
@@ -1582,10 +1576,14 @@
 error_burst and error_cost
 --------------------------
 
-These parameters  are used to limit the warning messages written to the kernel
-log from  the  routing  code.  The  higher the error_cost factor is, the fewer
-messages will  be written. Error_burst controls when messages will be dropped.
-The default settings limit warning messages to one every five seconds.
+These  parameters  are used to limit how many ICMP destination unreachable to 
+send  from  the  host  in question. ICMP destination unreachable messages are 
+sent  when  we can not reach the next hop, while trying to transmit a packet. 
+It  will also print some error messages to kernel logs if someone is ignoring 
+our   ICMP  redirects.  The  higher  the  error_cost  factor  is,  the  fewer 
+destination  unreachable  and error messages will be let through. Error_burst 
+controls  when  destination  unreachable  messages and error messages will be
+dropped. The default settings limit warning messages to five every second.
 
 flush
 -----
diff -urN linux-2.4.21-pre3/Documentation/networking/NAPI_HOWTO.txt linux-2.4.21-pre4/Documentation/networking/NAPI_HOWTO.txt
--- linux-2.4.21-pre3/Documentation/networking/NAPI_HOWTO.txt	Thu Nov 28 15:53:08 2002
+++ linux-2.4.21-pre4/Documentation/networking/NAPI_HOWTO.txt	Tue Jan 28 19:44:28 2003
@@ -721,6 +721,23 @@
 
 
 
+
+APPENDIX 3: Scheduling issues.
+==============================
+As seen NAPI moves processing to softirq level. Linux uses the ksoftirqd as the 
+general solution to schedule softirq's to run before next interrupt and by putting 
+them under scheduler control. Also this prevents consecutive softirq's from 
+monopolize the CPU. This also have the effect that the priority of ksoftirq needs 
+to be considered when running very CPU-intensive applications and networking to
+get the proper balance of softirq/user balance. Increasing ksoftirq priority to 0 
+(eventually more) is reported cure problems with low network performance at high 
+CPU load.
+
+Most used processes in a GIGE router:
+USER       PID %CPU %MEM  SIZE   RSS TTY STAT START   TIME COMMAND
+root         3  0.2  0.0     0     0  ?  RWN Aug 15 602:00 (ksoftirqd_CPU0)
+root       232  0.0  7.9 41400 40884  ?  S   Aug 15  74:12 gated 
+
 --------------------------------------------------------------------
 
 relevant sites:
diff -urN linux-2.4.21-pre3/Documentation/networking/ip-sysctl.txt linux-2.4.21-pre4/Documentation/networking/ip-sysctl.txt
--- linux-2.4.21-pre3/Documentation/networking/ip-sysctl.txt	Tue Jan 28 19:44:23 2003
+++ linux-2.4.21-pre4/Documentation/networking/ip-sysctl.txt	Tue Jan 28 19:44:28 2003
@@ -281,6 +281,14 @@
 	asassination.	
 	Default: 0
 
+tcp_low_latency - BOOLEAN
+	If set, the TCP stack makes decisions that prefer lower
+	latency as opposed to higher throughput.  By default, this
+	option is not set meaning that higher throughput is preferred.
+	An example of an application where this default should be
+	changed would be a Beowulf compute cluster.
+	Default: 0
+
 ip_local_port_range - 2 INTEGERS
 	Defines the local port range that is used by TCP and UDP to
 	choose the local port. The first number is the first, the 
diff -urN linux-2.4.21-pre3/Documentation/video4linux/bttv/CARDLIST linux-2.4.21-pre4/Documentation/video4linux/bttv/CARDLIST
--- linux-2.4.21-pre3/Documentation/video4linux/bttv/CARDLIST	Thu Nov 28 15:53:08 2002
+++ linux-2.4.21-pre4/Documentation/video4linux/bttv/CARDLIST	Tue Jan 28 19:44:28 2003
@@ -2,7 +2,7 @@
   card=0 -  *** UNKNOWN/GENERIC *** 
   card=1 - MIRO PCTV
   card=2 - Hauppauge (bt848)
-  card=3 - STB
+  card=3 - STB, Gateway P/N 6000699 (bt848)
   card=4 - Intel Create and Share PCI/ Smart Video Recorder III
   card=5 - Diamond DTV2000
   card=6 - AVerMedia TVPhone
@@ -24,22 +24,22 @@
   card=22 - Askey CPH050/ Phoebe Tv Master + FM
   card=23 - Modular Technology MM205 PCTV, bt878
   card=24 - Askey CPH05X/06X (bt878) [many vendors]
-  card=25 - Terratec Terra TV+ Version 1.0 (Bt848)/Vobis TV-Boostar
+  card=25 - Terratec TerraTV+ Version 1.0 (Bt848)/ Terra TValue Version 1.0/ Vobis TV-Boostar
   card=26 - Hauppauge WinCam newer (bt878)
   card=27 - Lifeview FlyVideo 98/ MAXI TV Video PCI2 LR50
-  card=28 - Terratec TerraTV+
+  card=28 - Terratec TerraTV+ Version 1.1 (bt878)
   card=29 - Imagenation PXC200
   card=30 - Lifeview FlyVideo 98 LR50
   card=31 - Formac iProTV
   card=32 - Intel Create and Share PCI/ Smart Video Recorder III
-  card=33 - Terratec TerraTValue
-  card=34 - Leadtek WinFast 2000
+  card=33 - Terratec TerraTValue Version Bt878
+  card=34 - Leadtek WinFast 2000/ WinFast 2000 XP
   card=35 - Lifeview FlyVideo 98 LR50 / Chronos Video Shuttle II
   card=36 - Lifeview FlyVideo 98FM LR50 / Typhoon TView TV/FM Tuner
   card=37 - Prolink PixelView PlayTV pro
   card=38 - Askey CPH06X TView99
   card=39 - Pinnacle PCTV Studio/Rave
-  card=40 - STB2
+  card=40 - STB TV PCI FM, Gateway P/N 6000704 (bt878)
   card=41 - AVerMedia TVPhone 98
   card=42 - ProVideo PV951
   card=43 - Little OnAir TV
@@ -69,7 +69,7 @@
   card=67 - IODATA GV-BCTV4/PCI
   card=68 - 3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA)
   card=69 - Active Imaging AIMMS
-  card=70 - Prolink Pixelview PV-BT878P+ (Rev.4C)
+  card=70 - Prolink Pixelview PV-BT878P+ (Rev.4C,8E)
   card=71 - Lifeview FlyVideo 98EZ (capture only) LR51
   card=72 - Prolink Pixelview PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM)
   card=73 - Sensoray 311
@@ -80,6 +80,7 @@
   card=78 - Jetway TV/Capture JW-TV878-FBK, Kworld KW-TV878RF
   card=79 - DSP Design TCVIDEO
   card=80 - Hauppauge WinTV PVR
+  card=81 - GV-BCTV5/PCI
 
 tuner.o
   type=0 - Temic PAL (4002 FH5)
diff -urN linux-2.4.21-pre3/Documentation/video4linux/bttv/Cards linux-2.4.21-pre4/Documentation/video4linux/bttv/Cards
--- linux-2.4.21-pre3/Documentation/video4linux/bttv/Cards	Thu Nov 28 15:53:08 2002
+++ linux-2.4.21-pre4/Documentation/video4linux/bttv/Cards	Tue Jan 28 19:44:28 2003
@@ -4,25 +4,27 @@
 
 
 Suppported cards:
-
-
 Bt848/Bt848a/Bt849/Bt878/Bt879 cards
 ------------------------------------
 
-All cards with Bt848/Bt848a/Bt849/Bt878/Bt879 and normal Composite/S-VHS inputs
-are supported.
-Teletext and Intercast support (PAL only) for ALL cards via VBI sample decoding
-in software.
+All cards with Bt848/Bt848a/Bt849/Bt878/Bt879 and normal
+Composite/S-VHS inputs are supported.  Teletext and Intercast support
+(PAL only) for ALL cards via VBI sample decoding in software.
+
+Some cards with additional multiplexing of inputs or other additional
+fancy chips are only partially supported (unless specifications by the
+card manufacturer are given).  When a card is listed here it isn't
+necessarily fully supported.
 
-Some cards with additional multiplexing of inputs are only partially 
-supported (unless specifications by the card manufacturer are given).
+All other cards only differ by additional components as tuners, sound
+decoders, EEPROMs, teletext decoders ...
 
-All other cards only differ by additional components as tuners, sound decoders,
-EEPROMs, teletext decoders ...
 
 Unsupported Cards: 
 ------------------
-Cards with Zoran (ZR) or Philips (SAA) or ISA are not supported by this driver. 
+
+Cards with Zoran (ZR) or Philips (SAA) or ISA are not supported by
+this driver.
 
 
 MATRIX Vision
@@ -197,7 +199,7 @@
   50686 "TV Tuner"                       = KNC1 TV Station
   50687 "TV Tuner stereo"                = KNC1 TV Station pro
   50688 "TV Tuner RDS" (black package)   = KNC1 TV Station RDS
-  50689  TV SAT DVB-S CARD CI PCI (SAA7146AH)
+  50689  TV SAT DVB-S CARD CI PCI (SAA7146AH, SU1278?) = "KNC1 TV Station DVB-S"
   50692 "TV/FM Tuner" (small PCB)
   50694  TV TUNER CARD RDS (PHILIPS CHIPSET SAA7134HL)
   50696  TV TUNER STEREO (PHILIPS CHIPSET SAA7134HL, MK3ME Tuner)
@@ -234,10 +236,20 @@
    PixelView PowerStudio PAK - (Model: PV-M3600 REV 4E)
    PixelView DigitalVCR PAK -  (Model: PV-M2400 REV 4C / 8D / 10A )
 
+   PixelView PlayTV PAK II (TV/FM card + usb camera)  PV-M3800 
+   PixelView PlayTV XP PV-M4700,PV-M4700(w/FM)
+   PixelView PlayTV DVR PV-M4600  package contents:PixelView PlayTV pro, windvr & videoMail s/w
+
    Further Cards:
    PV-BT878P+rev.9B (Play TV Pro, opt. w/FM w/NICAM)
    PV-BT878P+rev.2F
    PV-BT878P Rev.1D (bt878, capture only)
+
+   XCapture PV-CX881P (cx23881)
+   PlayTV HD PV-CX881PL+, PV-CX881PL+(w/FM) (cx23881)
+
+   DTV3000 PV-DTV3000P+ DVB-S CI = Twinhan VP-1030
+   DTV2000 DVB-S = Twinhan VP-1020
    
    Video Conferencing:
    PixelView Meeting PAK - (Model: PV-BT878P)
@@ -245,6 +257,9 @@
    PixelView Meeting PAK plus - (Model: PV-BT878P+rev 4C/8D/10A)
    PixelView Capture - (Model: PV-BT848P)
 
+   PixelView PlayTV USB pro
+   Model No. PV-NT1004+, PV-NT1004+ (w/FM) = NT1004 USB decoder chip + SAA7113 video decoder chip
+
 Dynalink
 --------
    These are CPH series.
@@ -275,6 +290,7 @@
    WinView 601 (Bt848)
    WinView 610 (Zoran)
    WinFast2000
+   WinFast2000 XP
 
 KNC One
 -------
@@ -283,18 +299,37 @@
    TV-Station pro (+TV stereo)
    TV-Station FM (+Radio)
    TV-Station RDS (+RDS)
+   TV Station SAT (analog satellite)
+   TV-Station DVB-S
 
    newer Cards have saa7134, but model name stayed the same?
 
-Provideo PV951 
---------------
-  These are sold as:
+Provideo 
+--------
+  PV951 or PV-951 (also are sold as:
    Boeder TV-FM Video Capture Card
    Titanmedia Supervision TV-2400
    Provideo PV951 TF
    3DeMon PV951
    MediaForte TV-Vision PV951
    Yoko PV951
+   Vivanco Tuner Card PCI Art.-Nr.: 68404
+  ) now named PV-951T
+
+  Surveillance Series
+  PV-141
+  PV-143
+  PV-147
+  PV-148 (capture only)
+  PV-150
+  PV-151
+
+  TV-FM Tuner Series
+  PV-951TDV (tv tuner + 1394)
+  PV-951T/TF
+  PV-951PT/TF
+  PV-956T/TF Low Profile
+  PV-911
 
 Highscreen
 ----------
@@ -324,12 +359,43 @@
 
    PCB      PCI-ID      Model-Name      Eeprom  Tuner  Sound    Country
    --------------------------------------------------------------------
-   M1A8-A      --       AVer TV-Phone           FM1216  --
+   M101.C   ISA !
+   M108-B      Bt848                     --     FR1236		 US   (2),(3)
+   M1A8-A      Bt848    AVer TV-Phone           FM1216  --
    M168-T   1461:0003   AVerTV Studio   48:17   FM1216 TDA9840T  D    (1) w/FM w/Remote
    M168-U   1461:0004   TVCapture98     40:11   FI1216   --      D    w/Remote
    M168II-B 1461:0003   Medion MD9592   48:16   FM1216 TDA9873H  D    w/FM
 
    (1) Daughterboard MB68-A with TDA9820T and TDA9840T
+   (2) Sony NE41S soldered (stereo sound?)
+   (3) Daughterboard M118-A w/ pic 16c54 and 4 MHz quartz
+ 
+   US site has different drivers for (as of 09/2002):
+   EZ Capture/InterCam PCI (BT-848 chip)
+   EZ Capture/InterCam PCI (BT-878 chip)
+   TV-Phone (BT-848 chip)
+   TV98 (BT-848 chip)
+   TV98 With Remote (BT-848 chip)
+   TV98 (BT-878 chip)
+   TV98 With Remote (BT-878)
+   TV/FM98 (BT-878 chip)
+   AVerTV
+   AverTV Stereo
+   AVerTV Studio
+
+   DE hat diverse Treiber fuer diese Modelle (Stand 09/2002):
+   TVPhone (848) mit Philips tuner FR12X6 (w/ FM radio)
+   TVPhone (848) mit Philips tuner FM12X6 (w/ FM radio)
+   TVCapture (848) w/Philips tuner FI12X6
+   TVCapture (848) non-Philips tuner
+   TVCapture98 (Bt878)
+   TVPhone98 (Bt878)
+   AVerTV und TVCapture98 w/VCR (Bt 878)
+   AVerTVStudio und TVPhone98 w/VCR (Bt878)
+   AVerTV GO Serie (Kein SVideo Input)
+   AVerTV98 (BT-878 chip)
+   AVerTV98 mit Fernbedienung (BT-878 chip)
+   AVerTV/FM98 (BT-878 chip)
 
 Aimslab
 -------
@@ -338,9 +404,9 @@
 
 IXMicro (former: IMS=Integrated Micro Solutions)
 -------
-   IXTV BT848
+   IXTV BT848 (=TurboTV)
    IXTV BT878
-   TurboTV (Bt848)
+   IMS TurboTV (Bt848)
 
 Lifetec/Medion/Tevion/Aldi
 --------------------------
@@ -352,8 +418,10 @@
 Modular Technologies (www.modulartech.com) UK
 ---------------------------------------------
    MM100 PCTV (Bt848)
+   MM201 PCTV (Bt878, Bt832) w/ Quartzsight camera
+   MM202 PCTV (Bt878, Bt832, tda9874)
    MM205 PCTV (Bt878)
-   MM210 PCTV (Bt878) (Galaxy TV)
+   MM210 PCTV (Bt878) (Galaxy TV, Galaxymedia ?)
 
 Terratec
 --------
@@ -365,11 +433,13 @@
    Terra TValue Version BT878,    "80-CP2830110-0 TTTV4" printed on the PCB, 
 				     "CPH011-D83" on back
    Terra TValue Version 1.0       "ceb105.PCB" (really identical to Terra TV+ Version 1.0)
+   Terra TValue New Revision	  "LR102 Rec.C"
    Terra Active Radio Upgrade (tea5757h, saa6588t)
 
    LR74 is a newer PCB revision of ceb105 (both incl. connector for Active Radio Upgrade)
 
    Cinergy 400 (saa7134), "E877 11(S)", "PM820092D" printed on PCB
+   Cinergy 600 (saa7134)
 
 Technisat
 ---------
@@ -380,7 +450,7 @@
    Mediafocus I (zr36120/zr36125, drp3510, Sat. analog + ADR Radio)
    Mediafocus II (saa7146, Sat. analog)
          SatADR Rev 2.1 (saa7146a, saa7113h, stv0056a, msp3400c, drp3510a, BSKE3-307A)
-   SkyStar 1 DVB  (AV7110)
+   SkyStar 1 DVB  (AV7110) = Technotrend Premium
    SkyStar 2 DVB  (B2C2) (=Sky2PC)
 
 Siemens
@@ -394,6 +464,9 @@
 Powercolor
 ----------
    MTV878
+       Package comes with different contents:
+       a) pcb "MTV878" (CARD=75)
+       b) Pixelview Rev. 4_
    MTV878R w/Remote Control
    MTV878F w/Remote Control w/FM radio
 
@@ -401,10 +474,14 @@
 --------
    Mirovideo PCTV (Bt848)
    Mirovideo PCTV SE (Bt848)
-   Mirovideo PCTV Pro (Bt848 + Daughterboard)
+   Mirovideo PCTV Pro (Bt848 + Daughterboard for TV Stereo and FM)
+   Studio PCTV Rave (Bt848 Version = Mirovideo PCTV)
    Studio PCTV Rave (Bt878 package w/o infrared)
    Studio PCTV      (Bt878)
    Studio PCTV Pro  (Bt878 stereo w/ FM)
+   Pinnacle PCTV    (Bt878, MT2032)
+   Pinnacle PCTV Pro (Bt878, MT2032)
+   Pinncale PCTV Sat (bt878a, HM1821/1221)
 
    M(J)PEG capture and playback:
    DC1+ (ISA)
@@ -477,7 +554,7 @@
 ------
    iProTV (Card for iMac Mezzanine slot, Bt848+SCSI)
    ProTV (Bt848)
-   ProTV II = ProTV Stereo (Bt878)
+   ProTV II = ProTV Stereo (Bt878) ["stereo" means FM stereo, tv is still mono]
 
 ATI
 ---
@@ -502,8 +579,10 @@
 
 STB
 ---
-   TV PCI (Temic4032FY5, tda9850??)
-   other variants?
+   STB Gateway 6000704 (bt878)
+   STB Gateway 6000699 (bt848)
+   STB Gateway 6000402 (bt848)
+   STB TV130 PCI
 
 Videologic
 ----------
@@ -514,6 +593,17 @@
 ------------
    TT-SAT PCI (PCB "Sat-PCI Rev.:1.3.1"; zr36125, vpx3225d, stc0056a, Tuner:BSKE6-155A
    TT-DVB-Sat
+    revisions 1.1, 1.3, 1.5, 1.6 and 2.1
+    This card is sold as OEM from:
+	Siemens DVB-s Card
+	Hauppauge WinTV DVB-S
+	Technisat SkyStar 1 DVB
+	Galaxis DVB Sat
+    Now this card is called TT-PCline Premium Family
+   TT-Budget (saa7146, bsru6-701a)
+    This card is sold as OEM from:
+	Hauppauge WinTV Nova
+	Satelco Standard PCI (DVB-S)
    TT-DVB-C PCI
 
 Teles
@@ -549,14 +639,70 @@
    Galaxis DVB Card C CI
    Galaxis DVB Card S
    Galaxis DVB Card C
+   Galaxis plug.in S [neuer Name: Galaxis DVB Card S CI
 
 Hauppauge
 ---------
    many many WinTV models ...
-   WinTV DVBs
-   WinTV NOVA
-   WinTV NOVA-CI
-   WinTV-Nexus-s
+   WinTV DVBs = Technotrend Premium 1.3
+   WinTV NOVA = Technotrend Budget 1.1 "S-DVB DATA"
+   WinTV NOVA-CI "SDVBACI"
+   WinTV Nova USB (=Technotrend USB 1.0)
+   WinTV-Nexus-s (=Technotrend Premium 2.1 or 2.2)
+   WinTV PVR
+   WinTV PVR 250
+   WinTV PVR 450
+
+  US models
+  990 WinTV-PVR-350 (249USD)
+  980 WinTV-PVR-250 (149USD)
+  880 WinTV-PVR-PCI (199USD)
+  881 WinTV-PVR-USB
+  190 WinTV-GO
+  191 WinTV-GO-FM
+  404 WinTV
+  401 WinTV-radio
+  495 WinTV-Theater
+  602 WinTV-USB
+  621 WinTV-USB-FM
+  600 USB-Live
+  698 WinTV-HD
+  697 WinTV-D
+  564 WinTV-Nexus-S
+
+  Deutsche Modelle
+  603 WinTV GO
+  719 WinTV Primio-FM
+  718 WinTV PCI-FM
+  497 WinTV Theater
+  569 WinTV USB
+  568 WinTV USB-FM
+  882 WinTV PVR
+  981 WinTV PVR 250
+  891 WinTV-PVR-USB
+  541 WinTV Nova
+  488 WinTV Nova-Ci
+  564 WinTV-Nexus-s
+  727 WinTV-DVB-c
+  545 Common Interface
+  898 WinTV-Nova-USB
+
+  UK models
+  607 WinTV Go
+  693,793 WinTV Primio FM
+  647,747 WinTV PCI FM
+  498 WinTV Theater
+  883 WinTV PVR
+  893 WinTV PVR USB  (Duplicate entry)
+  566 WinTV USB (UK)
+  573 WinTV USB FM
+  429 Impact VCB (bt848)
+  600 USB Libe (Video-In 1x Comp, 1xSVHS)
+  542 WinTV Nova
+  717 WinTV DVB-S
+  909 Nova-t PCI
+  893 Nova-t USB   (Duplicate entry)
+  
 
 Matrix-Vision
 -------------
@@ -622,7 +768,7 @@
 
 NoBrand
 -------
-   TV Excel = Australian Name for "PV-BT878P+ 8E" or so
+   TV Excel = Australian Name for "PV-BT878P+ 8E" or "878TV Rev.3_"
 
 Mach www.machspeed.com
 ----
@@ -642,9 +788,13 @@
    HS-878 Mini PCI Capture Add-on Card
    HS-879 Mini PCI 3D Audio and Capture Add-on Card (w/ ES1938 Solo-1)
 
-Satelco
+Satelco www.citycom-gmbh.de, www.satelco.de
 -------
    TV-FM =KNC1 saa7134
+   Standard PCI (DVB-S) = Technotrend Budget
+   Standard PCI (DVB-S) w/ CI
+   Satelco Hoghend PCI (DVB-S) = Technotrend Premium
+
 
 Sensoray www.sensoray.com
 --------
@@ -661,3 +811,71 @@
    Manufacturer of video cards is listed as:
    Cogent Electronics Industries [CEI]
 
+AITech
+------
+   Wavewatcher TV (ISA)
+   AITech WaveWatcher TV-PCI = can be LR26 (Bt848) or LR50 (BT878)
+   WaveWatcher TVR-202 TV/FM Radio Card (ISA)
+
+MAXRON
+------
+   Maxron MaxTV/FM Radio (KW-TV878-FNT) = Kworld or JW-TV878-FBK
+
+www.ids-imaging.de
+------------------
+   Falcon Series (capture only)
+ In USA: http://www.theimagingsource.com/
+   DFG/LC1	
+
+www.sknet-web.co.jp
+-------------------
+   SKnet Monster TV (saa7134)
+
+A-Max www.amaxhk.com (Colormax, Amax, Napa)
+-------------------
+   APAC Viewcomp 878
+
+Cybertainment
+-------------
+   CyberMail AV Video Email Kit w/ PCI Capture Card (capture only)
+   CyberMail Xtreme
+  These are Flyvideo
+
+VCR (http://www.vcrinc.com/) 
+---
+  Video Catcher 16
+
+Twinhan
+-------
+   DST Card/DST-IP (bt878, twinhan asic) VP-1020
+    Sold as:
+     KWorld DVBS Satellite TV-Card
+     Powercolor DSTV Satellite Tuner Card
+     Prolink Pixelview DTV2000
+     Provideo PV-911 Digital Satellite TV Tuner Card With Common Interface ?
+   DST-CI Card (DVB Satellite) VP-1030
+   DCT Card (DVB cable)
+
+MSI
+---
+    MSI TV@nywhere Tuner Card (MS-8876) (CX23881/883) Not Bt878 compatible.
+    MS-8401 DVB-S
+
+Focus www.focusinfo.com
+-----
+    InVideo PCI (bt878)
+
+Sdisilk www.sdisilk.com/
+-------
+    SDI Silk 100
+    SDI Silk 200 SDI Input Card
+
+www.euresys.com
+    PICOLO series 
+
+PMC/Pace
+www.pacecom.co.uk website closed
+
+Mercury www.kobian.com (UK and FR)
+    LR50
+    LR138RBG-Rx  == LR138
diff -urN linux-2.4.21-pre3/Documentation/x86_64/mm.txt linux-2.4.21-pre4/Documentation/x86_64/mm.txt
--- linux-2.4.21-pre3/Documentation/x86_64/mm.txt	Thu Nov 28 15:53:08 2002
+++ linux-2.4.21-pre4/Documentation/x86_64/mm.txt	Tue Jan 28 19:44:28 2003
@@ -2,7 +2,6 @@
 
 o	per process virtual address space limit of 512 Gigabytes
 o	top of userspace stack located at address 0x0000007fffffffff
-o	PAGE_OFFSET = 0xffff800000000000
 o	start of the kernel mapping =  0x0000010000000000
 o	global RAM per system 508*512GB=254 Terabytes
 o	no need of any common code change
@@ -65,6 +64,7 @@
         1    unmapped
         2    __PAGE_OFFSET - start of direct mapping of physical memory
         ...  direct mapping in further slots as needed.
+	509  some io mappings (others are in a memory hole below 4gb)
         510  vmalloc and ioremap space
 	511  kernel code mapping, fixmaps and modules.  
 
diff -urN linux-2.4.21-pre3/MAINTAINERS linux-2.4.21-pre4/MAINTAINERS
--- linux-2.4.21-pre3/MAINTAINERS	Tue Jan 28 19:44:23 2003
+++ linux-2.4.21-pre4/MAINTAINERS	Tue Jan 28 19:44:28 2003
@@ -1805,6 +1805,14 @@
 L:	linux-usb-devel@lists.sourceforge.net
 S:	Maintained
 
+USB SCANNER DRIVER
+P:	Henning Meier-Geinitz
+M:	henning@meier-geinitz.de
+L:	linux-usb-users@lists.sourceforge.net
+L:	linux-usb-devel@lists.sourceforge.net
+W:	http://www.meier-geinitz.de/kernel/
+S:	Maintained
+
 USB SE401 DRIVER
 P:	Jeroen Vreeken
 M:	pe1rxq@amsat.org
diff -urN linux-2.4.21-pre3/Makefile linux-2.4.21-pre4/Makefile
--- linux-2.4.21-pre3/Makefile	Tue Jan 28 19:44:23 2003
+++ linux-2.4.21-pre4/Makefile	Tue Jan 28 19:44:28 2003
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 21
-EXTRAVERSION = -pre3
+EXTRAVERSION = -pre4
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -urN linux-2.4.21-pre3/arch/alpha/config.in linux-2.4.21-pre4/arch/alpha/config.in
--- linux-2.4.21-pre3/arch/alpha/config.in	Thu Nov 28 15:53:08 2002
+++ linux-2.4.21-pre4/arch/alpha/config.in	Tue Jan 28 19:44:28 2003
@@ -42,6 +42,7 @@
 	 Eiger			CONFIG_ALPHA_EIGER		\
 	 Jensen			CONFIG_ALPHA_JENSEN		\
 	 LX164			CONFIG_ALPHA_LX164		\
+	 Marvel			CONFIG_ALPHA_MARVEL		\
 	 Miata			CONFIG_ALPHA_MIATA		\
 	 Mikasa			CONFIG_ALPHA_MIKASA		\
 	 Nautilus		CONFIG_ALPHA_NAUTILUS		\
@@ -181,6 +182,12 @@
 	define_bool CONFIG_ALPHA_EV6 y
 	define_bool CONFIG_ALPHA_EV67 y
 fi
+if [ "$CONFIG_ALPHA_MARVEL" = "y" ]
+then
+	define_bool CONFIG_ALPHA_EV6 y
+	define_bool CONFIG_ALPHA_EV67 y
+	define_bool CONFIG_ALPHA_EV7 y
+fi
 if [ "$CONFIG_ALPHA_RAWHIDE" = "y" ]
 then
 	define_bool CONFIG_ALPHA_EV5 y
@@ -208,7 +215,8 @@
 	-o "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_NORITAKE" = "y" \
 	-o "$CONFIG_ALPHA_DP264" = "y" -o "$CONFIG_ALPHA_RAWHIDE" = "y" \
 	-o "$CONFIG_ALPHA_EIGER" = "y" -o "$CONFIG_ALPHA_WILDFIRE" = "y" \
-	-o "$CONFIG_ALPHA_TITAN" = "y" -o "$CONFIG_ALPHA_SHARK" = "y" ]
+	-o "$CONFIG_ALPHA_TITAN" = "y" -o "$CONFIG_ALPHA_SHARK" = "y" \
+	-o "$CONFIG_ALPHA_MARVEL" = "y" ]
 then
 	define_bool CONFIG_ALPHA_SRM y
 fi
@@ -222,6 +230,8 @@
   bool 'Use SRM as bootloader' CONFIG_ALPHA_SRM
 fi
 
+bool 'Verbose Machine Checks' CONFIG_VERBOSE_MCHECK
+
 if [ "$CONFIG_ALPHA_ALCOR" = "y" -o "$CONFIG_ALPHA_MIKASA" = "y" \
 	-o "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_NORITAKE" = "y" \
 	-o "$CONFIG_ALPHA_RAWHIDE" = "y" ]
@@ -240,7 +250,7 @@
 if [ "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_RAWHIDE" = "y" \
 	-o "$CONFIG_ALPHA_DP264" = "y" -o "$CONFIG_ALPHA_WILDFIRE" = "y" \
 	-o "$CONFIG_ALPHA_TITAN" = "y" -o "$CONFIG_ALPHA_GENERIC" = "y" \
-	-o "$CONFIG_ALPHA_SHARK" = "y" ]
+	-o "$CONFIG_ALPHA_SHARK" = "y" -o "$CONFIG_ALPHA_MARVEL" = "y" ]
 then
 	bool 'Symmetric multi-processing support' CONFIG_SMP
 fi
@@ -249,6 +259,10 @@
    define_bool CONFIG_HAVE_DEC_LOCK y
 fi
 
+if [ "$CONFIG_ALPHA_GENERIC" = "y" -o "$CONFIG_ALPHA_SRM" = "y" ]; then
+	define_bool CONFIG_EARLY_PRINTK y
+fi
+
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
    bool 'Discontiguous Memory Support (EXPERIMENTAL)' CONFIG_DISCONTIGMEM
    if [ "$CONFIG_DISCONTIGMEM" = "y" ]; then
@@ -311,6 +325,7 @@
 tristate 'ATA/IDE/MFM/RLL support' CONFIG_IDE
 
 if [ "$CONFIG_IDE" != "n" ]; then
+  int '  Maximum IDE interfaces' MAX_HWIFS 4
   source drivers/ide/Config.in
 else
   define_bool CONFIG_BLK_DEV_IDE_MODES n
@@ -330,6 +345,7 @@
 
 if [ "$CONFIG_PCI" = "y" ]; then
   source drivers/message/fusion/Config.in
+  source drivers/ieee1394/Config.in
 fi
 
 if [ "$CONFIG_NET" = "y" ]; then
diff -urN linux-2.4.21-pre3/arch/alpha/defconfig linux-2.4.21-pre4/arch/alpha/defconfig
--- linux-2.4.21-pre3/arch/alpha/defconfig	Mon Nov 19 15:19:42 2001
+++ linux-2.4.21-pre4/arch/alpha/defconfig	Tue Jan 28 19:44:28 2003
@@ -51,6 +51,7 @@
 # CONFIG_ALPHA_TAKARA is not set
 # CONFIG_ALPHA_TITAN is not set
 # CONFIG_ALPHA_WILDFIRE is not set
+CONFIG_VERBOSE_MCHECK=y
 CONFIG_ISA=y
 CONFIG_EISA=y
 # CONFIG_SBUS is not set
diff -urN linux-2.4.21-pre3/arch/alpha/kernel/Makefile linux-2.4.21-pre4/arch/alpha/kernel/Makefile
--- linux-2.4.21-pre3/arch/alpha/kernel/Makefile	Sun Aug 12 10:51:41 2001
+++ linux-2.4.21-pre4/arch/alpha/kernel/Makefile	Tue Jan 28 19:44:28 2003
@@ -17,7 +17,8 @@
 export-objs := alpha_ksyms.o
 
 obj-y    := entry.o traps.o process.o osf_sys.o irq.o irq_alpha.o \
-	    signal.o setup.o ptrace.o time.o semaphore.o alpha_ksyms.o
+	    signal.o setup.o ptrace.o time.o semaphore.o alpha_ksyms.o \
+	    err_common.o
 
 #
 # FIXME!
@@ -38,20 +39,27 @@
 
 obj-y 	 += core_apecs.o core_cia.o core_irongate.o core_lca.o core_mcpcia.o \
 	    core_polaris.o core_t2.o core_tsunami.o core_titan.o \
+	    core_wildfire.o core_marvel.o \
 	    sys_alcor.o sys_cabriolet.o sys_dp264.o sys_eb64p.o sys_eiger.o \
 	    sys_jensen.o sys_miata.o sys_mikasa.o sys_nautilus.o sys_titan.o \
 	    sys_noritake.o sys_rawhide.o sys_ruffian.o sys_rx164.o \
 	    sys_sable.o sys_sio.o sys_sx164.o sys_takara.o sys_rx164.o \
-	    sys_wildfire.o core_wildfire.o irq_pyxis.o
+	    sys_wildfire.o sys_marvel.o \
+	    err_titan.o err_marvel.o \
+	    irq_pyxis.o srmcons.o gct.o
 
 else
 
+# Misc support
+obj-$(CONFIG_ALPHA_SRM) += srmcons.o gct.o
+
 # Core logic support
 obj-$(CONFIG_ALPHA_APECS) += core_apecs.o
 obj-$(CONFIG_ALPHA_CIA) += core_cia.o
 
 obj-$(CONFIG_ALPHA_IRONGATE) += core_irongate.o
 obj-$(CONFIG_ALPHA_LCA) += core_lca.o
+obj-$(CONFIG_ALPHA_MARVEL) += core_marvel.o
 obj-$(CONFIG_ALPHA_MCPCIA) += core_mcpcia.o
 obj-$(CONFIG_ALPHA_T2) += core_t2.o
 obj-$(CONFIG_ALPHA_TSUNAMI) += core_tsunami.o
@@ -69,7 +77,7 @@
 
 obj-$(CONFIG_ALPHA_DP264) += sys_dp264.o
 obj-$(CONFIG_ALPHA_SHARK) += sys_dp264.o
-obj-$(CONFIG_ALPHA_TITAN) += sys_titan.o
+obj-$(CONFIG_ALPHA_TITAN) += sys_titan.o err_titan.o
 
 ifneq ($(CONFIG_ALPHA_EB64P)$(CONFIG_ALPHA_EB66),)
 obj-y    += sys_eb64p.o
@@ -77,6 +85,7 @@
 
 obj-$(CONFIG_ALPHA_EIGER) += sys_eiger.o
 obj-$(CONFIG_ALPHA_JENSEN) += sys_jensen.o pci-noop.o
+obj-$(CONFIG_ALPHA_MARVEL) += sys_marvel.o err_marvel.o
 obj-$(CONFIG_ALPHA_MIATA) += sys_miata.o
 obj-$(CONFIG_ALPHA_MIKASA) += sys_mikasa.o
 obj-$(CONFIG_ALPHA_NAUTILUS) += sys_nautilus.o
diff -urN linux-2.4.21-pre3/arch/alpha/kernel/alpha_ksyms.c linux-2.4.21-pre4/arch/alpha/kernel/alpha_ksyms.c
--- linux-2.4.21-pre3/arch/alpha/kernel/alpha_ksyms.c	Fri Aug  2 17:39:42 2002
+++ linux-2.4.21-pre4/arch/alpha/kernel/alpha_ksyms.c	Tue Jan 28 19:44:28 2003
@@ -37,6 +37,8 @@
 
 extern struct hwrpb_struct *hwrpb;
 extern void dump_thread(struct pt_regs *, struct user *);
+extern void dump_elf_thread(elf_gregset_t dest, struct pt_regs *pt,
+			    struct task_struct *task);
 extern int dump_fpu(struct pt_regs *, elf_fpregset_t *);
 extern spinlock_t kernel_flag;
 extern spinlock_t rtc_lock;
@@ -142,6 +144,7 @@
 #endif
 
 EXPORT_SYMBOL(dump_thread);
+EXPORT_SYMBOL(dump_elf_thread);
 EXPORT_SYMBOL(dump_fpu);
 EXPORT_SYMBOL(hwrpb);
 EXPORT_SYMBOL(wrusp);
@@ -237,6 +240,13 @@
 EXPORT_SYMBOL(cpu_present_mask);
 #endif /* CONFIG_SMP */
 
+/*
+ * NUMA specific symbols
+ */
+#ifdef CONFIG_DISCONTIGMEM
+EXPORT_SYMBOL(plat_node_data);
+#endif /* CONFIG_DISCONTIGMEM */
+
 EXPORT_SYMBOL(rtc_lock);
 
 /*
@@ -266,3 +276,11 @@
 EXPORT_SYMBOL(irongate_ioremap);
 EXPORT_SYMBOL(irongate_iounmap);
 #endif
+#ifdef CONFIG_ALPHA_TITAN
+EXPORT_SYMBOL(titan_ioremap);
+EXPORT_SYMBOL(titan_iounmap);
+#endif
+#ifdef CONFIG_ALPHA_MARVEL
+EXPORT_SYMBOL(marvel_ioremap);
+EXPORT_SYMBOL(marvel_iounmap);
+#endif
diff -urN linux-2.4.21-pre3/arch/alpha/kernel/core_cia.c linux-2.4.21-pre4/arch/alpha/kernel/core_cia.c
--- linux-2.4.21-pre3/arch/alpha/kernel/core_cia.c	Tue Jan 28 19:44:23 2003
+++ linux-2.4.21-pre4/arch/alpha/kernel/core_cia.c	Tue Jan 28 19:44:28 2003
@@ -47,6 +47,15 @@
 
 #define vip	volatile int  *
 
+/* Save CIA configuration data as the console had it set up.  */
+
+struct 
+{
+	unsigned int w_base;
+	unsigned int w_mask;
+	unsigned int t_base;
+} saved_config[4] __attribute((common));
+
 /*
  * Given a bus, device, and function number, compute resulting
  * configuration space address.  It is therefore not safe to have
@@ -680,13 +689,31 @@
 		hose->dense_io_base = CIA_BW_IO - IDENT_ADDR;
 	}
 
+	/* Save CIA configuration data as the console had it set up.  */
+
+	saved_config[0].w_base = *(vip)CIA_IOC_PCI_W0_BASE;
+	saved_config[0].w_mask = *(vip)CIA_IOC_PCI_W0_MASK;
+	saved_config[0].t_base = *(vip)CIA_IOC_PCI_T0_BASE;
+
+	saved_config[1].w_base = *(vip)CIA_IOC_PCI_W1_BASE;
+	saved_config[1].w_mask = *(vip)CIA_IOC_PCI_W1_MASK;
+	saved_config[1].t_base = *(vip)CIA_IOC_PCI_T1_BASE;
+
+	saved_config[2].w_base = *(vip)CIA_IOC_PCI_W2_BASE;
+	saved_config[2].w_mask = *(vip)CIA_IOC_PCI_W2_MASK;
+	saved_config[2].t_base = *(vip)CIA_IOC_PCI_T2_BASE;
+
+	saved_config[3].w_base = *(vip)CIA_IOC_PCI_W3_BASE;
+	saved_config[3].w_mask = *(vip)CIA_IOC_PCI_W3_MASK;
+	saved_config[3].t_base = *(vip)CIA_IOC_PCI_T3_BASE;
+
 	/*
 	 * Set up the PCI to main memory translation windows.
 	 *
-	 * Window 0 is scatter-gather 8MB at 8MB (for isa)
-	 * Window 1 is scatter-gather 1MB at 768MB (for tbia)
+	 * Window 0 is S/G 8MB at 8MB (for isa)
+	 * Window 1 is S/G 1MB at 768MB (for tbia) (unused for CIA rev 1)
 	 * Window 2 is direct access 2GB at 2GB
-	 * Window 3 is DAC access 4GB at 8GB
+	 * Window 3 is DAC access 4GB at 8GB (or S/G for tbia if CIA rev 1)
 	 *
 	 * ??? NetBSD hints that page tables must be aligned to 32K,
 	 * possibly due to a hardware bug.  This is over-aligned
@@ -696,6 +723,7 @@
 
 	hose->sg_pci = NULL;
 	hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 32768);
+
 	__direct_map_base = 0x80000000;
 	__direct_map_size = 0x80000000;
 
@@ -727,7 +755,7 @@
 	} else if (cia_rev == 1) {
 		*(vip)CIA_IOC_PCI_W1_BASE = 0;
 		tbia_window = 3;
-	} else if (max_low_pfn > (0x100000000 >> PAGE_SHIFT)) {
+	} else if (max_low_pfn > (0x100000000UL >> PAGE_SHIFT)) {
 		*(vip)CIA_IOC_PCI_W3_BASE = 0;
 	} else {
 		*(vip)CIA_IOC_PCI_W3_BASE = 0x00000000 | 1 | 8;
@@ -773,6 +801,26 @@
 	do_init_arch(1);
 }
 
+void
+cia_kill_arch(int mode)
+{
+	*(vip)CIA_IOC_PCI_W0_BASE = saved_config[0].w_base;
+	*(vip)CIA_IOC_PCI_W0_MASK = saved_config[0].w_mask;
+	*(vip)CIA_IOC_PCI_T0_BASE = saved_config[0].t_base;
+
+	*(vip)CIA_IOC_PCI_W1_BASE = saved_config[1].w_base;
+	*(vip)CIA_IOC_PCI_W1_MASK = saved_config[1].w_mask;
+	*(vip)CIA_IOC_PCI_T1_BASE = saved_config[1].t_base;
+
+	*(vip)CIA_IOC_PCI_W2_BASE = saved_config[2].w_base;
+	*(vip)CIA_IOC_PCI_W2_MASK = saved_config[2].w_mask;
+	*(vip)CIA_IOC_PCI_T2_BASE = saved_config[2].t_base;
+
+	*(vip)CIA_IOC_PCI_W3_BASE = saved_config[3].w_base;
+	*(vip)CIA_IOC_PCI_W3_MASK = saved_config[3].w_mask;
+	*(vip)CIA_IOC_PCI_T3_BASE = saved_config[3].t_base;
+}
+
 void __init
 cia_init_pci(void)
 {
@@ -792,6 +840,7 @@
 	*(vip)CIA_IOC_CIA_ERR;		/* re-read to force write.  */
 }
 
+#ifdef CONFIG_VERBOSE_MCHECK
 static void
 cia_decode_pci_error(struct el_CIA_sysdata_mcheck *cia, const char *msg)
 {
@@ -1059,13 +1108,13 @@
 	printk(KERN_CRIT "  Command: %s, Parity bit: %d\n", cmd, par);
 	printk(KERN_CRIT "  Address: %#010lx, Mask: %#lx\n", addr, mask);
 }
+#endif
 
 static int
 cia_decode_mchk(unsigned long la_ptr)
 {
 	struct el_common *com;
 	struct el_CIA_sysdata_mcheck *cia;
-	int which;
 
 	com = (void *)la_ptr;
 	cia = (void *)(la_ptr + com->sys_offset);
@@ -1073,8 +1122,8 @@
 	if ((cia->cia_err & CIA_ERR_VALID) == 0)
 		return 0;
 
-	which = cia->cia_err & 0xfff;
-	switch (ffs(which) - 1) {
+#ifdef CONFIG_VERBOSE_MCHECK
+	switch (ffs(cia->cia_err & 0xfff) - 1) {
 	case 0: /* CIA_ERR_COR_ERR */
 		cia_decode_ecc_error(cia, "Corrected ECC error");
 		break;
@@ -1146,6 +1195,7 @@
 	if (cia->cia_err & CIA_ERR_LOST_IOA_TIMEOUT)
 		printk(KERN_CRIT "CIA lost machine check: "
 		       "I/O timeout\n");
+#endif
 
 	return 1;
 }
diff -urN linux-2.4.21-pre3/arch/alpha/kernel/core_irongate.c linux-2.4.21-pre4/arch/alpha/kernel/core_irongate.c
--- linux-2.4.21-pre3/arch/alpha/kernel/core_irongate.c	Thu Sep 13 15:21:32 2001
+++ linux-2.4.21-pre4/arch/alpha/kernel/core_irongate.c	Tue Jan 28 19:44:28 2003
@@ -412,88 +412,9 @@
  * IO map and AGP support
  */
 #include <linux/vmalloc.h>
-#include <asm/pgalloc.h>
-
-static inline void 
-irongate_remap_area_pte(pte_t * pte, unsigned long address, unsigned long size, 
-		     unsigned long phys_addr, unsigned long flags)
-{
-	unsigned long end;
-
-	address &= ~PMD_MASK;
-	end = address + size;
-	if (end > PMD_SIZE)
-		end = PMD_SIZE;
-	if (address >= end)
-		BUG();
-	do {
-		if (!pte_none(*pte)) {
-			printk("irongate_remap_area_pte: page already exists\n");
-			BUG();
-		}
-		set_pte(pte, 
-			mk_pte_phys(phys_addr, 
-				    __pgprot(_PAGE_VALID | _PAGE_ASM | 
-					     _PAGE_KRE | _PAGE_KWE | flags)));
-		address += PAGE_SIZE;
-		phys_addr += PAGE_SIZE;
-		pte++;
-	} while (address && (address < end));
-}
-
-static inline int 
-irongate_remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size, 
-		     unsigned long phys_addr, unsigned long flags)
-{
-	unsigned long end;
-
-	address &= ~PGDIR_MASK;
-	end = address + size;
-	if (end > PGDIR_SIZE)
-		end = PGDIR_SIZE;
-	phys_addr -= address;
-	if (address >= end)
-		BUG();
-	do {
-		pte_t * pte = pte_alloc(&init_mm, pmd, address);
-		if (!pte)
-			return -ENOMEM;
-		irongate_remap_area_pte(pte, address, end - address, 
-				     address + phys_addr, flags);
-		address = (address + PMD_SIZE) & PMD_MASK;
-		pmd++;
-	} while (address && (address < end));
-	return 0;
-}
-
-static int
-irongate_remap_area_pages(unsigned long address, unsigned long phys_addr,
-		       unsigned long size, unsigned long flags)
-{
-	pgd_t * dir;
-	unsigned long end = address + size;
-
-	phys_addr -= address;
-	dir = pgd_offset(&init_mm, address);
-	flush_cache_all();
-	if (address >= end)
-		BUG();
-	do {
-		pmd_t *pmd;
-		pmd = pmd_alloc(&init_mm, dir, address);
-		if (!pmd)
-			return -ENOMEM;
-		if (irongate_remap_area_pmd(pmd, address, end - address,
-					 phys_addr + address, flags))
-			return -ENOMEM;
-		address = (address + PGDIR_SIZE) & PGDIR_MASK;
-		dir++;
-	} while (address && (address < end));
-	return 0;
-}
-
 #include <linux/agp_backend.h>
 #include <linux/agpgart.h>
+#include <asm/pgalloc.h>
 
 #define GET_PAGE_DIR_OFF(addr) (addr >> 22)
 #define GET_PAGE_DIR_IDX(addr) (GET_PAGE_DIR_OFF(addr))
@@ -580,8 +501,8 @@
 		cur_gatt = phys_to_virt(GET_GATT(baddr) & ~1);
 		pte = cur_gatt[GET_GATT_OFF(baddr)] & ~1;
 
-		if (irongate_remap_area_pages(VMALLOC_VMADDR(vaddr), 
-					   pte, PAGE_SIZE, 0)) {
+		if (__alpha_remap_area_pages(VMALLOC_VMADDR(vaddr), 
+					     pte, PAGE_SIZE, 0)) {
 			printk("AGP ioremap: FAILED to map...\n");
 			vfree(area->addr);
 			return (unsigned long)NULL;
diff -urN linux-2.4.21-pre3/arch/alpha/kernel/core_marvel.c linux-2.4.21-pre4/arch/alpha/kernel/core_marvel.c
--- linux-2.4.21-pre3/arch/alpha/kernel/core_marvel.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/arch/alpha/kernel/core_marvel.c	Tue Jan 28 19:44:28 2003
@@ -0,0 +1,1125 @@
+/*
+ *	linux/arch/alpha/kernel/core_marvel.c
+ *
+ * Code common to all Marvel based systems.
+ */
+
+#include <linux/config.h>
+
+#define __EXTERN_INLINE inline
+#include <asm/io.h>
+#include <asm/core_marvel.h>
+#undef __EXTERN_INLINE
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+#include <linux/mc146818rtc.h>
+
+#include <asm/ptrace.h>
+#include <asm/system.h>
+#include <asm/smp.h>
+#include <asm/hwrpb.h>
+#include <asm/gct.h>
+#include <asm/pgalloc.h>
+
+#include <linux/bootmem.h>
+
+#include "proto.h"
+#include "pci_impl.h"
+
+
+/*
+ * Debug helpers
+ */
+#define DEBUG_CONFIG 0
+
+#if DEBUG_CONFIG
+# define DBG_CFG(args) printk args
+#else
+# define DBG_CFG(args)
+#endif
+
+
+/*
+ * Private data
+ */
+static struct io7 *io7_head = NULL;
+
+
+/*
+ * Helper functions
+ */
+static unsigned long __attribute__ ((unused))
+read_ev7_csr(int pe, unsigned long offset)
+{
+	ev7_csr *ev7csr = EV7_CSR_KERN(pe, offset);
+	unsigned long q;
+
+	mb();
+	q = ev7csr->csr;
+	mb();
+
+	return q;
+}
+
+static void __attribute__ ((unused))
+write_ev7_csr(int pe, unsigned long offset, unsigned long q)
+{
+	ev7_csr *ev7csr = EV7_CSR_KERN(pe, offset);
+
+	mb();
+	ev7csr->csr = q;
+	mb();
+}
+
+static char * __init
+mk_resource_name(int pe, int port, char *str)
+{
+	char tmp[80];
+	char *name;
+	
+	sprintf(tmp, "PCI %s PE %d PORT %d", str, pe, port);
+	name = alloc_bootmem(strlen(tmp) + 1);
+	strcpy(name, tmp);
+
+	return name;
+}
+
+inline struct io7 *
+marvel_next_io7(struct io7 *prev)
+{
+	return (prev ? prev->next : io7_head);
+}
+
+struct io7 *
+marvel_find_io7(int pe)
+{
+	struct io7 *io7;
+
+	for (io7 = io7_head; io7 && io7->pe != pe; io7 = io7->next)
+		continue;
+
+	return io7;
+}
+
+static struct io7 * __init
+alloc_io7(unsigned int pe)
+{
+	struct io7 *io7;
+	struct io7 *insp;
+	int h;
+
+	if (marvel_find_io7(pe)) {
+		printk(KERN_WARNING "IO7 at PE %d already allocated!\n", pe);
+		return NULL;
+	}
+
+	io7 = alloc_bootmem(sizeof(*io7));
+	io7->pe = pe;
+	io7->irq_lock = SPIN_LOCK_UNLOCKED;
+
+	for (h = 0; h < 4; h++) {
+		io7->ports[h].io7 = io7;
+		io7->ports[h].port = h;
+		io7->ports[h].enabled = 0; /* default to disabled */
+	}
+
+	/*
+	 * Insert in pe sorted order.
+	 */
+	if (NULL == io7_head)			/* empty list */
+		io7_head = io7;	
+	else if (io7_head->pe > io7->pe) {	/* insert at head */
+		io7->next = io7_head;
+		io7_head = io7;
+	} else {				/* insert at position */
+		for (insp = io7_head; insp; insp = insp->next) {
+			if (insp->pe == io7->pe) {
+				printk(KERN_ERR "Too many IO7s at PE %d\n", 
+				       io7->pe);
+				return NULL;
+			}
+
+			if (NULL == insp->next || 
+			    insp->next->pe > io7->pe) { /* insert here */
+				io7->next = insp->next;
+				insp->next = io7;
+				break;
+			}
+		}
+
+		if (NULL == insp) { /* couldn't insert ?!? */
+			printk(KERN_WARNING "Failed to insert IO7 at PE %d "
+			       " - adding at head of list\n", io7->pe);
+			io7->next = io7_head;
+			io7_head = io7;
+		}
+	}
+	
+	return io7;
+}
+
+void
+io7_clear_errors(struct io7 *io7)
+{
+	io7_port7_csrs *p7csrs;
+	io7_ioport_csrs *csrs;
+	int port;
+
+
+	/*
+	 * First the IO ports.
+	 */
+	for (port = 0; port < 4; port++) {
+		csrs = IO7_CSRS_KERN(io7->pe, port);
+
+		csrs->POx_ERR_SUM.csr = -1UL;
+		csrs->POx_TLB_ERR.csr = -1UL;
+		csrs->POx_SPL_COMPLT.csr = -1UL;
+		csrs->POx_TRANS_SUM.csr = -1UL;
+	}
+
+	/*
+	 * Then the common ones.
+	 */
+	p7csrs = IO7_PORT7_CSRS_KERN(io7->pe);
+
+	p7csrs->PO7_ERROR_SUM.csr = -1UL;
+	p7csrs->PO7_UNCRR_SYM.csr = -1UL;
+	p7csrs->PO7_CRRCT_SYM.csr = -1UL;
+}
+
+
+/*
+ * IO7 PCI, PCI/X, AGP configuration.
+ */
+static void __init
+io7_init_hose(struct io7 *io7, int port)
+{
+	static int hose_index = 0;
+
+	struct pci_controller *hose = alloc_pci_controller();
+	struct io7_port *io7_port = &io7->ports[port];
+	io7_ioport_csrs *csrs = IO7_CSRS_KERN(io7->pe, port);
+	int i;
+
+	hose->index = hose_index++;	/* arbitrary */
+	
+	/*
+	 * We don't have an isa or legacy hose, but glibc expects to be
+	 * able to use the bus == 0 / dev == 0 form of the iobase syscall
+	 * to determine information about the i/o system. Since XFree86 
+	 * relies on glibc's determination to tell whether or not to use
+	 * sparse access, we need to point the pci_isa_hose at a real hose
+	 * so at least that determination is correct.
+	 */
+	if (hose->index == 0)
+		pci_isa_hose = hose;
+
+	io7_port->csrs = csrs;
+	io7_port->hose = hose;
+	hose->sysdata = io7_port;
+
+	hose->io_space = alloc_resource();
+	hose->mem_space = alloc_resource();
+
+	/*
+	 * Base addresses for userland consumption. Since these are going
+	 * to be mapped, they are pure physical addresses.
+	 */
+	hose->sparse_mem_base = hose->sparse_io_base = 0;
+	hose->dense_mem_base = IO7_MEM_PHYS(io7->pe, port);
+	hose->dense_io_base = IO7_IO_PHYS(io7->pe, port);
+
+	/*
+	 * Base addresses and resource ranges for kernel consumption.
+	 */
+	hose->config_space_base = (unsigned long)IO7_CONF_KERN(io7->pe, port);
+
+	hose->io_space->start = (unsigned long)IO7_IO_KERN(io7->pe, port);
+	hose->io_space->end = hose->io_space->start + IO7_IO_SPACE - 1;
+	hose->io_space->name = mk_resource_name(io7->pe, port, "IO");
+	hose->io_space->flags = IORESOURCE_IO;
+
+	hose->mem_space->start = (unsigned long)IO7_MEM_KERN(io7->pe, port);
+	hose->mem_space->end = hose->mem_space->start + IO7_MEM_SPACE - 1;
+	hose->mem_space->name = mk_resource_name(io7->pe, port, "MEM");
+	hose->mem_space->flags = IORESOURCE_MEM;
+
+	if (request_resource(&ioport_resource, hose->io_space) < 0)
+		printk(KERN_ERR "Failed to request IO on hose %d\n", 
+		       hose->index);
+	if (request_resource(&iomem_resource, hose->mem_space) < 0)
+		printk(KERN_ERR "Failed to request MEM on hose %d\n", 
+		       hose->index);
+
+	/*
+	 * Save the existing DMA window settings for later restoration.
+	 */
+	for (i = 0; i < 4; i++) {
+		io7_port->saved_wbase[i] = csrs->POx_WBASE[i].csr;
+		io7_port->saved_wmask[i] = csrs->POx_WMASK[i].csr;
+		io7_port->saved_tbase[i] = csrs->POx_TBASE[i].csr;
+	}
+
+	/*
+	 * Set up the PCI to main memory translation windows.
+	 *
+	 * Window 0 is scatter-gather 8MB at 8MB
+	 * Window 1 is direct access 1GB at 2GB
+	 * Window 2 is scatter-gather (up-to) 1GB at 3GB
+	 * Window 3 is disabled
+	 */
+
+	/*
+	 * TBIA before modifying windows.
+	 */
+	marvel_pci_tbi(hose, 0, -1);
+
+	/*
+	 * Set up window 0 for scatter-gather 8MB at 8MB.
+	 */
+	hose->sg_isa = iommu_arena_new_node(marvel_cpuid_to_nid(io7->pe),
+					    hose, 0x00800000, 0x00800000, 0);
+	hose->sg_isa->align_entry = 8;	/* cache line boundary */
+	csrs->POx_WBASE[0].csr = 
+		hose->sg_isa->dma_base | wbase_m_ena | wbase_m_sg;
+	csrs->POx_WMASK[0].csr = (hose->sg_isa->size - 1) & wbase_m_addr;
+	csrs->POx_TBASE[0].csr = virt_to_phys(hose->sg_isa->ptes);
+
+	/*
+	 * Set up window 1 for direct-mapped 1GB at 2GB.
+	 */
+	csrs->POx_WBASE[1].csr = __direct_map_base | wbase_m_ena;
+	csrs->POx_WMASK[1].csr = (__direct_map_size - 1) & wbase_m_addr;
+	csrs->POx_TBASE[1].csr = 0;
+
+	/*
+	 * Set up window 2 for scatter-gather (up-to) 1GB at 3GB.
+	 */
+	hose->sg_pci = iommu_arena_new_node(marvel_cpuid_to_nid(io7->pe),
+					    hose, 0xc0000000, 0x40000000, 0);
+	hose->sg_pci->align_entry = 8;	/* cache line boundary */
+	csrs->POx_WBASE[2].csr = 
+		hose->sg_pci->dma_base | wbase_m_ena | wbase_m_sg;
+	csrs->POx_WMASK[2].csr = (hose->sg_pci->size - 1) & wbase_m_addr;
+	csrs->POx_TBASE[2].csr = virt_to_phys(hose->sg_pci->ptes);
+
+	/*
+	 * Disable window 3.
+	 */
+	csrs->POx_WBASE[3].csr = 0;
+
+	/*
+	 * Make sure that the AGP Monster Window is disabled.
+	 */
+	csrs->POx_CTRL.csr &= ~(1UL << 61);
+
+#if 1
+	printk("FIXME: disabling master aborts\n");
+	csrs->POx_MSK_HEI.csr &= ~(3UL << 14);
+#endif
+	/*
+	 * TBIA after modifying windows.
+	 */
+	marvel_pci_tbi(hose, 0, -1);
+}
+
+static void __init
+marvel_init_io7(struct io7 *io7)
+{
+	int i;
+
+	printk("Initializing IO7 at PID %d\n", io7->pe);
+
+	/*
+	 * Get the Port 7 CSR pointer.
+	 */
+	io7->csrs = IO7_PORT7_CSRS_KERN(io7->pe);
+
+	/*
+	 * Init this IO7's hoses.
+	 */
+	for (i = 0; i < IO7_NUM_PORTS; i++) {
+		io7_ioport_csrs *csrs = IO7_CSRS_KERN(io7->pe, i);
+		if (csrs->POx_CACHE_CTL.csr == 8) {
+			io7->ports[i].enabled = 1;
+			io7_init_hose(io7, i);
+		}
+	}
+}
+
+void
+marvel_io7_present(gct6_node *node)
+{
+	int pe;
+
+	if (node->type != GCT_TYPE_HOSE ||
+	    node->subtype != GCT_SUBTYPE_IO_PORT_MODULE) 
+		return;
+
+	pe = (node->id >> 8) & 0xff;
+	printk("Found an IO7 at PID %d\n", pe);
+
+	alloc_io7(pe);
+}
+
+static void __init
+marvel_init_vga_hose(void)
+{
+#ifdef CONFIG_VGA_HOSE
+	u64 *pu64 = (u64 *)((u64)hwrpb + hwrpb->ctbt_offset);
+
+	if (pu64[7] == 3) {	/* TERM_TYPE == graphics */
+		struct pci_controller *hose = NULL;
+		int h = (pu64[30] >> 24) & 0xff; /* TERM_OUT_LOC, hose # */
+		struct io7 *io7;
+		int pid, port;
+
+		/* FIXME - encoding is going to have to change for Marvel
+		 *         since hose will be able to overflow a byte...
+		 *         need to fix this decode when the console 
+		 *         changes its encoding
+		 */
+		printk("console graphics is on hose %d (console)\n", h);
+
+		/*
+		 * The console's hose numbering is:
+		 *
+		 *	hose<n:2>: PID
+		 *	hose<1:0>: PORT
+		 *
+		 * We need to find the hose at that pid and port
+		 */
+		pid = h >> 2;
+		port = h & 3;
+		if ((io7 = marvel_find_io7(pid)))
+			hose = io7->ports[port].hose;
+
+		if (hose) {
+			printk("Console graphics on hose %d\n", hose->index);
+			pci_vga_hose = hose;
+		}
+	}
+#endif /* CONFIG_VGA_HOSE */
+}
+
+gct6_search_struct gct_wanted_node_list[] = {
+	{ GCT_TYPE_HOSE, GCT_SUBTYPE_IO_PORT_MODULE, marvel_io7_present },
+	{ 0, 0, NULL }
+};
+
+/*
+ * In case the GCT is not complete, let the user specify PIDs with IO7s
+ * at boot time. Syntax is 'io7=a,b,c,...,n' where a-n are the PIDs (decimal)
+ * where IO7s are connected
+ */
+static int __init
+marvel_specify_io7(char *str)
+{
+	unsigned long pid;
+	struct io7 *io7;
+	char *pchar;
+
+	do {
+		pid = simple_strtoul(str, &pchar, 0);
+		if (pchar != str) {
+			printk("User-specified IO7 at PID %lu\n", pid);
+			io7 = alloc_io7(pid);
+			if (io7) marvel_init_io7(io7);
+		}
+
+		if (pchar == str) pchar++;
+		str = pchar;
+	} while(*str);
+
+	return 0;
+}
+__setup("io7=", marvel_specify_io7);
+
+void __init
+marvel_init_arch(void)
+{
+	struct io7 *io7;
+
+	/* With multiple PCI busses, we play with I/O as physical addrs.  */
+	ioport_resource.end = ~0UL;
+	iomem_resource.end = ~0UL;
+
+	/* PCI DMA Direct Mapping is 1GB at 2GB.  */
+	__direct_map_base = 0x80000000;
+	__direct_map_size = 0x40000000;
+
+	/* Parse the config tree.  */
+	gct6_find_nodes(GCT_NODE_PTR(0), gct_wanted_node_list);
+
+	/* Init the io7s.  */
+	for (io7 = NULL; NULL != (io7 = marvel_next_io7(io7)); ) 
+		marvel_init_io7(io7);
+
+	/* Check for graphic console location (if any).  */
+	marvel_init_vga_hose();
+}
+
+void
+marvel_kill_arch(int mode)
+{
+}
+
+
+/*
+ * PCI Configuration Space access functions
+ *
+ * Configuration space addresses have the following format:
+ *
+ * 	|2 2 2 2|1 1 1 1|1 1 1 1|1 1 
+ * 	|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
+ * 	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * 	|B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|R|R|
+ * 	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ *	 n:24	reserved for hose base
+ *	23:16	bus number (8 bits = 128 possible buses)
+ *	15:11	Device number (5 bits)
+ *	10:8	function number
+ *	 7:2	register number
+ *  
+ * Notes:
+ *	IO7 determines whether to use a type 0 or type 1 config cycle
+ *	based on the bus number. Therefore the bus number must be set 
+ *	to 0 for the root bus on any hose.
+ *	
+ *	The function number selects which function of a multi-function device 
+ *	(e.g., SCSI and Ethernet).
+ * 
+ */
+
+static inline unsigned long
+build_conf_addr(struct pci_controller *hose, u8 bus, 
+		unsigned int devfn, int where)
+{
+	return (hose->config_space_base | (bus << 16) | (devfn << 8) | where);
+}
+
+static unsigned long
+mk_conf_addr(struct pci_dev *dev, int where)
+{
+	struct pci_controller *hose = dev->sysdata;
+	unsigned long addr = 0;
+	struct io7_port *io7_port;
+	u8 bus;
+
+	if (!hose)
+		return addr;
+	
+	/* Check for enabled.  */
+	io7_port = hose->sysdata;
+	if (!io7_port->enabled)
+		return addr;
+
+	bus = dev->bus->number;
+
+	if (hose->first_busno == bus) {
+		/* Don't support idsel > 20 on primary bus.  */
+		if (dev->devfn >= PCI_DEVFN(21, 0))
+			return addr;
+		bus = 0;
+	}
+
+	addr = build_conf_addr(hose, bus, dev->devfn, where);
+
+	DBG_CFG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
+	return addr;
+}
+
+static int
+marvel_read_config_byte(struct pci_dev *dev, int where, u8 *value)
+{
+	unsigned long addr;
+	
+	if (0 == (addr = mk_conf_addr(dev, where)))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	*value = __kernel_ldbu(*(vucp)addr);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+marvel_read_config_word(struct pci_dev *dev, int where, u16 *value)
+{
+	unsigned long addr;
+	
+	if (0 == (addr = mk_conf_addr(dev, where)))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	*value = __kernel_ldwu(*(vusp)addr);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+marvel_read_config_dword(struct pci_dev *dev, int where, u32 *value)
+{
+	unsigned long addr;
+	
+	if (0 == (addr = mk_conf_addr(dev, where)))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	*value = *(vuip)addr;
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+marvel_write_config_byte(struct pci_dev *dev, int where, u8 value)
+{
+	unsigned long addr;
+	
+	if (0 == (addr = mk_conf_addr(dev, where)))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	__kernel_stb(value, *(vucp)addr);
+	mb();
+	__kernel_ldbu(*(vucp)addr);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+marvel_write_config_word(struct pci_dev *dev, int where, u16 value)
+{
+	unsigned long addr;
+	
+	if (0 == (addr = mk_conf_addr(dev, where)))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	__kernel_stw(value, *(vusp)addr);
+	mb();
+	__kernel_ldwu(*(vusp)addr);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+marvel_write_config_dword(struct pci_dev *dev, int where, u32 value)
+{
+	unsigned long addr;
+	
+	if (0 == (addr = mk_conf_addr(dev, where)))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	*(vuip)addr = value;
+	mb();
+	*(vuip)addr;
+	return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops marvel_pci_ops =
+{
+	read_byte:	marvel_read_config_byte,
+	read_word:	marvel_read_config_word,
+	read_dword:	marvel_read_config_dword,
+	write_byte:	marvel_write_config_byte,
+	write_word:	marvel_write_config_word,
+	write_dword:	marvel_write_config_dword
+};
+
+
+/*
+ * Other PCI helper functions.
+ */
+void
+marvel_pci_tbi(struct pci_controller *hose, dma_addr_t start, dma_addr_t end)
+{
+	io7_ioport_csrs *csrs = ((struct io7_port *)hose->sysdata)->csrs;
+
+	wmb();
+	csrs->POx_SG_TBIA.csr = 0;
+	mb();
+	csrs->POx_SG_TBIA.csr;
+}
+
+
+/*
+ * IO map support.
+ */
+unsigned long
+marvel_ioremap(unsigned long addr, unsigned long size)
+{
+	struct pci_controller *hose;
+	unsigned long baddr, last;
+	struct vm_struct *area;
+	unsigned long vaddr;
+	unsigned long *ptes;
+	unsigned long pfn;
+
+	/*
+	 * Adjust the addr.
+	 */ 
+#ifdef CONFIG_VGA_HOSE
+	if (pci_vga_hose && __marvel_is_mem_vga(addr)) {
+		addr += pci_vga_hose->mem_space->start;
+	}
+#endif
+
+	if (!marvel_is_ioaddr(addr))
+		return 0UL;
+
+	/*
+	 * Find the hose.
+	 */
+	for (hose = hose_head; hose; hose = hose->next) {
+		if ((addr >> 32) == (hose->mem_space->start >> 32))
+			break;
+	}
+	if (!hose)
+		return 0UL;
+
+	/*
+	 * We have the hose - calculate the bus limits.
+	 */
+	baddr = addr - hose->mem_space->start;
+	last = baddr + size - 1;
+
+	/*
+	 * Is it direct-mapped?
+	 */
+	if ((baddr >= __direct_map_base) && 
+	    ((baddr + size - 1) < __direct_map_base + __direct_map_size)) 
+		return IDENT_ADDR | (baddr - __direct_map_base);
+
+	/* 
+	 * Check the scatter-gather arena.
+	 */
+	if (hose->sg_pci &&
+	    baddr >= (unsigned long)hose->sg_pci->dma_base &&
+	    last < (unsigned long)hose->sg_pci->dma_base + hose->sg_pci->size){
+
+		/*
+		 * Adjust the limits (mappings must be page aligned)
+		 */
+		baddr -= hose->sg_pci->dma_base;
+		last -= hose->sg_pci->dma_base;
+		baddr &= PAGE_MASK;
+		size = PAGE_ALIGN(last) - baddr;
+
+		/*
+		 * Map it.
+		 */
+		area = get_vm_area(size, VM_IOREMAP);
+		if (!area) return (unsigned long)NULL;
+		ptes = hose->sg_pci->ptes;
+		for (vaddr = (unsigned long)area->addr; 
+		    baddr <= last; 
+		    baddr += PAGE_SIZE, vaddr += PAGE_SIZE) {
+			pfn = ptes[baddr >> PAGE_SHIFT];
+			if (!(pfn & 1)) {
+				printk("ioremap failed... pte not valid...\n");
+				vfree(area->addr);
+				return 0UL;
+			}
+			pfn >>= 1;	/* make it a true pfn */
+			
+			if (__alpha_remap_area_pages(VMALLOC_VMADDR(vaddr), 
+						     pfn << PAGE_SHIFT, 
+						     PAGE_SIZE, 0)) {
+				printk("FAILED to map...\n");
+				vfree(area->addr);
+				return 0UL;
+			}
+		}
+
+		flush_tlb_all();
+
+		vaddr = (unsigned long)area->addr + (addr & ~PAGE_MASK);
+
+		return vaddr;
+	}
+
+	/*
+	 * Not found - assume legacy ioremap.
+	 */
+	return addr;
+}
+
+void
+marvel_iounmap(unsigned long addr)
+{
+	if (((long)addr >> 41) == -2)
+		return;	/* kseg map, nothing to do */
+	if (addr)
+		return vfree((void *)(PAGE_MASK & addr)); 
+}
+
+
+/*
+ * RTC Support
+ */
+struct marvel_rtc_access_info {
+	unsigned long function;
+	unsigned long index;
+	unsigned long data;
+};
+
+static void
+__marvel_access_rtc(void *info)
+{
+	struct marvel_rtc_access_info *rtc_access = info;
+
+	register unsigned long __r0 __asm__("$0");
+	register unsigned long __r16 __asm__("$16") = rtc_access->function;
+	register unsigned long __r17 __asm__("$17") = rtc_access->index;
+	register unsigned long __r18 __asm__("$18") = rtc_access->data;
+	
+	__asm__ __volatile__(
+		"call_pal %4 # cserve rtc"
+		: "=r"(__r16), "=r"(__r17), "=r"(__r18), "=r"(__r0)
+		: "i"(PAL_cserve), "0"(__r16), "1"(__r17), "2"(__r18)
+		: "$1", "$22", "$23", "$24", "$25");
+
+	rtc_access->data = __r0;
+}
+
+u8
+__marvel_rtc_io(int write, u8 b, unsigned long addr)
+{
+	struct marvel_rtc_access_info rtc_access = {0, };
+	static u8 index = 0;
+	u8 ret = 0;
+
+	switch(addr) {
+	case 0x70:					/* RTC_PORT(0) */
+		if (write) index = b;
+		ret = index;
+		break;
+
+	case 0x71:					/* RTC_PORT(1) */
+		rtc_access.index = index;
+		rtc_access.data = BCD_TO_BIN(b);
+		rtc_access.function = 0x49;		/* GET_TOY */
+		if (write) rtc_access.function = 0x48;	/* PUT_TOY */
+
+#if CONFIG_SMP
+		if (smp_processor_id() != boot_cpuid)
+			smp_call_function_on_cpu(__marvel_access_rtc,
+						 &rtc_access,
+						 1,	/* retry */
+						 1,	/* wait  */
+						 1UL << boot_cpuid);
+		else
+			__marvel_access_rtc(&rtc_access);
+#else
+		__marvel_access_rtc(&rtc_access);
+#endif
+		ret = BIN_TO_BCD(rtc_access.data);
+		
+		break;
+
+	default:
+		printk(KERN_WARNING "Illegal RTC port %lx\n", addr);
+		break;
+	}
+
+	return ret;
+}
+
+
+/*
+ * NUMA Support
+ */
+/**********
+ * FIXME - for now each cpu is a node by itself 
+ *              -- no real support for striped mode 
+ **********
+ */
+int
+marvel_pa_to_nid(unsigned long pa)
+{
+	int cpuid;
+
+	if ((pa >> 43) & 1) 	/* I/O */ 
+		cpuid = (~(pa >> 35) & 0xff);
+	else			/* mem */
+		cpuid = ((pa >> 34) & 0x3) | ((pa >> (37 - 2)) & (0x1f << 2));
+
+	return marvel_cpuid_to_nid(cpuid);
+}
+
+int
+marvel_cpuid_to_nid(int cpuid)
+{
+	return cpuid;
+}
+
+unsigned long
+marvel_node_mem_start(int nid)
+{
+	unsigned long pa;
+
+	pa = (nid & 0x3) | ((nid & (0x1f << 2)) << 1);
+	pa <<= 34;
+
+	return pa;
+}
+
+unsigned long
+marvel_node_mem_size(int nid)
+{
+	return 16UL * 1024 * 1024 * 1024; /* 16GB */
+}
+
+
+/* 
+ * AGP GART Support.
+ */
+#include <linux/agp_backend.h>
+#include <asm/agp_backend.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+struct marvel_agp_aperture {
+	struct pci_iommu_arena *arena;
+	long pg_start;
+	long pg_count;
+};
+
+static int
+marvel_agp_setup(alpha_agp_info *agp)
+{
+	struct marvel_agp_aperture *aper;
+
+	if (!alpha_agpgart_size)
+		return -ENOMEM;
+
+	aper = kmalloc(sizeof(*aper), GFP_KERNEL);
+	if (aper == NULL) return -ENOMEM;
+
+	aper->arena = agp->hose->sg_pci;
+	aper->pg_count = alpha_agpgart_size / PAGE_SIZE;
+	aper->pg_start = iommu_reserve(aper->arena, aper->pg_count,
+				       aper->pg_count - 1);
+
+	if (aper->pg_start < 0) {
+		printk(KERN_ERR "Failed to reserve AGP memory\n");
+		kfree(aper);
+		return -ENOMEM;
+	}
+
+	agp->aperture.bus_base = 
+		aper->arena->dma_base + aper->pg_start * PAGE_SIZE;
+	agp->aperture.size = aper->pg_count * PAGE_SIZE;
+	agp->aperture.sysdata = aper;
+
+	return 0;
+}
+
+static void
+marvel_agp_cleanup(alpha_agp_info *agp)
+{
+	struct marvel_agp_aperture *aper = agp->aperture.sysdata;
+	int status;
+
+	status = iommu_release(aper->arena, aper->pg_start, aper->pg_count);
+	if (status == -EBUSY) {
+		printk(KERN_WARNING
+		       "Attempted to release bound AGP memory - unbinding\n");
+		iommu_unbind(aper->arena, aper->pg_start, aper->pg_count);
+		status = iommu_release(aper->arena, aper->pg_start, 
+				       aper->pg_count);
+	}
+	if (status < 0)
+		printk(KERN_ERR "Failed to release AGP memory\n");
+
+	kfree(aper);
+	kfree(agp);
+}
+
+static int
+marvel_agp_configure(alpha_agp_info *agp)
+{
+	io7_ioport_csrs *csrs = ((struct io7_port *)agp->hose->sysdata)->csrs;
+	struct io7 *io7 = ((struct io7_port *)agp->hose->sysdata)->io7;
+	unsigned int new_rate = 0;
+	unsigned long agp_pll;
+
+	/*
+	 * Check the requested mode against the PLL setting.
+	 * The agpgart_be code has not programmed the card yet,
+	 * so we can still tweak mode here.
+	 */
+	agp_pll = io7->csrs->POx_RST[IO7_AGP_PORT].csr;
+	switch(IO7_PLL_RNGB(agp_pll)) {
+	case 0x4:				/* 2x only */
+		/* 
+		 * The PLL is only programmed for 2x, so adjust the
+		 * rate to 2x, if necessary.
+		 */
+		if (agp->mode.bits.rate != 2) 
+			new_rate = 2;
+		break;
+
+	case 0x6:				/* 1x / 4x */
+		/*
+		 * The PLL is programmed for 1x or 4x.  Don't go faster
+		 * than requested, so if the requested rate is 2x, use 1x.
+		 */
+		if (agp->mode.bits.rate == 2) 
+			new_rate = 1;
+		break;
+
+	default:				/* ??????? */
+		/*
+		 * Don't know what this PLL setting is, take the requested
+		 * rate, but warn the user.
+		 */
+		printk("%s: unknown PLL setting RNGB=%lx (PLL6_CTL=%016lx)\n",
+		       __FUNCTION__, IO7_PLL_RNGB(agp_pll), agp_pll);
+		break;
+	}
+
+	/*
+	 * Set the new rate, if necessary.
+	 */
+	if (new_rate) {
+		printk("Requested AGP Rate %dX not compatible "
+		       "with PLL setting - using %dX\n",
+		       agp->mode.bits.rate,
+		       new_rate);
+
+		agp->mode.bits.rate = new_rate;
+	}
+		
+	printk("Enabling AGP on hose %d: %dX%s RQ %d\n", 
+	       agp->hose->index, agp->mode.bits.rate, 
+	       agp->mode.bits.sba ? " - SBA" : "", agp->mode.bits.rq);
+
+	csrs->AGP_CMD.csr = agp->mode.lw;
+
+	return 0;
+}
+
+static int 
+marvel_agp_bind_memory(alpha_agp_info *agp, off_t pg_start, agp_memory *mem)
+{
+	struct marvel_agp_aperture *aper = agp->aperture.sysdata;
+	return iommu_bind(aper->arena, aper->pg_start + pg_start, 
+			  mem->page_count, mem->memory);
+}
+
+static int 
+marvel_agp_unbind_memory(alpha_agp_info *agp, off_t pg_start, agp_memory *mem)
+{
+	struct marvel_agp_aperture *aper = agp->aperture.sysdata;
+	return iommu_unbind(aper->arena, aper->pg_start + pg_start,
+			    mem->page_count);
+}
+
+static unsigned long
+marvel_agp_translate(alpha_agp_info *agp, dma_addr_t addr)
+{
+	struct marvel_agp_aperture *aper = agp->aperture.sysdata;
+	unsigned long baddr = addr - aper->arena->dma_base;
+	unsigned long pte;
+
+	if (addr < agp->aperture.bus_base ||
+	    addr >= agp->aperture.bus_base + agp->aperture.size) {
+		printk("%s: addr out of range\n", __FUNCTION__);
+		return -EINVAL;
+	}
+
+	pte = aper->arena->ptes[baddr >> PAGE_SHIFT];
+	if (!(pte & 1)) {
+		printk("%s: pte not valid\n", __FUNCTION__);
+		return -EINVAL;
+	} 
+	return (pte >> 1) << PAGE_SHIFT;
+}
+
+struct alpha_agp_ops marvel_agp_ops =
+{
+	setup:		marvel_agp_setup,
+	cleanup:	marvel_agp_cleanup,
+	configure:	marvel_agp_configure,
+	bind:		marvel_agp_bind_memory,
+	unbind:		marvel_agp_unbind_memory,
+	translate:	marvel_agp_translate
+};
+
+alpha_agp_info *
+marvel_agp_info(void)
+{
+	struct pci_controller *hose;
+	io7_ioport_csrs *csrs;
+	alpha_agp_info *agp;
+	struct io7 *io7;
+
+	/*
+	 * Find the first IO7 with an AGP card.
+	 *
+	 * FIXME -- there should be a better way (we want to be able to
+	 * specify and what if the agp card is not video???)
+	 */
+	hose = NULL;
+	for (io7 = NULL; (io7 = marvel_next_io7(io7)) != NULL; ) {
+		struct pci_controller *h;
+		vuip addr;
+
+		if (!io7->ports[IO7_AGP_PORT].enabled)
+			continue;
+
+		h = io7->ports[IO7_AGP_PORT].hose;
+		addr = (vuip)build_conf_addr(h, 0, PCI_DEVFN(5, 0), 0);
+
+		if (*addr != 0xffffffffu) {
+			hose = h;
+			break;
+		}
+	}
+
+	printk("MARVEL - using hose %d as AGP\n", hose->index);
+
+	if (!hose || !hose->sg_pci)
+		return NULL;
+
+	/* 
+	 * Get the csrs from the hose.
+	 */
+	csrs = ((struct io7_port *)hose->sysdata)->csrs;
+
+	/*
+	 * Allocate the info structure.
+	 */
+	agp = kmalloc(sizeof(*agp), GFP_KERNEL);
+
+	/*
+	 * Fill it in.
+	 */
+	agp->type = 0 /* FIXME: ALPHA_CORE_AGP */;
+	agp->hose = hose;
+	agp->private = NULL;
+	agp->ops = &marvel_agp_ops;
+
+	/*
+	 * Aperture - not configured until ops.setup().
+	 */
+	agp->aperture.bus_base = 0;
+	agp->aperture.size = 0;
+	agp->aperture.sysdata = NULL;
+
+	/*
+	 * Capabilities.
+	 *
+	 * NOTE: IO7 reports through AGP_STAT that it can support a read queue
+	 *       depth of 17 (rq = 0x10). It actually only supports a depth of
+	 * 	 16 (rq = 0xf).
+	 */
+	agp->capability.lw = csrs->AGP_STAT.csr;
+	agp->capability.bits.rq = 0xf;
+	
+	/*
+	 * Mode.
+	 */
+	agp->mode.lw = csrs->AGP_CMD.csr;
+
+	return agp;
+}
diff -urN linux-2.4.21-pre3/arch/alpha/kernel/core_titan.c linux-2.4.21-pre4/arch/alpha/kernel/core_titan.c
--- linux-2.4.21-pre3/arch/alpha/kernel/core_titan.c	Sun Oct 21 10:30:58 2001
+++ linux-2.4.21-pre4/arch/alpha/kernel/core_titan.c	Tue Jan 28 19:44:28 2003
@@ -10,10 +10,13 @@
 #include <linux/pci.h>
 #include <linux/sched.h>
 #include <linux/init.h>
+#include <linux/vmalloc.h>
 
+#include <asm/hwrpb.h>
 #include <asm/ptrace.h>
 #include <asm/system.h>
 #include <asm/smp.h>
+#include <asm/pgalloc.h>
 
 #define __EXTERN_INLINE inline
 #include <asm/io.h>
@@ -25,14 +28,14 @@
 #include "proto.h"
 #include "pci_impl.h"
 
-unsigned TITAN_agp = 0;
+/* Save Titan configuration data as the console had it set up.  */
 
-static struct
+struct
 {
 	unsigned long wsba[4];
 	unsigned long wsm[4];
 	unsigned long tba[4];
-} saved_pachip_port[4];
+} saved_config[4] __attribute__((common));
 
 /*
  * BIOS32-style PCI interface:
@@ -47,6 +50,31 @@
 # define DBG_CFG(args)
 #endif
 
+
+/*
+ * Routines to access TIG registers.
+ */
+static inline volatile unsigned long *
+mk_tig_addr(int offset)
+{
+	return (volatile unsigned long *)(TITAN_TIG_SPACE + (offset << 6));
+}
+
+static inline u8 
+titan_read_tig(int offset, u8 value)
+{
+	volatile unsigned long *tig_addr = mk_tig_addr(offset);
+	return (u8)(*tig_addr & 0xff);
+}
+
+static inline void 
+titan_write_tig(int offset, u8 value)
+{
+	volatile unsigned long *tig_addr = mk_tig_addr(offset);
+	*tig_addr = (unsigned long)value;
+}
+
+
 /*
  * Given a bus, device, and function number, compute resulting
  * configuration space address
@@ -94,7 +122,7 @@
 		 "pci_addr=0x%p, type1=0x%p)\n",
 		 bus, device_fn, where, pci_addr, type1));
 
-        if (hose->first_busno == dev->bus->number)
+        if (hose->first_busno == bus)
 		bus = 0;
         *type1 = (bus != 0);
 
@@ -210,13 +238,16 @@
 	volatile unsigned long *csr;
 	unsigned long value;
 
-	/* Get the right hose */
+	/* Get the right hose.  */
 	port = &pachip->g_port;
 	if (hose->index & 2) 
 		port = &pachip->a_port;
 
 	/* We can invalidate up to 8 tlb entries in a go.  The flush
-	   matches against <31:16> in the pci address.  */
+	   matches against <31:16> in the pci address.  
+	   Note that gtlbi* and atlbi* are in the same place in the g_port
+	   and a_port, respectively, so the g_port offset can be used
+	   even if hose is an a_port */
 	csr = &port->port_specific.g.gtlbia.csr;
 	if (((start ^ end) & 0xffff0000) == 0)
 		csr = &port->port_specific.g.gtlbiv.csr;
@@ -231,9 +262,7 @@
 	*csr;
 }
 
-#define FN __FUNCTION__
-
-static int __init
+static int
 titan_query_agp(titan_pachip_port *port)
 {
 	union TPAchipPCTL pctl;
@@ -244,42 +273,11 @@
 	return pctl.pctl_r_bits.apctl_v_agp_present;
 
 }
-static void __init
-titan_init_agp(titan_pachip_port *port, struct pci_controller *hose)
-{
-	union TPAchipPCTL pctl;
-
-	if (!titan_query_agp(port))
-		return;
-
-	printk("AGP present on hose %d\n", hose->index);
-
-	/* get APCTL */
-	pctl.pctl_q_whole = port->pctl.csr;
-
-
-	pctl.pctl_r_bits.apctl_v_agp_en = 1;	/* enable AGP */
-	pctl.pctl_r_bits.apctl_v_agp_lp_rd = 0;	
-	pctl.pctl_r_bits.apctl_v_agp_hp_rd = 0;	
-
-	port->pctl.csr = pctl.pctl_q_whole;
-
-	TITAN_agp |= 1 << hose->index;
-
-#ifdef CONFIG_VGA_HOSE	
-	/* is a graphics card on the AGP? (always device 5) */
-	if (hose != NULL &&
-	    __kernel_ldwu(*(vusp)(hose->config_space_base + 0x280a)) == 
-	    PCI_CLASS_DISPLAY_VGA)
-		set_vga_hose(hose);
-#endif
-}
 
 static void __init
 titan_init_one_pachip_port(titan_pachip_port *port, int index)
 {
 	struct pci_controller *hose;
-	unsigned long sg_size;
 
 	hose = alloc_pci_controller();
 	if (index == 0)
@@ -287,10 +285,13 @@
 	hose->io_space = alloc_resource();
 	hose->mem_space = alloc_resource();
 
-	/* This is for userland consumption.  For some reason, the 40-bit
-	   PIO bias that we use in the kernel through KSEG didn't work for
-	   the page table based user mappings.  So make sure we get the
-	   43-bit PIO bias.  */
+	/*
+	 * This is for userland consumption.  The 40-bit PIO bias that we 
+	 * use in the kernel through KSEG doesn't work in the page table 
+	 * based user mappings. (43-bit KSEG sign extends the physical
+	 * address from bit 40 to hit the I/O bit - mapped addresses don't).
+	 * So make sure we get the 43-bit PIO bias.  
+	 */
 	hose->sparse_mem_base = 0;
 	hose->sparse_io_base = 0;
 	hose->dense_mem_base
@@ -316,65 +317,64 @@
 	if (request_resource(&iomem_resource, hose->mem_space) < 0)
 		printk(KERN_ERR "Failed to request MEM on hose %d\n", index);
 
-	/* It's safe to call this for both G-Ports and A-Ports */
-	titan_init_agp(port, hose);
-
 	/*
 	 * Save the existing PCI window translations.  SRM will 
 	 * need them when we go to reboot.
 	 */
-	saved_pachip_port[index].wsba[0] = port->wsba[0].csr;
-	saved_pachip_port[index].wsm[0]  = port->wsm[0].csr;
-	saved_pachip_port[index].tba[0]  = port->tba[0].csr;
-
-	saved_pachip_port[index].wsba[1] = port->wsba[1].csr;
-	saved_pachip_port[index].wsm[1]  = port->wsm[1].csr;
-	saved_pachip_port[index].tba[1]  = port->tba[1].csr;
-
-	saved_pachip_port[index].wsba[2] = port->wsba[2].csr;
-	saved_pachip_port[index].wsm[2]  = port->wsm[2].csr;
-	saved_pachip_port[index].tba[2]  = port->tba[2].csr;
-
-	saved_pachip_port[index].wsba[3] = port->wsba[3].csr;
-	saved_pachip_port[index].wsm[3]  = port->wsm[3].csr;
-	saved_pachip_port[index].tba[3]  = port->tba[3].csr;
+	saved_config[index].wsba[0] = port->wsba[0].csr;
+	saved_config[index].wsm[0]  = port->wsm[0].csr;
+	saved_config[index].tba[0]  = port->tba[0].csr;
+
+	saved_config[index].wsba[1] = port->wsba[1].csr;
+	saved_config[index].wsm[1]  = port->wsm[1].csr;
+	saved_config[index].tba[1]  = port->tba[1].csr;
+
+	saved_config[index].wsba[2] = port->wsba[2].csr;
+	saved_config[index].wsm[2]  = port->wsm[2].csr;
+	saved_config[index].tba[2]  = port->tba[2].csr;
+
+	saved_config[index].wsba[3] = port->wsba[3].csr;
+	saved_config[index].wsm[3]  = port->wsm[3].csr;
+	saved_config[index].tba[3]  = port->tba[3].csr;
 
 	/*
 	 * Set up the PCI to main memory translation windows.
 	 *
-	 * Note: Window 3 on Titan is Scatter-Gather ONLY
+	 * Note: Window 3 on Titan is Scatter-Gather ONLY.
 	 *
 	 * Window 0 is scatter-gather 8MB at 8MB (for isa)
-	 * Window 1 is scatter-gather (up to) 1GB at 1GB
-	 * Window 2 is direct access 2GB at 2GB
+	 * Window 1 is direct access 1GB at 2GB
+	 * Window 2 is scatter-gather 1GB at 3GB
 	 */
 	hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 0);
 	hose->sg_isa->align_entry = 8; /* 64KB for ISA */
 
-	hose->sg_pci = iommu_arena_new(hose, 0x40000000,
-				       size_for_memory(0x40000000), 0);
+	hose->sg_pci = iommu_arena_new(hose, 0xc0000000, 0x40000000, 0);
 	hose->sg_pci->align_entry = 4; /* Titan caches 4 PTEs at a time */
 
-	__direct_map_base = 0x80000000;
-	__direct_map_size = 0x80000000;
-
 	port->wsba[0].csr = hose->sg_isa->dma_base | 3;
 	port->wsm[0].csr  = (hose->sg_isa->size - 1) & 0xfff00000;
 	port->tba[0].csr  = virt_to_phys(hose->sg_isa->ptes);
 
-	port->wsba[1].csr = hose->sg_pci->dma_base | 3;
-	port->wsm[1].csr  = (hose->sg_pci->size - 1) & 0xfff00000;
-	port->tba[1].csr  = virt_to_phys(hose->sg_pci->ptes);
-
-	port->wsba[2].csr = 0x80000000 | 1;
-	port->wsm[2].csr  = (0x80000000 - 1) & 0xfff00000;
-	port->tba[2].csr  = 0;
+	port->wsba[1].csr = __direct_map_base | 1;
+	port->wsm[1].csr  = (__direct_map_size - 1) & 0xfff00000;
+	port->tba[1].csr  = 0;
+
+	port->wsba[2].csr = hose->sg_pci->dma_base | 3;
+	port->wsm[2].csr  = (hose->sg_pci->size - 1) & 0xfff00000;
+	port->tba[2].csr  = virt_to_phys(hose->sg_pci->ptes);
 
 	port->wsba[3].csr = 0;
 
-	/* Enable the Monster Window to make DAC pci64 possible. */
+	/* Enable the Monster Window to make DAC pci64 possible.  */
 	port->pctl.csr |= pctl_m_mwin;
 
+	/*
+	 * If it's an AGP port, initialize agplastwr.
+	 */
+	if (titan_query_agp(port)) 
+		port->port_specific.a.agplastwr.csr = __direct_map_base;
+
 	titan_pci_tbi(hose, 0, -1);
 }
 
@@ -392,25 +392,51 @@
 		titan_init_one_pachip_port(&pachip1->a_port, 3);/* hose 3 */
 }
 
+static void __init
+titan_init_vga_hose(void)
+{
+#ifdef CONFIG_VGA_HOSE
+	u64 *pu64 = (u64 *)((u64)hwrpb + hwrpb->ctbt_offset);
+
+	if (pu64[7] == 3) {	/* TERM_TYPE == graphics */
+		struct pci_controller *hose;
+		int h = (pu64[30] >> 24) & 0xff;	/* console hose # */
+
+		/*
+		 * Our hose numbering matches the console's, so just find
+		 * the right one...
+		 */
+		for (hose = hose_head; hose; hose = hose->next) {
+			if (hose->index == h) break;
+		}
+
+		if (hose) {
+			printk("Console graphics on hose %d\n", hose->index);
+			pci_vga_hose = hose;
+		}
+	}
+#endif /* CONFIG_VGA_HOSE */
+}
+
 void __init
 titan_init_arch(void)
 {
 #if 0
-	printk("%s: titan_init_arch()\n", FN);
-	printk("%s: CChip registers:\n", FN);
-	printk("%s: CSR_CSC 0x%lx\n", FN, TITAN_cchip->csc.csr);
-	printk("%s: CSR_MTR 0x%lx\n", FN, TITAN_cchip->mtr.csr);
-	printk("%s: CSR_MISC 0x%lx\n", FN, TITAN_cchip->misc.csr);
-	printk("%s: CSR_DIM0 0x%lx\n", FN, TITAN_cchip->dim0.csr);
-	printk("%s: CSR_DIM1 0x%lx\n", FN, TITAN_cchip->dim1.csr);
-	printk("%s: CSR_DIR0 0x%lx\n", FN, TITAN_cchip->dir0.csr);
-	printk("%s: CSR_DIR1 0x%lx\n", FN, TITAN_cchip->dir1.csr);
-	printk("%s: CSR_DRIR 0x%lx\n", FN, TITAN_cchip->drir.csr);
-
-	printk("%s: DChip registers:\n", FN);
-	printk("%s: CSR_DSC 0x%lx\n", FN, TITAN_dchip->dsc.csr);
-	printk("%s: CSR_STR 0x%lx\n", FN, TITAN_dchip->str.csr);
-	printk("%s: CSR_DREV 0x%lx\n", FN, TITAN_dchip->drev.csr);
+	printk("%s: titan_init_arch()\n", __FUNCTION__);
+	printk("%s: CChip registers:\n", __FUNCTION__);
+	printk("%s: CSR_CSC 0x%lx\n", __FUNCTION__, TITAN_cchip->csc.csr);
+	printk("%s: CSR_MTR 0x%lx\n", __FUNCTION__, TITAN_cchip->mtr.csr);
+	printk("%s: CSR_MISC 0x%lx\n", __FUNCTION__, TITAN_cchip->misc.csr);
+	printk("%s: CSR_DIM0 0x%lx\n", __FUNCTION__, TITAN_cchip->dim0.csr);
+	printk("%s: CSR_DIM1 0x%lx\n", __FUNCTION__, TITAN_cchip->dim1.csr);
+	printk("%s: CSR_DIR0 0x%lx\n", __FUNCTION__, TITAN_cchip->dir0.csr);
+	printk("%s: CSR_DIR1 0x%lx\n", __FUNCTION__, TITAN_cchip->dir1.csr);
+	printk("%s: CSR_DRIR 0x%lx\n", __FUNCTION__, TITAN_cchip->drir.csr);
+
+	printk("%s: DChip registers:\n", __FUNCTION__);
+	printk("%s: CSR_DSC 0x%lx\n", __FUNCTION__, TITAN_dchip->dsc.csr);
+	printk("%s: CSR_STR 0x%lx\n", __FUNCTION__, TITAN_dchip->str.csr);
+	printk("%s: CSR_DREV 0x%lx\n", __FUNCTION__, TITAN_dchip->drev.csr);
 #endif
 
 	boot_cpuid = __hard_smp_processor_id();
@@ -419,28 +445,35 @@
 	ioport_resource.end = ~0UL;
 	iomem_resource.end = ~0UL;
 
-	/* Init the PA chip(s) */
+	/* PCI DMA Direct Mapping is 1GB at 2GB.  */
+	__direct_map_base = 0x80000000;
+	__direct_map_size = 0x40000000;
+
+	/* Init the PA chip(s).  */
 	titan_init_pachips(TITAN_pachip0, TITAN_pachip1);
+
+	/* Check for graphic console location (if any).  */
+	titan_init_vga_hose();
 }
 
 static void
 titan_kill_one_pachip_port(titan_pachip_port *port, int index)
 {
-	port->wsba[0].csr = saved_pachip_port[index].wsba[0];
-	port->wsm[0].csr  = saved_pachip_port[index].wsm[0];
-	port->tba[0].csr  = saved_pachip_port[index].tba[0];
-
-	port->wsba[1].csr = saved_pachip_port[index].wsba[1];
-	port->wsm[1].csr  = saved_pachip_port[index].wsm[1];
-	port->tba[1].csr  = saved_pachip_port[index].tba[1];
-
-	port->wsba[2].csr = saved_pachip_port[index].wsba[2];
-	port->wsm[2].csr  = saved_pachip_port[index].wsm[2];
-	port->tba[2].csr  = saved_pachip_port[index].tba[2];
-
-	port->wsba[3].csr = saved_pachip_port[index].wsba[3];
-	port->wsm[3].csr  = saved_pachip_port[index].wsm[3];
-	port->tba[3].csr  = saved_pachip_port[index].tba[3];
+	port->wsba[0].csr = saved_config[index].wsba[0];
+	port->wsm[0].csr  = saved_config[index].wsm[0];
+	port->tba[0].csr  = saved_config[index].tba[0];
+
+	port->wsba[1].csr = saved_config[index].wsba[1];
+	port->wsm[1].csr  = saved_config[index].wsm[1];
+	port->tba[1].csr  = saved_config[index].tba[1];
+
+	port->wsba[2].csr = saved_config[index].wsba[2];
+	port->wsm[2].csr  = saved_config[index].wsm[2];
+	port->tba[2].csr  = saved_config[index].tba[2];
+
+	port->wsba[3].csr = saved_config[index].wsba[3];
+	port->wsm[3].csr  = saved_config[index].wsm[3];
+	port->tba[3].csr  = saved_config[index].tba[3];
 }
 
 static void
@@ -449,8 +482,8 @@
 	int pchip1_present = TITAN_cchip->csc.csr & 1L<<14;
 
 	if (pchip1_present) {
-		titan_kill_one_pachip_port(&pachip0->g_port, 1);
-		titan_kill_one_pachip_port(&pachip0->a_port, 3);
+		titan_kill_one_pachip_port(&pachip1->g_port, 1);
+		titan_kill_one_pachip_port(&pachip1->a_port, 3);
 	}
 	titan_kill_one_pachip_port(&pachip0->g_port, 0);
 	titan_kill_one_pachip_port(&pachip0->a_port, 2);
@@ -462,38 +495,333 @@
 	titan_kill_pachips(TITAN_pachip0, TITAN_pachip1);
 }
 
-static inline void
-titan_pci_clr_err_1(titan_pachip *pachip)
+
+/*
+ * IO map support.
+ */
+unsigned long
+titan_ioremap(unsigned long addr, unsigned long size)
 {
-	unsigned int jd;
+	int h = (addr & TITAN_HOSE_MASK) >> TITAN_HOSE_SHIFT;
+	unsigned long baddr = addr & ~TITAN_HOSE_MASK;
+	unsigned long last = baddr + size - 1;
+	struct pci_controller *hose;	
+	struct vm_struct *area;
+	unsigned long vaddr;
+	unsigned long *ptes;
+	unsigned long pfn;
+
+	/*
+	 * Adjust the addr.
+	 */ 
+#ifdef CONFIG_VGA_HOSE
+	if (pci_vga_hose && __titan_is_mem_vga(addr)) {
+		h = pci_vga_hose->index;
+		addr += pci_vga_hose->mem_space->start;
+	}
+#endif
+
+	/*
+	 * Find the hose.
+	 */
+	for (hose = hose_head; hose; hose = hose->next)
+		if (hose->index == h) break;
+	if (!hose) return (unsigned long)NULL;
+
+	/*
+	 * Is it direct-mapped?
+	 */
+	if ((baddr >= __direct_map_base) && 
+	    ((baddr + size - 1) < __direct_map_base + __direct_map_size)) 
+		return addr - __direct_map_base + TITAN_MEM_BIAS;
+
+	/* 
+	 * Check the scatter-gather arena.
+	 */
+	if (hose->sg_pci &&
+	    baddr >= (unsigned long)hose->sg_pci->dma_base &&
+	    last < (unsigned long)hose->sg_pci->dma_base + hose->sg_pci->size){
+
+		/*
+		 * Adjust the limits (mappings must be page aligned)
+		 */
+		baddr -= hose->sg_pci->dma_base;
+		last -= hose->sg_pci->dma_base;
+		baddr &= PAGE_MASK;
+		size = PAGE_ALIGN(last) - baddr;
+
+		/*
+		 * Map it
+		 */
+		area = get_vm_area(size, VM_IOREMAP);
+		if (!area) return (unsigned long)NULL;
+		ptes = hose->sg_pci->ptes;
+		for (vaddr = (unsigned long)area->addr; 
+		    baddr <= last; 
+		    baddr += PAGE_SIZE, vaddr += PAGE_SIZE) {
+			pfn = ptes[baddr >> PAGE_SHIFT];
+			if (!(pfn & 1)) {
+				printk("ioremap failed... pte not valid...\n");
+				vfree(area->addr);
+				return (unsigned long)NULL;
+			}
+			pfn >>= 1;	/* make it a true pfn */
+			
+			if (__alpha_remap_area_pages(VMALLOC_VMADDR(vaddr), 
+						     pfn << PAGE_SHIFT, 
+						     PAGE_SIZE, 0)) {
+				printk("FAILED to map...\n");
+				vfree(area->addr);
+				return (unsigned long)NULL;
+			}
+		}
+
+		flush_tlb_all();
+
+		vaddr = (unsigned long)area->addr + (addr & ~PAGE_MASK);
+		return vaddr;
+	}
+
+	/*
+	 * Not found - assume legacy ioremap.
+	 */
+	return addr + TITAN_MEM_BIAS;
 
-	jd = pachip->g_port.port_specific.g.gperror.csr;
-	pachip->g_port.port_specific.g.gperror.csr = jd;
-	mb();
-	pachip->g_port.port_specific.g.gperror.csr;
 }
 
-static inline void
-titan_pci_clr_err(void)
+void
+titan_iounmap(unsigned long addr)
 {
-	titan_pci_clr_err_1(TITAN_pachip0);
+	if (((long)addr >> 41) == -2)
+		return;	/* kseg map, nothing to do */
+	if (addr)
+		vfree((void *)(PAGE_MASK & addr)); 
+}
 
-	if (TITAN_cchip->csc.csr & 1L<<14)
-	    titan_pci_clr_err_1(TITAN_pachip1);
+
+/*
+ * AGP GART Support.
+ */
+#include <linux/agp_backend.h>
+#include <asm/agp_backend.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+struct titan_agp_aperture {
+	struct pci_iommu_arena *arena;
+	long pg_start;
+	long pg_count;
+};
+
+static int
+titan_agp_setup(alpha_agp_info *agp)
+{
+	struct titan_agp_aperture *aper;
+
+	if (!alpha_agpgart_size)
+		return -ENOMEM;
+
+	aper = kmalloc(sizeof(struct titan_agp_aperture), GFP_KERNEL);
+	if (aper == NULL)
+		return -ENOMEM;
+
+	aper->arena = agp->hose->sg_pci;
+	aper->pg_count = alpha_agpgart_size / PAGE_SIZE;
+	aper->pg_start = iommu_reserve(aper->arena, aper->pg_count,
+				       aper->pg_count - 1);
+	if (aper->pg_start < 0) {
+		printk(KERN_ERR "Failed to reserve AGP memory\n");
+		kfree(aper);
+		return -ENOMEM;
+	}
+
+	agp->aperture.bus_base = 
+		aper->arena->dma_base + aper->pg_start * PAGE_SIZE;
+	agp->aperture.size = aper->pg_count * PAGE_SIZE;
+	agp->aperture.sysdata = aper;
+
+	return 0;
 }
 
-void
-titan_machine_check(unsigned long vector, unsigned long la_ptr,
-		      struct pt_regs * regs)
+static void
+titan_agp_cleanup(alpha_agp_info *agp)
 {
-	/* clear error before any reporting. */
-	mb();
-	draina();
-	titan_pci_clr_err();
-	wrmces(0x7);
-	mb();
+	struct titan_agp_aperture *aper = agp->aperture.sysdata;
+	int status;
 
-	process_mcheck_info(vector, la_ptr, regs, "TITAN",
-			    mcheck_expected(smp_processor_id()));
+	status = iommu_release(aper->arena, aper->pg_start, aper->pg_count);
+	if (status == -EBUSY) {
+		printk(KERN_WARNING 
+		       "Attempted to release bound AGP memory - unbinding\n");
+		iommu_unbind(aper->arena, aper->pg_start, aper->pg_count);
+		status = iommu_release(aper->arena, aper->pg_start, 
+				       aper->pg_count);
+	}
+	if (status < 0)
+		printk(KERN_ERR "Failed to release AGP memory\n");
+
+	kfree(aper);
+	kfree(agp);
 }
 
+static int
+titan_agp_configure(alpha_agp_info *agp)
+{
+	union TPAchipPCTL pctl;
+	titan_pachip_port *port = agp->private;
+	pctl.pctl_q_whole = port->pctl.csr;
+
+	/* Side-Band Addressing? */
+	pctl.pctl_r_bits.apctl_v_agp_sba_en = agp->mode.bits.sba;
+
+	/* AGP Rate? */
+	pctl.pctl_r_bits.apctl_v_agp_rate = 0;		/* 1x */
+	if (agp->mode.bits.rate & 2) 
+		pctl.pctl_r_bits.apctl_v_agp_rate = 1;	/* 2x */
+#if 0
+	if (agp->mode.bits.rate & 4) 
+		pctl.pctl_r_bits.apctl_v_agp_rate = 2;	/* 4x */
+#endif
+	
+	/* RQ Depth? */
+	pctl.pctl_r_bits.apctl_v_agp_hp_rd = 2;
+	pctl.pctl_r_bits.apctl_v_agp_lp_rd = 7;
+
+	/*
+	 * AGP Enable.
+	 */
+	pctl.pctl_r_bits.apctl_v_agp_en = agp->mode.bits.enable;
+
+	/* Tell the user.  */
+	printk("Enabling AGP: %dX%s\n", 
+	       1 << pctl.pctl_r_bits.apctl_v_agp_rate,
+	       pctl.pctl_r_bits.apctl_v_agp_sba_en ? " - SBA" : "");
+	       
+	/* Write it.  */
+	port->pctl.csr = pctl.pctl_q_whole;
+	
+	/* And wait at least 5000 66MHz cycles (per Titan spec).  */
+	udelay(100);
+
+	return 0;
+}
+
+static int 
+titan_agp_bind_memory(alpha_agp_info *agp, off_t pg_start, agp_memory *mem)
+{
+	struct titan_agp_aperture *aper = agp->aperture.sysdata;
+	return iommu_bind(aper->arena, aper->pg_start + pg_start, 
+			  mem->page_count, mem->memory);
+}
+
+static int 
+titan_agp_unbind_memory(alpha_agp_info *agp, off_t pg_start, agp_memory *mem)
+{
+	struct titan_agp_aperture *aper = agp->aperture.sysdata;
+	return iommu_unbind(aper->arena, aper->pg_start + pg_start,
+			    mem->page_count);
+}
+
+static unsigned long
+titan_agp_translate(alpha_agp_info *agp, dma_addr_t addr)
+{
+	struct titan_agp_aperture *aper = agp->aperture.sysdata;
+	unsigned long baddr = addr - aper->arena->dma_base;
+	unsigned long pte;
+
+	if (addr < agp->aperture.bus_base ||
+	    addr >= agp->aperture.bus_base + agp->aperture.size) {
+		printk("%s: addr out of range\n", __FUNCTION__);
+		return -EINVAL;
+	}
+
+	pte = aper->arena->ptes[baddr >> PAGE_SHIFT];
+	if (!(pte & 1)) {
+		printk("%s: pte not valid\n", __FUNCTION__);
+		return -EINVAL;
+	}
+
+	return (pte >> 1) << PAGE_SHIFT;
+}
+
+struct alpha_agp_ops titan_agp_ops =
+{
+	setup:		titan_agp_setup,
+	cleanup:	titan_agp_cleanup,
+	configure:	titan_agp_configure,
+	bind:		titan_agp_bind_memory,
+	unbind:		titan_agp_unbind_memory,
+	translate:	titan_agp_translate
+};
+
+alpha_agp_info *
+titan_agp_info(void)
+{
+	alpha_agp_info *agp;
+	struct pci_controller *hose;
+	titan_pachip_port *port;
+	int hosenum = -1;
+	union TPAchipPCTL pctl;
+
+	/*
+	 * Find the AGP port.
+	 */
+	port = &TITAN_pachip0->a_port;
+	if (titan_query_agp(port))
+		hosenum = 2;
+	if (hosenum < 0 && 
+	    titan_query_agp(port = &TITAN_pachip1->a_port)) 
+		hosenum = 3;
+	
+	/*
+	 * Find the hose the port is on.
+	 */
+	for (hose = hose_head; hose; hose = hose->next)
+		if (hose->index == hosenum)
+			break;
+
+	if (!hose || !hose->sg_pci)
+		return NULL;
+
+	/*
+	 * Allocate the info structure.
+	 */
+	agp = kmalloc(sizeof(*agp), GFP_KERNEL);
+
+	/*
+	 * Fill it in.
+	 */
+	agp->type = 0 /* FIXME: ALPHA_CORE_AGP */;
+	agp->hose = hose;
+	agp->private = port;
+	agp->ops = &titan_agp_ops;
+
+	/*
+	 * Aperture - not configured until ops.setup().
+	 *
+	 * FIXME - should we go ahead and allocate it here?
+	 */
+	agp->aperture.bus_base = 0;
+	agp->aperture.size = 0;
+	agp->aperture.sysdata = NULL;
+
+	/*
+	 * Capabilities.
+	 */
+	agp->capability.lw = 0;
+	agp->capability.bits.rate = 3; 	/* 2x, 1x */
+	agp->capability.bits.sba = 1;
+	agp->capability.bits.rq = 7;	/* 8 - 1 */
+
+	/*
+	 * Mode.
+	 */
+	pctl.pctl_q_whole = port->pctl.csr;
+	agp->mode.lw = 0;
+	agp->mode.bits.rate = 1 << pctl.pctl_r_bits.apctl_v_agp_rate;
+	agp->mode.bits.sba = pctl.pctl_r_bits.apctl_v_agp_sba_en;
+	agp->mode.bits.rq = 7;	/* RQ Depth? */
+	agp->mode.bits.enable = pctl.pctl_r_bits.apctl_v_agp_en;
+
+	return agp;
+}
diff -urN linux-2.4.21-pre3/arch/alpha/kernel/core_wildfire.c linux-2.4.21-pre4/arch/alpha/kernel/core_wildfire.c
--- linux-2.4.21-pre3/arch/alpha/kernel/core_wildfire.c	Fri Mar  2 11:12:07 2001
+++ linux-2.4.21-pre4/arch/alpha/kernel/core_wildfire.c	Tue Jan 28 19:44:28 2003
@@ -475,6 +475,33 @@
 	write_dword:	wildfire_write_config_dword
 };
 
+
+/*
+ * NUMA Support
+ */
+int wildfire_pa_to_nid(unsigned long pa)
+{
+	return pa >> 36;
+}
+
+int wildfire_cpuid_to_nid(int cpuid)
+{
+	/* assume 4 CPUs per node */
+	return cpuid >> 2;
+}
+
+unsigned long wildfire_node_mem_start(int nid)
+{
+	/* 64GB per node */
+	return (unsigned long)nid * (64UL * 1024 * 1024 * 1024);
+}
+
+unsigned long wildfire_node_mem_size(int nid)
+{
+	/* 64GB per node */
+	return 64UL * 1024 * 1024 * 1024;
+}
+
 #if DEBUG_DUMP_REGS
 
 static void __init
diff -urN linux-2.4.21-pre3/arch/alpha/kernel/err_common.c linux-2.4.21-pre4/arch/alpha/kernel/err_common.c
--- linux-2.4.21-pre3/arch/alpha/kernel/err_common.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/arch/alpha/kernel/err_common.c	Tue Jan 28 19:44:28 2003
@@ -0,0 +1,772 @@
+/*
+ *	linux/arch/alpha/kernel/err_common.c
+ *
+ *	Copyright (C) 2000 Jeff Wiedemeier (Compaq Computer Corporation)
+ *
+ *	Error handling code supporting Alpha systems
+ */
+
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+
+#include <asm/io.h>
+#include <asm/hwrpb.h>
+#include <asm/smp.h>
+
+#include "err_impl.h"
+#include "proto.h"
+
+/*
+ * err_print_prefix -- error handling print routines should prefix
+ * all prints with this
+ */
+char *err_print_prefix = KERN_NOTICE;
+
+/*
+ * Forward references
+ */
+static void el_print_timestamp(union el_timestamp);
+static void el_process_subpackets(struct el_subpacket *, int);
+
+
+/*
+ * Generic
+ */
+void
+mchk_dump_mem(void *data, size_t length, char **annotation)
+{
+	unsigned long *ldata = data;
+	size_t i;
+	
+	for (i = 0; (i * sizeof(*ldata)) < length; i++) {
+		if (annotation && !annotation[i]) 
+			annotation = NULL;
+		printk("%s    %08x: %016lx    %s\n",
+		       err_print_prefix,
+		       (unsigned)(i * sizeof(*ldata)), ldata[i],
+		       annotation ? annotation[i] : "");
+	}
+}
+
+void
+mchk_dump_logout_frame(struct el_common *mchk_header)
+{
+	printk("%s  -- Frame Header --\n"
+	         "    Frame Size:   %d (0x%x) bytes\n"
+	         "    Flags:        %s%s\n"
+	         "    MCHK Code:    0x%x\n"
+	         "    Frame Rev:    %d\n"
+	         "    Proc Offset:  0x%08x\n"
+	         "    Sys Offset:   0x%08x\n"
+  	         "  -- Processor Region --\n",
+	       err_print_prefix, 
+	       mchk_header->size, mchk_header->size,
+	       mchk_header->retry ? "RETRY " : "", 
+  	         mchk_header->err2 ? "SECOND_ERR " : "",
+	       mchk_header->code,
+	       mchk_header->frame_rev,
+	       mchk_header->proc_offset,
+	       mchk_header->sys_offset);
+
+	mchk_dump_mem((void *)
+		      ((unsigned long)mchk_header + mchk_header->proc_offset),
+		      mchk_header->sys_offset - mchk_header->proc_offset,
+		      NULL);
+	
+	printk("%s  -- System Region --\n", err_print_prefix);
+	mchk_dump_mem((void *)
+		      ((unsigned long)mchk_header + mchk_header->sys_offset),
+		      mchk_header->size - mchk_header->sys_offset,
+		      NULL);
+	printk("%s  -- End of Frame --\n", err_print_prefix);
+}
+
+
+/*
+ * EV7 generic
+ */
+#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_EV7)
+
+void
+ev7_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs)
+{
+	/*
+	 * Sync the processor
+	 */
+	mb();
+	draina();
+
+	/*
+	 * Parse the logout frame without printing first. If the only error(s)
+	 * found are have a disposition of "dismiss", then just dismiss them
+	 * and don't print any message
+	 */
+	printk("%sEV7 MACHINE CHECK vector %lx\n", err_print_prefix, vector);
+
+	/* 
+	 * Release the logout frame 
+	 */
+	wrmces(0x7);
+	mb();
+}
+
+struct ev7_pal_subpacket {
+	union {
+		struct {
+			u32 mchk_code;
+			u32 subpacket_count;
+			u64 whami;
+			u64 rbox_whami;
+			u64 rbox_int;
+			u64 exc_addr;
+			union el_timestamp timestamp;
+			u64 halt_code;
+			u64 reserved;
+		} logout;
+	} by_type;
+};
+
+static char *el_ev7_processor_subpacket_annotation[] = {
+	"Subpacket Header",	"I_STAT",	"DC_STAT",
+	"C_ADDR",		"C_SYNDROME_1",	"C_SYNDROME_0",
+	"C_STAT",		"C_STS",	"MM_STAT",
+	"EXC_ADDR",		"IER_CM",	"ISUM",
+	"PAL_BASE",		"I_CTL",	"PROCESS_CONTEXT",
+	"CBOX_CTL",		"CBOX_STP_CTL",	"CBOX_ACC_CTL",
+	"CBOX_LCL_SET",		"CBOX_GLB_SET",	"BBOX_CTL",
+	"BBOX_ERR_STS",		"BBOX_ERR_IDX",	"CBOX_DDP_ERR_STS",
+	"BBOX_DAT_RMP",		NULL
+};
+
+static char *el_ev7_zbox_subpacket_annotation[] = {
+	"Subpacket Header", 	
+	"ZBOX(0): DRAM_ERR_STATUS_2 / DRAM_ERR_STATUS_1",
+	"ZBOX(0): DRAM_ERROR_CTL    / DRAM_ERR_STATUS_3",
+	"ZBOX(0): DIFT_TIMEOUT      / DRAM_ERR_ADR",
+	"ZBOX(0): FRC_ERR_ADR       / DRAM_MAPPER_CTL",
+	"ZBOX(0): reserved          / DIFT_ERR_STATUS",
+	"ZBOX(1): DRAM_ERR_STATUS_2 / DRAM_ERR_STATUS_1",
+	"ZBOX(1): DRAM_ERROR_CTL    / DRAM_ERR_STATUS_3",
+	"ZBOX(1): DIFT_TIMEOUT      / DRAM_ERR_ADR",
+	"ZBOX(1): FRC_ERR_ADR       / DRAM_MAPPER_CTL",
+	"ZBOX(1): reserved          / DIFT_ERR_STATUS",
+	"CBOX_CTL",		"CBOX_STP_CTL",
+	"ZBOX(0)_ERROR_PA",	"ZBOX(1)_ERROR_PA",
+	"ZBOX(0)_ORED_SYNDROME","ZBOX(1)_ORED_SYNDROME",
+	NULL
+};
+
+static char *el_ev7_rbox_subpacket_annotation[] = {
+	"Subpacket Header",	"RBOX_CFG",	"RBOX_N_CFG",
+	"RBOX_S_CFG",		"RBOX_E_CFG",	"RBOX_W_CFG",
+	"RBOX_N_ERR",		"RBOX_S_ERR",	"RBOX_E_ERR",
+	"RBOX_W_ERR",		"RBOX_IO_CFG",	"RBOX_IO_ERR",
+	"RBOX_L_ERR",		"RBOX_WHOAMI",	"RBOX_IMASL",
+	"RBOX_INTQ",		"RBOX_INT",	NULL
+};
+
+static char *el_ev7_io_subpacket_annotation[] = {
+	"Subpacket Header",	"IO_ASIC_REV",	"IO_SYS_REV",
+	"IO7_UPH",		"HPI_CTL",	"CRD_CTL",
+	"HEI_CTL",		"PO7_ERROR_SUM","PO7_UNCRR_SYM",
+	"PO7_CRRCT_SYM",	"PO7_UGBGE_SYM","PO7_ERR_PKT0",
+	"PO7_ERR_PKT1",		"reserved",	"reserved",
+	"PO0_ERR_SUM",		"PO0_TLB_ERR",	"PO0_SPL_COMPLT",
+	"PO0_TRANS_SUM",	"PO0_FIRST_ERR","PO0_MULT_ERR",
+	"DM CSR PH",		"DM CSR PH",	"DM CSR PH",
+	"DM CSR PH",		"reserved",
+	"PO1_ERR_SUM",		"PO1_TLB_ERR",	"PO1_SPL_COMPLT",
+	"PO1_TRANS_SUM",	"PO1_FIRST_ERR","PO1_MULT_ERR",
+	"DM CSR PH",		"DM CSR PH",	"DM CSR PH",
+	"DM CSR PH",		"reserved",
+	"PO2_ERR_SUM",		"PO2_TLB_ERR",	"PO2_SPL_COMPLT",
+	"PO2_TRANS_SUM",	"PO2_FIRST_ERR","PO2_MULT_ERR",
+	"DM CSR PH",		"DM CSR PH",	"DM CSR PH",
+	"DM CSR PH",		"reserved",
+	"PO3_ERR_SUM",		"PO3_TLB_ERR",	"PO3_SPL_COMPLT",
+	"PO3_TRANS_SUM",	"PO3_FIRST_ERR","PO3_MULT_ERR",
+	"DM CSR PH",		"DM CSR PH",	"DM CSR PH",
+	"DM CSR PH",		"reserved",	
+	NULL
+};
+	
+static struct el_subpacket_annotation el_ev7_pal_annotations[] = {
+	SUBPACKET_ANNOTATION(EL_CLASS__PAL,
+			     EL_TYPE__PAL__EV7_PROCESSOR,
+			     1,
+			     "EV7 Processor Subpacket",
+			     el_ev7_processor_subpacket_annotation),
+	SUBPACKET_ANNOTATION(EL_CLASS__PAL,
+			     EL_TYPE__PAL__EV7_ZBOX,
+			     1,
+			     "EV7 ZBOX Subpacket",
+			     el_ev7_zbox_subpacket_annotation),
+	SUBPACKET_ANNOTATION(EL_CLASS__PAL,
+			     EL_TYPE__PAL__EV7_RBOX,
+			     1,
+			     "EV7 RBOX Subpacket",
+			     el_ev7_rbox_subpacket_annotation),
+	SUBPACKET_ANNOTATION(EL_CLASS__PAL,
+			     EL_TYPE__PAL__EV7_IO,
+			     1,
+			     "EV7 IO Subpacket",
+			     el_ev7_io_subpacket_annotation)
+};
+
+static struct el_subpacket *
+ev7_process_pal_subpacket(struct el_subpacket *header)
+{
+	struct ev7_pal_subpacket *packet;
+
+	if (header->class != EL_CLASS__PAL) {
+		printk("%s  ** Unexpected header CLASS %d TYPE %d, aborting\n",
+		       err_print_prefix,
+		       header->class, header->type);
+		return NULL;
+	}
+
+	packet = (struct ev7_pal_subpacket *)header->by_type.raw.data_start;
+
+	switch(header->type) {
+	case EL_TYPE__PAL__LOGOUT_FRAME:
+		printk("%s*** MCHK occurred on LPID %ld (RBOX %lx)\n",
+		       err_print_prefix,
+		       packet->by_type.logout.whami, 
+		       packet->by_type.logout.rbox_whami);
+		el_print_timestamp(packet->by_type.logout.timestamp);
+		printk("%s  EXC_ADDR: %016lx\n"
+		         "  HALT_CODE: %lx\n", 
+		       err_print_prefix,
+		       packet->by_type.logout.exc_addr,
+		       packet->by_type.logout.halt_code);
+		el_process_subpackets(header,
+                                      packet->by_type.logout.subpacket_count);
+		break;
+	default:
+		printk("%s  ** PAL TYPE %d SUBPACKET\n", 
+		       err_print_prefix,
+		       header->type);
+		el_annotate_subpacket(header);
+		break;
+	}
+	
+	return (struct el_subpacket *)((unsigned long)header + header->length);
+}
+
+struct el_subpacket_handler ev7_pal_subpacket_handler =
+	SUBPACKET_HANDLER_INIT(EL_CLASS__PAL, ev7_process_pal_subpacket);
+
+void 
+ev7_register_error_handlers(void)
+{
+	int i;
+
+	for(i = 0;
+	    i<sizeof(el_ev7_pal_annotations)/sizeof(el_ev7_pal_annotations[1]);
+	    i++) {
+		cdl_register_subpacket_annotation(&el_ev7_pal_annotations[i]);
+	}	
+	cdl_register_subpacket_handler(&ev7_pal_subpacket_handler);
+}
+
+#endif /* CONFIG_ALPHA_GENERIC || CONFIG_ALPHA_EV7 */
+
+
+/*
+ * EV6 generic
+ */
+
+#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_EV6)
+
+static int
+ev6_parse_ibox(u64 i_stat, int print)
+{
+	int status = MCHK_DISPOSITION_REPORT;
+
+#define EV6__I_STAT__PAR	(1UL << 29)
+#define EV6__I_STAT__ERRMASK	(EV6__I_STAT__PAR)
+
+	if (!(i_stat & EV6__I_STAT__ERRMASK))
+		return MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+	if (!print)
+		return status;
+
+	if (i_stat & EV6__I_STAT__PAR)
+		printk("%s    Icache parity error\n", err_print_prefix);
+
+	return status;
+}
+
+static int
+ev6_parse_mbox(u64 mm_stat, u64 d_stat, u64 c_stat, int print)
+{
+	int status = MCHK_DISPOSITION_REPORT;
+
+#define EV6__MM_STAT__DC_TAG_PERR	(1UL << 10)
+#define EV6__MM_STAT__ERRMASK		(EV6__MM_STAT__DC_TAG_PERR)
+#define EV6__D_STAT__TPERR_P0		(1UL << 0)
+#define EV6__D_STAT__TPERR_P1		(1UL << 1)
+#define EV6__D_STAT__ECC_ERR_ST		(1UL << 2)
+#define EV6__D_STAT__ECC_ERR_LD		(1UL << 3)
+#define EV6__D_STAT__SEO		(1UL << 4)
+#define EV6__D_STAT__ERRMASK		(EV6__D_STAT__TPERR_P0 |	\
+                                         EV6__D_STAT__TPERR_P1 | 	\
+                                         EV6__D_STAT__ECC_ERR_ST | 	\
+                                         EV6__D_STAT__ECC_ERR_LD | 	\
+                                         EV6__D_STAT__SEO)
+
+	if (!(d_stat & EV6__D_STAT__ERRMASK) && 
+	    !(mm_stat & EV6__MM_STAT__ERRMASK))
+		return MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+	if (!print)
+		return status;
+
+	if (mm_stat & EV6__MM_STAT__DC_TAG_PERR)
+		printk("%s    Dcache tag parity error on probe\n",
+		       err_print_prefix);
+	if (d_stat & EV6__D_STAT__TPERR_P0)
+		printk("%s    Dcache tag parity error - pipe 0\n",
+		       err_print_prefix);
+	if (d_stat & EV6__D_STAT__TPERR_P1)
+		printk("%s    Dcache tag parity error - pipe 1\n",
+		       err_print_prefix);
+	if (d_stat & EV6__D_STAT__ECC_ERR_ST)
+		printk("%s    ECC error occurred on a store\n", 
+		       err_print_prefix);
+	if (d_stat & EV6__D_STAT__ECC_ERR_LD)
+		printk("%s    ECC error occurred on a %s load\n",
+		       err_print_prefix,
+		       c_stat ? "" : "speculative ");
+	if (d_stat & EV6__D_STAT__SEO)
+		printk("%s    Dcache second error\n", err_print_prefix);
+
+	return status;
+}
+
+static int
+ev6_parse_cbox(u64 c_addr, u64 c1_syn, u64 c2_syn, 
+	       u64 c_stat, u64 c_sts, int print)
+{
+	char *sourcename[] = { "UNKNOWN", "UNKNOWN", "UNKNOWN",
+			       "MEMORY", "BCACHE", "DCACHE", 
+			       "BCACHE PROBE", "BCACHE PROBE" };
+	char *streamname[] = { "D", "I" };
+	char *bitsname[] = { "SINGLE", "DOUBLE" };
+	int status = MCHK_DISPOSITION_REPORT;
+	int source = -1, stream = -1, bits = -1;
+
+#define EV6__C_STAT__BC_PERR		(0x01)
+#define EV6__C_STAT__DC_PERR		(0x02)
+#define EV6__C_STAT__DSTREAM_MEM_ERR	(0x03)
+#define EV6__C_STAT__DSTREAM_BC_ERR	(0x04)
+#define EV6__C_STAT__DSTREAM_DC_ERR	(0x05)
+#define EV6__C_STAT__PROBE_BC_ERR0	(0x06)	/* both 6 and 7 indicate... */
+#define EV6__C_STAT__PROBE_BC_ERR1	(0x07)	/* ...probe bc error.       */
+#define EV6__C_STAT__ISTREAM_MEM_ERR	(0x0B)
+#define EV6__C_STAT__ISTREAM_BC_ERR	(0x0C)
+#define EV6__C_STAT__DSTREAM_MEM_DBL	(0x13)
+#define EV6__C_STAT__DSTREAM_BC_DBL	(0x14)
+#define EV6__C_STAT__ISTREAM_MEM_DBL	(0x1B)
+#define EV6__C_STAT__ISTREAM_BC_DBL	(0x1C)
+#define EV6__C_STAT__SOURCE_MEMORY	(0x03)
+#define EV6__C_STAT__SOURCE_BCACHE	(0x04)
+#define EV6__C_STAT__SOURCE__S		(0)
+#define EV6__C_STAT__SOURCE__M 		(0x07)
+#define EV6__C_STAT__ISTREAM__S		(3)
+#define EV6__C_STAT__ISTREAM__M		(0x01)
+#define EV6__C_STAT__DOUBLE__S		(4)
+#define EV6__C_STAT__DOUBLE__M		(0x01)
+#define EV6__C_STAT__ERRMASK		(0x1F)
+#define EV6__C_STS__SHARED		(1 << 0)
+#define EV6__C_STS__DIRTY		(1 << 1)
+#define EV6__C_STS__VALID		(1 << 2)
+#define EV6__C_STS__PARITY		(1 << 3)
+
+	if (!(c_stat & EV6__C_STAT__ERRMASK))
+		return MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+	if (!print)
+		return status;
+
+	source = EXTRACT(c_stat, EV6__C_STAT__SOURCE);
+	stream = EXTRACT(c_stat, EV6__C_STAT__ISTREAM);
+	bits = EXTRACT(c_stat, EV6__C_STAT__DOUBLE);
+
+	if (c_stat & EV6__C_STAT__BC_PERR) {
+		printk("%s    Bcache tag parity error\n", err_print_prefix);
+		source = -1;
+	}
+
+	if (c_stat & EV6__C_STAT__DC_PERR) {
+		printk("%s    Dcache tag parity error\n", err_print_prefix);
+		source = -1;
+	}
+
+	if (c_stat == EV6__C_STAT__PROBE_BC_ERR0 ||
+	    c_stat == EV6__C_STAT__PROBE_BC_ERR1) {
+		printk("%s    Bcache single-bit error on a probe hit\n",
+		       err_print_prefix);
+		source = -1;
+	}
+
+	if (source != -1) 
+		printk("%s    %s-STREAM %s-BIT ECC error from %s\n",
+		       err_print_prefix,
+		       streamname[stream], bitsname[bits], sourcename[source]);
+
+	printk("%s    Address: 0x%016lx\n"
+	         "    Syndrome[upper.lower]: %02lx.%02lx\n", 
+	       err_print_prefix,
+	       c_addr,
+	       c2_syn, c1_syn);
+
+	if (source == EV6__C_STAT__SOURCE_MEMORY ||
+	    source == EV6__C_STAT__SOURCE_BCACHE) 
+		printk("%s    Block status: %s%s%s%s\n",
+		       err_print_prefix,
+		       (c_sts & EV6__C_STS__SHARED) ? "SHARED " : "",
+		       (c_sts & EV6__C_STS__DIRTY)  ? "DIRTY "  : "",
+		       (c_sts & EV6__C_STS__VALID)  ? "VALID "  : "",
+		       (c_sts & EV6__C_STS__PARITY) ? "PARITY " : "");
+		
+	return status;
+}
+
+int
+ev6_process_logout_frame(struct el_common *mchk_header, int print)
+{
+	struct el_common_EV6_mcheck *ev6mchk = 
+		(struct el_common_EV6_mcheck *)mchk_header;
+	int status = MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+	status |= ev6_parse_ibox(ev6mchk->I_STAT, print);
+	status |= ev6_parse_mbox(ev6mchk->MM_STAT, ev6mchk->DC_STAT, 
+				 ev6mchk->C_STAT, print);
+	status |= ev6_parse_cbox(ev6mchk->C_ADDR, ev6mchk->DC1_SYNDROME,
+				 ev6mchk->DC0_SYNDROME, ev6mchk->C_STAT,
+				 ev6mchk->C_STS, print);
+
+	if (!print)
+		return status;
+
+	if (status != MCHK_DISPOSITION_DISMISS) {
+		char *saved_err_prefix = err_print_prefix;
+
+		/*
+		 * Dump some additional information from the frame
+		 */
+		printk("%s    EXC_ADDR: 0x%016lx   IER_CM: 0x%016lx"
+		            "   ISUM: 0x%016lx\n"
+		         "    PAL_BASE: 0x%016lx   I_CTL:  0x%016lx"
+		            "   PCTX: 0x%016lx\n",
+		       err_print_prefix,
+		       ev6mchk->EXC_ADDR, ev6mchk->IER_CM, ev6mchk->ISUM,
+		       ev6mchk->PAL_BASE, ev6mchk->I_CTL, ev6mchk->PCTX);
+
+		if (status == MCHK_DISPOSITION_UNKNOWN_ERROR) {
+			printk("%s    UNKNOWN error, frame follows:\n",
+			       err_print_prefix);
+		} else {
+			/* had decode -- downgrade print level for frame */
+			err_print_prefix = KERN_NOTICE;
+		}
+
+		mchk_dump_logout_frame(mchk_header);
+
+		err_print_prefix = saved_err_prefix;
+	}
+
+	return status;
+}
+
+void
+ev6_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs)
+{
+	struct el_common *mchk_header = (struct el_common *)la_ptr;
+
+	/*
+	 * Sync the processor
+	 */
+	mb();
+	draina();
+
+	/*
+	 * Parse the logout frame without printing first. If the only error(s)
+	 * found are have a disposition of "dismiss", then just dismiss them
+	 * and don't print any message
+	 */
+	if (ev6_process_logout_frame(mchk_header, 0) != 
+	    MCHK_DISPOSITION_DISMISS) {
+		char *saved_err_prefix = err_print_prefix;
+		err_print_prefix = KERN_CRIT;
+
+		/*
+		 * Either a nondismissable error was detected or no
+		 * recognized error was detected  in the logout frame 
+		 * -- report the error in either case
+		 */
+		printk("%s*CPU %s Error (Vector 0x%x) reported on CPU %d:\n", 
+		       err_print_prefix,
+		       (vector == SCB_Q_PROCERR)?"Correctable":"Uncorrectable",
+		       (unsigned int)vector, (int)smp_processor_id());
+		
+		ev6_process_logout_frame(mchk_header, 1);
+		dik_show_regs(regs, NULL);
+
+		err_print_prefix = saved_err_prefix;
+	}
+
+	/* 
+	 * Release the logout frame 
+	 */
+	wrmces(0x7);
+	mb();
+}
+
+#endif /* CONFIG_ALPHA_GENERIC || CONFIG_ALPHA_EV6 */
+
+
+/*
+ * Console Data Log
+ */
+/* Data */
+static struct el_subpacket_handler *subpacket_handler_list = NULL;
+static struct el_subpacket_annotation *subpacket_annotation_list = NULL;
+
+static void
+el_print_timestamp(union el_timestamp timestamp)
+{
+	if (timestamp.as_int)
+		printk("%s  TIMESTAMP: %d/%d/%02d %d:%02d:%0d\n", 
+		       err_print_prefix,
+		       timestamp.b.month, timestamp.b.day,
+		       timestamp.b.year, timestamp.b.hour,
+		       timestamp.b.minute, timestamp.b.second);
+}
+
+static struct el_subpacket *
+el_process_header_subpacket(struct el_subpacket *header)
+{
+	union el_timestamp timestamp;
+	char *name = "UNKNOWN EVENT";
+	int packet_count = 0;
+	int length = 0;
+
+	if (header->class != EL_CLASS__HEADER) {
+		printk("%s** Unexpected header CLASS %d TYPE %d, aborting\n",
+		       err_print_prefix,
+		       header->class, header->type);
+		return NULL;
+	}
+
+	switch(header->type) {
+	case EL_TYPE__HEADER__SYSTEM_ERROR_FRAME:
+		name = "SYSTEM ERROR";
+		length = header->by_type.sys_err.frame_length;
+		packet_count = 
+			header->by_type.sys_err.frame_packet_count;
+		timestamp.as_int = 0;
+		break;
+	case EL_TYPE__HEADER__SYSTEM_EVENT_FRAME:
+		name = "SYSTEM EVENT";
+		length = header->by_type.sys_event.frame_length;
+		packet_count = 
+			header->by_type.sys_event.frame_packet_count;
+		timestamp = header->by_type.sys_event.timestamp;
+		break;
+	case EL_TYPE__HEADER__HALT_FRAME:
+		name = "ERROR HALT";
+		length = header->by_type.err_halt.frame_length;
+		packet_count = 
+			header->by_type.err_halt.frame_packet_count;
+		timestamp = header->by_type.err_halt.timestamp;
+		break;
+	case EL_TYPE__HEADER__LOGOUT_FRAME:
+		name = "LOGOUT FRAME";
+		length = header->by_type.logout_header.frame_length;
+		packet_count = 1;
+		timestamp.as_int = 0;
+		break;
+	default: /* Unknown */
+		printk("%s** Unknown header - CLASS %d TYPE %d, aborting\n",
+		       err_print_prefix,
+		       header->class, header->type);
+		return NULL;		
+	}
+
+	printk("%s*** %s:\n"
+	         "  CLASS %d, TYPE %d\n", 
+	       err_print_prefix,
+	       name,
+	       header->class, header->type);
+	el_print_timestamp(timestamp);
+	
+	/*
+	 * Process the subpackets
+	 */
+	el_process_subpackets(header, packet_count);
+
+	/* return the next header */
+	header = (struct el_subpacket *)
+		((unsigned long)header + header->length + length);
+	return header;
+}
+
+static void
+el_process_subpackets(struct el_subpacket *header, int packet_count)
+{
+	struct el_subpacket *subpacket;
+	int i;
+
+	subpacket = (struct el_subpacket *)
+		((unsigned long)header + header->length);
+
+	for (i = 0; subpacket && i < packet_count; i++) {
+		printk("%sPROCESSING SUBPACKET %d\n", err_print_prefix, i);
+		subpacket = el_process_subpacket(subpacket);
+	}
+}
+
+static struct el_subpacket *
+el_process_subpacket_reg(struct el_subpacket *header)
+{
+	struct el_subpacket *next = NULL;
+	struct el_subpacket_handler *h = subpacket_handler_list;
+
+	for (; h && h->class != header->class; h = h->next);
+	if (h) next = h->handler(header);
+
+	return next;
+}
+
+struct el_subpacket *
+el_process_subpacket(struct el_subpacket *header)
+{
+	struct el_subpacket *next = NULL;
+
+	switch(header->class) {
+	case EL_CLASS__TERMINATION:
+		/* Termination packet, there are no more */
+		break;
+	case EL_CLASS__HEADER: 
+		next = el_process_header_subpacket(header);
+		break;
+	default:
+		if (NULL == (next = el_process_subpacket_reg(header))) {
+			printk("%s** Unexpected header CLASS %d TYPE %d"
+			       " -- aborting.\n",
+			       err_print_prefix,
+			       header->class, header->type);
+		}
+		break;
+	}
+
+	return next;
+}
+
+void 
+el_annotate_subpacket(struct el_subpacket *header)
+{
+	struct el_subpacket_annotation *a;
+	char **annotation = NULL;
+
+	for (a = subpacket_annotation_list; a; a = a->next) {
+		if (a->class == header->class &&
+		    a->type == header->type &&
+		    a->revision == header->revision) {
+			/*
+			 * We found the annotation
+			 */
+			annotation = a->annotation;
+			printk("%s  %s\n", err_print_prefix, a->description);
+			break;
+		}
+	}
+
+	mchk_dump_mem(header, header->length, annotation);
+}
+
+static void __init
+cdl_process_console_data_log(int cpu, struct percpu_struct *pcpu)
+{
+	struct el_subpacket *header = (struct el_subpacket *)
+		(IDENT_ADDR | pcpu->console_data_log_pa);
+	int err;
+
+	printk("%s******* CONSOLE DATA LOG FOR CPU %d. *******\n"
+	         "*** Error(s) were logged on a previous boot\n",
+	       err_print_prefix, cpu);
+	
+	for (err = 0; header && (header->class != EL_CLASS__TERMINATION); err++)
+		header = el_process_subpacket(header);
+
+	/* let the console know it's ok to clear the error(s) at restart */
+	pcpu->console_data_log_pa = 0;
+
+	printk("%s*** %d total error(s) logged\n"
+	         "**** END OF CONSOLE DATA LOG FOR CPU %d ****\n", 
+	       err_print_prefix, err, cpu);
+}
+
+void __init
+cdl_check_console_data_log(void)
+{
+	struct percpu_struct *pcpu;
+	unsigned long cpu;
+
+	for (cpu = 0; cpu < hwrpb->nr_processors; cpu++) {
+		pcpu = (struct percpu_struct *)
+			((unsigned long)hwrpb + hwrpb->processor_offset 
+			 + cpu * hwrpb->processor_size);
+		if (pcpu->console_data_log_pa)
+			cdl_process_console_data_log(cpu, pcpu);
+	}
+
+}
+
+int __init
+cdl_register_subpacket_annotation(struct el_subpacket_annotation *new)
+{
+	struct el_subpacket_annotation *a = subpacket_annotation_list;
+
+	if (a == NULL) subpacket_annotation_list = new;
+	else {
+		for (; a->next != NULL; a = a->next) {
+			if ((a->class == new->class && a->type == new->type) ||
+			    a == new) {
+				printk("Attempted to re-register "
+				       "subpacket annotation\n");
+				return -EINVAL;
+			}
+		}
+		a->next = new;
+	}
+	new->next = NULL;
+
+	return 0;
+}
+
+int __init
+cdl_register_subpacket_handler(struct el_subpacket_handler *new)
+{
+	struct el_subpacket_handler *h = subpacket_handler_list;
+
+	if (h == NULL) subpacket_handler_list = new;
+	else {
+		for (; h->next != NULL; h = h->next) {
+			if (h->class == new->class || h == new) {
+				printk("Attempted to re-register "
+				       "subpacket handler\n");
+				return -EINVAL;
+			}
+		}
+		h->next = new;
+	}
+	new->next = NULL;
+
+	return 0;
+}
+
diff -urN linux-2.4.21-pre3/arch/alpha/kernel/err_impl.h linux-2.4.21-pre4/arch/alpha/kernel/err_impl.h
--- linux-2.4.21-pre3/arch/alpha/kernel/err_impl.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/arch/alpha/kernel/err_impl.h	Tue Jan 28 19:44:28 2003
@@ -0,0 +1,162 @@
+/*
+ *	linux/arch/alpha/kernel/err_impl.h
+ *
+ *	Copyright (C) 2000 Jeff Wiedemeier (Compaq Computer Corporation)
+ *
+ *	Contains declarations and macros to support Alpha error handling
+ * 	implementations.
+ */
+
+/*
+ * SCB Vector definitions
+ */
+#define SCB_Q_SYSERR	0x620
+#define SCB_Q_PROCERR	0x630
+#define SCB_Q_SYSMCHK	0x660
+#define SCB_Q_PROCMCHK	0x670
+#define SCB_Q_SYSEVENT	0x680
+
+/*
+ * Disposition definitions for logout frame parser
+ */
+#define MCHK_DISPOSITION_UNKNOWN_ERROR		0x00
+#define MCHK_DISPOSITION_REPORT			0x01
+#define MCHK_DISPOSITION_DISMISS		0x02
+
+/*
+ * Error Log definitions
+ */
+/*
+ * Types
+ */
+
+#define EL_CLASS__TERMINATION		(0)
+#  define EL_TYPE__TERMINATION__TERMINATION		(0)
+#define EL_CLASS__HEADER		(5)
+#  define EL_TYPE__HEADER__SYSTEM_ERROR_FRAME		(1)
+#  define EL_TYPE__HEADER__SYSTEM_EVENT_FRAME		(2)
+#  define EL_TYPE__HEADER__HALT_FRAME			(3)
+#  define EL_TYPE__HEADER__LOGOUT_FRAME			(19)
+#define EL_CLASS__GENERAL_NOTIFICATION	(9)
+#define EL_CLASS__PCI_ERROR_FRAME	(11)
+#define EL_CLASS__REGATTA_FAMILY	(12)
+#  define EL_TYPE__REGATTA__PROCESSOR_ERROR_FRAME	(1)
+#  define EL_TYPE__REGATTA__SYSTEM_ERROR_FRAME		(2)
+#  define EL_TYPE__REGATTA__ENVIRONMENTAL_FRAME		(3)
+#  define EL_TYPE__REGATTA__TITAN_PCHIP0_EXTENDED	(8)
+#  define EL_TYPE__REGATTA__TITAN_PCHIP1_EXTENDED	(9)
+#  define EL_TYPE__REGATTA__TITAN_MEMORY_EXTENDED	(10)
+#  define EL_TYPE__REGATTA__PROCESSOR_DBL_ERROR_HALT	(11)
+#  define EL_TYPE__REGATTA__SYSTEM_DBL_ERROR_HALT	(12)
+#define EL_CLASS__PAL                   (14)
+#  define EL_TYPE__PAL__LOGOUT_FRAME                    (1)
+#  define EL_TYPE__PAL__EV7_PROCESSOR			(4)
+#  define EL_TYPE__PAL__EV7_ZBOX			(5)
+#  define EL_TYPE__PAL__EV7_RBOX			(6)
+#  define EL_TYPE__PAL__EV7_IO				(7)
+
+union el_timestamp {
+	struct {
+		u8 second;
+		u8 minute;
+		u8 hour;
+		u8 day;
+		u8 month;
+		u8 year;
+	} b;
+	u64 as_int;
+};
+
+struct el_subpacket {
+	u16 length;		/* length of header (in bytes)	*/
+	u16 class;		/* header class and type...   	*/
+	u16 type;		/* ...determine content     	*/
+	u16 revision;		/* header revision 		*/
+	union {
+		struct {	/* Class 5, Type 1 - System Error	*/
+			u32 frame_length;
+			u32 frame_packet_count;			
+		} sys_err;			
+		struct {	/* Class 5, Type 2 - System Event 	*/
+			union el_timestamp timestamp;
+			u32 frame_length;
+			u32 frame_packet_count;			
+		} sys_event;
+		struct {	/* Class 5, Type 3 - Double Error Halt	*/
+			u16 halt_code;
+			u16 reserved;
+			union el_timestamp timestamp;
+			u32 frame_length;
+			u32 frame_packet_count;
+		} err_halt;
+		struct {	/* Clasee 5, Type 19 - Logout Frame Header */
+			u32 frame_length;
+			u32 frame_flags;
+			u32 cpu_offset;	
+			u32 system_offset;
+		} logout_header;
+		struct {	/* Class 12 - Regatta			*/
+			u64 cpuid;
+			u64 data_start[1];
+		} regatta_frame;
+		struct {	/* Raw 				        */
+			u64 data_start[1];
+		} raw;
+	} by_type;
+};
+
+struct el_subpacket_annotation {
+	struct el_subpacket_annotation *next;
+	u16 class;
+	u16 type;
+	u16 revision;
+	char *description;
+	char **annotation;
+};
+#define SUBPACKET_ANNOTATION(c, t, r, d, a) {NULL, (c), (t), (r), (d), (a)}
+
+struct el_subpacket_handler {
+	struct el_subpacket_handler *next;
+	u16 class;
+	struct el_subpacket *(*handler)(struct el_subpacket *);
+};
+#define SUBPACKET_HANDLER_INIT(c, h) {NULL, (c), (h)}
+
+/*
+ * Extract a field from a register given it's name. defines
+ * for the LSB (__S - shift count) and bitmask (__M) are required
+ */
+#define EXTRACT(u, f) (((u) >> f##__S) & f##__M)
+
+/*
+ * err_common.c
+ */
+extern char *err_print_prefix;
+
+extern void mchk_dump_mem(void *, size_t, char **);
+extern void mchk_dump_logout_frame(struct el_common *);
+extern void ev7_register_error_handlers(void);
+extern void ev7_machine_check(u64, u64, struct pt_regs *);
+extern void ev6_register_error_handlers(void);
+extern int ev6_process_logout_frame(struct el_common *, int);
+extern void ev6_machine_check(u64, u64, struct pt_regs *);
+extern struct el_subpacket *el_process_subpacket(struct el_subpacket *);
+extern void el_annotate_subpacket(struct el_subpacket *);
+extern void cdl_check_console_data_log(void);
+extern int cdl_register_subpacket_annotation(struct el_subpacket_annotation *);
+extern int cdl_register_subpacket_handler(struct el_subpacket_handler *);
+
+/*
+ * err_marvel.c
+ */
+extern void marvel_machine_check(u64, u64, struct pt_regs *);
+extern void marvel_register_error_handlers(void);
+
+/*
+ * err_titan.c
+ */
+extern int titan_process_logout_frame(struct el_common *, int);
+extern void titan_machine_check(u64, u64, struct pt_regs *);
+extern void titan_register_error_handlers(void);
+extern int privateer_process_logout_frame(struct el_common *, int);
+extern void privateer_machine_check(u64, u64, struct pt_regs *);
diff -urN linux-2.4.21-pre3/arch/alpha/kernel/err_marvel.c linux-2.4.21-pre4/arch/alpha/kernel/err_marvel.c
--- linux-2.4.21-pre3/arch/alpha/kernel/err_marvel.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/arch/alpha/kernel/err_marvel.c	Tue Jan 28 19:44:28 2003
@@ -0,0 +1,57 @@
+/*
+ *	linux/arch/alpha/kernel/err_marvel.c
+ *
+ *	Copyright (C) 2001 Jeff Wiedemeier (Compaq Computer Corporation)
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+
+#include <asm/io.h>
+#include <asm/console.h>
+#include <asm/core_marvel.h>
+#include <asm/hwrpb.h>
+#include <asm/smp.h>
+
+#include "err_impl.h"
+#include "proto.h"
+
+
+void
+marvel_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs)
+{
+	struct el_subpacket *el_ptr = (struct el_subpacket *)la_ptr;
+
+	/*
+	 * Sync the processor
+	 */
+	mb();
+	draina();
+
+	el_process_subpacket(el_ptr);
+
+	switch(vector) {
+	case SCB_Q_SYSEVENT:
+		printk(KERN_CRIT "MARVEL SYSEVENT %ld\n", vector);
+		break;
+	case SCB_Q_SYSMCHK:
+	case SCB_Q_SYSERR:
+		printk(KERN_CRIT "MARVEL SYSMCHK/ERR %ld\n", vector);
+		break;
+	default:
+		/* Don't know it - pass it up.  */
+		return ev7_machine_check(vector, la_ptr, regs);
+	}	
+
+        /* Release the logout frame.  */
+	wrmces(0x7);
+	mb();
+}
+
+void
+marvel_register_error_handlers(void)
+{
+	ev7_register_error_handlers();
+}
diff -urN linux-2.4.21-pre3/arch/alpha/kernel/err_titan.c linux-2.4.21-pre4/arch/alpha/kernel/err_titan.c
--- linux-2.4.21-pre3/arch/alpha/kernel/err_titan.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/arch/alpha/kernel/err_titan.c	Tue Jan 28 19:44:28 2003
@@ -0,0 +1,747 @@
+/*
+ *	linux/arch/alpha/kernel/err_titan.c
+ *
+ *	Copyright (C) 2000 Jeff Wiedemeier (Compaq Computer Corporation)
+ *
+ *	Error handling code supporting TITAN systems
+ */
+
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+
+#include <asm/io.h>
+#include <asm/core_titan.h>
+#include <asm/hwrpb.h>
+#include <asm/smp.h>
+
+#include "err_impl.h"
+#include "proto.h"
+
+
+static int
+titan_parse_c_misc(u64 c_misc, int print)
+{
+	char *src;
+	int nxs = 0;
+	int status = MCHK_DISPOSITION_REPORT;
+
+#define TITAN__CCHIP_MISC__NXM		(1UL << 28)
+#define TITAN__CCHIP_MISC__NXS__S	(29)
+#define TITAN__CCHIP_MISC__NXS__M	(0x7)
+
+	if (!(c_misc & TITAN__CCHIP_MISC__NXM))
+		return MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+#ifdef CONFIG_VERBOSE_MCHECK
+	if (!print)
+		return status;
+
+	nxs = EXTRACT(c_misc, TITAN__CCHIP_MISC__NXS);
+	switch(nxs) {
+	case 0:	/* CPU 0 */
+	case 1:	/* CPU 1 */
+	case 2:	/* CPU 2 */
+	case 3:	/* CPU 3 */
+		src = "CPU";
+		/* num is already the CPU number */
+		break;
+	case 4:	/* Pchip 0 */
+	case 5:	/* Pchip 1 */
+		src = "Pchip";
+		nxs -= 4;
+		break;
+	default:/* reserved */
+		src = "Unknown, NXS =";
+		/* leave num untouched */
+		break;
+	}
+
+	printk("%s    Non-existent memory access from: %s %d\n", 
+	       err_print_prefix, src, nxs);
+#endif /* CONFIG_VERBOSE_MCHECK */
+
+	return status;
+}
+
+static int
+titan_parse_p_serror(int which, u64 serror, int print)
+{
+	int status = MCHK_DISPOSITION_REPORT;
+
+#ifdef CONFIG_VERBOSE_MCHECK
+	char *serror_src[] = {"GPCI", "APCI", "AGP HP", "AGP LP"};
+	char *serror_cmd[] = {"DMA Read", "DMA RMW", "SGTE Read", "Reserved"};
+#endif /* CONFIG_VERBOSE_MCHECK */
+
+#define TITAN__PCHIP_SERROR__LOST_UECC	(1UL << 0)
+#define TITAN__PCHIP_SERROR__UECC	(1UL << 1)
+#define TITAN__PCHIP_SERROR__CRE	(1UL << 2)
+#define TITAN__PCHIP_SERROR__NXIO	(1UL << 3)
+#define TITAN__PCHIP_SERROR__LOST_CRE	(1UL << 4)
+#define TITAN__PCHIP_SERROR__ECCMASK	(TITAN__PCHIP_SERROR__UECC |	  \
+					 TITAN__PCHIP_SERROR__CRE)
+#define TITAN__PCHIP_SERROR__ERRMASK	(TITAN__PCHIP_SERROR__LOST_UECC | \
+					 TITAN__PCHIP_SERROR__UECC |	  \
+					 TITAN__PCHIP_SERROR__CRE |	  \
+					 TITAN__PCHIP_SERROR__NXIO |	  \
+					 TITAN__PCHIP_SERROR__LOST_CRE)
+#define TITAN__PCHIP_SERROR__SRC__S	(52)
+#define TITAN__PCHIP_SERROR__SRC__M	(0x3)
+#define TITAN__PCHIP_SERROR__CMD__S	(54)
+#define TITAN__PCHIP_SERROR__CMD__M	(0x3)
+#define TITAN__PCHIP_SERROR__SYN__S	(56)
+#define TITAN__PCHIP_SERROR__SYN__M	(0xff)
+#define TITAN__PCHIP_SERROR__ADDR__S	(15)
+#define TITAN__PCHIP_SERROR__ADDR__M	(0xffffffffUL)
+
+	if (!(serror & TITAN__PCHIP_SERROR__ERRMASK))
+		return MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+#ifdef CONFIG_VERBOSE_MCHECK
+	if (!print)
+		return status;
+
+	printk("%s  PChip %d SERROR: %016lx\n", 
+	       err_print_prefix, which, serror);
+	if (serror & TITAN__PCHIP_SERROR__ECCMASK) {
+		printk("%s    %sorrectable ECC Error:\n"
+		       "      Source: %-6s  Command: %-8s  Syndrome: 0x%08x\n"
+		       "      Address: 0x%lx\n", 
+		       err_print_prefix,
+		       (serror & TITAN__PCHIP_SERROR__UECC) ? "Unc" : "C",
+		       serror_src[EXTRACT(serror, TITAN__PCHIP_SERROR__SRC)],
+		       serror_cmd[EXTRACT(serror, TITAN__PCHIP_SERROR__CMD)],
+		       (unsigned)EXTRACT(serror, TITAN__PCHIP_SERROR__SYN),
+		       EXTRACT(serror, TITAN__PCHIP_SERROR__ADDR));
+	}
+	if (serror & TITAN__PCHIP_SERROR__NXIO)
+		printk("%s    Non Existent I/O Error\n", err_print_prefix);
+	if (serror & TITAN__PCHIP_SERROR__LOST_UECC)
+		printk("%s    Lost Uncorrectable ECC Error\n", 
+		       err_print_prefix);
+	if (serror & TITAN__PCHIP_SERROR__LOST_CRE)
+		printk("%s    Lost Correctable ECC Error\n", err_print_prefix);
+#endif /* CONFIG_VERBOSE_MCHECK */
+
+	return status;
+}
+
+static int 
+titan_parse_p_perror(int which, int port, u64 perror, int print)
+{
+	int cmd;
+	unsigned long addr;
+	int status = MCHK_DISPOSITION_REPORT;
+
+#ifdef CONFIG_VERBOSE_MCHECK
+	char *perror_cmd[] = { "Interrupt Acknowledge", "Special Cycle",
+			       "I/O Read",	       	"I/O Write",
+			       "Reserved",	       	"Reserved",
+			       "Memory Read",		"Memory Write",
+			       "Reserved",		"Reserved",
+			       "Configuration Read",	"Configuration Write",
+			       "Memory Read Multiple",	"Dual Address Cycle",
+			       "Memory Read Line","Memory Write and Invalidate"
+	};
+#endif /* CONFIG_VERBOSE_MCHECK */
+
+#define TITAN__PCHIP_PERROR__LOST	(1UL << 0)
+#define TITAN__PCHIP_PERROR__SERR	(1UL << 1)
+#define TITAN__PCHIP_PERROR__PERR	(1UL << 2)
+#define TITAN__PCHIP_PERROR__DCRTO	(1UL << 3)
+#define TITAN__PCHIP_PERROR__SGE	(1UL << 4)
+#define TITAN__PCHIP_PERROR__APE	(1UL << 5)
+#define TITAN__PCHIP_PERROR__TA		(1UL << 6)
+#define TITAN__PCHIP_PERROR__DPE	(1UL << 7)
+#define TITAN__PCHIP_PERROR__NDS	(1UL << 8)
+#define TITAN__PCHIP_PERROR__IPTPR	(1UL << 9)
+#define TITAN__PCHIP_PERROR__IPTPW	(1UL << 10)
+#define TITAN__PCHIP_PERROR__ERRMASK	(TITAN__PCHIP_PERROR__LOST |	\
+					 TITAN__PCHIP_PERROR__SERR |	\
+					 TITAN__PCHIP_PERROR__PERR |	\
+					 TITAN__PCHIP_PERROR__DCRTO |	\
+					 TITAN__PCHIP_PERROR__SGE |	\
+					 TITAN__PCHIP_PERROR__APE |	\
+					 TITAN__PCHIP_PERROR__TA |	\
+					 TITAN__PCHIP_PERROR__DPE |	\
+					 TITAN__PCHIP_PERROR__NDS |	\
+					 TITAN__PCHIP_PERROR__IPTPR |	\
+					 TITAN__PCHIP_PERROR__IPTPW)
+#define TITAN__PCHIP_PERROR__DAC	(1UL << 47)
+#define TITAN__PCHIP_PERROR__MWIN	(1UL << 48)
+#define TITAN__PCHIP_PERROR__CMD__S	(52)
+#define TITAN__PCHIP_PERROR__CMD__M	(0x0f)
+#define TITAN__PCHIP_PERROR__ADDR__S	(14)
+#define TITAN__PCHIP_PERROR__ADDR__M	(0x1ffffffff)
+
+	if (!(perror & TITAN__PCHIP_PERROR__ERRMASK))
+		return MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+	cmd = EXTRACT(perror, TITAN__PCHIP_PERROR__CMD);
+	addr = EXTRACT(perror, TITAN__PCHIP_PERROR__ADDR) << 2;
+
+	/*
+	 * Initializing the BIOS on a video card on a bus without
+	 * a south bridge (subtractive decode agent) can result in 
+	 * master aborts as the BIOS probes the capabilities of the
+	 * card. XFree86 does such initialization. If the error
+	 * is a master abort (No DevSel as PCI Master) and the command
+	 * is an I/O read or write below the address where we start
+	 * assigning PCI I/O spaces (SRM uses 0x1000), then mark the
+	 * error as dismissable so starting XFree86 doesn't result
+	 * in a series of uncorrectable errors being reported. Also
+	 * dismiss master aborts to VGA frame buffer space
+	 * (0xA0000 - 0xC0000) and legacy BIOS space (0xC0000 - 0x100000)
+	 * for the same reason.
+	 *
+	 * Also mark the error dismissible if it looks like the right
+	 * error but only the Lost bit is set. Since the BIOS initialization
+	 * can cause multiple master aborts and the error interrupt can
+	 * be handled on a different CPU than the BIOS code is run on,
+	 * it is possible for a second master abort to occur between the
+	 * time the PALcode reads PERROR and the time it writes PERROR
+	 * to acknowledge the error. If this timing happens, a second
+	 * error will be signalled after the first, and if no additional
+	 * errors occur, will look like a Lost error with no additional 
+	 * errors on the same transaction as the previous error.
+	 */
+	if (((perror & TITAN__PCHIP_PERROR__NDS) || 
+	     ((perror & TITAN__PCHIP_PERROR__ERRMASK) == 
+	      TITAN__PCHIP_PERROR__LOST)) &&
+	    ((((cmd & 0xE) == 2) && (addr < 0x1000)) ||
+	     (((cmd & 0xE) == 6) && (addr >= 0xA0000) && (addr < 0x100000)))) {
+		status = MCHK_DISPOSITION_DISMISS;
+	}
+
+#ifdef CONFIG_VERBOSE_MCHECK
+	if (!print) 
+		return status;
+
+	printk("%s  PChip %d %cPERROR: %016lx\n", 
+	       err_print_prefix, which, 
+	       port ? 'A' : 'G', perror);
+	if (perror & TITAN__PCHIP_PERROR__IPTPW)
+		printk("%s    Invalid Peer-to-Peer Write\n", err_print_prefix);
+	if (perror & TITAN__PCHIP_PERROR__IPTPR)
+		printk("%s    Invalid Peer-to-Peer Read\n", err_print_prefix);
+	if (perror & TITAN__PCHIP_PERROR__NDS)
+		printk("%s    No DEVSEL as PCI Master [Master Abort]\n",
+		       err_print_prefix);
+	if (perror & TITAN__PCHIP_PERROR__DPE)
+		printk("%s    Data Parity Error\n", err_print_prefix);
+	if (perror & TITAN__PCHIP_PERROR__TA)
+		printk("%s    Target Abort\n", err_print_prefix);
+	if (perror & TITAN__PCHIP_PERROR__APE)
+		printk("%s    Address Parity Error\n", err_print_prefix);
+	if (perror & TITAN__PCHIP_PERROR__SGE)
+		printk("%s    Scatter-Gather Error, Invalid PTE\n", 
+		       err_print_prefix);
+	if (perror & TITAN__PCHIP_PERROR__DCRTO)
+		printk("%s    Delayed-Completion Retry Timeout\n", 
+		       err_print_prefix);
+	if (perror & TITAN__PCHIP_PERROR__PERR)
+		printk("%s    PERR Asserted\n", err_print_prefix);
+	if (perror & TITAN__PCHIP_PERROR__SERR)
+		printk("%s    SERR Asserted\n", err_print_prefix);
+	if (perror & TITAN__PCHIP_PERROR__LOST)
+		printk("%s    Lost Error\n", err_print_prefix);
+	printk("%s      Command: 0x%x - %s\n"
+		 "      Address: 0x%lx\n",
+	       err_print_prefix,
+	       cmd, perror_cmd[cmd],
+	       addr);
+	if (perror & TITAN__PCHIP_PERROR__DAC)
+		printk("%s      Dual Address Cycle\n", err_print_prefix);
+	if (perror & TITAN__PCHIP_PERROR__MWIN)
+		printk("%s      Hit in Monster Window\n", err_print_prefix);
+#endif /* CONFIG_VERBOSE_MCHECK */
+
+	return status;
+}
+
+static int
+titan_parse_p_agperror(int which, u64 agperror, int print)
+{
+	int cmd, len;
+	unsigned long addr;
+	int status = MCHK_DISPOSITION_REPORT;
+
+#ifdef CONFIG_VERBOSE_MCHECK
+	char *agperror_cmd[] = { "Read (low-priority)",	"Read (high-priority)",
+				 "Write (low-priority)",
+				 "Write (high-priority)",
+				 "Reserved",		"Reserved",
+				 "Flush",		"Fence"
+	};
+#endif /* CONFIG_VERBOSE_MCHECK */
+
+#define TITAN__PCHIP_AGPERROR__LOST	(1UL << 0)
+#define TITAN__PCHIP_AGPERROR__LPQFULL	(1UL << 1)
+#define TITAN__PCHIP_AGPERROR__HPQFULL	(1UL << 2)
+#define TITAN__PCHIP_AGPERROR__RESCMD	(1UL << 3)
+#define TITAN__PCHIP_AGPERROR__IPTE	(1UL << 4)
+#define TITAN__PCHIP_AGPERROR__PTP	(1UL << 5)
+#define TITAN__PCHIP_AGPERROR__NOWINDOW	(1UL << 6)
+#define TITAN__PCHIP_AGPERROR__ERRMASK	(TITAN__PCHIP_AGPERROR__LOST |    \
+					 TITAN__PCHIP_AGPERROR__LPQFULL | \
+					 TITAN__PCHIP_AGPERROR__HPQFULL | \
+					 TITAN__PCHIP_AGPERROR__RESCMD |  \
+					 TITAN__PCHIP_AGPERROR__IPTE |    \
+					 TITAN__PCHIP_AGPERROR__PTP |     \
+					 TITAN__PCHIP_AGPERROR__NOWINDOW)
+#define TITAN__PCHIP_AGPERROR__DAC	(1UL << 48)
+#define TITAN__PCHIP_AGPERROR__MWIN	(1UL << 49)
+#define TITAN__PCHIP_AGPERROR__FENCE	(1UL << 59)
+#define TITAN__PCHIP_AGPERROR__CMD__S	(50)
+#define TITAN__PCHIP_AGPERROR__CMD__M	(0x07)
+#define TITAN__PCHIP_AGPERROR__ADDR__S	(15)
+#define TITAN__PCHIP_AGPERROR__ADDR__M  (0xffffffffUL)
+#define TITAN__PCHIP_AGPERROR__LEN__S	(53)
+#define TITAN__PCHIP_AGPERROR__LEN__M	(0x3f)
+
+	if (!(agperror & TITAN__PCHIP_AGPERROR__ERRMASK))
+		return MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+#ifdef CONFIG_VERBOSE_MCHECK
+	if (!print)
+		return status;
+
+	cmd = EXTRACT(agperror, TITAN__PCHIP_AGPERROR__CMD);
+	addr = EXTRACT(agperror, TITAN__PCHIP_AGPERROR__ADDR) << 3;
+	len = EXTRACT(agperror, TITAN__PCHIP_AGPERROR__LEN);
+
+	printk("%s  PChip %d AGPERROR: %016lx\n", err_print_prefix,
+	       which, agperror);
+	if (agperror & TITAN__PCHIP_AGPERROR__NOWINDOW)
+		printk("%s    No Window\n", err_print_prefix);
+	if (agperror & TITAN__PCHIP_AGPERROR__PTP)
+		printk("%s    Peer-to-Peer set\n", err_print_prefix);
+	if (agperror & TITAN__PCHIP_AGPERROR__IPTE)
+		printk("%s    Invalid PTE\n", err_print_prefix);
+	if (agperror & TITAN__PCHIP_AGPERROR__RESCMD)
+		printk("%s    Reserved Command\n", err_print_prefix);
+	if (agperror & TITAN__PCHIP_AGPERROR__HPQFULL)
+		printk("%s    HP Transaction Received while Queue Full\n", 
+		       err_print_prefix);
+	if (agperror & TITAN__PCHIP_AGPERROR__LPQFULL)
+		printk("%s    LP Transaction Received while Queue Full\n", 
+		       err_print_prefix);
+	if (agperror & TITAN__PCHIP_AGPERROR__LOST)
+		printk("%s    Lost Error\n", err_print_prefix);
+	printk("%s      Command: 0x%x - %s, %d Quadwords%s\n"
+		 "      Address: 0x%lx\n",
+	       err_print_prefix, cmd, agperror_cmd[cmd], len,
+	       (agperror & TITAN__PCHIP_AGPERROR__FENCE) ? ", FENCE" : "",
+	       addr);
+	if (agperror & TITAN__PCHIP_AGPERROR__DAC)
+		printk("%s      Dual Address Cycle\n", err_print_prefix);
+	if (agperror & TITAN__PCHIP_AGPERROR__MWIN)
+		printk("%s      Hit in Monster Window\n", err_print_prefix);
+#endif /* CONFIG_VERBOSE_MCHECK */
+
+	return status;
+}	
+
+static int
+titan_parse_p_chip(int which, u64 serror, u64 gperror, 
+		   u64 aperror, u64 agperror, int print)
+{
+	int status = MCHK_DISPOSITION_UNKNOWN_ERROR;
+	status |= titan_parse_p_serror(which, serror, print);
+	status |= titan_parse_p_perror(which, 0, gperror, print);
+	status |= titan_parse_p_perror(which, 1, aperror, print);
+	status |= titan_parse_p_agperror(which, agperror, print);
+	return status;
+}
+
+int
+titan_process_logout_frame(struct el_common *mchk_header, int print)
+{
+	struct el_TITAN_sysdata_mcheck *tmchk =
+		(struct el_TITAN_sysdata_mcheck *)
+		((unsigned long)mchk_header + mchk_header->sys_offset);
+	int status = MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+	status |= titan_parse_c_misc(tmchk->c_misc, print);
+	status |= titan_parse_p_chip(0, tmchk->p0_serror, tmchk->p0_gperror,
+				     tmchk->p0_aperror, tmchk->p0_agperror, 
+				     print);
+	status |= titan_parse_p_chip(1, tmchk->p1_serror, tmchk->p1_gperror,
+				     tmchk->p1_aperror, tmchk->p1_agperror, 
+				     print);
+
+	return status;
+}
+
+void
+titan_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs)
+{
+	struct el_common *mchk_header = (struct el_common *)la_ptr;
+	struct el_TITAN_sysdata_mcheck *tmchk =
+		(struct el_TITAN_sysdata_mcheck *)
+		((unsigned long)mchk_header + mchk_header->sys_offset);
+	u64 irqmask;
+
+	/*
+	 * Mask of Titan interrupt sources which are reported as machine checks
+	 *
+	 * 63 - CChip Error
+	 * 62 - PChip 0 H_Error
+	 * 61 - PChip 1 H_Error
+	 * 60 - PChip 0 C_Error
+	 * 59 - PChip 1 C_Error
+	 */
+#define TITAN_MCHECK_INTERRUPT_MASK	0xF800000000000000UL
+
+	/*
+	 * Sync the processor
+	 */
+	mb();
+	draina();
+	
+	/*
+	 * Only handle system errors here 
+	 */
+	if ((vector != SCB_Q_SYSMCHK) && (vector != SCB_Q_SYSERR)) 
+		return ev6_machine_check(vector, la_ptr, regs);
+
+	/* 
+	 * It's a system error, handle it here
+	 *
+	 * The PALcode has already cleared the error, so just parse it
+	 */
+	
+	/* 
+	 * Parse the logout frame without printing first. If the only error(s)
+	 * found are classified as "dismissable", then just dismiss them and
+	 * don't print any message
+	 */
+	if (titan_process_logout_frame(mchk_header, 0) != 
+	    MCHK_DISPOSITION_DISMISS) {
+		char *saved_err_prefix = err_print_prefix;
+		err_print_prefix = KERN_CRIT;
+
+		/*
+		 * Either a nondismissable error was detected or no
+		 * recognized error was detected  in the logout frame 
+		 * -- report the error in either case
+		 */
+		printk("%s"
+		       "*System %s Error (Vector 0x%x) reported on CPU %d:\n", 
+		       err_print_prefix,
+		       (vector == SCB_Q_SYSERR)?"Correctable":"Uncorrectable",
+		       (unsigned int)vector, (int)smp_processor_id());
+		
+#ifdef CONFIG_VERBOSE_MCHECK
+		titan_process_logout_frame(mchk_header, 1);
+		dik_show_regs(regs, NULL);
+#endif /* CONFIG_VERBOSE_MCHECK */
+
+		err_print_prefix = saved_err_prefix;
+
+		/*
+		 * Convert any pending interrupts which report as system
+		 * machine checks to interrupts
+		 */
+		irqmask = tmchk->c_dirx & TITAN_MCHECK_INTERRUPT_MASK;
+		titan_dispatch_irqs(irqmask, regs);
+	}	
+
+
+	/* 
+	 * Release the logout frame 
+	 */
+	wrmces(0x7);
+	mb();
+}
+
+/*
+ * Subpacket Annotations
+ */
+static char *el_titan_pchip0_extended_annotation[] = {
+	"Subpacket Header", 	"P0_SCTL",	"P0_SERREN",
+	"P0_APCTL",		"P0_APERREN",	"P0_AGPERREN",
+	"P0_ASPRST",		"P0_AWSBA0",	"P0_AWSBA1",
+	"P0_AWSBA2",		"P0_AWSBA3",	"P0_AWSM0",
+	"P0_AWSM1",		"P0_AWSM2",	"P0_AWSM3",
+	"P0_ATBA0",		"P0_ATBA1",	"P0_ATBA2",
+	"P0_ATBA3",		"P0_GPCTL",	"P0_GPERREN",
+	"P0_GSPRST",		"P0_GWSBA0",	"P0_GWSBA1",
+	"P0_GWSBA2",		"P0_GWSBA3",	"P0_GWSM0",
+	"P0_GWSM1",		"P0_GWSM2",	"P0_GWSM3",
+	"P0_GTBA0",		"P0_GTBA1",	"P0_GTBA2",
+	"P0_GTBA3",		NULL 
+};
+static char *el_titan_pchip1_extended_annotation[] = {
+	"Subpacket Header", 	"P1_SCTL",	"P1_SERREN",
+	"P1_APCTL",		"P1_APERREN",	"P1_AGPERREN",
+	"P1_ASPRST",		"P1_AWSBA0",	"P1_AWSBA1",
+	"P1_AWSBA2",		"P1_AWSBA3",	"P1_AWSM0",
+	"P1_AWSM1",		"P1_AWSM2",	"P1_AWSM3",
+	"P1_ATBA0",		"P1_ATBA1",	"P1_ATBA2",
+	"P1_ATBA3",		"P1_GPCTL",	"P1_GPERREN",
+	"P1_GSPRST",		"P1_GWSBA0",	"P1_GWSBA1",
+	"P1_GWSBA2",		"P1_GWSBA3",	"P1_GWSM0",
+	"P1_GWSM1",		"P1_GWSM2",	"P1_GWSM3",
+	"P1_GTBA0",		"P1_GTBA1",	"P1_GTBA2",
+	"P1_GTBA3",		NULL 
+};
+static char *el_titan_memory_extended_annotation[] = {
+	"Subpacket Header", 	"AAR0",		"AAR1",
+	"AAR2",			"AAR3",		"P0_SCTL",
+	"P0_GPCTL",		"P0_APCTL",	"P1_SCTL",
+	"P1_GPCTL",		"P1_SCTL",	NULL 
+};
+
+static struct el_subpacket_annotation el_titan_annotations[] = {
+	SUBPACKET_ANNOTATION(EL_CLASS__REGATTA_FAMILY,
+			     EL_TYPE__REGATTA__TITAN_PCHIP0_EXTENDED,
+			     1,
+			     "Titan PChip 0 Extended Frame",
+			     el_titan_pchip0_extended_annotation),
+	SUBPACKET_ANNOTATION(EL_CLASS__REGATTA_FAMILY,
+			     EL_TYPE__REGATTA__TITAN_PCHIP1_EXTENDED,
+			     1,
+			     "Titan PChip 1 Extended Frame",
+			     el_titan_pchip1_extended_annotation),
+	SUBPACKET_ANNOTATION(EL_CLASS__REGATTA_FAMILY,
+			     EL_TYPE__REGATTA__TITAN_MEMORY_EXTENDED,
+			     1,
+			     "Titan Memory Extended Frame",
+			     el_titan_memory_extended_annotation),
+	SUBPACKET_ANNOTATION(EL_CLASS__REGATTA_FAMILY,
+			     EL_TYPE__TERMINATION__TERMINATION,
+			     1,
+			     "Termination Subpacket",
+			     NULL)
+};
+
+static struct el_subpacket *
+el_process_regatta_subpacket(struct el_subpacket *header)
+{
+	int status;
+
+	if (header->class != EL_CLASS__REGATTA_FAMILY) {
+		printk("%s  ** Unexpected header CLASS %d TYPE %d, aborting\n",
+		       err_print_prefix,
+		       header->class, header->type);
+		return NULL;
+	}
+
+	switch(header->type) {
+	case EL_TYPE__REGATTA__PROCESSOR_ERROR_FRAME:
+	case EL_TYPE__REGATTA__SYSTEM_ERROR_FRAME:
+	case EL_TYPE__REGATTA__ENVIRONMENTAL_FRAME:
+	case EL_TYPE__REGATTA__PROCESSOR_DBL_ERROR_HALT:
+	case EL_TYPE__REGATTA__SYSTEM_DBL_ERROR_HALT:
+		printk("%s  ** Occurred on CPU %d:\n", 
+		       err_print_prefix,
+		       (int)header->by_type.regatta_frame.cpuid);
+		status = privateer_process_logout_frame((struct el_common *)
+			header->by_type.regatta_frame.data_start, 1);
+		break;
+	default:
+		printk("%s  ** REGATTA TYPE %d SUBPACKET\n", 
+		       err_print_prefix, header->type);
+		el_annotate_subpacket(header);
+		break;
+	}
+
+
+	return (struct el_subpacket *)((unsigned long)header + header->length);
+} 
+
+static struct el_subpacket_handler titan_subpacket_handler = 
+	SUBPACKET_HANDLER_INIT(EL_CLASS__REGATTA_FAMILY, 
+			       el_process_regatta_subpacket);
+
+void
+titan_register_error_handlers(void)
+{
+	size_t i;
+
+	for (i = 0; i < ARRAY_SIZE (el_titan_annotations); i++)
+		cdl_register_subpacket_annotation(&el_titan_annotations[i]);
+
+	cdl_register_subpacket_handler(&titan_subpacket_handler);
+}
+
+
+/*
+ * Privateer
+ */
+
+static int
+privateer_process_680_frame(struct el_common *mchk_header, int print)
+{
+	struct el_PRIVATEER_envdata_mcheck *emchk =
+		(struct el_PRIVATEER_envdata_mcheck *)
+		((unsigned long)mchk_header + mchk_header->sys_offset);
+	int status = MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+	/* TODO - catagorize errors, for now, no error */
+
+#ifdef CONFIG_VERBOSE_MCHECK
+	if (!print)
+		return status;
+
+	/* TODO - decode instead of just dumping... */
+	printk("%s  Summary Flags:         %016lx\n"
+ 	         "  CChip DIRx:            %016lx\n"
+		 "  System Management IR:  %016lx\n"
+		 "  CPU IR:                %016lx\n"
+		 "  Power Supply IR:       %016lx\n"
+		 "  LM78 Fault Status:     %016lx\n"
+		 "  System Doors:          %016lx\n"
+		 "  Temperature Warning:   %016lx\n"
+		 "  Fan Control:           %016lx\n"
+		 "  Fatal Power Down Code: %016lx\n",
+	       err_print_prefix,
+	       emchk->summary,
+	       emchk->c_dirx,
+	       emchk->smir,
+	       emchk->cpuir,
+	       emchk->psir,
+	       emchk->fault,
+	       emchk->sys_doors,
+	       emchk->temp_warn,
+	       emchk->fan_ctrl,
+	       emchk->code);
+#endif /* CONFIG_VERBOSE_MCHECK */
+
+	return status;
+}
+
+int
+privateer_process_logout_frame(struct el_common *mchk_header, int print)
+{
+	struct el_common_EV6_mcheck *ev6mchk = 
+		(struct el_common_EV6_mcheck *)mchk_header;
+	int status = MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+	/*
+	 * Machine check codes
+	 */
+#define PRIVATEER_MCHK__CORR_ECC		0x86	/* 630 */
+#define PRIVATEER_MCHK__DC_TAG_PERR		0x9E	/* 630 */
+#define PRIVATEER_MCHK__PAL_BUGCHECK		0x8E	/* 670 */
+#define PRIVATEER_MCHK__OS_BUGCHECK		0x90	/* 670 */
+#define PRIVATEER_MCHK__PROC_HRD_ERR		0x98	/* 670 */
+#define PRIVATEER_MCHK__ISTREAM_CMOV_PRX	0xA0	/* 670 */
+#define PRIVATEER_MCHK__ISTREAM_CMOV_FLT	0xA2	/* 670 */
+#define PRIVATEER_MCHK__SYS_HRD_ERR		0x202	/* 660 */
+#define PRIVATEER_MCHK__SYS_CORR_ERR		0x204	/* 620 */
+#define PRIVATEER_MCHK__SYS_ENVIRON		0x206	/* 680 */
+
+	switch(ev6mchk->MCHK_Code) {
+	/*
+	 * Vector 630 - Processor, Correctable
+	 */
+	case PRIVATEER_MCHK__CORR_ECC:
+	case PRIVATEER_MCHK__DC_TAG_PERR:
+		/*
+		 * Fall through to vector 670 for processing...
+		 */
+	/*
+	 * Vector 670 - Processor, Uncorrectable
+	 */
+	case PRIVATEER_MCHK__PAL_BUGCHECK:
+	case PRIVATEER_MCHK__OS_BUGCHECK:
+	case PRIVATEER_MCHK__PROC_HRD_ERR:
+	case PRIVATEER_MCHK__ISTREAM_CMOV_PRX:
+	case PRIVATEER_MCHK__ISTREAM_CMOV_FLT:
+		status |= ev6_process_logout_frame(mchk_header, print);
+		break;
+
+	/*
+	 * Vector 620 - System, Correctable
+	 */
+	case PRIVATEER_MCHK__SYS_CORR_ERR:
+		/*
+		 * Fall through to vector 660 for processing...
+		 */
+	/*
+	 * Vector 660 - System, Uncorrectable
+	 */
+	case PRIVATEER_MCHK__SYS_HRD_ERR:
+		status |= titan_process_logout_frame(mchk_header, print);
+		break;
+
+	/* 
+	 * Vector 680 - System, Environmental
+	 */
+	case PRIVATEER_MCHK__SYS_ENVIRON:	/* System, Environmental */
+		status |= privateer_process_680_frame(mchk_header, print);
+		break;
+
+	/* 
+	 * Unknown
+	 */
+	default:
+		status |= MCHK_DISPOSITION_REPORT;
+		if (print) {
+			printk("%s** Unknown Error, frame follows\n", 
+			       err_print_prefix);
+			mchk_dump_logout_frame(mchk_header);
+		}
+
+	}
+
+	return status;
+}
+
+void
+privateer_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs)
+{
+	struct el_common *mchk_header = (struct el_common *)la_ptr;
+	struct el_TITAN_sysdata_mcheck *tmchk =
+		(struct el_TITAN_sysdata_mcheck *)
+		(la_ptr + mchk_header->sys_offset);
+	u64 irqmask;
+	char *saved_err_prefix = err_print_prefix;
+
+#define PRIVATEER_680_INTERRUPT_MASK		(0xE00UL)
+#define PRIVATEER_HOTPLUG_INTERRUPT_MASK	(0xE00UL)
+
+	/*
+	 * Sync the processor.
+	 */
+	mb();
+	draina();
+
+	/* 
+	 * Only handle system events here.
+	 */
+	if (vector != SCB_Q_SYSEVENT) 
+		return titan_machine_check(vector, la_ptr, regs);
+
+	/*
+	 * Report the event - System Events should be reported even if no
+	 * error is indicated since the event could indicate the return
+	 * to normal status.
+	 */
+	err_print_prefix = KERN_CRIT;
+	printk("%s*System Event (Vector 0x%x) reported on CPU %d:\n", 
+	       err_print_prefix,
+	       (unsigned int)vector, (int)smp_processor_id());
+	privateer_process_680_frame(mchk_header, 1);
+	err_print_prefix = saved_err_prefix;
+	
+	/* 
+	 * Convert any pending interrupts which report as 680 machine
+	 * checks to interrupts.
+	 */
+	irqmask = tmchk->c_dirx & PRIVATEER_680_INTERRUPT_MASK;
+
+	/*
+	 * Dispatch the interrupt(s).
+	 */
+	titan_dispatch_irqs(irqmask, regs);
+
+	/* 
+	 * Release the logout frame.
+	 */
+	wrmces(0x7);
+	mb();
+}
diff -urN linux-2.4.21-pre3/arch/alpha/kernel/gct.c linux-2.4.21-pre4/arch/alpha/kernel/gct.c
--- linux-2.4.21-pre3/arch/alpha/kernel/gct.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/arch/alpha/kernel/gct.c	Tue Jan 28 19:44:28 2003
@@ -0,0 +1,48 @@
+/*
+ *	linux/arch/alpha/kernel/gct.c
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+
+#include <asm/hwrpb.h>
+#include <asm/gct.h>
+
+int
+gct6_find_nodes(gct6_node *node, gct6_search_struct *search)
+{
+	gct6_search_struct *wanted;
+	int status = 0;
+
+	/* First check the magic number.  */
+	if (node->magic != GCT_NODE_MAGIC) {
+		printk(KERN_ERR "GCT Node MAGIC incorrect - GCT invalid\n");
+		return -EINVAL;
+	}
+
+	/* Check against the search struct.  */
+	for (wanted = search; 
+	     wanted && (wanted->type | wanted->subtype); 
+	     wanted++) {
+		if (node->type != wanted->type)
+			continue;
+		if (node->subtype != wanted->subtype)
+			continue;
+
+		/* Found it -- call out.  */
+		if (wanted->callout)
+			wanted->callout(node);
+	}
+
+	/* Now walk the tree, siblings first.  */
+	if (node->next) 
+		status |= gct6_find_nodes(GCT_NODE_PTR(node->next), search);
+
+	/* Then the children.  */
+	if (node->child) 
+		status |= gct6_find_nodes(GCT_NODE_PTR(node->child), search);
+
+	return status;
+}
diff -urN linux-2.4.21-pre3/arch/alpha/kernel/irq.c linux-2.4.21-pre4/arch/alpha/kernel/irq.c
--- linux-2.4.21-pre3/arch/alpha/kernel/irq.c	Mon Sep 17 13:16:30 2001
+++ linux-2.4.21-pre4/arch/alpha/kernel/irq.c	Tue Jan 28 19:44:28 2003
@@ -374,15 +374,17 @@
 	irq_dir[irq] = proc_mkdir(name, root_irq_dir);
 
 #ifdef CONFIG_SMP
-	/* create /proc/irq/1234/smp_affinity */
-	entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]);
+	if (irq_desc[irq].handler->set_affinity) {
+		/* create /proc/irq/1234/smp_affinity */
+		entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]);
+
+		entry->nlink = 1;
+		entry->data = (void *)(long)irq;
+		entry->read_proc = irq_affinity_read_proc;
+		entry->write_proc = irq_affinity_write_proc;
 
-	entry->nlink = 1;
-	entry->data = (void *)(long)irq;
-	entry->read_proc = irq_affinity_read_proc;
-	entry->write_proc = irq_affinity_write_proc;
-
-	smp_affinity_entry[irq] = entry;
+		smp_affinity_entry[irq] = entry;
+	}
 #endif
 }
 
@@ -410,12 +412,16 @@
 #endif
 
 	/*
-	 * Create entries for all existing IRQs.
+	 * Create entries for all existing IRQs. If the number of IRQs
+	 * is greater the 1/4 the total dynamic inode space for /proc,
+	 * don't pollute the inode space
 	 */
-	for (i = 0; i < NR_IRQS; i++) {
-		if (irq_desc[i].handler == &no_irq_type)
-			continue;
-		register_irq_proc(i);
+	if (ACTUAL_NR_IRQS < (PROC_NDYNAMIC / 4)) {
+		for (i = 0; i < ACTUAL_NR_IRQS; i++) {
+			if (irq_desc[i].handler == &no_irq_type)
+				continue;
+			register_irq_proc(i);
+		}
 	}
 }
 
@@ -534,7 +540,7 @@
 	*p++ = '\n';
 #endif
 
-	for (i = 0; i < NR_IRQS; i++) {
+	for (i = 0; i < ACTUAL_NR_IRQS; i++) {
 		action = irq_desc[i].action;
 		if (!action) 
 			continue;
diff -urN linux-2.4.21-pre3/arch/alpha/kernel/irq_alpha.c linux-2.4.21-pre4/arch/alpha/kernel/irq_alpha.c
--- linux-2.4.21-pre3/arch/alpha/kernel/irq_alpha.c	Thu Oct  4 18:47:08 2001
+++ linux-2.4.21-pre4/arch/alpha/kernel/irq_alpha.c	Tue Jan 28 19:44:28 2003
@@ -152,7 +152,7 @@
 
 	mchk_header = (struct el_common *)la_ptr;
 
-	printk(KERN_CRIT "%s machine check: vector=0x%lx pc=0x%lx code=0x%lx\n",
+	printk(KERN_CRIT "%s machine check: vector=0x%lx pc=0x%lx code=0x%x\n",
 	       machine, vector, regs->pc, mchk_header->code);
 
 	switch ((unsigned int) mchk_header->code) {
diff -urN linux-2.4.21-pre3/arch/alpha/kernel/machvec_impl.h linux-2.4.21-pre4/arch/alpha/kernel/machvec_impl.h
--- linux-2.4.21-pre3/arch/alpha/kernel/machvec_impl.h	Thu Sep 13 15:21:32 2001
+++ linux-2.4.21-pre4/arch/alpha/kernel/machvec_impl.h	Tue Jan 28 19:44:28 2003
@@ -9,10 +9,12 @@
 #include <linux/config.h>
 #include <asm/pgalloc.h>
 
-/* Whee.  IRONGATE, POLARIS, TSUNAMI, TITAN, and WILDFIRE don't have an HAE.
+/* Whee.  These systems don't have an HAE:
+       IRONGATE, MARVEL, POLARIS, TSUNAMI, TITAN, WILDFIRE
    Fix things up for the GENERIC kernel by defining the HAE address
    to be that of the cache. Now we can read and write it as we like.  ;-)  */
 #define IRONGATE_HAE_ADDRESS	(&alpha_mv.hae_cache)
+#define MARVEL_HAE_ADDRESS	(&alpha_mv.hae_cache)
 #define POLARIS_HAE_ADDRESS	(&alpha_mv.hae_cache)
 #define TSUNAMI_HAE_ADDRESS	(&alpha_mv.hae_cache)
 #define TITAN_HAE_ADDRESS	(&alpha_mv.hae_cache)
@@ -32,7 +34,6 @@
 #define T2_IACK_SC		1
 #define WILDFIRE_IACK_SC	1 /* FIXME */
 
-
 /*
  * Some helpful macros for filling in the blanks.
  */
@@ -63,6 +64,13 @@
 	mv_flush_tlb_current:		ev5_flush_tlb_current,		\
 	mv_flush_tlb_current_page:	ev5_flush_tlb_current_page
 
+#define DO_EV7_MMU							\
+	max_asn:			EV6_MAX_ASN,			\
+	mv_switch_mm:			ev5_switch_mm,			\
+	mv_activate_mm:			ev5_activate_mm,		\
+	mv_flush_tlb_current:		ev5_flush_tlb_current,		\
+	mv_flush_tlb_current_page:	ev5_flush_tlb_current_page
+
 #define IO_LITE(UP,low)							\
 	hae_register:		(unsigned long *) CAT(UP,_HAE_ADDRESS),	\
 	iack_sc:		CAT(UP,_IACK_SC),			\
@@ -91,6 +99,7 @@
 #define DO_CIA_IO	IO(CIA,cia)
 #define DO_IRONGATE_IO	IO(IRONGATE,irongate)
 #define DO_LCA_IO	IO(LCA,lca)
+#define DO_MARVEL_IO	IO(MARVEL,marvel)
 #define DO_MCPCIA_IO	IO(MCPCIA,mcpcia)
 #define DO_POLARIS_IO	IO(POLARIS,polaris)
 #define DO_T2_IO	IO(T2,t2)
@@ -109,6 +118,7 @@
 #define DO_CIA_BUS	BUS(cia)
 #define DO_IRONGATE_BUS	BUS(irongate)
 #define DO_LCA_BUS	BUS(lca)
+#define DO_MARVEL_BUS	BUS(marvel)
 #define DO_MCPCIA_BUS	BUS(mcpcia)
 #define DO_POLARIS_BUS	BUS(polaris)
 #define DO_T2_BUS	BUS(t2)
@@ -116,7 +126,6 @@
 #define DO_TITAN_BUS	BUS(titan)
 #define DO_WILDFIRE_BUS	BUS(wildfire)
 
-
 /*
  * In a GENERIC kernel, we have lots of these vectors floating about,
  * all but one of which we want to go away.  In a non-GENERIC kernel,
diff -urN linux-2.4.21-pre3/arch/alpha/kernel/osf_sys.c linux-2.4.21-pre4/arch/alpha/kernel/osf_sys.c
--- linux-2.4.21-pre3/arch/alpha/kernel/osf_sys.c	Fri Aug  2 17:39:42 2002
+++ linux-2.4.21-pre4/arch/alpha/kernel/osf_sys.c	Tue Jan 28 19:44:28 2003
@@ -462,13 +462,8 @@
 
 asmlinkage int osf_swapon(const char *path, int flags, int lowat, int hiwat)
 {
-	int ret;
-
 	/* for now, simply ignore lowat and hiwat... */
-	lock_kernel();
-	ret = sys_swapon(path, flags);
-	unlock_kernel();
-	return ret;
+	return sys_swapon(path, flags);
 }
 
 asmlinkage unsigned long sys_getpagesize(void)
@@ -529,18 +524,13 @@
 	unsigned long raddr;
 	long err;
 
-	lock_kernel();
 	err = sys_shmat(shmid, shmaddr, shmflg, &raddr);
-	if (err)
-		goto out;
+
 	/*
 	 * This works because all user-level addresses are
 	 * non-negative longs!
 	 */
-	err = raddr;
-out:
-	unlock_kernel();
-	return err;
+	return err ? err : (long)raddr;
 }
 
 
diff -urN linux-2.4.21-pre3/arch/alpha/kernel/pci.c linux-2.4.21-pre4/arch/alpha/kernel/pci.c
--- linux-2.4.21-pre3/arch/alpha/kernel/pci.c	Thu Nov 28 15:53:08 2002
+++ linux-2.4.21-pre4/arch/alpha/kernel/pci.c	Tue Jan 28 19:44:28 2003
@@ -41,6 +41,8 @@
 
 const char pci_hae0_name[] = "HAE0";
 
+/* Indicate whether we respect the PCI setup left by console. */
+int __initdata pci_probe_only;
 
 /*
  * The PCI controller list.
@@ -66,17 +68,6 @@
 }
 
 static void __init
-quirk_ali_ide_ports(struct pci_dev *dev)
-{
-	if (dev->resource[0].end == 0xffff)
-		dev->resource[0].end = dev->resource[0].start + 7;
-	if (dev->resource[2].end == 0xffff)
-		dev->resource[2].end = dev->resource[2].start + 7;
-	if (dev->resource[3].end == 0xffff)
-		dev->resource[3].end = dev->resource[3].start + 7;
-}
-
-static void __init
 quirk_cypress(struct pci_dev *dev)
 {
 	/* The Notorious Cy82C693 chip.  */
@@ -114,8 +105,6 @@
 	  quirk_eisa_bridge },
 	{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82378,
 	  quirk_isa_bridge },
-	{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229,
-	  quirk_ali_ide_ports },
 	{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693,
 	  quirk_cypress },
 	{ 0 }
@@ -243,10 +232,25 @@
 	struct pci_dev *dev = bus->self;
 
 	if (!dev) {
-		/* Root bus */
+		/* Root bus. */
+		u32 pci_mem_end;
+		u32 sg_base = hose->sg_pci ? hose->sg_pci->dma_base : ~0;
+		unsigned long end;
+
 		bus->resource[0] = hose->io_space;
 		bus->resource[1] = hose->mem_space;
-	}
+
+		/* Adjust hose mem_space limit to prevent PCI allocations
+		   in the iommu windows. */
+		pci_mem_end = min((u32)__direct_map_base, sg_base) - 1;
+		end = hose->mem_space->start + pci_mem_end;
+		if (hose->mem_space->end > end)
+			hose->mem_space->end = end;
+ 	} else if (pci_probe_only &&
+ 		   (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
+ 		pci_read_bridge_bases(bus);
+ 		pcibios_fixup_device_resources(dev, bus);
+	} 
 
 	for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) {
 		struct pci_dev *dev = pci_dev_b(ln);
@@ -359,6 +363,30 @@
 	pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
 }
 
+static void __init
+pcibios_claim_console_setup(void)
+{
+	struct list_head *lb;
+
+	for(lb = pci_root_buses.next; lb != &pci_root_buses; lb = lb->next) {
+		struct pci_bus *b = pci_bus_b(lb);
+		struct list_head *ld;
+
+		for (ld = b->devices.next; ld != &b->devices; ld = ld->next) {
+			struct pci_dev *dev = pci_dev_b(ld);
+			int i;
+
+			for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+				struct resource *r = &dev->resource[i];
+
+				if (r->parent || !r->start || !r->flags)
+					continue;
+				pci_claim_resource(dev, i);
+			}
+		}
+	}
+}
+
 void __init
 common_init_pci(void)
 {
@@ -376,7 +404,12 @@
 		next_busno += 1;
 	}
 
-	pci_assign_unassigned_resources();
+	if (pci_probe_only)
+		pcibios_claim_console_setup();
+	else	/* FIXME: `else' will be removed when
+		   pci_assign_unassigned_resources() is able to work
+		   correctly with [partially] allocated PCI tree. */
+		pci_assign_unassigned_resources();
 	pci_fixup_irqs(alpha_mv.pci_swizzle, alpha_mv.pci_map_irq);
 }
 
diff -urN linux-2.4.21-pre3/arch/alpha/kernel/pci_impl.h linux-2.4.21-pre4/arch/alpha/kernel/pci_impl.h
--- linux-2.4.21-pre3/arch/alpha/kernel/pci_impl.h	Tue Jan 28 19:44:23 2003
+++ linux-2.4.21-pre4/arch/alpha/kernel/pci_impl.h	Tue Jan 28 19:44:28 2003
@@ -71,6 +71,8 @@
 
 #define IRONGATE_DEFAULT_MEM_BASE ((256*8-16)*1024*1024)
 
+#define DEFAULT_AGP_APER_SIZE	(64*1024*1024)
+
 /* 
  * A small note about bridges and interrupts.  The DECchip 21050 (and
  * later) adheres to the PCI-PCI bridge specification.  This says that
@@ -150,11 +152,20 @@
 extern struct pci_controller *hose_head, **hose_tail;
 extern struct pci_controller *pci_isa_hose;
 
+/* Indicate that we trust the console to configure things properly.  */
+extern int pci_probe_only;
+
+extern unsigned long alpha_agpgart_size;
+
 extern void common_init_pci(void);
 extern u8 common_swizzle(struct pci_dev *, u8 *);
 extern struct pci_controller *alloc_pci_controller(void);
 extern struct resource *alloc_resource(void);
 
+extern struct pci_iommu_arena *iommu_arena_new_node(int,
+						    struct pci_controller *,
+					            dma_addr_t, unsigned long,
+					            unsigned long);
 extern struct pci_iommu_arena *iommu_arena_new(struct pci_controller *,
 					       dma_addr_t, unsigned long,
 					       unsigned long);
diff -urN linux-2.4.21-pre3/arch/alpha/kernel/pci_iommu.c linux-2.4.21-pre4/arch/alpha/kernel/pci_iommu.c
--- linux-2.4.21-pre3/arch/alpha/kernel/pci_iommu.c	Tue Jan 28 19:44:23 2003
+++ linux-2.4.21-pre4/arch/alpha/kernel/pci_iommu.c	Tue Jan 28 19:44:28 2003
@@ -60,8 +60,8 @@
 }
 
 struct pci_iommu_arena *
-iommu_arena_new(struct pci_controller *hose, dma_addr_t base,
-		unsigned long window_size, unsigned long align)
+iommu_arena_new_node(int nid, struct pci_controller *hose, dma_addr_t base,
+		     unsigned long window_size, unsigned long align)
 {
 	unsigned long mem_size;
 	struct pci_iommu_arena *arena;
@@ -75,9 +75,36 @@
 	if (align < mem_size)
 		align = mem_size;
 
+
+#ifdef CONFIG_DISCONTIGMEM
+
+        if (!NODE_DATA(nid) ||
+            (NULL == (arena = alloc_bootmem_node(NODE_DATA(nid),
+                                                 sizeof(*arena))))) {
+                printk("%s: couldn't allocate arena from node %d\n"
+                       "    falling back to system-wide allocation\n",
+                       __FUNCTION__, nid);
+                arena = alloc_bootmem(sizeof(*arena));
+        }
+
+        if (!NODE_DATA(nid) ||
+            (NULL == (arena->ptes = __alloc_bootmem_node(NODE_DATA(nid),
+                                                         mem_size,
+                                                         align,
+                                                         0)))) {
+                printk("%s: couldn't allocate arena ptes from node %d\n"
+                       "    falling back to system-wide allocation\n",
+                       __FUNCTION__, nid);
+                arena->ptes = __alloc_bootmem(mem_size, align, 0);
+        }
+
+#else /* CONFIG_DISCONTIGMEM */
+
 	arena = alloc_bootmem(sizeof(*arena));
 	arena->ptes = __alloc_bootmem(mem_size, align, 0);
 
+#endif /* CONFIG_DISCONTIGMEM */
+
 	spin_lock_init(&arena->lock);
 	arena->hose = hose;
 	arena->dma_base = base;
@@ -91,6 +118,13 @@
 	return arena;
 }
 
+struct pci_iommu_arena *
+iommu_arena_new(struct pci_controller *hose, dma_addr_t base,
+		unsigned long window_size, unsigned long align)
+{
+	return iommu_arena_new_node(0, hose, base, window_size, align);
+}
+
 /* Must be called with the arena lock held */
 static long
 iommu_arena_find_pages(struct pci_iommu_arena *arena, long n, long mask)
diff -urN linux-2.4.21-pre3/arch/alpha/kernel/process.c linux-2.4.21-pre4/arch/alpha/kernel/process.c
--- linux-2.4.21-pre3/arch/alpha/kernel/process.c	Sun Sep 30 12:26:08 2001
+++ linux-2.4.21-pre4/arch/alpha/kernel/process.c	Tue Jan 28 19:44:28 2003
@@ -336,7 +336,7 @@
 }
 
 /*
- * fill in the user structure for a core dump..
+ * Fill in the user structure for an ECOFF core dump.
  */
 void
 dump_thread(struct pt_regs * pt, struct user * dump)
@@ -396,6 +396,55 @@
 	memcpy((char *)dump->regs + EF_SIZE, sw->fp, 32 * 8);
 }
 
+/*
+ * Fill in the user structure for a ELF core dump.
+ */
+void
+dump_elf_thread(elf_gregset_t dest, struct pt_regs *pt,
+		struct task_struct *task)
+{
+	/* switch stack follows right below pt_regs: */
+	struct switch_stack * sw = ((struct switch_stack *) pt) - 1;
+
+	dest[ 0] = pt->r0;
+	dest[ 1] = pt->r1;
+	dest[ 2] = pt->r2;
+	dest[ 3] = pt->r3;
+	dest[ 4] = pt->r4;
+	dest[ 5] = pt->r5;
+	dest[ 6] = pt->r6;
+	dest[ 7] = pt->r7;
+	dest[ 8] = pt->r8;
+	dest[ 9] = sw->r9;
+	dest[10] = sw->r10;
+	dest[11] = sw->r11;
+	dest[12] = sw->r12;
+	dest[13] = sw->r13;
+	dest[14] = sw->r14;
+	dest[15] = sw->r15;
+	dest[16] = pt->r16;
+	dest[17] = pt->r17;
+	dest[18] = pt->r18;
+	dest[19] = pt->r19;
+	dest[20] = pt->r20;
+	dest[21] = pt->r21;
+	dest[22] = pt->r22;
+	dest[23] = pt->r23;
+	dest[24] = pt->r24;
+	dest[25] = pt->r25;
+	dest[26] = pt->r26;
+	dest[27] = pt->r27;
+	dest[28] = pt->r28;
+	dest[29] = pt->gp;
+	dest[30] = rdusp();
+	dest[31] = pt->pc;
+
+	/* Once upon a time this was the PS value.  Which is stupid
+	   since that is always 8 for usermode.  Usurped for the more
+	   useful value of the thread's UNIQUE field.  */
+	dest[32] = task->thread.unique;
+}
+
 int
 dump_fpu(struct pt_regs * regs, elf_fpregset_t *r)
 {
diff -urN linux-2.4.21-pre3/arch/alpha/kernel/proto.h linux-2.4.21-pre4/arch/alpha/kernel/proto.h
--- linux-2.4.21-pre3/arch/alpha/kernel/proto.h	Tue Jan 28 19:44:23 2003
+++ linux-2.4.21-pre4/arch/alpha/kernel/proto.h	Tue Jan 28 19:44:28 2003
@@ -1,4 +1,6 @@
 #include <linux/config.h>
+
+
 /* Prototypes of functions used across modules here in this directory.  */
 
 #define vucp	volatile unsigned char  *
@@ -24,6 +26,7 @@
 extern void cia_init_pci(void);
 extern void cia_init_arch(void);
 extern void pyxis_init_arch(void);
+extern void cia_kill_arch(int);
 extern void cia_machine_check(u64, u64, struct pt_regs *);
 extern void cia_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
 
@@ -40,6 +43,21 @@
 extern void lca_machine_check(u64, u64, struct pt_regs *);
 extern void lca_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
 
+/* core_marvel.c */
+extern struct pci_ops marvel_pci_ops;
+extern void marvel_init_arch(void);
+extern void marvel_kill_arch(int);
+extern void marvel_machine_check(u64, u64, struct pt_regs *);
+extern void marvel_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
+extern int marvel_pa_to_nid(unsigned long);
+extern int marvel_cpuid_to_nid(int);
+extern unsigned long marvel_node_mem_start(int);
+extern unsigned long marvel_node_mem_size(int);
+extern struct _alpha_agp_info *marvel_agp_info(void);
+struct io7 *marvel_find_io7(int pe);
+struct io7 *marvel_next_io7(struct io7 *prev);
+void io7_clear_errors(struct io7 *io7);
+
 /* core_mcpcia.c */
 extern struct pci_ops mcpcia_pci_ops;
 extern void mcpcia_init_arch(void);
@@ -67,6 +85,7 @@
 extern void titan_kill_arch(int);
 extern void titan_machine_check(u64, u64, struct pt_regs *);
 extern void titan_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
+extern struct _alpha_agp_info *titan_agp_info(void);
 
 /* core_tsunami.c */
 extern struct pci_ops tsunami_pci_ops;
@@ -81,13 +100,23 @@
 extern void wildfire_kill_arch(int);
 extern void wildfire_machine_check(u64, u64, struct pt_regs *);
 extern void wildfire_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
+extern int wildfire_pa_to_nid(unsigned long);
+extern int wildfire_cpuid_to_nid(int);
+extern unsigned long wildfire_node_mem_start(int);
+extern unsigned long wildfire_node_mem_size(int);
 
 /* setup.c */
 extern unsigned long srm_hae;
 extern int boot_cpuid;
-extern int srmcons_output;
+
+/* srmcons.c */
+#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM)
 extern void register_srm_console(void);
 extern void unregister_srm_console(void);
+#else
+#define register_srm_console()
+#define unregister_srm_console()
+#endif
 
 /* smp.c */
 extern void setup_smp(void);
@@ -148,6 +177,10 @@
 extern void switch_to_system_map(void);
 extern void srm_paging_stop(void);
 
+/* ../mm/remap.c */
+extern int __alpha_remap_area_pages(unsigned long, unsigned long, 
+				    unsigned long, unsigned long);
+
 /* irq.c */
 
 #ifdef CONFIG_SMP
diff -urN linux-2.4.21-pre3/arch/alpha/kernel/ptrace.c linux-2.4.21-pre4/arch/alpha/kernel/ptrace.c
--- linux-2.4.21-pre3/arch/alpha/kernel/ptrace.c	Tue Sep 18 17:03:51 2001
+++ linux-2.4.21-pre4/arch/alpha/kernel/ptrace.c	Tue Jan 28 19:44:28 2003
@@ -102,7 +102,9 @@
 
 	if (regno == 30) {
 		addr = &task->thread.usp;
-	} else if (regno == 31 || regno > 64) {
+	} else if (regno == 65) {
+		addr = &task->thread.unique;
+	} else if (regno == 31 || regno > 65) {
 		zero = 0;
 		addr = &zero;
 	} else {
diff -urN linux-2.4.21-pre3/arch/alpha/kernel/setup.c linux-2.4.21-pre4/arch/alpha/kernel/setup.c
--- linux-2.4.21-pre3/arch/alpha/kernel/setup.c	Tue Jan 28 19:44:23 2003
+++ linux-2.4.21-pre4/arch/alpha/kernel/setup.c	Tue Jan 28 19:44:28 2003
@@ -71,18 +71,25 @@
 
  * "srmcons" specified in the boot command arguments allows us to
  * see kernel messages during the period of time before the true
- * console device is "registered" during console_init(). As of this
- * version (2.4.10), time_init() is the last Alpha-specific code
- * called before console_init(), so we put "unregister" code
- * there to prevent schizophrenic console behavior later... ;-}
+ * console device is "registered" during console_init(). 
+ * As of this version (2.4.20), console_init() will call
+ * disable_early_printk() as the last action before initializing
+ * the console drivers. That's the last possible time srmcons can be 
+ * unregistered without interfering with console behavior.
  *
- * By default, OFF; set it with a bootcommand arg of "srmcons".
+ * By default, OFF; set it with a bootcommand arg of "srmcons" or 
+ * "console=srm". The meaning of these two args is:
+ *     "srmcons"     - early callback prints 
+ *     "console=srm" - full callback based console, including early prints
  */
 int srmcons_output = 0;
 
 /* Enforce a memory size limit; useful for testing. By default, none. */
 unsigned long mem_size_limit = 0;
 
+/* Set AGP GART window size (0 means disabled). */
+unsigned long alpha_agpgart_size = DEFAULT_AGP_APER_SIZE;
+
 #ifdef CONFIG_ALPHA_GENERIC
 struct alpha_machine_vector alpha_mv;
 int alpha_using_srm;
@@ -147,6 +154,7 @@
 WEAK(eiger_mv);
 WEAK(jensen_mv);
 WEAK(lx164_mv);
+WEAK(marvel_ev7_mv);
 WEAK(miata_mv);
 WEAK(mikasa_mv);
 WEAK(mikasa_primo_mv);
@@ -166,6 +174,7 @@
 WEAK(shark_mv);
 WEAK(sx164_mv);
 WEAK(takara_mv);
+WEAK(titan_mv);
 WEAK(webbrick_mv);
 WEAK(wildfire_mv);
 WEAK(xl_mv);
@@ -295,6 +304,24 @@
 			max_low_pfn = end;
 	}
 
+	/*
+	 * Except for the NUMA systems (wildfire, marvel) all of the 
+	 * Alpha systems we run on support 32GB of memory or less.
+	 * Since the NUMA systems introduce large holes in memory addressing,
+	 * we can get into a situation where there is not enough contiguous
+	 * memory for the memory map. 
+	 *
+	 * Limit memory to the first 32GB to limit the NUMA systems to 
+	 * memory on their first node (wildfire) or 2 (marvel) to avoid 
+	 * not being able to produce the memory map. In order to access 
+	 * all of the memory on the NUMA systems, build with discontiguous
+	 * memory support.
+	 *
+	 * If the user specified a memory limit, let that memory limit stand.
+	 */
+	if (!mem_size_limit) 
+		mem_size_limit = (32ul * 1024 * 1024 * 1024) >> PAGE_SHIFT;
+
 	if (mem_size_limit && max_low_pfn >= mem_size_limit)
 	{
 		printk("setup: forcing memory size to %ldK (from %ldK).\n",
@@ -433,57 +460,6 @@
 #undef PFN_PHYS
 #undef PFN_MAX
 
-#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM)
-/*
- *      Manage the SRM callbacks as a "console".
- */
-static struct console srmcons;
-
-void __init register_srm_console(void)
-{
-        register_console(&srmcons);
-}
-
-void __init unregister_srm_console(void)
-{
-        unregister_console(&srmcons);
-}
-
-static void srm_console_write(struct console *co, const char *s,
-                                unsigned count)
-{
-	srm_printk(s);
-}
-
-static kdev_t srm_console_device(struct console *c)
-{
-  /* Huh? */
-        return MKDEV(TTY_MAJOR, 64 + c->index);
-}
-
-static int __init srm_console_setup(struct console *co, char *options)
-{
-	return 1;
-}
-
-static struct console srmcons = {
-	name:		"srm0",
-	write:		srm_console_write,
-	device:		srm_console_device,
-	setup:		srm_console_setup,
-	flags:		CON_PRINTBUFFER | CON_ENABLED, /* fake it out */
-	index:		-1,
-};
-
-#else
-void __init register_srm_console(void)
-{
-}
-void __init unregister_srm_console(void)
-{
-}
-#endif
-
 void __init
 setup_arch(char **cmdline_p)
 {
@@ -544,7 +520,16 @@
 			continue;
 		}
 		if (strncmp(p, "srmcons", 7) == 0) {
-			srmcons_output = 1;
+			srmcons_output |= 1;
+			continue;
+		}
+		if (strncmp(p, "console=srm", 11) == 0) {
+			srmcons_output |= 2;
+			continue;
+		}
+		if (strncmp(p, "gartsize=", 9) == 0) {
+			alpha_agpgart_size =
+				get_mem_size_limit(p+9) << PAGE_SHIFT;
 			continue;
 		}
 	}
@@ -555,6 +540,13 @@
 	/* If we want SRM console printk echoing early, do it now. */
 	if (alpha_using_srm && srmcons_output) {
 		register_srm_console();
+
+		/*
+		 * If "console=srm" was specified, clear the srmcons_output
+		 * flag now so that time.c won't unregister_srm_console
+		 */
+		if (srmcons_output & 2)
+			srmcons_output = 0;
 	}
 
 	/*
@@ -649,6 +641,15 @@
 	paging_init();
 }
 
+void __init
+disable_early_printk(void)
+{
+	if (alpha_using_srm && srmcons_output) {
+		unregister_srm_console();
+		srmcons_output = 0;
+	}
+}
+
 static char sys_unknown[] = "Unknown";
 static char systype_names[][16] = {
 	"0",
@@ -658,7 +659,7 @@
 	"Mikasa", "EB64", "EB66", "EB64+", "AlphaBook1",
 	"Rawhide", "K2", "Lynx", "XL", "EB164", "Noritake",
 	"Cortex", "29", "Miata", "XXM", "Takara", "Yukon",
-	"Tsunami", "Wildfire", "CUSCO", "Eiger", "Titan"
+	"Tsunami", "Wildfire", "CUSCO", "Eiger", "Titan", "Marvel"
 };
 
 static char unofficial_names[][8] = {"100", "Ruffian"};
@@ -677,15 +678,20 @@
 static char eb66_names[][8] = {"EB66", "EB66+"};
 static int eb66_indices[] = {0,0,1};
 
+static char marvel_names[][16] = {
+	"Marvel/EV7"
+};
+static int marvel_indices[] = { 0 };
+
 static char rawhide_names[][16] = {
 	"Dodge", "Wrangler", "Durango", "Tincup", "DaVinci"
 };
 static int rawhide_indices[] = {0,0,0,1,1,2,2,3,3,4,4};
 
 static char titan_names[][16] = {
-	"0", "Privateer"
+	"DEFAULT", "Privateer", "Falcon", "Granite"
 };
-static int titan_indices[] = {0,1};
+static int titan_indices[] = {0,1,2,2,3};
 
 static char tsunami_names[][16] = {
 	"0", "DP264", "Warhol", "Windjammer", "Monet", "Clipper",
@@ -738,6 +744,7 @@
 		NULL,		/* CUSCO */
 		&eiger_mv,	/* Eiger */
 		NULL,		/* Titan */
+		NULL,		/* Marvel */
 	};
 
 	static struct alpha_machine_vector *unofficial_vecs[] __initdata =
@@ -775,10 +782,17 @@
 		&eb66p_mv
 	};
 
+	static struct alpha_machine_vector *marvel_vecs[] __initdata =
+	{
+		&marvel_ev7_mv,
+	};
+
 	static struct alpha_machine_vector *titan_vecs[] __initdata =
 	{
-		NULL,
+		&titan_mv,		/* default   */
 		&privateer_mv,		/* privateer */
+		&titan_mv,		/* falcon    */
+		&privateer_mv,		/* granite   */
 	};
 
 	static struct alpha_machine_vector *tsunami_vecs[]  __initdata =
@@ -847,7 +861,12 @@
 			if (member < N(eb66_indices))
 				vec = eb66_vecs[eb66_indices[member]];
 			break;
+		case ST_DEC_MARVEL:
+			if (member < N(marvel_indices))
+				vec = marvel_vecs[marvel_indices[member]];
+			break;
 		case ST_DEC_TITAN:
+			vec = titan_vecs[0];	/* default */
 			if (member < N(titan_indices))
 				vec = titan_vecs[titan_indices[member]];
 			break;
@@ -989,11 +1008,16 @@
 		if (member < N(eb66_indices))
 			*variation_name = eb66_names[eb66_indices[member]];
 		break;
+	case ST_DEC_MARVEL:
+		if (member < N(marvel_indices))
+			*variation_name = marvel_names[marvel_indices[member]];
+		break;
 	case ST_DEC_RAWHIDE:
 		if (member < N(rawhide_indices))
 			*variation_name = rawhide_names[rawhide_indices[member]];
 		break;
 	case ST_DEC_TITAN:
+		*variation_name = titan_names[0];	/* default */
 		if (member < N(titan_indices))
 			*variation_name = titan_names[titan_indices[member]];
 		break;
diff -urN linux-2.4.21-pre3/arch/alpha/kernel/smp.c linux-2.4.21-pre4/arch/alpha/kernel/smp.c
--- linux-2.4.21-pre3/arch/alpha/kernel/smp.c	Tue Jan 28 19:44:23 2003
+++ linux-2.4.21-pre4/arch/alpha/kernel/smp.c	Tue Jan 28 19:44:28 2003
@@ -174,6 +174,9 @@
 	/* Get our local ticker going. */
 	smp_setup_percpu_timer(cpuid);
 
+	/* Call platform-specific callin, if specified */
+	if (alpha_mv.smp_callin) alpha_mv.smp_callin();
+
 	/* Must have completely accurate bogos.  */
 	__sti();
 
@@ -862,11 +865,36 @@
 	       && time_before (jiffies, timeout))
 		barrier();
 
-	/* We either got one or timed out -- clear the lock.  */
+	/* If there's no response yet, log a message but allow a longer
+	 * timeout period -- if we get a response this time, log
+	 * a message saying when we got it.. 
+	 */
+	if (atomic_read(&data.unstarted_count) > 0) {
+		long start_time = jiffies;
+		printk(KERN_ERR "%s: initial timeout -- trying long wait\n",
+		       __FUNCTION__);
+		timeout = jiffies + 30 * HZ;
+		while (atomic_read(&data.unstarted_count) > 0
+		       && time_before(jiffies, timeout))
+			barrier();
+		if (atomic_read(&data.unstarted_count) <= 0) {
+			long delta = jiffies - start_time;
+			printk(KERN_ERR 
+			       "%s: response %ld.%ld seconds into long wait\n",
+			       __FUNCTION__, delta / HZ,
+			       (100 * (delta - ((delta / HZ) * HZ))) / HZ);
+		}
+	}
+
+	/* We either got one or timed out -- clear the lock. */
 	mb();
 	smp_call_function_data = 0;
-	if (atomic_read (&data.unstarted_count) > 0)
-		return -ETIMEDOUT;
+
+	/* 
+	 * If after both the initial and long timeout periods we still don't
+	 * have a response, something is very wrong...
+	 */
+	BUG_ON(atomic_read (&data.unstarted_count) > 0);
 
 	/* Wait for a complete response, if needed.  */
 	if (wait) {
diff -urN linux-2.4.21-pre3/arch/alpha/kernel/srmcons.c linux-2.4.21-pre4/arch/alpha/kernel/srmcons.c
--- linux-2.4.21-pre3/arch/alpha/kernel/srmcons.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/arch/alpha/kernel/srmcons.c	Tue Jan 28 19:44:28 2003
@@ -0,0 +1,361 @@
+/*
+ *	linux/arch/alpha/kernel/srmcons.c
+ *
+ * Callback based driver for SRM Console console device.
+ * (TTY driver and console driver)
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/timer.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+
+#include <asm/console.h>
+#include <asm/uaccess.h>
+
+
+static spinlock_t srmcons_callback_lock = SPIN_LOCK_UNLOCKED;
+static int srm_is_registered_console = 0;
+
+/* 
+ * The TTY driver
+ */
+#define MAX_SRM_CONSOLE_DEVICES 1	/* only support 1 console device */
+
+static int srmcons_refcount;
+static struct tty_struct *srmcons_table[MAX_SRM_CONSOLE_DEVICES];
+static struct termios *srmcons_termios[MAX_SRM_CONSOLE_DEVICES];
+static struct termios *srmcons_termios_locked[MAX_SRM_CONSOLE_DEVICES];
+
+struct srmcons_private {
+	struct tty_struct *tty;
+	struct timer_list timer;
+	spinlock_t lock;
+};
+
+typedef union _srmcons_result {
+	struct {
+		unsigned long c :61;
+		unsigned long status :3;
+	} bits;
+	long as_long;
+} srmcons_result;
+
+/* called with callback_lock held */
+static int
+srmcons_do_receive_chars(struct tty_struct *tty)
+{
+	srmcons_result result;
+	int count = 0, loops = 0;
+
+	do {
+		result.as_long = callback_getc(0);
+		if (result.bits.status < 2) {
+			tty_insert_flip_char(tty, (char)result.bits.c, 0);
+			count++;
+		}
+	} while((result.bits.status & 1) && (++loops < 10));
+
+	if (count)
+		tty_schedule_flip(tty);
+
+	return count;
+}
+
+static void
+srmcons_receive_chars(unsigned long data)
+{
+	struct srmcons_private *srmconsp = (struct srmcons_private *)data;
+	unsigned long flags;
+	int incr = 10;
+
+	local_irq_save(flags);
+	if (spin_trylock(&srmcons_callback_lock)) {
+		if (!srmcons_do_receive_chars(srmconsp->tty))
+			incr = 100;
+		spin_unlock(&srmcons_callback_lock);
+	} 
+
+	spin_lock(&srmconsp->lock);
+	if (srmconsp->tty) {
+		srmconsp->timer.expires = jiffies + incr;
+		add_timer(&srmconsp->timer);
+	}
+	spin_unlock(&srmconsp->lock);
+
+	local_irq_restore(flags);
+}
+
+/* called with callback_lock held */
+static int
+srmcons_do_write(struct tty_struct *tty, const unsigned char *buf, int count)
+{
+	unsigned char *str_cr = "\r";
+	long c, remaining = count;
+	srmcons_result result;
+	unsigned char *cur;
+	int need_cr;
+
+	for (cur = (unsigned char *)buf; remaining > 0; ) {
+		need_cr = 0;
+		/* 
+		 * Break it up into reasonable size chunks to allow a chance
+		 * for input to get in
+		 */
+		for (c = 0; c < min_t(long, 128L, remaining) && !need_cr; c++)
+			if (cur[c] == '\n')
+				need_cr = 1;
+		
+		while (c > 0) {
+			result.as_long = callback_puts(0, cur, c);
+			c -= result.bits.c;
+			remaining -= result.bits.c;
+			cur += result.bits.c;
+
+			/*
+			 * Check for pending input iff a tty was provided
+			 */
+			if (tty)
+				srmcons_do_receive_chars(tty);
+		}
+
+		while (need_cr) {
+			result.as_long = callback_puts(0, str_cr, 1);
+			if (result.bits.c > 0)
+				need_cr = 0;
+		}
+	}
+	return count;
+}
+
+static int
+srmcons_write(struct tty_struct *tty, int from_user,
+	      const unsigned char *buf, int count)
+{
+	unsigned long flags;
+
+	if (from_user) {
+		unsigned char tmp[512];
+		int ret = 0;
+		size_t c;
+
+		while ((c = count) > 0) {
+			if (c > sizeof(tmp))
+				c = sizeof(tmp);
+			
+			c -= copy_from_user(tmp, buf, c);
+
+			if (!c) { 
+				printk("%s: EFAULT (count %d)\n",
+				       __FUNCTION__, count);
+				return -EFAULT;
+			}
+
+			spin_lock_irqsave(&srmcons_callback_lock, flags);
+			srmcons_do_write(tty, tmp, c);
+			spin_unlock_irqrestore(&srmcons_callback_lock, flags);
+
+			buf += c;
+			count -= c;
+			ret += c;
+		}
+
+		return ret;
+	}
+
+	spin_lock_irqsave(&srmcons_callback_lock, flags);
+	srmcons_do_write(tty, buf, count);
+	spin_unlock_irqrestore(&srmcons_callback_lock, flags);
+
+	return count;
+}
+
+static int
+srmcons_write_room(struct tty_struct *tty)
+{
+	return 512;
+}
+
+static int
+srmcons_chars_in_buffer(struct tty_struct *tty)
+{
+	return 0;
+}
+
+static int
+srmcons_get_private_struct(struct srmcons_private **ps)
+{
+	static struct srmcons_private *srmconsp = NULL;
+	static spinlock_t srmconsp_lock = SPIN_LOCK_UNLOCKED;
+	unsigned long flags;
+	int retval = 0;
+
+	spin_lock_irqsave(&srmconsp_lock, flags);
+
+	do {
+		if (srmconsp != NULL) {
+			*ps = srmconsp;
+			break;
+		}
+
+		srmconsp = kmalloc(sizeof(*srmconsp), GFP_KERNEL);
+		if (srmconsp == NULL) {
+			retval = -ENOMEM;
+			break;
+		}
+
+		srmconsp->tty = NULL;
+		srmconsp->lock = SPIN_LOCK_UNLOCKED;
+		init_timer(&srmconsp->timer);
+
+		*ps = srmconsp;
+	} while(0);
+
+	spin_unlock_irqrestore(&srmconsp_lock, flags);
+
+	return retval;
+}
+
+static int
+srmcons_open(struct tty_struct *tty, struct file *filp)
+{
+	struct srmcons_private *srmconsp;
+	unsigned long flags;
+	int retval;
+
+	retval = srmcons_get_private_struct(&srmconsp);
+	if (retval)
+		return retval;
+
+	spin_lock_irqsave(&srmconsp->lock, flags);
+
+	if (!srmconsp->tty) {
+		tty->driver_data = srmconsp;
+
+		srmconsp->tty = tty;
+		srmconsp->timer.function = srmcons_receive_chars;
+		srmconsp->timer.data = (unsigned long)srmconsp;
+		srmconsp->timer.expires = jiffies + 10;
+		add_timer(&srmconsp->timer);
+	}
+
+	spin_unlock_irqrestore(&srmconsp->lock, flags);
+
+	return 0;
+}
+
+static void
+srmcons_close(struct tty_struct *tty, struct file *filp)
+{
+	struct srmcons_private *srmconsp = tty->driver_data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&srmconsp->lock, flags);
+
+	if (tty->count == 1) {
+		srmconsp->tty = NULL;
+		del_timer(&srmconsp->timer);
+	}
+
+	spin_unlock_irqrestore(&srmconsp->lock, flags);
+}
+
+
+static struct tty_driver srmcons_driver = {
+	.driver_name	= "srm",
+	.name		= "srm",
+	.magic		= TTY_DRIVER_MAGIC,
+	.major		= 0, 	/* dynamic */
+	.minor_start	= 0,
+	.num		= MAX_SRM_CONSOLE_DEVICES,
+	.type		= TTY_DRIVER_TYPE_SYSTEM,
+	.subtype	= SYSTEM_TYPE_SYSCONS,
+
+	.table		= srmcons_table,
+	.termios	= srmcons_termios,
+	.termios_locked	= srmcons_termios_locked,
+	.refcount	= &srmcons_refcount,
+
+	.open		= srmcons_open,
+	.close		= srmcons_close,
+	.write		= srmcons_write,
+	.write_room	= srmcons_write_room,
+	.chars_in_buffer= srmcons_chars_in_buffer,
+};
+
+static int __init
+srmcons_init(void)
+{
+	if (srm_is_registered_console) {
+		srmcons_driver.init_termios = tty_std_termios;
+		return tty_register_driver(&srmcons_driver);
+	}
+
+	return -ENODEV;
+}
+
+module_init(srmcons_init);
+
+
+/*
+ * The console driver
+ */
+static void
+srm_console_write(struct console *co, const char *s, unsigned count)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&srmcons_callback_lock, flags);
+	srmcons_do_write(NULL, s, count);
+	spin_unlock_irqrestore(&srmcons_callback_lock, flags);
+}
+
+static kdev_t
+srm_console_device(struct console *co)
+{
+	return mk_kdev(srmcons_driver.major,
+		       srmcons_driver.minor_start + co->index);
+}
+
+static int __init
+srm_console_setup(struct console *co, char *options)
+{
+	return 0;
+}
+
+static struct console srmcons = {
+	.name		= "srm",
+	.write		= srm_console_write,
+	.device		= srm_console_device,
+	.setup		= srm_console_setup,
+	.flags		= CON_PRINTBUFFER,
+	.index		= -1,
+};
+
+void __init
+register_srm_console(void)
+{
+	if (!srm_is_registered_console) {
+		callback_open_console();
+		register_console(&srmcons);
+		srm_is_registered_console = 1;
+	}
+}
+
+void __init
+unregister_srm_console(void)
+{
+	if (srm_is_registered_console) {
+		callback_close_console();
+		unregister_console(&srmcons);
+		srm_is_registered_console = 0;
+	}
+}
diff -urN linux-2.4.21-pre3/arch/alpha/kernel/sys_alcor.c linux-2.4.21-pre4/arch/alpha/kernel/sys_alcor.c
--- linux-2.4.21-pre3/arch/alpha/kernel/sys_alcor.c	Tue Jan 28 19:44:23 2003
+++ linux-2.4.21-pre4/arch/alpha/kernel/sys_alcor.c	Tue Jan 28 19:44:28 2003
@@ -220,6 +220,8 @@
 static void
 alcor_kill_arch(int mode)
 {
+	cia_kill_arch(mode);
+
 	switch(mode) {
 	case LINUX_REBOOT_CMD_RESTART:
 		/* Who said DEC engineer's have no sense of humor? ;-)  */
diff -urN linux-2.4.21-pre3/arch/alpha/kernel/sys_cabriolet.c linux-2.4.21-pre4/arch/alpha/kernel/sys_cabriolet.c
--- linux-2.4.21-pre3/arch/alpha/kernel/sys_cabriolet.c	Fri Oct 12 15:35:53 2001
+++ linux-2.4.21-pre4/arch/alpha/kernel/sys_cabriolet.c	Tue Jan 28 19:44:28 2003
@@ -365,6 +365,7 @@
 	init_irq:		cabriolet_init_irq,
 	init_rtc:		common_init_rtc,
 	init_pci:		cia_cab_init_pci,
+	kill_arch:		cia_kill_arch,
 	pci_map_irq:		cabriolet_map_irq,
 	pci_swizzle:		common_swizzle,
 };
@@ -416,6 +417,7 @@
 	init_irq:		cabriolet_init_irq,
 	init_rtc:		common_init_rtc,
 	init_pci:		alphapc164_init_pci,
+	kill_arch:		cia_kill_arch,
 	pci_map_irq:		alphapc164_map_irq,
 	pci_swizzle:		common_swizzle,
 };
@@ -441,6 +443,7 @@
 	init_irq:		pc164_init_irq,
 	init_rtc:		common_init_rtc,
 	init_pci:		alphapc164_init_pci,
+	kill_arch:		cia_kill_arch,
 	pci_map_irq:		alphapc164_map_irq,
 	pci_swizzle:		common_swizzle,
 };
diff -urN linux-2.4.21-pre3/arch/alpha/kernel/sys_marvel.c linux-2.4.21-pre4/arch/alpha/kernel/sys_marvel.c
--- linux-2.4.21-pre3/arch/alpha/kernel/sys_marvel.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/arch/alpha/kernel/sys_marvel.c	Tue Jan 28 19:44:28 2003
@@ -0,0 +1,499 @@
+/*
+ * linux/arch/alpha/kernel/sys_marvel.c
+ *
+ * Marvel / IO7 support
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+
+#include <asm/ptrace.h>
+#include <asm/system.h>
+#include <asm/dma.h>
+#include <asm/irq.h>
+#include <asm/bitops.h>
+#include <asm/mmu_context.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/core_marvel.h>
+#include <asm/hwrpb.h>
+
+#include "proto.h"
+#include "err_impl.h"
+#include "irq_impl.h"
+#include "pci_impl.h"
+#include "machvec_impl.h"
+
+#if NR_IRQS < MARVEL_NR_IRQS
+# error NR_IRQS < MARVEL_NR_IRQS !!!
+#endif
+
+
+/*
+ * Interrupt handling.
+ */
+static void 
+io7_device_interrupt(unsigned long vector, struct pt_regs * regs)
+{
+	unsigned int pid;
+	unsigned int irq;
+
+	/*
+	 * Vector is 0x800 + (interrupt)
+	 *
+	 * where (interrupt) is:
+	 *
+	 *	...16|15 14|13     4|3 0
+	 *	-----+-----+--------+---
+	 *	  PE |  0  |   irq  | 0
+	 *
+	 * where (irq) is 
+	 *
+	 *       0x0800 - 0x0ff0	 - 0x0800 + (LSI id << 4)
+	 *	 0x1000 - 0x2ff0	 - 0x1000 + (MSI_DAT<8:0> << 4)
+	 */
+	pid = vector >> 16;
+	irq = ((vector & 0xffff) - 0x800) >> 4;
+
+	irq += 16;				/* offset for legacy */
+	irq &= MARVEL_IRQ_VEC_IRQ_MASK;		/* not too many bits */
+	irq |= pid << MARVEL_IRQ_VEC_PE_SHIFT;	/* merge the pid     */
+
+	handle_irq(irq, regs);
+}
+
+static volatile unsigned long *
+io7_get_irq_ctl(unsigned int irq, struct io7 **pio7)
+{
+	volatile unsigned long *ctl;
+	unsigned int pid;
+	struct io7 *io7;
+
+	pid = irq >> MARVEL_IRQ_VEC_PE_SHIFT;
+
+	if (!(io7 = marvel_find_io7(pid))) {
+		printk(KERN_ERR 
+		       "%s for nonexistent io7 -- vec %x, pid %d\n",
+		       __FUNCTION__, irq, pid);
+		return NULL;
+	}
+
+	irq &= MARVEL_IRQ_VEC_IRQ_MASK;	/* isolate the vector    */
+	irq -= 16;			/* subtract legacy bias  */
+
+	if (irq >= 0x180) {
+		printk(KERN_ERR 
+		       "%s for invalid irq -- pid %d adjusted irq %x\n",
+		       __FUNCTION__, pid, irq);
+		return NULL;
+	}
+
+	ctl = &io7->csrs->PO7_LSI_CTL[irq & 0xff].csr; /* assume LSI */
+	if (irq >= 0x80)	     	/* MSI */
+		ctl = &io7->csrs->PO7_MSI_CTL[((irq - 0x80) >> 5) & 0x0f].csr;
+
+	if (pio7) *pio7 = io7;
+	return ctl;
+}
+
+static void
+io7_enable_irq(unsigned int irq)
+{
+	volatile unsigned long *ctl;
+	struct io7 *io7;
+
+	ctl = io7_get_irq_ctl(irq, &io7);
+	if (!ctl || !io7) {
+		printk(KERN_ERR "%s: get_ctl failed for irq %x\n", 
+		       __FUNCTION__, irq);
+		return;
+	}
+		
+	spin_lock(&io7->irq_lock);
+	*ctl |= 1UL << 24;
+	mb();
+	*ctl;
+	spin_unlock(&io7->irq_lock);
+}
+
+static void
+io7_disable_irq(unsigned int irq)
+{
+	volatile unsigned long *ctl;
+	struct io7 *io7;
+
+	ctl = io7_get_irq_ctl(irq, &io7);
+	if (!ctl || !io7) {
+		printk(KERN_ERR "%s: get_ctl failed for irq %x\n", 
+		       __FUNCTION__, irq);
+		return;
+	}
+		
+	spin_lock(&io7->irq_lock);
+	*ctl &= ~(1UL << 24);
+	mb();
+	*ctl;
+	spin_unlock(&io7->irq_lock);
+}
+
+static unsigned int
+io7_startup_irq(unsigned int irq)
+{
+	io7_enable_irq(irq);
+	return 0;	/* never anything pending */
+}
+
+static void
+io7_end_irq(unsigned int irq)
+{
+	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+		io7_enable_irq(irq);
+}
+
+static void
+marvel_irq_noop(unsigned int irq) 
+{ 
+	return; 
+}
+
+static unsigned int
+marvel_irq_noop_return(unsigned int irq) 
+{ 
+	return 0; 
+}
+
+static struct hw_interrupt_type marvel_legacy_irq_type = {
+	typename:	"LEGACY",
+	startup:	marvel_irq_noop_return,
+	shutdown:	marvel_irq_noop,
+	enable:		marvel_irq_noop,
+	disable:	marvel_irq_noop,
+	ack:		marvel_irq_noop,
+	end:		marvel_irq_noop,
+};
+
+static struct hw_interrupt_type io7_lsi_irq_type = {
+	typename:	"LSI",
+	startup:	io7_startup_irq,
+	shutdown:	io7_disable_irq,
+	enable:		io7_enable_irq,
+	disable:	io7_disable_irq,
+	ack:		io7_disable_irq,
+	end:		io7_end_irq,
+};
+
+static struct hw_interrupt_type io7_msi_irq_type = {
+	typename:	"MSI",
+	startup:	io7_startup_irq,
+	shutdown:	io7_disable_irq,
+	enable:		io7_enable_irq,
+	disable:	io7_disable_irq,
+	ack:		marvel_irq_noop,
+	end:		io7_end_irq,
+};
+
+static void
+io7_redirect_irq(struct io7 *io7, 
+		 volatile unsigned long *csr, 
+		 unsigned int where)
+{
+	unsigned long val;
+	
+	val = *csr;
+	val &= ~(0x1ffUL << 24);		/* clear the target pid   */
+	val |= ((unsigned long)where << 24);	/* set the new target pid */
+	
+	*csr = val;
+	mb();
+	*csr;
+}
+
+static void 
+io7_redirect_one_lsi(struct io7 *io7, unsigned int which, unsigned int where)
+{
+	unsigned long val;
+
+	/*
+	 * LSI_CTL has target PID @ 14
+	 */
+	val = io7->csrs->PO7_LSI_CTL[which].csr;
+	val &= ~(0x1ffUL << 14);		/* clear the target pid */
+	val |= ((unsigned long)where << 14);	/* set teh new target pid */
+
+	io7->csrs->PO7_LSI_CTL[which].csr = val;
+	mb();
+	io7->csrs->PO7_LSI_CTL[which].csr;
+}
+
+static void 
+io7_redirect_one_msi(struct io7 *io7, unsigned int which, unsigned int where)
+{
+	unsigned long val;
+
+	/*
+	 * MSI_CTL has target PID @ 14
+	 */
+	val = io7->csrs->PO7_MSI_CTL[which].csr;
+	val &= ~(0x1ffUL << 14);		/* clear the target pid */
+	val |= ((unsigned long)where << 14);	/* set teh new target pid */
+
+	io7->csrs->PO7_MSI_CTL[which].csr = val;
+	mb();
+	io7->csrs->PO7_MSI_CTL[which].csr;
+}
+
+static void __init
+init_one_io7_lsi(struct io7 *io7, unsigned int which, unsigned int where)
+{
+	/*
+	 * LSI_CTL has target PID @ 14
+	 */
+	io7->csrs->PO7_LSI_CTL[which].csr = ((unsigned long)where << 14);
+	mb();
+	io7->csrs->PO7_LSI_CTL[which].csr;
+}
+
+static void __init
+init_one_io7_msi(struct io7 *io7, unsigned int which, unsigned int where)
+{
+	/*
+	 * MSI_CTL has target PID @ 14
+	 */
+	io7->csrs->PO7_MSI_CTL[which].csr = ((unsigned long)where << 14);
+	mb();
+	io7->csrs->PO7_MSI_CTL[which].csr;
+}
+
+static void __init
+init_io7_irqs(struct io7 *io7, 
+	      struct hw_interrupt_type *lsi_ops,
+	      struct hw_interrupt_type *msi_ops)
+{
+	long base = (io7->pe << MARVEL_IRQ_VEC_PE_SHIFT) + 16;
+	long i;
+
+	printk("Initializing interrupts for IO7 at PE %u - base %lx\n",
+		io7->pe, base);
+
+	/*
+	 * Where should interrupts from this IO7 go?
+	 *
+	 * They really should be sent to the local CPU to avoid having to
+	 * traverse the mesh, but if it's not an SMP kernel, they have to
+	 * go to the boot CPU. Send them all to the boot CPU for now,
+	 * as each secondary starts, it can redirect it's local device
+	 * interrupts.
+	 */
+	printk("  Interrupts reported to CPU at PE %u\n", boot_cpuid);
+
+	spin_lock(&io7->irq_lock);
+
+	/* set up the error irqs */
+	io7_redirect_irq(io7, &io7->csrs->HLT_CTL.csr, boot_cpuid);
+	io7_redirect_irq(io7, &io7->csrs->HPI_CTL.csr, boot_cpuid);
+	io7_redirect_irq(io7, &io7->csrs->CRD_CTL.csr, boot_cpuid);
+	io7_redirect_irq(io7, &io7->csrs->STV_CTL.csr, boot_cpuid);
+	io7_redirect_irq(io7, &io7->csrs->HEI_CTL.csr, boot_cpuid);
+
+	/* Set up the lsi irqs.  */
+	for (i = 0; i < 128; ++i) {
+		irq_desc[base + i].status = IRQ_DISABLED | IRQ_LEVEL;
+		irq_desc[base + i].handler = lsi_ops;
+	}
+
+	/* Disable the implemented irqs in hardware.  */
+	for (i = 0; i < 0x60; ++i) 
+		init_one_io7_lsi(io7, i, boot_cpuid);
+
+	init_one_io7_lsi(io7, 0x74, boot_cpuid);
+	init_one_io7_lsi(io7, 0x75, boot_cpuid);
+
+
+	/* Set up the msi irqs.  */
+	for (i = 128; i < (128 + 512); ++i) {
+		irq_desc[base + i].status = IRQ_DISABLED | IRQ_LEVEL;
+		irq_desc[base + i].handler = msi_ops;
+	}
+
+	for (i = 0; i < 16; ++i)
+		init_one_io7_msi(io7, i, boot_cpuid);
+
+	spin_unlock(&io7->irq_lock);
+}
+
+static void __init
+marvel_init_irq(void)
+{
+	int i;
+	struct io7 *io7 = NULL;
+
+	/* Reserve the legacy irqs.  */
+	for (i = 0; i < 16; ++i) {
+		irq_desc[i].status = IRQ_DISABLED;
+		irq_desc[i].handler = &marvel_legacy_irq_type;
+	}
+
+	/* Init the io7 irqs.  */
+	for (io7 = NULL; (io7 = marvel_next_io7(io7)) != NULL; )
+		init_io7_irqs(io7, &io7_lsi_irq_type, &io7_msi_irq_type);
+}
+
+static int 
+marvel_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+	struct pci_controller *hose = dev->sysdata;
+	struct io7_port *io7_port = hose->sysdata;
+	struct io7 *io7 = io7_port->io7;
+	int msi_loc, msi_data_off;
+	u16 msg_ctl;
+	u16 msg_dat;
+	u8 intline; 
+	int irq;
+
+	pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &intline);
+	irq = intline;
+
+	msi_loc = pci_find_capability(dev, PCI_CAP_ID_MSI);
+	msg_ctl = 0;
+	if (msi_loc) 
+		pci_read_config_word(dev, msi_loc + PCI_MSI_FLAGS, &msg_ctl);
+
+	if (msg_ctl & PCI_MSI_FLAGS_ENABLE) {
+ 		msi_data_off = PCI_MSI_DATA_32;
+		if (msg_ctl & PCI_MSI_FLAGS_64BIT) 
+			msi_data_off = PCI_MSI_DATA_64;
+		pci_read_config_word(dev, msi_loc + msi_data_off, &msg_dat);
+
+		irq = msg_dat & 0x1ff;		/* we use msg_data<8:0> */
+		irq += 0x80;			/* offset for lsi       */
+
+#if 1
+		printk("PCI:%d:%d:%d (hose %d) [%s] is using MSI\n",
+		       dev->bus->number, 
+		       PCI_SLOT(dev->devfn), 
+		       PCI_FUNC(dev->devfn),
+		       hose->index,
+		       dev->name);
+		printk("  %d message(s) from 0x%04x\n", 
+		       1 << ((msg_ctl & PCI_MSI_FLAGS_QSIZE) >> 4),
+		       msg_dat);
+		printk("  reporting on %d IRQ(s) from %d (0x%x)\n", 
+		       1 << ((msg_ctl & PCI_MSI_FLAGS_QSIZE) >> 4),
+		       (irq + 16) | (io7->pe << MARVEL_IRQ_VEC_PE_SHIFT),
+		       (irq + 16) | (io7->pe << MARVEL_IRQ_VEC_PE_SHIFT));
+#endif
+
+#if 0
+		pci_write_config_word(dev, msi_loc + PCI_MSI_FLAGS,
+				      msg_ctl & ~PCI_MSI_FLAGS_ENABLE);
+		pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &intline);
+		irq = intline;
+
+		printk("  forcing LSI interrupt on irq %d [0x%x]\n", irq, irq);
+#endif
+	}
+
+	irq += 16;					/* offset for legacy */
+	irq |= io7->pe << MARVEL_IRQ_VEC_PE_SHIFT;	/* merge the pid     */
+
+	return irq; 
+}
+
+static void __init
+marvel_init_pci(void)
+{
+	struct io7 *io7;
+
+	marvel_register_error_handlers();
+
+	pci_probe_only = 1;
+	common_init_pci();
+
+#ifdef CONFIG_VGA_HOSE
+	locate_and_init_vga(NULL);
+#endif
+
+	/* Clear any io7 errors.  */
+	for (io7 = NULL; (io7 = marvel_next_io7(io7)) != NULL; ) 
+		io7_clear_errors(io7);
+}
+
+static void
+marvel_init_rtc(void)
+{
+	init_rtc_irq();
+}
+
+static void
+marvel_smp_callin(void)
+{
+	int cpuid = hard_smp_processor_id();
+	struct io7 *io7 = marvel_find_io7(cpuid);
+	unsigned int i;
+
+	if (!io7)
+		return;
+
+	/* 
+	 * There is a local IO7 - redirect all of it's interrupts here.
+	 */
+	printk("Redirecting IO7 interrupts to local CPU at PE %u\n", cpuid);
+
+	/* Redirect the error IRQS here.  */
+	io7_redirect_irq(io7, &io7->csrs->HLT_CTL.csr, cpuid);
+	io7_redirect_irq(io7, &io7->csrs->HPI_CTL.csr, cpuid);
+	io7_redirect_irq(io7, &io7->csrs->CRD_CTL.csr, cpuid);
+	io7_redirect_irq(io7, &io7->csrs->STV_CTL.csr, cpuid);
+	io7_redirect_irq(io7, &io7->csrs->HEI_CTL.csr, cpuid);
+
+	/* Redirect the implemented LSIs here.  */
+	for (i = 0; i < 0x60; ++i) 
+		io7_redirect_one_lsi(io7, i, cpuid);
+
+	io7_redirect_one_lsi(io7, 0x74, cpuid);
+	io7_redirect_one_lsi(io7, 0x75, cpuid);
+
+	/* Redirect the MSIs here.  */
+	for (i = 0; i < 16; ++i)
+		io7_redirect_one_msi(io7, i, cpuid);
+}
+
+/*
+ * System Vectors
+ */
+struct alpha_machine_vector marvel_ev7_mv __initmv = {
+	vector_name:		"MARVEL/EV7",
+	DO_EV7_MMU,
+	DO_DEFAULT_RTC,
+	DO_MARVEL_IO,
+	DO_MARVEL_BUS,
+	machine_check:		marvel_machine_check,
+	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
+	min_io_address:		DEFAULT_IO_BASE,
+	min_mem_address:	DEFAULT_MEM_BASE,
+	pci_dac_offset:		IO7_DAC_OFFSET,
+
+	nr_irqs:		MARVEL_NR_IRQS,
+	device_interrupt:	io7_device_interrupt,
+
+	agp_info:		marvel_agp_info,
+
+	smp_callin:		marvel_smp_callin,
+	init_arch:		marvel_init_arch,
+	init_irq:		marvel_init_irq,
+	init_rtc:		marvel_init_rtc,
+	init_pci:		marvel_init_pci,
+	kill_arch:		marvel_kill_arch,
+	pci_map_irq:		marvel_map_irq,
+	pci_swizzle:		common_swizzle,
+
+	pa_to_nid:		marvel_pa_to_nid,
+	cpuid_to_nid:		marvel_cpuid_to_nid,
+	node_mem_start:		marvel_node_mem_start,
+	node_mem_size:		marvel_node_mem_size,
+};
+ALIAS_MV(marvel_ev7)
diff -urN linux-2.4.21-pre3/arch/alpha/kernel/sys_miata.c linux-2.4.21-pre4/arch/alpha/kernel/sys_miata.c
--- linux-2.4.21-pre3/arch/alpha/kernel/sys_miata.c	Mon Feb 25 11:37:52 2002
+++ linux-2.4.21-pre4/arch/alpha/kernel/sys_miata.c	Tue Jan 28 19:44:28 2003
@@ -245,6 +245,8 @@
 static void
 miata_kill_arch(int mode)
 {
+	cia_kill_arch(mode);
+
 	switch(mode) {
 	case LINUX_REBOOT_CMD_RESTART:
 		/* Who said DEC engineers have no sense of humor? ;-)  */ 
diff -urN linux-2.4.21-pre3/arch/alpha/kernel/sys_mikasa.c linux-2.4.21-pre4/arch/alpha/kernel/sys_mikasa.c
--- linux-2.4.21-pre3/arch/alpha/kernel/sys_mikasa.c	Fri Oct 27 10:55:01 2000
+++ linux-2.4.21-pre4/arch/alpha/kernel/sys_mikasa.c	Tue Jan 28 19:44:28 2003
@@ -259,6 +259,7 @@
 	init_irq:		mikasa_init_irq,
 	init_rtc:		common_init_rtc,
 	init_pci:		cia_init_pci,
+	kill_arch:		cia_kill_arch,
 	pci_map_irq:		mikasa_map_irq,
 	pci_swizzle:		common_swizzle,
 };
diff -urN linux-2.4.21-pre3/arch/alpha/kernel/sys_nautilus.c linux-2.4.21-pre4/arch/alpha/kernel/sys_nautilus.c
--- linux-2.4.21-pre3/arch/alpha/kernel/sys_nautilus.c	Mon May 21 13:40:39 2001
+++ linux-2.4.21-pre4/arch/alpha/kernel/sys_nautilus.c	Tue Jan 28 19:44:28 2003
@@ -45,6 +45,7 @@
 #include <asm/hwrpb.h>
 
 #include "proto.h"
+#include "err_impl.h"
 #include "irq_impl.h"
 #include "pci_impl.h"
 #include "machvec_impl.h"
@@ -99,324 +100,12 @@
 	}
 }
 
-/* Machine check handler code
- *
- * Perform analysis of a machine check that was triggered by the EV6
- * CPU's fault-detection mechanism.
- */
-
-/* IPR structures for EV6, containing the necessary data for the
- * machine check handler to unpick the logout frame
- */
-
-/* I_STAT */
-
-#define EV6__I_STAT__PAR                ( 1 << 29 )
-
-/* MM_STAT */
-
-#define EV6__MM_STAT__DC_TAG_PERR       ( 1 << 10 )
-
-/* DC_STAT */
-
-#define EV6__DC_STAT__SEO               ( 1 << 4 )
-#define EV6__DC_STAT__ECC_ERR_LD        ( 1 << 3 )
-#define EV6__DC_STAT__ECC_ERR_ST        ( 1 << 2 )
-#define EV6__DC_STAT__TPERR_P1          ( 1 << 1 )
-#define EV6__DC_STAT__TPERR_P0          ( 1      )
-
-/* C_STAT */
-
-#define EV6__C_STAT__BC_PERR            ( 0x01 )
-#define EV6__C_STAT__DC_PERR            ( 0x02 )
-#define EV6__C_STAT__DSTREAM_MEM_ERR    ( 0x03 )
-#define EV6__C_STAT__DSTREAM_BC_ERR     ( 0x04 )
-#define EV6__C_STAT__DSTREAM_DC_ERR     ( 0x05 )
-#define EV6__C_STAT__PROBE_BC_ERR0      ( 0x06 )
-#define EV6__C_STAT__PROBE_BC_ERR1      ( 0x07 )
-#define EV6__C_STAT__ISTREAM_MEM_ERR    ( 0x0B )
-#define EV6__C_STAT__ISTREAM_BC_ERR     ( 0x0C )
-#define EV6__C_STAT__DSTREAM_MEM_DBL    ( 0x13 )
-#define EV6__C_STAT__DSTREAM_BC_DBL     ( 0x14 )
-#define EV6__C_STAT__ISTREAM_MEM_DBL    ( 0x1B )
-#define EV6__C_STAT__ISTREAM_BC_DBL     ( 0x1C )
-
-
-/* Take the two syndromes from the CBOX error chain and convert them
- * into a bit number.  */
-
-/* NOTE - since I don't know of any difference between C0 and C1 I
-   just ignore C1, since in all cases I've seen so far they are
-   identical.  */
-
-static const unsigned char ev6_bit_to_syndrome[72] =
-{
-	0xce, 0xcb, 0xd3, 0xd5, 0xd6, 0xd9, 0xda, 0xdc,     /* 0 */
-	0x23, 0x25, 0x26, 0x29, 0x2a, 0x2c, 0x31, 0x34,     /* 8 */
-	0x0e, 0x0b, 0x13, 0x15, 0x16, 0x19, 0x1a, 0x1c,     /* 16 */
-	0xe3, 0xe5, 0xe6, 0xe9, 0xea, 0xec, 0xf1, 0xf4,     /* 24 */
-	0x4f, 0x4a, 0x52, 0x54, 0x57, 0x58, 0x5b, 0x5d,     /* 32 */
-	0xa2, 0xa4, 0xa7, 0xa8, 0xab, 0xad, 0xb0, 0xb5,     /* 40 */
-	0x8f, 0x8a, 0x92, 0x94, 0x97, 0x98, 0x9b, 0x9d,     /* 48 */
-	0x62, 0x64, 0x67, 0x68, 0x6b, 0x6d, 0x70, 0x75,     /* 56 */
-	0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80      /* 64 */
-};
-
-
-static int ev6_syn2bit(unsigned long c0, unsigned long c1)
-{
-	int bit;
-
-	for (bit = 0; bit < 72; bit++)
-		if (ev6_bit_to_syndrome[bit] == c0)	return bit;
-	for (bit = 0; bit < 72; bit++)
-		if (ev6_bit_to_syndrome[bit] == c1)	return bit + 64;
-
-	return -1;                  /* not found */
-}
-
-
-/* Single bit ECC errors are categorized here.  */
-
-#if 0
-static const char *interr = "CPU internal error";
-static const char *slotb= "Slot-B error";
-static const char *membus= "Memory/EV6-bus error";
-#else
-static const char *interr = "";
-static const char *slotb = "";
-static const char *membus = "";
-#endif
-
-static void
-ev6_crd_interp(char *interp, struct el_common_EV6_mcheck * L)
-{
-	/* Icache data or tag parity error.  */
-	if (L->I_STAT & EV6__I_STAT__PAR) {
-		sprintf(interp, "%s: I_STAT[PAR]\n "
-			"Icache data or tag parity error", interr);
-		return;
-	}
-
-	/* Dcache tag parity error (on issue) (DFAULT).  */
-	if (L->MM_STAT & EV6__MM_STAT__DC_TAG_PERR) {
-		sprintf(interp, "%s: MM_STAT[DC_TAG_PERR]\n "
-			"Dcache tag parity error(on issue)", interr);
-		return;
-	}
-
-	/* Errors relating to D-stream set non-zero DC_STAT.
-	   Mask CRD bits.  */
-	switch (L->DC_STAT & (EV6__DC_STAT__ECC_ERR_ST
-			      | EV6__DC_STAT__ECC_ERR_LD)) {
-	case EV6__DC_STAT__ECC_ERR_ST:
-		/* Dcache single-bit ECC error on small store */
-		sprintf(interp, "%s: DC_STAT[ECC_ERR_ST]\n "
-			"Dcache single-bit ECC error on small store", interr);
-		return;
-
-	case EV6__DC_STAT__ECC_ERR_LD:
-		switch (L->C_STAT) {
-		case 0:
-			/* Dcache single-bit error on speculative load */
-			/* Bcache victim read on Dcache/Bcache miss */
-			sprintf(interp, "%s: DC_STAT[ECC_ERR_LD] C_STAT=0\n "
-				"Dcache single-bit ECC error on speculative load",
-				slotb);
-			return;
-
-		case EV6__C_STAT__DSTREAM_DC_ERR:
-			/* Dcache single bit error on load */
-			sprintf(interp, "%s: DC_STAT[ECC_ERR_LD] C_STAT[DSTREAM_DC_ERR]\n"
-				" Dcache single-bit ECC error on speculative load, bit %d",
-				interr, ev6_syn2bit(L->DC0_SYNDROME, L->DC1_SYNDROME));
-			return;
-
-		case EV6__C_STAT__DSTREAM_BC_ERR:
-			/* Bcache single-bit error on Dcache fill */
-			sprintf(interp, "%s: DC_STAT[ECC_ERR_LD] C_STAT[DSTREAM_BC_ERR]\n"
-				" Bcache single-bit error on Dcache fill, bit %d",
-				slotb, ev6_syn2bit(L->DC0_SYNDROME, L->DC1_SYNDROME));
-			return;
-
-		case EV6__C_STAT__DSTREAM_MEM_ERR:
-			/* Memory single-bit error on Dcache fill */
-			sprintf(interp, "%s (to Dcache): DC_STAT[ECC_ERR_LD] "
-				"C_STAT[DSTREAM_MEM_ERR]\n "
-				"Memory single-bit error on Dcache fill, "
-				"Address 0x%lX, bit %d",
-				membus, L->C_ADDR, ev6_syn2bit(L->DC0_SYNDROME,
-							       L->DC1_SYNDROME));
-			return;
-		}
-	}
-
-	/* I-stream, other misc errors go on C_STAT alone */
-	switch (L->C_STAT) {
-	case EV6__C_STAT__ISTREAM_BC_ERR:
-		/* Bcache single-bit error on Icache fill (also MCHK) */
-		sprintf(interp, "%s: C_STAT[ISTREAM_BC_ERR]\n "
-			"Bcache single-bit error on Icache fill, bit %d",
-			slotb, ev6_syn2bit(L->DC0_SYNDROME, L->DC1_SYNDROME));
-		return;
-
-	case EV6__C_STAT__ISTREAM_MEM_ERR:
-		/* Memory single-bit error on Icache fill (also MCHK) */
-		sprintf(interp, "%s : C_STATISTREAM_MEM_ERR]\n "
-			"Memory single-bit error on Icache fill "
-			"addr 0x%lX, bit %d",
-			membus, L->C_ADDR, ev6_syn2bit(L->DC0_SYNDROME,
-						       L->DC1_SYNDROME));
-		return;
-
-	case EV6__C_STAT__PROBE_BC_ERR0:
-	case EV6__C_STAT__PROBE_BC_ERR1:
-		/* Bcache single-bit error on a probe hit */
-		sprintf(interp, "%s: C_STAT[PROBE_BC_ERR]\n "
-			"Bcache single-bit error on a probe hit, "
-			"addr 0x%lx, bit %d",
-			slotb, L->C_ADDR, ev6_syn2bit(L->DC0_SYNDROME,
-						      L->DC1_SYNDROME));
-		return;
-	}
-}
-
-static void
-ev6_mchk_interp(char *interp, struct el_common_EV6_mcheck * L)
-{
-	/* Machine check errors described by DC_STAT */
-	switch (L->DC_STAT) {
-	case EV6__DC_STAT__TPERR_P0:
-	case EV6__DC_STAT__TPERR_P1:
-		/* Dcache tag parity error (on retry) */
-		sprintf(interp, "%s: DC_STAT[TPERR_P0|TPERR_P1]\n "
-			"Dcache tag parity error(on retry)", interr);
-		return;
-
-	case EV6__DC_STAT__SEO:
-		/* Dcache second error on store */
-		sprintf(interp, "%s: DC_STAT[SEO]\n "
-			"Dcache second error during mcheck", interr);
-		return;
-	}
-
-	/* Machine check errors described by C_STAT */
-	switch (L->C_STAT) {
-	case EV6__C_STAT__DC_PERR:
-		/* Dcache duplicate tag parity error */
-		sprintf(interp, "%s: C_STAT[DC_PERR]\n "
-			"Dcache duplicate tag parity error at 0x%lX",
-			interr, L->C_ADDR);
-		return;
-
-	case EV6__C_STAT__BC_PERR:
-		/* Bcache tag parity error */
-		sprintf(interp, "%s: C_STAT[BC_PERR]\n "
-			"Bcache tag parity error at 0x%lX",
-			slotb, L->C_ADDR);
-		return;
-
-	case EV6__C_STAT__ISTREAM_BC_ERR:
-		/* Bcache single-bit error on Icache fill (also CRD) */
-		sprintf(interp, "%s: C_STAT[ISTREAM_BC_ERR]\n "
-			"Bcache single-bit error on Icache fill 0x%lX bit %d",
-			slotb, L->C_ADDR,
-			ev6_syn2bit(L->DC0_SYNDROME, L->DC1_SYNDROME));
-		return;
-
-
-	case EV6__C_STAT__ISTREAM_MEM_ERR:
-		/* Memory single-bit error on Icache fill (also CRD) */
-		sprintf(interp, "%s: C_STAT[ISTREAM_MEM_ERR]\n "
-			"Memory single-bit error on Icache fill 0x%lX, bit %d",
-			membus, L->C_ADDR,
-			ev6_syn2bit(L->DC0_SYNDROME, L->DC1_SYNDROME));
-		return;
-
-
-	case EV6__C_STAT__ISTREAM_BC_DBL:
-		/* Bcache double-bit error on Icache fill */
-		sprintf(interp, "%s: C_STAT[ISTREAM_BC_DBL]\n "
-			"Bcache double-bit error on Icache fill at 0x%lX",
-			slotb, L->C_ADDR);
-		return;
-	case EV6__C_STAT__DSTREAM_BC_DBL:
-		/* Bcache double-bit error on Dcache fill */
-		sprintf(interp, "%s: C_STAT[DSTREAM_BC_DBL]\n "
-			"Bcache double-bit error on Dcache fill at 0x%lX",
-			slotb, L->C_ADDR);
-		return;
-
-	case EV6__C_STAT__ISTREAM_MEM_DBL:
-		/* Memory double-bit error on Icache fill */
-		sprintf(interp, "%s: C_STAT[ISTREAM_MEM_DBL]\n "
-			"Memory double-bit error on Icache fill at 0x%lX",
-			membus, L->C_ADDR);
-		return;
-
-	case EV6__C_STAT__DSTREAM_MEM_DBL:
-		/* Memory double-bit error on Dcache fill */
-		sprintf(interp, "%s: C_STAT[DSTREAM_MEM_DBL]\n "
-			"Memory double-bit error on Dcache fill at 0x%lX",
-			membus, L->C_ADDR);
-		return;
-	}
-}
-
-static void
-ev6_cpu_machine_check(unsigned long vector, struct el_common_EV6_mcheck *L,
-		      struct pt_regs *regs)
-{
-	char interp[80];
-
-	/* This is verbose and looks intimidating.  Should it be printed for
-	   corrected (CRD) machine checks? */
-
-	printk(KERN_CRIT "PALcode logout frame:  "
-	       "MCHK_Code       %d  "
-	       "MCHK_Frame_Rev  %d\n"
-	       "I_STAT  %016lx  "
-	       "DC_STAT %016lx  "
-	       "C_ADDR  %016lx\n"
-	       "SYND1   %016lx  "
-	       "SYND0   %016lx  "
-	       "C_STAT  %016lx\n"
-	       "C_STS   %016lx  "
-	       "RES     %016lx  "
-	       "EXC_ADDR%016lx\n"
-	       "IER_CM  %016lx  "
-	       "ISUM    %016lx  "
-	       "MM_STAT %016lx\n"
-	       "PALBASE %016lx  "
-	       "I_CTL   %016lx  "
-	       "PCTX    %016lx\n"
-	       "CPU registers: "
-	       "PC      %016lx  "
-	       "Return  %016lx\n",
-	       L->MCHK_Code, L->MCHK_Frame_Rev, L->I_STAT, L->DC_STAT,
-	       L->C_ADDR, L->DC1_SYNDROME, L->DC0_SYNDROME, L->C_STAT,
-	       L->C_STS, L->RESERVED0, L->EXC_ADDR, L->IER_CM, L->ISUM,
-	       L->MM_STAT, L->PAL_BASE, L->I_CTL, L->PCTX,
-	       regs->pc, regs->r26);
-
-	/* Attempt an interpretation on the meanings of the fields above.  */
-	sprintf(interp, "No interpretation available!" );
-	if (vector == SCB_Q_PROCERR)
-		ev6_crd_interp(interp, L);
-	else if (vector == SCB_Q_PROCMCHK)
-		ev6_mchk_interp(interp, L);
-
-	printk(KERN_CRIT "interpretation: %s\n\n", interp);
-}
-
-
 /* Perform analysis of a machine check that arrived from the system (NMI) */
 
 static void
 naut_sys_machine_check(unsigned long vector, unsigned long la_ptr,
 		       struct pt_regs *regs)
 {
-	printk("xtime %lx\n", CURRENT_TIME);
 	printk("PC %lx RA %lx\n", regs->pc, regs->r26);
 	irongate_pci_clr_err();
 }
@@ -429,7 +118,6 @@
 		       struct pt_regs *regs)
 {
 	char *mchk_class;
-	unsigned cpu_analysis=0, sys_analysis=0;
 
 	/* Now for some analysis.  Machine checks fall into two classes --
 	   those picked up by the system, and those picked up by the CPU.
@@ -462,39 +150,20 @@
 		return;
 	}
 
-	switch (vector) {
-	case SCB_Q_SYSERR:
-		mchk_class = "Correctable System Machine Check (NMI)";
-		sys_analysis = 1;
-		break;
-	case SCB_Q_SYSMCHK:
-		mchk_class = "Fatal System Machine Check (NMI)";
-		sys_analysis = 1;
-		break;
-
-	case SCB_Q_PROCERR:
-		mchk_class = "Correctable Processor Machine Check";
-		cpu_analysis = 1;
-		break;
-	case SCB_Q_PROCMCHK:
-		mchk_class = "Fatal Processor Machine Check";
-		cpu_analysis = 1;
-		break;
-
-	default:
-		mchk_class = "Unknown vector!";
-		break;
+	if (vector == SCB_Q_SYSERR)
+		mchk_class = "Correctable";
+	else if (vector == SCB_Q_SYSMCHK)
+		mchk_class = "Fatal";
+	else {
+		ev6_machine_check(vector, la_ptr, regs);
+		return;
 	}
 
-	printk(KERN_CRIT "NAUTILUS Machine check 0x%lx [%s]\n",
+	printk(KERN_CRIT "NAUTILUS Machine check 0x%lx "
+			 "[%s System Machine Check (NMI)]\n",
 	       vector, mchk_class);
 
-	if (cpu_analysis)
-		ev6_cpu_machine_check(vector,
-				      (struct el_common_EV6_mcheck *)la_ptr,
-				      regs);
-	if (sys_analysis)
-		naut_sys_machine_check(vector, la_ptr, regs);
+	naut_sys_machine_check(vector, la_ptr, regs);
 
 	/* Tell the PALcode to clear the machine check */
 	draina();
diff -urN linux-2.4.21-pre3/arch/alpha/kernel/sys_ruffian.c linux-2.4.21-pre4/arch/alpha/kernel/sys_ruffian.c
--- linux-2.4.21-pre3/arch/alpha/kernel/sys_ruffian.c	Fri Oct 12 15:35:53 2001
+++ linux-2.4.21-pre4/arch/alpha/kernel/sys_ruffian.c	Tue Jan 28 19:44:28 2003
@@ -84,6 +84,7 @@
 static void
 ruffian_kill_arch (int mode)
 {
+	cia_kill_arch(mode);
 #if 0
 	/* This only causes re-entry to ARCSBIOS */
 	/* Perhaps this works for other PYXIS as well?  */
diff -urN linux-2.4.21-pre3/arch/alpha/kernel/sys_sx164.c linux-2.4.21-pre4/arch/alpha/kernel/sys_sx164.c
--- linux-2.4.21-pre3/arch/alpha/kernel/sys_sx164.c	Fri Oct 12 15:35:53 2001
+++ linux-2.4.21-pre4/arch/alpha/kernel/sys_sx164.c	Tue Jan 28 19:44:28 2003
@@ -171,7 +171,7 @@
 	init_irq:		sx164_init_irq,
 	init_rtc:		common_init_rtc,
 	init_pci:		sx164_init_pci,
-	kill_arch:		NULL,
+	kill_arch:		cia_kill_arch,
 	pci_map_irq:		sx164_map_irq,
 	pci_swizzle:		common_swizzle,
 };
diff -urN linux-2.4.21-pre3/arch/alpha/kernel/sys_titan.c linux-2.4.21-pre4/arch/alpha/kernel/sys_titan.c
--- linux-2.4.21-pre3/arch/alpha/kernel/sys_titan.c	Fri Oct 12 15:35:53 2001
+++ linux-2.4.21-pre4/arch/alpha/kernel/sys_titan.c	Tue Jan 28 19:44:28 2003
@@ -8,6 +8,8 @@
  *
  * Code supporting TITAN systems (EV6+TITAN), currently:
  *      Privateer
+ *	Falcon
+ *	Granite
  */
 
 #include <linux/config.h>
@@ -33,12 +35,26 @@
 #include "irq_impl.h"
 #include "pci_impl.h"
 #include "machvec_impl.h"
+#include "err_impl.h"
 
-/* Note mask bit is true for ENABLED irqs. */
-static unsigned long cached_irq_mask;
-/* Titan boards handle at most four CPUs.  */
-static unsigned long cpu_irq_affinity[4] = { ~0UL, ~0UL, ~0UL, ~0UL };
+
+/*
+ * Titan generic
+ */
+
+/*
+ * Titan supports up to 4 CPUs
+ */
+static unsigned long titan_cpu_irq_affinity[4] = { ~0UL, ~0UL, ~0UL, ~0UL };
 
+/*
+ * Mask is set (1) if enabled
+ */
+static unsigned long titan_cached_irq_mask;
+
+/*
+ * Need SMP-safe access to interrupt CSRs
+ */
 spinlock_t titan_irq_lock = SPIN_LOCK_UNLOCKED;
 
 static void
@@ -54,10 +70,10 @@
 	unsigned long mask0, mask1, mask2, mask3, dummy;
 
 	mask &= ~isa_enable;
-	mask0 = mask & cpu_irq_affinity[0];
-	mask1 = mask & cpu_irq_affinity[1];
-	mask2 = mask & cpu_irq_affinity[2];
-	mask3 = mask & cpu_irq_affinity[3];
+	mask0 = mask & titan_cpu_irq_affinity[0];
+	mask1 = mask & titan_cpu_irq_affinity[1];
+	mask2 = mask & titan_cpu_irq_affinity[2];
+	mask3 = mask & titan_cpu_irq_affinity[3];
 
 	if (bcpu == 0) mask0 |= isa_enable;
 	else if (bcpu == 1) mask1 |= isa_enable;
@@ -84,8 +100,8 @@
 	*dim3;
 #else
 	volatile unsigned long *dimB;
-	if (bcpu == 0) dimB = &cchip->dim0.csr;
-	else if (bcpu == 1) dimB = &cchip->dim1.csr;
+	dimB = &cchip->dim0.csr;
+	if (bcpu == 1) dimB = &cchip->dim1.csr;
 	else if (bcpu == 2) dimB = &cchip->dim2.csr;
 	else if (bcpu == 3) dimB = &cchip->dim3.csr;
 
@@ -96,79 +112,68 @@
 }
 
 static inline void
-privateer_enable_irq(unsigned int irq)
+titan_enable_irq(unsigned int irq)
 {
 	spin_lock(&titan_irq_lock);
-	cached_irq_mask |= 1UL << (irq - 16);
-	titan_update_irq_hw(cached_irq_mask);
+	titan_cached_irq_mask |= 1UL << (irq - 16);
+	titan_update_irq_hw(titan_cached_irq_mask);
 	spin_unlock(&titan_irq_lock);
 }
 
 static inline void
-privateer_disable_irq(unsigned int irq)
+titan_disable_irq(unsigned int irq)
 {
 	spin_lock(&titan_irq_lock);
-	cached_irq_mask &= ~(1UL << (irq - 16));
-	titan_update_irq_hw(cached_irq_mask);
+	titan_cached_irq_mask &= ~(1UL << (irq - 16));
+	titan_update_irq_hw(titan_cached_irq_mask);
 	spin_unlock(&titan_irq_lock);
 }
 
 static unsigned int
-privateer_startup_irq(unsigned int irq)
+titan_startup_irq(unsigned int irq)
 {
-	privateer_enable_irq(irq);
+	titan_enable_irq(irq);
 	return 0;	/* never anything pending */
 }
 
 static void
-privateer_end_irq(unsigned int irq)
+titan_end_irq(unsigned int irq)
 {
 	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
-		privateer_enable_irq(irq);
+		titan_enable_irq(irq);
 }
 
 static void
-cpu_set_irq_affinity(unsigned int irq, unsigned long affinity)
+titan_cpu_set_irq_affinity(unsigned int irq, unsigned long affinity)
 {
 	int cpu;
 
 	for (cpu = 0; cpu < 4; cpu++) {
 		if (affinity & (1UL << cpu))
-			cpu_irq_affinity[cpu] |= 1UL << irq;
+			titan_cpu_irq_affinity[cpu] |= 1UL << irq;
 		else
-			cpu_irq_affinity[cpu] &= ~(1UL << irq);
+			titan_cpu_irq_affinity[cpu] &= ~(1UL << irq);
 	}
 
 }
 
 static void
-privateer_set_affinity(unsigned int irq, unsigned long affinity)
+titan_set_irq_affinity(unsigned int irq, unsigned long affinity)
 { 
 	spin_lock(&titan_irq_lock);
-	cpu_set_irq_affinity(irq - 16, affinity);
-	titan_update_irq_hw(cached_irq_mask);
+	titan_cpu_set_irq_affinity(irq - 16, affinity);
+	titan_update_irq_hw(titan_cached_irq_mask);
 	spin_unlock(&titan_irq_lock);
 }
 
-static struct hw_interrupt_type privateer_irq_type = {
-	typename:	"PRIVATEER",
-	startup:	privateer_startup_irq,
-	shutdown:	privateer_disable_irq,
-	enable:		privateer_enable_irq,
-	disable:	privateer_disable_irq,
-	ack:		privateer_disable_irq,
-	end:		privateer_end_irq,
-	set_affinity:	privateer_set_affinity,
-};
-
 static void
-privateer_device_interrupt(unsigned long vector, struct pt_regs * regs)
+titan_device_interrupt(unsigned long vector, struct pt_regs * regs)
 {
-	printk("privateer_device_interrupt: NOT IMPLEMENTED YET!! \n");
+	printk("titan_device_interrupt: NOT IMPLEMENTED YET!! \n");
 }
 
 static void 
-privateer_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
+titan_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
 {
 	int irq;
 
@@ -181,192 +186,209 @@
 init_titan_irqs(struct hw_interrupt_type * ops, int imin, int imax)
 {
 	long i;
-	for(i = imin; i <= imax; ++i) {
+	for (i = imin; i <= imax; ++i) {
 		irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
 		irq_desc[i].handler = ops;
 	}
 }
 
+static struct hw_interrupt_type titan_irq_type = {
+	typename:	"TITAN",
+	startup:	titan_startup_irq,
+	shutdown:	titan_disable_irq,
+	enable:		titan_enable_irq,
+	disable:	titan_disable_irq,
+	ack:		titan_disable_irq,
+	end:		titan_end_irq,
+	set_affinity:	titan_set_irq_affinity,
+};
+
+static void
+titan_intr_nop(int irq, void *dev_id, struct pt_regs *regs)
+{
+	/*
+	 * This is a NOP interrupt handler for the purposes of
+	 * event counting -- just return.
+	 */
+}
+
 static void __init
-privateer_init_irq(void)
+titan_init_irq(void)
 {
-	extern asmlinkage void entInt(void);
-	int cpu;
+	if (alpha_using_srm && !alpha_mv.device_interrupt)
+		alpha_mv.device_interrupt = titan_srm_device_interrupt;
+	if (!alpha_mv.device_interrupt)
+		alpha_mv.device_interrupt = titan_device_interrupt;
 
+	titan_update_irq_hw(0);
+
+	init_titan_irqs(&titan_irq_type, 16, 63 + 16);
+}
+
+static void __init
+titan_legacy_init_irq(void)
+{
+	/* init the legacy dma controller */
 	outb(0, DMA1_RESET_REG);
 	outb(0, DMA2_RESET_REG);
 	outb(DMA_MODE_CASCADE, DMA2_MODE_REG);
 	outb(0, DMA2_MASK_REG);
 
-	if (alpha_using_srm)
-		alpha_mv.device_interrupt = privateer_srm_device_interrupt;
+	/* init the legacy irq controller */
+	init_i8259a_irqs();
 
-	titan_update_irq_hw(0UL);
+	/* init the titan irqs */
+	titan_init_irq();
+}
 
-	init_i8259a_irqs();
-	init_titan_irqs(&privateer_irq_type, 16, 63 + 16);
+void
+titan_dispatch_irqs(u64 mask, struct pt_regs *regs)
+{
+	unsigned long vector;
+
+	/*
+	 * Mask down to those interrupts which are enable on this processor
+	 */
+	mask &= titan_cpu_irq_affinity[smp_processor_id()];
+
+	/*
+	 * Dispatch all requested interrupts 
+	 */
+	while (mask) {
+		/* convert to SRM vector... priority is <63> -> <0> */
+		__asm__("ctlz %1, %0" : "=r"(vector) : "r"(mask));
+		vector = 63 - vector;
+		mask &= ~(1UL << vector);	/* clear it out 	 */
+		vector = 0x900 + (vector << 4);	/* convert to SRM vector */
+		
+		/* dispatch it */
+		alpha_mv.device_interrupt(vector, regs);
+	}
 }
 
+
 /*
- * Privateer PCI Fixup configuration.
- *
- * PCHIP 0 BUS 0 (Hose 0)
- *
- *     IDSEL	Dev	What
- *     -----	---	----
- *	18	 7	Embedded Southbridge
- *	19	 8	Slot 0 
- *	20	 9	Slot 1
- *	21	10	Slot 2 
- *	22	11	Slot 3
- *	23	12	Embedded HotPlug controller
- *	27	16	Embedded Southbridge IDE
- *	29	18     	Embedded Southbridge PMU
- *	31	20	Embedded Southbridge USB
- *
- * PCHIP 1 BUS 0 (Hose 1)
- *
- *     IDSEL	Dev	What
- *     -----	---	----
- *	12	 1	Slot 0
- * 	13	 2	Slot 1
- *	17	 6	Embedded hotPlug controller
- *
- * PCHIP 0 BUS 1 (Hose 2)
- *
- *     IDSEL	What
- *     -----	----
- *	NONE	AGP
- *
- * PCHIP 1 BUS 1 (Hose 3)
- *
- *     IDSEL	Dev	What
- *     -----	---	----
- *	12	 1	Slot 0
- * 	13	 2	Slot 1
- *	17	 6	Embedded hotPlug controller
- *
- * Summary @ TITAN_CSR_DIM0:
- * Bit      Meaning
- *  0-7     Unused
- *  8       PCHIP 0 BUS 1 YUKON (if present)
- *  9       PCHIP 1 BUS 1 YUKON
- * 10       PCHIP 1 BUS 0 YUKON
- * 11       PCHIP 0 BUS 0 YUKON
- * 12       PCHIP 0 BUS 0 SLOT 2 INT A
- * 13       PCHIP 0 BUS 0 SLOT 2 INT B
- * 14       PCHIP 0 BUS 0 SLOT 2 INT C
- * 15       PCHIP 0 BUS 0 SLOT 2 INT D
- * 16       PCHIP 0 BUS 0 SLOT 3 INT A
- * 17       PCHIP 0 BUS 0 SLOT 3 INT B
- * 18       PCHIP 0 BUS 0 SLOT 3 INT C
- * 19       PCHIP 0 BUS 0 SLOT 3 INT D
- * 20       PCHIP 0 BUS 0 SLOT 0 INT A
- * 21       PCHIP 0 BUS 0 SLOT 0 INT B
- * 22       PCHIP 0 BUS 0 SLOT 0 INT C
- * 23       PCHIP 0 BUS 0 SLOT 0 INT D
- * 24       PCHIP 0 BUS 0 SLOT 1 INT A
- * 25       PCHIP 0 BUS 0 SLOT 1 INT B
- * 26       PCHIP 0 BUS 0 SLOT 1 INT C
- * 27       PCHIP 0 BUS 0 SLOT 1 INT D
- * 28       PCHIP 1 BUS 0 SLOT 0 INT A
- * 29       PCHIP 1 BUS 0 SLOT 0 INT B
- * 30       PCHIP 1 BUS 0 SLOT 0 INT C
- * 31       PCHIP 1 BUS 0 SLOT 0 INT D
- * 32       PCHIP 1 BUS 0 SLOT 1 INT A
- * 33       PCHIP 1 BUS 0 SLOT 1 INT B
- * 34       PCHIP 1 BUS 0 SLOT 1 INT C
- * 35       PCHIP 1 BUS 0 SLOT 1 INT D
- * 36       PCHIP 1 BUS 1 SLOT 0 INT A
- * 37       PCHIP 1 BUS 1 SLOT 0 INT B
- * 38       PCHIP 1 BUS 1 SLOT 0 INT C
- * 39       PCHIP 1 BUS 1 SLOT 0 INT D
- * 40       PCHIP 1 BUS 1 SLOT 1 INT A
- * 41       PCHIP 1 BUS 1 SLOT 1 INT B
- * 42       PCHIP 1 BUS 1 SLOT 1 INT C
- * 43       PCHIP 1 BUS 1 SLOT 1 INT D
- * 44       AGP INT A
- * 45       AGP INT B
- * 46-47    Unused
- * 49       Reserved for Sleep mode
- * 50       Temperature Warning (optional)
- * 51       Power Warning (optional)
- * 52       Reserved
- * 53       South Bridge NMI
- * 54       South Bridge SMI INT
- * 55       South Bridge ISA Interrupt
- * 56-58    Unused
- * 59       PCHIP1_C_ERROR
- * 60       PCHIP0_C_ERROR 
- * 61       PCHIP1_H_ERROR
- * 62       PCHIP0_H_ERROR
- * 63       Reserved
- *
+ * Titan Family
  */
-static int __init
-privateer_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static void __init
+titan_late_init(void)
 {
-	u8 irq;
-	
-	pcibios_read_config_byte(dev->bus->number,
-				 dev->devfn,
-				 PCI_INTERRUPT_LINE,
-				 &irq);
-
-	/* is it routed through ISA? */
-	if ((irq & 0xF0) == 0xE0)
-		return (int)irq;
+	/*
+	 * Enable the system error interrupts. These interrupts are 
+	 * all reported to the kernel as machine checks, so the handler
+	 * is a nop so it can be called to count the individual events.
+	 */
+	request_irq(63+16, titan_intr_nop, SA_INTERRUPT, 
+		    "CChip Error", NULL);
+	request_irq(62+16, titan_intr_nop, SA_INTERRUPT, 
+		    "PChip 0 H_Error", NULL);
+	request_irq(61+16, titan_intr_nop, SA_INTERRUPT, 
+		    "PChip 1 H_Error", NULL);
+	request_irq(60+16, titan_intr_nop, SA_INTERRUPT, 
+		    "PChip 0 C_Error", NULL);
+	request_irq(59+16, titan_intr_nop, SA_INTERRUPT, 
+		    "PChip 1 C_Error", NULL);
+
+	/* 
+	 * Register our error handlers.
+	 */
+	titan_register_error_handlers();
+
+	/*
+	 * Check if the console left us any error logs.
+	 */
+	cdl_check_console_data_log();
 
-	return (int)irq + 16;	/* HACK -- this better only be called once */
 }
 
-#ifdef CONFIG_VGA_HOSE
-static struct pci_controller * __init
-privateer_vga_hose_select(struct pci_controller *h1, struct pci_controller *h2)
+static int __devinit
+titan_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
 {
-	struct pci_controller *hose = h1;
-	int agp1, agp2;
-
-	/* which hose(s) are agp? */
-	agp1 = (0 != (TITAN_agp & (1 << h1->index)));
-	agp2 = (0 != (TITAN_agp & (1 << h2->index)));
-       
-	hose = h1;			/* default to h1 */
-	if (agp1 ^ agp2) {
-		if (agp2) hose = h2;	/* take agp if only one */
-	} else if (h2->index < h1->index)
-		hose = h2;		/* first hose if 2xpci or 2xagp */
+	u8 intline;
+	int irq;
 
-	return hose;
+ 	/* Get the current intline.  */
+	pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &intline);
+	irq = intline;
+
+ 	/* Is it explicitly routed through ISA?  */
+ 	if ((irq & 0xF0) == 0xE0)
+ 		return irq;
+ 
+ 	/* Offset by 16 to make room for ISA interrupts 0 - 15.  */
+ 	return irq + 16;
 }
-#endif
 
 static void __init
-privateer_init_pci(void)
+titan_init_pci(void)
 {
+ 	/*
+ 	 * This isn't really the right place, but there's some init
+ 	 * that needs to be done after everything is basically up.
+ 	 */
+ 	titan_late_init();
+ 
+	pci_probe_only = 1;
 	common_init_pci();
 	SMC669_Init(0);
 #ifdef CONFIG_VGA_HOSE
-	locate_and_init_vga(privateer_vga_hose_select);
+	locate_and_init_vga(NULL);
 #endif
 }
 
-void
-privateer_machine_check(unsigned long vector, unsigned long la_ptr,
-			struct pt_regs * regs)
+
+/*
+ * Privateer
+ */
+static void __init
+privateer_init_pci(void)
 {
-	/* only handle system events here */
-	if (vector != SCB_Q_SYSEVENT) 
-		return titan_machine_check(vector, la_ptr, regs);
-
-	/* it's a system event, handle it here */
-	printk("PRIVATEER 680 Machine Check on CPU %d\n", smp_processor_id());
+	/*
+	 * Hook a couple of extra err interrupts that the
+	 * common titan code won't.
+	 */
+	request_irq(53+16, titan_intr_nop, SA_INTERRUPT, 
+		    "NMI", NULL);
+	request_irq(50+16, titan_intr_nop, SA_INTERRUPT, 
+		    "Temperature Warning", NULL);
+
+	/*
+	 * Finish with the common version.
+	 */
+	return titan_init_pci();
 }
 
-
+
 /*
- * The System Vectors
+ * The System Vectors.
  */
+struct alpha_machine_vector titan_mv __initmv = {
+	vector_name:		"TITAN",
+	DO_EV6_MMU,
+	DO_DEFAULT_RTC,
+	DO_TITAN_IO,
+	DO_TITAN_BUS,
+	machine_check:		titan_machine_check,
+	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
+	min_io_address:		DEFAULT_IO_BASE,
+	min_mem_address:	DEFAULT_MEM_BASE,
+	pci_dac_offset:		TITAN_DAC_OFFSET,
+
+	nr_irqs:		80,	/* 64 + 16 */
+	/* device_interrupt will be filled in by titan_init_irq */
+
+	agp_info:		titan_agp_info,
+
+	init_arch:		titan_init_arch,
+	init_irq:		titan_legacy_init_irq,
+	init_rtc:		common_init_rtc,
+	init_pci:		titan_init_pci,
+
+	kill_arch:		titan_kill_arch,
+	pci_map_irq:		titan_map_irq,
+	pci_swizzle:		common_swizzle,
+};
+ALIAS_MV(titan)
 
 struct alpha_machine_vector privateer_mv __initmv = {
 	vector_name:		"PRIVATEER",
@@ -381,14 +403,18 @@
 	pci_dac_offset:		TITAN_DAC_OFFSET,
 
 	nr_irqs:		80,	/* 64 + 16 */
-	device_interrupt:	privateer_device_interrupt,
+	/* device_interrupt will be filled in by titan_init_irq */
+
+	agp_info:		titan_agp_info,
 
 	init_arch:		titan_init_arch,
-	init_irq:		privateer_init_irq,
+	init_irq:		titan_legacy_init_irq,
 	init_rtc:		common_init_rtc,
 	init_pci:		privateer_init_pci,
+
 	kill_arch:		titan_kill_arch,
-	pci_map_irq:		privateer_map_irq,
+	pci_map_irq:		titan_map_irq,
 	pci_swizzle:		common_swizzle,
 };
-ALIAS_MV(privateer)
+/* No alpha_mv alias for privateer since we compile it
+   in unconditionally with titan; setup_arch knows how to cope. */
diff -urN linux-2.4.21-pre3/arch/alpha/kernel/sys_wildfire.c linux-2.4.21-pre4/arch/alpha/kernel/sys_wildfire.c
--- linux-2.4.21-pre3/arch/alpha/kernel/sys_wildfire.c	Fri Mar  2 11:12:07 2001
+++ linux-2.4.21-pre4/arch/alpha/kernel/sys_wildfire.c	Tue Jan 28 19:44:28 2003
@@ -352,5 +352,10 @@
 	kill_arch:		wildfire_kill_arch,
 	pci_map_irq:		wildfire_map_irq,
 	pci_swizzle:		common_swizzle,
+
+	pa_to_nid:		wildfire_pa_to_nid,
+	cpuid_to_nid:		wildfire_cpuid_to_nid,
+	node_mem_start:		wildfire_node_mem_start,
+	node_mem_size:		wildfire_node_mem_size,
 };
 ALIAS_MV(wildfire)
diff -urN linux-2.4.21-pre3/arch/alpha/kernel/time.c linux-2.4.21-pre4/arch/alpha/kernel/time.c
--- linux-2.4.21-pre3/arch/alpha/kernel/time.c	Tue Jan 28 19:44:23 2003
+++ linux-2.4.21-pre4/arch/alpha/kernel/time.c	Tue Jan 28 19:44:28 2003
@@ -380,21 +380,6 @@
 
 	/* Startup the timer source. */
 	alpha_mv.init_rtc();
-
-	/*
-	 * If we had wanted SRM console printk echoing early, undo it now.
-	 *
-	 * "srmcons" specified in the boot command arguments allows us to
-	 * see kernel messages during the period of time before the true
-	 * console device is "registered" during console_init(). As of this
-	 * version (2.4.10), time_init() is the last Alpha-specific code
-	 * called before console_init(), so we put this "unregister" code
-	 * here to prevent schizophrenic console behavior later... ;-}
-	 */
-	if (alpha_using_srm && srmcons_output) {
-		unregister_srm_console();
-		srmcons_output = 0;
-	}
 }
 
 /*
diff -urN linux-2.4.21-pre3/arch/alpha/lib/callback_srm.S linux-2.4.21-pre4/arch/alpha/lib/callback_srm.S
--- linux-2.4.21-pre3/arch/alpha/lib/callback_srm.S	Mon Jun 19 17:59:33 2000
+++ linux-2.4.21-pre4/arch/alpha/lib/callback_srm.S	Tue Jan 28 19:44:28 2003
@@ -78,6 +78,8 @@
 CALLBACK(open, CCB_OPEN, 3)
 CALLBACK(close, CCB_CLOSE, 2)
 CALLBACK(read, CCB_READ, 5)
+CALLBACK(open_console, CCB_OPEN_CONSOLE, 1)
+CALLBACK(close_console, CCB_CLOSE_CONSOLE, 1)
 CALLBACK(getenv, CCB_GET_ENV, 4)
 CALLBACK(setenv, CCB_SET_ENV, 4)
 CALLBACK(getc, CCB_GETC, 2)
diff -urN linux-2.4.21-pre3/arch/alpha/mm/Makefile linux-2.4.21-pre4/arch/alpha/mm/Makefile
--- linux-2.4.21-pre3/arch/alpha/mm/Makefile	Thu May 24 15:20:18 2001
+++ linux-2.4.21-pre4/arch/alpha/mm/Makefile	Tue Jan 28 19:44:28 2003
@@ -9,7 +9,7 @@
 
 O_TARGET := mm.o
 
-obj-y	:= init.o fault.o extable.o
+obj-y	:= init.o fault.o extable.o remap.o
 
 obj-$(CONFIG_DISCONTIGMEM) += numa.o
 
diff -urN linux-2.4.21-pre3/arch/alpha/mm/numa.c linux-2.4.21-pre4/arch/alpha/mm/numa.c
--- linux-2.4.21-pre3/arch/alpha/mm/numa.c	Tue Jan 28 19:44:23 2003
+++ linux-2.4.21-pre4/arch/alpha/mm/numa.c	Tue Jan 28 19:44:28 2003
@@ -69,8 +69,8 @@
 	int show_init = 0;
 
 	/* Find the bounds of current node */
-	node_pfn_start = (nid * NODE_MAX_MEM_SIZE) >> PAGE_SHIFT;
-	node_pfn_end = node_pfn_start + (NODE_MAX_MEM_SIZE >> PAGE_SHIFT);
+	node_pfn_start = (NODE_MEM_START(nid)) >> PAGE_SHIFT;
+	node_pfn_end = node_pfn_start + (NODE_MEM_SIZE(nid) >> PAGE_SHIFT);
 	
 	/* Find free clusters, and init and free the bootmem accordingly.  */
 	memdesc = (struct memdesc_struct *)
@@ -110,10 +110,14 @@
 			max_low_pfn = end;
 	}
 
-	if (mem_size_limit && max_low_pfn >= mem_size_limit) {
-		printk("setup: forcing memory size to %ldK (from %ldK).\n",
-		       mem_size_limit << (PAGE_SHIFT - 10),
-		       max_low_pfn    << (PAGE_SHIFT - 10));
+	if (mem_size_limit && max_low_pfn > mem_size_limit) {
+		static int msg_shown = 0;
+		if (!msg_shown) {
+			msg_shown = 1;
+			printk("setup: forcing memory size to %ldK (from %ldK).\n",
+			       mem_size_limit << (PAGE_SHIFT - 10),
+			       max_low_pfn    << (PAGE_SHIFT - 10));
+		}
 		max_low_pfn = mem_size_limit;
 	}
 
diff -urN linux-2.4.21-pre3/arch/alpha/mm/remap.c linux-2.4.21-pre4/arch/alpha/mm/remap.c
--- linux-2.4.21-pre3/arch/alpha/mm/remap.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/arch/alpha/mm/remap.c	Tue Jan 28 19:44:28 2003
@@ -0,0 +1,88 @@
+#include <linux/vmalloc.h>
+#include <asm/pgalloc.h>
+
+/* called with the page_table_lock held */
+static inline void 
+remap_area_pte(pte_t * pte, unsigned long address, unsigned long size, 
+	       unsigned long phys_addr, unsigned long flags)
+{
+	unsigned long end;
+
+	address &= ~PMD_MASK;
+	end = address + size;
+	if (end > PMD_SIZE)
+		end = PMD_SIZE;
+	if (address >= end)
+		BUG();
+	do {
+		if (!pte_none(*pte)) {
+			printk("remap_area_pte: page already exists\n");
+			BUG();
+		}
+		set_pte(pte, 
+			mk_pte_phys(phys_addr, 
+				    __pgprot(_PAGE_VALID | _PAGE_ASM | 
+					     _PAGE_KRE | _PAGE_KWE | flags)));
+		address += PAGE_SIZE;
+		phys_addr += PAGE_SIZE;
+		pte++;
+	} while (address && (address < end));
+}
+
+/* called with the page_table_lock held */
+static inline int 
+remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size, 
+	       unsigned long phys_addr, unsigned long flags)
+{
+	unsigned long end;
+
+	address &= ~PGDIR_MASK;
+	end = address + size;
+	if (end > PGDIR_SIZE)
+		end = PGDIR_SIZE;
+	phys_addr -= address;
+	if (address >= end)
+		BUG();
+	do {
+		pte_t * pte = pte_alloc(&init_mm, pmd, address);
+		if (!pte)
+			return -ENOMEM;
+		remap_area_pte(pte, address, end - address, 
+				     address + phys_addr, flags);
+		address = (address + PMD_SIZE) & PMD_MASK;
+		pmd++;
+	} while (address && (address < end));
+	return 0;
+}
+
+int
+__alpha_remap_area_pages(unsigned long address, unsigned long phys_addr,
+			 unsigned long size, unsigned long flags)
+{
+	pgd_t * dir;
+	int error = 0;
+	unsigned long end = address + size;
+
+	phys_addr -= address;
+	dir = pgd_offset(&init_mm, address);
+	flush_cache_all();
+	if (address >= end)
+		BUG();
+	spin_lock(&init_mm.page_table_lock);
+	do {
+		pmd_t *pmd;
+		pmd = pmd_alloc(&init_mm, dir, address);
+		error = -ENOMEM;
+		if (!pmd)
+			break;
+		if (remap_area_pmd(pmd, address, end - address,
+			           phys_addr + address, flags))
+			break;
+		error = 0;
+		address = (address + PGDIR_SIZE) & PGDIR_MASK;
+		dir++;
+	} while (address && (address < end));
+	spin_unlock(&init_mm.page_table_lock);
+	return error;
+}
+
diff -urN linux-2.4.21-pre3/arch/alpha/vmlinux.lds.in linux-2.4.21-pre4/arch/alpha/vmlinux.lds.in
--- linux-2.4.21-pre3/arch/alpha/vmlinux.lds.in	Thu Nov 22 10:54:10 2001
+++ linux-2.4.21-pre4/arch/alpha/vmlinux.lds.in	Tue Jan 28 19:44:28 2003
@@ -8,7 +8,7 @@
 #ifdef CONFIG_ALPHA_LEGACY_START_ADDRESS
   . = 0xfffffc0000310000;
 #else
-  . = 0xfffffc0000810000;
+  . = 0xfffffc0001010000;
 #endif
 
   _text = .;
diff -urN linux-2.4.21-pre3/arch/i386/config.in linux-2.4.21-pre4/arch/i386/config.in
--- linux-2.4.21-pre3/arch/i386/config.in	Tue Jan 28 19:44:23 2003
+++ linux-2.4.21-pre4/arch/i386/config.in	Tue Jan 28 19:44:28 2003
@@ -36,6 +36,7 @@
 	 Pentium-4				CONFIG_MPENTIUM4 \
 	 K6/K6-II/K6-III			CONFIG_MK6 \
 	 Athlon/Duron/K7			CONFIG_MK7 \
+	 Opteron/Athlon64/Hammer/K8		CONFIG_MK8 \
 	 Elan					CONFIG_MELAN \
 	 Crusoe					CONFIG_MCRUSOE \
 	 Winchip-C6				CONFIG_MWINCHIPC6 \
@@ -99,7 +100,7 @@
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
    define_bool CONFIG_X86_HAS_TSC y
    define_bool CONFIG_X86_GOOD_APIC y
-   define_bool CONFIG_X86_PGE y
+   bool 'PGE extensions (not for Cyrix/Transmeta)' CONFIG_X86_PGE
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
    define_bool CONFIG_X86_PPRO_FENCE y
    define_bool CONFIG_X86_F00F_WORKS_OK y
@@ -126,6 +127,11 @@
    define_bool CONFIG_X86_HAS_TSC y
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
 fi
+if [ "$CONFIG_MK8" = "y" ]; then
+   # for now. may later want to add SSE support and optimized
+   # functions
+   define_bool CONFIG_MK7 y
+fi
 if [ "$CONFIG_MK7" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 6
    define_bool CONFIG_X86_HAS_TSC y
diff -urN linux-2.4.21-pre3/arch/i386/kernel/apic.c linux-2.4.21-pre4/arch/i386/kernel/apic.c
--- linux-2.4.21-pre3/arch/i386/kernel/apic.c	Tue Jan 28 19:44:23 2003
+++ linux-2.4.21-pre4/arch/i386/kernel/apic.c	Tue Jan 28 19:44:28 2003
@@ -611,6 +611,8 @@
 	case X86_VENDOR_AMD:
 		if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model > 1)
 			break;
+		if (boot_cpu_data.x86 == 15 && cpu_has_apic)
+			break;
 		goto no_apic;
 	case X86_VENDOR_INTEL:
 		if (boot_cpu_data.x86 == 6 ||
diff -urN linux-2.4.21-pre3/arch/i386/kernel/bluesmoke.c linux-2.4.21-pre4/arch/i386/kernel/bluesmoke.c
--- linux-2.4.21-pre3/arch/i386/kernel/bluesmoke.c	Fri Aug  2 17:39:42 2002
+++ linux-2.4.21-pre4/arch/i386/kernel/bluesmoke.c	Tue Jan 28 19:44:28 2003
@@ -221,7 +221,7 @@
 			/*
 			 *	AMD K7 machine check is Intel like
 			 */
-			if(c->x86 == 6)
+			if(c->x86 == 6 || c->x86 == 15)
 				intel_mcheck_init(c);
 			break;
 		case X86_VENDOR_INTEL:
diff -urN linux-2.4.21-pre3/arch/i386/kernel/dmi_scan.c linux-2.4.21-pre4/arch/i386/kernel/dmi_scan.c
--- linux-2.4.21-pre3/arch/i386/kernel/dmi_scan.c	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre4/arch/i386/kernel/dmi_scan.c	Tue Jan 28 19:44:28 2003
@@ -99,14 +99,6 @@
 	u8 buf[15];
 	u32 fp=0xF0000;
 
-#ifdef CONFIG_SIMNOW
-	/*
- 	 *	Skip on x86/64 with simnow. Will eventually go away
- 	 *	If you see this ifdef in 2.6pre mail me !
- 	 */
-	return -1;
-#endif
- 	
 	while( fp < 0xFFFFF)
 	{
 		isa_memcpy_fromio(buf, fp, 15);
@@ -694,6 +686,18 @@
 			MATCH(DMI_BIOS_VERSION, "R0204P1"),
 			MATCH(DMI_BIOS_DATE, "09/12/00"), NO_MATCH
 			} },
+			
+	{ swab_apm_power_in_minutes, "Sony VAIO", {	/* Handle problems with APM on Sony Vaio PCG-Z600RE */
+			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
+			MATCH(DMI_BIOS_VERSION, "R0116Z1"),
+			NO_MATCH, NO_MATCH
+			} },
+	
+	{ swab_apm_power_in_minutes, "Sony VAIO", {	/* Handle problems with APM on Sony Vaio PCG-Z600RE */
+			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
+			MATCH(DMI_BIOS_VERSION, "RK116Z1"),
+			NO_MATCH, NO_MATCH
+			} },
 
 	/* Machines which have problems handling enabled local APICs */
 
diff -urN linux-2.4.21-pre3/arch/i386/kernel/io_apic.c linux-2.4.21-pre4/arch/i386/kernel/io_apic.c
--- linux-2.4.21-pre3/arch/i386/kernel/io_apic.c	Tue Jan 28 19:44:23 2003
+++ linux-2.4.21-pre4/arch/i386/kernel/io_apic.c	Tue Jan 28 19:44:28 2003
@@ -292,7 +292,7 @@
 
 	Dprintk("querying PCI -> IRQ mapping bus:%d, slot:%d, pin:%d.\n",
 		bus, slot, pin);
-	if (mp_bus_id_to_pci_bus[bus] == -1) {
+	if ((mp_bus_id_to_pci_bus==NULL) || (mp_bus_id_to_pci_bus[bus] == -1)) {
 		printk(KERN_WARNING "PCI BIOS passed nonexistent PCI bus %d!\n", bus);
 		return -1;
 	}
@@ -739,8 +739,9 @@
 
 void __init UNEXPECTED_IO_APIC(void)
 {
-	printk(KERN_WARNING " WARNING: unexpected IO-APIC, please mail\n");
-	printk(KERN_WARNING "          to linux-smp@vger.kernel.org\n");
+	printk(KERN_WARNING 
+		"An unexpected IO-APIC was found. If this kernel release is less than\n"
+		"three months old please report this to linux-smp@vger.kernel.org\n");
 }
 
 void __init print_IO_APIC(void)
@@ -793,6 +794,7 @@
 	printk(KERN_DEBUG ".......     : PRQ implemented: %X\n", reg_01.PRQ);
 	printk(KERN_DEBUG ".......     : IO APIC version: %04X\n", reg_01.version);
 	if (	(reg_01.version != 0x01) && /* 82489DX IO-APICs */
+		(reg_01.version != 0x02) && /* VIA */
 		(reg_01.version != 0x10) && /* oldest IO-APICs */
 		(reg_01.version != 0x11) && /* Pentium/Pro IO-APICs */
 		(reg_01.version != 0x13) && /* Xeon IO-APICs */
diff -urN linux-2.4.21-pre3/arch/i386/kernel/mpparse.c linux-2.4.21-pre4/arch/i386/kernel/mpparse.c
--- linux-2.4.21-pre3/arch/i386/kernel/mpparse.c	Tue Jan 28 19:44:23 2003
+++ linux-2.4.21-pre4/arch/i386/kernel/mpparse.c	Tue Jan 28 19:44:28 2003
@@ -891,18 +891,16 @@
 	 * there is a real-mode segmented pointer pointing to the
 	 * 4K EBDA area at 0x40E, calculate and scan it here.
 	 *
-	 * NOTE! There are Linux loaders that will corrupt the EBDA
+	 * NOTE! There were Linux loaders that will corrupt the EBDA
 	 * area, and as such this kind of SMP config may be less
 	 * trustworthy, simply because the SMP table may have been
-	 * stomped on during early boot. These loaders are buggy and
-	 * should be fixed.
+	 * stomped on during early boot.  Thankfully the bootloaders
+	 * now honour the EBDA.
 	 */
 
 	address = *(unsigned short *)phys_to_virt(0x40E);
 	address <<= 4;
 	smp_scan_config(address, 0x1000);
-	if (smp_found_config)
-		printk(KERN_WARNING "WARNING: MP table in the EBDA can be UNSAFE, contact linux-smp@vger.kernel.org if you experience SMP problems!\n");
 }
 
 #else
diff -urN linux-2.4.21-pre3/arch/i386/kernel/mtrr.c linux-2.4.21-pre4/arch/i386/kernel/mtrr.c
--- linux-2.4.21-pre3/arch/i386/kernel/mtrr.c	Fri Aug  2 17:39:42 2002
+++ linux-2.4.21-pre4/arch/i386/kernel/mtrr.c	Tue Jan 28 19:44:28 2003
@@ -2143,7 +2143,7 @@
 		   query the width (in bits) of the physical
 		   addressable memory on the Hammer family.
 		 */
-		if (boot_cpu_data.x86 == 7 && (cpuid_eax(0x80000000) >= 0x80000008)) {
+		if (boot_cpu_data.x86 == 15 && (cpuid_eax(0x80000000) >= 0x80000008)) {
 			u32	phys_addr;
 			phys_addr = cpuid_eax(0x80000008) & 0xff ;
 			size_or_mask = ~((1 << (phys_addr - PAGE_SHIFT)) - 1);
diff -urN linux-2.4.21-pre3/arch/i386/kernel/nmi.c linux-2.4.21-pre4/arch/i386/kernel/nmi.c
--- linux-2.4.21-pre3/arch/i386/kernel/nmi.c	Fri Aug  2 17:39:42 2002
+++ linux-2.4.21-pre4/arch/i386/kernel/nmi.c	Tue Jan 28 19:44:28 2003
@@ -72,18 +72,21 @@
 
 int __init check_nmi_watchdog (void)
 {
-	irq_cpustat_t tmp[NR_CPUS];
+	unsigned int prev_nmi_count[NR_CPUS];
 	int j, cpu;
 
 	printk(KERN_INFO "testing NMI watchdog ... ");
 
-	memcpy(tmp, irq_stat, sizeof(tmp));
+	for (j = 0; j < smp_num_cpus; j++) {
+		cpu = cpu_logical_map(j);
+		prev_nmi_count[cpu] = irq_stat[cpu].__nmi_count;
+	}
 	sti();
 	mdelay((10*1000)/nmi_hz); // wait 10 ticks
 
 	for (j = 0; j < smp_num_cpus; j++) {
 		cpu = cpu_logical_map(j);
-		if (nmi_count(cpu) - tmp[cpu].__nmi_count <= 5) {
+		if (nmi_count(cpu) - prev_nmi_count[cpu] <= 5) {
 			printk("CPU#%d: NMI appears to be stuck!\n", cpu);
 			return -1;
 		}
@@ -119,7 +122,7 @@
 		nmi_watchdog = nmi;
 	if ((nmi == NMI_LOCAL_APIC) &&
 			(boot_cpu_data.x86_vendor == X86_VENDOR_AMD) &&
-			(boot_cpu_data.x86 == 6))
+	       	    ((boot_cpu_data.x86 == 6) || (boot_cpu_data.x86 == 15)))
 		nmi_watchdog = nmi;
 	/*
 	 * We can enable the IO-APIC watchdog
@@ -278,7 +281,7 @@
 {
 	switch (boot_cpu_data.x86_vendor) {
 	case X86_VENDOR_AMD:
-		if (boot_cpu_data.x86 != 6)
+		if (boot_cpu_data.x86 != 6 && boot_cpu_data.x86 != 15)
 			return;
 		setup_k7_watchdog();
 		break;
diff -urN linux-2.4.21-pre3/arch/i386/kernel/setup.c linux-2.4.21-pre4/arch/i386/kernel/setup.c
--- linux-2.4.21-pre3/arch/i386/kernel/setup.c	Tue Jan 28 19:44:23 2003
+++ linux-2.4.21-pre4/arch/i386/kernel/setup.c	Tue Jan 28 19:44:28 2003
@@ -71,6 +71,9 @@
  *  CacheSize bug workaround updates for AMD, Intel & VIA Cyrix.
  *  Dave Jones <davej@suse.de>, September, October 2001.
  *
+ *  Provisions for empty E820 memory regions (reported by certain BIOSes).
+ *  Alex Achenbach <xela@slit.de>, December 2002.
+ *
  */
 
 /*
@@ -501,7 +504,7 @@
 	int chgidx, still_changing;
 	int overlap_entries;
 	int new_bios_entry;
-	int old_nr, new_nr;
+	int old_nr, new_nr, chg_nr;
 	int i;
 
 	/*
@@ -555,20 +558,24 @@
 	for (i=0; i < 2*old_nr; i++)
 		change_point[i] = &change_point_list[i];
 
-	/* record all known change-points (starting and ending addresses) */
+	/* record all known change-points (starting and ending addresses),
+	   omitting those that are for empty memory regions */
 	chgidx = 0;
 	for (i=0; i < old_nr; i++)	{
-		change_point[chgidx]->addr = biosmap[i].addr;
-		change_point[chgidx++]->pbios = &biosmap[i];
-		change_point[chgidx]->addr = biosmap[i].addr + biosmap[i].size;
-		change_point[chgidx++]->pbios = &biosmap[i];
+		if (biosmap[i].size != 0) {
+			change_point[chgidx]->addr = biosmap[i].addr;
+			change_point[chgidx++]->pbios = &biosmap[i];
+			change_point[chgidx]->addr = biosmap[i].addr + biosmap[i].size;
+			change_point[chgidx++]->pbios = &biosmap[i];
+		}
 	}
+	chg_nr = chgidx;    	/* true number of change-points */
 
 	/* sort change-point list by memory addresses (low -> high) */
 	still_changing = 1;
 	while (still_changing)	{
 		still_changing = 0;
-		for (i=1; i < 2*old_nr; i++)  {
+		for (i=1; i < chg_nr; i++)  {
 			/* if <current_addr> > <last_addr>, swap */
 			/* or, if current=<start_addr> & last=<end_addr>, swap */
 			if ((change_point[i]->addr < change_point[i-1]->addr) ||
@@ -591,7 +598,7 @@
 	last_type = 0;		 /* start with undefined memory type */
 	last_addr = 0;		 /* start with 0 as last starting address */
 	/* loop through change-points, determining affect on the new bios map */
-	for (chgidx=0; chgidx < 2*old_nr; chgidx++)
+	for (chgidx=0; chgidx < chg_nr; chgidx++)
 	{
 		/* keep track of all overlapping bios entries */
 		if (change_point[chgidx]->addr == change_point[chgidx]->pbios->addr)
@@ -1481,11 +1488,9 @@
 }
 
 /*
- * Cx86_dir0_msb is a HACK needed by check_cx686_cpuid/slop in bugs.h in
- * order to identify the Cyrix CPU model after we're out of setup.c
- *
- * Actually since bugs.h doesn't even reference this perhaps someone should
- * fix the documentation ???
+ * Cx86_dir0_msb is a HACK needed by check_cx686_cpuid/slop in
+ * order to identify the Cyrix CPU model after we're out of the
+ * initial setup.
  */
 static unsigned char Cx86_dir0_msb __initdata = 0;
 
diff -urN linux-2.4.21-pre3/arch/i386/kernel/time.c linux-2.4.21-pre4/arch/i386/kernel/time.c
--- linux-2.4.21-pre3/arch/i386/kernel/time.c	Tue Jan 28 19:44:23 2003
+++ linux-2.4.21-pre4/arch/i386/kernel/time.c	Tue Jan 28 19:44:28 2003
@@ -279,6 +279,7 @@
 static inline void mark_timeoffset_cyclone(void)
 {
 	int count;
+	unsigned long delta = last_cyclone_timer;
 	spin_lock(&i8253_lock);
 	/* quickly read the cyclone timer */
 	if(cyclone_timer)
@@ -291,6 +292,13 @@
 	count |= inb(0x40) << 8;
 	spin_unlock(&i8253_lock);
 
+	/*lost tick compensation*/
+	delta = last_cyclone_timer - delta;
+	if(delta > loops_per_jiffy+2000){
+		delta = (delta/loops_per_jiffy)-1;
+		jiffies += delta;
+	}
+               
 	count = ((LATCH-1) - count) * TICK_SIZE;
 	delay_at_last_interrupt = (count + LATCH/2) / LATCH;
 }
diff -urN linux-2.4.21-pre3/arch/m68k/bvme6000/rtc.c linux-2.4.21-pre4/arch/m68k/bvme6000/rtc.c
--- linux-2.4.21-pre3/arch/m68k/bvme6000/rtc.c	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre4/arch/m68k/bvme6000/rtc.c	Tue Jan 28 19:44:28 2003
@@ -179,7 +179,6 @@
 		return -ENODEV;
 
 	printk(KERN_INFO "DP8570A Real Time Clock Driver v%s\n", RTC_VERSION);
-	misc_register(&rtc_dev);
-	return 0;
+	return misc_register(&rtc_dev);
 }
 
diff -urN linux-2.4.21-pre3/arch/m68k/kernel/head.S linux-2.4.21-pre4/arch/m68k/kernel/head.S
--- linux-2.4.21-pre3/arch/m68k/kernel/head.S	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre4/arch/m68k/kernel/head.S	Tue Jan 28 19:44:28 2003
@@ -130,7 +130,7 @@
  *
  * mmu_engage
  * ----------
- *	Thanks to a small helping routine enabling the mmu got quiet simple
+ *	Thanks to a small helping routine enabling the mmu got quite simple
  * and there is only one way left. mmu_engage makes a complete a new mapping
  * that only includes the absolute necessary to be able to jump to the final
  * postion and to restore the original mapping.
@@ -1202,7 +1202,7 @@
  *
  * Map the kernel (that's already done),
  * Map the I/O (on most machines that's the
- * 0x5000.0000 ... 0x5200.0000 range,
+ * 0x5000.0000 ... 0x5300.0000 range,
  * Map the video frame buffer using as few pages
  * as absolutely (this requirement mostly stems from
  * the fact that when the frame buffer is at
@@ -1246,10 +1246,11 @@
 	andl	L(mac_videobase),%d0
 
 	mmu_map		#VIDEOMEMBASE,%d0,#VIDEOMEMSIZE,%d3
-	mmu_map_eq	#0x40800000,#0x02000000,%d3	/* rom ? */
-	mmu_map_eq	#0x50000000,#0x02000000,%d3
-	mmu_map_eq	#0x60000000,#0x00400000,%d3
-	mmu_map_eq	#0x9c000000,#0x00400000,%d3
+	/* The ROM starts at 4000 0000		    	*/
+	mmu_map_eq	#0x40000000,#0x02000000,%d3
+	/* IO devices                               	*/
+	mmu_map_eq	#0x50000000,#0x03000000,%d3
+	/* NuBus slot space				*/
 	mmu_map_tt	#1,#0xf8000000,#0x08000000,%d3
 
 	jbra	L(mmu_init_done)
@@ -1461,6 +1462,9 @@
 	andl	L(mac_videobase),%d0
 	addl	#VIDEOMEMBASE,%d0
 	movel	%d0,L(mac_videobase)
+#ifdef MAC_SERIAL_DEBUG
+	orl	#0x50000000,L(mac_sccbase)
+#endif		
 1:
 #endif
 
@@ -3048,10 +3052,6 @@
 #ifdef CONFIG_MAC
 	is_not_mac(5f)
 
-#ifdef CONSOLE
-	console_putc	%d0
-#endif /* CONSOLE */
-
 #ifdef MAC_SERIAL_DEBUG
 
 #ifdef MAC_USE_SCC_A
@@ -3446,6 +3446,10 @@
 	putn	%pc@(L(cputype))
 	putc	'\n'
 
+#ifdef MAC_SERIAL_DEBUG
+	putn	%pc@(L(mac_sccbase))
+	putc	'\n'
+#endif	
 #  if defined(MMU_PRINT)
 	jbsr	mmu_print_machine_cpu_types
 #  endif /* MMU_PRINT */
@@ -3622,7 +3626,7 @@
 	movel	%a0@(Lconsole_struct_num_columns),%d1
 	cmpl	%d1,%d0
 	jcs	1f
-	putc	'\n'	/* recursion is OK! */
+	console_putc	#'\n'	/* recursion is OK! */
 1:
 	movel	%a0@(Lconsole_struct_cur_row),%d1
 
diff -urN linux-2.4.21-pre3/arch/m68k/mac/config.c linux-2.4.21-pre4/arch/m68k/mac/config.c
--- linux-2.4.21-pre3/arch/m68k/mac/config.c	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre4/arch/m68k/mac/config.c	Tue Jan 28 19:44:28 2003
@@ -104,7 +104,7 @@
 
 void mac_bang(int irq, void *vector, struct pt_regs *p)
 {
-	printk("Resetting ...\n");
+	printk(KERN_INFO "Resetting ...\n");
 	mac_reset();
 }
 
@@ -205,7 +205,7 @@
 void __init config_mac(void)
 {
 	if (!MACH_IS_MAC) {
-	  printk("ERROR: no Mac, but config_mac() called!! \n");
+	  printk(KERN_ERR "ERROR: no Mac, but config_mac() called!! \n");
 	}
 
 #ifdef CONFIG_VT
@@ -370,13 +370,14 @@
 	 */	 
 	 
 	{	MAC_MODEL_Q605, "Quadra 605", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE,   MAC_SCC_QUADRA,	MAC_ETHER_NONE,		MAC_NUBUS},
+	{	MAC_MODEL_Q605_ACC, "Quadra 605", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE,   MAC_SCC_QUADRA,	MAC_ETHER_NONE,		MAC_NUBUS},
 	{	MAC_MODEL_Q610, "Quadra 610", MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE,   MAC_SCC_QUADRA,	MAC_ETHER_SONIC,	MAC_NUBUS},
 	{	MAC_MODEL_Q630, "Quadra 630", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_QUADRA, MAC_SCC_QUADRA,	MAC_ETHER_SONIC,	MAC_NUBUS},
  	{	MAC_MODEL_Q650, "Quadra 650", MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE,   MAC_SCC_QUADRA,	MAC_ETHER_SONIC,	MAC_NUBUS},
 	/*	The Q700 does have a NS Sonic */
-	{	MAC_MODEL_Q700, "Quadra 700", MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE,   MAC_SCC_QUADRA2,	MAC_ETHER_SONIC,	MAC_NUBUS},
+	{	MAC_MODEL_Q700, "Quadra 700", MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE,   MAC_SCC_QUADRA,	MAC_ETHER_SONIC,	MAC_NUBUS},
 	{	MAC_MODEL_Q800, "Quadra 800", MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE,   MAC_SCC_QUADRA,	MAC_ETHER_SONIC,	MAC_NUBUS},
-	{	MAC_MODEL_Q840, "Quadra 840AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_II,	MAC_ETHER_MACE,		MAC_NUBUS},
+	{	MAC_MODEL_Q840, "Quadra 840AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_PSC,	MAC_ETHER_MACE,		MAC_NUBUS},
 	{	MAC_MODEL_Q900, "Quadra 900", MAC_ADB_IOP, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE,   MAC_SCC_IOP,	MAC_ETHER_SONIC,	MAC_NUBUS},
 	{	MAC_MODEL_Q950, "Quadra 950", MAC_ADB_IOP, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE,   MAC_SCC_IOP,	MAC_ETHER_SONIC,	MAC_NUBUS},
 
@@ -389,8 +390,8 @@
 	{	MAC_MODEL_P475F, "Performa 475", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE,   MAC_SCC_II,	MAC_ETHER_NONE, MAC_NUBUS},
 	{	MAC_MODEL_P520,  "Performa 520", MAC_ADB_CUDA, MAC_VIA_IIci,   MAC_SCSI_OLD,    MAC_IDE_NONE,   MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
 	{	MAC_MODEL_P550,  "Performa 550", MAC_ADB_CUDA, MAC_VIA_IIci,   MAC_SCSI_OLD,    MAC_IDE_NONE,   MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
-	{	MAC_MODEL_P575,  "Performa 575", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE,   MAC_SCC_II,	MAC_ETHER_NONE, MAC_NUBUS},
 	/* These have the comm slot, and therefore the possibility of SONIC ethernet */
+	{	MAC_MODEL_P575,  "Performa 575", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE,   MAC_SCC_II,	MAC_ETHER_SONIC, MAC_NUBUS},
 	{	MAC_MODEL_P588,  "Performa 588", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_QUADRA, MAC_SCC_II,	MAC_ETHER_SONIC, MAC_NUBUS},
 	{	MAC_MODEL_TV,    "TV",           MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_OLD,	MAC_IDE_NONE,   MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
 	{	MAC_MODEL_P600,  "Performa 600", MAC_ADB_IISI, MAC_VIA_IIci,   MAC_SCSI_OLD,	MAC_IDE_NONE,   MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
@@ -402,7 +403,7 @@
 	/* The C610 may or may not have SONIC.  We probe to make sure */
 	{	MAC_MODEL_C610, "Centris 610",   MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_SONIC,	MAC_NUBUS},
 	{	MAC_MODEL_C650, "Centris 650",   MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_SONIC,	MAC_NUBUS},
-	{	MAC_MODEL_C660, "Centris 660AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_MACE,		MAC_NUBUS},
+	{	MAC_MODEL_C660, "Centris 660AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_PSC,	MAC_ETHER_MACE,		MAC_NUBUS},
 
 	/*
 	 * The PowerBooks all the same "Combo" custom IC for SCSI and SCC
@@ -455,7 +456,7 @@
 		/* no bootinfo model id -> NetBSD booter was used! */
 		/* XXX FIXME: breaks for model > 31 */
 		model=(mac_bi_data.cpuid>>2)&63;
-		printk ("No bootinfo model ID, using cpuid instead (hey, use Penguin!)\n");
+		printk (KERN_WARNING "No bootinfo model ID, using cpuid instead (hey, use Penguin!)\n");
 	}
 
 	macintosh_config = mac_data_table; 
@@ -473,22 +474,22 @@
 	iop_preinit();
 	mac_debug_init();
 
-	printk ("Detected Macintosh model: %d \n", model);
+	printk (KERN_INFO "Detected Macintosh model: %d \n", model);
 
 	/*
 	 * Report booter data:
 	 */
-	printk (" Penguin bootinfo data:\n");
-	printk (" Video: addr 0x%lx row 0x%lx depth %lx dimensions %ld x %ld\n", 
+	printk (KERN_DEBUG " Penguin bootinfo data:\n");
+	printk (KERN_DEBUG " Video: addr 0x%lx row 0x%lx depth %lx dimensions %ld x %ld\n", 
 		mac_bi_data.videoaddr, mac_bi_data.videorow, 
 		mac_bi_data.videodepth, mac_bi_data.dimensions & 0xFFFF, 
 		mac_bi_data.dimensions >> 16); 
-	printk (" Videological 0x%lx phys. 0x%lx, SCC at 0x%lx \n",
+	printk (KERN_DEBUG " Videological 0x%lx phys. 0x%lx, SCC at 0x%lx \n",
 		mac_bi_data.videological, mac_orig_videoaddr, 
 		mac_bi_data.sccbase); 
-	printk (" Boottime: 0x%lx GMTBias: 0x%lx \n",
+	printk (KERN_DEBUG " Boottime: 0x%lx GMTBias: 0x%lx \n",
 		mac_bi_data.boottime, mac_bi_data.gmtbias); 
-	printk (" Machine ID: %ld CPUid: 0x%lx memory size: 0x%lx \n",
+	printk (KERN_DEBUG " Machine ID: %ld CPUid: 0x%lx memory size: 0x%lx \n",
 		mac_bi_data.id, mac_bi_data.cpuid, mac_bi_data.memsize); 
 #if 0
 	printk ("Ramdisk: addr 0x%lx size 0x%lx\n", 
@@ -511,7 +512,7 @@
 	    MACHW_SET(MAC_SCSI_96_2);
 	  break;
 	default:
-	  printk("config.c: wtf: unknown scsi, using 53c80\n");
+	  printk(KERN_WARNING "config.c: wtf: unknown scsi, using 53c80\n");
 	  MACHW_SET(MAC_SCSI_80);
 	  break;
 
@@ -525,7 +526,7 @@
 
 void mac_report_hardware(void)
 {
-	printk("Apple Macintosh %s\n", macintosh_config->name);
+	printk(KERN_INFO "Apple Macintosh %s\n", macintosh_config->name);
 }
 
 static void mac_get_model(char *str)
diff -urN linux-2.4.21-pre3/arch/m68k/mac/iop.c linux-2.4.21-pre4/arch/m68k/mac/iop.c
--- linux-2.4.21-pre3/arch/m68k/mac/iop.c	Mon Jun 11 19:15:27 2001
+++ linux-2.4.21-pre4/arch/m68k/mac/iop.c	Tue Jan 28 19:44:28 2003
@@ -28,7 +28,7 @@
  *		  globally-visible functions take an IOP number instead of an
  *		  an actual base address.
  * 990610 (jmt) - Finished the message passing framework and it seems to work.
- *		  Sending _definately_ works; my adb-bus.c mods can send
+ *		  Sending _definitely_ works; my adb-bus.c mods can send
  *		  messages and receive the MSG_COMPLETED status back from the
  *		  IOP. The trick now is figuring out the message formats.
  * 990611 (jmt) - More cleanups. Fixed problem where unclaimed messages on a
diff -urN linux-2.4.21-pre3/arch/m68k/mvme16x/rtc.c linux-2.4.21-pre4/arch/m68k/mvme16x/rtc.c
--- linux-2.4.21-pre3/arch/m68k/mvme16x/rtc.c	Mon Jun 11 19:15:27 2001
+++ linux-2.4.21-pre4/arch/m68k/mvme16x/rtc.c	Tue Jan 28 19:44:28 2003
@@ -168,7 +168,6 @@
 		return -ENODEV;
 
 	printk(KERN_INFO "MK48T08 Real Time Clock Driver v%s\n", RTC_VERSION);
-	misc_register(&rtc_dev);
-	return 0;
+	return misc_register(&rtc_dev);
 }
 
diff -urN linux-2.4.21-pre3/arch/m68k/q40/q40ints.c linux-2.4.21-pre4/arch/m68k/q40/q40ints.c
--- linux-2.4.21-pre3/arch/m68k/q40/q40ints.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.21-pre4/arch/m68k/q40/q40ints.c	Tue Jan 28 19:44:28 2003
@@ -271,7 +271,7 @@
 #if 0
 static struct IRQ_TABLE iirqs[]={
   {Q40_IRQ_FRAME_MASK,Q40_IRQ_FRAME},
-  Q40_{IRQ_KEYB_MASK,Q40_IRQ_KEYBOARD},
+  {Q40_IRQ_KEYB_MASK,Q40_IRQ_KEYBOARD},
   {0,0}};
 #endif
 static struct IRQ_TABLE eirqs[]={
diff -urN linux-2.4.21-pre3/arch/ppc/kernel/process.c linux-2.4.21-pre4/arch/ppc/kernel/process.c
--- linux-2.4.21-pre3/arch/ppc/kernel/process.c	Mon Nov 26 05:29:17 2001
+++ linux-2.4.21-pre4/arch/ppc/kernel/process.c	Tue Jan 28 19:44:28 2003
@@ -34,6 +34,7 @@
 #include <linux/user.h>
 #include <linux/elf.h>
 #include <linux/init.h>
+#include <linux/prctl.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
@@ -403,6 +404,40 @@
 	current->thread.fpscr = 0;
 }
 
+/*
+ * Support for the PR_GET/SET_FPEXC prctl() calls.
+ */
+static inline unsigned int __unpack_fe01(unsigned int msr_bits)
+{
+	return ((msr_bits & MSR_FE0) >> 10) | ((msr_bits & MSR_FE1) >> 8);
+}
+
+static inline unsigned int __pack_fe01(unsigned int fpmode)
+{
+	return ((fpmode << 10) & MSR_FE0) | ((fpmode << 8) & MSR_FE1);
+}
+
+int set_fpexc_mode(struct task_struct *tsk, unsigned int val)
+{
+	struct pt_regs *regs = tsk->thread.regs;
+
+	if (val > PR_FP_EXC_PRECISE)
+		return -EINVAL;
+	tsk->thread.fpexc_mode = __pack_fe01(val);
+	if (regs != NULL && (regs->msr & MSR_FP) != 0)
+		regs->msr = (regs->msr & ~(MSR_FE0|MSR_FE1))
+			| tsk->thread.fpexc_mode;
+	return 0;
+}
+
+int get_fpexc_mode(struct task_struct *tsk, unsigned long adr)
+{
+	unsigned int val;
+
+	val = __unpack_fe01(tsk->thread.fpexc_mode);
+	return put_user(val, (unsigned int *) adr);
+}
+
 int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6,
 	      struct pt_regs *regs)
 {
diff -urN linux-2.4.21-pre3/arch/ppc64/boot/Makefile linux-2.4.21-pre4/arch/ppc64/boot/Makefile
--- linux-2.4.21-pre3/arch/ppc64/boot/Makefile	Fri Aug  2 17:39:43 2002
+++ linux-2.4.21-pre4/arch/ppc64/boot/Makefile	Tue Jan 28 19:44:28 2003
@@ -93,6 +93,8 @@
 	ls -l $(TOPDIR)/vmlinux | awk '{printf "/* generated -- do not edit! */\nunsigned long vmlinux_filesize = %d;\n", $$5}' > imagesize.c
 	$(CROSS_COMPILE)nm -n $(TOPDIR)/vmlinux | tail -1 | awk '{printf "unsigned long vmlinux_memsize = 0x%s;\n", substr($$1,8)}' >> imagesize.c
 
+zImage.o: $(TOPDIR)/vmlinux
+
 vmlinux .config System.map: % : $(TOPDIR)/%
 	gzip -cvf9 $(TOPDIR)/$@ > kernel-$@.gz
 	$(OBJCOPY) zImage.o \
diff -urN linux-2.4.21-pre3/arch/ppc64/boot/README linux-2.4.21-pre4/arch/ppc64/boot/README
--- linux-2.4.21-pre3/arch/ppc64/boot/README	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/arch/ppc64/boot/README	Tue Jan 28 19:44:28 2003
@@ -0,0 +1,10 @@
+
+To extract the kernel vmlinux, System.map or .config from the zImage binary:
+
+objcopy -j .kernel:vmlinux -O binary zImage vmlinux.gz
+objcopy -j .kernel:System.map -O binary zImage System.map.gz
+objcopy -j .kernel:.config -O binary zImage config.gz
+
+
+	Peter
+
diff -urN linux-2.4.21-pre3/arch/ppc64/boot/addRamDisk.c linux-2.4.21-pre4/arch/ppc64/boot/addRamDisk.c
--- linux-2.4.21-pre3/arch/ppc64/boot/addRamDisk.c	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/boot/addRamDisk.c	Tue Jan 28 19:44:28 2003
@@ -154,9 +154,8 @@
   
 	/* Process the Sysmap file to determine where _end is */
 	sysmapPages = sysmapLen / 4096;
-	for (i=0; i<sysmapPages; ++i) {
-		get4k(sysmap, inbuf);
-	}
+	/* read the whole file line by line, expect that it doesnt fail */
+	while ( fgets(inbuf, 4096, sysmap) )  ;
 	/* search for _end in the last page of the system map */
 	ptr_end = strstr(inbuf, " _end");
 	if (!ptr_end) {
diff -urN linux-2.4.21-pre3/arch/ppc64/boot/addSystemMap.c linux-2.4.21-pre4/arch/ppc64/boot/addSystemMap.c
--- linux-2.4.21-pre3/arch/ppc64/boot/addSystemMap.c	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/boot/addSystemMap.c	Tue Jan 28 19:44:28 2003
@@ -146,10 +146,8 @@
   /* Process the Sysmap file to determine the true end of the kernel */
 	sysmapPages = sysmapLen / 4096;
 	printf("System map pages to copy = %ld\n", sysmapPages);
-	for (i=0; i<sysmapPages; ++i)
-	{
-		get4k(sysmap, inbuf);
-	}
+	/* read the whole file line by line, expect that it doesnt fail */
+	while ( fgets(inbuf, 4096, sysmap) )  ;
 	/* search for _end in the last page of the system map */
 	ptr_end = strstr(inbuf, " _end");
 	if (!ptr_end)
diff -urN linux-2.4.21-pre3/arch/ppc64/config.in linux-2.4.21-pre4/arch/ppc64/config.in
--- linux-2.4.21-pre3/arch/ppc64/config.in	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/config.in	Tue Jan 28 19:44:28 2003
@@ -38,6 +38,7 @@
 else
 bool 'MsChunks Physical to Absolute address translation support' CONFIG_MSCHUNKS
 tristate 'Firmware flash interface' CONFIG_RTAS_FLASH
+tristate 'Scanlog Dump interface' CONFIG_SCANLOG
 fi
 
 
@@ -228,6 +229,8 @@
 source drivers/usb/Config.in
 fi
 
+source lib/Config.in
+
 mainmenu_option next_comment
 comment 'Kernel hacking'
 
diff -urN linux-2.4.21-pre3/arch/ppc64/configs/pSeries_defconfig linux-2.4.21-pre4/arch/ppc64/configs/pSeries_defconfig
--- linux-2.4.21-pre3/arch/ppc64/configs/pSeries_defconfig	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/configs/pSeries_defconfig	Tue Jan 28 19:44:28 2003
@@ -26,6 +26,7 @@
 # CONFIG_HMT is not set
 # CONFIG_MSCHUNKS is not set
 CONFIG_RTAS_FLASH=m
+CONFIG_SCANLOG=m
 
 #
 # Loadable module support
@@ -42,6 +43,7 @@
 # CONFIG_MCA is not set
 # CONFIG_EISA is not set
 CONFIG_PCI=y
+# CONFIG_PCMCIA is not set
 CONFIG_NET=y
 CONFIG_SYSCTL=y
 CONFIG_SYSVIPC=y
@@ -52,7 +54,6 @@
 # CONFIG_BINFMT_MISC is not set
 CONFIG_PCI_NAMES=y
 # CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
 
 #
 # Parallel port support
@@ -61,20 +62,7 @@
 # CONFIG_VGA_CONSOLE is not set
 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)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
+# CONFIG_CMDLINE_BOOL is not set
 
 #
 # Block devices
@@ -92,6 +80,7 @@
 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)
@@ -178,21 +167,13 @@
 # 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
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
 # CONFIG_BLK_DEV_IDECS is not set
 CONFIG_BLK_DEV_IDECD=y
 # 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
+# CONFIG_IDE_TASKFILE_IO is not set
 
 #
 # IDE chipset support/bugfixes
@@ -200,8 +181,8 @@
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
 CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_BLK_DEV_GENERIC is not set
 # CONFIG_IDEPCI_SHARE_IRQ is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
@@ -210,28 +191,31 @@
 # 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
 # CONFIG_WDC_ALI15X3 is not set
 # 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_TRIFLEX is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
 # CONFIG_BLK_DEV_CS5530 is not set
 # CONFIG_BLK_DEV_HPT34X is not set
 # CONFIG_HPT34X_AUTODMA is not set
 # CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_NFORCE is not set
 # CONFIG_BLK_DEV_NS87415 is not set
 # CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_PDC202XX is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
 # CONFIG_PDC202XX_BURST is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
 # CONFIG_PDC202XX_FORCE is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
 # CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
 # CONFIG_BLK_DEV_SIS5513 is not set
 # CONFIG_BLK_DEV_SLC90E66 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
@@ -325,6 +309,7 @@
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
 
 #
@@ -367,15 +352,16 @@
 # CONFIG_NET_ISA is not set
 CONFIG_NET_PCI=y
 CONFIG_PCNET32=y
+# CONFIG_AMD8111_ETH 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_TC35815 is not set
 # CONFIG_DE4X5 is not set
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
-CONFIG_EEPRO100=y
+# CONFIG_EEPRO100 is not set
+CONFIG_E100=y
 # CONFIG_LNE390 is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
@@ -387,11 +373,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_8139_OLD_RX_RESET is not set
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
+# CONFIG_SUNDANCE_MMIO 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
@@ -401,12 +389,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_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -443,11 +433,6 @@
 # CONFIG_HAMRADIO is not set
 
 #
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
-
-#
 # ISDN subsystem
 #
 # CONFIG_ISDN is not set
@@ -563,9 +548,10 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
-# CONFIG_RTC is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
@@ -590,6 +576,8 @@
 # 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=y
 CONFIG_JBD=y
@@ -607,9 +595,10 @@
 CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
 # CONFIG_ZISOFS is not set
-# CONFIG_MINIX_FS 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
@@ -639,6 +628,7 @@
 # CONFIG_ROOT_NFS is not set
 CONFIG_NFSD=y
 CONFIG_NFSD_V3=y
+# CONFIG_NFSD_TCP is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
@@ -654,7 +644,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
@@ -712,11 +701,22 @@
 # CONFIG_SOUND is not set
 
 #
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
 # USB support
 #
 # CONFIG_USB is not set
 
 #
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
+
+#
 # Kernel hacking
 #
 CONFIG_MAGIC_SYSRQ=y
@@ -724,9 +724,9 @@
 # CONFIG_XMON is not set
 CONFIG_KDB=y
 # CONFIG_KDB_OFF is not set
-# CONFIG_KALLSYMS is not set
+CONFIG_KALLSYMS=y
+# CONFIG_XMON is not set
 CONFIG_PPCDBG=y
-
 CONFIG_DUMP=y
 CONFIG_DUMP_COMPRESS_RLE=y
 CONFIG_DUMP_COMPRESS_GZIP=y
diff -urN linux-2.4.21-pre3/arch/ppc64/defconfig linux-2.4.21-pre4/arch/ppc64/defconfig
--- linux-2.4.21-pre3/arch/ppc64/defconfig	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/defconfig	Tue Jan 28 19:44:28 2003
@@ -26,6 +26,7 @@
 # CONFIG_HMT is not set
 # CONFIG_MSCHUNKS is not set
 CONFIG_RTAS_FLASH=m
+CONFIG_SCANLOG=m
 
 #
 # Loadable module support
@@ -42,6 +43,7 @@
 # CONFIG_MCA is not set
 # CONFIG_EISA is not set
 CONFIG_PCI=y
+# CONFIG_PCMCIA is not set
 CONFIG_NET=y
 CONFIG_SYSCTL=y
 CONFIG_SYSVIPC=y
@@ -52,7 +54,6 @@
 # CONFIG_BINFMT_MISC is not set
 CONFIG_PCI_NAMES=y
 # CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
 
 #
 # Parallel port support
@@ -61,20 +62,7 @@
 # CONFIG_VGA_CONSOLE is not set
 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)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
+# CONFIG_CMDLINE_BOOL is not set
 
 #
 # Block devices
@@ -92,6 +80,7 @@
 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)
@@ -178,21 +167,13 @@
 # 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
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
 # CONFIG_BLK_DEV_IDECS is not set
 CONFIG_BLK_DEV_IDECD=y
 # 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
+# CONFIG_IDE_TASKFILE_IO is not set
 
 #
 # IDE chipset support/bugfixes
@@ -200,8 +181,8 @@
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
 CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_BLK_DEV_GENERIC is not set
 # CONFIG_IDEPCI_SHARE_IRQ is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
@@ -210,28 +191,31 @@
 # 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
 # CONFIG_WDC_ALI15X3 is not set
 # 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_TRIFLEX is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
 # CONFIG_BLK_DEV_CS5530 is not set
 # CONFIG_BLK_DEV_HPT34X is not set
 # CONFIG_HPT34X_AUTODMA is not set
 # CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_NFORCE is not set
 # CONFIG_BLK_DEV_NS87415 is not set
 # CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_PDC202XX is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
 # CONFIG_PDC202XX_BURST is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
 # CONFIG_PDC202XX_FORCE is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
 # CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
 # CONFIG_BLK_DEV_SIS5513 is not set
 # CONFIG_BLK_DEV_SLC90E66 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
@@ -325,6 +309,7 @@
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
 
 #
@@ -367,15 +352,16 @@
 # CONFIG_NET_ISA is not set
 CONFIG_NET_PCI=y
 CONFIG_PCNET32=y
+# CONFIG_AMD8111_ETH 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_TC35815 is not set
 # CONFIG_DE4X5 is not set
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
-CONFIG_EEPRO100=y
+# CONFIG_EEPRO100 is not set
+CONFIG_E100=y
 # CONFIG_LNE390 is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
@@ -387,11 +373,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_8139_OLD_RX_RESET is not set
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
+# CONFIG_SUNDANCE_MMIO 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
@@ -403,10 +391,12 @@
 CONFIG_ACENIC=y
 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_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -443,11 +433,6 @@
 # CONFIG_HAMRADIO is not set
 
 #
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
-
-#
 # ISDN subsystem
 #
 # CONFIG_ISDN is not set
@@ -563,9 +548,10 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
-# CONFIG_RTC is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
@@ -590,6 +576,8 @@
 # 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=y
 CONFIG_JBD=y
@@ -607,9 +595,10 @@
 CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
 # CONFIG_ZISOFS is not set
-# CONFIG_MINIX_FS 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
@@ -639,6 +628,7 @@
 # CONFIG_ROOT_NFS is not set
 CONFIG_NFSD=y
 CONFIG_NFSD_V3=y
+# CONFIG_NFSD_TCP is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
@@ -654,7 +644,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
@@ -712,11 +701,22 @@
 # CONFIG_SOUND is not set
 
 #
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
 # USB support
 #
 # CONFIG_USB is not set
 
 #
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
+
+#
 # Kernel hacking
 #
 CONFIG_MAGIC_SYSRQ=y
@@ -724,9 +724,9 @@
 # CONFIG_XMON is not set
 CONFIG_KDB=y
 # CONFIG_KDB_OFF is not set
-# CONFIG_KALLSYMS is not set
+CONFIG_KALLSYMS=y
+# CONFIG_XMON is not set
 CONFIG_PPCDBG=y
-
 CONFIG_DUMP=y
 CONFIG_DUMP_COMPRESS_RLE=y
 CONFIG_DUMP_COMPRESS_GZIP=y
diff -urN linux-2.4.21-pre3/arch/ppc64/kdb/Makefile linux-2.4.21-pre4/arch/ppc64/kdb/Makefile
--- linux-2.4.21-pre3/arch/ppc64/kdb/Makefile	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/arch/ppc64/kdb/Makefile	Tue Jan 28 19:44:28 2003
@@ -0,0 +1,16 @@
+O_TARGET	:= kdba.o
+obj-y		:= kdba_bt.o kdba_bp.o kdba_id.o kdba_io.o ppc-dis.o ppc-opc.o kdbasupport.o  start.o kdba_utils.o
+
+# Warning: running with a minimal-toc means that kdb_setjmp will break
+# due to saving the wrong r30. A solution would be to move it into setjmp.S
+EXTRA_CFLAGS = -mno-minimal-toc
+
+# override CFLAGS := $(CFLAGS) -g
+
+override CFLAGS := $(CFLAGS) -I.
+
+# Translate to Rules.make lists.
+O_OBJS		:= $(filter-out	$(export-objs), $(obj-y))
+OX_OBJS		:= $(filter	$(export-objs), $(obj-y))
+
+include $(TOPDIR)/Rules.make
diff -urN linux-2.4.21-pre3/arch/ppc64/kdb/ansidecl.h linux-2.4.21-pre4/arch/ppc64/kdb/ansidecl.h
--- linux-2.4.21-pre3/arch/ppc64/kdb/ansidecl.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/arch/ppc64/kdb/ansidecl.h	Tue Jan 28 19:44:29 2003
@@ -0,0 +1,198 @@
+/* ANSI and traditional C compatability macros
+   Copyright 1991, 1992, 1996, 1999 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+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.  */
+
+/* ANSI and traditional C compatibility macros
+
+   ANSI C is assumed if __STDC__ is #defined.
+
+   Macro	ANSI C definition	Traditional C definition
+   -----	---- - ----------	----------- - ----------
+   PTR		`void *'		`char *'
+   LONG_DOUBLE	`long double'		`double'
+   VOLATILE	`volatile'		`'
+   SIGNED	`signed'		`'
+   PTRCONST	`void *const'		`char *'
+   ANSI_PROTOTYPES  1			not defined
+
+   CONST is also defined, but is obsolete.  Just use const.
+
+   obsolete --     DEFUN (name, arglist, args)
+
+	Defines function NAME.
+
+	ARGLIST lists the arguments, separated by commas and enclosed in
+	parentheses.  ARGLIST becomes the argument list in traditional C.
+
+	ARGS list the arguments with their types.  It becomes a prototype in
+	ANSI C, and the type declarations in traditional C.  Arguments should
+	be separated with `AND'.  For functions with a variable number of
+	arguments, the last thing listed should be `DOTS'.
+
+   obsolete --     DEFUN_VOID (name)
+
+	Defines a function NAME, which takes no arguments.
+
+   obsolete --     EXFUN (name, (prototype))	-- obsolete.
+
+	Replaced by PARAMS.  Do not use; will disappear someday soon.
+	Was used in external function declarations.
+	In ANSI C it is `NAME PROTOTYPE' (so PROTOTYPE should be enclosed in
+	parentheses).  In traditional C it is `NAME()'.
+	For a function that takes no arguments, PROTOTYPE should be `(void)'.
+
+   obsolete --     PROTO (type, name, (prototype)    -- obsolete.
+
+	This one has also been replaced by PARAMS.  Do not use.
+
+   PARAMS ((args))
+
+	We could use the EXFUN macro to handle prototype declarations, but
+	the name is misleading and the result is ugly.  So we just define a
+	simple macro to handle the parameter lists, as in:
+
+	      static int foo PARAMS ((int, char));
+
+	This produces:  `static int foo();' or `static int foo (int, char);'
+
+	EXFUN would have done it like this:
+
+	      static int EXFUN (foo, (int, char));
+
+	but the function is not external...and it's hard to visually parse
+	the function name out of the mess.   EXFUN should be considered
+	obsolete; new code should be written to use PARAMS.
+
+   DOTS is also obsolete.
+
+   Examples:
+
+	extern int printf PARAMS ((const char *format, ...));
+*/
+
+#ifndef	_ANSIDECL_H
+
+#define	_ANSIDECL_H	1
+
+
+/* Every source file includes this file,
+   so they will all get the switch for lint.  */
+/* LINTLIBRARY */
+
+
+#if defined (__STDC__) || defined (_AIX) || (defined (__mips) && defined (_SYSTYPE_SVR4)) || defined(_WIN32)
+/* All known AIX compilers implement these things (but don't always
+   define __STDC__).  The RISC/OS MIPS compiler defines these things
+   in SVR4 mode, but does not define __STDC__.  */
+
+#define	PTR		void *
+#define	PTRCONST	void *CONST
+#define	LONG_DOUBLE	long double
+
+#ifndef IN_GCC
+#define	AND		,
+#define	NOARGS		void
+#define	VOLATILE	volatile
+#define	SIGNED		signed
+#endif /* ! IN_GCC */
+
+#ifndef PARAMS
+#define PARAMS(paramlist)		paramlist
+#endif
+#define ANSI_PROTOTYPES			1
+
+#define VPARAMS(ARGS)			ARGS
+#define VA_START(va_list,var)		va_start(va_list,var)
+
+/* These are obsolete.  Do not use.  */
+#ifndef IN_GCC
+#define CONST				const
+#define DOTS				, ...
+#define PROTO(type, name, arglist)	type name arglist
+#define EXFUN(name, proto)		name proto
+#define DEFUN(name, arglist, args)	name(args)
+#define DEFUN_VOID(name)		name(void)
+#endif /* ! IN_GCC */
+
+#else	/* Not ANSI C.  */
+
+#define	PTR		char *
+#define	PTRCONST	PTR
+#define	LONG_DOUBLE	double
+
+#ifndef IN_GCC
+#define	AND		;
+#define	NOARGS
+#define	VOLATILE
+#define	SIGNED
+#endif /* !IN_GCC */
+
+#ifndef const /* some systems define it in header files for non-ansi mode */
+#define	const
+#endif
+
+#define PARAMS(paramlist)		()
+
+#define VPARAMS(ARGS)			(va_alist) va_dcl
+#define VA_START(va_list,var)		va_start(va_list)
+
+/* These are obsolete.  Do not use.  */
+#ifndef IN_GCC
+#define CONST
+#define DOTS
+#define PROTO(type, name, arglist)	type name ()
+#define EXFUN(name, proto)		name()
+#define DEFUN(name, arglist, args)	name arglist args;
+#define DEFUN_VOID(name)		name()
+#endif /* ! IN_GCC */
+
+#endif	/* ANSI C.  */
+
+/* Define macros for some gcc attributes.  This permits us to use the
+   macros freely, and know that they will come into play for the
+   version of gcc in which they are supported.  */
+
+#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)
+# define __attribute__(x)
+#endif
+
+#ifndef ATTRIBUTE_UNUSED_LABEL
+# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 93)
+#  define ATTRIBUTE_UNUSED_LABEL
+# else
+#  define ATTRIBUTE_UNUSED_LABEL ATTRIBUTE_UNUSED
+# endif /* GNUC < 2.93 */
+#endif /* ATTRIBUTE_UNUSED_LABEL */
+
+#ifndef ATTRIBUTE_UNUSED
+#define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
+#endif /* ATTRIBUTE_UNUSED */
+
+#ifndef ATTRIBUTE_NORETURN
+#define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__))
+#endif /* ATTRIBUTE_NORETURN */
+
+#ifndef ATTRIBUTE_PRINTF
+#define ATTRIBUTE_PRINTF(m, n) __attribute__ ((format (__printf__, m, n)))
+#define ATTRIBUTE_PRINTF_1 ATTRIBUTE_PRINTF(1, 2)
+#define ATTRIBUTE_PRINTF_2 ATTRIBUTE_PRINTF(2, 3)
+#define ATTRIBUTE_PRINTF_3 ATTRIBUTE_PRINTF(3, 4)
+#define ATTRIBUTE_PRINTF_4 ATTRIBUTE_PRINTF(4, 5)
+#define ATTRIBUTE_PRINTF_5 ATTRIBUTE_PRINTF(5, 6)
+#endif /* ATTRIBUTE_PRINTF */
+
+#endif	/* ansidecl.h	*/
diff -urN linux-2.4.21-pre3/arch/ppc64/kdb/bfd.h linux-2.4.21-pre4/arch/ppc64/kdb/bfd.h
--- linux-2.4.21-pre3/arch/ppc64/kdb/bfd.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/arch/ppc64/kdb/bfd.h	Tue Jan 28 19:44:29 2003
@@ -0,0 +1,3706 @@
+/* DO NOT EDIT!  -*- buffer-read-only: t -*-  This file is automatically 
+   generated from "bfd-in.h", "init.c", "opncls.c", "libbfd.c", 
+   "section.c", "archures.c", "reloc.c", "syms.c", "bfd.c", "archive.c", 
+   "corefile.c", "targets.c" and "format.c".
+   Run "make headers" in your build bfd/ to regenerate.  */
+
+/* Main header file for the bfd library -- portable access to object files.
+   Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+   2000, 2001
+   Free Software Foundation, Inc.
+   Contributed by Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+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.  */
+
+#ifndef __BFD_H_SEEN__
+#define __BFD_H_SEEN__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ansidecl.h"
+#include "symcat.h"
+#if defined (__STDC__) || defined (ALMOST_STDC) || defined (HAVE_STRINGIZE)
+#ifndef SABER
+/* This hack is to avoid a problem with some strict ANSI C preprocessors.
+   The problem is, "32_" is not a valid preprocessing token, and we don't
+   want extra underscores (e.g., "nlm_32_").  The XCONCAT2 macro will
+   cause the inner CONCAT2 macros to be evaluated first, producing
+   still-valid pp-tokens.  Then the final concatenation can be done.  */
+#undef CONCAT4
+#define CONCAT4(a,b,c,d) XCONCAT2(CONCAT2(a,b),CONCAT2(c,d))
+#endif
+#endif
+
+#define BFD_VERSION 211920007
+#define BFD_VERSION_DATE 20011016
+#define BFD_VERSION_STRING "2.11.92.0.7 20011016 Debian\/GNU Linux"
+
+/* The word size used by BFD on the host.  This may be 64 with a 32
+   bit target if the host is 64 bit, or if other 64 bit targets have
+   been selected with --enable-targets, or if --enable-64-bit-bfd.  */
+#define BFD_ARCH_SIZE 64
+
+/* The word size of the default bfd target.  */
+#define BFD_DEFAULT_TARGET_SIZE 32
+
+#define BFD_HOST_64BIT_LONG 1
+#define BFD_HOST_64_BIT long
+#define BFD_HOST_U_64_BIT unsigned long
+
+#if BFD_ARCH_SIZE >= 64
+#define BFD64
+#endif
+
+#ifndef INLINE
+#if __GNUC__ >= 2
+#define INLINE __inline__
+#else
+#define INLINE
+#endif
+#endif
+
+/* forward declaration */
+typedef struct _bfd bfd;
+
+/* To squelch erroneous compiler warnings ("illegal pointer
+   combination") from the SVR3 compiler, we would like to typedef
+   boolean to int (it doesn't like functions which return boolean.
+   Making sure they are never implicitly declared to return int
+   doesn't seem to help).  But this file is not configured based on
+   the host.  */
+/* General rules: functions which are boolean return true on success
+   and false on failure (unless they're a predicate).   -- bfd.doc */
+/* I'm sure this is going to break something and someone is going to
+   force me to change it.  */
+/* typedef enum boolean {false, true} boolean; */
+/* Yup, SVR4 has a "typedef enum boolean" in <sys/types.h>  -fnf */
+/* It gets worse if the host also defines a true/false enum... -sts */
+/* And even worse if your compiler has built-in boolean types... -law */
+#if defined (__GNUG__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 6))
+#define TRUE_FALSE_ALREADY_DEFINED
+#endif
+#ifdef MPW
+/* Pre-emptive strike - get the file with the enum.  */
+#include <Types.h>
+#define TRUE_FALSE_ALREADY_DEFINED
+#endif /* MPW */
+#ifndef TRUE_FALSE_ALREADY_DEFINED
+typedef enum bfd_boolean {false, true} boolean;
+#define BFD_TRUE_FALSE
+#else
+/* Use enum names that will appear nowhere else.  */
+typedef enum bfd_boolean {bfd_fffalse, bfd_tttrue} boolean;
+#endif
+
+/* Support for different sizes of target format ints and addresses.
+   If the type `long' is at least 64 bits, BFD_HOST_64BIT_LONG will be
+   set to 1 above.  Otherwise, if gcc is being used, this code will
+   use gcc's "long long" type.  Otherwise, BFD_HOST_64_BIT must be
+   defined above.  */
+
+#ifndef BFD_HOST_64_BIT
+# if BFD_HOST_64BIT_LONG
+#  define BFD_HOST_64_BIT long
+#  define BFD_HOST_U_64_BIT unsigned long
+# else
+#  ifdef __GNUC__
+#   if __GNUC__ >= 2
+#    define BFD_HOST_64_BIT long long
+#    define BFD_HOST_U_64_BIT unsigned long long
+#   endif /* __GNUC__ >= 2 */
+#  endif /* ! defined (__GNUC__) */
+# endif /* ! BFD_HOST_64BIT_LONG */
+#endif /* ! defined (BFD_HOST_64_BIT) */
+
+#ifdef BFD64
+
+#ifndef BFD_HOST_64_BIT
+ #error No 64 bit integer type available
+#endif /* ! defined (BFD_HOST_64_BIT) */
+
+typedef BFD_HOST_U_64_BIT bfd_vma;
+typedef BFD_HOST_64_BIT bfd_signed_vma;
+typedef BFD_HOST_U_64_BIT bfd_size_type;
+typedef BFD_HOST_U_64_BIT symvalue;
+
+#ifndef fprintf_vma
+#if BFD_HOST_64BIT_LONG
+#define sprintf_vma(s,x) sprintf (s, "%016lx", x)
+#define fprintf_vma(f,x) fprintf (f, "%016lx", x)
+#else
+#define _bfd_int64_low(x) ((unsigned long) (((x) & 0xffffffff)))
+#define _bfd_int64_high(x) ((unsigned long) (((x) >> 32) & 0xffffffff))
+#define fprintf_vma(s,x) \
+  fprintf ((s), "%08lx%08lx", _bfd_int64_high (x), _bfd_int64_low (x))
+#define sprintf_vma(s,x) \
+  sprintf ((s), "%08lx%08lx", _bfd_int64_high (x), _bfd_int64_low (x))
+#endif
+#endif
+
+#else /* not BFD64  */
+
+/* Represent a target address.  Also used as a generic unsigned type
+   which is guaranteed to be big enough to hold any arithmetic types
+   we need to deal with.  */
+typedef unsigned long bfd_vma;
+
+/* A generic signed type which is guaranteed to be big enough to hold any
+   arithmetic types we need to deal with.  Can be assumed to be compatible
+   with bfd_vma in the same way that signed and unsigned ints are compatible
+   (as parameters, in assignment, etc).  */
+typedef long bfd_signed_vma;
+
+typedef unsigned long symvalue;
+typedef unsigned long bfd_size_type;
+
+/* Print a bfd_vma x on stream s.  */
+#define fprintf_vma(s,x) fprintf (s, "%08lx", x)
+#define sprintf_vma(s,x) sprintf (s, "%08lx", x)
+
+#endif /* not BFD64  */
+
+/* A pointer to a position in a file.  */
+/* FIXME:  This should be using off_t from <sys/types.h>.
+   For now, try to avoid breaking stuff by not including <sys/types.h> here.
+   This will break on systems with 64-bit file offsets (e.g. 4.4BSD).
+   Probably the best long-term answer is to avoid using file_ptr AND off_t
+   in this header file, and to handle this in the BFD implementation
+   rather than in its interface.  */
+/* typedef off_t	file_ptr; */
+typedef bfd_signed_vma file_ptr;
+typedef bfd_vma ufile_ptr;
+
+extern void bfd_sprintf_vma PARAMS ((bfd *, char *, bfd_vma));
+extern void bfd_fprintf_vma PARAMS ((bfd *, PTR, bfd_vma));
+
+#define printf_vma(x) fprintf_vma(stdout,x)
+#define bfd_printf_vma(abfd,x) bfd_fprintf_vma (abfd,stdout,x)
+
+typedef unsigned int flagword;	/* 32 bits of flags */
+typedef unsigned char bfd_byte;
+
+/** File formats */
+
+typedef enum bfd_format {
+	      bfd_unknown = 0,	/* file format is unknown */
+	      bfd_object,	/* linker/assember/compiler output */
+	      bfd_archive,	/* object archive file */
+	      bfd_core,		/* core dump */
+	      bfd_type_end}	/* marks the end; don't use it! */
+         bfd_format;
+
+/* Values that may appear in the flags field of a BFD.  These also
+   appear in the object_flags field of the bfd_target structure, where
+   they indicate the set of flags used by that backend (not all flags
+   are meaningful for all object file formats) (FIXME: at the moment,
+   the object_flags values have mostly just been copied from backend
+   to another, and are not necessarily correct).  */
+
+/* No flags.  */
+#define BFD_NO_FLAGS   	0x00
+
+/* BFD contains relocation entries.  */
+#define HAS_RELOC   	0x01
+
+/* BFD is directly executable.  */
+#define EXEC_P      	0x02
+
+/* BFD has line number information (basically used for F_LNNO in a
+   COFF header).  */
+#define HAS_LINENO  	0x04
+
+/* BFD has debugging information.  */
+#define HAS_DEBUG   	0x08
+
+/* BFD has symbols.  */
+#define HAS_SYMS    	0x10
+
+/* BFD has local symbols (basically used for F_LSYMS in a COFF
+   header).  */
+#define HAS_LOCALS  	0x20
+
+/* BFD is a dynamic object.  */
+#define DYNAMIC     	0x40
+
+/* Text section is write protected (if D_PAGED is not set, this is
+   like an a.out NMAGIC file) (the linker sets this by default, but
+   clears it for -r or -N).  */
+#define WP_TEXT     	0x80
+
+/* BFD is dynamically paged (this is like an a.out ZMAGIC file) (the
+   linker sets this by default, but clears it for -r or -n or -N).  */
+#define D_PAGED     	0x100
+
+/* BFD is relaxable (this means that bfd_relax_section may be able to
+   do something) (sometimes bfd_relax_section can do something even if
+   this is not set).  */
+#define BFD_IS_RELAXABLE 0x200
+
+/* This may be set before writing out a BFD to request using a
+   traditional format.  For example, this is used to request that when
+   writing out an a.out object the symbols not be hashed to eliminate
+   duplicates.  */
+#define BFD_TRADITIONAL_FORMAT 0x400
+
+/* This flag indicates that the BFD contents are actually cached in
+   memory.  If this is set, iostream points to a bfd_in_memory struct.  */
+#define BFD_IN_MEMORY 0x800
+
+/* symbols and relocation */
+
+/* A count of carsyms (canonical archive symbols).  */
+typedef unsigned long symindex;
+
+/* How to perform a relocation.  */
+typedef const struct reloc_howto_struct reloc_howto_type;
+
+#define BFD_NO_MORE_SYMBOLS ((symindex) ~0)
+
+/* General purpose part of a symbol X;
+   target specific parts are in libcoff.h, libaout.h, etc.  */
+
+#define bfd_get_section(x) ((x)->section)
+#define bfd_get_output_section(x) ((x)->section->output_section)
+#define bfd_set_section(x,y) ((x)->section) = (y)
+#define bfd_asymbol_base(x) ((x)->section->vma)
+#define bfd_asymbol_value(x) (bfd_asymbol_base(x) + (x)->value)
+#define bfd_asymbol_name(x) ((x)->name)
+/*Perhaps future: #define bfd_asymbol_bfd(x) ((x)->section->owner)*/
+#define bfd_asymbol_bfd(x) ((x)->the_bfd)
+#define bfd_asymbol_flavour(x) (bfd_asymbol_bfd(x)->xvec->flavour)
+
+/* A canonical archive symbol.  */
+/* This is a type pun with struct ranlib on purpose! */
+typedef struct carsym {
+  char *name;
+  file_ptr file_offset;		/* look here to find the file */
+} carsym;			/* to make these you call a carsymogen */
+
+/* Used in generating armaps (archive tables of contents).
+   Perhaps just a forward definition would do? */
+struct orl {			/* output ranlib */
+  char **name;			/* symbol name */
+  union {
+    file_ptr pos;
+    bfd *abfd;
+  } u;				/* bfd* or file position */
+  int namidx;			/* index into string table */
+};
+
+/* Linenumber stuff */
+typedef struct lineno_cache_entry {
+  unsigned int line_number;	/* Linenumber from start of function*/
+  union {
+    struct symbol_cache_entry *sym; /* Function name */
+    bfd_vma offset;	    /* Offset into section */
+  } u;
+} alent;
+
+/* object and core file sections */
+
+#define	align_power(addr, align)	\
+	( ((addr) + ((1<<(align))-1)) & (-1 << (align)))
+
+typedef struct sec *sec_ptr;
+
+#define bfd_get_section_name(bfd, ptr) ((ptr)->name + 0)
+#define bfd_get_section_vma(bfd, ptr) ((ptr)->vma + 0)
+#define bfd_get_section_alignment(bfd, ptr) ((ptr)->alignment_power + 0)
+#define bfd_section_name(bfd, ptr) ((ptr)->name)
+#define bfd_section_size(bfd, ptr) (bfd_get_section_size_before_reloc(ptr))
+#define bfd_section_vma(bfd, ptr) ((ptr)->vma)
+#define bfd_section_lma(bfd, ptr) ((ptr)->lma)
+#define bfd_section_alignment(bfd, ptr) ((ptr)->alignment_power)
+#define bfd_get_section_flags(bfd, ptr) ((ptr)->flags + 0)
+#define bfd_get_section_userdata(bfd, ptr) ((ptr)->userdata)
+
+#define bfd_is_com_section(ptr) (((ptr)->flags & SEC_IS_COMMON) != 0)
+
+#define bfd_set_section_vma(bfd, ptr, val) (((ptr)->vma = (ptr)->lma= (val)), ((ptr)->user_set_vma = (boolean)true), true)
+#define bfd_set_section_alignment(bfd, ptr, val) (((ptr)->alignment_power = (val)),true)
+#define bfd_set_section_userdata(bfd, ptr, val) (((ptr)->userdata = (val)),true)
+
+typedef struct stat stat_type;
+
+typedef enum bfd_print_symbol
+{
+  bfd_print_symbol_name,
+  bfd_print_symbol_more,
+  bfd_print_symbol_all
+} bfd_print_symbol_type;
+
+/* Information about a symbol that nm needs.  */
+
+typedef struct _symbol_info
+{
+  symvalue value;
+  char type;
+  const char *name;            /* Symbol name.  */
+  unsigned char stab_type;     /* Stab type.  */
+  char stab_other;             /* Stab other.  */
+  short stab_desc;             /* Stab desc.  */
+  const char *stab_name;       /* String for stab type.  */
+} symbol_info;
+
+/* Get the name of a stabs type code.  */
+
+extern const char *bfd_get_stab_name PARAMS ((int));
+
+/* Hash table routines.  There is no way to free up a hash table.  */
+
+/* An element in the hash table.  Most uses will actually use a larger
+   structure, and an instance of this will be the first field.  */
+
+struct bfd_hash_entry
+{
+  /* Next entry for this hash code.  */
+  struct bfd_hash_entry *next;
+  /* String being hashed.  */
+  const char *string;
+  /* Hash code.  This is the full hash code, not the index into the
+     table.  */
+  unsigned long hash;
+};
+
+/* A hash table.  */
+
+struct bfd_hash_table
+{
+  /* The hash array.  */
+  struct bfd_hash_entry **table;
+  /* The number of slots in the hash table.  */
+  unsigned int size;
+  /* A function used to create new elements in the hash table.  The
+     first entry is itself a pointer to an element.  When this
+     function is first invoked, this pointer will be NULL.  However,
+     having the pointer permits a hierarchy of method functions to be
+     built each of which calls the function in the superclass.  Thus
+     each function should be written to allocate a new block of memory
+     only if the argument is NULL.  */
+  struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *,
+					     struct bfd_hash_table *,
+					     const char *));
+   /* An objalloc for this hash table.  This is a struct objalloc *,
+     but we use PTR to avoid requiring the inclusion of objalloc.h.  */
+  PTR memory;
+};
+
+/* Initialize a hash table.  */
+extern boolean bfd_hash_table_init
+  PARAMS ((struct bfd_hash_table *,
+	   struct bfd_hash_entry *(*) (struct bfd_hash_entry *,
+				       struct bfd_hash_table *,
+				       const char *)));
+
+/* Initialize a hash table specifying a size.  */
+extern boolean bfd_hash_table_init_n
+  PARAMS ((struct bfd_hash_table *,
+	   struct bfd_hash_entry *(*) (struct bfd_hash_entry *,
+				       struct bfd_hash_table *,
+				       const char *),
+	   unsigned int size));
+
+/* Free up a hash table.  */
+extern void bfd_hash_table_free PARAMS ((struct bfd_hash_table *));
+
+/* Look up a string in a hash table.  If CREATE is true, a new entry
+   will be created for this string if one does not already exist.  The
+   COPY argument must be true if this routine should copy the string
+   into newly allocated memory when adding an entry.  */
+extern struct bfd_hash_entry *bfd_hash_lookup
+  PARAMS ((struct bfd_hash_table *, const char *, boolean create,
+	   boolean copy));
+
+/* Replace an entry in a hash table.  */
+extern void bfd_hash_replace
+  PARAMS ((struct bfd_hash_table *, struct bfd_hash_entry *old,
+	   struct bfd_hash_entry *nw));
+
+/* Base method for creating a hash table entry.  */
+extern struct bfd_hash_entry *bfd_hash_newfunc
+  PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *,
+	   const char *));
+
+/* Grab some space for a hash table entry.  */
+extern PTR bfd_hash_allocate PARAMS ((struct bfd_hash_table *,
+				      unsigned int));
+
+/* Traverse a hash table in a random order, calling a function on each
+   element.  If the function returns false, the traversal stops.  The
+   INFO argument is passed to the function.  */
+extern void bfd_hash_traverse PARAMS ((struct bfd_hash_table *,
+				       boolean (*) (struct bfd_hash_entry *,
+						    PTR),
+				       PTR info));
+
+#define COFF_SWAP_TABLE (PTR) &bfd_coff_std_swap_table
+
+/* User program access to BFD facilities */
+
+/* Direct I/O routines, for programs which know more about the object
+   file than BFD does.  Use higher level routines if possible.  */
+
+extern bfd_size_type bfd_bread PARAMS ((PTR, bfd_size_type, bfd *));
+extern bfd_size_type bfd_bwrite PARAMS ((const PTR, bfd_size_type, bfd *));
+extern int bfd_seek PARAMS ((bfd *, file_ptr, int));
+extern ufile_ptr bfd_tell PARAMS ((bfd *));
+extern int bfd_flush PARAMS ((bfd *));
+extern int bfd_stat PARAMS ((bfd *, struct stat *));
+
+/* Deprecated old routines.  */
+#if __GNUC__
+#define bfd_read(BUF, ELTSIZE, NITEMS, ABFD)				\
+  (warn_deprecated ("bfd_read", __FILE__, __LINE__, __FUNCTION__),	\
+   bfd_bread ((BUF), (ELTSIZE) * (NITEMS), (ABFD)))
+#define bfd_write(BUF, ELTSIZE, NITEMS, ABFD)				\
+  (warn_deprecated ("bfd_write", __FILE__, __LINE__, __FUNCTION__),	\
+   bfd_bwrite ((BUF), (ELTSIZE) * (NITEMS), (ABFD)))
+#else
+#define bfd_read(BUF, ELTSIZE, NITEMS, ABFD)				\
+  (warn_deprecated ("bfd_read", (const char *) 0, 0, (const char *) 0), \
+   bfd_bread ((BUF), (ELTSIZE) * (NITEMS), (ABFD)))
+#define bfd_write(BUF, ELTSIZE, NITEMS, ABFD)				\
+  (warn_deprecated ("bfd_write", (const char *) 0, 0, (const char *) 0),\
+   bfd_bwrite ((BUF), (ELTSIZE) * (NITEMS), (ABFD)))
+#endif
+extern void warn_deprecated
+  PARAMS ((const char *, const char *, int, const char *));
+
+/* Cast from const char * to char * so that caller can assign to
+   a char * without a warning.  */
+#define bfd_get_filename(abfd) ((char *) (abfd)->filename)
+#define bfd_get_cacheable(abfd) ((abfd)->cacheable)
+#define bfd_get_format(abfd) ((abfd)->format)
+#define bfd_get_target(abfd) ((abfd)->xvec->name)
+#define bfd_get_flavour(abfd) ((abfd)->xvec->flavour)
+#define bfd_family_coff(abfd) \
+  (bfd_get_flavour (abfd) == bfd_target_coff_flavour || \
+   bfd_get_flavour (abfd) == bfd_target_xcoff_flavour)
+#define bfd_big_endian(abfd) ((abfd)->xvec->byteorder == BFD_ENDIAN_BIG)
+#define bfd_little_endian(abfd) ((abfd)->xvec->byteorder == BFD_ENDIAN_LITTLE)
+#define bfd_header_big_endian(abfd) \
+  ((abfd)->xvec->header_byteorder == BFD_ENDIAN_BIG)
+#define bfd_header_little_endian(abfd) \
+  ((abfd)->xvec->header_byteorder == BFD_ENDIAN_LITTLE)
+#define bfd_get_file_flags(abfd) ((abfd)->flags)
+#define bfd_applicable_file_flags(abfd) ((abfd)->xvec->object_flags)
+#define bfd_applicable_section_flags(abfd) ((abfd)->xvec->section_flags)
+#define bfd_my_archive(abfd) ((abfd)->my_archive)
+#define bfd_has_map(abfd) ((abfd)->has_armap)
+
+#define bfd_valid_reloc_types(abfd) ((abfd)->xvec->valid_reloc_types)
+#define bfd_usrdata(abfd) ((abfd)->usrdata)
+
+#define bfd_get_start_address(abfd) ((abfd)->start_address)
+#define bfd_get_symcount(abfd) ((abfd)->symcount)
+#define bfd_get_outsymbols(abfd) ((abfd)->outsymbols)
+#define bfd_count_sections(abfd) ((abfd)->section_count)
+
+#define bfd_get_symbol_leading_char(abfd) ((abfd)->xvec->symbol_leading_char)
+
+#define bfd_set_cacheable(abfd,bool) (((abfd)->cacheable = (boolean) (bool)), true)
+
+extern boolean bfd_cache_close PARAMS ((bfd *abfd));
+/* NB: This declaration should match the autogenerated one in libbfd.h.  */
+
+extern boolean bfd_record_phdr
+  PARAMS ((bfd *, unsigned long, boolean, flagword, boolean, bfd_vma,
+	   boolean, boolean, unsigned int, struct sec **));
+
+/* Byte swapping routines.  */
+
+bfd_vma		bfd_getb64	   PARAMS ((const unsigned char *));
+bfd_vma 	bfd_getl64	   PARAMS ((const unsigned char *));
+bfd_signed_vma	bfd_getb_signed_64 PARAMS ((const unsigned char *));
+bfd_signed_vma	bfd_getl_signed_64 PARAMS ((const unsigned char *));
+bfd_vma		bfd_getb32	   PARAMS ((const unsigned char *));
+bfd_vma		bfd_getl32	   PARAMS ((const unsigned char *));
+bfd_signed_vma	bfd_getb_signed_32 PARAMS ((const unsigned char *));
+bfd_signed_vma	bfd_getl_signed_32 PARAMS ((const unsigned char *));
+bfd_vma		bfd_getb16	   PARAMS ((const unsigned char *));
+bfd_vma		bfd_getl16	   PARAMS ((const unsigned char *));
+bfd_signed_vma	bfd_getb_signed_16 PARAMS ((const unsigned char *));
+bfd_signed_vma	bfd_getl_signed_16 PARAMS ((const unsigned char *));
+void		bfd_putb64	   PARAMS ((bfd_vma, unsigned char *));
+void		bfd_putl64	   PARAMS ((bfd_vma, unsigned char *));
+void		bfd_putb32	   PARAMS ((bfd_vma, unsigned char *));
+void		bfd_putl32	   PARAMS ((bfd_vma, unsigned char *));
+void		bfd_putb16	   PARAMS ((bfd_vma, unsigned char *));
+void		bfd_putl16	   PARAMS ((bfd_vma, unsigned char *));
+
+/* Byte swapping routines which take size and endiannes as arguments.  */
+
+bfd_vma         bfd_get_bits       PARAMS ((bfd_byte *, int, boolean));
+void            bfd_put_bits       PARAMS ((bfd_vma, bfd_byte *, int, boolean));
+
+/* Externally visible ECOFF routines.  */
+
+#if defined(__STDC__) || defined(ALMOST_STDC)
+struct ecoff_debug_info;
+struct ecoff_debug_swap;
+struct ecoff_extr;
+struct symbol_cache_entry;
+struct bfd_link_info;
+struct bfd_link_hash_entry;
+struct bfd_elf_version_tree;
+#endif
+extern bfd_vma bfd_ecoff_get_gp_value PARAMS ((bfd * abfd));
+extern boolean bfd_ecoff_set_gp_value PARAMS ((bfd *abfd, bfd_vma gp_value));
+extern boolean bfd_ecoff_set_regmasks
+  PARAMS ((bfd *abfd, unsigned long gprmask, unsigned long fprmask,
+	   unsigned long *cprmask));
+extern PTR bfd_ecoff_debug_init
+  PARAMS ((bfd *output_bfd, struct ecoff_debug_info *output_debug,
+	   const struct ecoff_debug_swap *output_swap,
+	   struct bfd_link_info *));
+extern void bfd_ecoff_debug_free
+  PARAMS ((PTR handle, bfd *output_bfd, struct ecoff_debug_info *output_debug,
+	   const struct ecoff_debug_swap *output_swap,
+	   struct bfd_link_info *));
+extern boolean bfd_ecoff_debug_accumulate
+  PARAMS ((PTR handle, bfd *output_bfd, struct ecoff_debug_info *output_debug,
+	   const struct ecoff_debug_swap *output_swap,
+	   bfd *input_bfd, struct ecoff_debug_info *input_debug,
+	   const struct ecoff_debug_swap *input_swap,
+	   struct bfd_link_info *));
+extern boolean bfd_ecoff_debug_accumulate_other
+  PARAMS ((PTR handle, bfd *output_bfd, struct ecoff_debug_info *output_debug,
+	   const struct ecoff_debug_swap *output_swap, bfd *input_bfd,
+	   struct bfd_link_info *));
+extern boolean bfd_ecoff_debug_externals
+  PARAMS ((bfd *abfd, struct ecoff_debug_info *debug,
+	   const struct ecoff_debug_swap *swap,
+	   boolean relocateable,
+	   boolean (*get_extr) (struct symbol_cache_entry *,
+				struct ecoff_extr *),
+	   void (*set_index) (struct symbol_cache_entry *,
+			      bfd_size_type)));
+extern boolean bfd_ecoff_debug_one_external
+  PARAMS ((bfd *abfd, struct ecoff_debug_info *debug,
+	   const struct ecoff_debug_swap *swap,
+	   const char *name, struct ecoff_extr *esym));
+extern bfd_size_type bfd_ecoff_debug_size
+  PARAMS ((bfd *abfd, struct ecoff_debug_info *debug,
+	   const struct ecoff_debug_swap *swap));
+extern boolean bfd_ecoff_write_debug
+  PARAMS ((bfd *abfd, struct ecoff_debug_info *debug,
+	   const struct ecoff_debug_swap *swap, file_ptr where));
+extern boolean bfd_ecoff_write_accumulated_debug
+  PARAMS ((PTR handle, bfd *abfd, struct ecoff_debug_info *debug,
+	   const struct ecoff_debug_swap *swap,
+	   struct bfd_link_info *info, file_ptr where));
+extern boolean bfd_mips_ecoff_create_embedded_relocs
+  PARAMS ((bfd *, struct bfd_link_info *, struct sec *, struct sec *,
+	   char **));
+
+/* Externally visible ELF routines.  */
+
+struct bfd_link_needed_list
+{
+  struct bfd_link_needed_list *next;
+  bfd *by;
+  const char *name;
+};
+
+extern boolean bfd_elf32_record_link_assignment
+  PARAMS ((bfd *, struct bfd_link_info *, const char *, boolean));
+extern boolean bfd_elf64_record_link_assignment
+  PARAMS ((bfd *, struct bfd_link_info *, const char *, boolean));
+extern struct bfd_link_needed_list *bfd_elf_get_needed_list
+  PARAMS ((bfd *, struct bfd_link_info *));
+extern boolean bfd_elf_get_bfd_needed_list
+  PARAMS ((bfd *, struct bfd_link_needed_list **));
+extern boolean bfd_elf32_size_dynamic_sections
+  PARAMS ((bfd *, const char *, const char *, const char *,
+	   const char * const *, struct bfd_link_info *, struct sec **,
+	   struct bfd_elf_version_tree *));
+extern boolean bfd_elf64_size_dynamic_sections
+  PARAMS ((bfd *, const char *, const char *, const char *,
+	   const char * const *, struct bfd_link_info *, struct sec **,
+	   struct bfd_elf_version_tree *));
+extern void bfd_elf_set_dt_needed_name PARAMS ((bfd *, const char *));
+extern void bfd_elf_set_dt_needed_soname PARAMS ((bfd *, const char *));
+extern const char *bfd_elf_get_dt_soname PARAMS ((bfd *));
+extern struct bfd_link_needed_list *bfd_elf_get_runpath_list
+  PARAMS ((bfd *, struct bfd_link_info *));
+
+/* Return an upper bound on the number of bytes required to store a
+   copy of ABFD's program header table entries.  Return -1 if an error
+   occurs; bfd_get_error will return an appropriate code.  */
+extern long bfd_get_elf_phdr_upper_bound PARAMS ((bfd *abfd));
+
+/* Copy ABFD's program header table entries to *PHDRS.  The entries
+   will be stored as an array of Elf_Internal_Phdr structures, as
+   defined in include/elf/internal.h.  To find out how large the
+   buffer needs to be, call bfd_get_elf_phdr_upper_bound.
+
+   Return the number of program header table entries read, or -1 if an
+   error occurs; bfd_get_error will return an appropriate code.  */
+extern int bfd_get_elf_phdrs PARAMS ((bfd *abfd, void *phdrs));
+
+/* Return the arch_size field of an elf bfd, or -1 if not elf.  */
+extern int bfd_get_arch_size PARAMS ((bfd *));
+
+/* Return true if address "naturally" sign extends, or -1 if not elf.  */
+extern int bfd_get_sign_extend_vma PARAMS ((bfd *));
+
+extern boolean bfd_m68k_elf32_create_embedded_relocs
+  PARAMS ((bfd *, struct bfd_link_info *, struct sec *, struct sec *,
+	   char **));
+
+/* SunOS shared library support routines for the linker.  */
+
+extern struct bfd_link_needed_list *bfd_sunos_get_needed_list
+  PARAMS ((bfd *, struct bfd_link_info *));
+extern boolean bfd_sunos_record_link_assignment
+  PARAMS ((bfd *, struct bfd_link_info *, const char *));
+extern boolean bfd_sunos_size_dynamic_sections
+  PARAMS ((bfd *, struct bfd_link_info *, struct sec **, struct sec **,
+	   struct sec **));
+
+/* Linux shared library support routines for the linker.  */
+
+extern boolean bfd_i386linux_size_dynamic_sections
+  PARAMS ((bfd *, struct bfd_link_info *));
+extern boolean bfd_m68klinux_size_dynamic_sections
+  PARAMS ((bfd *, struct bfd_link_info *));
+extern boolean bfd_sparclinux_size_dynamic_sections
+  PARAMS ((bfd *, struct bfd_link_info *));
+
+/* mmap hacks */
+
+struct _bfd_window_internal;
+typedef struct _bfd_window_internal bfd_window_internal;
+
+typedef struct _bfd_window {
+  /* What the user asked for.  */
+  PTR data;
+  bfd_size_type size;
+  /* The actual window used by BFD.  Small user-requested read-only
+     regions sharing a page may share a single window into the object
+     file.  Read-write versions shouldn't until I've fixed things to
+     keep track of which portions have been claimed by the
+     application; don't want to give the same region back when the
+     application wants two writable copies!  */
+  struct _bfd_window_internal *i;
+} bfd_window;
+
+extern void bfd_init_window PARAMS ((bfd_window *));
+extern void bfd_free_window PARAMS ((bfd_window *));
+extern boolean bfd_get_file_window
+  PARAMS ((bfd *, file_ptr, bfd_size_type, bfd_window *, boolean));
+
+/* XCOFF support routines for the linker.  */
+
+extern boolean bfd_xcoff_link_record_set
+  PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *,
+	   bfd_size_type));
+extern boolean bfd_xcoff_import_symbol
+  PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *,
+	   bfd_vma, const char *, const char *, const char *, unsigned int));
+extern boolean bfd_xcoff_export_symbol
+  PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *));
+extern boolean bfd_xcoff_link_count_reloc
+  PARAMS ((bfd *, struct bfd_link_info *, const char *));
+extern boolean bfd_xcoff_record_link_assignment
+  PARAMS ((bfd *, struct bfd_link_info *, const char *));
+extern boolean bfd_xcoff_size_dynamic_sections
+  PARAMS ((bfd *, struct bfd_link_info *, const char *, const char *,
+	   unsigned long, unsigned long, unsigned long, boolean,
+	   int, boolean, boolean, struct sec **));
+
+/* Externally visible COFF routines.  */
+
+#if defined(__STDC__) || defined(ALMOST_STDC)
+struct internal_syment;
+union internal_auxent;
+#endif
+
+extern boolean bfd_coff_get_syment
+  PARAMS ((bfd *, struct symbol_cache_entry *, struct internal_syment *));
+
+extern boolean bfd_coff_get_auxent
+  PARAMS ((bfd *, struct symbol_cache_entry *, int, union internal_auxent *));
+
+extern boolean bfd_coff_set_symbol_class
+  PARAMS ((bfd *, struct symbol_cache_entry *, unsigned int));
+
+extern boolean bfd_m68k_coff_create_embedded_relocs
+  PARAMS ((bfd *, struct bfd_link_info *, struct sec *, struct sec *,
+	   char **));
+
+/* ARM Interworking support.  Called from linker.  */
+extern boolean bfd_arm_allocate_interworking_sections
+  PARAMS ((struct bfd_link_info *));
+
+extern boolean bfd_arm_process_before_allocation
+  PARAMS ((bfd *, struct bfd_link_info *, int));
+
+extern boolean bfd_arm_get_bfd_for_interworking
+  PARAMS ((bfd *, struct bfd_link_info *));
+
+/* PE ARM Interworking support.  Called from linker.  */
+extern boolean bfd_arm_pe_allocate_interworking_sections
+  PARAMS ((struct bfd_link_info *));
+
+extern boolean bfd_arm_pe_process_before_allocation
+  PARAMS ((bfd *, struct bfd_link_info *, int));
+
+extern boolean bfd_arm_pe_get_bfd_for_interworking
+  PARAMS ((bfd *, struct bfd_link_info *));
+
+/* ELF ARM Interworking support.  Called from linker.  */
+extern boolean bfd_elf32_arm_allocate_interworking_sections
+  PARAMS ((struct bfd_link_info *));
+
+extern boolean bfd_elf32_arm_process_before_allocation
+  PARAMS ((bfd *, struct bfd_link_info *, int));
+
+extern boolean bfd_elf32_arm_get_bfd_for_interworking
+  PARAMS ((bfd *, struct bfd_link_info *));
+
+/* TI COFF load page support.  */
+extern void bfd_ticoff_set_section_load_page
+  PARAMS ((struct sec *, int));
+
+extern int bfd_ticoff_get_section_load_page
+  PARAMS ((struct sec *));
+
+/* And more from the source.  */
+void
+bfd_init PARAMS ((void));
+
+bfd *
+bfd_openr PARAMS ((const char *filename, const char *target));
+
+bfd *
+bfd_fdopenr PARAMS ((const char *filename, const char *target, int fd));
+
+bfd *
+bfd_openstreamr PARAMS ((const char *, const char *, PTR));
+
+bfd *
+bfd_openw PARAMS ((const char *filename, const char *target));
+
+boolean
+bfd_close PARAMS ((bfd *abfd));
+
+boolean
+bfd_close_all_done PARAMS ((bfd *));
+
+bfd *
+bfd_create PARAMS ((const char *filename, bfd *templ));
+
+boolean
+bfd_make_writable PARAMS ((bfd *abfd));
+
+boolean
+bfd_make_readable PARAMS ((bfd *abfd));
+
+
+/* Byte swapping macros for user section data.  */
+
+#define bfd_put_8(abfd, val, ptr) \
+                ((void) (*((unsigned char *) (ptr)) = (unsigned char) (val)))
+#define bfd_put_signed_8 \
+               bfd_put_8
+#define bfd_get_8(abfd, ptr) \
+                (*(unsigned char *) (ptr) & 0xff)
+#define bfd_get_signed_8(abfd, ptr) \
+               (((*(unsigned char *) (ptr) & 0xff) ^ 0x80) - 0x80)
+
+#define bfd_put_16(abfd, val, ptr) \
+                BFD_SEND(abfd, bfd_putx16, ((val),(ptr)))
+#define bfd_put_signed_16 \
+                bfd_put_16
+#define bfd_get_16(abfd, ptr) \
+                BFD_SEND(abfd, bfd_getx16, (ptr))
+#define bfd_get_signed_16(abfd, ptr) \
+                BFD_SEND (abfd, bfd_getx_signed_16, (ptr))
+
+#define bfd_put_32(abfd, val, ptr) \
+                BFD_SEND(abfd, bfd_putx32, ((val),(ptr)))
+#define bfd_put_signed_32 \
+                bfd_put_32
+#define bfd_get_32(abfd, ptr) \
+                BFD_SEND(abfd, bfd_getx32, (ptr))
+#define bfd_get_signed_32(abfd, ptr) \
+                BFD_SEND(abfd, bfd_getx_signed_32, (ptr))
+
+#define bfd_put_64(abfd, val, ptr) \
+                BFD_SEND(abfd, bfd_putx64, ((val), (ptr)))
+#define bfd_put_signed_64 \
+                bfd_put_64
+#define bfd_get_64(abfd, ptr) \
+                BFD_SEND(abfd, bfd_getx64, (ptr))
+#define bfd_get_signed_64(abfd, ptr) \
+                BFD_SEND(abfd, bfd_getx_signed_64, (ptr))
+
+#define bfd_get(bits, abfd, ptr)                               \
+                ( (bits) ==  8 ? (bfd_vma) bfd_get_8 (abfd, ptr)       \
+                : (bits) == 16 ? bfd_get_16 (abfd, ptr)        \
+                : (bits) == 32 ? bfd_get_32 (abfd, ptr)        \
+                : (bits) == 64 ? bfd_get_64 (abfd, ptr)        \
+                : (abort (), (bfd_vma) - 1))
+
+#define bfd_put(bits, abfd, val, ptr)                          \
+                ( (bits) ==  8 ? bfd_put_8  (abfd, val, ptr)   \
+                : (bits) == 16 ? bfd_put_16 (abfd, val, ptr)   \
+                : (bits) == 32 ? bfd_put_32 (abfd, val, ptr)   \
+                : (bits) == 64 ? bfd_put_64 (abfd, val, ptr)   \
+                : (abort (), (void) 0))
+
+
+/* Byte swapping macros for file header data.  */
+
+#define bfd_h_put_8(abfd, val, ptr) \
+  bfd_put_8 (abfd, val, ptr)
+#define bfd_h_put_signed_8(abfd, val, ptr) \
+  bfd_put_8 (abfd, val, ptr)
+#define bfd_h_get_8(abfd, ptr) \
+  bfd_get_8 (abfd, ptr)
+#define bfd_h_get_signed_8(abfd, ptr) \
+  bfd_get_signed_8 (abfd, ptr)
+
+#define bfd_h_put_16(abfd, val, ptr) \
+  BFD_SEND (abfd, bfd_h_putx16, (val, ptr))
+#define bfd_h_put_signed_16 \
+  bfd_h_put_16
+#define bfd_h_get_16(abfd, ptr) \
+  BFD_SEND (abfd, bfd_h_getx16, (ptr))
+#define bfd_h_get_signed_16(abfd, ptr) \
+  BFD_SEND (abfd, bfd_h_getx_signed_16, (ptr))
+
+#define bfd_h_put_32(abfd, val, ptr) \
+  BFD_SEND (abfd, bfd_h_putx32, (val, ptr))
+#define bfd_h_put_signed_32 \
+  bfd_h_put_32
+#define bfd_h_get_32(abfd, ptr) \
+  BFD_SEND (abfd, bfd_h_getx32, (ptr))
+#define bfd_h_get_signed_32(abfd, ptr) \
+  BFD_SEND (abfd, bfd_h_getx_signed_32, (ptr))
+
+#define bfd_h_put_64(abfd, val, ptr) \
+  BFD_SEND (abfd, bfd_h_putx64, (val, ptr))
+#define bfd_h_put_signed_64 \
+  bfd_h_put_64
+#define bfd_h_get_64(abfd, ptr) \
+  BFD_SEND (abfd, bfd_h_getx64, (ptr))
+#define bfd_h_get_signed_64(abfd, ptr) \
+  BFD_SEND (abfd, bfd_h_getx_signed_64, (ptr))
+
+/* Refinements on the above, which should eventually go away.  Save
+   cluttering the source with (bfd_vma) and (bfd_byte *) casts.  */
+
+#define H_PUT_64(abfd, val, where) \
+  bfd_h_put_64 ((abfd), (bfd_vma) (val), (bfd_byte *) (where))
+
+#define H_PUT_32(abfd, val, where) \
+  bfd_h_put_32 ((abfd), (bfd_vma) (val), (bfd_byte *) (where))
+
+#define H_PUT_16(abfd, val, where) \
+  bfd_h_put_16 ((abfd), (bfd_vma) (val), (bfd_byte *) (where))
+
+#define H_PUT_8 bfd_h_put_8
+
+#define H_PUT_S64(abfd, val, where) \
+  bfd_h_put_signed_64 ((abfd), (bfd_vma) (val), (bfd_byte *) (where))
+
+#define H_PUT_S32(abfd, val, where) \
+  bfd_h_put_signed_32 ((abfd), (bfd_vma) (val), (bfd_byte *) (where))
+
+#define H_PUT_S16(abfd, val, where) \
+  bfd_h_put_signed_16 ((abfd), (bfd_vma) (val), (bfd_byte *) (where))
+
+#define H_PUT_S8 bfd_h_put_signed_8
+
+#define H_GET_64(abfd, where) \
+  bfd_h_get_64 ((abfd), (bfd_byte *) (where))
+
+#define H_GET_32(abfd, where) \
+  bfd_h_get_32 ((abfd), (bfd_byte *) (where))
+
+#define H_GET_16(abfd, where) \
+  bfd_h_get_16 ((abfd), (bfd_byte *) (where))
+
+#define H_GET_8 bfd_h_get_8
+
+#define H_GET_S64(abfd, where) \
+  bfd_h_get_signed_64 ((abfd), (bfd_byte *) (where))
+
+#define H_GET_S32(abfd, where) \
+  bfd_h_get_signed_32 ((abfd), (bfd_byte *) (where))
+
+#define H_GET_S16(abfd, where) \
+  bfd_h_get_signed_16 ((abfd), (bfd_byte *) (where))
+
+#define H_GET_S8 bfd_h_get_signed_8
+
+
+/* This structure is used for a comdat section, as in PE.  A comdat
+   section is associated with a particular symbol.  When the linker
+   sees a comdat section, it keeps only one of the sections with a
+   given name and associated with a given symbol.  */
+
+struct bfd_comdat_info
+{
+  /* The name of the symbol associated with a comdat section.  */
+  const char *name;
+
+  /* The local symbol table index of the symbol associated with a
+     comdat section.  This is only meaningful to the object file format
+     specific code; it is not an index into the list returned by
+     bfd_canonicalize_symtab.  */
+  long symbol;
+};
+
+typedef struct sec
+{
+  /* The name of the section; the name isn't a copy, the pointer is
+     the same as that passed to bfd_make_section.  */
+
+  const char *name;
+
+  /* A unique sequence number.  */
+
+  int id;
+
+  /* Which section in the bfd; 0..n-1 as sections are created in a bfd.  */
+
+  int index;
+
+  /* The next section in the list belonging to the BFD, or NULL.  */
+
+  struct sec *next;
+
+  /* The field flags contains attributes of the section. Some
+     flags are read in from the object file, and some are
+     synthesized from other information.  */
+
+  flagword flags;
+
+#define SEC_NO_FLAGS   0x000
+
+  /* Tells the OS to allocate space for this section when loading.
+     This is clear for a section containing debug information only.  */
+#define SEC_ALLOC      0x001
+
+  /* Tells the OS to load the section from the file when loading.
+     This is clear for a .bss section.  */
+#define SEC_LOAD       0x002
+
+  /* The section contains data still to be relocated, so there is
+     some relocation information too.  */
+#define SEC_RELOC      0x004
+
+  /* ELF reserves 4 processor specific bits and 8 operating system
+     specific bits in sh_flags; at present we can get away with just
+     one in communicating between the assembler and BFD, but this
+     isn't a good long-term solution.  */
+#define SEC_ARCH_BIT_0 0x008
+
+  /* A signal to the OS that the section contains read only data.  */
+#define SEC_READONLY   0x010
+
+  /* The section contains code only.  */
+#define SEC_CODE       0x020
+
+  /* The section contains data only.  */
+#define SEC_DATA       0x040
+
+  /* The section will reside in ROM.  */
+#define SEC_ROM        0x080
+
+  /* The section contains constructor information. This section
+     type is used by the linker to create lists of constructors and
+     destructors used by <<g++>>. When a back end sees a symbol
+     which should be used in a constructor list, it creates a new
+     section for the type of name (e.g., <<__CTOR_LIST__>>), attaches
+     the symbol to it, and builds a relocation. To build the lists
+     of constructors, all the linker has to do is catenate all the
+     sections called <<__CTOR_LIST__>> and relocate the data
+     contained within - exactly the operations it would peform on
+     standard data.  */
+#define SEC_CONSTRUCTOR 0x100
+
+  /* The section is a constructor, and should be placed at the
+     end of the text, data, or bss section(?).  */
+#define SEC_CONSTRUCTOR_TEXT 0x1100
+#define SEC_CONSTRUCTOR_DATA 0x2100
+#define SEC_CONSTRUCTOR_BSS  0x3100
+
+  /* The section has contents - a data section could be
+     <<SEC_ALLOC>> | <<SEC_HAS_CONTENTS>>; a debug section could be
+     <<SEC_HAS_CONTENTS>>  */
+#define SEC_HAS_CONTENTS 0x200
+
+  /* An instruction to the linker to not output the section
+     even if it has information which would normally be written.  */
+#define SEC_NEVER_LOAD 0x400
+
+  /* The section is a COFF shared library section.  This flag is
+     only for the linker.  If this type of section appears in
+     the input file, the linker must copy it to the output file
+     without changing the vma or size.  FIXME: Although this
+     was originally intended to be general, it really is COFF
+     specific (and the flag was renamed to indicate this).  It
+     might be cleaner to have some more general mechanism to
+     allow the back end to control what the linker does with
+     sections.  */
+#define SEC_COFF_SHARED_LIBRARY 0x800
+
+  /* The section has GOT references.  This flag is only for the
+     linker, and is currently only used by the elf32-hppa back end.
+     It will be set if global offset table references were detected
+     in this section, which indicate to the linker that the section
+     contains PIC code, and must be handled specially when doing a
+     static link.  */
+#define SEC_HAS_GOT_REF 0x4000
+
+  /* The section contains common symbols (symbols may be defined
+     multiple times, the value of a symbol is the amount of
+     space it requires, and the largest symbol value is the one
+     used).  Most targets have exactly one of these (which we
+     translate to bfd_com_section_ptr), but ECOFF has two.  */
+#define SEC_IS_COMMON 0x8000
+
+  /* The section contains only debugging information.  For
+     example, this is set for ELF .debug and .stab sections.
+     strip tests this flag to see if a section can be
+     discarded.  */
+#define SEC_DEBUGGING 0x10000
+
+  /* The contents of this section are held in memory pointed to
+     by the contents field.  This is checked by bfd_get_section_contents,
+     and the data is retrieved from memory if appropriate.  */
+#define SEC_IN_MEMORY 0x20000
+
+  /* The contents of this section are to be excluded by the
+     linker for executable and shared objects unless those
+     objects are to be further relocated.  */
+#define SEC_EXCLUDE 0x40000
+
+  /* The contents of this section are to be sorted based on the sum of
+     the symbol and addend values specified by the associated relocation
+     entries.  Entries without associated relocation entries will be
+     appended to the end of the section in an unspecified order.  */
+#define SEC_SORT_ENTRIES 0x80000
+
+  /* When linking, duplicate sections of the same name should be
+     discarded, rather than being combined into a single section as
+     is usually done.  This is similar to how common symbols are
+     handled.  See SEC_LINK_DUPLICATES below.  */
+#define SEC_LINK_ONCE 0x100000
+
+  /* If SEC_LINK_ONCE is set, this bitfield describes how the linker
+     should handle duplicate sections.  */
+#define SEC_LINK_DUPLICATES 0x600000
+
+  /* This value for SEC_LINK_DUPLICATES means that duplicate
+     sections with the same name should simply be discarded.  */
+#define SEC_LINK_DUPLICATES_DISCARD 0x0
+
+  /* This value for SEC_LINK_DUPLICATES means that the linker
+     should warn if there are any duplicate sections, although
+     it should still only link one copy.  */
+#define SEC_LINK_DUPLICATES_ONE_ONLY 0x200000
+
+  /* This value for SEC_LINK_DUPLICATES means that the linker
+     should warn if any duplicate sections are a different size.  */
+#define SEC_LINK_DUPLICATES_SAME_SIZE 0x400000
+
+  /* This value for SEC_LINK_DUPLICATES means that the linker
+     should warn if any duplicate sections contain different
+     contents.  */
+#define SEC_LINK_DUPLICATES_SAME_CONTENTS 0x600000
+
+  /* This section was created by the linker as part of dynamic
+     relocation or other arcane processing.  It is skipped when
+     going through the first-pass output, trusting that someone
+     else up the line will take care of it later.  */
+#define SEC_LINKER_CREATED 0x800000
+
+  /* This section should not be subject to garbage collection.  */
+#define SEC_KEEP 0x1000000
+
+  /* This section contains "short" data, and should be placed
+     "near" the GP.  */
+#define SEC_SMALL_DATA 0x2000000
+
+  /* This section contains data which may be shared with other
+     executables or shared objects.  */
+#define SEC_SHARED 0x4000000
+
+  /* When a section with this flag is being linked, then if the size of
+     the input section is less than a page, it should not cross a page
+     boundary.  If the size of the input section is one page or more, it
+     should be aligned on a page boundary.  */
+#define SEC_BLOCK 0x8000000
+
+  /* Conditionally link this section; do not link if there are no
+     references found to any symbol in the section.  */
+#define SEC_CLINK 0x10000000
+
+  /* Attempt to merge identical entities in the section.
+     Entity size is given in the entsize field.  */
+#define SEC_MERGE 0x20000000
+
+  /* If given with SEC_MERGE, entities to merge are zero terminated
+     strings where entsize specifies character size instead of fixed
+     size entries.  */
+#define SEC_STRINGS 0x40000000
+
+  /* This section contains data about section groups.  */
+#define SEC_GROUP 0x80000000
+
+  /*  End of section flags.  */
+
+  /* Some internal packed boolean fields.  */
+
+  /* See the vma field.  */
+  unsigned int user_set_vma : 1;
+
+  /* Whether relocations have been processed.  */
+  unsigned int reloc_done : 1;
+
+  /* A mark flag used by some of the linker backends.  */
+  unsigned int linker_mark : 1;
+
+  /* Another mark flag used by some of the linker backends.  Set for
+     output sections that have an input section.  */
+  unsigned int linker_has_input : 1;
+
+  /* A mark flag used by some linker backends for garbage collection.  */
+  unsigned int gc_mark : 1;
+
+  /* Used by the ELF code to mark sections which have been allocated
+     to segments.  */
+  unsigned int segment_mark : 1;
+
+  /* End of internal packed boolean fields.  */
+
+  /*  The virtual memory address of the section - where it will be
+      at run time.  The symbols are relocated against this.  The
+      user_set_vma flag is maintained by bfd; if it's not set, the
+      backend can assign addresses (for example, in <<a.out>>, where
+      the default address for <<.data>> is dependent on the specific
+      target and various flags).  */
+
+  bfd_vma vma;
+
+  /*  The load address of the section - where it would be in a
+      rom image; really only used for writing section header
+      information. */
+
+  bfd_vma lma;
+
+  /* The size of the section in octets, as it will be output.
+     Contains a value even if the section has no contents (e.g., the
+     size of <<.bss>>).  This will be filled in after relocation.  */
+
+  bfd_size_type _cooked_size;
+
+  /* The original size on disk of the section, in octets.  Normally this
+     value is the same as the size, but if some relaxing has
+     been done, then this value will be bigger.  */
+
+  bfd_size_type _raw_size;
+
+  /* If this section is going to be output, then this value is the
+     offset in *bytes* into the output section of the first byte in the
+     input section (byte ==> smallest addressable unit on the
+     target).  In most cases, if this was going to start at the
+     100th octet (8-bit quantity) in the output section, this value
+     would be 100.  However, if the target byte size is 16 bits
+     (bfd_octets_per_byte is "2"), this value would be 50.  */
+
+  bfd_vma output_offset;
+
+  /* The output section through which to map on output.  */
+
+  struct sec *output_section;
+
+  /* The alignment requirement of the section, as an exponent of 2 -
+     e.g., 3 aligns to 2^3 (or 8).  */
+
+  unsigned int alignment_power;
+
+  /* If an input section, a pointer to a vector of relocation
+     records for the data in this section.  */
+
+  struct reloc_cache_entry *relocation;
+
+  /* If an output section, a pointer to a vector of pointers to
+     relocation records for the data in this section.  */
+
+  struct reloc_cache_entry **orelocation;
+
+  /* The number of relocation records in one of the above  */
+
+  unsigned reloc_count;
+
+  /* Information below is back end specific - and not always used
+     or updated.  */
+
+  /* File position of section data.  */
+
+  file_ptr filepos;
+
+  /* File position of relocation info.  */
+
+  file_ptr rel_filepos;
+
+  /* File position of line data.  */
+
+  file_ptr line_filepos;
+
+  /* Pointer to data for applications.  */
+
+  PTR userdata;
+
+  /* If the SEC_IN_MEMORY flag is set, this points to the actual
+     contents.  */
+  unsigned char *contents;
+
+  /* Attached line number information.  */
+
+  alent *lineno;
+
+  /* Number of line number records.  */
+
+  unsigned int lineno_count;
+
+  /* Entity size for merging purposes.  */
+
+  unsigned int entsize;
+
+  /* Optional information about a COMDAT entry; NULL if not COMDAT.  */
+
+  struct bfd_comdat_info *comdat;
+
+  /* When a section is being output, this value changes as more
+     linenumbers are written out.  */
+
+  file_ptr moving_line_filepos;
+
+  /* What the section number is in the target world.  */
+
+  int target_index;
+
+  PTR used_by_bfd;
+
+  /* If this is a constructor section then here is a list of the
+     relocations created to relocate items within it.  */
+
+  struct relent_chain *constructor_chain;
+
+  /* The BFD which owns the section.  */
+
+  bfd *owner;
+
+  /* A symbol which points at this section only */
+  struct symbol_cache_entry *symbol;
+  struct symbol_cache_entry **symbol_ptr_ptr;
+
+  struct bfd_link_order *link_order_head;
+  struct bfd_link_order *link_order_tail;
+} asection ;
+
+/* These sections are global, and are managed by BFD.  The application
+   and target back end are not permitted to change the values in
+   these sections.  New code should use the section_ptr macros rather
+   than referring directly to the const sections.  The const sections
+   may eventually vanish.  */
+#define BFD_ABS_SECTION_NAME "*ABS*"
+#define BFD_UND_SECTION_NAME "*UND*"
+#define BFD_COM_SECTION_NAME "*COM*"
+#define BFD_IND_SECTION_NAME "*IND*"
+
+/* the absolute section */
+extern const asection bfd_abs_section;
+#define bfd_abs_section_ptr ((asection *) &bfd_abs_section)
+#define bfd_is_abs_section(sec) ((sec) == bfd_abs_section_ptr)
+/* Pointer to the undefined section */
+extern const asection bfd_und_section;
+#define bfd_und_section_ptr ((asection *) &bfd_und_section)
+#define bfd_is_und_section(sec) ((sec) == bfd_und_section_ptr)
+/* Pointer to the common section */
+extern const asection bfd_com_section;
+#define bfd_com_section_ptr ((asection *) &bfd_com_section)
+/* Pointer to the indirect section */
+extern const asection bfd_ind_section;
+#define bfd_ind_section_ptr ((asection *) &bfd_ind_section)
+#define bfd_is_ind_section(sec) ((sec) == bfd_ind_section_ptr)
+
+extern const struct symbol_cache_entry * const bfd_abs_symbol;
+extern const struct symbol_cache_entry * const bfd_com_symbol;
+extern const struct symbol_cache_entry * const bfd_und_symbol;
+extern const struct symbol_cache_entry * const bfd_ind_symbol;
+#define bfd_get_section_size_before_reloc(section) \
+     ((section)->reloc_done ? (abort (), (bfd_size_type) 1) \
+                            : (section)->_raw_size)
+#define bfd_get_section_size_after_reloc(section) \
+     ((section)->reloc_done ? (section)->_cooked_size \
+                            : (abort (), (bfd_size_type) 1))
+asection *
+bfd_get_section_by_name PARAMS ((bfd *abfd, const char *name));
+
+char *
+bfd_get_unique_section_name PARAMS ((bfd *abfd,
+    const char *templat,
+    int *count));
+
+asection *
+bfd_make_section_old_way PARAMS ((bfd *abfd, const char *name));
+
+asection *
+bfd_make_section_anyway PARAMS ((bfd *abfd, const char *name));
+
+asection *
+bfd_make_section PARAMS ((bfd *, const char *name));
+
+boolean
+bfd_set_section_flags PARAMS ((bfd *abfd, asection *sec, flagword flags));
+
+void
+bfd_map_over_sections PARAMS ((bfd *abfd,
+    void (*func) (bfd *abfd,
+    asection *sect,
+    PTR obj),
+    PTR obj));
+
+boolean
+bfd_set_section_size PARAMS ((bfd *abfd, asection *sec, bfd_size_type val));
+
+boolean
+bfd_set_section_contents PARAMS ((bfd *abfd, asection *section,
+    PTR data, file_ptr offset,
+    bfd_size_type count));
+
+boolean
+bfd_get_section_contents PARAMS ((bfd *abfd, asection *section,
+    PTR location, file_ptr offset,
+    bfd_size_type count));
+
+boolean
+bfd_copy_private_section_data PARAMS ((bfd *ibfd, asection *isec,
+    bfd *obfd, asection *osec));
+
+#define bfd_copy_private_section_data(ibfd, isection, obfd, osection) \
+     BFD_SEND (obfd, _bfd_copy_private_section_data, \
+               (ibfd, isection, obfd, osection))
+void
+_bfd_strip_section_from_output PARAMS ((struct bfd_link_info *info, asection *section));
+
+enum bfd_architecture
+{
+  bfd_arch_unknown,   /* File arch not known */
+  bfd_arch_obscure,   /* Arch known, not one of these */
+  bfd_arch_m68k,      /* Motorola 68xxx */
+#define bfd_mach_m68000 1
+#define bfd_mach_m68008 2
+#define bfd_mach_m68010 3
+#define bfd_mach_m68020 4
+#define bfd_mach_m68030 5
+#define bfd_mach_m68040 6
+#define bfd_mach_m68060 7
+#define bfd_mach_cpu32  8
+#define bfd_mach_mcf5200  9
+#define bfd_mach_mcf5206e 10
+#define bfd_mach_mcf5307  11
+#define bfd_mach_mcf5407  12
+  bfd_arch_vax,       /* DEC Vax */
+  bfd_arch_i960,      /* Intel 960 */
+    /* The order of the following is important.
+       lower number indicates a machine type that
+       only accepts a subset of the instructions
+       available to machines with higher numbers.
+       The exception is the "ca", which is
+       incompatible with all other machines except
+       "core". */
+
+#define bfd_mach_i960_core      1
+#define bfd_mach_i960_ka_sa     2
+#define bfd_mach_i960_kb_sb     3
+#define bfd_mach_i960_mc        4
+#define bfd_mach_i960_xa        5
+#define bfd_mach_i960_ca        6
+#define bfd_mach_i960_jx        7
+#define bfd_mach_i960_hx        8
+
+  bfd_arch_a29k,      /* AMD 29000 */
+  bfd_arch_sparc,     /* SPARC */
+#define bfd_mach_sparc                 1
+/* The difference between v8plus and v9 is that v9 is a true 64 bit env.  */
+#define bfd_mach_sparc_sparclet        2
+#define bfd_mach_sparc_sparclite       3
+#define bfd_mach_sparc_v8plus          4
+#define bfd_mach_sparc_v8plusa         5 /* with ultrasparc add'ns */
+#define bfd_mach_sparc_sparclite_le    6
+#define bfd_mach_sparc_v9              7
+#define bfd_mach_sparc_v9a             8 /* with ultrasparc add'ns */
+#define bfd_mach_sparc_v8plusb         9 /* with cheetah add'ns */
+#define bfd_mach_sparc_v9b             10 /* with cheetah add'ns */
+/* Nonzero if MACH has the v9 instruction set.  */
+#define bfd_mach_sparc_v9_p(mach) \
+  ((mach) >= bfd_mach_sparc_v8plus && (mach) <= bfd_mach_sparc_v9b \
+   && (mach) != bfd_mach_sparc_sparclite_le)
+  bfd_arch_mips,      /* MIPS Rxxxx */
+#define bfd_mach_mips3000              3000
+#define bfd_mach_mips3900              3900
+#define bfd_mach_mips4000              4000
+#define bfd_mach_mips4010              4010
+#define bfd_mach_mips4100              4100
+#define bfd_mach_mips4111              4111
+#define bfd_mach_mips4300              4300
+#define bfd_mach_mips4400              4400
+#define bfd_mach_mips4600              4600
+#define bfd_mach_mips4650              4650
+#define bfd_mach_mips5000              5000
+#define bfd_mach_mips6000              6000
+#define bfd_mach_mips8000              8000
+#define bfd_mach_mips10000             10000
+#define bfd_mach_mips12000             12000
+#define bfd_mach_mips16                16
+#define bfd_mach_mips5                 5
+#define bfd_mach_mips_sb1              12310201 /* octal 'SB', 01 */
+#define bfd_mach_mipsisa32             32
+#define bfd_mach_mipsisa64             64
+  bfd_arch_i386,      /* Intel 386 */
+#define bfd_mach_i386_i386 0
+#define bfd_mach_i386_i8086 1
+#define bfd_mach_i386_i386_intel_syntax 2
+#define bfd_mach_x86_64 3
+#define bfd_mach_x86_64_intel_syntax 4
+  bfd_arch_we32k,     /* AT&T WE32xxx */
+  bfd_arch_tahoe,     /* CCI/Harris Tahoe */
+  bfd_arch_i860,      /* Intel 860 */
+  bfd_arch_i370,      /* IBM 360/370 Mainframes */
+  bfd_arch_romp,      /* IBM ROMP PC/RT */
+  bfd_arch_alliant,   /* Alliant */
+  bfd_arch_convex,    /* Convex */
+  bfd_arch_m88k,      /* Motorola 88xxx */
+  bfd_arch_pyramid,   /* Pyramid Technology */
+  bfd_arch_h8300,     /* Hitachi H8/300 */
+#define bfd_mach_h8300   1
+#define bfd_mach_h8300h  2
+#define bfd_mach_h8300s  3
+  bfd_arch_pdp11,     /* DEC PDP-11 */
+  bfd_arch_powerpc,   /* PowerPC */
+#define bfd_mach_ppc           0
+#define bfd_mach_ppc_403       403
+#define bfd_mach_ppc_403gc     4030
+#define bfd_mach_ppc_505       505
+#define bfd_mach_ppc_601       601
+#define bfd_mach_ppc_602       602
+#define bfd_mach_ppc_603       603
+#define bfd_mach_ppc_ec603e    6031
+#define bfd_mach_ppc_604       604
+#define bfd_mach_ppc_620       620
+#define bfd_mach_ppc_630       630
+#define bfd_mach_ppc_750       750
+#define bfd_mach_ppc_860       860
+#define bfd_mach_ppc_a35       35
+#define bfd_mach_ppc_rs64ii    642
+#define bfd_mach_ppc_rs64iii   643
+#define bfd_mach_ppc_7400      7400
+  bfd_arch_rs6000,    /* IBM RS/6000 */
+#define bfd_mach_rs6k          0
+#define bfd_mach_rs6k_rs1      6001
+#define bfd_mach_rs6k_rsc      6003
+#define bfd_mach_rs6k_rs2      6002
+  bfd_arch_hppa,      /* HP PA RISC */
+  bfd_arch_d10v,      /* Mitsubishi D10V */
+#define bfd_mach_d10v          0
+#define bfd_mach_d10v_ts2      2
+#define bfd_mach_d10v_ts3      3
+  bfd_arch_d30v,      /* Mitsubishi D30V */
+  bfd_arch_m68hc11,   /* Motorola 68HC11 */
+  bfd_arch_m68hc12,   /* Motorola 68HC12 */
+  bfd_arch_z8k,       /* Zilog Z8000 */
+#define bfd_mach_z8001         1
+#define bfd_mach_z8002         2
+  bfd_arch_h8500,     /* Hitachi H8/500 */
+  bfd_arch_sh,        /* Hitachi SH */
+#define bfd_mach_sh            0
+#define bfd_mach_sh2        0x20
+#define bfd_mach_sh_dsp     0x2d
+#define bfd_mach_sh3        0x30
+#define bfd_mach_sh3_dsp    0x3d
+#define bfd_mach_sh3e       0x3e
+#define bfd_mach_sh4        0x40
+  bfd_arch_alpha,     /* Dec Alpha */
+#define bfd_mach_alpha_ev4  0x10
+#define bfd_mach_alpha_ev5  0x20
+#define bfd_mach_alpha_ev6  0x30
+  bfd_arch_arm,       /* Advanced Risc Machines ARM */
+#define bfd_mach_arm_2         1
+#define bfd_mach_arm_2a        2
+#define bfd_mach_arm_3         3
+#define bfd_mach_arm_3M        4
+#define bfd_mach_arm_4         5
+#define bfd_mach_arm_4T        6
+#define bfd_mach_arm_5         7
+#define bfd_mach_arm_5T        8
+#define bfd_mach_arm_5TE       9
+#define bfd_mach_arm_XScale    10
+  bfd_arch_ns32k,     /* National Semiconductors ns32000 */
+  bfd_arch_w65,       /* WDC 65816 */
+  bfd_arch_tic30,     /* Texas Instruments TMS320C30 */
+  bfd_arch_tic54x,    /* Texas Instruments TMS320C54X */
+  bfd_arch_tic80,     /* TI TMS320c80 (MVP) */
+  bfd_arch_v850,      /* NEC V850 */
+#define bfd_mach_v850          0
+#define bfd_mach_v850e         'E'
+#define bfd_mach_v850ea        'A'
+  bfd_arch_arc,       /* ARC Cores */
+#define bfd_mach_arc_5         0
+#define bfd_mach_arc_6         1
+#define bfd_mach_arc_7         2
+#define bfd_mach_arc_8         3
+  bfd_arch_m32r,      /* Mitsubishi M32R/D */
+#define bfd_mach_m32r          0 /* backwards compatibility */
+#define bfd_mach_m32rx         'x'
+  bfd_arch_mn10200,   /* Matsushita MN10200 */
+  bfd_arch_mn10300,   /* Matsushita MN10300 */
+#define bfd_mach_mn10300               300
+#define bfd_mach_am33          330
+  bfd_arch_fr30,
+#define bfd_mach_fr30          0x46523330
+  bfd_arch_mcore,
+  bfd_arch_ia64,      /* HP/Intel ia64 */
+#define bfd_mach_ia64_elf64    0
+#define bfd_mach_ia64_elf32    1
+  bfd_arch_pj,
+  bfd_arch_avr,       /* Atmel AVR microcontrollers */
+#define bfd_mach_avr1          1
+#define bfd_mach_avr2          2
+#define bfd_mach_avr3          3
+#define bfd_mach_avr4          4
+#define bfd_mach_avr5          5
+  bfd_arch_cris,      /* Axis CRIS */
+  bfd_arch_s390,      /* IBM s390 */
+#define bfd_mach_s390_esa      0
+#define bfd_mach_s390_esame    1
+  bfd_arch_openrisc,  /* OpenRISC */
+  bfd_arch_last
+  };
+
+typedef struct bfd_arch_info
+{
+  int bits_per_word;
+  int bits_per_address;
+  int bits_per_byte;
+  enum bfd_architecture arch;
+  unsigned long mach;
+  const char *arch_name;
+  const char *printable_name;
+  unsigned int section_align_power;
+  /* True if this is the default machine for the architecture.  */
+  boolean the_default;
+  const struct bfd_arch_info * (*compatible)
+       PARAMS ((const struct bfd_arch_info *a,
+                const struct bfd_arch_info *b));
+
+  boolean (*scan) PARAMS ((const struct bfd_arch_info *, const char *));
+
+  const struct bfd_arch_info *next;
+} bfd_arch_info_type;
+const char *
+bfd_printable_name PARAMS ((bfd *abfd));
+
+const bfd_arch_info_type *
+bfd_scan_arch PARAMS ((const char *string));
+
+const char **
+bfd_arch_list PARAMS ((void));
+
+const bfd_arch_info_type *
+bfd_arch_get_compatible PARAMS ((
+    const bfd *abfd,
+    const bfd *bbfd));
+
+void
+bfd_set_arch_info PARAMS ((bfd *abfd, const bfd_arch_info_type *arg));
+
+enum bfd_architecture
+bfd_get_arch PARAMS ((bfd *abfd));
+
+unsigned long
+bfd_get_mach PARAMS ((bfd *abfd));
+
+unsigned int
+bfd_arch_bits_per_byte PARAMS ((bfd *abfd));
+
+unsigned int
+bfd_arch_bits_per_address PARAMS ((bfd *abfd));
+
+const bfd_arch_info_type *
+bfd_get_arch_info PARAMS ((bfd *abfd));
+
+const bfd_arch_info_type *
+bfd_lookup_arch PARAMS ((enum bfd_architecture
+    arch,
+    unsigned long machine));
+
+const char *
+bfd_printable_arch_mach PARAMS ((enum bfd_architecture arch, unsigned long machine));
+
+unsigned int
+bfd_octets_per_byte PARAMS ((bfd *abfd));
+
+unsigned int
+bfd_arch_mach_octets_per_byte PARAMS ((enum bfd_architecture arch,
+    unsigned long machine));
+
+typedef enum bfd_reloc_status
+{
+  /* No errors detected */
+  bfd_reloc_ok,
+
+  /* The relocation was performed, but there was an overflow. */
+  bfd_reloc_overflow,
+
+  /* The address to relocate was not within the section supplied. */
+  bfd_reloc_outofrange,
+
+  /* Used by special functions */
+  bfd_reloc_continue,
+
+  /* Unsupported relocation size requested. */
+  bfd_reloc_notsupported,
+
+  /* Unused */
+  bfd_reloc_other,
+
+  /* The symbol to relocate against was undefined. */
+  bfd_reloc_undefined,
+
+  /* The relocation was performed, but may not be ok - presently
+     generated only when linking i960 coff files with i960 b.out
+     symbols.  If this type is returned, the error_message argument
+     to bfd_perform_relocation will be set.  */
+  bfd_reloc_dangerous
+ }
+ bfd_reloc_status_type;
+
+
+typedef struct reloc_cache_entry
+{
+  /* A pointer into the canonical table of pointers  */
+  struct symbol_cache_entry **sym_ptr_ptr;
+
+  /* offset in section */
+  bfd_size_type address;
+
+  /* addend for relocation value */
+  bfd_vma addend;
+
+  /* Pointer to how to perform the required relocation */
+  reloc_howto_type *howto;
+
+} arelent;
+enum complain_overflow
+{
+  /* Do not complain on overflow. */
+  complain_overflow_dont,
+
+  /* Complain if the bitfield overflows, whether it is considered
+     as signed or unsigned. */
+  complain_overflow_bitfield,
+
+  /* Complain if the value overflows when considered as signed
+     number. */
+  complain_overflow_signed,
+
+  /* Complain if the value overflows when considered as an
+     unsigned number. */
+  complain_overflow_unsigned
+};
+
+struct reloc_howto_struct
+{
+  /*  The type field has mainly a documentary use - the back end can
+      do what it wants with it, though normally the back end's
+      external idea of what a reloc number is stored
+      in this field.  For example, a PC relative word relocation
+      in a coff environment has the type 023 - because that's
+      what the outside world calls a R_PCRWORD reloc.  */
+  unsigned int type;
+
+  /*  The value the final relocation is shifted right by.  This drops
+      unwanted data from the relocation.  */
+  unsigned int rightshift;
+
+  /*  The size of the item to be relocated.  This is *not* a
+      power-of-two measure.  To get the number of bytes operated
+      on by a type of relocation, use bfd_get_reloc_size.  */
+  int size;
+
+  /*  The number of bits in the item to be relocated.  This is used
+      when doing overflow checking.  */
+  unsigned int bitsize;
+
+  /*  Notes that the relocation is relative to the location in the
+      data section of the addend.  The relocation function will
+      subtract from the relocation value the address of the location
+      being relocated.  */
+  boolean pc_relative;
+
+  /*  The bit position of the reloc value in the destination.
+      The relocated value is left shifted by this amount.  */
+  unsigned int bitpos;
+
+  /* What type of overflow error should be checked for when
+     relocating.  */
+  enum complain_overflow complain_on_overflow;
+
+  /* If this field is non null, then the supplied function is
+     called rather than the normal function.  This allows really
+     strange relocation methods to be accomodated (e.g., i960 callj
+     instructions).  */
+  bfd_reloc_status_type (*special_function)
+    PARAMS ((bfd *, arelent *, struct symbol_cache_entry *, PTR, asection *,
+             bfd *, char **));
+
+  /* The textual name of the relocation type.  */
+  char *name;
+
+  /* Some formats record a relocation addend in the section contents
+     rather than with the relocation.  For ELF formats this is the
+     distinction between USE_REL and USE_RELA (though the code checks
+     for USE_REL == 1/0).  The value of this field is TRUE if the
+     addend is recorded with the section contents; when performing a
+     partial link (ld -r) the section contents (the data) will be
+     modified.  The value of this field is FALSE if addends are
+     recorded with the relocation (in arelent.addend); when performing
+     a partial link the relocation will be modified.
+     All relocations for all ELF USE_RELA targets should set this field
+     to FALSE (values of TRUE should be looked on with suspicion).
+     However, the converse is not true: not all relocations of all ELF
+     USE_REL targets set this field to TRUE.  Why this is so is peculiar
+     to each particular target.  For relocs that aren't used in partial
+     links (e.g. GOT stuff) it doesn't matter what this is set to.  */
+  boolean partial_inplace;
+
+  /* The src_mask selects which parts of the read in data
+     are to be used in the relocation sum.  E.g., if this was an 8 bit
+     byte of data which we read and relocated, this would be
+     0x000000ff.  When we have relocs which have an addend, such as
+     sun4 extended relocs, the value in the offset part of a
+     relocating field is garbage so we never use it.  In this case
+     the mask would be 0x00000000.  */
+  bfd_vma src_mask;
+
+  /* The dst_mask selects which parts of the instruction are replaced
+     into the instruction.  In most cases src_mask == dst_mask,
+     except in the above special case, where dst_mask would be
+     0x000000ff, and src_mask would be 0x00000000.  */
+  bfd_vma dst_mask;
+
+  /* When some formats create PC relative instructions, they leave
+     the value of the pc of the place being relocated in the offset
+     slot of the instruction, so that a PC relative relocation can
+     be made just by adding in an ordinary offset (e.g., sun3 a.out).
+     Some formats leave the displacement part of an instruction
+     empty (e.g., m88k bcs); this flag signals the fact.  */
+  boolean pcrel_offset;
+};
+#define HOWTO(C, R, S, B, P, BI, O, SF, NAME, INPLACE, MASKSRC, MASKDST, PC) \
+  { (unsigned) C, R, S, B, P, BI, O, SF, NAME, INPLACE, MASKSRC, MASKDST, PC }
+#define NEWHOWTO(FUNCTION, NAME, SIZE, REL, IN) \
+  HOWTO (0, 0, SIZE, 0, REL, 0, complain_overflow_dont, FUNCTION, \
+         NAME, false, 0, 0, IN)
+
+#define EMPTY_HOWTO(C) \
+  HOWTO ((C), 0, 0, 0, false, 0, complain_overflow_dont, NULL, \
+         NULL, false, 0, 0, false)
+
+#define HOWTO_PREPARE(relocation, symbol)               \
+  {                                                     \
+    if (symbol != (asymbol *) NULL)                     \
+      {                                                 \
+        if (bfd_is_com_section (symbol->section))       \
+          {                                             \
+            relocation = 0;                             \
+          }                                             \
+        else                                            \
+          {                                             \
+            relocation = symbol->value;                 \
+          }                                             \
+      }                                                 \
+  }
+unsigned int
+bfd_get_reloc_size PARAMS ((reloc_howto_type *));
+
+typedef struct relent_chain
+{
+  arelent relent;
+  struct relent_chain *next;
+} arelent_chain;
+bfd_reloc_status_type
+bfd_check_overflow PARAMS ((enum complain_overflow how,
+    unsigned int bitsize,
+    unsigned int rightshift,
+    unsigned int addrsize,
+    bfd_vma relocation));
+
+bfd_reloc_status_type
+bfd_perform_relocation PARAMS ((bfd *abfd,
+    arelent *reloc_entry,
+    PTR data,
+    asection *input_section,
+    bfd *output_bfd,
+    char **error_message));
+
+bfd_reloc_status_type
+bfd_install_relocation PARAMS ((bfd *abfd,
+    arelent *reloc_entry,
+    PTR data, bfd_vma data_start,
+    asection *input_section,
+    char **error_message));
+
+enum bfd_reloc_code_real {
+  _dummy_first_bfd_reloc_code_real,
+
+
+/* Basic absolute relocations of N bits. */
+  BFD_RELOC_64,
+  BFD_RELOC_32,
+  BFD_RELOC_26,
+  BFD_RELOC_24,
+  BFD_RELOC_16,
+  BFD_RELOC_14,
+  BFD_RELOC_8,
+
+/* PC-relative relocations.  Sometimes these are relative to the address
+of the relocation itself; sometimes they are relative to the start of
+the section containing the relocation.  It depends on the specific target.
+
+The 24-bit relocation is used in some Intel 960 configurations. */
+  BFD_RELOC_64_PCREL,
+  BFD_RELOC_32_PCREL,
+  BFD_RELOC_24_PCREL,
+  BFD_RELOC_16_PCREL,
+  BFD_RELOC_12_PCREL,
+  BFD_RELOC_8_PCREL,
+
+/* For ELF. */
+  BFD_RELOC_32_GOT_PCREL,
+  BFD_RELOC_16_GOT_PCREL,
+  BFD_RELOC_8_GOT_PCREL,
+  BFD_RELOC_32_GOTOFF,
+  BFD_RELOC_16_GOTOFF,
+  BFD_RELOC_LO16_GOTOFF,
+  BFD_RELOC_HI16_GOTOFF,
+  BFD_RELOC_HI16_S_GOTOFF,
+  BFD_RELOC_8_GOTOFF,
+  BFD_RELOC_64_PLT_PCREL,
+  BFD_RELOC_32_PLT_PCREL,
+  BFD_RELOC_24_PLT_PCREL,
+  BFD_RELOC_16_PLT_PCREL,
+  BFD_RELOC_8_PLT_PCREL,
+  BFD_RELOC_64_PLTOFF,
+  BFD_RELOC_32_PLTOFF,
+  BFD_RELOC_16_PLTOFF,
+  BFD_RELOC_LO16_PLTOFF,
+  BFD_RELOC_HI16_PLTOFF,
+  BFD_RELOC_HI16_S_PLTOFF,
+  BFD_RELOC_8_PLTOFF,
+
+/* Relocations used by 68K ELF. */
+  BFD_RELOC_68K_GLOB_DAT,
+  BFD_RELOC_68K_JMP_SLOT,
+  BFD_RELOC_68K_RELATIVE,
+
+/* Linkage-table relative. */
+  BFD_RELOC_32_BASEREL,
+  BFD_RELOC_16_BASEREL,
+  BFD_RELOC_LO16_BASEREL,
+  BFD_RELOC_HI16_BASEREL,
+  BFD_RELOC_HI16_S_BASEREL,
+  BFD_RELOC_8_BASEREL,
+  BFD_RELOC_RVA,
+
+/* Absolute 8-bit relocation, but used to form an address like 0xFFnn. */
+  BFD_RELOC_8_FFnn,
+
+/* These PC-relative relocations are stored as word displacements --
+i.e., byte displacements shifted right two bits.  The 30-bit word
+displacement (<<32_PCREL_S2>> -- 32 bits, shifted 2) is used on the
+SPARC.  (SPARC tools generally refer to this as <<WDISP30>>.)  The
+signed 16-bit displacement is used on the MIPS, and the 23-bit
+displacement is used on the Alpha. */
+  BFD_RELOC_32_PCREL_S2,
+  BFD_RELOC_16_PCREL_S2,
+  BFD_RELOC_23_PCREL_S2,
+
+/* High 22 bits and low 10 bits of 32-bit value, placed into lower bits of
+the target word.  These are used on the SPARC. */
+  BFD_RELOC_HI22,
+  BFD_RELOC_LO10,
+
+/* For systems that allocate a Global Pointer register, these are
+displacements off that register.  These relocation types are
+handled specially, because the value the register will have is
+decided relatively late. */
+  BFD_RELOC_GPREL16,
+  BFD_RELOC_GPREL32,
+
+/* Reloc types used for i960/b.out. */
+  BFD_RELOC_I960_CALLJ,
+
+/* SPARC ELF relocations.  There is probably some overlap with other
+relocation types already defined. */
+  BFD_RELOC_NONE,
+  BFD_RELOC_SPARC_WDISP22,
+  BFD_RELOC_SPARC22,
+  BFD_RELOC_SPARC13,
+  BFD_RELOC_SPARC_GOT10,
+  BFD_RELOC_SPARC_GOT13,
+  BFD_RELOC_SPARC_GOT22,
+  BFD_RELOC_SPARC_PC10,
+  BFD_RELOC_SPARC_PC22,
+  BFD_RELOC_SPARC_WPLT30,
+  BFD_RELOC_SPARC_COPY,
+  BFD_RELOC_SPARC_GLOB_DAT,
+  BFD_RELOC_SPARC_JMP_SLOT,
+  BFD_RELOC_SPARC_RELATIVE,
+  BFD_RELOC_SPARC_UA16,
+  BFD_RELOC_SPARC_UA32,
+  BFD_RELOC_SPARC_UA64,
+
+/* I think these are specific to SPARC a.out (e.g., Sun 4). */
+  BFD_RELOC_SPARC_BASE13,
+  BFD_RELOC_SPARC_BASE22,
+
+/* SPARC64 relocations */
+#define BFD_RELOC_SPARC_64 BFD_RELOC_64
+  BFD_RELOC_SPARC_10,
+  BFD_RELOC_SPARC_11,
+  BFD_RELOC_SPARC_OLO10,
+  BFD_RELOC_SPARC_HH22,
+  BFD_RELOC_SPARC_HM10,
+  BFD_RELOC_SPARC_LM22,
+  BFD_RELOC_SPARC_PC_HH22,
+  BFD_RELOC_SPARC_PC_HM10,
+  BFD_RELOC_SPARC_PC_LM22,
+  BFD_RELOC_SPARC_WDISP16,
+  BFD_RELOC_SPARC_WDISP19,
+  BFD_RELOC_SPARC_7,
+  BFD_RELOC_SPARC_6,
+  BFD_RELOC_SPARC_5,
+#define BFD_RELOC_SPARC_DISP64 BFD_RELOC_64_PCREL
+  BFD_RELOC_SPARC_PLT64,
+  BFD_RELOC_SPARC_HIX22,
+  BFD_RELOC_SPARC_LOX10,
+  BFD_RELOC_SPARC_H44,
+  BFD_RELOC_SPARC_M44,
+  BFD_RELOC_SPARC_L44,
+  BFD_RELOC_SPARC_REGISTER,
+
+/* SPARC little endian relocation */
+  BFD_RELOC_SPARC_REV32,
+
+/* Alpha ECOFF and ELF relocations.  Some of these treat the symbol or
+"addend" in some special way.
+For GPDISP_HI16 ("gpdisp") relocations, the symbol is ignored when
+writing; when reading, it will be the absolute section symbol.  The
+addend is the displacement in bytes of the "lda" instruction from
+the "ldah" instruction (which is at the address of this reloc). */
+  BFD_RELOC_ALPHA_GPDISP_HI16,
+
+/* For GPDISP_LO16 ("ignore") relocations, the symbol is handled as
+with GPDISP_HI16 relocs.  The addend is ignored when writing the
+relocations out, and is filled in with the file's GP value on
+reading, for convenience. */
+  BFD_RELOC_ALPHA_GPDISP_LO16,
+
+/* The ELF GPDISP relocation is exactly the same as the GPDISP_HI16
+relocation except that there is no accompanying GPDISP_LO16
+relocation. */
+  BFD_RELOC_ALPHA_GPDISP,
+
+/* The Alpha LITERAL/LITUSE relocs are produced by a symbol reference;
+the assembler turns it into a LDQ instruction to load the address of
+the symbol, and then fills in a register in the real instruction.
+
+The LITERAL reloc, at the LDQ instruction, refers to the .lita
+section symbol.  The addend is ignored when writing, but is filled
+in with the file's GP value on reading, for convenience, as with the
+GPDISP_LO16 reloc.
+
+The ELF_LITERAL reloc is somewhere between 16_GOTOFF and GPDISP_LO16.
+It should refer to the symbol to be referenced, as with 16_GOTOFF,
+but it generates output not based on the position within the .got
+section, but relative to the GP value chosen for the file during the
+final link stage.
+
+The LITUSE reloc, on the instruction using the loaded address, gives
+information to the linker that it might be able to use to optimize
+away some literal section references.  The symbol is ignored (read
+as the absolute section symbol), and the "addend" indicates the type
+of instruction using the register:
+1 - "memory" fmt insn
+2 - byte-manipulation (byte offset reg)
+3 - jsr (target of branch) */
+  BFD_RELOC_ALPHA_LITERAL,
+  BFD_RELOC_ALPHA_ELF_LITERAL,
+  BFD_RELOC_ALPHA_LITUSE,
+
+/* The HINT relocation indicates a value that should be filled into the
+"hint" field of a jmp/jsr/ret instruction, for possible branch-
+prediction logic which may be provided on some processors. */
+  BFD_RELOC_ALPHA_HINT,
+
+/* The LINKAGE relocation outputs a linkage pair in the object file,
+which is filled by the linker. */
+  BFD_RELOC_ALPHA_LINKAGE,
+
+/* The CODEADDR relocation outputs a STO_CA in the object file,
+which is filled by the linker. */
+  BFD_RELOC_ALPHA_CODEADDR,
+
+/* The GPREL_HI/LO relocations together form a 32-bit offset from the
+GP register. */
+  BFD_RELOC_ALPHA_GPREL_HI16,
+  BFD_RELOC_ALPHA_GPREL_LO16,
+
+/* Bits 27..2 of the relocation address shifted right 2 bits;
+simple reloc otherwise. */
+  BFD_RELOC_MIPS_JMP,
+
+/* The MIPS16 jump instruction. */
+  BFD_RELOC_MIPS16_JMP,
+
+/* MIPS16 GP relative reloc. */
+  BFD_RELOC_MIPS16_GPREL,
+
+/* High 16 bits of 32-bit value; simple reloc. */
+  BFD_RELOC_HI16,
+
+/* High 16 bits of 32-bit value but the low 16 bits will be sign
+extended and added to form the final result.  If the low 16
+bits form a negative number, we need to add one to the high value
+to compensate for the borrow when the low bits are added. */
+  BFD_RELOC_HI16_S,
+
+/* Low 16 bits. */
+  BFD_RELOC_LO16,
+
+/* Like BFD_RELOC_HI16_S, but PC relative. */
+  BFD_RELOC_PCREL_HI16_S,
+
+/* Like BFD_RELOC_LO16, but PC relative. */
+  BFD_RELOC_PCREL_LO16,
+
+/* Relocation relative to the global pointer. */
+#define BFD_RELOC_MIPS_GPREL BFD_RELOC_GPREL16
+
+/* Relocation against a MIPS literal section. */
+  BFD_RELOC_MIPS_LITERAL,
+
+/* MIPS ELF relocations. */
+  BFD_RELOC_MIPS_GOT16,
+  BFD_RELOC_MIPS_CALL16,
+#define BFD_RELOC_MIPS_GPREL32 BFD_RELOC_GPREL32
+  BFD_RELOC_MIPS_GOT_HI16,
+  BFD_RELOC_MIPS_GOT_LO16,
+  BFD_RELOC_MIPS_CALL_HI16,
+  BFD_RELOC_MIPS_CALL_LO16,
+  BFD_RELOC_MIPS_SUB,
+  BFD_RELOC_MIPS_GOT_PAGE,
+  BFD_RELOC_MIPS_GOT_OFST,
+  BFD_RELOC_MIPS_GOT_DISP,
+  BFD_RELOC_MIPS_SHIFT5,
+  BFD_RELOC_MIPS_SHIFT6,
+  BFD_RELOC_MIPS_INSERT_A,
+  BFD_RELOC_MIPS_INSERT_B,
+  BFD_RELOC_MIPS_DELETE,
+  BFD_RELOC_MIPS_HIGHEST,
+  BFD_RELOC_MIPS_HIGHER,
+  BFD_RELOC_MIPS_SCN_DISP,
+  BFD_RELOC_MIPS_REL16,
+  BFD_RELOC_MIPS_RELGOT,
+  BFD_RELOC_MIPS_JALR,
+
+
+/* i386/elf relocations */
+  BFD_RELOC_386_GOT32,
+  BFD_RELOC_386_PLT32,
+  BFD_RELOC_386_COPY,
+  BFD_RELOC_386_GLOB_DAT,
+  BFD_RELOC_386_JUMP_SLOT,
+  BFD_RELOC_386_RELATIVE,
+  BFD_RELOC_386_GOTOFF,
+  BFD_RELOC_386_GOTPC,
+
+/* x86-64/elf relocations */
+  BFD_RELOC_X86_64_GOT32,
+  BFD_RELOC_X86_64_PLT32,
+  BFD_RELOC_X86_64_COPY,
+  BFD_RELOC_X86_64_GLOB_DAT,
+  BFD_RELOC_X86_64_JUMP_SLOT,
+  BFD_RELOC_X86_64_RELATIVE,
+  BFD_RELOC_X86_64_GOTPCREL,
+  BFD_RELOC_X86_64_32S,
+
+/* ns32k relocations */
+  BFD_RELOC_NS32K_IMM_8,
+  BFD_RELOC_NS32K_IMM_16,
+  BFD_RELOC_NS32K_IMM_32,
+  BFD_RELOC_NS32K_IMM_8_PCREL,
+  BFD_RELOC_NS32K_IMM_16_PCREL,
+  BFD_RELOC_NS32K_IMM_32_PCREL,
+  BFD_RELOC_NS32K_DISP_8,
+  BFD_RELOC_NS32K_DISP_16,
+  BFD_RELOC_NS32K_DISP_32,
+  BFD_RELOC_NS32K_DISP_8_PCREL,
+  BFD_RELOC_NS32K_DISP_16_PCREL,
+  BFD_RELOC_NS32K_DISP_32_PCREL,
+
+/* PDP11 relocations */
+  BFD_RELOC_PDP11_DISP_8_PCREL,
+  BFD_RELOC_PDP11_DISP_6_PCREL,
+
+/* Picojava relocs.  Not all of these appear in object files. */
+  BFD_RELOC_PJ_CODE_HI16,
+  BFD_RELOC_PJ_CODE_LO16,
+  BFD_RELOC_PJ_CODE_DIR16,
+  BFD_RELOC_PJ_CODE_DIR32,
+  BFD_RELOC_PJ_CODE_REL16,
+  BFD_RELOC_PJ_CODE_REL32,
+
+/* Power(rs6000) and PowerPC relocations. */
+  BFD_RELOC_PPC_B26,
+  BFD_RELOC_PPC_BA26,
+  BFD_RELOC_PPC_TOC16,
+  BFD_RELOC_PPC_B16,
+  BFD_RELOC_PPC_B16_BRTAKEN,
+  BFD_RELOC_PPC_B16_BRNTAKEN,
+  BFD_RELOC_PPC_BA16,
+  BFD_RELOC_PPC_BA16_BRTAKEN,
+  BFD_RELOC_PPC_BA16_BRNTAKEN,
+  BFD_RELOC_PPC_COPY,
+  BFD_RELOC_PPC_GLOB_DAT,
+  BFD_RELOC_PPC_JMP_SLOT,
+  BFD_RELOC_PPC_RELATIVE,
+  BFD_RELOC_PPC_LOCAL24PC,
+  BFD_RELOC_PPC_EMB_NADDR32,
+  BFD_RELOC_PPC_EMB_NADDR16,
+  BFD_RELOC_PPC_EMB_NADDR16_LO,
+  BFD_RELOC_PPC_EMB_NADDR16_HI,
+  BFD_RELOC_PPC_EMB_NADDR16_HA,
+  BFD_RELOC_PPC_EMB_SDAI16,
+  BFD_RELOC_PPC_EMB_SDA2I16,
+  BFD_RELOC_PPC_EMB_SDA2REL,
+  BFD_RELOC_PPC_EMB_SDA21,
+  BFD_RELOC_PPC_EMB_MRKREF,
+  BFD_RELOC_PPC_EMB_RELSEC16,
+  BFD_RELOC_PPC_EMB_RELST_LO,
+  BFD_RELOC_PPC_EMB_RELST_HI,
+  BFD_RELOC_PPC_EMB_RELST_HA,
+  BFD_RELOC_PPC_EMB_BIT_FLD,
+  BFD_RELOC_PPC_EMB_RELSDA,
+  BFD_RELOC_PPC64_HIGHER,
+  BFD_RELOC_PPC64_HIGHER_S,
+  BFD_RELOC_PPC64_HIGHEST,
+  BFD_RELOC_PPC64_HIGHEST_S,
+  BFD_RELOC_PPC64_TOC16_LO,
+  BFD_RELOC_PPC64_TOC16_HI,
+  BFD_RELOC_PPC64_TOC16_HA,
+  BFD_RELOC_PPC64_TOC,
+  BFD_RELOC_PPC64_PLTGOT16,
+  BFD_RELOC_PPC64_PLTGOT16_LO,
+  BFD_RELOC_PPC64_PLTGOT16_HI,
+  BFD_RELOC_PPC64_PLTGOT16_HA,
+  BFD_RELOC_PPC64_ADDR16_DS,
+  BFD_RELOC_PPC64_ADDR16_LO_DS,
+  BFD_RELOC_PPC64_GOT16_DS,
+  BFD_RELOC_PPC64_GOT16_LO_DS,
+  BFD_RELOC_PPC64_PLT16_LO_DS,
+  BFD_RELOC_PPC64_SECTOFF_DS,
+  BFD_RELOC_PPC64_SECTOFF_LO_DS,
+  BFD_RELOC_PPC64_TOC16_DS,
+  BFD_RELOC_PPC64_TOC16_LO_DS,
+  BFD_RELOC_PPC64_PLTGOT16_DS,
+  BFD_RELOC_PPC64_PLTGOT16_LO_DS,
+
+/* IBM 370/390 relocations */
+  BFD_RELOC_I370_D12,
+
+/* The type of reloc used to build a contructor table - at the moment
+probably a 32 bit wide absolute relocation, but the target can choose.
+It generally does map to one of the other relocation types. */
+  BFD_RELOC_CTOR,
+
+/* ARM 26 bit pc-relative branch.  The lowest two bits must be zero and are
+not stored in the instruction. */
+  BFD_RELOC_ARM_PCREL_BRANCH,
+
+/* ARM 26 bit pc-relative branch.  The lowest bit must be zero and is
+not stored in the instruction.  The 2nd lowest bit comes from a 1 bit
+field in the instruction. */
+  BFD_RELOC_ARM_PCREL_BLX,
+
+/* Thumb 22 bit pc-relative branch.  The lowest bit must be zero and is
+not stored in the instruction.  The 2nd lowest bit comes from a 1 bit
+field in the instruction. */
+  BFD_RELOC_THUMB_PCREL_BLX,
+
+/* These relocs are only used within the ARM assembler.  They are not
+(at present) written to any object files. */
+  BFD_RELOC_ARM_IMMEDIATE,
+  BFD_RELOC_ARM_ADRL_IMMEDIATE,
+  BFD_RELOC_ARM_OFFSET_IMM,
+  BFD_RELOC_ARM_SHIFT_IMM,
+  BFD_RELOC_ARM_SWI,
+  BFD_RELOC_ARM_MULTI,
+  BFD_RELOC_ARM_CP_OFF_IMM,
+  BFD_RELOC_ARM_ADR_IMM,
+  BFD_RELOC_ARM_LDR_IMM,
+  BFD_RELOC_ARM_LITERAL,
+  BFD_RELOC_ARM_IN_POOL,
+  BFD_RELOC_ARM_OFFSET_IMM8,
+  BFD_RELOC_ARM_HWLITERAL,
+  BFD_RELOC_ARM_THUMB_ADD,
+  BFD_RELOC_ARM_THUMB_IMM,
+  BFD_RELOC_ARM_THUMB_SHIFT,
+  BFD_RELOC_ARM_THUMB_OFFSET,
+  BFD_RELOC_ARM_GOT12,
+  BFD_RELOC_ARM_GOT32,
+  BFD_RELOC_ARM_JUMP_SLOT,
+  BFD_RELOC_ARM_COPY,
+  BFD_RELOC_ARM_GLOB_DAT,
+  BFD_RELOC_ARM_PLT32,
+  BFD_RELOC_ARM_RELATIVE,
+  BFD_RELOC_ARM_GOTOFF,
+  BFD_RELOC_ARM_GOTPC,
+
+/* Hitachi SH relocs.  Not all of these appear in object files. */
+  BFD_RELOC_SH_PCDISP8BY2,
+  BFD_RELOC_SH_PCDISP12BY2,
+  BFD_RELOC_SH_IMM4,
+  BFD_RELOC_SH_IMM4BY2,
+  BFD_RELOC_SH_IMM4BY4,
+  BFD_RELOC_SH_IMM8,
+  BFD_RELOC_SH_IMM8BY2,
+  BFD_RELOC_SH_IMM8BY4,
+  BFD_RELOC_SH_PCRELIMM8BY2,
+  BFD_RELOC_SH_PCRELIMM8BY4,
+  BFD_RELOC_SH_SWITCH16,
+  BFD_RELOC_SH_SWITCH32,
+  BFD_RELOC_SH_USES,
+  BFD_RELOC_SH_COUNT,
+  BFD_RELOC_SH_ALIGN,
+  BFD_RELOC_SH_CODE,
+  BFD_RELOC_SH_DATA,
+  BFD_RELOC_SH_LABEL,
+  BFD_RELOC_SH_LOOP_START,
+  BFD_RELOC_SH_LOOP_END,
+  BFD_RELOC_SH_COPY,
+  BFD_RELOC_SH_GLOB_DAT,
+  BFD_RELOC_SH_JMP_SLOT,
+  BFD_RELOC_SH_RELATIVE,
+  BFD_RELOC_SH_GOTPC,
+
+/* Thumb 23-, 12- and 9-bit pc-relative branches.  The lowest bit must
+be zero and is not stored in the instruction. */
+  BFD_RELOC_THUMB_PCREL_BRANCH9,
+  BFD_RELOC_THUMB_PCREL_BRANCH12,
+  BFD_RELOC_THUMB_PCREL_BRANCH23,
+
+/* ARC Cores relocs.
+ARC 22 bit pc-relative branch.  The lowest two bits must be zero and are
+not stored in the instruction.  The high 20 bits are installed in bits 26
+through 7 of the instruction. */
+  BFD_RELOC_ARC_B22_PCREL,
+
+/* ARC 26 bit absolute branch.  The lowest two bits must be zero and are not
+stored in the instruction.  The high 24 bits are installed in bits 23
+through 0. */
+  BFD_RELOC_ARC_B26,
+
+/* Mitsubishi D10V relocs.
+This is a 10-bit reloc with the right 2 bits
+assumed to be 0. */
+  BFD_RELOC_D10V_10_PCREL_R,
+
+/* Mitsubishi D10V relocs.
+This is a 10-bit reloc with the right 2 bits
+assumed to be 0.  This is the same as the previous reloc
+except it is in the left container, i.e.,
+shifted left 15 bits. */
+  BFD_RELOC_D10V_10_PCREL_L,
+
+/* This is an 18-bit reloc with the right 2 bits
+assumed to be 0. */
+  BFD_RELOC_D10V_18,
+
+/* This is an 18-bit reloc with the right 2 bits
+assumed to be 0. */
+  BFD_RELOC_D10V_18_PCREL,
+
+/* Mitsubishi D30V relocs.
+This is a 6-bit absolute reloc. */
+  BFD_RELOC_D30V_6,
+
+/* This is a 6-bit pc-relative reloc with
+the right 3 bits assumed to be 0. */
+  BFD_RELOC_D30V_9_PCREL,
+
+/* This is a 6-bit pc-relative reloc with
+the right 3 bits assumed to be 0. Same
+as the previous reloc but on the right side
+of the container. */
+  BFD_RELOC_D30V_9_PCREL_R,
+
+/* This is a 12-bit absolute reloc with the
+right 3 bitsassumed to be 0. */
+  BFD_RELOC_D30V_15,
+
+/* This is a 12-bit pc-relative reloc with
+the right 3 bits assumed to be 0. */
+  BFD_RELOC_D30V_15_PCREL,
+
+/* This is a 12-bit pc-relative reloc with
+the right 3 bits assumed to be 0. Same
+as the previous reloc but on the right side
+of the container. */
+  BFD_RELOC_D30V_15_PCREL_R,
+
+/* This is an 18-bit absolute reloc with
+the right 3 bits assumed to be 0. */
+  BFD_RELOC_D30V_21,
+
+/* This is an 18-bit pc-relative reloc with
+the right 3 bits assumed to be 0. */
+  BFD_RELOC_D30V_21_PCREL,
+
+/* This is an 18-bit pc-relative reloc with
+the right 3 bits assumed to be 0. Same
+as the previous reloc but on the right side
+of the container. */
+  BFD_RELOC_D30V_21_PCREL_R,
+
+/* This is a 32-bit absolute reloc. */
+  BFD_RELOC_D30V_32,
+
+/* This is a 32-bit pc-relative reloc. */
+  BFD_RELOC_D30V_32_PCREL,
+
+/* Mitsubishi M32R relocs.
+This is a 24 bit absolute address. */
+  BFD_RELOC_M32R_24,
+
+/* This is a 10-bit pc-relative reloc with the right 2 bits assumed to be 0. */
+  BFD_RELOC_M32R_10_PCREL,
+
+/* This is an 18-bit reloc with the right 2 bits assumed to be 0. */
+  BFD_RELOC_M32R_18_PCREL,
+
+/* This is a 26-bit reloc with the right 2 bits assumed to be 0. */
+  BFD_RELOC_M32R_26_PCREL,
+
+/* This is a 16-bit reloc containing the high 16 bits of an address
+used when the lower 16 bits are treated as unsigned. */
+  BFD_RELOC_M32R_HI16_ULO,
+
+/* This is a 16-bit reloc containing the high 16 bits of an address
+used when the lower 16 bits are treated as signed. */
+  BFD_RELOC_M32R_HI16_SLO,
+
+/* This is a 16-bit reloc containing the lower 16 bits of an address. */
+  BFD_RELOC_M32R_LO16,
+
+/* This is a 16-bit reloc containing the small data area offset for use in
+add3, load, and store instructions. */
+  BFD_RELOC_M32R_SDA16,
+
+/* This is a 9-bit reloc */
+  BFD_RELOC_V850_9_PCREL,
+
+/* This is a 22-bit reloc */
+  BFD_RELOC_V850_22_PCREL,
+
+/* This is a 16 bit offset from the short data area pointer. */
+  BFD_RELOC_V850_SDA_16_16_OFFSET,
+
+/* This is a 16 bit offset (of which only 15 bits are used) from the
+short data area pointer. */
+  BFD_RELOC_V850_SDA_15_16_OFFSET,
+
+/* This is a 16 bit offset from the zero data area pointer. */
+  BFD_RELOC_V850_ZDA_16_16_OFFSET,
+
+/* This is a 16 bit offset (of which only 15 bits are used) from the
+zero data area pointer. */
+  BFD_RELOC_V850_ZDA_15_16_OFFSET,
+
+/* This is an 8 bit offset (of which only 6 bits are used) from the
+tiny data area pointer. */
+  BFD_RELOC_V850_TDA_6_8_OFFSET,
+
+/* This is an 8bit offset (of which only 7 bits are used) from the tiny
+data area pointer. */
+  BFD_RELOC_V850_TDA_7_8_OFFSET,
+
+/* This is a 7 bit offset from the tiny data area pointer. */
+  BFD_RELOC_V850_TDA_7_7_OFFSET,
+
+/* This is a 16 bit offset from the tiny data area pointer. */
+  BFD_RELOC_V850_TDA_16_16_OFFSET,
+
+/* This is a 5 bit offset (of which only 4 bits are used) from the tiny
+data area pointer. */
+  BFD_RELOC_V850_TDA_4_5_OFFSET,
+
+/* This is a 4 bit offset from the tiny data area pointer. */
+  BFD_RELOC_V850_TDA_4_4_OFFSET,
+
+/* This is a 16 bit offset from the short data area pointer, with the
+bits placed non-contigously in the instruction. */
+  BFD_RELOC_V850_SDA_16_16_SPLIT_OFFSET,
+
+/* This is a 16 bit offset from the zero data area pointer, with the
+bits placed non-contigously in the instruction. */
+  BFD_RELOC_V850_ZDA_16_16_SPLIT_OFFSET,
+
+/* This is a 6 bit offset from the call table base pointer. */
+  BFD_RELOC_V850_CALLT_6_7_OFFSET,
+
+/* This is a 16 bit offset from the call table base pointer. */
+  BFD_RELOC_V850_CALLT_16_16_OFFSET,
+
+
+/* This is a 32bit pcrel reloc for the mn10300, offset by two bytes in the
+instruction. */
+  BFD_RELOC_MN10300_32_PCREL,
+
+/* This is a 16bit pcrel reloc for the mn10300, offset by two bytes in the
+instruction. */
+  BFD_RELOC_MN10300_16_PCREL,
+
+/* This is a 8bit DP reloc for the tms320c30, where the most
+significant 8 bits of a 24 bit word are placed into the least
+significant 8 bits of the opcode. */
+  BFD_RELOC_TIC30_LDP,
+
+/* This is a 7bit reloc for the tms320c54x, where the least
+significant 7 bits of a 16 bit word are placed into the least
+significant 7 bits of the opcode. */
+  BFD_RELOC_TIC54X_PARTLS7,
+
+/* This is a 9bit DP reloc for the tms320c54x, where the most
+significant 9 bits of a 16 bit word are placed into the least
+significant 9 bits of the opcode. */
+  BFD_RELOC_TIC54X_PARTMS9,
+
+/* This is an extended address 23-bit reloc for the tms320c54x. */
+  BFD_RELOC_TIC54X_23,
+
+/* This is a 16-bit reloc for the tms320c54x, where the least
+significant 16 bits of a 23-bit extended address are placed into
+the opcode. */
+  BFD_RELOC_TIC54X_16_OF_23,
+
+/* This is a reloc for the tms320c54x, where the most
+significant 7 bits of a 23-bit extended address are placed into
+the opcode. */
+  BFD_RELOC_TIC54X_MS7_OF_23,
+
+/* This is a 48 bit reloc for the FR30 that stores 32 bits. */
+  BFD_RELOC_FR30_48,
+
+/* This is a 32 bit reloc for the FR30 that stores 20 bits split up into
+two sections. */
+  BFD_RELOC_FR30_20,
+
+/* This is a 16 bit reloc for the FR30 that stores a 6 bit word offset in
+4 bits. */
+  BFD_RELOC_FR30_6_IN_4,
+
+/* This is a 16 bit reloc for the FR30 that stores an 8 bit byte offset
+into 8 bits. */
+  BFD_RELOC_FR30_8_IN_8,
+
+/* This is a 16 bit reloc for the FR30 that stores a 9 bit short offset
+into 8 bits. */
+  BFD_RELOC_FR30_9_IN_8,
+
+/* This is a 16 bit reloc for the FR30 that stores a 10 bit word offset
+into 8 bits. */
+  BFD_RELOC_FR30_10_IN_8,
+
+/* This is a 16 bit reloc for the FR30 that stores a 9 bit pc relative
+short offset into 8 bits. */
+  BFD_RELOC_FR30_9_PCREL,
+
+/* This is a 16 bit reloc for the FR30 that stores a 12 bit pc relative
+short offset into 11 bits. */
+  BFD_RELOC_FR30_12_PCREL,
+
+/* Motorola Mcore relocations. */
+  BFD_RELOC_MCORE_PCREL_IMM8BY4,
+  BFD_RELOC_MCORE_PCREL_IMM11BY2,
+  BFD_RELOC_MCORE_PCREL_IMM4BY2,
+  BFD_RELOC_MCORE_PCREL_32,
+  BFD_RELOC_MCORE_PCREL_JSR_IMM11BY2,
+  BFD_RELOC_MCORE_RVA,
+
+/* This is a 16 bit reloc for the AVR that stores 8 bit pc relative
+short offset into 7 bits. */
+  BFD_RELOC_AVR_7_PCREL,
+
+/* This is a 16 bit reloc for the AVR that stores 13 bit pc relative
+short offset into 12 bits. */
+  BFD_RELOC_AVR_13_PCREL,
+
+/* This is a 16 bit reloc for the AVR that stores 17 bit value (usually
+program memory address) into 16 bits. */
+  BFD_RELOC_AVR_16_PM,
+
+/* This is a 16 bit reloc for the AVR that stores 8 bit value (usually
+data memory address) into 8 bit immediate value of LDI insn. */
+  BFD_RELOC_AVR_LO8_LDI,
+
+/* This is a 16 bit reloc for the AVR that stores 8 bit value (high 8 bit
+of data memory address) into 8 bit immediate value of LDI insn. */
+  BFD_RELOC_AVR_HI8_LDI,
+
+/* This is a 16 bit reloc for the AVR that stores 8 bit value (most high 8 bit
+of program memory address) into 8 bit immediate value of LDI insn. */
+  BFD_RELOC_AVR_HH8_LDI,
+
+/* This is a 16 bit reloc for the AVR that stores negated 8 bit value
+(usually data memory address) into 8 bit immediate value of SUBI insn. */
+  BFD_RELOC_AVR_LO8_LDI_NEG,
+
+/* This is a 16 bit reloc for the AVR that stores negated 8 bit value
+(high 8 bit of data memory address) into 8 bit immediate value of
+SUBI insn. */
+  BFD_RELOC_AVR_HI8_LDI_NEG,
+
+/* This is a 16 bit reloc for the AVR that stores negated 8 bit value
+(most high 8 bit of program memory address) into 8 bit immediate value
+of LDI or SUBI insn. */
+  BFD_RELOC_AVR_HH8_LDI_NEG,
+
+/* This is a 16 bit reloc for the AVR that stores 8 bit value (usually
+command address) into 8 bit immediate value of LDI insn. */
+  BFD_RELOC_AVR_LO8_LDI_PM,
+
+/* This is a 16 bit reloc for the AVR that stores 8 bit value (high 8 bit
+of command address) into 8 bit immediate value of LDI insn. */
+  BFD_RELOC_AVR_HI8_LDI_PM,
+
+/* This is a 16 bit reloc for the AVR that stores 8 bit value (most high 8 bit
+of command address) into 8 bit immediate value of LDI insn. */
+  BFD_RELOC_AVR_HH8_LDI_PM,
+
+/* This is a 16 bit reloc for the AVR that stores negated 8 bit value
+(usually command address) into 8 bit immediate value of SUBI insn. */
+  BFD_RELOC_AVR_LO8_LDI_PM_NEG,
+
+/* This is a 16 bit reloc for the AVR that stores negated 8 bit value
+(high 8 bit of 16 bit command address) into 8 bit immediate value
+of SUBI insn. */
+  BFD_RELOC_AVR_HI8_LDI_PM_NEG,
+
+/* This is a 16 bit reloc for the AVR that stores negated 8 bit value
+(high 6 bit of 22 bit command address) into 8 bit immediate
+value of SUBI insn. */
+  BFD_RELOC_AVR_HH8_LDI_PM_NEG,
+
+/* This is a 32 bit reloc for the AVR that stores 23 bit value
+into 22 bits. */
+  BFD_RELOC_AVR_CALL,
+
+/* Direct 12 bit. */
+  BFD_RELOC_390_12,
+
+/* 12 bit GOT offset. */
+  BFD_RELOC_390_GOT12,
+
+/* 32 bit PC relative PLT address. */
+  BFD_RELOC_390_PLT32,
+
+/* Copy symbol at runtime. */
+  BFD_RELOC_390_COPY,
+
+/* Create GOT entry. */
+  BFD_RELOC_390_GLOB_DAT,
+
+/* Create PLT entry. */
+  BFD_RELOC_390_JMP_SLOT,
+
+/* Adjust by program base. */
+  BFD_RELOC_390_RELATIVE,
+
+/* 32 bit PC relative offset to GOT. */
+  BFD_RELOC_390_GOTPC,
+
+/* 16 bit GOT offset. */
+  BFD_RELOC_390_GOT16,
+
+/* PC relative 16 bit shifted by 1. */
+  BFD_RELOC_390_PC16DBL,
+
+/* 16 bit PC rel. PLT shifted by 1. */
+  BFD_RELOC_390_PLT16DBL,
+
+/* PC relative 32 bit shifted by 1. */
+  BFD_RELOC_390_PC32DBL,
+
+/* 32 bit PC rel. PLT shifted by 1. */
+  BFD_RELOC_390_PLT32DBL,
+
+/* 32 bit PC rel. GOT shifted by 1. */
+  BFD_RELOC_390_GOTPCDBL,
+
+/* 64 bit GOT offset. */
+  BFD_RELOC_390_GOT64,
+
+/* 64 bit PC relative PLT address. */
+  BFD_RELOC_390_PLT64,
+
+/* 32 bit rel. offset to GOT entry. */
+  BFD_RELOC_390_GOTENT,
+
+/* These two relocations are used by the linker to determine which of
+the entries in a C++ virtual function table are actually used.  When
+the --gc-sections option is given, the linker will zero out the entries
+that are not used, so that the code for those functions need not be
+included in the output.
+
+VTABLE_INHERIT is a zero-space relocation used to describe to the
+linker the inheritence tree of a C++ virtual function table.  The
+relocation's symbol should be the parent class' vtable, and the
+relocation should be located at the child vtable.
+
+VTABLE_ENTRY is a zero-space relocation that describes the use of a
+virtual function table entry.  The reloc's symbol should refer to the
+table of the class mentioned in the code.  Off of that base, an offset
+describes the entry that is being used.  For Rela hosts, this offset
+is stored in the reloc's addend.  For Rel hosts, we are forced to put
+this offset in the reloc's section offset. */
+  BFD_RELOC_VTABLE_INHERIT,
+  BFD_RELOC_VTABLE_ENTRY,
+
+/* Intel IA64 Relocations. */
+  BFD_RELOC_IA64_IMM14,
+  BFD_RELOC_IA64_IMM22,
+  BFD_RELOC_IA64_IMM64,
+  BFD_RELOC_IA64_DIR32MSB,
+  BFD_RELOC_IA64_DIR32LSB,
+  BFD_RELOC_IA64_DIR64MSB,
+  BFD_RELOC_IA64_DIR64LSB,
+  BFD_RELOC_IA64_GPREL22,
+  BFD_RELOC_IA64_GPREL64I,
+  BFD_RELOC_IA64_GPREL32MSB,
+  BFD_RELOC_IA64_GPREL32LSB,
+  BFD_RELOC_IA64_GPREL64MSB,
+  BFD_RELOC_IA64_GPREL64LSB,
+  BFD_RELOC_IA64_LTOFF22,
+  BFD_RELOC_IA64_LTOFF64I,
+  BFD_RELOC_IA64_PLTOFF22,
+  BFD_RELOC_IA64_PLTOFF64I,
+  BFD_RELOC_IA64_PLTOFF64MSB,
+  BFD_RELOC_IA64_PLTOFF64LSB,
+  BFD_RELOC_IA64_FPTR64I,
+  BFD_RELOC_IA64_FPTR32MSB,
+  BFD_RELOC_IA64_FPTR32LSB,
+  BFD_RELOC_IA64_FPTR64MSB,
+  BFD_RELOC_IA64_FPTR64LSB,
+  BFD_RELOC_IA64_PCREL21B,
+  BFD_RELOC_IA64_PCREL21BI,
+  BFD_RELOC_IA64_PCREL21M,
+  BFD_RELOC_IA64_PCREL21F,
+  BFD_RELOC_IA64_PCREL22,
+  BFD_RELOC_IA64_PCREL60B,
+  BFD_RELOC_IA64_PCREL64I,
+  BFD_RELOC_IA64_PCREL32MSB,
+  BFD_RELOC_IA64_PCREL32LSB,
+  BFD_RELOC_IA64_PCREL64MSB,
+  BFD_RELOC_IA64_PCREL64LSB,
+  BFD_RELOC_IA64_LTOFF_FPTR22,
+  BFD_RELOC_IA64_LTOFF_FPTR64I,
+  BFD_RELOC_IA64_LTOFF_FPTR32MSB,
+  BFD_RELOC_IA64_LTOFF_FPTR32LSB,
+  BFD_RELOC_IA64_LTOFF_FPTR64MSB,
+  BFD_RELOC_IA64_LTOFF_FPTR64LSB,
+  BFD_RELOC_IA64_SEGREL32MSB,
+  BFD_RELOC_IA64_SEGREL32LSB,
+  BFD_RELOC_IA64_SEGREL64MSB,
+  BFD_RELOC_IA64_SEGREL64LSB,
+  BFD_RELOC_IA64_SECREL32MSB,
+  BFD_RELOC_IA64_SECREL32LSB,
+  BFD_RELOC_IA64_SECREL64MSB,
+  BFD_RELOC_IA64_SECREL64LSB,
+  BFD_RELOC_IA64_REL32MSB,
+  BFD_RELOC_IA64_REL32LSB,
+  BFD_RELOC_IA64_REL64MSB,
+  BFD_RELOC_IA64_REL64LSB,
+  BFD_RELOC_IA64_LTV32MSB,
+  BFD_RELOC_IA64_LTV32LSB,
+  BFD_RELOC_IA64_LTV64MSB,
+  BFD_RELOC_IA64_LTV64LSB,
+  BFD_RELOC_IA64_IPLTMSB,
+  BFD_RELOC_IA64_IPLTLSB,
+  BFD_RELOC_IA64_COPY,
+  BFD_RELOC_IA64_TPREL22,
+  BFD_RELOC_IA64_TPREL64MSB,
+  BFD_RELOC_IA64_TPREL64LSB,
+  BFD_RELOC_IA64_LTOFF_TP22,
+  BFD_RELOC_IA64_LTOFF22X,
+  BFD_RELOC_IA64_LDXMOV,
+
+/* Motorola 68HC11 reloc.
+This is the 8 bits high part of an absolute address. */
+  BFD_RELOC_M68HC11_HI8,
+
+/* Motorola 68HC11 reloc.
+This is the 8 bits low part of an absolute address. */
+  BFD_RELOC_M68HC11_LO8,
+
+/* Motorola 68HC11 reloc.
+This is the 3 bits of a value. */
+  BFD_RELOC_M68HC11_3B,
+
+/* These relocs are only used within the CRIS assembler.  They are not
+(at present) written to any object files. */
+  BFD_RELOC_CRIS_BDISP8,
+  BFD_RELOC_CRIS_UNSIGNED_5,
+  BFD_RELOC_CRIS_SIGNED_6,
+  BFD_RELOC_CRIS_UNSIGNED_6,
+  BFD_RELOC_CRIS_UNSIGNED_4,
+
+/* Relocs used in ELF shared libraries for CRIS. */
+  BFD_RELOC_CRIS_COPY,
+  BFD_RELOC_CRIS_GLOB_DAT,
+  BFD_RELOC_CRIS_JUMP_SLOT,
+  BFD_RELOC_CRIS_RELATIVE,
+
+/* 32-bit offset to symbol-entry within GOT. */
+  BFD_RELOC_CRIS_32_GOT,
+
+/* 16-bit offset to symbol-entry within GOT. */
+  BFD_RELOC_CRIS_16_GOT,
+
+/* 32-bit offset to symbol-entry within GOT, with PLT handling. */
+  BFD_RELOC_CRIS_32_GOTPLT,
+
+/* 16-bit offset to symbol-entry within GOT, with PLT handling. */
+  BFD_RELOC_CRIS_16_GOTPLT,
+
+/* 32-bit offset to symbol, relative to GOT. */
+  BFD_RELOC_CRIS_32_GOTREL,
+
+/* 32-bit offset to symbol with PLT entry, relative to GOT. */
+  BFD_RELOC_CRIS_32_PLT_GOTREL,
+
+/* 32-bit offset to symbol with PLT entry, relative to this relocation. */
+  BFD_RELOC_CRIS_32_PLT_PCREL,
+
+/* Intel i860 Relocations. */
+  BFD_RELOC_860_COPY,
+  BFD_RELOC_860_GLOB_DAT,
+  BFD_RELOC_860_JUMP_SLOT,
+  BFD_RELOC_860_RELATIVE,
+  BFD_RELOC_860_PC26,
+  BFD_RELOC_860_PLT26,
+  BFD_RELOC_860_PC16,
+  BFD_RELOC_860_LOW0,
+  BFD_RELOC_860_SPLIT0,
+  BFD_RELOC_860_LOW1,
+  BFD_RELOC_860_SPLIT1,
+  BFD_RELOC_860_LOW2,
+  BFD_RELOC_860_SPLIT2,
+  BFD_RELOC_860_LOW3,
+  BFD_RELOC_860_LOGOT0,
+  BFD_RELOC_860_SPGOT0,
+  BFD_RELOC_860_LOGOT1,
+  BFD_RELOC_860_SPGOT1,
+  BFD_RELOC_860_LOGOTOFF0,
+  BFD_RELOC_860_SPGOTOFF0,
+  BFD_RELOC_860_LOGOTOFF1,
+  BFD_RELOC_860_SPGOTOFF1,
+  BFD_RELOC_860_LOGOTOFF2,
+  BFD_RELOC_860_LOGOTOFF3,
+  BFD_RELOC_860_LOPC,
+  BFD_RELOC_860_HIGHADJ,
+  BFD_RELOC_860_HAGOT,
+  BFD_RELOC_860_HAGOTOFF,
+  BFD_RELOC_860_HAPC,
+  BFD_RELOC_860_HIGH,
+  BFD_RELOC_860_HIGOT,
+  BFD_RELOC_860_HIGOTOFF,
+
+/* OpenRISC Relocations. */
+  BFD_RELOC_OPENRISC_ABS_26,
+  BFD_RELOC_OPENRISC_REL_26,
+
+/* H8 elf Relocations. */
+  BFD_RELOC_H8_DIR16A8,
+  BFD_RELOC_H8_DIR16R8,
+  BFD_RELOC_H8_DIR24A8,
+  BFD_RELOC_H8_DIR24R8,
+  BFD_RELOC_H8_DIR32A16,
+  BFD_RELOC_UNUSED };
+typedef enum bfd_reloc_code_real bfd_reloc_code_real_type;
+reloc_howto_type *
+bfd_reloc_type_lookup PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
+
+const char *
+bfd_get_reloc_code_name PARAMS ((bfd_reloc_code_real_type code));
+
+
+typedef struct symbol_cache_entry
+{
+       /* A pointer to the BFD which owns the symbol. This information
+          is necessary so that a back end can work out what additional
+          information (invisible to the application writer) is carried
+          with the symbol.
+
+          This field is *almost* redundant, since you can use section->owner
+          instead, except that some symbols point to the global sections
+          bfd_{abs,com,und}_section.  This could be fixed by making
+          these globals be per-bfd (or per-target-flavor).  FIXME. */
+
+  struct _bfd *the_bfd; /* Use bfd_asymbol_bfd(sym) to access this field. */
+
+       /* The text of the symbol. The name is left alone, and not copied; the
+          application may not alter it. */
+  const char *name;
+
+       /* The value of the symbol.  This really should be a union of a
+          numeric value with a pointer, since some flags indicate that
+          a pointer to another symbol is stored here.  */
+  symvalue value;
+
+       /* Attributes of a symbol: */
+
+#define BSF_NO_FLAGS    0x00
+
+       /* The symbol has local scope; <<static>> in <<C>>. The value
+          is the offset into the section of the data. */
+#define BSF_LOCAL      0x01
+
+       /* The symbol has global scope; initialized data in <<C>>. The
+          value is the offset into the section of the data. */
+#define BSF_GLOBAL     0x02
+
+       /* The symbol has global scope and is exported. The value is
+          the offset into the section of the data. */
+#define BSF_EXPORT     BSF_GLOBAL /* no real difference */
+
+       /* A normal C symbol would be one of:
+          <<BSF_LOCAL>>, <<BSF_FORT_COMM>>,  <<BSF_UNDEFINED>> or
+          <<BSF_GLOBAL>> */
+
+       /* The symbol is a debugging record. The value has an arbitary
+          meaning, unless BSF_DEBUGGING_RELOC is also set.  */
+#define BSF_DEBUGGING  0x08
+
+       /* The symbol denotes a function entry point.  Used in ELF,
+          perhaps others someday.  */
+#define BSF_FUNCTION    0x10
+
+       /* Used by the linker. */
+#define BSF_KEEP        0x20
+#define BSF_KEEP_G      0x40
+
+       /* A weak global symbol, overridable without warnings by
+          a regular global symbol of the same name.  */
+#define BSF_WEAK        0x80
+
+       /* This symbol was created to point to a section, e.g. ELF's
+          STT_SECTION symbols.  */
+#define BSF_SECTION_SYM 0x100
+
+       /* The symbol used to be a common symbol, but now it is
+          allocated. */
+#define BSF_OLD_COMMON  0x200
+
+       /* The default value for common data. */
+#define BFD_FORT_COMM_DEFAULT_VALUE 0
+
+       /* In some files the type of a symbol sometimes alters its
+          location in an output file - ie in coff a <<ISFCN>> symbol
+          which is also <<C_EXT>> symbol appears where it was
+          declared and not at the end of a section.  This bit is set
+          by the target BFD part to convey this information. */
+
+#define BSF_NOT_AT_END    0x400
+
+       /* Signal that the symbol is the label of constructor section. */
+#define BSF_CONSTRUCTOR   0x800
+
+       /* Signal that the symbol is a warning symbol.  The name is a
+          warning.  The name of the next symbol is the one to warn about;
+          if a reference is made to a symbol with the same name as the next
+          symbol, a warning is issued by the linker. */
+#define BSF_WARNING       0x1000
+
+       /* Signal that the symbol is indirect.  This symbol is an indirect
+          pointer to the symbol with the same name as the next symbol. */
+#define BSF_INDIRECT      0x2000
+
+       /* BSF_FILE marks symbols that contain a file name.  This is used
+          for ELF STT_FILE symbols.  */
+#define BSF_FILE          0x4000
+
+       /* Symbol is from dynamic linking information.  */
+#define BSF_DYNAMIC       0x8000
+
+       /* The symbol denotes a data object.  Used in ELF, and perhaps
+          others someday.  */
+#define BSF_OBJECT        0x10000
+
+       /* This symbol is a debugging symbol.  The value is the offset
+          into the section of the data.  BSF_DEBUGGING should be set
+          as well.  */
+#define BSF_DEBUGGING_RELOC 0x20000
+
+  flagword flags;
+
+       /* A pointer to the section to which this symbol is
+          relative.  This will always be non NULL, there are special
+          sections for undefined and absolute symbols.  */
+  struct sec *section;
+
+       /* Back end special data.  */
+  union
+    {
+      PTR p;
+      bfd_vma i;
+    } udata;
+
+} asymbol;
+#define bfd_get_symtab_upper_bound(abfd) \
+     BFD_SEND (abfd, _bfd_get_symtab_upper_bound, (abfd))
+boolean
+bfd_is_local_label PARAMS ((bfd *abfd, asymbol *sym));
+
+boolean
+bfd_is_local_label_name PARAMS ((bfd *abfd, const char *name));
+
+#define bfd_is_local_label_name(abfd, name) \
+     BFD_SEND (abfd, _bfd_is_local_label_name, (abfd, name))
+#define bfd_canonicalize_symtab(abfd, location) \
+     BFD_SEND (abfd, _bfd_canonicalize_symtab,\
+                  (abfd, location))
+boolean
+bfd_set_symtab PARAMS ((bfd *abfd, asymbol **location, unsigned int count));
+
+void
+bfd_print_symbol_vandf PARAMS ((bfd *abfd, PTR file, asymbol *symbol));
+
+#define bfd_make_empty_symbol(abfd) \
+     BFD_SEND (abfd, _bfd_make_empty_symbol, (abfd))
+#define bfd_make_debug_symbol(abfd,ptr,size) \
+        BFD_SEND (abfd, _bfd_make_debug_symbol, (abfd, ptr, size))
+int
+bfd_decode_symclass PARAMS ((asymbol *symbol));
+
+boolean
+bfd_is_undefined_symclass PARAMS ((int symclass));
+
+void
+bfd_symbol_info PARAMS ((asymbol *symbol, symbol_info *ret));
+
+boolean
+bfd_copy_private_symbol_data PARAMS ((bfd *ibfd, asymbol *isym, bfd *obfd, asymbol *osym));
+
+#define bfd_copy_private_symbol_data(ibfd, isymbol, obfd, osymbol) \
+     BFD_SEND (obfd, _bfd_copy_private_symbol_data, \
+               (ibfd, isymbol, obfd, osymbol))
+struct _bfd
+{
+    /* The filename the application opened the BFD with.  */
+    const char *filename;
+
+    /* A pointer to the target jump table.             */
+    const struct bfd_target *xvec;
+
+    /* To avoid dragging too many header files into every file that
+       includes `<<bfd.h>>', IOSTREAM has been declared as a "char
+       *", and MTIME as a "long".  Their correct types, to which they
+       are cast when used, are "FILE *" and "time_t".    The iostream
+       is the result of an fopen on the filename.  However, if the
+       BFD_IN_MEMORY flag is set, then iostream is actually a pointer
+       to a bfd_in_memory struct.  */
+    PTR iostream;
+
+    /* Is the file descriptor being cached?  That is, can it be closed as
+       needed, and re-opened when accessed later?  */
+
+    boolean cacheable;
+
+    /* Marks whether there was a default target specified when the
+       BFD was opened. This is used to select which matching algorithm
+       to use to choose the back end. */
+
+    boolean target_defaulted;
+
+    /* The caching routines use these to maintain a
+       least-recently-used list of BFDs */
+
+    struct _bfd *lru_prev, *lru_next;
+
+    /* When a file is closed by the caching routines, BFD retains
+       state information on the file here: */
+
+    ufile_ptr where;
+
+    /* and here: (``once'' means at least once) */
+
+    boolean opened_once;
+
+    /* Set if we have a locally maintained mtime value, rather than
+       getting it from the file each time: */
+
+    boolean mtime_set;
+
+    /* File modified time, if mtime_set is true: */
+
+    long mtime;
+
+    /* Reserved for an unimplemented file locking extension.*/
+
+    int ifd;
+
+    /* The format which belongs to the BFD. (object, core, etc.) */
+
+    bfd_format format;
+
+    /* The direction the BFD was opened with*/
+
+    enum bfd_direction {no_direction = 0,
+                        read_direction = 1,
+                        write_direction = 2,
+                        both_direction = 3} direction;
+
+    /* Format_specific flags*/
+
+    flagword flags;
+
+    /* Currently my_archive is tested before adding origin to
+       anything. I believe that this can become always an add of
+       origin, with origin set to 0 for non archive files.   */
+
+    ufile_ptr origin;
+
+    /* Remember when output has begun, to stop strange things
+       from happening. */
+    boolean output_has_begun;
+
+    /* Pointer to linked list of sections*/
+    struct sec  *sections;
+
+    /* The number of sections */
+    unsigned int section_count;
+
+    /* Stuff only useful for object files:
+       The start address. */
+    bfd_vma start_address;
+
+    /* Used for input and output*/
+    unsigned int symcount;
+
+    /* Symbol table for output BFD (with symcount entries) */
+    struct symbol_cache_entry  **outsymbols;
+
+    /* Pointer to structure which contains architecture information*/
+    const struct bfd_arch_info *arch_info;
+
+    /* Stuff only useful for archives:*/
+    PTR arelt_data;
+    struct _bfd *my_archive;     /* The containing archive BFD.  */
+    struct _bfd *next;           /* The next BFD in the archive.  */
+    struct _bfd *archive_head;   /* The first BFD in the archive.  */
+    boolean has_armap;
+
+    /* A chain of BFD structures involved in a link.  */
+    struct _bfd *link_next;
+
+    /* A field used by _bfd_generic_link_add_archive_symbols.  This will
+       be used only for archive elements.  */
+    int archive_pass;
+
+    /* Used by the back end to hold private data. */
+
+    union
+      {
+      struct aout_data_struct *aout_data;
+      struct artdata *aout_ar_data;
+      struct _oasys_data *oasys_obj_data;
+      struct _oasys_ar_data *oasys_ar_data;
+      struct coff_tdata *coff_obj_data;
+      struct pe_tdata *pe_obj_data;
+      struct xcoff_tdata *xcoff_obj_data;
+      struct ecoff_tdata *ecoff_obj_data;
+      struct ieee_data_struct *ieee_data;
+      struct ieee_ar_data_struct *ieee_ar_data;
+      struct srec_data_struct *srec_data;
+      struct ihex_data_struct *ihex_data;
+      struct tekhex_data_struct *tekhex_data;
+      struct elf_obj_tdata *elf_obj_data;
+      struct nlm_obj_tdata *nlm_obj_data;
+      struct bout_data_struct *bout_data;
+      struct sun_core_struct *sun_core_data;
+      struct sco5_core_struct *sco5_core_data;
+      struct trad_core_struct *trad_core_data;
+      struct som_data_struct *som_data;
+      struct hpux_core_struct *hpux_core_data;
+      struct hppabsd_core_struct *hppabsd_core_data;
+      struct sgi_core_struct *sgi_core_data;
+      struct lynx_core_struct *lynx_core_data;
+      struct osf_core_struct *osf_core_data;
+      struct cisco_core_struct *cisco_core_data;
+      struct versados_data_struct *versados_data;
+      struct netbsd_core_struct *netbsd_core_data;
+      PTR any;
+      } tdata;
+
+    /* Used by the application to hold private data*/
+    PTR usrdata;
+
+  /* Where all the allocated stuff under this BFD goes.  This is a
+     struct objalloc *, but we use PTR to avoid requiring the inclusion of
+     objalloc.h.  */
+    PTR memory;
+};
+
+typedef enum bfd_error
+{
+  bfd_error_no_error = 0,
+  bfd_error_system_call,
+  bfd_error_invalid_target,
+  bfd_error_wrong_format,
+  bfd_error_wrong_object_format,
+  bfd_error_invalid_operation,
+  bfd_error_no_memory,
+  bfd_error_no_symbols,
+  bfd_error_no_armap,
+  bfd_error_no_more_archived_files,
+  bfd_error_malformed_archive,
+  bfd_error_file_not_recognized,
+  bfd_error_file_ambiguously_recognized,
+  bfd_error_no_contents,
+  bfd_error_nonrepresentable_section,
+  bfd_error_no_debug_section,
+  bfd_error_bad_value,
+  bfd_error_file_truncated,
+  bfd_error_file_too_big,
+  bfd_error_invalid_error_code
+} bfd_error_type;
+
+bfd_error_type
+bfd_get_error PARAMS ((void));
+
+void
+bfd_set_error PARAMS ((bfd_error_type error_tag));
+
+const char *
+bfd_errmsg PARAMS ((bfd_error_type error_tag));
+
+void
+bfd_perror PARAMS ((const char *message));
+
+typedef void (*bfd_error_handler_type) PARAMS ((const char *, ...));
+
+bfd_error_handler_type
+bfd_set_error_handler PARAMS ((bfd_error_handler_type));
+
+void
+bfd_set_error_program_name PARAMS ((const char *));
+
+bfd_error_handler_type
+bfd_get_error_handler PARAMS ((void));
+
+const char *
+bfd_archive_filename PARAMS ((bfd *));
+
+long
+bfd_get_reloc_upper_bound PARAMS ((bfd *abfd, asection *sect));
+
+long
+bfd_canonicalize_reloc PARAMS ((bfd *abfd,
+    asection *sec,
+    arelent **loc,
+    asymbol **syms));
+
+void
+bfd_set_reloc PARAMS ((bfd *abfd, asection *sec, arelent **rel, unsigned int count)
+    
+    );
+
+boolean
+bfd_set_file_flags PARAMS ((bfd *abfd, flagword flags));
+
+int
+bfd_get_arch_size PARAMS ((bfd *abfd));
+
+int
+bfd_get_sign_extend_vma PARAMS ((bfd *abfd));
+
+boolean
+bfd_set_start_address PARAMS ((bfd *abfd, bfd_vma vma));
+
+long
+bfd_get_mtime PARAMS ((bfd *abfd));
+
+long
+bfd_get_size PARAMS ((bfd *abfd));
+
+unsigned int
+bfd_get_gp_size PARAMS ((bfd *abfd));
+
+void
+bfd_set_gp_size PARAMS ((bfd *abfd, unsigned int i));
+
+bfd_vma
+bfd_scan_vma PARAMS ((const char *string, const char **end, int base));
+
+boolean
+bfd_copy_private_bfd_data PARAMS ((bfd *ibfd, bfd *obfd));
+
+#define bfd_copy_private_bfd_data(ibfd, obfd) \
+     BFD_SEND (obfd, _bfd_copy_private_bfd_data, \
+               (ibfd, obfd))
+boolean
+bfd_merge_private_bfd_data PARAMS ((bfd *ibfd, bfd *obfd));
+
+#define bfd_merge_private_bfd_data(ibfd, obfd) \
+     BFD_SEND (obfd, _bfd_merge_private_bfd_data, \
+               (ibfd, obfd))
+boolean
+bfd_set_private_flags PARAMS ((bfd *abfd, flagword flags));
+
+#define bfd_set_private_flags(abfd, flags) \
+     BFD_SEND (abfd, _bfd_set_private_flags, \
+               (abfd, flags))
+#define bfd_sizeof_headers(abfd, reloc) \
+     BFD_SEND (abfd, _bfd_sizeof_headers, (abfd, reloc))
+
+#define bfd_find_nearest_line(abfd, sec, syms, off, file, func, line) \
+     BFD_SEND (abfd, _bfd_find_nearest_line,  (abfd, sec, syms, off, file, func, line))
+
+       /* Do these three do anything useful at all, for any back end?  */
+#define bfd_debug_info_start(abfd) \
+        BFD_SEND (abfd, _bfd_debug_info_start, (abfd))
+
+#define bfd_debug_info_end(abfd) \
+        BFD_SEND (abfd, _bfd_debug_info_end, (abfd))
+
+#define bfd_debug_info_accumulate(abfd, section) \
+        BFD_SEND (abfd, _bfd_debug_info_accumulate, (abfd, section))
+
+
+#define bfd_stat_arch_elt(abfd, stat) \
+        BFD_SEND (abfd, _bfd_stat_arch_elt,(abfd, stat))
+
+#define bfd_update_armap_timestamp(abfd) \
+        BFD_SEND (abfd, _bfd_update_armap_timestamp, (abfd))
+
+#define bfd_set_arch_mach(abfd, arch, mach)\
+        BFD_SEND ( abfd, _bfd_set_arch_mach, (abfd, arch, mach))
+
+#define bfd_relax_section(abfd, section, link_info, again) \
+       BFD_SEND (abfd, _bfd_relax_section, (abfd, section, link_info, again))
+
+#define bfd_gc_sections(abfd, link_info) \
+       BFD_SEND (abfd, _bfd_gc_sections, (abfd, link_info))
+
+#define bfd_merge_sections(abfd, link_info) \
+       BFD_SEND (abfd, _bfd_merge_sections, (abfd, link_info))
+
+#define bfd_link_hash_table_create(abfd) \
+       BFD_SEND (abfd, _bfd_link_hash_table_create, (abfd))
+
+#define bfd_link_add_symbols(abfd, info) \
+       BFD_SEND (abfd, _bfd_link_add_symbols, (abfd, info))
+
+#define bfd_final_link(abfd, info) \
+       BFD_SEND (abfd, _bfd_final_link, (abfd, info))
+
+#define bfd_free_cached_info(abfd) \
+       BFD_SEND (abfd, _bfd_free_cached_info, (abfd))
+
+#define bfd_get_dynamic_symtab_upper_bound(abfd) \
+       BFD_SEND (abfd, _bfd_get_dynamic_symtab_upper_bound, (abfd))
+
+#define bfd_print_private_bfd_data(abfd, file)\
+       BFD_SEND (abfd, _bfd_print_private_bfd_data, (abfd, file))
+
+#define bfd_canonicalize_dynamic_symtab(abfd, asymbols) \
+       BFD_SEND (abfd, _bfd_canonicalize_dynamic_symtab, (abfd, asymbols))
+
+#define bfd_get_dynamic_reloc_upper_bound(abfd) \
+       BFD_SEND (abfd, _bfd_get_dynamic_reloc_upper_bound, (abfd))
+
+#define bfd_canonicalize_dynamic_reloc(abfd, arels, asyms) \
+       BFD_SEND (abfd, _bfd_canonicalize_dynamic_reloc, (abfd, arels, asyms))
+
+extern bfd_byte *bfd_get_relocated_section_contents
+       PARAMS ((bfd *, struct bfd_link_info *,
+                 struct bfd_link_order *, bfd_byte *,
+                 boolean, asymbol **));
+
+boolean
+bfd_alt_mach_code PARAMS ((bfd *abfd, int index));
+
+symindex
+bfd_get_next_mapent PARAMS ((bfd *abfd, symindex previous, carsym **sym));
+
+boolean
+bfd_set_archive_head PARAMS ((bfd *output, bfd *new_head));
+
+bfd *
+bfd_openr_next_archived_file PARAMS ((bfd *archive, bfd *previous));
+
+const char *
+bfd_core_file_failing_command PARAMS ((bfd *abfd));
+
+int
+bfd_core_file_failing_signal PARAMS ((bfd *abfd));
+
+boolean
+core_file_matches_executable_p PARAMS ((bfd *core_bfd, bfd *exec_bfd));
+
+#define BFD_SEND(bfd, message, arglist) \
+               ((*((bfd)->xvec->message)) arglist)
+
+#ifdef DEBUG_BFD_SEND
+#undef BFD_SEND
+#define BFD_SEND(bfd, message, arglist) \
+  (((bfd) && (bfd)->xvec && (bfd)->xvec->message) ? \
+    ((*((bfd)->xvec->message)) arglist) : \
+    (bfd_assert (__FILE__,__LINE__), NULL))
+#endif
+#define BFD_SEND_FMT(bfd, message, arglist) \
+            (((bfd)->xvec->message[(int) ((bfd)->format)]) arglist)
+
+#ifdef DEBUG_BFD_SEND
+#undef BFD_SEND_FMT
+#define BFD_SEND_FMT(bfd, message, arglist) \
+  (((bfd) && (bfd)->xvec && (bfd)->xvec->message) ? \
+   (((bfd)->xvec->message[(int) ((bfd)->format)]) arglist) : \
+   (bfd_assert (__FILE__,__LINE__), NULL))
+#endif
+enum bfd_flavour {
+  bfd_target_unknown_flavour,
+  bfd_target_aout_flavour,
+  bfd_target_coff_flavour,
+  bfd_target_ecoff_flavour,
+  bfd_target_xcoff_flavour,
+  bfd_target_elf_flavour,
+  bfd_target_ieee_flavour,
+  bfd_target_nlm_flavour,
+  bfd_target_oasys_flavour,
+  bfd_target_tekhex_flavour,
+  bfd_target_srec_flavour,
+  bfd_target_ihex_flavour,
+  bfd_target_som_flavour,
+  bfd_target_os9k_flavour,
+  bfd_target_versados_flavour,
+  bfd_target_msdos_flavour,
+  bfd_target_ovax_flavour,
+  bfd_target_evax_flavour
+};
+
+enum bfd_endian { BFD_ENDIAN_BIG, BFD_ENDIAN_LITTLE, BFD_ENDIAN_UNKNOWN };
+
+/* Forward declaration.  */
+typedef struct bfd_link_info _bfd_link_info;
+
+typedef struct bfd_target
+{
+  char *name;
+  enum bfd_flavour flavour;
+  enum bfd_endian byteorder;
+  enum bfd_endian header_byteorder;
+  flagword object_flags;
+  flagword section_flags;
+  char symbol_leading_char;
+  char ar_pad_char;
+  unsigned short ar_max_namelen;
+  bfd_vma        (*bfd_getx64) PARAMS ((const bfd_byte *));
+  bfd_signed_vma (*bfd_getx_signed_64) PARAMS ((const bfd_byte *));
+  void           (*bfd_putx64) PARAMS ((bfd_vma, bfd_byte *));
+  bfd_vma        (*bfd_getx32) PARAMS ((const bfd_byte *));
+  bfd_signed_vma (*bfd_getx_signed_32) PARAMS ((const bfd_byte *));
+  void           (*bfd_putx32) PARAMS ((bfd_vma, bfd_byte *));
+  bfd_vma        (*bfd_getx16) PARAMS ((const bfd_byte *));
+  bfd_signed_vma (*bfd_getx_signed_16) PARAMS ((const bfd_byte *));
+  void           (*bfd_putx16) PARAMS ((bfd_vma, bfd_byte *));
+  bfd_vma        (*bfd_h_getx64) PARAMS ((const bfd_byte *));
+  bfd_signed_vma (*bfd_h_getx_signed_64) PARAMS ((const bfd_byte *));
+  void           (*bfd_h_putx64) PARAMS ((bfd_vma, bfd_byte *));
+  bfd_vma        (*bfd_h_getx32) PARAMS ((const bfd_byte *));
+  bfd_signed_vma (*bfd_h_getx_signed_32) PARAMS ((const bfd_byte *));
+  void           (*bfd_h_putx32) PARAMS ((bfd_vma, bfd_byte *));
+  bfd_vma        (*bfd_h_getx16) PARAMS ((const bfd_byte *));
+  bfd_signed_vma (*bfd_h_getx_signed_16) PARAMS ((const bfd_byte *));
+  void           (*bfd_h_putx16) PARAMS ((bfd_vma, bfd_byte *));
+  const struct bfd_target *(*_bfd_check_format[bfd_type_end]) PARAMS ((bfd *));
+  boolean  (*_bfd_set_format[bfd_type_end]) PARAMS ((bfd *));
+  boolean  (*_bfd_write_contents[bfd_type_end]) PARAMS ((bfd *));
+
+  /* Generic entry points.  */
+#define BFD_JUMP_TABLE_GENERIC(NAME) \
+CONCAT2 (NAME,_close_and_cleanup), \
+CONCAT2 (NAME,_bfd_free_cached_info), \
+CONCAT2 (NAME,_new_section_hook), \
+CONCAT2 (NAME,_get_section_contents), \
+CONCAT2 (NAME,_get_section_contents_in_window)
+
+  /* Called when the BFD is being closed to do any necessary cleanup.  */
+  boolean  (*_close_and_cleanup) PARAMS ((bfd *));
+  /* Ask the BFD to free all cached information.  */
+  boolean  (*_bfd_free_cached_info) PARAMS ((bfd *));
+  /* Called when a new section is created.  */
+  boolean  (*_new_section_hook) PARAMS ((bfd *, sec_ptr));
+  /* Read the contents of a section.  */
+  boolean  (*_bfd_get_section_contents) PARAMS ((bfd *, sec_ptr, PTR,
+                                                 file_ptr, bfd_size_type));
+  boolean  (*_bfd_get_section_contents_in_window)
+    PARAMS ((bfd *, sec_ptr, bfd_window *, file_ptr, bfd_size_type));
+
+  /* Entry points to copy private data.  */
+#define BFD_JUMP_TABLE_COPY(NAME) \
+CONCAT2 (NAME,_bfd_copy_private_bfd_data), \
+CONCAT2 (NAME,_bfd_merge_private_bfd_data), \
+CONCAT2 (NAME,_bfd_copy_private_section_data), \
+CONCAT2 (NAME,_bfd_copy_private_symbol_data), \
+CONCAT2 (NAME,_bfd_set_private_flags), \
+CONCAT2 (NAME,_bfd_print_private_bfd_data) \
+  /* Called to copy BFD general private data from one object file
+     to another.  */
+  boolean  (*_bfd_copy_private_bfd_data) PARAMS ((bfd *, bfd *));
+  /* Called to merge BFD general private data from one object file
+     to a common output file when linking.  */
+  boolean  (*_bfd_merge_private_bfd_data) PARAMS ((bfd *, bfd *));
+  /* Called to copy BFD private section data from one object file
+     to another.  */
+  boolean  (*_bfd_copy_private_section_data) PARAMS ((bfd *, sec_ptr,
+                                                      bfd *, sec_ptr));
+  /* Called to copy BFD private symbol data from one symbol
+     to another.  */
+  boolean  (*_bfd_copy_private_symbol_data) PARAMS ((bfd *, asymbol *,
+                                                     bfd *, asymbol *));
+  /* Called to set private backend flags */
+  boolean  (*_bfd_set_private_flags) PARAMS ((bfd *, flagword));
+
+  /* Called to print private BFD data */
+  boolean  (*_bfd_print_private_bfd_data) PARAMS ((bfd *, PTR));
+
+  /* Core file entry points.  */
+#define BFD_JUMP_TABLE_CORE(NAME) \
+CONCAT2 (NAME,_core_file_failing_command), \
+CONCAT2 (NAME,_core_file_failing_signal), \
+CONCAT2 (NAME,_core_file_matches_executable_p)
+  char *   (*_core_file_failing_command) PARAMS ((bfd *));
+  int      (*_core_file_failing_signal) PARAMS ((bfd *));
+  boolean  (*_core_file_matches_executable_p) PARAMS ((bfd *, bfd *));
+
+  /* Archive entry points.  */
+#define BFD_JUMP_TABLE_ARCHIVE(NAME) \
+CONCAT2 (NAME,_slurp_armap), \
+CONCAT2 (NAME,_slurp_extended_name_table), \
+CONCAT2 (NAME,_construct_extended_name_table), \
+CONCAT2 (NAME,_truncate_arname), \
+CONCAT2 (NAME,_write_armap), \
+CONCAT2 (NAME,_read_ar_hdr), \
+CONCAT2 (NAME,_openr_next_archived_file), \
+CONCAT2 (NAME,_get_elt_at_index), \
+CONCAT2 (NAME,_generic_stat_arch_elt), \
+CONCAT2 (NAME,_update_armap_timestamp)
+  boolean  (*_bfd_slurp_armap) PARAMS ((bfd *));
+  boolean  (*_bfd_slurp_extended_name_table) PARAMS ((bfd *));
+  boolean  (*_bfd_construct_extended_name_table)
+    PARAMS ((bfd *, char **, bfd_size_type *, const char **));
+  void     (*_bfd_truncate_arname) PARAMS ((bfd *, const char *, char *));
+  boolean  (*write_armap)
+    PARAMS ((bfd *, unsigned int, struct orl *, unsigned int, int));
+  PTR      (*_bfd_read_ar_hdr_fn) PARAMS ((bfd *));
+  bfd *    (*openr_next_archived_file) PARAMS ((bfd *, bfd *));
+#define bfd_get_elt_at_index(b,i) BFD_SEND(b, _bfd_get_elt_at_index, (b,i))
+  bfd *    (*_bfd_get_elt_at_index) PARAMS ((bfd *, symindex));
+  int      (*_bfd_stat_arch_elt) PARAMS ((bfd *, struct stat *));
+  boolean  (*_bfd_update_armap_timestamp) PARAMS ((bfd *));
+
+  /* Entry points used for symbols.  */
+#define BFD_JUMP_TABLE_SYMBOLS(NAME) \
+CONCAT2 (NAME,_get_symtab_upper_bound), \
+CONCAT2 (NAME,_get_symtab), \
+CONCAT2 (NAME,_make_empty_symbol), \
+CONCAT2 (NAME,_print_symbol), \
+CONCAT2 (NAME,_get_symbol_info), \
+CONCAT2 (NAME,_bfd_is_local_label_name), \
+CONCAT2 (NAME,_get_lineno), \
+CONCAT2 (NAME,_find_nearest_line), \
+CONCAT2 (NAME,_bfd_make_debug_symbol), \
+CONCAT2 (NAME,_read_minisymbols), \
+CONCAT2 (NAME,_minisymbol_to_symbol)
+  long     (*_bfd_get_symtab_upper_bound) PARAMS ((bfd *));
+  long     (*_bfd_canonicalize_symtab) PARAMS ((bfd *,
+                                                struct symbol_cache_entry **));
+  struct symbol_cache_entry *
+           (*_bfd_make_empty_symbol) PARAMS ((bfd *));
+  void     (*_bfd_print_symbol) PARAMS ((bfd *, PTR,
+                                         struct symbol_cache_entry *,
+                                         bfd_print_symbol_type));
+#define bfd_print_symbol(b,p,s,e) BFD_SEND(b, _bfd_print_symbol, (b,p,s,e))
+  void     (*_bfd_get_symbol_info) PARAMS ((bfd *,
+                                            struct symbol_cache_entry *,
+                                            symbol_info *));
+#define bfd_get_symbol_info(b,p,e) BFD_SEND(b, _bfd_get_symbol_info, (b,p,e))
+  boolean  (*_bfd_is_local_label_name) PARAMS ((bfd *, const char *));
+
+  alent *  (*_get_lineno) PARAMS ((bfd *, struct symbol_cache_entry *));
+  boolean  (*_bfd_find_nearest_line)
+    PARAMS ((bfd *, struct sec *, struct symbol_cache_entry **, bfd_vma,
+             const char **, const char **, unsigned int *));
+ /* Back-door to allow format-aware applications to create debug symbols
+    while using BFD for everything else.  Currently used by the assembler
+    when creating COFF files.  */
+  asymbol *(*_bfd_make_debug_symbol) PARAMS ((bfd *, void *,
+                                              unsigned long size));
+#define bfd_read_minisymbols(b, d, m, s) \
+  BFD_SEND (b, _read_minisymbols, (b, d, m, s))
+  long     (*_read_minisymbols) PARAMS ((bfd *, boolean, PTR *,
+                                         unsigned int *));
+#define bfd_minisymbol_to_symbol(b, d, m, f) \
+  BFD_SEND (b, _minisymbol_to_symbol, (b, d, m, f))
+  asymbol *(*_minisymbol_to_symbol) PARAMS ((bfd *, boolean, const PTR,
+                                             asymbol *));
+
+  /* Routines for relocs.  */
+#define BFD_JUMP_TABLE_RELOCS(NAME) \
+CONCAT2 (NAME,_get_reloc_upper_bound), \
+CONCAT2 (NAME,_canonicalize_reloc), \
+CONCAT2 (NAME,_bfd_reloc_type_lookup)
+  long     (*_get_reloc_upper_bound) PARAMS ((bfd *, sec_ptr));
+  long     (*_bfd_canonicalize_reloc) PARAMS ((bfd *, sec_ptr, arelent **,
+                                               struct symbol_cache_entry **));
+  /* See documentation on reloc types.  */
+  reloc_howto_type *
+           (*reloc_type_lookup) PARAMS ((bfd *, bfd_reloc_code_real_type));
+
+  /* Routines used when writing an object file.  */
+#define BFD_JUMP_TABLE_WRITE(NAME) \
+CONCAT2 (NAME,_set_arch_mach), \
+CONCAT2 (NAME,_set_section_contents)
+  boolean  (*_bfd_set_arch_mach) PARAMS ((bfd *, enum bfd_architecture,
+                                          unsigned long));
+  boolean  (*_bfd_set_section_contents) PARAMS ((bfd *, sec_ptr, PTR,
+                                                 file_ptr, bfd_size_type));
+
+  /* Routines used by the linker.  */
+#define BFD_JUMP_TABLE_LINK(NAME) \
+CONCAT2 (NAME,_sizeof_headers), \
+CONCAT2 (NAME,_bfd_get_relocated_section_contents), \
+CONCAT2 (NAME,_bfd_relax_section), \
+CONCAT2 (NAME,_bfd_link_hash_table_create), \
+CONCAT2 (NAME,_bfd_link_add_symbols), \
+CONCAT2 (NAME,_bfd_final_link), \
+CONCAT2 (NAME,_bfd_link_split_section), \
+CONCAT2 (NAME,_bfd_gc_sections), \
+CONCAT2 (NAME,_bfd_merge_sections)
+  int      (*_bfd_sizeof_headers) PARAMS ((bfd *, boolean));
+  bfd_byte *(*_bfd_get_relocated_section_contents)
+    PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_order *,
+             bfd_byte *, boolean, struct symbol_cache_entry **));
+
+  boolean  (*_bfd_relax_section)
+    PARAMS ((bfd *, struct sec *, struct bfd_link_info *, boolean *));
+
+  /* Create a hash table for the linker.  Different backends store
+     different information in this table.  */
+  struct bfd_link_hash_table *(*_bfd_link_hash_table_create) PARAMS ((bfd *));
+
+  /* Add symbols from this object file into the hash table.  */
+  boolean  (*_bfd_link_add_symbols) PARAMS ((bfd *, struct bfd_link_info *));
+
+  /* Do a link based on the link_order structures attached to each
+     section of the BFD.  */
+  boolean  (*_bfd_final_link) PARAMS ((bfd *, struct bfd_link_info *));
+
+  /* Should this section be split up into smaller pieces during linking.  */
+  boolean  (*_bfd_link_split_section) PARAMS ((bfd *, struct sec *));
+
+  /* Remove sections that are not referenced from the output.  */
+  boolean  (*_bfd_gc_sections) PARAMS ((bfd *, struct bfd_link_info *));
+
+  /* Attempt to merge SEC_MERGE sections.  */
+  boolean  (*_bfd_merge_sections) PARAMS ((bfd *, struct bfd_link_info *));
+
+  /* Routines to handle dynamic symbols and relocs.  */
+#define BFD_JUMP_TABLE_DYNAMIC(NAME) \
+CONCAT2 (NAME,_get_dynamic_symtab_upper_bound), \
+CONCAT2 (NAME,_canonicalize_dynamic_symtab), \
+CONCAT2 (NAME,_get_dynamic_reloc_upper_bound), \
+CONCAT2 (NAME,_canonicalize_dynamic_reloc)
+  /* Get the amount of memory required to hold the dynamic symbols. */
+  long     (*_bfd_get_dynamic_symtab_upper_bound) PARAMS ((bfd *));
+  /* Read in the dynamic symbols.  */
+  long     (*_bfd_canonicalize_dynamic_symtab)
+    PARAMS ((bfd *, struct symbol_cache_entry **));
+  /* Get the amount of memory required to hold the dynamic relocs.  */
+  long     (*_bfd_get_dynamic_reloc_upper_bound) PARAMS ((bfd *));
+  /* Read in the dynamic relocs.  */
+  long     (*_bfd_canonicalize_dynamic_reloc)
+    PARAMS ((bfd *, arelent **, struct symbol_cache_entry **));
+
+ /* Opposite endian version of this target.  */
+ const struct bfd_target * alternative_target;
+
+ PTR backend_data;
+
+} bfd_target;
+boolean
+bfd_set_default_target PARAMS ((const char *name));
+
+const bfd_target *
+bfd_find_target PARAMS ((const char *target_name, bfd *abfd));
+
+const char **
+bfd_target_list PARAMS ((void));
+
+const bfd_target *
+bfd_search_for_target PARAMS ((int (* search_func) (const bfd_target *, void *), void *));
+
+boolean
+bfd_check_format PARAMS ((bfd *abfd, bfd_format format));
+
+boolean
+bfd_check_format_matches PARAMS ((bfd *abfd, bfd_format format, char ***matching));
+
+boolean
+bfd_set_format PARAMS ((bfd *abfd, bfd_format format));
+
+const char *
+bfd_format_string PARAMS ((bfd_format format));
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff -urN linux-2.4.21-pre3/arch/ppc64/kdb/genkallsyms.pl linux-2.4.21-pre4/arch/ppc64/kdb/genkallsyms.pl
--- linux-2.4.21-pre3/arch/ppc64/kdb/genkallsyms.pl	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/arch/ppc64/kdb/genkallsyms.pl	Tue Jan 28 19:44:29 2003
@@ -0,0 +1,226 @@
+#!/usr/bin/perl -w
+# File genkallsyms.pl created by Todd Inglett at 07:56:04 on Mon Apr 30 2001. 
+# use Math::BigInt;
+
+my $me = "genkallsyms";
+my $objdump = "objdump";
+my $outfile;
+my $objfile;
+my $verbose = 0;
+my $dummy = 0;
+
+my %sections;		# indexed by sect name.  Value is [Name, Size, Addr, Name_off, Sect_idx]
+my $sectlist;		# same section references in a list.
+my $nextsect = 0;	# index of next free section in sectlist.
+
+my @symbols;		# Value is [Name, sec_ref, Addr, Name_off]
+my $nextsym = 0;	# index of next free symbol
+my $strtablen = 0;	# string table length.
+
+# my $shift32multiplier = Math::BigInt->new(2**30) * 4;  # 2**32 without going floating point
+
+#
+# Parse the cmdline options
+#
+my $arg;
+while (defined($arg = shift)) {
+    if ($arg eq '-objdump') {
+	$objdump = shift;
+    } elsif ($arg eq '-o') {
+	$outfile = shift;
+    } elsif ($arg eq '-h') {
+	usage();
+    } elsif ($arg eq '-v') {
+	$verbose = 1;
+    } elsif ($arg eq '-dummy') {
+	$dummy = 1;
+    } elsif ($arg !~ m/^-/) {
+	unshift @ARGV, $arg;
+	last;
+    } else {
+	die "$me: unknown option $arg\n";
+    }
+}
+
+usage() unless ($#ARGV == 0 || $dummy);
+$objfile = $ARGV[0];	# typically vmlinux
+
+if ($verbose) {
+    print "outfile=$outfile\n";
+    print "objdump=$objdump\n";
+    print "objfile=$objfile\n";
+}
+( $dummy || -r $objfile ) or die "$me: cannot read $objfile: $!\n";
+
+
+if (!$dummy) {
+    #
+    # Read the section table from objdump -h into hash
+    # %sections.  Each entry is [Name, Size, Addr, Name_Off, Sect_idx] and
+    # the hash is indexed by Name.
+    #
+    open(S, "$objdump -h $objfile 2>&1 |") or die "$me: cannot $objdump -h $objfile: $!\n";
+    my $sline;
+    while (defined($sline = <S>)) {
+	chomp($sline);
+	$sline =~ s/^\s*//;
+	next unless $sline =~ m/^[0-9]/;
+	my ($idx, $name, $size, $vma, $rest) = split(/\s+/, $sline, 5);
+	print "name=$name, size=$size, vma=$vma\n" if $verbose;
+	$sectlist[$nextsect] = [$name, $size, $vma, 0, 0];
+	$sections{$name} = $sectlist[$nextsect++];
+    }
+    close(S);
+    print "$me: processed $nextsect sections\n" if $verbose;
+
+    # Sort by start addr for readability.  This is not required.
+    @sectlist = sort { $a->[2] cmp $b->[2] } @sectlist;
+    for (my $i = 0; $i < $nextsect; $i++) {
+	$sectlist[$i]->[4] = $i;	# Sect_Idx
+    }
+
+    #
+    # Now read the symbol table from objdump -t
+    #
+    open(S, "$objdump -t $objfile 2>&1 |") or die "$me: cannot $objdump -t $objfile: $!\n";
+    while (defined($sline = <S>)) {
+	last if $sline =~ m/^SYMBOL/;
+    }
+    while (defined($sline = <S>)) {
+	chomp($sline);
+	my ($addr, $foo, $type, $sect, $val, $name) = split(/\s+/, $sline);
+	# Now type might be empty.
+	if (!defined($name)) {
+	    $name = $val;
+	    $val = $sect;
+	    $sect = $type;
+	    $type = " ";
+	}
+	# Weed out symbols which are not useful.
+	next if !$name;
+	next if $sect eq ".rodata"; # TOC entries, I think.
+	next if $sect eq "*ABS*";
+	next if $name =~ m/^LC?\.\./;
+	# print "$addr,$type,$sect,$val,$name\n" if $verbose;
+	my $sec_ref = $sections{$sect};
+	$symbols[$nextsym++] = [$name, $sec_ref, $addr, 0];
+    }
+    close(S);
+    print "$me: processed $nextsym symbols\n" if $verbose;
+    # Sort by addr for readability.  This is not required.
+    @symbols = sort { $a->[2] cmp $b->[2] } @symbols;
+
+    #
+    # Now that everything is sorted, we need to assign space for
+    # each string in the string table.
+    #
+    for (my $i = 0; $i < $nextsect; $i++) {
+	my $len = length($sectlist[$i]->[0]);
+	$sectlist[$i]->[3] = $strtablen;
+	$strtablen += $len+1;
+    }
+    for (my $i = 0; $i < $nextsym; $i++) {
+	my $len = length($symbols[$i]->[0]);
+	$symbols[$i]->[3] = $strtablen;
+	$strtablen += $len+1;
+    }
+}
+
+if ($outfile) {
+    open(OUT, ">$outfile") or die "$me:  cannot open $outfile for write: $!\n";
+} else {
+    open(OUT, ">&STDOUT");
+}
+
+if ($dummy) {
+    # Produce dummy output and exit.
+    print OUT "long __start___kallsyms = 0;\n";
+    print OUT "long __stop___kallsyms = 0;\n";
+    exit 0;
+}
+
+print OUT "#include <stddef.h>\n";
+print OUT "#include <linux/kallsyms.h>\n\n";
+print OUT "#define NUM_SECTIONS\t\t", int(keys %sections), "\n";
+print OUT "#define NUM_SYMBOLS\t\t", $nextsym, "\n";
+print OUT "#define NUM_STRING_CHARS\t", $strtablen, "\n";
+print OUT "#define FIRST_SECTION_ADDR\t0x", $sectlist[0]->[2], "UL /* section ", $sectlist[0]->[0], " */\n";
+print OUT "#define LAST_SECTION_ADDR\t0x", $sectlist[$nextsect-1]->[2], "UL + 0x", $sectlist[$nextsect-1]->[1], "UL /* section ", $sectlist[$nextsect-1]->[0], " */\n";
+print OUT <<EOF;
+
+#define SOFF(secidx) (sizeof(struct kallsyms_section)*secidx)
+typedef struct kdata {
+	struct kallsyms_header hdr;
+	struct kallsyms_section sections[NUM_SECTIONS];
+	struct kallsyms_symbol symbols[NUM_SYMBOLS];
+	const char strings[NUM_STRING_CHARS];
+} kdata_t;
+
+kdata_t __start___kallsyms = {
+  {	/* kallsyms_header */
+	sizeof(struct kallsyms_header),	/* Size of this header */
+	sizeof(kdata_t),		/* Total size of kallsyms data */
+	NUM_SECTIONS,			/* Number of section entries */
+	offsetof(kdata_t, sections),	/* Offset to first section entry */
+	sizeof(struct kallsyms_section),/* Size of one section entry */
+	NUM_SYMBOLS,			/* Number of symbol entries */
+	offsetof(kdata_t, symbols),	/* Offset to first symbol entry */
+	sizeof(struct kallsyms_symbol),	/* Size of one symbol entry */
+	offsetof(kdata_t, strings),	/* Offset to first string */
+	FIRST_SECTION_ADDR,		/* Start address of first section */
+	LAST_SECTION_ADDR,		/* End address of last section */
+  },
+  {	/* kallsyms_section table */
+	/* start_addr, size, name_off, flags */
+EOF
+
+for (my $i = 0; $i < $nextsect; $i++) {
+    my $sectref = $sectlist[$i];
+    print OUT "\t{0x", $sectref->[2], "UL, 0x", $sectref->[1], ", ", $sectref->[3], "},\t /* [$i] ", $sectref->[0], " */\n";
+}
+
+print OUT <<EOF;
+  },
+  {	/* kallsyms_symbol table */
+	/* section_off, addr, name_off */
+EOF
+
+for (my $i = 0; $i < $nextsym; $i++) {
+    my $symref = $symbols[$i];
+    my $secref = $symref->[1];
+    print OUT "\t{SOFF(", $secref->[4], "), 0x", $symref->[2], "UL, ", $symref->[3], "},  /* ", $symref->[0], " */\n";
+}
+
+print OUT <<EOF;
+  },
+  /* string table */ ""
+EOF
+
+for (my $i = 0; $i < $nextsect; $i++) {
+    my $sectref = $sectlist[$i];
+    print OUT "\t\"", $sectref->[0], "\\0\"\t/* ", $sectref->[3], " */\n";
+}
+for (my $i = 0; $i < $nextsym; $i++) {
+    my $symref = $symbols[$i];
+    print OUT "\t\"", $symref->[0], "\\0\"\t/* ", $symref->[3], " */\n";
+}
+
+
+print OUT <<EOF;
+};
+
+long __stop___kallsyms = 0;
+EOF
+
+sub usage {
+    die "Usage:  genkallsyms [-h] -objdump /path/to/objdump -o _ksyms.c vmlinux\n";
+}
+
+# Return a BigInt given a 64bit hex number (without a leading 0x)..
+# The number is assumed to be 16 chars long.
+#sub bighex {
+#    my ($hexstr) = @_;
+#    my $bighi = Math::BigInt->new(hex(substr($hexstr, 0, 8)));
+#    my $biglow = Math::BigInt->new(hex(substr($hexstr, 8, 8)));
+#    return $bighi * $shift32multiplier + $biglow;
+#}
diff -urN linux-2.4.21-pre3/arch/ppc64/kdb/kdba_bp.c linux-2.4.21-pre4/arch/ppc64/kdb/kdba_bp.c
--- linux-2.4.21-pre3/arch/ppc64/kdb/kdba_bp.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/arch/ppc64/kdb/kdba_bp.c	Tue Jan 28 19:44:29 2003
@@ -0,0 +1,733 @@
+/*
+ * Kernel Debugger Architecture Dependent Breakpoint Handling
+ *
+ * Copyright (C) 1999 Silicon Graphics, Inc.
+ * Copyright (C) Scott Lurndal (slurn@engr.sgi.com)
+ * Copyright (C) Scott Foehner (sfoehner@engr.sgi.com)
+ * Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com)
+ *
+ * See the file LIA-COPYRIGHT for additional information.
+ *
+ * Written March 1999 by Scott Lurndal at Silicon Graphics, Inc.
+ *
+ * Modifications from:
+ *      Richard Bass                    1999/07/20
+ *              Many bug fixes and enhancements.
+ *      Scott Foehner
+ *              Port to ia64
+ *	Scott Lurndal			1999/12/12
+ *		v1.0 restructuring.
+ *	Keith Owens			2000/05/23
+ *		KDB v1.2
+ */
+
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/ptrace.h>
+#include <linux/kdb.h>
+#include <linux/kdbprivate.h>
+#include "privinst.h"
+
+static char *kdba_rwtypes[] = { "Instruction(Register)", "Data Write",
+			"I/O", "Data Access"};
+
+/*
+ * Table describing processor architecture hardware
+ * breakpoint registers.
+ */
+
+kdbhard_bp_t	kdb_hardbreaks[KDB_MAXHARDBPT];
+
+/*
+ * kdba_db_trap
+ *
+ * 	Perform breakpoint processing upon entry to the
+ *	processor debugger fault.   Determine and print
+ *	the active breakpoint.
+ *
+ * Parameters:
+ *	ef	Exception frame containing machine register state
+ *	error	Error number passed to kdb.
+ * Outputs:
+ *	None.
+ * Returns:
+ *	KDB_DB_BPT	Standard instruction or data breakpoint encountered
+ *	KDB_DB_SS	Single Step fault ('ss' command or end of 'ssb' command)
+ *	KDB_DB_SSB	Single Step fault, caller should continue ('ssb' command)
+ *	KDB_DB_SSBPT	Single step over breakpoint
+ *	KDB_DB_NOBPT	No existing kdb breakpoint matches this debug exception
+ * Locking:
+ *	None.
+ * Remarks:
+ *	Yup, there be goto's here.
+ *
+ *	If multiple processors receive debug exceptions simultaneously,
+ *	one may be waiting at the kdb fence in kdb() while the user
+ *	issues a 'bc' command to clear the breakpoint the processor
+ *	which is waiting has already encountered.  If this is the case,
+ *	the debug registers will no longer match any entry in the
+ *	breakpoint table, and we'll return the value KDB_DB_NOBPT.
+ *	This can cause a panic in die_if_kernel().  It is safer to
+ *	disable the breakpoint (bd), go until all processors are past
+ *	the breakpoint then clear the breakpoint (bc).  This code
+ *	recognises a breakpoint even when disabled but not when it has
+ *	been cleared.
+ *
+ *	WARNING: This routine clears the debug state.  It should be called
+ *		 once per debug and the result cached.
+ */
+
+kdb_dbtrap_t
+kdba_db_trap(kdb_eframe_t ef, int error_unused)
+{
+	kdb_machreg_t  msr,trap;
+	int rw, reg;
+	int i;
+	kdb_dbtrap_t rv = KDB_DB_BPT;
+	kdb_bp_t *bp;
+
+	msr = get_msr();
+	trap = ef->trap;
+	if (KDB_DEBUG(BP))
+		kdb_printf("kdb: msr 0x%lx trap 0x%lx\n", msr,trap);
+	if (msr & MSR_SE || ((trap & 0x700) || (trap & 0xd00))) 
+	{
+		if (KDB_STATE(SSBPT)) {
+			if (KDB_DEBUG(BP))
+				kdb_printf("ssbpt\n");
+			KDB_STATE_CLEAR(SSBPT);
+			for(i=0,bp=kdb_breakpoints;
+			    i < KDB_MAXBPT;
+			    i++, bp++) {
+				if (KDB_DEBUG(BP))
+					kdb_printf("bp 0x%p enabled %d delayed %d global %d cpu %d\n",
+						   bp, bp->bp_enabled, bp->bp_delayed, bp->bp_global, bp->bp_cpu);
+				if (!bp->bp_enabled)
+					continue;
+				if (!bp->bp_global && bp->bp_cpu != smp_processor_id())
+					continue;
+				if (KDB_DEBUG(BP))
+					kdb_printf("bp for this cpu\n");
+				if (bp->bp_delayed) {
+					bp->bp_delayed = 0;
+					if (KDB_DEBUG(BP))
+						kdb_printf("kdba_installbp\n");
+					kdba_installbp(ef, bp);
+					if (!KDB_STATE(DOING_SS)) {
+						set_msr(get_msr() & ~MSR_SE);
+						return(KDB_DB_SSBPT);
+					}
+					break;
+				}
+			}
+			if (i == KDB_MAXBPT) {
+				kdb_printf("kdb: Unable to find delayed breakpoint\n");
+			}
+			if (!KDB_STATE(DOING_SS)) {
+				set_msr(get_msr() & ~MSR_SE);
+				return(KDB_DB_NOBPT);
+			}
+			/* FALLTHROUGH */
+		}
+
+		/*
+		 * KDB_STATE_DOING_SS is set when the kernel debugger is using
+		 * the processor trap flag to single-step a processor.  If a
+		 * single step trap occurs and this flag is clear, the SS trap
+		 * will be ignored by KDB and the kernel will be allowed to deal
+		 * with it as necessary (e.g. for ptrace).
+		 */
+		if (!KDB_STATE(DOING_SS))
+			goto unknown;
+
+		/* single step */
+		rv = KDB_DB_SS;		/* Indicate single step */
+		if (KDB_STATE(DOING_SSB)) {
+
+			kdb_id1(ef->nip);
+			rv = KDB_DB_SSB; /* Indicate ssb - dismiss immediately */
+		} else {
+			/*
+			 * Print current insn
+			 */
+			kdb_printf("SS trap at ");
+			kdb_symbol_print(ef->nip, NULL, KDB_SP_DEFAULT|KDB_SP_NEWLINE);
+			kdb_id1(ef->nip);
+			KDB_STATE_CLEAR(DOING_SS);
+		}
+
+		if (rv != KDB_DB_SSB)
+			set_msr(get_msr() & ~MSR_SE);
+	}
+	if (rv > 0)
+		goto handled;
+	
+	goto handle;
+
+
+handle:
+
+	/*
+	 * Determine which breakpoint was encountered.
+	 */
+	for(i=0, bp=kdb_breakpoints; i<KDB_MAXBPT; i++, bp++) {
+		if (!(bp->bp_free)
+		 && (bp->bp_global || bp->bp_cpu == smp_processor_id())
+		 && (bp->bp_hard)
+		 && (bp->bp_hard->bph_reg == reg)) {
+			/*
+			 * Hit this breakpoint.
+			 */
+//			kdb_printf("%s breakpoint #%d at " kdb_bfd_vma_fmt "\n",
+			kdb_printf("%s breakpoint #%d at 0x%ld\n",
+				  kdba_rwtypes[rw],
+				  i, (long )bp->bp_addr);
+
+			/*
+			 * For an instruction breakpoint, disassemble
+			 * the current instruction.
+			 */
+			if (rw == 0) {
+				kdb_id1(ef->nip);
+			}
+
+			goto handled;
+		}
+	}
+
+unknown:
+	rv = KDB_DB_NOBPT;	/* Cause kdb() to return */
+
+handled:
+
+
+	return rv;
+}
+
+/*
+ * kdba_bp_trap
+ *
+ * 	Perform breakpoint processing upon entry to the
+ *	processor breakpoint instruction fault.   Determine and print
+ *	the active breakpoint.
+ *
+ * Parameters:
+ *	ef	Exception frame containing machine register state
+ *	error	Error number passed to kdb.
+ * Outputs:
+ *	None.
+ * Returns:
+ *	0	Standard instruction or data breakpoint encountered
+ *	1	Single Step fault ('ss' command)
+ *	2	Single Step fault, caller should continue ('ssb' command)
+ *	3	No existing kdb breakpoint matches this debug exception
+ * Locking:
+ *	None.
+ * Remarks:
+ *
+ * 	If multiple processors receive debug exceptions simultaneously,
+ *	one may be waiting at the kdb fence in kdb() while the user
+ *	issues a 'bc' command to clear the breakpoint the processor which
+ * 	is waiting has already encountered.   If this is the case, the
+ *	debug registers will no longer match any entry in the breakpoint
+ *	table, and we'll return the value '3'.  This can cause a panic
+ *	in die_if_kernel().  It is safer to disable the breakpoint (bd),
+ *	'go' until all processors are past the breakpoint then clear the
+ *	breakpoint (bc).  This code recognises a breakpoint even when
+ *	disabled but not when it has been cleared.
+ *
+ *	WARNING: This routine resets the eip.  It should be called
+ *		 once per breakpoint and the result cached.
+ */
+
+kdb_dbtrap_t
+kdba_bp_trap(kdb_eframe_t ef, int error_unused)
+{
+	int i;
+	kdb_dbtrap_t rv;
+	kdb_bp_t *bp;
+
+	/*
+	 * Determine which breakpoint was encountered.
+	 */
+	if (KDB_DEBUG(BP))
+		kdb_printf("kdba_bp_trap: eip=0x%lx (not adjusted) "
+			   "msr=0x%lx trap=0x%lx ef=0x%p esp=0x%lx\n",
+			   ef->nip, ef->msr, ef->trap, ef, ef->gpr[1]);
+
+	rv = KDB_DB_NOBPT;	/* Cause kdb() to return */
+
+	for(i=0, bp=kdb_breakpoints; i<KDB_MAXBPT; i++, bp++) {
+		if (bp->bp_free)
+			continue;
+		if (!bp->bp_global && bp->bp_cpu != smp_processor_id())
+			continue;
+		 if (bp->bp_addr == (ef->nip - bp->bp_adjust)) {
+			/* Hit this breakpoint.  */
+			ef->nip -= bp->bp_adjust;
+			kdb_printf("Instruction(i) breakpoint #%d at 0x%lx (adjusted)\n",
+				  i, ef->nip);
+			kdb_id1(ef->nip);
+			rv = KDB_DB_BPT;
+			bp->bp_delay = 1;
+			break;
+		}
+	}
+
+	return rv;
+}
+
+/*
+ * kdba_handle_bp
+ *
+ *	Handle an instruction-breakpoint trap.  Called when re-installing
+ *	an enabled breakpoint which has has the bp_delay bit set.
+ *
+ * Parameters:
+ * Returns:
+ * Locking:
+ * Remarks:
+ *
+ * Ok, we really need to:
+ *	1) Restore the original instruction byte
+ *	2) Single Step
+ *	3) Restore breakpoint instruction
+ *	4) Continue.
+ *
+ *
+ */
+
+static void
+kdba_handle_bp(kdb_eframe_t ef, kdb_bp_t *bp)
+{
+	if (!ef) {
+		kdb_printf("kdba_handle_bp: ef == NULL\n");
+		return;
+	}
+
+	if (KDB_DEBUG(BP))
+		kdb_printf("ef->eip = 0x%lx\n", ef->nip);
+
+	/*
+	 * Setup single step
+	 */
+	kdba_setsinglestep(ef);
+
+	/* KDB_STATE_SSBPT is set when the kernel debugger must single step
+	 * a task in order to re-establish an instruction breakpoint which
+	 * uses the instruction replacement mechanism. 
+	 */
+	KDB_STATE_SET(SSBPT);
+
+	/*
+	 * Reset delay attribute
+	 */
+	bp->bp_delay = 0;
+	bp->bp_delayed = 1;
+}
+
+
+/*
+ * kdba_bptype
+ *
+ *	Return a string describing type of breakpoint.
+ *
+ * Parameters:
+ *	bph	Pointer to hardware breakpoint description
+ * Outputs:
+ *	None.
+ * Returns:
+ *	Character string.
+ * Locking:
+ *	None.
+ * Remarks:
+ */
+
+char *
+kdba_bptype(kdbhard_bp_t *bph)
+{
+	char *mode;
+
+	mode = kdba_rwtypes[bph->bph_mode];
+
+	return mode;
+}
+
+/*
+ * kdba_printbpreg
+ *
+ *	Print register name assigned to breakpoint
+ *
+ * Parameters:
+ *	bph	Pointer hardware breakpoint structure
+ * Outputs:
+ *	None.
+ * Returns:
+ *	None.
+ * Locking:
+ *	None.
+ * Remarks:
+ */
+
+void
+kdba_printbpreg(kdbhard_bp_t *bph)
+{
+	kdb_printf(" in dr%ld", bph->bph_reg);
+}
+
+/*
+ * kdba_printbp
+ *
+ *	Print string describing hardware breakpoint.
+ *
+ * Parameters:
+ *	bph	Pointer to hardware breakpoint description
+ * Outputs:
+ *	None.
+ * Returns:
+ *	None.
+ * Locking:
+ *	None.
+ * Remarks:
+ */
+
+void
+kdba_printbp(kdb_bp_t *bp)
+{
+	kdb_printf("\n    is enabled");
+	if (bp->bp_hardtype) {
+		kdba_printbpreg(bp->bp_hard);
+		if (bp->bp_hard->bph_mode != 0) {
+			kdb_printf(" for %d bytes",
+				   bp->bp_hard->bph_length+1);
+		}
+	}
+}
+
+/*
+ * kdba_parsebp
+ *
+ *	Parse architecture dependent portion of the
+ *	breakpoint command.
+ *
+ * Parameters:
+ *	None.
+ * Outputs:
+ *	None.
+ * Returns:
+ *	Zero for success, a kdb diagnostic for failure
+ * Locking:
+ *	None.
+ * Remarks:
+ *	for Ia32 architure, data access, data write and
+ *	I/O breakpoints are supported in addition to instruction
+ * 	breakpoints.
+ *
+ *	{datar|dataw|io|inst} [length]
+ */
+
+int
+kdba_parsebp(int argc, const char **argv, int *nextargp, kdb_bp_t *bp)
+{
+	int		nextarg = *nextargp;
+	int		diag;
+	kdbhard_bp_t 	*bph = &bp->bp_template;
+
+	bph->bph_mode = 0;		/* Default to instruction breakpoint */
+	bph->bph_length = 0;		/* Length must be zero for insn bp */
+	if ((argc + 1) != nextarg) {
+		if (strnicmp(argv[nextarg], "datar", sizeof("datar")) == 0) {
+			bph->bph_mode = 3;
+		} else if (strnicmp(argv[nextarg], "dataw", sizeof("dataw")) == 0) {
+			bph->bph_mode = 1;
+		} else if (strnicmp(argv[nextarg], "io", sizeof("io")) == 0) {
+			bph->bph_mode = 2;
+		} else if (strnicmp(argv[nextarg], "inst", sizeof("inst")) == 0) {
+			bph->bph_mode = 0;
+		} else {
+			return KDB_ARGCOUNT;
+		}
+
+		bph->bph_length = 3;	/* Default to 4 byte */
+
+		nextarg++;
+
+		if ((argc + 1) != nextarg) {
+			unsigned long len;
+
+			diag = kdbgetularg((char *)argv[nextarg],
+					   &len);
+			if (diag)
+				return diag;
+
+
+			if ((len > 4) || (len == 3))
+				return KDB_BADLENGTH;
+
+			bph->bph_length = len;
+			bph->bph_length--; /* Normalize for debug register */
+			nextarg++;
+		}
+
+		if ((argc + 1) != nextarg)
+			return KDB_ARGCOUNT;
+
+		/*
+		 * Indicate to architecture independent level that
+		 * a hardware register assignment is required to enable
+		 * this breakpoint.
+		 */
+
+		bph->bph_free = 0;
+	} else {
+		if (KDB_DEBUG(BP))
+			kdb_printf("kdba_bp: no args, forcehw is %d\n", bp->bp_forcehw);
+		if (bp->bp_forcehw) {
+			/*
+			 * We are forced to use a hardware register for this
+			 * breakpoint because either the bph or bpha
+			 * commands were used to establish this breakpoint.
+			 */
+			bph->bph_free = 0;
+		} else {
+			/*
+			 * Indicate to architecture dependent level that
+			 * the instruction replacement breakpoint technique
+			 * should be used for this breakpoint.
+			 */
+			bph->bph_free = 1;
+			bp->bp_adjust = 1;	/* software, int 3 is one byte */
+		}
+	}
+
+	*nextargp = nextarg;
+	return 0;
+}
+
+/*
+ * kdba_allocbp
+ *
+ *	Associate a hardware register with a breakpoint.
+ *
+ * Parameters:
+ *	None.
+ * Outputs:
+ *	None.
+ * Returns:
+ *	A pointer to the allocated register kdbhard_bp_t structure for
+ *	success, Null and a non-zero diagnostic for failure.
+ * Locking:
+ *	None.
+ * Remarks:
+ */
+
+kdbhard_bp_t *
+kdba_allocbp(kdbhard_bp_t *bph, int *diagp)
+{
+	int i;
+	kdbhard_bp_t *newbph;
+
+	for(i=0,newbph=kdb_hardbreaks; i < KDB_MAXHARDBPT; i++, newbph++) {
+		if (newbph->bph_free) {
+			break;
+		}
+	}
+
+	if (i == KDB_MAXHARDBPT) {
+		*diagp = KDB_TOOMANYDBREGS;
+		return NULL;
+	}
+
+	*diagp = 0;
+
+	/*
+	 * Copy data from template.  Can't just copy the entire template
+	 * here because the register number in kdb_hardbreaks must be
+	 * preserved.
+	 */
+	newbph->bph_data = bph->bph_data;
+	newbph->bph_write = bph->bph_write;
+	newbph->bph_mode = bph->bph_mode;
+	newbph->bph_length = bph->bph_length;
+
+	/*
+	 * Mark entry allocated.
+	 */
+	newbph->bph_free = 0;
+
+	return newbph;
+}
+
+/*
+ * kdba_freebp
+ *
+ *	Deallocate a hardware breakpoint
+ *
+ * Parameters:
+ *	None.
+ * Outputs:
+ *	None.
+ * Returns:
+ *	Zero for success, a kdb diagnostic for failure
+ * Locking:
+ *	None.
+ * Remarks:
+ */
+
+void
+kdba_freebp(kdbhard_bp_t *bph)
+{
+	bph->bph_free = 1;
+}
+
+/*
+ * kdba_initbp
+ *
+ *	Initialize the breakpoint table for the hardware breakpoint
+ *	register.
+ *
+ * Parameters:
+ *	None.
+ * Outputs:
+ *	None.
+ * Returns:
+ *	Zero for success, a kdb diagnostic for failure
+ * Locking:
+ *	None.
+ * Remarks:
+ *
+ *	There is one entry per register.  On the ia32 architecture
+ *	all the registers are interchangeable, so no special allocation
+ *	criteria are required.
+ */
+
+void
+kdba_initbp(void)
+{
+	int i;
+	kdbhard_bp_t *bph;
+
+	/*
+	 * Clear the hardware breakpoint table
+	 */
+
+	memset(kdb_hardbreaks, '\0', sizeof(kdb_hardbreaks));
+
+	for(i=0,bph=kdb_hardbreaks; i<KDB_MAXHARDBPT; i++, bph++) {
+		bph->bph_reg = i;
+		bph->bph_free = 1;
+	}
+}
+
+/*
+ * kdba_installbp
+ *
+ *	Install a breakpoint
+ *
+ * Parameters:
+ *	ef	Exception frame
+ *	bp	Breakpoint structure for the breakpoint to be installed
+ * Outputs:
+ *	None.
+ * Returns:
+ *	None.
+ * Locking:
+ *	None.
+ * Remarks:
+ *	For hardware breakpoints, a debug register is allocated
+ *	and assigned to the breakpoint.  If no debug register is
+ *	available, a warning message is printed and the breakpoint
+ *	is disabled.
+ *
+ *	For instruction replacement breakpoints, we must single-step
+ *	over the replaced instruction at this point so we can re-install
+ *	the breakpoint instruction after the single-step.
+ */
+
+int
+kdba_installbp(kdb_eframe_t ef, kdb_bp_t *bp)
+{
+	/*
+	 * Install the breakpoint, if it is not already installed.
+	 */
+
+	if (KDB_DEBUG(BP)) {
+		kdb_printf("kdba_installbp bp_installed %d\n", bp->bp_installed);
+	}
+	if (!bp->bp_installed) {
+		if (bp->bp_hardtype) {
+			//kdba_installdbreg(bp);
+			bp->bp_installed = 1;
+			if (KDB_DEBUG(BP)) {
+				kdb_printf("kdba_installbp hardware reg %ld at " kdb_bfd_vma_fmt "\n",
+					   (long unsigned int) bp->bp_hard->bph_reg, (long unsigned int) bp->bp_addr);
+			}
+		} else if (bp->bp_delay) {
+			if (KDB_DEBUG(BP))
+				kdb_printf("kdba_installbp delayed bp\n");
+			kdba_handle_bp(ef, bp);
+		} else {
+			bp->bp_inst = kdb_getword((unsigned long *)bp->bp_addr, 1,sizeof(bp->bp_addr));
+#if 0
+			bp->bp_inst = kdba_getword(bp->bp_addr, 1);
+			kdba_putword(bp->bp_addr, 1, 0x7fe00008);
+#endif
+			kdb_putword(bp->bp_addr, 1, 0x7fe00008);
+			if (KDB_DEBUG(BP))
+				kdb_printf("kdba_installbp instruction 0x%x at " kdb_bfd_vma_fmt "\n",
+					   0x7fe00008, bp->bp_addr);
+			bp->bp_installed = 1;
+		}
+	}
+return 0;
+}
+
+/*
+ * kdba_removebp
+ *
+ *	Make a breakpoint ineffective.
+ *
+ * Parameters:
+ *	None.
+ * Outputs:
+ *	None.
+ * Returns:
+ *	None.
+ * Locking:
+ *	None.
+ * Remarks:
+ */
+
+int
+kdba_removebp(kdb_bp_t *bp)
+{
+	/*
+	 * For hardware breakpoints, remove it from the active register,
+	 * for software breakpoints, restore the instruction stream.
+	 */
+	if (KDB_DEBUG(BP)) {
+		kdb_printf("kdba_removebp bp_installed %d\n", bp->bp_installed);
+	}
+	if (bp->bp_installed) {
+		if (bp->bp_hardtype) {
+			if (KDB_DEBUG(BP)) {
+				kdb_printf("kdb: removing hardware reg %ld at " kdb_bfd_vma_fmt "\n",
+					   bp->bp_hard->bph_reg, bp->bp_addr);
+			}
+//			kdba_removedbreg(bp);
+		} else
+		{
+			if (KDB_DEBUG(BP))
+				kdb_printf("kdb: restoring instruction 0x%x at " kdb_bfd_vma_fmt "\n",
+					   bp->bp_inst, bp->bp_addr);
+#if 0
+			kdba_putword(bp->bp_addr, 1, bp->bp_inst);
+#endif
+			kdb_putword(bp->bp_addr, 1, bp->bp_inst);
+		}
+		bp->bp_installed = 0;
+	}
+return 0;
+}
diff -urN linux-2.4.21-pre3/arch/ppc64/kdb/kdba_bt.c linux-2.4.21-pre4/arch/ppc64/kdb/kdba_bt.c
--- linux-2.4.21-pre3/arch/ppc64/kdb/kdba_bt.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/arch/ppc64/kdb/kdba_bt.c	Tue Jan 28 19:44:29 2003
@@ -0,0 +1,280 @@
+/*
+ * Minimalist Kernel Debugger - Architecture Dependent Stack Traceback
+ *
+ * Copyright (C) 1999 Silicon Graphics, Inc.
+ * Copyright (C) Scott Lurndal (slurn@engr.sgi.com)
+ * Copyright (C) Scott Foehner (sfoehner@engr.sgi.com)
+ * Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com)
+ *
+ * See the file LIA-COPYRIGHT for additional information.
+ *
+ * Written March 1999 by Scott Lurndal at Silicon Graphics, Inc.
+ *
+ * Modifications from:
+ *      Richard Bass                    1999/07/20
+ *              Many bug fixes and enhancements.
+ *      Scott Foehner
+ *              Port to ia64
+ *      Srinivasa Thirumalachar
+ *              RSE support for ia64
+ *	Masahiro Adegawa                1999/12/01
+ *		'sr' command, active flag in 'ps'
+ *	Scott Lurndal			1999/12/12
+ *		Significantly restructure for linux2.3
+ *	Keith Owens			2000/05/23
+ *		KDB v1.2
+ *
+ */
+
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/kallsyms.h>
+#include <linux/kdb.h>
+#include <linux/kdbprivate.h>
+#include <linux/ptrace.h>	/* for STACK_FRAME_OVERHEAD */
+#include <asm/system.h>
+#include "privinst.h"
+
+void systemreset(struct pt_regs *regs)
+{
+	udbg_printf("Oh no!\n");
+	kdb_printf("Oh no!\n");
+	kdb(KDB_REASON_OOPS, 0, (kdb_eframe_t) regs);
+	for (;;);
+}
+
+/* human name vector lookup. */
+static
+const char *getvecname(unsigned long vec)
+{
+	char *ret;
+	switch (vec) {
+	case 0x100:	ret = "(System Reset)"; break; 
+	case 0x200:	ret = "(Machine Check)"; break; 
+	case 0x300:	ret = "(Data Access)"; break; 
+	case 0x400:	ret = "(Instruction Access)"; break; 
+	case 0x500:	ret = "(Hardware Interrupt)"; break; 
+	case 0x600:	ret = "(Alignment)"; break; 
+	case 0x700:	ret = "(Program Check)"; break; 
+	case 0x800:	ret = "(FPU Unavailable)"; break; 
+	case 0x900:	ret = "(Decrementer)"; break; 
+	case 0xc00:	ret = "(System Call)"; break; 
+	case 0xd00:	ret = "(Single Step)"; break; 
+	case 0xf00:	ret = "(Performance Monitor)"; break; 
+	default: ret = "";
+	}
+	return ret;
+}
+
+
+extern unsigned long kdba_getword(unsigned long addr, size_t width);
+
+/* Copy a block of memory using kdba_getword().
+ * This is not efficient.
+ */
+static void kdba_getmem(unsigned long addr, void *p, int size)
+{
+	unsigned char *dst = (unsigned char *)p;
+	while (size > 0) {
+		*dst++ = kdba_getword(addr++, 1);
+		size--;
+	}
+}
+
+
+/*
+ * kdba_bt_stack_ppc
+ *
+ *	kdba_bt_stack with ppc specific parameters.
+ *	Specification as kdba_bt_stack plus :-
+ *
+ * Inputs:
+ *	As kba_bt_stack plus
+ *	regs_esp If 1 get esp from the registers (exception frame), if 0
+ *		 get esp from kdba_getregcontents.
+ */
+
+static int
+kdba_bt_stack_ppc(struct pt_regs *regs, kdb_machreg_t *addr, int argcount,
+		   struct task_struct *p, int regs_esp)
+{
+
+	kdb_machreg_t	esp,eip,ebp,old_esp;
+	kdb_symtab_t	symtab, *sym;
+	kdbtbtable_t	tbtab;
+	/* declare these as raw ptrs so we don't get func descriptors */
+	extern void *ret_from_except, *ret_from_syscall_1, *do_bottom_half_ret;
+
+if (!regs && !addr)
+{
+    kdb_printf(" invalid regs pointer \n");
+    return 0;
+}
+
+	/*
+	 * The caller may have supplied an address at which the
+	 * stack traceback operation should begin.  This address
+	 * is assumed by this code to point to a return-address
+	 * on the stack to be traced back.
+	 *
+	 * The end result of this will make it appear as if a function
+	 * entitled '<unknown>' was called from the function which
+	 * contains return-address.
+	 */
+	if (addr) {
+		eip = 0;
+		esp = *addr;
+		ebp=0;
+	} else {
+		ebp=regs->link;
+		eip = regs->nip;
+		if (regs_esp)
+			esp = regs->gpr[1];
+		else
+			kdba_getregcontents("esp", regs, &esp);
+	}
+
+	kdb_printf("          SP(esp)            PC(eip)      Function(args)\n");
+
+	/* (Ref: 64-bit PowerPC ELF ABI Spplement; Ian Lance Taylor, Zembu Labs).
+	 A PPC stack frame looks like this:
+
+	 High Address
+	 Back Chain
+	 FP reg save area
+	 GP reg save area
+	 Local var space
+	 Parameter save area		(SP+48)
+	 TOC save area		(SP+40)
+	 link editor doubleword	(SP+32)
+	 compiler doubleword		(SP+24)
+	 LR save			(SP+16)
+	 CR save			(SP+8)
+	 Back Chain			(SP+0)
+
+	 Note that the LR (ret addr) may not be saved in the *current* frame if
+	 no functions have been called from the current function.
+	 */
+
+	/*
+	 * Run through the activation records and print them.
+	 */
+	while (1) {
+		kdb_printf("0x%016lx  0x%016lx  ", esp, eip);
+		kdbnearsym(eip, &symtab);
+		kdba_find_tb_table(eip, &tbtab);
+		sym = symtab.sym_name ? &symtab : &tbtab.symtab; /* use fake symtab if necessary */
+		if (esp >= PAGE_OFFSET) { 
+		    if ((sym) && sym->sym_name) {
+			{
+
+/* if this fails, eip is outside of kernel space, dont trust it. */
+			    if (eip > PAGE_OFFSET) { 
+				    kdb_printf("%s", sym->sym_name);
+			    } else {
+				    kdb_printf("NO_SYMBOL");
+			    }
+			}
+/* if this fails, eip is outside of kernel space, dont trust data. */
+			if (eip > PAGE_OFFSET) { 
+			    if (eip - sym->sym_start > 0) {
+				kdb_printf(" +0x%lx", eip - sym->sym_start);
+			    }
+			}
+		    } else
+			kdb_printf("NO_SYMBOL");
+		}
+		else  /* userspace... */ {
+		    kdb_printf("UserSpace function");
+		    /* more code here to look up userspace function names..*/
+		}
+
+		kdb_printf("\n");
+		/* ret_from_except=0xa5e0 ret_from_syscall_1=a378 do_bottom_half_ret=a5e0 */
+		if (esp < PAGE_OFFSET) { /* below kernelspace..   */
+                            kdb_printf("<Stack contents outside of kernel space.  %.16lx>\n", esp );
+			    break;
+		} else {
+		    if (eip == (kdb_machreg_t)ret_from_except ||
+			eip == (kdb_machreg_t)ret_from_syscall_1 ||
+			eip == (kdb_machreg_t)do_bottom_half_ret) {
+			/* pull exception regs from the stack */
+			struct pt_regs eregs;
+			kdba_getmem(esp+STACK_FRAME_OVERHEAD, &eregs, sizeof(eregs));
+			kdb_printf("  [exception: %lx:%s regs 0x%lx] nip:[0x%x] gpr[1]:[0x%x]\n", eregs.trap,getvecname(eregs.trap), esp+STACK_FRAME_OVERHEAD,(unsigned int)eregs.nip,(unsigned int)eregs.gpr[1]);
+			old_esp = esp;
+			esp = kdba_getword(esp, 8);
+			if (!esp)
+			    break;
+			eip = kdba_getword(esp+16, 8);	/* saved lr */
+			if (esp < PAGE_OFFSET) {  /* userspace... */
+			    if (old_esp > PAGE_OFFSET) {
+				kdb_printf("<Stack drops into userspace here %.16lx>\n",esp);
+				break;
+			    }
+			}
+/* we want to follow exception registers, not into user stack.  ...   */
+			esp = eregs.gpr[1];
+			eip = eregs.nip;
+		    } else {
+			esp = kdba_getword(esp, 8);
+			if (!esp)
+			    break;
+			eip = kdba_getword(esp+16, 8);	/* saved lr */
+
+#if 0
+			if (esp < p) {
+			    kdb_printf("<Stack drops into userspace %.16lx  %.16lx >\n", esp,p );
+			    break;
+			}
+#endif
+		    }
+		}
+	}
+	return 0;
+}
+
+
+/*
+ * kdba_bt_stack
+ *
+ *	This function implements the 'bt' command.  Print a stack
+ *	traceback.
+ *
+ *	bt [<address-expression>]   (addr-exp is for alternate stacks)
+ *	btp <pid>		     (Kernel stack for <pid>)
+ *
+ * 	address expression refers to a return address on the stack.  It
+ *	may be preceeded by a frame pointer.
+ *
+ * Inputs:
+ *	regs	registers at time kdb was entered.
+ *	addr	Pointer to Address provided to 'bt' command, if any.
+ *	argcount
+ *	p	Pointer to task for 'btp' command.
+ * Outputs:
+ *	None.
+ * Returns:
+ *	zero for success, a kdb diagnostic if error
+ * Locking:
+ *	none.
+ * Remarks:
+ *	mds comes in handy when examining the stack to do a manual
+ *	traceback.
+ */
+
+int
+kdba_bt_stack(struct pt_regs *regs, kdb_machreg_t *addr, int argcount,
+	      struct task_struct *p)
+{
+	return(kdba_bt_stack_ppc(regs, addr, argcount, p, 0));
+}
+
+int
+kdba_bt_process(struct task_struct *p, int argcount)
+{
+	return(kdba_bt_stack_ppc(p->thread.regs, (kdb_machreg_t *) p->thread.ksp, argcount, p, 0));
+}
+
diff -urN linux-2.4.21-pre3/arch/ppc64/kdb/kdba_id.c linux-2.4.21-pre4/arch/ppc64/kdb/kdba_id.c
--- linux-2.4.21-pre3/arch/ppc64/kdb/kdba_id.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/arch/ppc64/kdb/kdba_id.c	Tue Jan 28 19:44:29 2003
@@ -0,0 +1,278 @@
+/*
+ * Minimalist Kernel Debugger - Architecture Dependent Instruction Disassembly
+ *
+ * Copyright (C) 1999 Silicon Graphics, Inc.
+ *
+ * See the file LIA-COPYRIGHT for additional information.
+ *
+ * Written March 1999 by Scott Lurndal at Silicon Graphics, Inc.
+ *
+ * Modifications from:
+ *      Richard Bass                    1999/07/20
+ *              Many bug fixes and enhancements.
+ *      Scott Foehner
+ *              Port to ia64
+ *      Srinivasa Thirumalachar
+ *              RSE support for ia64
+ *	Masahiro Adegawa                1999/12/01
+ *		'sr' command, active flag in 'ps'
+ *	Scott Lurndal			1999/12/12
+ *		Significantly restructure for linux2.3
+ *	Keith Owens			2000/05/23
+ *		KDB v1.2
+ *
+ */
+
+#include <stdarg.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/kdb.h>
+#include <linux/kdbprivate.h>
+
+/*
+ * kdba_dis_getsym
+ *
+ *	Get a symbol for the disassembler.
+ *
+ * Parameters:
+ *	addr	Address for which to get symbol
+ *	dip	Pointer to disassemble_info
+ * Returns:
+ *	0
+ * Locking:
+ * Remarks:
+ *	Not used for kdb.
+ */
+
+/* ARGSUSED */
+static int
+kdba_dis_getsym(bfd_vma addr, disassemble_info *dip)
+{
+
+	return 0;
+}
+
+/*
+ * kdba_printaddress
+ *
+ *	Print (symbolically) an address.
+ *
+ * Parameters:
+ *	addr	Address for which to get symbol
+ *	dip	Pointer to disassemble_info
+ *	flag	True if a ":<tab>" sequence should follow the address
+ * Returns:
+ *	number of chars printed
+ * Locking:
+ * Remarks:
+ *
+ */
+
+/* ARGSUSED */
+void
+kdba_printaddress(kdb_machreg_t addr, disassemble_info *dip, int flag)
+{
+	kdb_symtab_t symtab;
+
+	/*
+	 * Print a symbol name or address as necessary.
+	 */
+	kdbnearsym(addr, &symtab);
+	if (symtab.sym_name) {
+		/* Do not use kdb_symbol_print here, it always does
+		 * kdb_printf but we want dip->fprintf_func.
+		 */
+		dip->fprintf_func(dip->stream,
+			"0x%0*lx %s",
+			2*sizeof(addr), addr, symtab.sym_name);
+		/* Add offset if needed.  Pad output with blanks to get
+		 * consistent size symbols for disassembly listings.
+		 */
+		if (addr == symtab.sym_start) {
+			if (!flag)
+				dip->fprintf_func(dip->stream, "         ");
+		} else {
+			int len, i;
+			char buf[20];
+			sprintf(buf, "%lx", addr - symtab.sym_start);
+			dip->fprintf_func(dip->stream, "+0x%s", buf);
+			if (!flag) {
+				len = strlen(buf);
+				for (i = len; i < 6; i++)
+					dip->fprintf_func(dip->stream, " ");
+			}
+		}
+
+	} else {
+		dip->fprintf_func(dip->stream, "0x%0*lx", 2*sizeof(addr), addr);
+	}
+
+	if (flag)
+		dip->fprintf_func(dip->stream, ":   ");
+}
+
+/*
+ * kdba_dis_printaddr
+ *
+ *	Print (symbolically) an address.  Called by GNU disassembly
+ *	code via disassemble_info structure.
+ *
+ * Parameters:
+ *	addr	Address for which to get symbol
+ *	dip	Pointer to disassemble_info
+ * Returns:
+ *	number of chars printed.
+ * Locking:
+ * Remarks:
+ *	This function will never append ":<tab>" to the printed
+ *	symbolic address.
+ */
+
+static void
+kdba_dis_printaddr(bfd_vma addr, disassemble_info *dip)
+{
+	return kdba_printaddress(addr, dip, 0);
+}
+
+/*
+ * kdba_dis_getmem
+ *
+ *	Fetch 'length' bytes from 'addr' into 'buf'.
+ *
+ * Parameters:
+ *	addr	Address for which to get symbol
+ *	buf	Address of buffer to fill with bytes from 'addr'
+ *	length	Number of bytes to fetch
+ *	dip	Pointer to disassemble_info
+ * Returns:
+ *	0
+ * Locking:
+ * Remarks:
+ *
+ */
+extern int kdba_getword(unsigned long addr, size_t width);
+
+
+/* ARGSUSED */
+static int
+kdba_dis_getmem(bfd_vma addr, bfd_byte *buf, unsigned int length, disassemble_info *dip)
+{
+	bfd_byte	*bp = buf;
+	int		i;
+
+	/*
+	 * Fill the provided buffer with bytes from
+	 * memory, starting at address 'addr' for 'length bytes.
+	 *
+	 */
+
+	for(i=0; i<length; i++ ){
+		*bp++ = (bfd_byte)kdba_getword(addr++, sizeof(bfd_byte));
+	}
+
+	return 0;
+}
+
+/*
+ * kdba_id_parsemode
+ *
+ * 	Parse IDMODE environment variable string and
+ *	set appropriate value into "disassemble_info" structure.
+ *
+ * Parameters:
+ *	mode	Mode string
+ *	dip	Disassemble_info structure pointer
+ * Returns:
+ * Locking:
+ * Remarks:
+ *	We handle the values 'x86' and '8086' to enable either
+ *	32-bit instruction set or 16-bit legacy instruction set.
+ */
+
+int
+kdba_id_parsemode(const char *mode, disassemble_info *dip)
+{
+
+
+	return 0;
+}
+
+/*
+ * kdba_check_pc
+ *
+ * 	Check that the pc is satisfactory.
+ *
+ * Parameters:
+ *	pc	Program Counter Value.
+ * Returns:
+ *	None
+ * Locking:
+ *	None.
+ * Remarks:
+ *	Can change pc.
+ */
+
+void
+kdba_check_pc(kdb_machreg_t *pc)
+{
+	/* No action */
+}
+
+/*
+ * kdba_id_printinsn
+ *
+ * 	Format and print a single instruction at 'pc'. Return the
+ *	length of the instruction.
+ *
+ * Parameters:
+ *	pc	Program Counter Value.
+ *	dip	Disassemble_info structure pointer
+ * Returns:
+ *	Length of instruction, -1 for error.
+ * Locking:
+ *	None.
+ * Remarks:
+ *	Depends on 'IDMODE' environment variable.
+ */
+
+int
+kdba_id_printinsn(kdb_machreg_t pc, disassemble_info *dip)
+{
+	kdba_dis_printaddr(pc, dip);
+	return print_insn_big_powerpc(pc, dip);
+}
+
+/*
+ * kdba_id_init
+ *
+ * 	Initialize the architecture dependent elements of
+ *	the disassembly information structure
+ *	for the GNU disassembler.
+ *
+ * Parameters:
+ *	None.
+ * Outputs:
+ *	None.
+ * Returns:
+ *	None.
+ * Locking:
+ *	None.
+ * Remarks:
+ */
+
+void __init
+kdba_id_init(disassemble_info *dip)
+{
+	dip->read_memory_func       = kdba_dis_getmem;
+	dip->print_address_func     = kdba_dis_printaddr;
+	dip->symbol_at_address_func = kdba_dis_getsym;
+
+	dip->flavour                = bfd_target_elf_flavour;
+	dip->arch		    = bfd_arch_powerpc;
+	dip->mach		    = bfd_mach_ppc_750;
+	dip->endian	    	    = BFD_ENDIAN_BIG;
+
+	dip->display_endian         = BFD_ENDIAN_BIG;
+}
diff -urN linux-2.4.21-pre3/arch/ppc64/kdb/kdba_io.c linux-2.4.21-pre4/arch/ppc64/kdb/kdba_io.c
--- linux-2.4.21-pre3/arch/ppc64/kdb/kdba_io.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/arch/ppc64/kdb/kdba_io.c	Tue Jan 28 19:44:29 2003
@@ -0,0 +1,155 @@
+/*
+ * Kernel Debugger Console I/O handler
+ *
+ * Copyright (C) 1999 Silicon Graphics, Inc.
+ * Copyright (C) Scott Lurndal (slurn@engr.sgi.com)
+ * Copyright (C) Scott Foehner (sfoehner@engr.sgi.com)
+ * Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com)
+ *
+ * See the file LIA-COPYRIGHT for additional information.
+ *
+ * Written March 1999 by Scott Lurndal at Silicon Graphics, Inc.
+ *
+ * Modifications from:
+ *	Chuck Fleckenstein		1999/07/20
+ *		Move kdb_info struct declaration to this file
+ *		for cases where serial support is not compiled into
+ *		the kernel.
+ *
+ *	Masahiro Adegawa		1999/07/20
+ *		Handle some peculiarities of japanese 86/106
+ *		keyboards.
+ *
+ *	marc@mucom.co.il		1999/07/20
+ *		Catch buffer overflow for serial input.
+ *
+ *      Scott Foehner
+ *              Port to ia64
+ *
+ *	Scott Lurndal			2000/01/03
+ *		Restructure for v1.0
+ *
+ *	Keith Owens			2000/05/23
+ *		KDB v1.2
+ *
+ *	Andi Kleen			2000/03/19
+ *		Support simultaneous input from serial line and keyboard.
+ */
+
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <linux/pc_keyb.h>
+#include <linux/console.h>
+#include <linux/ctype.h>
+#include <linux/keyboard.h>
+#include <linux/serial_reg.h>
+
+#include <linux/kdb.h>
+#include <linux/kdbprivate.h>
+#include <asm/machdep.h>
+#undef FILE
+
+int kdb_port;
+int inchar(void);
+
+/*
+ * This module contains code to read characters from the keyboard or a serial
+ * port.
+ *
+ * It is used by the kernel debugger, and is polled, not interrupt driven.
+ *
+ */
+void
+kdb_resetkeyboard(void)
+{
+#if 0
+	kdb_kbdsend(KBD_CMD_ENABLE);
+#endif
+}
+
+
+#if 0
+/* code that may be resurrected later.. */
+#if defined(CONFIG_VT)
+/*
+ * Check if the keyboard controller has a keypress for us.
+ * Some parts (Enter Release, LED change) are still blocking polled here,
+ * but hopefully they are all short.
+ */
+static int get_kbd_char(void)
+{
+	int keychar;
+/*  	keychar = inchar(); */
+	keychar = ppc_md.udbg_getc_poll();
+
+	if (keychar == '\n')
+	{
+	    kdb_printf("\n");
+	}
+
+	/*
+	 * echo the character.
+	 */
+	kdb_printf("%c", keychar);
+
+	return keychar ;
+}
+#endif /* CONFIG_VT */
+#endif
+
+static int get_char_lp(void)
+{
+    int keychar;
+    keychar = ppc_md.udbg_getc_poll();
+
+    if (keychar == '\n')
+    {
+	kdb_printf("\n");
+    }
+
+#if 0
+    /* echo the character. */
+    if (keychar != -1)
+	kdb_printf("%c", keychar);
+#endif
+
+    return keychar ;
+}
+
+
+char *
+kdba_read(char *buffer, size_t bufsize)
+{
+	char	*cp = buffer;
+	char	*bufend = buffer+bufsize-2;	/* Reserve space for newline and null byte */
+
+	for (;;) {
+	    unsigned char key = ppc_md.udbg_getc();
+		/* Echo is done in the low level functions */
+		switch (key) {
+		case '\b': /* backspace */
+		case '\x7f': /* delete */
+			if (cp > buffer) {
+				udbg_puts("\b \b");
+				--cp;
+			}
+			break;
+		case '\n': /* enter */
+		case '\r': /* - the other enter... */
+			ppc_md.udbg_putc('\n');
+			*cp++ = '\n';
+			*cp++ = '\0';
+			return buffer;
+		default:
+			if (cp < bufend)
+			ppc_md.udbg_putc(key);
+				*cp++ = key;
+			break;
+		}
+	}
+}
+
+
+
diff -urN linux-2.4.21-pre3/arch/ppc64/kdb/kdba_utils.c linux-2.4.21-pre4/arch/ppc64/kdb/kdba_utils.c
--- linux-2.4.21-pre3/arch/ppc64/kdb/kdba_utils.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/arch/ppc64/kdb/kdba_utils.c	Tue Jan 28 19:44:29 2003
@@ -0,0 +1,569 @@
+/* utilities migrated from Xmon or other kernel debug tools. */
+
+/*
+
+Notes for migrating functions from xmon...
+Add functions to this file.  parmlist for functions must match
+   (int argc, const char **argv, const char **envp, struct pt_regs *fp)
+add function prototype to kdbasupport.c
+add function hook to kdba_init() within kdbasupport.c
+
+
+Common bits...
+mread() function calls need to be changed to kdba_readarea_size calls.  straightforward change.
+This:
+	nr = mread(codeaddr, &namlen, 2); 
+becomes this:
+	nr = kdba_readarea_size(codeaddr,&namlen,2);
+
+*/
+
+
+#include <linux/string.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/ptrace.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/kdb.h>
+#include <linux/kdbprivate.h>
+
+#include "privinst.h"
+
+#define EOF	(-1)
+
+/* workaround for abort definition in kernel/pci.h */
+#define abort(x) 
+/* for traverse_all_pci_devices */
+#include "../kernel/pci.h"
+/* for NUM_TCE_LEVELS */
+#include <asm/pci_dma.h>
+
+
+/* prototypes */
+int scanhex(unsigned long *);
+int hexdigit(int c);
+int kdba_readarea_size(unsigned long from_xxx,void *to,  size_t size);
+void machine_halt(void); 
+
+
+
+/*
+ A traceback table typically follows each function.
+ The find_tb_table() func will fill in this struct.  Note that the struct
+ is not an exact match with the encoded table defined by the ABI.  It is
+ defined here more for programming convenience.
+ */
+struct tbtable {
+	unsigned long	flags;		/* flags: */
+#define TBTAB_FLAGSGLOBALLINK	(1L<<47)
+#define TBTAB_FLAGSISEPROL	(1L<<46)
+#define TBTAB_FLAGSHASTBOFF	(1L<<45)
+#define TBTAB_FLAGSINTPROC	(1L<<44)
+#define TBTAB_FLAGSHASCTL	(1L<<43)
+#define TBTAB_FLAGSTOCLESS	(1L<<42)
+#define TBTAB_FLAGSFPPRESENT	(1L<<41)
+#define TBTAB_FLAGSNAMEPRESENT	(1L<<38)
+#define TBTAB_FLAGSUSESALLOCA	(1L<<37)
+#define TBTAB_FLAGSSAVESCR	(1L<<33)
+#define TBTAB_FLAGSSAVESLR	(1L<<32)
+#define TBTAB_FLAGSSTORESBC	(1L<<31)
+#define TBTAB_FLAGSFIXUP	(1L<<30)
+#define TBTAB_FLAGSPARMSONSTK	(1L<<0)
+	unsigned char	fp_saved;	/* num fp regs saved f(32-n)..f31 */
+	unsigned char	gpr_saved;	/* num gpr's saved */
+	unsigned char	fixedparms;	/* num fixed point parms */
+	unsigned char	floatparms;	/* num float parms */
+	unsigned char	parminfo[32];	/* types of args.  null terminated */
+#define TBTAB_PARMFIXED 1
+#define TBTAB_PARMSFLOAT 2
+#define TBTAB_PARMDFLOAT 3
+	unsigned int	tb_offset;	/* offset from start of func */
+	unsigned long	funcstart;	/* addr of start of function */
+	char		name[64];	/* name of function (null terminated)*/
+};
+
+
+static int find_tb_table(unsigned long codeaddr, struct tbtable *tab);
+
+
+/* Very cheap human name for vector lookup. */
+static
+const char *getvecname(unsigned long vec)
+{
+	char *ret;
+	switch (vec) {
+	case 0x100:	ret = "(System Reset)"; break; 
+	case 0x200:	ret = "(Machine Check)"; break; 
+	case 0x300:	ret = "(Data Access)"; break; 
+	case 0x400:	ret = "(Instruction Access)"; break; 
+	case 0x500:	ret = "(Hardware Interrupt)"; break; 
+	case 0x600:	ret = "(Alignment)"; break; 
+	case 0x700:	ret = "(Program Check)"; break; 
+	case 0x800:	ret = "(FPU Unavailable)"; break; 
+	case 0x900:	ret = "(Decrementer)"; break; 
+	case 0xc00:	ret = "(System Call)"; break; 
+	case 0xd00:	ret = "(Single Step)"; break; 
+	case 0xf00:	ret = "(Performance Monitor)"; break; 
+	default: ret = "";
+	}
+	return ret;
+}
+
+int kdba_halt(int argc, const char **argv, const char **envp, struct pt_regs *fp)
+{
+    kdb_printf("halting machine. ");
+    machine_halt();
+return 0;
+}
+
+
+int kdba_excprint(int argc, const char **argv, const char **envp, struct pt_regs *fp)
+{
+	struct task_struct *c;
+	struct tbtable tab;
+
+#ifdef CONFIG_SMP
+	kdb_printf("cpu %d: ", smp_processor_id());
+#endif /* CONFIG_SMP */
+
+	kdb_printf("Vector: %lx %s at  [%p]\n", fp->trap, getvecname(fp->trap), fp);
+	kdb_printf("    pc: %lx", fp->nip);
+	if (find_tb_table(fp->nip, &tab) && tab.name[0]) {
+		/* Got a nice name for it */
+		int delta = fp->nip - tab.funcstart;
+		kdb_printf(" (%s+0x%x)", tab.name, delta);
+	}
+	kdb_printf("\n");
+	kdb_printf("    lr: %lx", fp->link);
+	if (find_tb_table(fp->link, &tab) && tab.name[0]) {
+		/* Got a nice name for it */
+		int delta = fp->link - tab.funcstart;
+		kdb_printf(" (%s+0x%x)", tab.name, delta);
+	}
+	kdb_printf("\n");
+	kdb_printf("    sp: %lx\n", fp->gpr[1]);
+	kdb_printf("   msr: %lx\n", fp->msr);
+
+	if (fp->trap == 0x300 || fp->trap == 0x600) {
+		kdb_printf("   dar: %lx\n", fp->dar);
+		kdb_printf(" dsisr: %lx\n", fp->dsisr);
+	}
+
+	/* XXX: need to copy current or we die.  Why? */
+	c = current;
+	kdb_printf("  current = 0x%p\n", c);
+	kdb_printf("  paca    = 0x%p\n", get_paca());
+	if (c) {
+		kdb_printf("  current = %p, pid = %ld, comm = %s\n",
+		       c, (unsigned long)c->pid, (char *)c->comm);
+	}
+return 0;
+}
+
+
+
+
+/* Starting at codeaddr scan forward for a tbtable and fill in the
+ given table.  Return non-zero if successful at doing something.
+ */
+static int
+find_tb_table(unsigned long codeaddr, struct tbtable *tab)
+{
+	unsigned long codeaddr_max;
+	unsigned long tbtab_start;
+	int nr;
+	int instr;
+	int num_parms;
+
+	if (tab == NULL)
+		return 0;
+	memset(tab, 0, sizeof(tab));
+
+	/* Scan instructions starting at codeaddr for 128k max */
+	for (codeaddr_max = codeaddr + 128*1024*4;
+	     codeaddr < codeaddr_max;
+	     codeaddr += 4) {
+	    nr=kdba_readarea_size(codeaddr,&instr,4);
+		if (nr != 4)
+			return 0;	/* Bad read.  Give up promptly. */
+		if (instr == 0) {
+			/* table should follow. */
+			int version;
+			unsigned long flags;
+			tbtab_start = codeaddr;	/* save it to compute func start addr */
+			codeaddr += 4;
+			nr = kdba_readarea_size(codeaddr,&flags,8);
+			if (nr != 8)
+				return 0;	/* Bad read or no tb table. */
+			tab->flags = flags;
+			version = (flags >> 56) & 0xff;
+			if (version != 0)
+				continue;	/* No tb table here. */
+			/* Now, like the version, some of the flags are values
+			 that are more conveniently extracted... */
+			tab->fp_saved = (flags >> 24) & 0x3f;
+			tab->gpr_saved = (flags >> 16) & 0x3f;
+			tab->fixedparms = (flags >> 8) & 0xff;
+			tab->floatparms = (flags >> 1) & 0x7f;
+			codeaddr += 8;
+			num_parms = tab->fixedparms + tab->floatparms;
+			if (num_parms) {
+				unsigned int parminfo;
+				int parm;
+				if (num_parms > 32)
+					return 1;	/* incomplete */
+				nr = kdba_readarea_size(codeaddr,&parminfo,4);
+				if (nr != 4)
+					return 1;	/* incomplete */
+				/* decode parminfo...32 bits.
+				 A zero means fixed.  A one means float and the
+				 following bit determines single (0) or double (1).
+				 */
+				for (parm = 0; parm < num_parms; parm++) {
+					if (parminfo & 0x80000000) {
+						parminfo <<= 1;
+						if (parminfo & 0x80000000)
+							tab->parminfo[parm] = TBTAB_PARMDFLOAT;
+						else
+							tab->parminfo[parm] = TBTAB_PARMSFLOAT;
+					} else {
+						tab->parminfo[parm] = TBTAB_PARMFIXED;
+					}
+					parminfo <<= 1;
+				}
+				codeaddr += 4;
+			}
+			if (flags & TBTAB_FLAGSHASTBOFF) {
+			    nr = kdba_readarea_size(codeaddr,&tab->tb_offset,4);
+				if (nr != 4)
+					return 1;	/* incomplete */
+				if (tab->tb_offset > 0) {
+					tab->funcstart = tbtab_start - tab->tb_offset;
+				}
+				codeaddr += 4;
+			}
+			/* hand_mask appears to be always be omitted. */
+			if (flags & TBTAB_FLAGSHASCTL) {
+				/* Assume this will never happen for C or asm */
+				return 1;	/* incomplete */
+			}
+			if (flags & TBTAB_FLAGSNAMEPRESENT) {
+				short namlen;
+				nr = kdba_readarea_size(codeaddr,&namlen,2);
+				if (nr != 2)
+					return 1;	/* incomplete */
+				if (namlen >= sizeof(tab->name))
+					namlen = sizeof(tab->name)-1;
+				codeaddr += 2;
+				nr = kdba_readarea_size(codeaddr,tab->name,namlen);
+				tab->name[namlen] = '\0';
+				codeaddr += namlen;
+			}
+			return 1;
+		}
+	}
+	return 0;	/* hit max...sorry. */
+}
+
+
+int kdba_dissect_msr(int argc, const char **argv, const char **envp, struct pt_regs *regs)
+{
+   long int msr;
+   msr = get_msr();
+
+   kdb_printf("msr dissection: %lx\n",msr);
+   if (msr & MSR_SF)   kdb_printf(" 64 bit mode enabled \n");
+   if (msr & MSR_ISF)  kdb_printf(" Interrupt 64b mode valid on 630 \n");
+   if (msr & MSR_HV)   kdb_printf(" Hypervisor State \n");
+   if (msr & MSR_VEC)  kdb_printf(" Enable Altivec \n");
+   if (msr & MSR_POW)  kdb_printf(" Enable Power Management  \n");
+   if (msr & MSR_WE)   kdb_printf(" Wait State Enable   \n");
+   if (msr & MSR_TGPR) kdb_printf(" TLB Update registers in use   \n");
+   if (msr & MSR_CE)   kdb_printf(" Critical Interrupt Enable   \n");
+   if (msr & MSR_ILE)  kdb_printf(" Interrupt Little Endian   \n");
+   if (msr & MSR_EE)   kdb_printf(" External Interrupt Enable   \n");
+   if (msr & MSR_PR)   kdb_printf(" Problem State / Privilege Level  \n"); 
+   if (msr & MSR_FP)   kdb_printf(" Floating Point enable   \n");
+   if (msr & MSR_ME)   kdb_printf(" Machine Check Enable   \n");
+   if (msr & MSR_FE0)  kdb_printf(" Floating Exception mode 0  \n"); 
+   if (msr & MSR_SE)   kdb_printf(" Single Step   \n");
+   if (msr & MSR_BE)   kdb_printf(" Branch Trace   \n");
+   if (msr & MSR_DE)   kdb_printf(" Debug Exception Enable   \n");
+   if (msr & MSR_FE1)  kdb_printf(" Floating Exception mode 1   \n");
+   if (msr & MSR_IP)   kdb_printf(" Exception prefix 0x000/0xFFF   \n");
+   if (msr & MSR_IR)   kdb_printf(" Instruction Relocate   \n");
+   if (msr & MSR_DR)   kdb_printf(" Data Relocate   \n");
+   if (msr & MSR_PE)   kdb_printf(" Protection Enable   \n");
+   if (msr & MSR_PX)   kdb_printf(" Protection Exclusive Mode   \n");
+   if (msr & MSR_RI)   kdb_printf(" Recoverable Exception   \n");
+   if (msr & MSR_LE)   kdb_printf(" Little Endian   \n");
+   kdb_printf(".\n");
+return 0;
+}
+
+
+
+
+
+int kdba_super_regs(int argc, const char **argv, const char **envp, struct pt_regs *regs){
+	int i;
+/*	int cmd; */
+/*	unsigned long val; */
+	struct paca_struct*  ptrPaca = NULL;
+	struct ItLpPaca*  ptrLpPaca = NULL;
+	struct ItLpRegSave*  ptrLpRegSave = NULL;
+
+/*	cmd = skipbl(); */
+/*	if (cmd == '\n') { */
+	{
+	        unsigned long sp, toc;
+		kdb_printf("sr::");
+		asm("mr %0,1" : "=r" (sp) :);
+		asm("mr %0,2" : "=r" (toc) :);
+
+		kdb_printf("msr  = %.16lx  sprg0= %.16lx\n", get_msr(), get_sprg0());
+		kdb_printf("pvr  = %.16lx  sprg1= %.16lx\n", get_pvr(), get_sprg1()); 
+		kdb_printf("dec  = %.16lx  sprg2= %.16lx\n", get_dec(), get_sprg2());
+		kdb_printf("sp   = %.16lx  sprg3= %.16lx\n", sp, get_sprg3());
+		kdb_printf("toc  = %.16lx  dar  = %.16lx\n", toc, get_dar());
+		kdb_printf("srr0 = %.16lx  srr1 = %.16lx\n", get_srr0(), get_srr1());
+		kdb_printf("asr  = %.16lx\n", mfasr());
+		for (i = 0; i < 8; ++i)
+			kdb_printf("sr%.2ld = %.16lx  sr%.2ld = %.16lx\n", (long int)i, (unsigned long)get_sr(i), (long int)(i+8), (long unsigned int) get_sr(i+8));
+
+		// Dump out relevant Paca data areas.
+		kdb_printf("Paca: \n");
+		ptrPaca = (struct paca_struct*)get_sprg3();
+    
+		kdb_printf("  Local Processor Control Area (LpPaca): \n");
+		ptrLpPaca = ptrPaca->xLpPacaPtr;
+		kdb_printf("    Saved Srr0=%.16lx  Saved Srr1=%.16lx \n", ptrLpPaca->xSavedSrr0, ptrLpPaca->xSavedSrr1);
+		kdb_printf("    Saved Gpr3=%.16lx  Saved Gpr4=%.16lx \n", ptrLpPaca->xSavedGpr3, ptrLpPaca->xSavedGpr4);
+		kdb_printf("    Saved Gpr5=%.16lx \n", ptrLpPaca->xSavedGpr5);
+    
+		kdb_printf("  Local Processor Register Save Area (LpRegSave): \n");
+		ptrLpRegSave = ptrPaca->xLpRegSavePtr;
+		kdb_printf("    Saved Sprg0=%.16lx  Saved Sprg1=%.16lx \n", ptrLpRegSave->xSPRG0, ptrLpRegSave->xSPRG0);
+		kdb_printf("    Saved Sprg2=%.16lx  Saved Sprg3=%.16lx \n", ptrLpRegSave->xSPRG2, ptrLpRegSave->xSPRG3);
+		kdb_printf("    Saved Msr  =%.16lx  Saved Nia  =%.16lx \n", ptrLpRegSave->xMSR, ptrLpRegSave->xNIA);
+    
+		return 0;
+	} 
+
+
+}
+
+
+
+	
+int kdba_dump_tce_table(int argc, const char **argv, const char **envp, struct pt_regs *regs){
+    struct TceTable kt; 
+    long tce_table_address;
+    int nr;
+    int i,j,k;
+    int full,empty;
+    int fulldump=0;
+    u64 mapentry;
+    int totalpages;
+    int levelpages;
+
+    if (argc == 0) {
+	kdb_printf("need address\n");
+	return 0;
+    }
+    else 
+	kdbgetularg(argv[1], &tce_table_address);
+
+    if (argc==2)
+	if (strcmp(argv[2], "full") == 0) 
+	    fulldump=1;
+
+
+    /* with address, read contents of memory and dump tce table. */
+    /* possibly making some assumptions on the depth and size of table..*/
+
+    nr = kdba_readarea_size(tce_table_address+0 ,&kt.busNumber,8);
+    nr = kdba_readarea_size(tce_table_address+8 ,&kt.size,8);
+    nr = kdba_readarea_size(tce_table_address+16,&kt.startOffset,8);
+    nr = kdba_readarea_size(tce_table_address+24,&kt.base,8);
+    nr = kdba_readarea_size(tce_table_address+32,&kt.index,8);
+    nr = kdba_readarea_size(tce_table_address+40,&kt.tceType,8);
+    nr = kdba_readarea_size(tce_table_address+48,&kt.lock,8);
+
+    kdb_printf("\n");
+    kdb_printf("TceTable at address %s:\n",argv[1]);
+    kdb_printf("BusNumber:   0x%x \n",(uint)kt.busNumber);
+    kdb_printf("size:        0x%x \n",(uint)kt.size);
+    kdb_printf("startOffset: 0x%x \n",(uint)kt.startOffset);
+    kdb_printf("base:        0x%x \n",(uint)kt.base);
+    kdb_printf("index:       0x%x \n",(uint)kt.index);
+    kdb_printf("tceType:     0x%x \n",(uint)kt.tceType);
+    kdb_printf("lock:        0x%x \n",(uint)kt.lock.lock);
+
+    nr = kdba_readarea_size(tce_table_address+56,&kt.mlbm.maxLevel,8);
+    kdb_printf(" maxLevel:        0x%x \n",(uint)kt.mlbm.maxLevel);
+    totalpages=0;
+    for (i=0;i<NUM_TCE_LEVELS;i++) {
+	nr = kdba_readarea_size(tce_table_address+64+i*24,&kt.mlbm.level[i].numBits,8);
+	nr = kdba_readarea_size(tce_table_address+72+i*24,&kt.mlbm.level[i].numBytes,8);
+	nr = kdba_readarea_size(tce_table_address+80+i*24,&kt.mlbm.level[i].map,8);
+	kdb_printf("   level[%d]\n",i);
+	kdb_printf("   numBits:   0x%x\n",(uint)kt.mlbm.level[i].numBits);
+	kdb_printf("   numBytes:  0x%x\n",(uint)kt.mlbm.level[i].numBytes);
+	kdb_printf("   map*:      %p\n",kt.mlbm.level[i].map);
+
+	 /* if these dont match, this might not be a valid tce table, so
+	    dont try to iterate the map entries. */
+	if (kt.mlbm.level[i].numBits == 8*kt.mlbm.level[i].numBytes) {
+	    full=0;empty=0;levelpages=0;
+	    for (j=0;j<kt.mlbm.level[i].numBytes; j++) {
+		mapentry=0;
+		nr = kdba_readarea_size((long int)(kt.mlbm.level[i].map+j),&mapentry,1);
+		if (mapentry)
+		    full++;
+		else
+		    empty++;
+		if (mapentry && fulldump) {
+		    kdb_printf("0x%lx\n",mapentry);
+		}
+		for (k=0;(k<=64) && ((0x1UL<<k) <= mapentry);k++) {
+		    if ((0x1UL<<k) & mapentry) levelpages++;
+		}
+	    }
+	    kdb_printf("      full:0x%x empty:0x%x pages:0x%x\n",full,empty,levelpages);
+	} else {
+	    kdb_printf("      numBits/numBytes mismatch..? \n");
+	}
+	totalpages+=levelpages;
+    }
+    kdb_printf("      Total pages:0x%x\n",totalpages);
+    kdb_printf("\n");
+    return 0;
+}
+
+int kdba_kernelversion(int argc, const char **argv, const char **envp, struct pt_regs *regs){
+    kdb_symtab_t   symtab;
+    long banner_start_addr;
+    char * banner_addr;
+    int nr;
+
+    banner_start_addr = kdbgetsymval("linux_banner", &symtab);
+    if (banner_start_addr) {
+	banner_start_addr = symtab.sym_start;
+    } else {
+	kdb_printf("linux_banner symbol not found! \n");
+	return 0;
+    }
+
+    nr = kdba_readarea_size(banner_start_addr,&banner_addr,8);
+
+    kdb_printf("%s",banner_addr);
+
+    return 0;
+}
+
+int kdba_dmesg(int argc, const char **argv, const char **envp, struct pt_regs *regs){
+    kdb_symtab_t   symtab;
+    long log_buf_addr=0;
+    long log_start_addr=0;
+    int nr;                 
+    unsigned long default_lines;   /* number of lines to read */
+    long index_into_log_buf; /* pointer into log_buf */
+    long saved_index;  /* saved pointer into log_buf */
+    char current_char; /* temp char value */
+    int line_count=0;  /* temp counter for # lines*/
+    long log_size;  /* size of log_buf */
+    int wrapped; 
+
+    if (argc == 0)
+	default_lines=10; 
+    else 
+	kdbgetularg(argv[1], &default_lines);
+
+    log_buf_addr = kdbgetsymval("log_buf", &symtab);
+    if (log_buf_addr) {
+	log_buf_addr = symtab.sym_start;
+    } else {
+	kdb_printf("log_buf symbol not found! Can't do dmesg.\n");
+	return 0;
+    }
+    log_start_addr = kdbgetsymval("log_start", &symtab);
+    if (log_start_addr) {
+	log_start_addr = symtab.sym_start;
+    } else {
+	kdb_printf("log_start symbol not found! Can't do dmesg.\n");
+	return 0;
+    }
+
+    log_size = log_start_addr - log_buf_addr;
+
+    nr = kdba_readarea_size(log_start_addr,&index_into_log_buf,8);
+
+    saved_index=index_into_log_buf;
+    if (index_into_log_buf > log_size ) {
+	wrapped=1;
+    } else {
+	wrapped=0;
+    }
+
+    while ((index_into_log_buf > 0 ) && (line_count <= default_lines)) {
+	nr = kdba_readarea_size(log_buf_addr+(index_into_log_buf%log_size),&current_char,1);
+	if (current_char == 0x0a ) {
+	    line_count++;
+	}	
+	index_into_log_buf--;
+    }
+
+    if (line_count < default_lines ) {
+	kdb_printf("Something went wrong trying to count %ld lines\n",default_lines);
+    }
+
+    while ((index_into_log_buf < saved_index+1) && line_count >= 0 ) {
+	nr = kdba_readarea_size(log_buf_addr+index_into_log_buf%log_size,&current_char,1);
+	kdb_printf("%c",current_char);
+	if (current_char == 0x0a) line_count--;
+	index_into_log_buf++;
+    }
+
+    return 0; 
+}
+
+
+static void * 
+kdba_dump_pci(struct device_node *dn, void *data)
+{
+    struct pci_controller *phb;
+    char *device_type;
+    char *status;
+
+    phb = (struct pci_controller *)data;
+    device_type = get_property(dn, "device_type", 0);
+    status = get_property(dn, "status", 0);
+
+    dn->phb = phb;
+    kdb_printf("dn:   %p \n",dn);
+    kdb_printf("    phb      : %p\n",dn->phb);
+    kdb_printf("    name     : %s\n",dn->name);
+    kdb_printf("    full_name: %s\n",dn->full_name);
+    kdb_printf("    busno    : 0x%x\n",dn->busno);
+    kdb_printf("    devfn    : 0x%x\n",dn->devfn);
+    kdb_printf("    tce_table: %p\n",dn->tce_table);
+    return NULL;
+}
+
+
+int kdba_dump_pci_info(int argc, const char **argv, const char **envp, struct pt_regs *regs){
+
+    kdb_printf("kdba_dump_pci_info\n");
+
+/* call this traverse function with my function pointer.. it takes care of traversing, my func just needs to parse the device info.. */
+    traverse_all_pci_devices(kdba_dump_pci);
+    return 0;
+}
+
+
+
+
+
diff -urN linux-2.4.21-pre3/arch/ppc64/kdb/kdbasupport.c linux-2.4.21-pre4/arch/ppc64/kdb/kdbasupport.c
--- linux-2.4.21-pre3/arch/ppc64/kdb/kdbasupport.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/arch/ppc64/kdb/kdbasupport.c	Tue Jan 28 19:44:29 2003
@@ -0,0 +1,1246 @@
+/*
+ * Kernel Debugger Architecture Independent Support Functions
+ *
+ * Copyright (C) 1999 Silicon Graphics, Inc.
+ * Copyright (C) Scott Lurndal (slurn@engr.sgi.com)
+ * Copyright (C) Scott Foehner (sfoehner@engr.sgi.com)
+ * Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com)
+ *
+ * See the file LIA-COPYRIGHT for additional information.
+ *
+ * Written March 1999 by Scott Lurndal at Silicon Graphics, Inc.
+ *
+ * Modifications from:
+ *      Richard Bass                    1999/07/20
+ *              Many bug fixes and enhancements.
+ *      Scott Foehner
+ *              Port to ia64
+ *	Scott Lurndal			1999/12/12
+ *		v1.0 restructuring.
+ *	Keith Owens			2000/05/23
+ *		KDB v1.2
+ */
+
+#include <linux/string.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/ptrace.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/kdb.h>
+#include <linux/kdbprivate.h>
+
+#include <asm/processor.h>
+#include "privinst.h"
+#include <asm/uaccess.h>
+#include <asm/machdep.h>
+
+extern const char *kdb_diemsg;
+
+
+/* prototypes */
+int valid_ppc64_kernel_address(unsigned long addr, unsigned long size);
+extern int kdba_excprint(int argc, const char **argv, const char **envp, struct pt_regs *regs);
+extern int kdba_super_regs(int argc, const char **argv, const char **envp, struct pt_regs *regs);
+extern int kdba_dissect_msr(int argc, const char **argv, const char **envp, struct pt_regs *regs);
+extern int kdba_halt(int argc, const char **argv, const char **envp, struct pt_regs *regs);
+extern int kdba_dump_tce_table(int argc, const char **argv, const char **envp, struct pt_regs *regs);
+extern int kdba_kernelversion(int argc, const char **argv, const char **envp, struct pt_regs *regs);
+extern int kdba_dmesg(int argc, const char **argv, const char **envp, struct pt_regs *regs);
+extern int kdba_dump_pci_info(int argc, const char **argv, const char **envp, struct pt_regs *regs);
+unsigned long kdba_getword(unsigned long addr, size_t width);
+
+/*
+ * kdba_init
+ * 	Architecture specific initialization.
+ */
+/*
+kdb_register("commandname",              # name of command user will use to invoke function  
+             function_name,              # name of function within the code 
+             "function example usage",   # sample usage 
+             "function description",     # brief description. 
+             0                           # if i hit enter again, will command repeat itself ?
+Note: functions must take parameters as such:
+functionname(int argc, const char **argv, const char **envp, struct pt_regs *regs)
+*/
+
+void __init
+kdba_init(void)
+{
+	kdba_enable_lbr();
+	kdb_register("excp", kdba_excprint, "excp", "print exception info", 0);
+	kdb_register("superreg", kdba_super_regs, "superreg", "display super_regs", 0);
+	kdb_register("msr", kdba_dissect_msr, "msr", "dissect msr", 0);
+	kdb_register("halt", kdba_halt, "halt", "halt machine", 0);
+	kdb_register("dump_tce_table", kdba_dump_tce_table, "dump_tce_table <addr> [full]", "dump the tce table located at <addr>", 0);
+	kdb_register("kernel", kdba_kernelversion, "version", "display running kernel version", 0);
+	kdb_register("version", kdba_kernelversion, "version", "display running kernel version", 0);
+	kdb_register("_dmesg", kdba_dmesg, "dmesg <lines>", "display lines from dmesg (log_buf) buffer", 0);
+	kdb_register("pci_info", kdba_dump_pci_info, "dump_pci_info", "dump pci device info", 0);
+
+
+	if (!ppc_md.udbg_getc_poll)
+		kdb_on = 0;
+}
+
+
+
+
+/*
+ * kdba_prologue
+ *
+ *	This function analyzes a gcc-generated function prototype
+ *	with or without frame pointers to determine the amount of
+ *	automatic storage and register save storage is used on the
+ *	stack of the target function.  It only counts instructions
+ *	that have been executed up to but excluding the current eip.
+ * Inputs:
+ *	code	Start address of function code to analyze
+ *	pc	Current program counter within function
+ *	sp	Current stack pointer for function
+ *	fp	Current frame pointer for function, may not be valid
+ *	ss	Start of stack for current process.
+ *	caller	1 if looking for data on the caller frame, 0 for callee.
+ * Outputs:
+ *	ar	Activation record, all fields may be set.  fp and oldfp
+ *		are 0 if they cannot be extracted.  return is 0 if the
+ *		code cannot find a valid return address.  args and arg0
+ *		are 0 if the number of arguments cannot be safely
+ *		calculated.
+ * Returns:
+ *	1 if prologue is valid, 0 otherwise.  If pc is 0 treat it as a
+ *	valid prologue to allow bt on wild branches.
+ * Locking:
+ *	None.
+ * Remarks:
+ *
+ */
+int
+kdba_prologue(const kdb_symtab_t *symtab, kdb_machreg_t pc, kdb_machreg_t sp,
+	      kdb_machreg_t fp, kdb_machreg_t ss, int caller, kdb_ar_t *ar)
+{
+	/* We don't currently use kdb's generic activation record scanning
+	 * code to handle backtrace.
+	 */
+	return 0;
+}
+
+
+
+/*
+ * kdba_getregcontents
+ *
+ *	Return the contents of the register specified by the
+ *	input string argument.   Return an error if the string
+ *	does not match a machine register.
+ *
+ *	The following pseudo register names are supported:
+ *	   &regs	 - Prints address of exception frame
+ *	   kesp		 - Prints kernel stack pointer at time of fault
+ *	   cesp		 - Prints current kernel stack pointer, inside kdb
+ *	   ceflags	 - Prints current flags, inside kdb
+ *	   %<regname>	 - Uses the value of the registers at the
+ *			   last time the user process entered kernel
+ *			   mode, instead of the registers at the time
+ *			   kdb was entered.
+ *
+ * Parameters:
+ *	regname		Pointer to string naming register
+ *	regs		Pointer to structure containing registers.
+ * Outputs:
+ *	*contents	Pointer to unsigned long to recieve register contents
+ * Returns:
+ *	0		Success
+ *	KDB_BADREG	Invalid register name
+ * Locking:
+ * 	None.
+ * Remarks:
+ * 	If kdb was entered via an interrupt from the kernel itself then
+ *	ss and esp are *not* on the stack.
+ */
+
+static struct kdbregs {
+	char   *reg_name;
+	size_t	reg_offset;
+} kdbreglist[] = {
+	{ "gpr0",	offsetof(struct pt_regs, gpr[0]) },
+	{ "gpr1",	offsetof(struct pt_regs, gpr[1]) },
+	{ "gpr2",	offsetof(struct pt_regs, gpr[2]) },
+	{ "gpr3",	offsetof(struct pt_regs, gpr[3]) },
+	{ "gpr4",	offsetof(struct pt_regs, gpr[4]) },
+	{ "gpr5",	offsetof(struct pt_regs, gpr[5]) },
+	{ "gpr6",	offsetof(struct pt_regs, gpr[6]) },
+	{ "gpr7",	offsetof(struct pt_regs, gpr[7]) },
+	{ "gpr8",	offsetof(struct pt_regs, gpr[8]) },
+	{ "gpr9",	offsetof(struct pt_regs, gpr[9]) },
+	{ "gpr10",	offsetof(struct pt_regs, gpr[10]) },
+	{ "gpr11",	offsetof(struct pt_regs, gpr[11]) },
+	{ "gpr12",	offsetof(struct pt_regs, gpr[12]) },
+	{ "gpr13",	offsetof(struct pt_regs, gpr[13]) },
+	{ "gpr14",	offsetof(struct pt_regs, gpr[14]) },
+	{ "gpr15",	offsetof(struct pt_regs, gpr[15]) },
+	{ "gpr16",	offsetof(struct pt_regs, gpr[16]) },
+	{ "gpr17",	offsetof(struct pt_regs, gpr[17]) },
+	{ "gpr18",	offsetof(struct pt_regs, gpr[18]) },
+	{ "gpr19",	offsetof(struct pt_regs, gpr[19]) },
+	{ "gpr20",	offsetof(struct pt_regs, gpr[20]) },
+	{ "gpr21",	offsetof(struct pt_regs, gpr[21]) },
+	{ "gpr22",	offsetof(struct pt_regs, gpr[22]) },
+	{ "gpr23",	offsetof(struct pt_regs, gpr[23]) },
+	{ "gpr24",	offsetof(struct pt_regs, gpr[24]) },
+	{ "gpr25",	offsetof(struct pt_regs, gpr[25]) },
+	{ "gpr26",	offsetof(struct pt_regs, gpr[26]) },
+	{ "gpr27",	offsetof(struct pt_regs, gpr[27]) },
+	{ "gpr28",	offsetof(struct pt_regs, gpr[28]) },
+	{ "gpr29",	offsetof(struct pt_regs, gpr[29]) },
+	{ "gpr30",	offsetof(struct pt_regs, gpr[30]) },
+	{ "gpr31",	offsetof(struct pt_regs, gpr[31]) },
+	{ "eip",	offsetof(struct pt_regs, nip) },
+	{ "msr",	offsetof(struct pt_regs, msr) },
+	{ "esp",	offsetof(struct pt_regs, gpr[1]) },
+  	{ "orig_gpr3",  offsetof(struct pt_regs, orig_gpr3) },
+	{ "ctr", 	offsetof(struct pt_regs, ctr) },
+	{ "link",	offsetof(struct pt_regs, link) },
+	{ "xer", 	offsetof(struct pt_regs, xer) },
+	{ "ccr",	offsetof(struct pt_regs, ccr) },
+	{ "mq",		offsetof(struct pt_regs, softe) /* mq */ },
+	{ "trap",	offsetof(struct pt_regs, trap) },
+	{ "dar",	offsetof(struct pt_regs, dar)  },
+	{ "dsisr",	offsetof(struct pt_regs, dsisr) },
+	{ "result",	offsetof(struct pt_regs, result) },
+};
+
+static const int nkdbreglist = sizeof(kdbreglist) / sizeof(struct kdbregs);
+
+unsigned long
+getsp(void)
+{
+	unsigned long x;
+	asm("mr %0,1" : "=r" (x):);
+	return x;
+}
+
+int
+kdba_getregcontents(const char *regname,
+		    struct pt_regs *regs,
+		    kdb_machreg_t *contents)
+{
+	int i;
+
+	if (strcmp(regname, "&regs") == 0) {
+		*contents = (unsigned long)regs;
+		return 0;
+	}
+
+	if (strcmp(regname, "kesp") == 0) {
+		*contents = (unsigned long) current->thread.ksp;
+		return 0;
+	}
+
+	if (strcmp(regname, "cesp") == 0) {
+		*contents = getsp();
+		return 0;
+	}
+
+	if (strcmp(regname, "ceflags") == 0) {
+		int flags;
+		save_flags(flags);
+		*contents = flags;
+		return 0;
+	}
+
+	if (regname[0] == '%') {
+		/* User registers:  %%e[a-c]x, etc */
+		regname++;
+		regs = (struct pt_regs *)
+			(current->thread.ksp - sizeof(struct pt_regs));
+	}
+
+	for (i=0; i<nkdbreglist; i++) {
+		if (strnicmp(kdbreglist[i].reg_name,
+			     regname,
+			     strlen(regname)) == 0)
+			break;
+	}
+
+	if ((i < nkdbreglist)
+	 && (strlen(kdbreglist[i].reg_name) == strlen(regname))) {
+		*contents = *(unsigned long *)((unsigned long)regs +
+				kdbreglist[i].reg_offset);
+		return(0);
+	}
+
+	return KDB_BADREG;
+}
+
+/*
+ * kdba_setregcontents
+ *
+ *	Set the contents of the register specified by the
+ *	input string argument.   Return an error if the string
+ *	does not match a machine register.
+ *
+ *	Supports modification of user-mode registers via
+ *	%<register-name>
+ *
+ * Parameters:
+ *	regname		Pointer to string naming register
+ *	regs		Pointer to structure containing registers.
+ *	contents	Unsigned long containing new register contents
+ * Outputs:
+ * Returns:
+ *	0		Success
+ *	KDB_BADREG	Invalid register name
+ * Locking:
+ * 	None.
+ * Remarks:
+ */
+
+int
+kdba_setregcontents(const char *regname,
+		  struct pt_regs *regs,
+		  unsigned long contents)
+{
+	int i;
+
+	if (regname[0] == '%') {
+		regname++;
+		regs = (struct pt_regs *)
+			(current->thread.ksp - sizeof(struct pt_regs));
+	}
+
+	for (i=0; i<nkdbreglist; i++) {
+		if (strnicmp(kdbreglist[i].reg_name,
+			     regname,
+			     strlen(regname)) == 0)
+			break;
+	}
+
+	if ((i < nkdbreglist)
+	 && (strlen(kdbreglist[i].reg_name) == strlen(regname))) {
+		*(unsigned long *)((unsigned long)regs
+				   + kdbreglist[i].reg_offset) = contents;
+		return 0;
+	}
+
+	return KDB_BADREG;
+}
+
+/*
+ * kdba_dumpregs
+ *
+ *	Dump the specified register set to the display.
+ *
+ * Parameters:
+ *	regs		Pointer to structure containing registers.
+ *	type		Character string identifying register set to dump
+ *	extra		string further identifying register (optional)
+ * Outputs:
+ * Returns:
+ *	0		Success
+ * Locking:
+ * 	None.
+ * Remarks:
+ *	This function will dump the general register set if the type
+ *	argument is NULL (struct pt_regs).   The alternate register
+ *	set types supported by this function:
+ *
+ *	d 		Debug registers
+ *	c		Control registers
+ *	u		User registers at most recent entry to kernel
+ * Following not yet implemented:
+ *	m		Model Specific Registers (extra defines register #)
+ *	r		Memory Type Range Registers (extra defines register)
+ */
+
+int
+kdba_dumpregs(struct pt_regs *regs,
+	    const char *type,
+	    const char *extra)
+{
+	int i;
+	int count = 0;
+
+	if (type
+	 && (type[0] == 'u')) {
+		type = NULL;
+		regs = (struct pt_regs *)
+			(current->thread.ksp - sizeof(struct pt_regs));
+	}
+
+	if (type == NULL) {
+		struct kdbregs *rlp;
+		kdb_machreg_t contents;
+
+		for (i=0, rlp=kdbreglist; i<nkdbreglist; i++,rlp++) {
+			kdba_getregcontents(rlp->reg_name, regs, &contents);
+			kdb_printf("%-5s = 0x%p%c", rlp->reg_name, (void *)contents, (++count % 2) ? ' ' : '\n');
+		}
+
+		kdb_printf("&regs = 0x%p\n", regs);
+
+		return 0;
+	}
+
+	switch (type[0]) {
+	case 'm':
+		break;
+	case 'r':
+		break;
+	default:
+		return KDB_BADREG;
+	}
+
+	/* NOTREACHED */
+	return 0;
+}
+
+kdb_machreg_t
+kdba_getpc(kdb_eframe_t ef)
+{
+	return ef->nip;
+}
+
+int
+kdba_setpc(kdb_eframe_t ef, kdb_machreg_t newpc)
+{
+/* for ppc64, newpc passed in is actually a function descriptor for kdb. */
+    ef->nip =     kdba_getword(newpc+8, 8);
+    KDB_STATE_SET(IP_ADJUSTED);
+    return 0;
+}
+
+/*
+ * kdba_main_loop
+ *
+ *	Do any architecture specific set up before entering the main kdb loop.
+ *	The primary function of this routine is to make all processes look the
+ *	same to kdb, kdb must be able to list a process without worrying if the
+ *	process is running or blocked, so make all process look as though they
+ *	are blocked.
+ *
+ * Inputs:
+ *	reason		The reason KDB was invoked
+ *	error		The hardware-defined error code
+ *	error2		kdb's current reason code.  Initially error but can change
+ *			acording to kdb state.
+ *	db_result	Result from break or debug point.
+ *	ef		The exception frame at time of fault/breakpoint.  If reason
+ *			is KDB_REASON_SILENT then ef is NULL, otherwise it should
+ *			always be valid.
+ * Returns:
+ *	0	KDB was invoked for an event which it wasn't responsible
+ *	1	KDB handled the event for which it was invoked.
+ * Outputs:
+ *	Sets eip and esp in current->thread.
+ * Locking:
+ *	None.
+ * Remarks:
+ *	none.
+ */
+
+int
+kdba_main_loop(kdb_reason_t reason, kdb_reason_t reason2, int error,
+	       kdb_dbtrap_t db_result, kdb_eframe_t ef)
+{
+	int rv;
+	unsigned int msr;
+	if (current->thread.regs == NULL)
+	{
+		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)" : : "b" (&regs));
+		/* Fetch the link reg for this stack frame.
+		 NOTE: the prev kdb_printf fills in the lr. */
+		regs.nip = regs.link = ((unsigned long *)regs.gpr[1])[2];
+		regs.msr = get_msr();
+		regs.ctr = get_ctr();
+		regs.xer = get_xer();
+		regs.ccr = get_cr();
+		regs.trap = 0;
+		current->thread.regs = &regs;
+	}
+	if (ef) {
+		kdba_getregcontents("eip", ef, &(current->thread.regs->nip));
+		kdba_getregcontents("esp", ef, &(current->thread.regs->gpr[1]));
+		
+	}
+	msr = get_msr();
+	set_msr( msr & ~0x8000);
+	rv = kdb_main_loop(reason, reason2, error, db_result, ef);
+	set_msr(msr);
+	return rv;
+}
+
+void
+kdba_disableint(kdb_intstate_t *state)
+{
+	int *fp = (int *)state;
+	int   flags;
+
+	save_flags(flags);
+	cli();
+
+	*fp = flags;
+}
+
+void
+kdba_restoreint(kdb_intstate_t *state)
+{
+	int flags = *(int *)state;
+	restore_flags(flags);
+}
+
+void
+kdba_setsinglestep(struct pt_regs *regs)
+{
+	regs->msr |= MSR_SE;
+}
+
+void
+kdba_clearsinglestep(struct pt_regs *regs)
+{
+	
+	regs->msr &= ~MSR_SE;
+}
+
+int
+kdba_getcurrentframe(struct pt_regs *regs)
+{
+	regs->gpr[1] = getsp();
+	/* this stack pointer becomes invalid after we return, so take another step back.  */
+	regs->gpr[1] = kdba_getword(regs->gpr[1], 8);
+	return 0;
+}
+
+#ifdef KDB_HAVE_LONGJMP
+int kdba_setjmp(kdb_jmp_buf *buf)
+{
+    asm volatile (
+	"mflr 0; std 0,0(%0)\n\
+	 std	1,8(%0)\n\
+	 std	2,16(%0)\n\
+	 mfcr 0; std 0,24(%0)\n\
+	 std	13,32(%0)\n\
+	 std	14,40(%0)\n\
+	 std	15,48(%0)\n\
+	 std	16,56(%0)\n\
+	 std	17,64(%0)\n\
+	 std	18,72(%0)\n\
+	 std	19,80(%0)\n\
+	 std	20,88(%0)\n\
+	 std	21,96(%0)\n\
+	 std	22,104(%0)\n\
+	 std	23,112(%0)\n\
+	 std	24,120(%0)\n\
+	 std	25,128(%0)\n\
+	 std	26,136(%0)\n\
+	 std	27,144(%0)\n\
+	 std	28,152(%0)\n\
+	 std	29,160(%0)\n\
+	 std	30,168(%0)\n\
+	 std	31,176(%0)\n\
+	 " : : "r" (buf));
+    KDB_STATE_SET(LONGJMP);
+    return 0;
+}
+void kdba_longjmp(kdb_jmp_buf *buf, int val)
+{
+    if (val == 0)
+	val = 1;
+    asm volatile (
+	"ld	13,32(%0)\n\
+	 ld	14,40(%0)\n\
+	 ld	15,48(%0)\n\
+	 ld	16,56(%0)\n\
+	 ld	17,64(%0)\n\
+	 ld	18,72(%0)\n\
+	 ld	19,80(%0)\n\
+	 ld	20,88(%0)\n\
+	 ld	21,96(%0)\n\
+	 ld	22,104(%0)\n\
+	 ld	23,112(%0)\n\
+	 ld	24,120(%0)\n\
+	 ld	25,128(%0)\n\
+	 ld	26,136(%0)\n\
+	 ld	27,144(%0)\n\
+	 ld	28,152(%0)\n\
+	 ld	29,160(%0)\n\
+	 ld	30,168(%0)\n\
+	 ld	31,176(%0)\n\
+	 ld	0,24(%0)\n\
+	 mtcrf	0x38,0\n\
+	 ld	0,0(%0)\n\
+	 ld	1,8(%0)\n\
+	 ld	2,16(%0)\n\
+	 mtlr	0\n\
+	 mr	3,%1\n\
+	 " : : "r" (buf), "r" (val));
+}
+#endif
+
+/*
+ * kdba_enable_mce
+ *
+ *	This function is called once on each CPU to enable machine
+ *	check exception handling.
+ *
+ * Inputs:
+ *	None.
+ * Outputs:
+ *	None.
+ * Returns:
+ *	None.
+ * Locking:
+ *	None.
+ * Remarks:
+ *
+ */
+
+void
+kdba_enable_mce(void)
+{
+}
+
+/*
+ * kdba_enable_lbr
+ *
+ *	Enable last branch recording.
+ *
+ * Parameters:
+ *	None.
+ * Returns:
+ *	None
+ * Locking:
+ *	None
+ * Remarks:
+ *	None.
+ */
+
+void
+kdba_enable_lbr(void)
+{
+}
+
+/*
+ * kdba_disable_lbr
+ *
+ *	disable last branch recording.
+ *
+ * Parameters:
+ *	None.
+ * Returns:
+ *	None
+ * Locking:
+ *	None
+ * Remarks:
+ *	None.
+ */
+
+void
+kdba_disable_lbr(void)
+{
+}
+
+/*
+ * kdba_print_lbr
+ *
+ *	Print last branch and last exception addresses
+ *
+ * Parameters:
+ *	None.
+ * Returns:
+ *	None
+ * Locking:
+ *	None
+ * Remarks:
+ *	None.
+ */
+
+void
+kdba_print_lbr(void)
+{
+}
+
+/*
+ * kdba_getword
+ *
+ * 	Architecture specific function to access kernel virtual
+ *	address space.
+ *
+ * Parameters:
+ *	None.
+ * Returns:
+ *	None.
+ * Locking:
+ *	None.
+ * Remarks:
+ *	None.
+ */
+
+/* 	if (access_ok(VERIFY_READ,__gu_addr,size))			\ */
+ 
+extern inline void sync(void)
+{
+	asm volatile("sync; isync");
+}
+
+extern void (*debugger_fault_handler)(struct pt_regs *);
+extern void longjmp(u_int *, int);
+#if 0
+static void handle_fault(struct pt_regs *);
+
+static int fault_type;
+#endif
+
+unsigned long
+kdba_getword(unsigned long addr, size_t width)
+{
+	/*
+	 * This function checks the address for validity.  Any address
+	 * in the range PAGE_OFFSET to high_memory is legal, any address
+	 * which maps to a vmalloc region is legal, and any address which
+	 * is a user address, we use get_user() to verify validity.
+	 */
+
+    if (!valid_ppc64_kernel_address(addr, width)) {
+		        /*
+			 * Would appear to be an illegal kernel address;
+			 * Print a message once, and don't print again until
+			 * a legal address is used.
+			 */
+			if (!KDB_STATE(SUPPRESS)) {
+#if 1
+				kdb_printf("    kdb: Possibly Bad kernel address 0x%lx \n",addr);
+#else
+				kdb_printf("kdb: ! \n");
+#endif
+				KDB_STATE_SET(SUPPRESS);
+			}
+			return 0L;
+	}
+
+
+	/*
+	 * A good address.  Reset error flag.
+	 */
+	KDB_STATE_CLEAR(SUPPRESS);
+
+	switch (width) {
+	case 8:
+	{	unsigned long *lp;
+
+		lp = (unsigned long *)(addr);
+		return *lp;
+	}
+	case 4:
+	{	unsigned int *ip;
+
+		ip = (unsigned int *)(addr);
+		return *ip;
+	}
+	case 2:
+	{	unsigned short *sp;
+
+		sp = (unsigned short *)(addr);
+		return *sp;
+	}
+	case 1:
+	{	unsigned char *cp;
+
+		cp = (unsigned char *)(addr);
+		return *cp;
+	}
+	}
+
+	kdb_printf("kdbgetword: Bad width\n");
+	return 0L;
+}
+
+
+
+/*
+ * kdba_putword
+ *
+ * 	Architecture specific function to access kernel virtual
+ *	address space.
+ *
+ * Parameters:
+ *	None.
+ * Returns:
+ *	None.
+ * Locking:
+ *	None.
+ * Remarks:
+ *	None.
+ */
+
+unsigned long
+kdba_putword(unsigned long addr, size_t size, unsigned long contents)
+{
+	/*
+	 * This function checks the address for validity.  Any address
+	 * in the range PAGE_OFFSET to high_memory is legal, any address
+	 * which maps to a vmalloc region is legal, and any address which
+	 * is a user address, we use get_user() to verify validity.
+	 */
+
+	if (addr < PAGE_OFFSET) {
+		/*
+		 * Usermode address.
+		 */
+		unsigned long diag;
+
+		switch (size) {
+		case 4:
+		{	unsigned long *lp;
+
+			lp = (unsigned long *) addr;
+			diag = put_user(contents, lp);
+			break;
+		}
+		case 2:
+		{	unsigned short *sp;
+
+			sp = (unsigned short *) addr;
+			diag = put_user(contents, sp);
+			break;
+		}
+		case 1:
+		{	unsigned char *cp;
+
+			cp = (unsigned char *) addr;
+			diag = put_user(contents, cp);
+			break;
+		}
+		default:
+			kdb_printf("kdba_putword: Bad width\n");
+			return 0;
+		}
+
+		if (diag) {
+			if (!KDB_STATE(SUPPRESS)) {
+				kdb_printf("kdb: Bad user address 0x%lx\n", addr);
+				KDB_STATE_SET(SUPPRESS);
+			}
+			return 0;
+		}
+		KDB_STATE_CLEAR(SUPPRESS);
+		return 0;
+	}
+
+#if 0
+	if (addr > (unsigned long)high_memory) {
+		if (!kdb_vmlist_check(addr, addr+size)) {
+			/*
+			 * Would appear to be an illegal kernel address;
+			 * Print a message once, and don't print again until
+			 * a legal address is used.
+			 */
+			if (!KDB_STATE(SUPPRESS)) {
+				kdb_printf("kdb: xx Bad kernel address 0x%lx\n", addr);
+				KDB_STATE_SET(SUPPRESS);
+			}
+			return 0L;
+		}
+	}
+#endif
+
+	/*
+	 * A good address.  Reset error flag.
+	 */
+	KDB_STATE_CLEAR(SUPPRESS);
+
+	switch (size) {
+	case 4:
+	{	unsigned long *lp;
+
+		lp = (unsigned long *)(addr);
+		*lp = contents;
+		return 0;
+	}
+	case 2:
+	{	unsigned short *sp;
+
+		sp = (unsigned short *)(addr);
+		*sp = (unsigned short) contents;
+		return 0;
+	}
+	case 1:
+	{	unsigned char *cp;
+
+		cp = (unsigned char *)(addr);
+		*cp = (unsigned char) contents;
+		return 0;
+	}
+	}
+
+	kdb_printf("kdba_putword: Bad width\n");
+	return 0;
+}
+
+/*
+ * kdba_callback_die
+ *
+ *	Callback function for kernel 'die' function.
+ *
+ * Parameters:
+ *	regs	Register contents at time of trap
+ *	error_code  Trap-specific error code value
+ *	trapno	Trap number
+ *	vp	Pointer to die message
+ * Returns:
+ *	Returns 1 if fault handled by kdb.
+ * Locking:
+ *	None.
+ * Remarks:
+ *
+ */
+int
+kdba_callback_die(struct pt_regs *regs, int error_code, long trapno, void *vp)
+{
+	/*
+	 * Save a pointer to the message provided to 'die()'.
+	 */
+	kdb_diemsg = (char *)vp;
+
+	return kdb(KDB_REASON_OOPS, error_code, (kdb_eframe_t) regs);
+}
+
+/*
+ * kdba_callback_bp
+ *
+ *	Callback function for kernel breakpoint trap.
+ *
+ * Parameters:
+ *	regs	Register contents at time of trap
+ *	error_code  Trap-specific error code value
+ *	trapno	Trap number
+ *	vp	Not Used.
+ * Returns:
+ *	Returns 1 if fault handled by kdb.
+ * Locking:
+ *	None.
+ * Remarks:
+ *
+ */
+
+int
+kdba_callback_bp(struct pt_regs *regs, int error_code, long trapno, void *vp)
+{
+	int diag;
+
+	if (KDB_DEBUG(BP))
+		kdb_printf("cb_bp: e_c = %d  tn = %ld regs = 0x%p\n", error_code,
+			   trapno, regs);
+
+	diag = kdb(KDB_REASON_BREAK, error_code, (kdb_eframe_t) regs);
+
+	if (KDB_DEBUG(BP))
+		kdb_printf("cb_bp: e_c = %d  tn = %ld regs = 0x%p diag = %d\n", error_code,
+			   trapno, regs, diag);
+	return diag;
+}
+
+/*
+ * kdba_callback_debug
+ *
+ *	Callback function for kernel debug register trap.
+ *
+ * Parameters:
+ *	regs	Register contents at time of trap
+ *	error_code  Trap-specific error code value
+ *	trapno	Trap number
+ *	vp	Not used.
+ * Returns:
+ *	Returns 1 if fault handled by kdb.
+ * Locking:
+ *	None.
+ * Remarks:
+ *
+ */
+
+int
+kdba_callback_debug(struct pt_regs *regs, int error_code, long trapno, void *vp)
+{
+	return kdb(KDB_REASON_DEBUG, error_code, (kdb_eframe_t) regs);
+}
+
+
+
+
+/*
+ * kdba_adjust_ip
+ *
+ * 	Architecture specific adjustment of instruction pointer before leaving
+ *	kdb.
+ *
+ * Parameters:
+ *	reason		The reason KDB was invoked
+ *	error		The hardware-defined error code
+ *	ef		The exception frame at time of fault/breakpoint.  If reason
+ *			is KDB_REASON_SILENT then ef is NULL, otherwise it should
+ *			always be valid.
+ * Returns:
+ *	None.
+ * Locking:
+ *	None.
+ * Remarks:
+ *	noop on ix86.
+ */
+
+void
+kdba_adjust_ip(kdb_reason_t reason, int error, kdb_eframe_t ef)
+{
+	return;
+}
+
+
+
+/*
+ * kdba_find_tb_table
+ *
+ * 	Find the traceback table (defined by the ELF64 ABI) located at
+ *	the end of the function containing pc.
+ *
+ * Parameters:
+ *	eip	starting instruction addr.  does not need to be at the start of the func.
+ *	tab	table to populate if successful
+ * Returns:
+ *	non-zero if successful.  unsuccessful means that a valid tb table was not found
+ * Locking:
+ *	None.
+ * Remarks:
+ *	None.
+ */
+int kdba_find_tb_table(kdb_machreg_t eip, kdbtbtable_t *tab)
+{
+	kdb_machreg_t codeaddr = eip;
+	kdb_machreg_t codeaddr_max;
+	kdb_machreg_t tbtab_start;
+	int instr;
+	int num_parms;
+
+	if (tab == NULL)
+		return 0;
+	memset(tab, 0, sizeof(tab));
+
+	if (eip < PAGE_OFFSET) {  /* this is gonna fail for userspace, at least for now.. */
+	    return 0;
+	}
+
+	/* Scan instructions starting at codeaddr for 128k max */
+	for (codeaddr_max = codeaddr + 128*1024*4;
+	     codeaddr < codeaddr_max;
+	     codeaddr += 4) {
+		instr = kdba_getword(codeaddr, 4);
+		if (instr == 0) {
+			/* table should follow. */
+			int version;
+			unsigned long flags;
+			tbtab_start = codeaddr;	/* save it to compute func start addr */
+			codeaddr += 4;
+			flags = kdba_getword(codeaddr, 8);
+			tab->flags = flags;
+			version = (flags >> 56) & 0xff;
+			if (version != 0)
+				continue;	/* No tb table here. */
+			/* Now, like the version, some of the flags are values
+			 that are more conveniently extracted... */
+			tab->fp_saved = (flags >> 24) & 0x3f;
+			tab->gpr_saved = (flags >> 16) & 0x3f;
+			tab->fixedparms = (flags >> 8) & 0xff;
+			tab->floatparms = (flags >> 1) & 0x7f;
+			codeaddr += 8;
+			num_parms = tab->fixedparms + tab->floatparms;
+			if (num_parms) {
+				unsigned int parminfo;
+				int parm;
+				if (num_parms > 32)
+					return 1;	/* incomplete */
+				parminfo = kdba_getword(codeaddr, 4);
+				/* decode parminfo...32 bits.
+				 A zero means fixed.  A one means float and the
+				 following bit determines single (0) or double (1).
+				 */
+				for (parm = 0; parm < num_parms; parm++) {
+					if (parminfo & 0x80000000) {
+						parminfo <<= 1;
+						if (parminfo & 0x80000000)
+							tab->parminfo[parm] = KDBTBTAB_PARMDFLOAT;
+						else
+							tab->parminfo[parm] = KDBTBTAB_PARMSFLOAT;
+					} else {
+						tab->parminfo[parm] = KDBTBTAB_PARMFIXED;
+					}
+					parminfo <<= 1;
+				}
+				codeaddr += 4;
+			}
+			if (flags & KDBTBTAB_FLAGSHASTBOFF) {
+				tab->tb_offset = kdba_getword(codeaddr, 4);
+				if (tab->tb_offset > 0) {
+					tab->funcstart = tbtab_start - tab->tb_offset;
+				}
+				codeaddr += 4;
+			}
+			/* hand_mask appears to be always be omitted. */
+			if (flags & KDBTBTAB_FLAGSHASCTL) {
+				/* Assume this will never happen for C or asm */
+				return 1;	/* incomplete */
+			}
+			if (flags & KDBTBTAB_FLAGSNAMEPRESENT) {
+				int i;
+				short namlen = kdba_getword(codeaddr, 2);
+				if (namlen >= sizeof(tab->name))
+					namlen = sizeof(tab->name)-1;
+				codeaddr += 2;
+				for (i = 0; i < namlen; i++) {
+					tab->name[i] = kdba_getword(codeaddr++, 1);
+				}
+				tab->name[namlen] = '\0';
+			}
+			/* Fake up a symtab entry in case the caller finds it useful */
+			tab->symtab.value = tab->symtab.sym_start = tab->funcstart;
+			tab->symtab.sym_name = tab->name;
+			tab->symtab.sym_end = tbtab_start;
+			return 1;
+		}
+	}
+	return 0;	/* hit max...sorry. */
+}
+
+
+int
+kdba_putarea_size(unsigned long to_xxx, void *from, size_t size)
+{
+    char c;
+    kdb_printf("   ** this function calls copy_to_user...  \n");
+    kdb_printf("   kdba_putarea_size [0x%ul]\n",(unsigned int) to_xxx);
+    c = *((volatile char *)from);
+    c=*((volatile char *)from+size-1);
+    return __copy_to_user((void *)to_xxx,from,size);
+}
+
+
+
+
+
+/*
+ * valid_ppc64_kernel_address() returns '1' if the address passed in is
+ * within a valid range.  Function returns 0 if address is outside valid ranges.
+ */
+
+/*
+
+    KERNELBASE    c000000000000000
+        (good range)
+    high_memory   c0000000 20000000
+
+    VMALLOC_START d000000000000000
+        (good range)
+    VMALLOC_END   VMALLOC_START + VALID_EA_BITS  
+
+    IMALLOC_START e000000000000000
+        (good range)
+    IMALLOC_END   IMALLOC_START + VALID_EA_BITS
+
+*/
+
+int valid_ppc64_kernel_address(unsigned long addr, unsigned long size)
+{
+	unsigned long i;
+	unsigned long end = (addr + size - 1);
+
+
+	for (i = addr; i <= end; i = i ++ ) {
+	    if (((unsigned long)i < (unsigned long long)KERNELBASE     )  || 
+		(((unsigned long)i > (unsigned long long)high_memory) &&
+		 ((unsigned long)i < (unsigned long long)VMALLOC_START) )  ||
+		(((unsigned long)i > (unsigned long long)VMALLOC_END) &&
+		 ((unsigned long)i < (unsigned long long)IMALLOC_START) )  ||
+		( (unsigned long)i > (unsigned long long)IMALLOC_END    )       ) {
+		return 0;
+	    }
+	}
+	return 1;
+}
+
+
+int
+kdba_getarea_size(void *to, unsigned long from_xxx, size_t size)
+{
+	int is_valid_kern_addr = valid_ppc64_kernel_address(from_xxx, size);
+	int diag = 0;
+
+	*((volatile char *)to) = '\0';
+	*((volatile char *)to + size - 1) = '\0';
+
+
+	if (is_valid_kern_addr) {
+		memcpy(to, (void *)from_xxx, size);
+	} else {
+            /*  user space address, just return.  */
+	    diag = -1;
+	}
+
+	return diag;
+}
+
+
+
+/*
+ *  kdba_readarea_size, reads size-lump of memory into to* passed in, returns size.
+ * Making it feel a bit more like mread.. when i'm clearer on kdba end, probally will
+ * remove one of these.
+ */
+int
+kdba_readarea_size(unsigned long from_xxx,void *to, size_t size)
+{
+    int is_valid_kern_addr = valid_ppc64_kernel_address(from_xxx, size);
+
+    *((volatile char *)to) = '\0';
+    *((volatile char *)to + size - 1) = '\0';
+
+    if (is_valid_kern_addr) {
+	memcpy(to, (void *)from_xxx, size);
+	return size;
+    } else {
+	/*  user-space, just return...    */
+	return 0;
+    }
+    /* wont get here */
+    return 0;
+}
+
diff -urN linux-2.4.21-pre3/arch/ppc64/kdb/nonstdio.h linux-2.4.21-pre4/arch/ppc64/kdb/nonstdio.h
--- linux-2.4.21-pre3/arch/ppc64/kdb/nonstdio.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/arch/ppc64/kdb/nonstdio.h	Tue Jan 28 19:44:29 2003
@@ -0,0 +1,32 @@
+#ifndef NONSTDIO_H
+#define NONSTDIO_H
+
+#define EOF	(-1)
+#if 0 
+typedef int	FILE;
+#endif
+
+/* candidate for removal.. */
+extern FILE *xmon_stdin, *xmon_stdout;
+#if 0
+#define stdin	xmon_stdin
+#define stdout	xmon_stdout
+#endif
+#define printf	xmon_printf
+#define fprintf	xmon_fprintf
+#define fputs	xmon_fputs
+#define fgets	xmon_fgets
+#define putchar	xmon_putchar
+#define getchar	xmon_getchar
+#define putc	xmon_putc
+#define getc	xmon_getc
+#define fopen(n, m)	NULL
+#define fflush(f)	do {} while (0)
+#define fclose(f)	do {} while (0)
+extern char *fgets(char *, int, void *);
+extern void xmon_printf(const char *, ...);
+extern void xmon_fprintf(void *, const char *, ...);
+extern void xmon_sprintf(char *, const char *, ...);
+#define perror(s)	printf("%s: no files!\n", (s))
+
+#endif
diff -urN linux-2.4.21-pre3/arch/ppc64/kdb/opintl.h linux-2.4.21-pre4/arch/ppc64/kdb/opintl.h
--- linux-2.4.21-pre3/arch/ppc64/kdb/opintl.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/arch/ppc64/kdb/opintl.h	Tue Jan 28 19:44:29 2003
@@ -0,0 +1,42 @@
+/* opintl.h - opcodes specific header for gettext code.
+   Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+
+   Written by Tom Tromey <tromey@cygnus.com>
+
+   This file is part of the opcodes library used by GAS and the GNU binutils.
+
+   You should have received a copy of the GNU General Public License
+   along with GAS; see the file COPYING.  If not, write to the Free
+   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA. */
+
+#ifdef ENABLE_NLS
+# include <libintl.h>
+/* Note the use of dgetext() and PACKAGE here, rather than gettext().
+   
+   This is because the code in this directory is used to build a library which
+   will be linked with code in other directories to form programs.  We want to
+   maintain a seperate translation file for this directory however, rather
+   than being forced to merge it with that of any program linked to
+   libopcodes.  This is a library, so it cannot depend on the catalog
+   currently loaded.
+
+   In order to do this, we have to make sure that when we extract messages we
+   use the OPCODES domain rather than the domain of the program that included
+   the opcodes library, (eg OBJDUMP).  Hence we use dgettext (PACKAGE, String)
+   and define PACKAGE to be 'opcodes'.  (See the code in configure).  */
+# define _(String) dgettext (PACKAGE, String)
+# ifdef gettext_noop
+#  define N_(String) gettext_noop (String)
+# else
+#  define N_(String) (String)
+# endif
+#else
+# define gettext(Msgid) (Msgid)
+# define dgettext(Domainname, Msgid) (Msgid)
+# define dcgettext(Domainname, Msgid, Category) (Msgid)
+# define textdomain(Domainname) while (0) /* nothing */
+# define bindtextdomain(Domainname, Dirname) while (0) /* nothing */
+# define _(String) (String)
+# define N_(String) (String)
+#endif
diff -urN linux-2.4.21-pre3/arch/ppc64/kdb/ppc-dis.c linux-2.4.21-pre4/arch/ppc64/kdb/ppc-dis.c
--- linux-2.4.21-pre3/arch/ppc64/kdb/ppc-dis.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/arch/ppc64/kdb/ppc-dis.c	Tue Jan 28 19:44:29 2003
@@ -0,0 +1,281 @@
+/* ppc-dis.c -- Disassemble PowerPC instructions
+   Copyright 1994 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Cygnus Support
+
+This file is part of GDB, GAS, and the GNU binutils.
+
+GDB, GAS, and the GNU binutils are free software; you can redistribute
+them and/or modify them under the terms of the GNU General Public
+License as published by the Free Software Foundation; either version
+2, or (at your option) any later version.
+
+GDB, GAS, and the GNU binutils are distributed in the hope that they
+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 file; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+#ifdef __KERNEL__
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/dis-asm.h>
+#include <linux/kdb.h>
+#include "ppc.h"
+
+#if 0
+#include <setjmp.h>
+#endif
+
+#else
+#include <stdio.h>
+#include "sysdep.h"
+#include "dis-asm.h"
+#include "opcode/ppc.h"
+#endif
+bfd_vma
+bfd_getb32 (addr)
+     register const bfd_byte *addr;
+{
+  unsigned long v;
+
+  v = (unsigned long) addr[0] << 24;
+  v |= (unsigned long) addr[1] << 16;
+  v |= (unsigned long) addr[2] << 8;
+  v |= (unsigned long) addr[3];
+  return (bfd_vma) v;
+}
+
+bfd_vma
+bfd_getl32 (addr)
+     register const bfd_byte *addr;
+{
+  unsigned long v;
+
+  v = (unsigned long) addr[0];
+  v |= (unsigned long) addr[1] << 8;
+  v |= (unsigned long) addr[2] << 16;
+  v |= (unsigned long) addr[3] << 24;
+  return (bfd_vma) v;
+}
+/* This file provides several disassembler functions, all of which use
+   the disassembler interface defined in dis-asm.h.  Several functions
+   are provided because this file handles disassembly for the PowerPC
+   in both big and little endian mode and also for the POWER (RS/6000)
+   chip.  */
+
+static int print_insn_powerpc PARAMS ((bfd_vma, struct disassemble_info *,
+				       int bigendian, int dialect));
+
+/* Print a big endian PowerPC instruction.  For convenience, also
+   disassemble instructions supported by the Motorola PowerPC 601
+   and the Altivec vector unit.  */
+
+int
+print_insn_big_powerpc (memaddr, info)
+     bfd_vma memaddr;
+     struct disassemble_info *info;
+{
+  return print_insn_powerpc (memaddr, info, 1,
+			     PPC_OPCODE_PPC | PPC_OPCODE_601 |
+			     PPC_OPCODE_ALTIVEC);
+}
+
+/* Print a little endian PowerPC instruction.  For convenience, also
+   disassemble instructions supported by the Motorola PowerPC 601
+   and the Altivec vector unit.  */
+
+int
+print_insn_little_powerpc (memaddr, info)
+     bfd_vma memaddr;
+     struct disassemble_info *info;
+{
+  return print_insn_powerpc (memaddr, info, 0,
+			     PPC_OPCODE_PPC | PPC_OPCODE_601 |
+			     PPC_OPCODE_ALTIVEC);
+}
+
+/* Print a POWER (RS/6000) instruction.  */
+
+int
+print_insn_rs6000 (memaddr, info)
+     bfd_vma memaddr;
+     struct disassemble_info *info;
+{
+  return print_insn_powerpc (memaddr, info, 1, PPC_OPCODE_POWER);
+}
+
+/* Print a PowerPC or POWER instruction.  */
+
+static int
+print_insn_powerpc (memaddr, info, bigendian, dialect)
+     bfd_vma memaddr;
+     struct disassemble_info *info;
+     int bigendian;
+     int dialect;
+{
+  bfd_byte buffer[4];
+  int status;
+  unsigned long insn;
+  const struct powerpc_opcode *opcode;
+  const struct powerpc_opcode *opcode_end;
+  unsigned long op;
+
+  (*info->fprintf_func) (info->stream, "  ");
+
+  status = (*info->read_memory_func) (memaddr, buffer, 4, info);
+  if (status != 0)
+    {
+      (*info->memory_error_func) (status, memaddr, info);
+      return -1;
+    }
+
+  if (bigendian)
+    insn = bfd_getb32 (buffer);
+  else
+    insn = bfd_getl32 (buffer);
+
+  /* Get the major opcode of the instruction.  */
+  op = PPC_OP (insn);
+
+  /* Find the first match in the opcode table.  We could speed this up
+     a bit by doing a binary search on the major opcode.  */
+  opcode_end = powerpc_opcodes + powerpc_num_opcodes;
+  for (opcode = powerpc_opcodes; opcode < opcode_end; opcode++)
+    {
+      unsigned long table_op;
+      const unsigned char *opindex;
+      const struct powerpc_operand *operand;
+      int invalid;
+      int need_comma;
+      int need_paren;
+
+      table_op = PPC_OP (opcode->opcode);
+      if (op < table_op)
+	break;
+      if (op > table_op)
+	continue;
+
+      if ((insn & opcode->mask) != opcode->opcode
+	  || (opcode->flags & dialect) == 0)
+	continue;
+
+      /* Make two passes over the operands.  First see if any of them
+	 have extraction functions, and, if they do, make sure the
+	 instruction is valid.  */
+      invalid = 0;
+      for (opindex = opcode->operands; *opindex != 0; opindex++)
+	{
+	  operand = powerpc_operands + *opindex;
+	  if (operand->extract)
+	    (*operand->extract) (insn, &invalid);
+	}
+      if (invalid)
+	continue;
+
+      /* The instruction is valid.  */
+      (*info->fprintf_func) (info->stream, "%s", opcode->name);
+      if (opcode->operands[0] != 0)
+	(*info->fprintf_func) (info->stream, "\t");
+
+      /* Now extract and print the operands.  */
+      need_comma = 0;
+      need_paren = 0;
+      for (opindex = opcode->operands; *opindex != 0; opindex++)
+	{
+	  long value;
+
+	  operand = powerpc_operands + *opindex;
+
+	  /* Operands that are marked FAKE are simply ignored.  We
+	     already made sure that the extract function considered
+	     the instruction to be valid.  */
+	  if ((operand->flags & PPC_OPERAND_FAKE) != 0)
+	    continue;
+
+	  /* Extract the value from the instruction.  */
+	  if (operand->extract)
+	    value = (*operand->extract) (insn, (int *) NULL);
+	  else
+	    {
+	      value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
+	      if ((operand->flags & PPC_OPERAND_SIGNED) != 0
+		  && (value & (1 << (operand->bits - 1))) != 0)
+		value -= 1 << operand->bits;
+	    }
+
+	  /* If the operand is optional, and the value is zero, don't
+	     print anything.  */
+	  if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0
+	      && (operand->flags & PPC_OPERAND_NEXT) == 0
+	      && value == 0)
+	    continue;
+
+	  if (need_comma)
+	    {
+	      (*info->fprintf_func) (info->stream, ",");
+	      need_comma = 0;
+	    }
+
+	  /* Print the operand as directed by the flags.  */
+	  if ((operand->flags & PPC_OPERAND_GPR) != 0)
+	    (*info->fprintf_func) (info->stream, "r%ld", value);
+	  else if ((operand->flags & PPC_OPERAND_FPR) != 0)
+	    (*info->fprintf_func) (info->stream, "f%ld", value);
+	  else if ((operand->flags & PPC_OPERAND_VR) != 0)
+	    (*info->fprintf_func) (info->stream, "v%ld", value);
+	  else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0)
+	    (*info->print_address_func) (memaddr + value, info);
+	  else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
+	    (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info);
+	  else if ((operand->flags & PPC_OPERAND_CR) == 0
+		   || (dialect & PPC_OPCODE_PPC) == 0)
+	    (*info->fprintf_func) (info->stream, "%ld", value);
+	  else
+	    {
+	      if (operand->bits == 3)
+		(*info->fprintf_func) (info->stream, "cr%d", value);
+	      else
+		{
+		  static const char *cbnames[4] = { "lt", "gt", "eq", "so" };
+		  int cr;
+		  int cc;
+
+		  cr = value >> 2;
+		  if (cr != 0)
+		    (*info->fprintf_func) (info->stream, "4*cr%d", cr);
+		  cc = value & 3;
+		  if (cc != 0)
+		    {
+		      if (cr != 0)
+			(*info->fprintf_func) (info->stream, "+");
+		      (*info->fprintf_func) (info->stream, "%s", cbnames[cc]);
+		    }
+		}
+	    }
+
+	  if (need_paren)
+	    {
+	      (*info->fprintf_func) (info->stream, ")");
+	      need_paren = 0;
+	    }
+
+	  if ((operand->flags & PPC_OPERAND_PARENS) == 0)
+	    need_comma = 1;
+	  else
+	    {
+	      (*info->fprintf_func) (info->stream, "(");
+	      need_paren = 1;
+	    }
+	}
+
+      /* We have found and printed an instruction; return.  */
+      return 4;
+    }
+
+  /* We could not find a match.  */
+  (*info->fprintf_func) (info->stream, ".long 0x%lx", insn);
+
+  return 4;
+}
diff -urN linux-2.4.21-pre3/arch/ppc64/kdb/ppc-opc.c linux-2.4.21-pre4/arch/ppc64/kdb/ppc-opc.c
--- linux-2.4.21-pre3/arch/ppc64/kdb/ppc-opc.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/arch/ppc64/kdb/ppc-opc.c	Tue Jan 28 19:44:29 2003
@@ -0,0 +1,3491 @@
+/* ppc-opc.c -- PowerPC opcode list
+   Copyright (c) 1994, 95, 96, 97, 98, 99, 2000 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Cygnus Support
+
+This file is part of GDB, GAS, and the GNU binutils.
+
+GDB, GAS, and the GNU binutils are free software; you can redistribute
+them and/or modify them under the terms of the GNU General Public
+License as published by the Free Software Foundation; either version
+2, or (at your option) any later version.
+
+GDB, GAS, and the GNU binutils are distributed in the hope that they
+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 file; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+#ifndef __KERNEL__
+#include <stdio.h>
+#include "sysdep.h"
+#include "opcode/ppc.h"
+#include "opintl.h"
+#else
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/dis-asm.h>
+#include <linux/kdb.h>
+#include "ppc.h"
+#include "opintl.h"
+#endif
+/* This file holds the PowerPC opcode table.  The opcode table
+   includes almost all of the extended instruction mnemonics.  This
+   permits the disassembler to use them, and simplifies the assembler
+   logic, at the cost of increasing the table size.  The table is
+   strictly constant data, so the compiler should be able to put it in
+   the .text section.
+
+   This file also holds the operand table.  All knowledge about
+   inserting operands into instructions and vice-versa is kept in this
+   file.  */
+
+/* Local insertion and extraction functions.  */
+
+static unsigned long insert_bat PARAMS ((unsigned long, long, const char **));
+static long extract_bat PARAMS ((unsigned long, int *));
+static unsigned long insert_bba PARAMS ((unsigned long, long, const char **));
+static long extract_bba PARAMS ((unsigned long, int *));
+static unsigned long insert_bd PARAMS ((unsigned long, long, const char **));
+static long extract_bd PARAMS ((unsigned long, int *));
+static unsigned long insert_bdm PARAMS ((unsigned long, long, const char **));
+static long extract_bdm PARAMS ((unsigned long, int *));
+static unsigned long insert_bdp PARAMS ((unsigned long, long, const char **));
+static long extract_bdp PARAMS ((unsigned long, int *));
+static int valid_bo PARAMS ((long));
+static unsigned long insert_bo PARAMS ((unsigned long, long, const char **));
+static long extract_bo PARAMS ((unsigned long, int *));
+static unsigned long insert_boe PARAMS ((unsigned long, long, const char **));
+static long extract_boe PARAMS ((unsigned long, int *));
+static unsigned long insert_ds PARAMS ((unsigned long, long, const char **));
+static long extract_ds PARAMS ((unsigned long, int *));
+static unsigned long insert_li PARAMS ((unsigned long, long, const char **));
+static long extract_li PARAMS ((unsigned long, int *));
+static unsigned long insert_mbe PARAMS ((unsigned long, long, const char **));
+static long extract_mbe PARAMS ((unsigned long, int *));
+static unsigned long insert_mb6 PARAMS ((unsigned long, long, const char **));
+static long extract_mb6 PARAMS ((unsigned long, int *));
+static unsigned long insert_nb PARAMS ((unsigned long, long, const char **));
+static long extract_nb PARAMS ((unsigned long, int *));
+static unsigned long insert_nsi PARAMS ((unsigned long, long, const char **));
+static long extract_nsi PARAMS ((unsigned long, int *));
+static unsigned long insert_ral PARAMS ((unsigned long, long, const char **));
+static unsigned long insert_ram PARAMS ((unsigned long, long, const char **));
+static unsigned long insert_ras PARAMS ((unsigned long, long, const char **));
+static unsigned long insert_rbs PARAMS ((unsigned long, long, const char **));
+static long extract_rbs PARAMS ((unsigned long, int *));
+static unsigned long insert_sh6 PARAMS ((unsigned long, long, const char **));
+static long extract_sh6 PARAMS ((unsigned long, int *));
+static unsigned long insert_spr PARAMS ((unsigned long, long, const char **));
+static long extract_spr PARAMS ((unsigned long, int *));
+static unsigned long insert_tbr PARAMS ((unsigned long, long, const char **));
+static long extract_tbr PARAMS ((unsigned long, int *));
+
+/* The operands table.
+
+   The fields are bits, shift, insert, extract, flags.
+
+   We used to put parens around the various additions, like the one
+   for BA just below.  However, that caused trouble with feeble
+   compilers with a limit on depth of a parenthesized expression, like
+   (reportedly) the compiler in Microsoft Developer Studio 5.  So we
+   omit the parens, since the macros are never used in a context where
+   the addition will be ambiguous.  */
+
+const struct powerpc_operand powerpc_operands[] =
+{
+  /* The zero index is used to indicate the end of the list of
+     operands.  */
+#define UNUSED 0
+  { 0, 0, 0, 0, 0 },
+
+  /* The BA field in an XL form instruction.  */
+#define BA UNUSED + 1
+#define BA_MASK (0x1f << 16)
+  { 5, 16, 0, 0, PPC_OPERAND_CR },
+
+  /* The BA field in an XL form instruction when it must be the same
+     as the BT field in the same instruction.  */
+#define BAT BA + 1
+  { 5, 16, insert_bat, extract_bat, PPC_OPERAND_FAKE },
+
+  /* The BB field in an XL form instruction.  */
+#define BB BAT + 1
+#define BB_MASK (0x1f << 11)
+  { 5, 11, 0, 0, PPC_OPERAND_CR },
+
+  /* The BB field in an XL form instruction when it must be the same
+     as the BA field in the same instruction.  */
+#define BBA BB + 1
+  { 5, 11, insert_bba, extract_bba, PPC_OPERAND_FAKE },
+
+  /* The BD field in a B form instruction.  The lower two bits are
+     forced to zero.  */
+#define BD BBA + 1
+  { 16, 0, insert_bd, extract_bd, PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED },
+
+  /* The BD field in a B form instruction when absolute addressing is
+     used.  */
+#define BDA BD + 1
+  { 16, 0, insert_bd, extract_bd, PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED },
+
+  /* The BD field in a B form instruction when the - modifier is used.
+     This sets the y bit of the BO field appropriately.  */
+#define BDM BDA + 1
+  { 16, 0, insert_bdm, extract_bdm,
+      PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED },
+
+  /* The BD field in a B form instruction when the - modifier is used
+     and absolute address is used.  */
+#define BDMA BDM + 1
+  { 16, 0, insert_bdm, extract_bdm,
+      PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED },
+
+  /* The BD field in a B form instruction when the + modifier is used.
+     This sets the y bit of the BO field appropriately.  */
+#define BDP BDMA + 1
+  { 16, 0, insert_bdp, extract_bdp,
+      PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED },
+
+  /* The BD field in a B form instruction when the + modifier is used
+     and absolute addressing is used.  */
+#define BDPA BDP + 1
+  { 16, 0, insert_bdp, extract_bdp,
+      PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED },
+
+  /* The BF field in an X or XL form instruction.  */
+#define BF BDPA + 1
+  { 3, 23, 0, 0, PPC_OPERAND_CR },
+
+  /* An optional BF field.  This is used for comparison instructions,
+     in which an omitted BF field is taken as zero.  */
+#define OBF BF + 1
+  { 3, 23, 0, 0, PPC_OPERAND_CR | PPC_OPERAND_OPTIONAL },
+
+  /* The BFA field in an X or XL form instruction.  */
+#define BFA OBF + 1
+  { 3, 18, 0, 0, PPC_OPERAND_CR },
+
+  /* The BI field in a B form or XL form instruction.  */
+#define BI BFA + 1
+#define BI_MASK (0x1f << 16)
+  { 5, 16, 0, 0, PPC_OPERAND_CR },
+
+  /* The BO field in a B form instruction.  Certain values are
+     illegal.  */
+#define BO BI + 1
+#define BO_MASK (0x1f << 21)
+  { 5, 21, insert_bo, extract_bo, 0 },
+
+  /* The BO field in a B form instruction when the + or - modifier is
+     used.  This is like the BO field, but it must be even.  */
+#define BOE BO + 1
+  { 5, 21, insert_boe, extract_boe, 0 },
+
+  /* The BT field in an X or XL form instruction.  */
+#define BT BOE + 1
+  { 5, 21, 0, 0, PPC_OPERAND_CR },
+
+  /* The condition register number portion of the BI field in a B form
+     or XL form instruction.  This is used for the extended
+     conditional branch mnemonics, which set the lower two bits of the
+     BI field.  This field is optional.  */
+#define CR BT + 1
+  { 3, 18, 0, 0, PPC_OPERAND_CR | PPC_OPERAND_OPTIONAL },
+
+  /* The D field in a D form instruction.  This is a displacement off
+     a register, and implies that the next operand is a register in
+     parentheses.  */
+#define D CR + 1
+  { 16, 0, 0, 0, PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED },
+
+  /* The DS field in a DS form instruction.  This is like D, but the
+     lower two bits are forced to zero.  */
+#define DS D + 1
+  { 16, 0, insert_ds, extract_ds, PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED },
+
+  /* The E field in a wrteei instruction.  */
+#define E DS + 1
+  { 1, 15, 0, 0, 0 },
+
+  /* The FL1 field in a POWER SC form instruction.  */
+#define FL1 E + 1
+  { 4, 12, 0, 0, 0 },
+
+  /* The FL2 field in a POWER SC form instruction.  */
+#define FL2 FL1 + 1
+  { 3, 2, 0, 0, 0 },
+
+  /* The FLM field in an XFL form instruction.  */
+#define FLM FL2 + 1
+  { 8, 17, 0, 0, 0 },
+
+  /* The FRA field in an X or A form instruction.  */
+#define FRA FLM + 1
+#define FRA_MASK (0x1f << 16)
+  { 5, 16, 0, 0, PPC_OPERAND_FPR },
+
+  /* The FRB field in an X or A form instruction.  */
+#define FRB FRA + 1
+#define FRB_MASK (0x1f << 11)
+  { 5, 11, 0, 0, PPC_OPERAND_FPR },
+
+  /* The FRC field in an A form instruction.  */
+#define FRC FRB + 1
+#define FRC_MASK (0x1f << 6)
+  { 5, 6, 0, 0, PPC_OPERAND_FPR },
+
+  /* The FRS field in an X form instruction or the FRT field in a D, X
+     or A form instruction.  */
+#define FRS FRC + 1
+#define FRT FRS
+  { 5, 21, 0, 0, PPC_OPERAND_FPR },
+
+  /* The FXM field in an XFX instruction.  */
+#define FXM FRS + 1
+#define FXM_MASK (0xff << 12)
+  { 8, 12, 0, 0, 0 },
+
+  /* The L field in a D or X form instruction.  */
+#define L FXM + 1
+  { 1, 21, 0, 0, PPC_OPERAND_OPTIONAL },
+
+  /* The LEV field in a POWER SC form instruction.  */
+#define LEV L + 1
+  { 7, 5, 0, 0, 0 },
+
+  /* The LI field in an I form instruction.  The lower two bits are
+     forced to zero.  */
+#define LI LEV + 1
+  { 26, 0, insert_li, extract_li, PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED },
+
+  /* The LI field in an I form instruction when used as an absolute
+     address.  */
+#define LIA LI + 1
+  { 26, 0, insert_li, extract_li, PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED },
+
+  /* The MB field in an M form instruction.  */
+#define MB LIA + 1
+#define MB_MASK (0x1f << 6)
+  { 5, 6, 0, 0, 0 },
+
+  /* The ME field in an M form instruction.  */
+#define ME MB + 1
+#define ME_MASK (0x1f << 1)
+  { 5, 1, 0, 0, 0 },
+
+  /* The MB and ME fields in an M form instruction expressed a single
+     operand which is a bitmask indicating which bits to select.  This
+     is a two operand form using PPC_OPERAND_NEXT.  See the
+     description in opcode/ppc.h for what this means.  */
+#define MBE ME + 1
+  { 5, 6, 0, 0, PPC_OPERAND_OPTIONAL | PPC_OPERAND_NEXT },
+  { 32, 0, insert_mbe, extract_mbe, 0 },
+
+  /* The MB or ME field in an MD or MDS form instruction.  The high
+     bit is wrapped to the low end.  */
+#define MB6 MBE + 2
+#define ME6 MB6
+#define MB6_MASK (0x3f << 5)
+  { 6, 5, insert_mb6, extract_mb6, 0 },
+
+  /* The NB field in an X form instruction.  The value 32 is stored as
+     0.  */
+#define NB MB6 + 1
+  { 6, 11, insert_nb, extract_nb, 0 },
+
+  /* The NSI field in a D form instruction.  This is the same as the
+     SI field, only negated.  */
+#define NSI NB + 1
+  { 16, 0, insert_nsi, extract_nsi,
+      PPC_OPERAND_NEGATIVE | PPC_OPERAND_SIGNED },
+
+  /* The RA field in an D, DS, X, XO, M, or MDS form instruction.  */
+#define RA NSI + 1
+#define RA_MASK (0x1f << 16)
+  { 5, 16, 0, 0, PPC_OPERAND_GPR },
+
+  /* The RA field in a D or X form instruction which is an updating
+     load, which means that the RA field may not be zero and may not
+     equal the RT field.  */
+#define RAL RA + 1
+  { 5, 16, insert_ral, 0, PPC_OPERAND_GPR },
+
+  /* The RA field in an lmw instruction, which has special value
+     restrictions.  */
+#define RAM RAL + 1
+  { 5, 16, insert_ram, 0, PPC_OPERAND_GPR },
+
+  /* The RA field in a D or X form instruction which is an updating
+     store or an updating floating point load, which means that the RA
+     field may not be zero.  */
+#define RAS RAM + 1
+  { 5, 16, insert_ras, 0, PPC_OPERAND_GPR },
+
+  /* The RB field in an X, XO, M, or MDS form instruction.  */
+#define RB RAS + 1
+#define RB_MASK (0x1f << 11)
+  { 5, 11, 0, 0, PPC_OPERAND_GPR },
+
+  /* The RB field in an X form instruction when it must be the same as
+     the RS field in the instruction.  This is used for extended
+     mnemonics like mr.  */
+#define RBS RB + 1
+  { 5, 1, insert_rbs, extract_rbs, PPC_OPERAND_FAKE },
+
+  /* The RS field in a D, DS, X, XFX, XS, M, MD or MDS form
+     instruction or the RT field in a D, DS, X, XFX or XO form
+     instruction.  */
+#define RS RBS + 1
+#define RT RS
+#define RT_MASK (0x1f << 21)
+  { 5, 21, 0, 0, PPC_OPERAND_GPR },
+
+  /* The SH field in an X or M form instruction.  */
+#define SH RS + 1
+#define SH_MASK (0x1f << 11)
+  { 5, 11, 0, 0, 0 },
+
+  /* The SH field in an MD form instruction.  This is split.  */
+#define SH6 SH + 1
+#define SH6_MASK ((0x1f << 11) | (1 << 1))
+  { 6, 1, insert_sh6, extract_sh6, 0 },
+
+  /* The SI field in a D form instruction.  */
+#define SI SH6 + 1
+  { 16, 0, 0, 0, PPC_OPERAND_SIGNED },
+
+  /* The SI field in a D form instruction when we accept a wide range
+     of positive values.  */
+#define SISIGNOPT SI + 1
+  { 16, 0, 0, 0, PPC_OPERAND_SIGNED | PPC_OPERAND_SIGNOPT },
+
+  /* The SPR field in an XFX form instruction.  This is flipped--the
+     lower 5 bits are stored in the upper 5 and vice- versa.  */
+#define SPR SISIGNOPT + 1
+#define SPR_MASK (0x3ff << 11)
+  { 10, 11, insert_spr, extract_spr, 0 },
+
+  /* The BAT index number in an XFX form m[ft]ibat[lu] instruction.  */
+#define SPRBAT SPR + 1
+#define SPRBAT_MASK (0x3 << 17)
+  { 2, 17, 0, 0, 0 },
+
+  /* The SPRG register number in an XFX form m[ft]sprg instruction.  */
+#define SPRG SPRBAT + 1
+#define SPRG_MASK (0x3 << 16)
+  { 2, 16, 0, 0, 0 },
+
+  /* The SR field in an X form instruction.  */
+#define SR SPRG + 1
+  { 4, 16, 0, 0, 0 },
+
+  /* The SV field in a POWER SC form instruction.  */
+#define SV SR + 1
+  { 14, 2, 0, 0, 0 },
+
+  /* The TBR field in an XFX form instruction.  This is like the SPR
+     field, but it is optional.  */
+#define TBR SV + 1
+  { 10, 11, insert_tbr, extract_tbr, PPC_OPERAND_OPTIONAL },
+
+  /* The TO field in a D or X form instruction.  */
+#define TO TBR + 1
+#define TO_MASK (0x1f << 21)
+  { 5, 21, 0, 0, 0 },
+
+  /* The U field in an X form instruction.  */
+#define U TO + 1
+  { 4, 12, 0, 0, 0 },
+
+  /* The UI field in a D form instruction.  */
+#define UI U + 1
+  { 16, 0, 0, 0, 0 },
+
+  /* The VA field in a VA, VX or VXR form instruction. */
+#define VA UI + 1
+#define VA_MASK	(0x1f << 16)
+  {5, 16, 0, 0, PPC_OPERAND_VR},
+
+  /* The VB field in a VA, VX or VXR form instruction. */
+#define VB VA + 1
+#define VB_MASK (0x1f << 11)
+  {5, 11, 0, 0, PPC_OPERAND_VR}, 
+
+  /* The VC field in a VA form instruction. */
+#define VC VB + 1
+#define VC_MASK (0x1f << 6)
+  {5, 6, 0, 0, PPC_OPERAND_VR},
+
+  /* The VD or VS field in a VA, VX, VXR or X form instruction. */
+#define VD VC + 1
+#define VS VD
+#define VD_MASK (0x1f << 21)
+  {5, 21, 0, 0, PPC_OPERAND_VR},
+
+  /* The SIMM field in a VX form instruction. */
+#define SIMM VD + 1
+  { 5, 16, 0, 0, PPC_OPERAND_SIGNED},
+
+  /* The UIMM field in a VX form instruction. */
+#define UIMM SIMM + 1
+  { 5, 16, 0, 0, 0 },
+
+  /* The SHB field in a VA form instruction. */
+#define SHB UIMM + 1
+  { 4, 6, 0, 0, 0 },
+};
+
+/* The functions used to insert and extract complicated operands.  */
+
+/* The BA field in an XL form instruction when it must be the same as
+   the BT field in the same instruction.  This operand is marked FAKE.
+   The insertion function just copies the BT field into the BA field,
+   and the extraction function just checks that the fields are the
+   same.  */
+
+/*ARGSUSED*/
+static unsigned long
+insert_bat (insn, value, errmsg)
+     unsigned long insn;
+     long value ATTRIBUTE_UNUSED;
+     const char **errmsg ATTRIBUTE_UNUSED;
+{
+  return insn | (((insn >> 21) & 0x1f) << 16);
+}
+
+static long
+extract_bat (insn, invalid)
+     unsigned long insn;
+     int *invalid;
+{
+  if (invalid != (int *) NULL
+      && ((insn >> 21) & 0x1f) != ((insn >> 16) & 0x1f))
+    *invalid = 1;
+  return 0;
+}
+
+/* The BB field in an XL form instruction when it must be the same as
+   the BA field in the same instruction.  This operand is marked FAKE.
+   The insertion function just copies the BA field into the BB field,
+   and the extraction function just checks that the fields are the
+   same.  */
+
+/*ARGSUSED*/
+static unsigned long
+insert_bba (insn, value, errmsg)
+     unsigned long insn;
+     long value ATTRIBUTE_UNUSED;
+     const char **errmsg ATTRIBUTE_UNUSED;
+{
+  return insn | (((insn >> 16) & 0x1f) << 11);
+}
+
+static long
+extract_bba (insn, invalid)
+     unsigned long insn;
+     int *invalid;
+{
+  if (invalid != (int *) NULL
+      && ((insn >> 16) & 0x1f) != ((insn >> 11) & 0x1f))
+    *invalid = 1;
+  return 0;
+}
+
+/* The BD field in a B form instruction.  The lower two bits are
+   forced to zero.  */
+
+/*ARGSUSED*/
+static unsigned long
+insert_bd (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg ATTRIBUTE_UNUSED;
+{
+  return insn | (value & 0xfffc);
+}
+
+/*ARGSUSED*/
+static long
+extract_bd (insn, invalid)
+     unsigned long insn;
+     int *invalid ATTRIBUTE_UNUSED;
+{
+  if ((insn & 0x8000) != 0)
+    return (insn & 0xfffc) - 0x10000;
+  else
+    return insn & 0xfffc;
+}
+
+/* The BD field in a B form instruction when the - modifier is used.
+   This modifier means that the branch is not expected to be taken.
+   We must set the y bit of the BO field to 1 if the offset is
+   negative.  When extracting, we require that the y bit be 1 and that
+   the offset be positive, since if the y bit is 0 we just want to
+   print the normal form of the instruction.  */
+
+/*ARGSUSED*/
+static unsigned long
+insert_bdm (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg ATTRIBUTE_UNUSED;
+{
+  if ((value & 0x8000) != 0)
+    insn |= 1 << 21;
+  return insn | (value & 0xfffc);
+}
+
+static long
+extract_bdm (insn, invalid)
+     unsigned long insn;
+     int *invalid;
+{
+  if (invalid != (int *) NULL
+      && ((insn & (1 << 21)) == 0
+	  || (insn & (1 << 15)) == 0))
+    *invalid = 1;
+  if ((insn & 0x8000) != 0)
+    return (insn & 0xfffc) - 0x10000;
+  else
+    return insn & 0xfffc;
+}
+
+/* The BD field in a B form instruction when the + modifier is used.
+   This is like BDM, above, except that the branch is expected to be
+   taken.  */
+
+/*ARGSUSED*/
+static unsigned long
+insert_bdp (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg ATTRIBUTE_UNUSED;
+{
+  if ((value & 0x8000) == 0)
+    insn |= 1 << 21;
+  return insn | (value & 0xfffc);
+}
+
+static long
+extract_bdp (insn, invalid)
+     unsigned long insn;
+     int *invalid;
+{
+  if (invalid != (int *) NULL
+      && ((insn & (1 << 21)) == 0
+	  || (insn & (1 << 15)) != 0))
+    *invalid = 1;
+  if ((insn & 0x8000) != 0)
+    return (insn & 0xfffc) - 0x10000;
+  else
+    return insn & 0xfffc;
+}
+
+/* Check for legal values of a BO field.  */
+
+static int
+valid_bo (value)
+     long value;
+{
+  /* Certain encodings have bits that are required to be zero.  These
+     are (z must be zero, y may be anything):
+         001zy
+	 011zy
+	 1z00y
+	 1z01y
+	 1z1zz
+     */
+  switch (value & 0x14)
+    {
+    default:
+    case 0:
+      return 1;
+    case 0x4:
+      return (value & 0x2) == 0;
+    case 0x10:
+      return (value & 0x8) == 0;
+    case 0x14:
+      return value == 0x14;
+    }
+}
+
+/* The BO field in a B form instruction.  Warn about attempts to set
+   the field to an illegal value.  */
+
+static unsigned long
+insert_bo (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  if (errmsg != (const char **) NULL
+      && ! valid_bo (value))
+    *errmsg = _("invalid conditional option");
+  return insn | ((value & 0x1f) << 21);
+}
+
+static long
+extract_bo (insn, invalid)
+     unsigned long insn;
+     int *invalid;
+{
+  long value;
+
+  value = (insn >> 21) & 0x1f;
+  if (invalid != (int *) NULL
+      && ! valid_bo (value))
+    *invalid = 1;
+  return value;
+}
+
+/* The BO field in a B form instruction when the + or - modifier is
+   used.  This is like the BO field, but it must be even.  When
+   extracting it, we force it to be even.  */
+
+static unsigned long
+insert_boe (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  if (errmsg != (const char **) NULL)
+    {
+      if (! valid_bo (value))
+	*errmsg = _("invalid conditional option");
+      else if ((value & 1) != 0)
+	*errmsg = _("attempt to set y bit when using + or - modifier");
+    }
+  return insn | ((value & 0x1f) << 21);
+}
+
+static long
+extract_boe (insn, invalid)
+     unsigned long insn;
+     int *invalid;
+{
+  long value;
+
+  value = (insn >> 21) & 0x1f;
+  if (invalid != (int *) NULL
+      && ! valid_bo (value))
+    *invalid = 1;
+  return value & 0x1e;
+}
+
+/* The DS field in a DS form instruction.  This is like D, but the
+   lower two bits are forced to zero.  */
+
+/*ARGSUSED*/
+static unsigned long
+insert_ds (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg ATTRIBUTE_UNUSED;
+{
+  return insn | (value & 0xfffc);
+}
+
+/*ARGSUSED*/
+static long
+extract_ds (insn, invalid)
+     unsigned long insn;
+     int *invalid ATTRIBUTE_UNUSED;
+{
+  if ((insn & 0x8000) != 0)
+    return (insn & 0xfffc) - 0x10000;
+  else
+    return insn & 0xfffc;
+}
+
+/* The LI field in an I form instruction.  The lower two bits are
+   forced to zero.  */
+
+/*ARGSUSED*/
+static unsigned long
+insert_li (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  if ((value & 3) != 0 && errmsg != (const char **) NULL)
+    *errmsg = _("ignoring least significant bits in branch offset");
+  return insn | (value & 0x3fffffc);
+}
+
+/*ARGSUSED*/
+static long
+extract_li (insn, invalid)
+     unsigned long insn;
+     int *invalid ATTRIBUTE_UNUSED;
+{
+  if ((insn & 0x2000000) != 0)
+    return (insn & 0x3fffffc) - 0x4000000;
+  else
+    return insn & 0x3fffffc;
+}
+
+/* The MB and ME fields in an M form instruction expressed as a single
+   operand which is itself a bitmask.  The extraction function always
+   marks it as invalid, since we never want to recognize an
+   instruction which uses a field of this type.  */
+
+static unsigned long
+insert_mbe (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  unsigned long uval, mask;
+  int mb, me, mx, count, last;
+
+  uval = value;
+
+  if (uval == 0)
+    {
+      if (errmsg != (const char **) NULL)
+	*errmsg = _("illegal bitmask");
+      return insn;
+    }
+
+  mb = 0;
+  me = 32;
+  if ((uval & 1) != 0)
+    last = 1;
+  else
+    last = 0;
+  count = 0;
+
+  /* mb: location of last 0->1 transition */
+  /* me: location of last 1->0 transition */
+  /* count: # transitions */
+
+  for (mx = 0, mask = 1 << 31; mx < 32; ++mx, mask >>= 1)
+    {
+      if ((uval & mask) && !last)
+	{
+	  ++count;
+	  mb = mx;
+	  last = 1;
+	}
+      else if (!(uval & mask) && last)
+	{
+	  ++count;
+	  me = mx;
+	  last = 0;
+	}
+    }
+  if (me == 0)
+    me = 32;
+
+  if (count != 2 && (count != 0 || ! last))
+    {
+      if (errmsg != (const char **) NULL)
+	*errmsg = _("illegal bitmask");
+    }
+
+  return insn | (mb << 6) | ((me - 1) << 1);
+}
+
+static long
+extract_mbe (insn, invalid)
+     unsigned long insn;
+     int *invalid;
+{
+  long ret;
+  int mb, me;
+  int i;
+
+  if (invalid != (int *) NULL)
+    *invalid = 1;
+
+  mb = (insn >> 6) & 0x1f;
+  me = (insn >> 1) & 0x1f;
+  if (mb < me + 1)
+    {
+      ret = 0;
+      for (i = mb; i <= me; i++)
+	ret |= (long) 1 << (31 - i);
+    }
+  else if (mb == me + 1)
+    ret = ~0;
+  else /* (mb > me + 1) */
+    {
+      ret = ~ (long) 0;
+      for (i = me + 1; i < mb; i++)
+	ret &= ~ ((long) 1 << (31 - i));
+    }
+  return ret;
+}
+
+/* The MB or ME field in an MD or MDS form instruction.  The high bit
+   is wrapped to the low end.  */
+
+/*ARGSUSED*/
+static unsigned long
+insert_mb6 (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg ATTRIBUTE_UNUSED;
+{
+  return insn | ((value & 0x1f) << 6) | (value & 0x20);
+}
+
+/*ARGSUSED*/
+static long
+extract_mb6 (insn, invalid)
+     unsigned long insn;
+     int *invalid ATTRIBUTE_UNUSED;
+{
+  return ((insn >> 6) & 0x1f) | (insn & 0x20);
+}
+
+/* The NB field in an X form instruction.  The value 32 is stored as
+   0.  */
+
+static unsigned long
+insert_nb (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  if (value < 0 || value > 32)
+    *errmsg = _("value out of range");
+  if (value == 32)
+    value = 0;
+  return insn | ((value & 0x1f) << 11);
+}
+
+/*ARGSUSED*/
+static long
+extract_nb (insn, invalid)
+     unsigned long insn;
+     int *invalid ATTRIBUTE_UNUSED;
+{
+  long ret;
+
+  ret = (insn >> 11) & 0x1f;
+  if (ret == 0)
+    ret = 32;
+  return ret;
+}
+
+/* The NSI field in a D form instruction.  This is the same as the SI
+   field, only negated.  The extraction function always marks it as
+   invalid, since we never want to recognize an instruction which uses
+   a field of this type.  */
+
+/*ARGSUSED*/
+static unsigned long
+insert_nsi (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg ATTRIBUTE_UNUSED;
+{
+  return insn | ((- value) & 0xffff);
+}
+
+static long
+extract_nsi (insn, invalid)
+     unsigned long insn;
+     int *invalid;
+{
+  if (invalid != (int *) NULL)
+    *invalid = 1;
+  if ((insn & 0x8000) != 0)
+    return - ((long)(insn & 0xffff) - 0x10000);
+  else
+    return - (long)(insn & 0xffff);
+}
+
+/* The RA field in a D or X form instruction which is an updating
+   load, which means that the RA field may not be zero and may not
+   equal the RT field.  */
+
+static unsigned long
+insert_ral (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  if (value == 0
+      || (unsigned long) value == ((insn >> 21) & 0x1f))
+    *errmsg = "invalid register operand when updating";
+  return insn | ((value & 0x1f) << 16);
+}
+
+/* The RA field in an lmw instruction, which has special value
+   restrictions.  */
+
+static unsigned long
+insert_ram (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  if ((unsigned long) value >= ((insn >> 21) & 0x1f))
+    *errmsg = _("index register in load range");
+  return insn | ((value & 0x1f) << 16);
+}
+
+/* The RA field in a D or X form instruction which is an updating
+   store or an updating floating point load, which means that the RA
+   field may not be zero.  */
+
+static unsigned long
+insert_ras (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  if (value == 0)
+    *errmsg = _("invalid register operand when updating");
+  return insn | ((value & 0x1f) << 16);
+}
+
+/* The RB field in an X form instruction when it must be the same as
+   the RS field in the instruction.  This is used for extended
+   mnemonics like mr.  This operand is marked FAKE.  The insertion
+   function just copies the BT field into the BA field, and the
+   extraction function just checks that the fields are the same.  */
+
+/*ARGSUSED*/
+static unsigned long
+insert_rbs (insn, value, errmsg)
+     unsigned long insn;
+     long value ATTRIBUTE_UNUSED;
+     const char **errmsg ATTRIBUTE_UNUSED;
+{
+  return insn | (((insn >> 21) & 0x1f) << 11);
+}
+
+static long
+extract_rbs (insn, invalid)
+     unsigned long insn;
+     int *invalid;
+{
+  if (invalid != (int *) NULL
+      && ((insn >> 21) & 0x1f) != ((insn >> 11) & 0x1f))
+    *invalid = 1;
+  return 0;
+}
+
+/* The SH field in an MD form instruction.  This is split.  */
+
+/*ARGSUSED*/
+static unsigned long
+insert_sh6 (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg ATTRIBUTE_UNUSED;
+{
+  return insn | ((value & 0x1f) << 11) | ((value & 0x20) >> 4);
+}
+
+/*ARGSUSED*/
+static long
+extract_sh6 (insn, invalid)
+     unsigned long insn;
+     int *invalid ATTRIBUTE_UNUSED;
+{
+  return ((insn >> 11) & 0x1f) | ((insn << 4) & 0x20);
+}
+
+/* The SPR field in an XFX form instruction.  This is flipped--the
+   lower 5 bits are stored in the upper 5 and vice- versa.  */
+
+static unsigned long
+insert_spr (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg ATTRIBUTE_UNUSED;
+{
+  return insn | ((value & 0x1f) << 16) | ((value & 0x3e0) << 6);
+}
+
+static long
+extract_spr (insn, invalid)
+     unsigned long insn;
+     int *invalid ATTRIBUTE_UNUSED;
+{
+  return ((insn >> 16) & 0x1f) | ((insn >> 6) & 0x3e0);
+}
+
+/* The TBR field in an XFX instruction.  This is just like SPR, but it
+   is optional.  When TBR is omitted, it must be inserted as 268 (the
+   magic number of the TB register).  These functions treat 0
+   (indicating an omitted optional operand) as 268.  This means that
+   ``mftb 4,0'' is not handled correctly.  This does not matter very
+   much, since the architecture manual does not define mftb as
+   accepting any values other than 268 or 269.  */
+
+#define TB (268)
+
+static unsigned long
+insert_tbr (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg ATTRIBUTE_UNUSED;
+{
+  if (value == 0)
+    value = TB;
+  return insn | ((value & 0x1f) << 16) | ((value & 0x3e0) << 6);
+}
+
+static long
+extract_tbr (insn, invalid)
+     unsigned long insn;
+     int *invalid ATTRIBUTE_UNUSED;
+{
+  long ret;
+
+  ret = ((insn >> 16) & 0x1f) | ((insn >> 6) & 0x3e0);
+  if (ret == TB)
+    ret = 0;
+  return ret;
+}
+
+/* Macros used to form opcodes.  */
+
+/* The main opcode.  */
+#define OP(x) ((((unsigned long)(x)) & 0x3f) << 26)
+#define OP_MASK OP (0x3f)
+
+/* The main opcode combined with a trap code in the TO field of a D
+   form instruction.  Used for extended mnemonics for the trap
+   instructions.  */
+#define OPTO(x,to) (OP (x) | ((((unsigned long)(to)) & 0x1f) << 21))
+#define OPTO_MASK (OP_MASK | TO_MASK)
+
+/* The main opcode combined with a comparison size bit in the L field
+   of a D form or X form instruction.  Used for extended mnemonics for
+   the comparison instructions.  */
+#define OPL(x,l) (OP (x) | ((((unsigned long)(l)) & 1) << 21))
+#define OPL_MASK OPL (0x3f,1)
+
+/* An A form instruction.  */
+#define A(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0x1f) << 1) | (((unsigned long)(rc)) & 1))
+#define A_MASK A (0x3f, 0x1f, 1)
+
+/* An A_MASK with the FRB field fixed.  */
+#define AFRB_MASK (A_MASK | FRB_MASK)
+
+/* An A_MASK with the FRC field fixed.  */
+#define AFRC_MASK (A_MASK | FRC_MASK)
+
+/* An A_MASK with the FRA and FRC fields fixed.  */
+#define AFRAFRC_MASK (A_MASK | FRA_MASK | FRC_MASK)
+
+/* A B form instruction.  */
+#define B(op, aa, lk) (OP (op) | ((((unsigned long)(aa)) & 1) << 1) | ((lk) & 1))
+#define B_MASK B (0x3f, 1, 1)
+
+/* A B form instruction setting the BO field.  */
+#define BBO(op, bo, aa, lk) (B ((op), (aa), (lk)) | ((((unsigned long)(bo)) & 0x1f) << 21))
+#define BBO_MASK BBO (0x3f, 0x1f, 1, 1)
+
+/* A BBO_MASK with the y bit of the BO field removed.  This permits
+   matching a conditional branch regardless of the setting of the y
+   bit.  */
+#define Y_MASK (((unsigned long)1) << 21)
+#define BBOY_MASK (BBO_MASK &~ Y_MASK)
+
+/* A B form instruction setting the BO field and the condition bits of
+   the BI field.  */
+#define BBOCB(op, bo, cb, aa, lk) \
+  (BBO ((op), (bo), (aa), (lk)) | ((((unsigned long)(cb)) & 0x3) << 16))
+#define BBOCB_MASK BBOCB (0x3f, 0x1f, 0x3, 1, 1)
+
+/* A BBOCB_MASK with the y bit of the BO field removed.  */
+#define BBOYCB_MASK (BBOCB_MASK &~ Y_MASK)
+
+/* A BBOYCB_MASK in which the BI field is fixed.  */
+#define BBOYBI_MASK (BBOYCB_MASK | BI_MASK)
+
+/* The main opcode mask with the RA field clear.  */
+#define DRA_MASK (OP_MASK | RA_MASK)
+
+/* A DS form instruction.  */
+#define DSO(op, xop) (OP (op) | ((xop) & 0x3))
+#define DS_MASK DSO (0x3f, 3)
+
+/* An M form instruction.  */
+#define M(op, rc) (OP (op) | ((rc) & 1))
+#define M_MASK M (0x3f, 1)
+
+/* An M form instruction with the ME field specified.  */
+#define MME(op, me, rc) (M ((op), (rc)) | ((((unsigned long)(me)) & 0x1f) << 1))
+
+/* An M_MASK with the MB and ME fields fixed.  */
+#define MMBME_MASK (M_MASK | MB_MASK | ME_MASK)
+
+/* An M_MASK with the SH and ME fields fixed.  */
+#define MSHME_MASK (M_MASK | SH_MASK | ME_MASK)
+
+/* An MD form instruction.  */
+#define MD(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0x7) << 2) | ((rc) & 1))
+#define MD_MASK MD (0x3f, 0x7, 1)
+
+/* An MD_MASK with the MB field fixed.  */
+#define MDMB_MASK (MD_MASK | MB6_MASK)
+
+/* An MD_MASK with the SH field fixed.  */
+#define MDSH_MASK (MD_MASK | SH6_MASK)
+
+/* An MDS form instruction.  */
+#define MDS(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0xf) << 1) | ((rc) & 1))
+#define MDS_MASK MDS (0x3f, 0xf, 1)
+
+/* An MDS_MASK with the MB field fixed.  */
+#define MDSMB_MASK (MDS_MASK | MB6_MASK)
+
+/* An SC form instruction.  */
+#define SC(op, sa, lk) (OP (op) | ((((unsigned long)(sa)) & 1) << 1) | ((lk) & 1))
+#define SC_MASK (OP_MASK | (((unsigned long)0x3ff) << 16) | (((unsigned long)1) << 1) | 1)
+
+/* An VX form instruction. */
+#define VX(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x7ff))
+
+/* The mask for an VX form instruction. */
+#define VX_MASK	VX(0x3f, 0x7ff)
+
+/* An VA form instruction. */
+#define VXA(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x07f))
+
+/* The mask for an VA form instruction. */
+#define VXA_MASK VXA(0x3f, 0x7f)
+
+/* An VXR form instruction. */
+#define VXR(op, xop, rc) (OP (op) | (((rc) & 1) << 10) | (((unsigned long)(xop)) & 0x3ff))
+
+/* The mask for a VXR form instruction. */
+#define VXR_MASK VXR(0x3f, 0x3ff, 1)
+
+/* An X form instruction.  */
+#define X(op, xop) (OP (op) | ((((unsigned long)(xop)) & 0x3ff) << 1))
+
+/* An X form instruction with the RC bit specified.  */
+#define XRC(op, xop, rc) (X ((op), (xop)) | ((rc) & 1))
+
+/* The mask for an X form instruction.  */
+#define X_MASK XRC (0x3f, 0x3ff, 1)
+
+/* An X_MASK with the RA field fixed.  */
+#define XRA_MASK (X_MASK | RA_MASK)
+
+/* An X_MASK with the RB field fixed.  */
+#define XRB_MASK (X_MASK | RB_MASK)
+
+/* An X_MASK with the RT field fixed.  */
+#define XRT_MASK (X_MASK | RT_MASK)
+
+/* An X_MASK with the RA and RB fields fixed.  */
+#define XRARB_MASK (X_MASK | RA_MASK | RB_MASK)
+
+/* An X_MASK with the RT and RA fields fixed.  */
+#define XRTRA_MASK (X_MASK | RT_MASK | RA_MASK)
+
+/* An X form comparison instruction.  */
+#define XCMPL(op, xop, l) (X ((op), (xop)) | ((((unsigned long)(l)) & 1) << 21))
+
+/* The mask for an X form comparison instruction.  */
+#define XCMP_MASK (X_MASK | (((unsigned long)1) << 22))
+
+/* The mask for an X form comparison instruction with the L field
+   fixed.  */
+#define XCMPL_MASK (XCMP_MASK | (((unsigned long)1) << 21))
+
+/* An X form trap instruction with the TO field specified.  */
+#define XTO(op, xop, to) (X ((op), (xop)) | ((((unsigned long)(to)) & 0x1f) << 21))
+#define XTO_MASK (X_MASK | TO_MASK)
+
+/* An X form tlb instruction with the SH field specified.  */
+#define XTLB(op, xop, sh) (X ((op), (xop)) | ((((unsigned long)(sh)) & 0x1f) << 11))
+#define XTLB_MASK (X_MASK | SH_MASK)
+
+/* An XFL form instruction.  */
+#define XFL(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0x3ff) << 1) | (((unsigned long)(rc)) & 1))
+#define XFL_MASK (XFL (0x3f, 0x3ff, 1) | (((unsigned long)1) << 25) | (((unsigned long)1) << 16))
+
+/* An XL form instruction with the LK field set to 0.  */
+#define XL(op, xop) (OP (op) | ((((unsigned long)(xop)) & 0x3ff) << 1))
+
+/* An XL form instruction which uses the LK field.  */
+#define XLLK(op, xop, lk) (XL ((op), (xop)) | ((lk) & 1))
+
+/* The mask for an XL form instruction.  */
+#define XL_MASK XLLK (0x3f, 0x3ff, 1)
+
+/* An XL form instruction which explicitly sets the BO field.  */
+#define XLO(op, bo, xop, lk) \
+  (XLLK ((op), (xop), (lk)) | ((((unsigned long)(bo)) & 0x1f) << 21))
+#define XLO_MASK (XL_MASK | BO_MASK)
+
+/* An XL form instruction which explicitly sets the y bit of the BO
+   field.  */
+#define XLYLK(op, xop, y, lk) (XLLK ((op), (xop), (lk)) | ((((unsigned long)(y)) & 1) << 21))
+#define XLYLK_MASK (XL_MASK | Y_MASK)
+
+/* An XL form instruction which sets the BO field and the condition
+   bits of the BI field.  */
+#define XLOCB(op, bo, cb, xop, lk) \
+  (XLO ((op), (bo), (xop), (lk)) | ((((unsigned long)(cb)) & 3) << 16))
+#define XLOCB_MASK XLOCB (0x3f, 0x1f, 0x3, 0x3ff, 1)
+
+/* An XL_MASK or XLYLK_MASK or XLOCB_MASK with the BB field fixed.  */
+#define XLBB_MASK (XL_MASK | BB_MASK)
+#define XLYBB_MASK (XLYLK_MASK | BB_MASK)
+#define XLBOCBBB_MASK (XLOCB_MASK | BB_MASK)
+
+/* An XL_MASK with the BO and BB fields fixed.  */
+#define XLBOBB_MASK (XL_MASK | BO_MASK | BB_MASK)
+
+/* An XL_MASK with the BO, BI and BB fields fixed.  */
+#define XLBOBIBB_MASK (XL_MASK | BO_MASK | BI_MASK | BB_MASK)
+
+/* An XO form instruction.  */
+#define XO(op, xop, oe, rc) \
+  (OP (op) | ((((unsigned long)(xop)) & 0x1ff) << 1) | ((((unsigned long)(oe)) & 1) << 10) | (((unsigned long)(rc)) & 1))
+#define XO_MASK XO (0x3f, 0x1ff, 1, 1)
+
+/* An XO_MASK with the RB field fixed.  */
+#define XORB_MASK (XO_MASK | RB_MASK)
+
+/* An XS form instruction.  */
+#define XS(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0x1ff) << 2) | (((unsigned long)(rc)) & 1))
+#define XS_MASK XS (0x3f, 0x1ff, 1)
+
+/* A mask for the FXM version of an XFX form instruction.  */
+#define XFXFXM_MASK (X_MASK | (((unsigned long)1) << 20) | (((unsigned long)1) << 11))
+
+/* An XFX form instruction with the FXM field filled in.  */
+#define XFXM(op, xop, fxm) \
+  (X ((op), (xop)) | ((((unsigned long)(fxm)) & 0xff) << 12))
+
+/* An XFX form instruction with the SPR field filled in.  */
+#define XSPR(op, xop, spr) \
+  (X ((op), (xop)) | ((((unsigned long)(spr)) & 0x1f) << 16) | ((((unsigned long)(spr)) & 0x3e0) << 6))
+#define XSPR_MASK (X_MASK | SPR_MASK)
+
+/* An XFX form instruction with the SPR field filled in except for the
+   SPRBAT field.  */
+#define XSPRBAT_MASK (XSPR_MASK &~ SPRBAT_MASK)
+
+/* An XFX form instruction with the SPR field filled in except for the
+   SPRG field.  */
+#define XSPRG_MASK (XSPR_MASK &~ SPRG_MASK)
+
+/* An X form instruction with everything filled in except the E field.  */
+#define XE_MASK (0xffff7fff)
+
+/* The BO encodings used in extended conditional branch mnemonics.  */
+#define BODNZF	(0x0)
+#define BODNZFP	(0x1)
+#define BODZF	(0x2)
+#define BODZFP	(0x3)
+#define BOF	(0x4)
+#define BOFP	(0x5)
+#define BODNZT	(0x8)
+#define BODNZTP	(0x9)
+#define BODZT	(0xa)
+#define BODZTP	(0xb)
+#define BOT	(0xc)
+#define BOTP	(0xd)
+#define BODNZ	(0x10)
+#define BODNZP	(0x11)
+#define BODZ	(0x12)
+#define BODZP	(0x13)
+#define BOU	(0x14)
+
+/* The BI condition bit encodings used in extended conditional branch
+   mnemonics.  */
+#define CBLT	(0)
+#define CBGT	(1)
+#define CBEQ	(2)
+#define CBSO	(3)
+
+/* The TO encodings used in extended trap mnemonics.  */
+#define TOLGT	(0x1)
+#define TOLLT	(0x2)
+#define TOEQ	(0x4)
+#define TOLGE	(0x5)
+#define TOLNL	(0x5)
+#define TOLLE	(0x6)
+#define TOLNG	(0x6)
+#define TOGT	(0x8)
+#define TOGE	(0xc)
+#define TONL	(0xc)
+#define TOLT	(0x10)
+#define TOLE	(0x14)
+#define TONG	(0x14)
+#define TONE	(0x18)
+#define TOU	(0x1f)
+
+/* Smaller names for the flags so each entry in the opcodes table will
+   fit on a single line.  */
+#undef	PPC
+#define PPC     PPC_OPCODE_PPC | PPC_OPCODE_ANY
+#define PPCCOM	PPC_OPCODE_PPC | PPC_OPCODE_COMMON | PPC_OPCODE_ANY
+#define PPC32   PPC_OPCODE_PPC | PPC_OPCODE_32 | PPC_OPCODE_ANY
+#undef PPC64
+#define PPC64   PPC_OPCODE_PPC | PPC_OPCODE_64 | PPC_OPCODE_ANY
+#define PPCONLY	PPC_OPCODE_PPC
+#define PPC403	PPC
+#define PPC405	PPC403
+#define PPC750	PPC
+#define PPC860	PPC
+#define PPCVEC	PPC_OPCODE_ALTIVEC | PPC_OPCODE_ANY
+#define	POWER   PPC_OPCODE_POWER | PPC_OPCODE_ANY
+#define	POWER2	PPC_OPCODE_POWER | PPC_OPCODE_POWER2 | PPC_OPCODE_ANY
+#define PPCPWR2	PPC_OPCODE_PPC | PPC_OPCODE_POWER | PPC_OPCODE_POWER2 | PPC_OPCODE_ANY
+#define	POWER32	PPC_OPCODE_POWER | PPC_OPCODE_ANY | PPC_OPCODE_32
+#define	COM     PPC_OPCODE_POWER | PPC_OPCODE_PPC | PPC_OPCODE_COMMON | PPC_OPCODE_ANY
+#define	COM32   PPC_OPCODE_POWER | PPC_OPCODE_PPC | PPC_OPCODE_COMMON | PPC_OPCODE_ANY | PPC_OPCODE_32
+#define	M601    PPC_OPCODE_POWER | PPC_OPCODE_601 | PPC_OPCODE_ANY
+#define PWRCOM	PPC_OPCODE_POWER | PPC_OPCODE_601 | PPC_OPCODE_COMMON | PPC_OPCODE_ANY
+#define	MFDEC1	PPC_OPCODE_POWER
+#define	MFDEC2	PPC_OPCODE_PPC | PPC_OPCODE_601
+
+/* The opcode table.
+
+   The format of the opcode table is:
+
+   NAME	     OPCODE	MASK		FLAGS		{ OPERANDS }
+
+   NAME is the name of the instruction.
+   OPCODE is the instruction opcode.
+   MASK is the opcode mask; this is used to tell the disassembler
+     which bits in the actual opcode must match OPCODE.
+   FLAGS are flags indicated what processors support the instruction.
+   OPERANDS is the list of operands.
+
+   The disassembler reads the table in order and prints the first
+   instruction which matches, so this table is sorted to put more
+   specific instructions before more general instructions.  It is also
+   sorted by major opcode.  */
+
+const struct powerpc_opcode powerpc_opcodes[] = {
+{ "tdlgti",  OPTO(2,TOLGT), OPTO_MASK,	PPC64,		{ RA, SI } },
+{ "tdllti",  OPTO(2,TOLLT), OPTO_MASK,	PPC64,		{ RA, SI } },
+{ "tdeqi",   OPTO(2,TOEQ), OPTO_MASK,	PPC64,		{ RA, SI } },
+{ "tdlgei",  OPTO(2,TOLGE), OPTO_MASK,	PPC64,		{ RA, SI } },
+{ "tdlnli",  OPTO(2,TOLNL), OPTO_MASK,	PPC64,		{ RA, SI } },
+{ "tdllei",  OPTO(2,TOLLE), OPTO_MASK,	PPC64,		{ RA, SI } },
+{ "tdlngi",  OPTO(2,TOLNG), OPTO_MASK,	PPC64,		{ RA, SI } },
+{ "tdgti",   OPTO(2,TOGT), OPTO_MASK,	PPC64,		{ RA, SI } },
+{ "tdgei",   OPTO(2,TOGE), OPTO_MASK,	PPC64,		{ RA, SI } },
+{ "tdnli",   OPTO(2,TONL), OPTO_MASK,	PPC64,		{ RA, SI } },
+{ "tdlti",   OPTO(2,TOLT), OPTO_MASK,	PPC64,		{ RA, SI } },
+{ "tdlei",   OPTO(2,TOLE), OPTO_MASK,	PPC64,		{ RA, SI } },
+{ "tdngi",   OPTO(2,TONG), OPTO_MASK,	PPC64,		{ RA, SI } },
+{ "tdnei",   OPTO(2,TONE), OPTO_MASK,	PPC64,		{ RA, SI } },
+{ "tdi",     OP(2),	OP_MASK,	PPC64,		{ TO, RA, SI } },
+
+{ "twlgti",  OPTO(3,TOLGT), OPTO_MASK,	PPCCOM,		{ RA, SI } },
+{ "tlgti",   OPTO(3,TOLGT), OPTO_MASK,	PWRCOM,		{ RA, SI } },
+{ "twllti",  OPTO(3,TOLLT), OPTO_MASK,	PPCCOM,		{ RA, SI } },
+{ "tllti",   OPTO(3,TOLLT), OPTO_MASK,	PWRCOM,		{ RA, SI } },
+{ "tweqi",   OPTO(3,TOEQ), OPTO_MASK,	PPCCOM,		{ RA, SI } },
+{ "teqi",    OPTO(3,TOEQ), OPTO_MASK,	PWRCOM,		{ RA, SI } },
+{ "twlgei",  OPTO(3,TOLGE), OPTO_MASK,	PPCCOM,		{ RA, SI } },
+{ "tlgei",   OPTO(3,TOLGE), OPTO_MASK,	PWRCOM,		{ RA, SI } },
+{ "twlnli",  OPTO(3,TOLNL), OPTO_MASK,	PPCCOM,		{ RA, SI } },
+{ "tlnli",   OPTO(3,TOLNL), OPTO_MASK,	PWRCOM,		{ RA, SI } },
+{ "twllei",  OPTO(3,TOLLE), OPTO_MASK,	PPCCOM,		{ RA, SI } },
+{ "tllei",   OPTO(3,TOLLE), OPTO_MASK,	PWRCOM,		{ RA, SI } },
+{ "twlngi",  OPTO(3,TOLNG), OPTO_MASK,	PPCCOM,		{ RA, SI } },
+{ "tlngi",   OPTO(3,TOLNG), OPTO_MASK,	PWRCOM,		{ RA, SI } },
+{ "twgti",   OPTO(3,TOGT), OPTO_MASK,	PPCCOM,		{ RA, SI } },
+{ "tgti",    OPTO(3,TOGT), OPTO_MASK,	PWRCOM,		{ RA, SI } },
+{ "twgei",   OPTO(3,TOGE), OPTO_MASK,	PPCCOM,		{ RA, SI } },
+{ "tgei",    OPTO(3,TOGE), OPTO_MASK,	PWRCOM,		{ RA, SI } },
+{ "twnli",   OPTO(3,TONL), OPTO_MASK,	PPCCOM,		{ RA, SI } },
+{ "tnli",    OPTO(3,TONL), OPTO_MASK,	PWRCOM,		{ RA, SI } },
+{ "twlti",   OPTO(3,TOLT), OPTO_MASK,	PPCCOM,		{ RA, SI } },
+{ "tlti",    OPTO(3,TOLT), OPTO_MASK,	PWRCOM,		{ RA, SI } },
+{ "twlei",   OPTO(3,TOLE), OPTO_MASK,	PPCCOM,		{ RA, SI } },
+{ "tlei",    OPTO(3,TOLE), OPTO_MASK,	PWRCOM,		{ RA, SI } },
+{ "twngi",   OPTO(3,TONG), OPTO_MASK,	PPCCOM,		{ RA, SI } },
+{ "tngi",    OPTO(3,TONG), OPTO_MASK,	PWRCOM,		{ RA, SI } },
+{ "twnei",   OPTO(3,TONE), OPTO_MASK,	PPCCOM,		{ RA, SI } },
+{ "tnei",    OPTO(3,TONE), OPTO_MASK,	PWRCOM,		{ RA, SI } },
+{ "twi",     OP(3),	OP_MASK,	PPCCOM,		{ TO, RA, SI } },
+{ "ti",      OP(3),	OP_MASK,	PWRCOM,		{ TO, RA, SI } },
+
+{ "macchw",	XO(4,172,0,0), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "macchw.",	XO(4,172,0,1), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "macchwo",	XO(4,172,1,0), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "macchwo.",	XO(4,172,1,1), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "macchws",	XO(4,236,0,0), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "macchws.",	XO(4,236,0,1), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "macchwso",	XO(4,236,1,0), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "macchwso.",	XO(4,236,1,1), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "macchwsu",	XO(4,204,0,0), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "macchwsu.",	XO(4,204,0,1), XO_MASK, PPC405,		{ RT, RA, RB } },
+{ "macchwsuo",	XO(4,204,1,0), XO_MASK, PPC405,		{ RT, RA, RB } },
+{ "macchwsuo.",	XO(4,204,1,1), XO_MASK, PPC405,		{ RT, RA, RB } },
+{ "macchwu",	XO(4,140,0,0), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "macchwu.",	XO(4,140,0,1), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "macchwuo",	XO(4,140,1,0), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "macchwuo.",	XO(4,140,1,1), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "machhw",	XO(4,44,0,0),  XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "machhw.",	XO(4,44,0,1),  XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "machhwo",	XO(4,44,1,0),  XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "machhwo.",	XO(4,44,1,1),  XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "machhws",	XO(4,108,0,0), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "machhws.",	XO(4,108,0,1), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "machhwso",	XO(4,108,1,0), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "machhwso.",	XO(4,108,1,1), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "machhwsu",	XO(4,76,0,0),  XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "machhwsu.",	XO(4,76,0,1),  XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "machhwsuo",	XO(4,76,1,0),  XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "machhwsuo.",	XO(4,76,1,1),  XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "machhwu",	XO(4,12,0,0),  XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "machhwu.",	XO(4,12,0,1),  XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "machhwuo",	XO(4,12,1,0),  XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "machhwuo.",	XO(4,12,1,1),  XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "maclhw",	XO(4,428,0,0), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "maclhw.",	XO(4,428,0,1), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "maclhwo",	XO(4,428,1,0), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "maclhwo.",	XO(4,428,1,1), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "maclhws",	XO(4,492,0,0), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "maclhws.",	XO(4,492,0,1), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "maclhwso",	XO(4,492,1,0), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "maclhwso.",	XO(4,492,1,1), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "maclhwsu",	XO(4,460,0,0), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "maclhwsu.",	XO(4,460,0,1), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "maclhwsuo",	XO(4,460,1,0), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "maclhwsuo.",	XO(4,460,1,1), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "maclhwu",	XO(4,396,0,0), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "maclhwu.",	XO(4,396,0,1), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "maclhwuo",	XO(4,396,1,0), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "maclhwuo.",	XO(4,396,1,1), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "mulchw",	XRC(4,168,0),  X_MASK,	PPC405,		{ RT, RA, RB } },
+{ "mulchw.",	XRC(4,168,1),  X_MASK,	PPC405,		{ RT, RA, RB } },
+{ "mulchwu",	XRC(4,136,0),  X_MASK,	PPC405,		{ RT, RA, RB } },
+{ "mulchwu.",	XRC(4,136,1),  X_MASK,	PPC405,		{ RT, RA, RB } },
+{ "mulhhw",	XRC(4,40,0),   X_MASK,	PPC405,		{ RT, RA, RB } },
+{ "mulhhw.",	XRC(4,40,1),   X_MASK,	PPC405,		{ RT, RA, RB } },
+{ "mulhhwu",	XRC(4,8,0),    X_MASK,	PPC405,		{ RT, RA, RB } },
+{ "mulhhwu.",	XRC(4,8,1),    X_MASK,	PPC405,		{ RT, RA, RB } },
+{ "mullhw",	XRC(4,424,0),  X_MASK,	PPC405,		{ RT, RA, RB } },
+{ "mullhw.",	XRC(4,424,1),  X_MASK,	PPC405,		{ RT, RA, RB } },
+{ "mullhwu",	XRC(4,392,0),  X_MASK,	PPC405,		{ RT, RA, RB } },
+{ "mullhwu.",	XRC(4,392,1),  X_MASK,	PPC405,		{ RT, RA, RB } },
+{ "nmacchw",	XO(4,174,0,0), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "nmacchw.",	XO(4,174,0,1), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "nmacchwo",	XO(4,174,1,0), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "nmacchwo.",	XO(4,174,1,1), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "nmacchws",	XO(4,238,0,0), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "nmacchws.",	XO(4,238,0,1), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "nmacchwso",	XO(4,238,1,0), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "nmacchwso.",	XO(4,238,1,1), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "nmachhw",	XO(4,46,0,0),  XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "nmachhw.",	XO(4,46,0,1),  XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "nmachhwo",	XO(4,46,1,0),  XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "nmachhwo.",	XO(4,46,1,1),  XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "nmachhws",	XO(4,110,0,0), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "nmachhws.",	XO(4,110,0,1), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "nmachhwso",	XO(4,110,1,0), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "nmachhwso.",	XO(4,110,1,1), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "nmaclhw",	XO(4,430,0,0), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "nmaclhw.",	XO(4,430,0,1), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "nmaclhwo",	XO(4,430,1,0), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "nmaclhwo.",	XO(4,430,1,1), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "nmaclhws",	XO(4,494,0,0), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "nmaclhws.",	XO(4,494,0,1), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "nmaclhwso",	XO(4,494,1,0), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "nmaclhwso.",	XO(4,494,1,1), XO_MASK,	PPC405,		{ RT, RA, RB } },
+{ "mfvscr",  VX(4, 1540), VX_MASK,	PPCVEC,		{ VD } },
+{ "mtvscr",  VX(4, 1604), VX_MASK,	PPCVEC,		{ VD } },
+{ "vaddcuw", VX(4,  384), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vaddfp",  VX(4,   10), VX_MASK, 	PPCVEC,		{ VD, VA, VB } },
+{ "vaddsbs", VX(4,  768), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vaddshs", VX(4,  832), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vaddsws", VX(4,  896), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vaddubm", VX(4,    0), VX_MASK, 	PPCVEC,		{ VD, VA, VB } },
+{ "vaddubs", VX(4,  512), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vadduhm", VX(4,   64), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vadduhs", VX(4,  576), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vadduwm", VX(4,  128), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vadduws", VX(4,  640), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vand",    VX(4, 1028), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vandc",   VX(4, 1092), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vavgsb",  VX(4, 1282), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vavgsh",  VX(4, 1346), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vavgsw",  VX(4, 1410), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vavgub",  VX(4, 1026), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vavguh",  VX(4, 1090), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vavguw",  VX(4, 1154), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vcfsx",   VX(4,  842), VX_MASK,	PPCVEC,		{ VD, VB, UIMM } },
+{ "vcfux",   VX(4,  778), VX_MASK,	PPCVEC,		{ VD, VB, UIMM } },
+{ "vcmpbfp",   VXR(4, 966, 0), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpbfp.",  VXR(4, 966, 1), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpeqfp",  VXR(4, 198, 0), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpeqfp.", VXR(4, 198, 1), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpequb",  VXR(4,   6, 0), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpequb.", VXR(4,   6, 1), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpequh",  VXR(4,  70, 0), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpequh.", VXR(4,  70, 1), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpequw",  VXR(4, 134, 0), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpequw.", VXR(4, 134, 1), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgefp",  VXR(4, 454, 0), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgefp.", VXR(4, 454, 1), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgtfp",  VXR(4, 710, 0), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgtfp.", VXR(4, 710, 1), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgtsb",  VXR(4, 774, 0), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgtsb.", VXR(4, 774, 1), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgtsh",  VXR(4, 838, 0), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgtsh.", VXR(4, 838, 1), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgtsw",  VXR(4, 902, 0), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgtsw.", VXR(4, 902, 1), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgtub",  VXR(4, 518, 0), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgtub.", VXR(4, 518, 1), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgtuh",  VXR(4, 582, 0), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgtuh.", VXR(4, 582, 1), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgtuw",  VXR(4, 646, 0), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgtuw.", VXR(4, 646, 1), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vctsxs",    VX(4,  970), VX_MASK,	PPCVEC,		{ VD, VB, UIMM } },
+{ "vctuxs",    VX(4,  906), VX_MASK,	PPCVEC,		{ VD, VB, UIMM } },
+{ "vexptefp",  VX(4,  394), VX_MASK,	PPCVEC,		{ VD, VB } },
+{ "vlogefp",   VX(4,  458), VX_MASK,	PPCVEC,		{ VD, VB } },
+{ "vmaddfp",   VXA(4,  46), VXA_MASK,	PPCVEC,		{ VD, VA, VB, VC } },
+{ "vmaxfp",    VX(4, 1034), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmaxsb",    VX(4,  258), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmaxsh",    VX(4,  322), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmaxsw",    VX(4,  386), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmaxub",    VX(4,    2), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmaxuh",    VX(4,   66), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmaxuw",    VX(4,  130), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmhaddshs", VXA(4,  32), VXA_MASK,	PPCVEC,		{ VD, VA, VB, VC } },
+{ "vmhraddshs", VXA(4, 33), VXA_MASK,	PPCVEC,		{ VD, VA, VB, VC } },
+{ "vminfp",    VX(4, 1098), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vminsb",    VX(4,  770), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vminsh",    VX(4,  834), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vminsw",    VX(4,  898), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vminub",    VX(4,  514), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vminuh",    VX(4,  578), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vminuw",    VX(4,  642), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmladduhm", VXA(4,  34), VXA_MASK,	PPCVEC,		{ VD, VA, VB, VC } },
+{ "vmrghb",    VX(4,   12), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmrghh",    VX(4,   76), VX_MASK,    PPCVEC,		{ VD, VA, VB } },
+{ "vmrghw",    VX(4,  140), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmrglb",    VX(4,  268), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmrglh",    VX(4,  332), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmrglw",    VX(4,  396), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmsummbm",  VXA(4,  37), VXA_MASK,	PPCVEC,		{ VD, VA, VB, VC } },
+{ "vmsumshm",  VXA(4,  40), VXA_MASK,	PPCVEC,		{ VD, VA, VB, VC } },
+{ "vmsumshs",  VXA(4,  41), VXA_MASK,	PPCVEC,		{ VD, VA, VB, VC } },
+{ "vmsumubm",  VXA(4,  36), VXA_MASK,   PPCVEC,		{ VD, VA, VB, VC } },
+{ "vmsumuhm",  VXA(4,  38), VXA_MASK,   PPCVEC,		{ VD, VA, VB, VC } },
+{ "vmsumuhs",  VXA(4,  39), VXA_MASK,   PPCVEC,		{ VD, VA, VB, VC } },
+{ "vmulesb",   VX(4,  776), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmulesh",   VX(4,  840), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmuleub",   VX(4,  520), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmuleuh",   VX(4,  584), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmulosb",   VX(4,  264), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmulosh",   VX(4,  328), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmuloub",   VX(4,    8), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmulouh",   VX(4,   72), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vnmsubfp",  VXA(4,  47), VXA_MASK,	PPCVEC,		{ VD, VA, VC, VB } },
+{ "vnor",      VX(4, 1284), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vor",       VX(4, 1156), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vperm",     VXA(4,  43), VXA_MASK,	PPCVEC,		{ VD, VA, VB, VC } },
+{ "vpkpx",     VX(4,  782), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vpkshss",   VX(4,  398), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vpkshus",   VX(4,  270), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vpkswss",   VX(4,  462), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vpkswus",   VX(4,  334), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vpkuhum",   VX(4,   14), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vpkuhus",   VX(4,  142), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vpkuwum",   VX(4,   78), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vpkuwus",   VX(4,  206), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vrefp",     VX(4,  266), VX_MASK,	PPCVEC,		{ VD, VB } },
+{ "vrfim",     VX(4,  714), VX_MASK,	PPCVEC,		{ VD, VB } },
+{ "vrfin",     VX(4,  522), VX_MASK,	PPCVEC,		{ VD, VB } },
+{ "vrfip",     VX(4,  650), VX_MASK,	PPCVEC,		{ VD, VB } },
+{ "vrfiz",     VX(4,  586), VX_MASK,	PPCVEC,		{ VD, VB } },
+{ "vrlb",      VX(4,    4), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vrlh",      VX(4,   68), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vrlw",      VX(4,  132), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vrsqrtefp", VX(4,  330), VX_MASK,	PPCVEC,		{ VD, VB } },
+{ "vsel",      VXA(4,  42), VXA_MASK,	PPCVEC,		{ VD, VA, VB, VC } },
+{ "vsl",       VX(4,  452), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vslb",      VX(4,  260), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsldoi",    VXA(4,  44), VXA_MASK,	PPCVEC,		{ VD, VA, VB, SHB } },
+{ "vslh",      VX(4,  324), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vslo",      VX(4, 1036), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vslw",      VX(4,  388), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vspltb",    VX(4,  524), VX_MASK,	PPCVEC,		{ VD, VB, UIMM } },
+{ "vsplth",    VX(4,  588), VX_MASK,	PPCVEC,		{ VD, VB, UIMM } },
+{ "vspltisb",  VX(4,  780), VX_MASK,	PPCVEC,		{ VD, SIMM } },
+{ "vspltish",  VX(4,  844), VX_MASK,	PPCVEC,		{ VD, SIMM } },
+{ "vspltisw",  VX(4,  908), VX_MASK,	PPCVEC,		{ VD, SIMM } },
+{ "vspltw",    VX(4,  652), VX_MASK,	PPCVEC,		{ VD, VB, UIMM } },
+{ "vsr",       VX(4,  708), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsrab",     VX(4,  772), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsrah",     VX(4,  836), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsraw",     VX(4,  900), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsrb",      VX(4,  516), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsrh",      VX(4,  580), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsro",      VX(4, 1100), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsrw",      VX(4,  644), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsubcuw",   VX(4, 1408), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsubfp",    VX(4,   74), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsubsbs",   VX(4, 1792), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsubshs",   VX(4, 1856), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsubsws",   VX(4, 1920), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsububm",   VX(4, 1024), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsububs",   VX(4, 1536), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsubuhm",   VX(4, 1088), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsubuhs",   VX(4, 1600), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsubuwm",   VX(4, 1152), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsubuws",   VX(4, 1664), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsumsws",   VX(4, 1928), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsum2sws",  VX(4, 1672), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsum4sbs",  VX(4, 1800), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsum4shs",  VX(4, 1608), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsum4ubs",  VX(4, 1544), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vupkhpx",   VX(4,  846), VX_MASK,	PPCVEC,		{ VD, VB } },
+{ "vupkhsb",   VX(4,  526), VX_MASK,	PPCVEC,		{ VD, VB } },
+{ "vupkhsh",   VX(4,  590), VX_MASK,	PPCVEC,		{ VD, VB } },
+{ "vupklpx",   VX(4,  974), VX_MASK,	PPCVEC,		{ VD, VB } },
+{ "vupklsb",   VX(4,  654), VX_MASK,	PPCVEC,		{ VD, VB } },
+{ "vupklsh",   VX(4,  718), VX_MASK,	PPCVEC,		{ VD, VB } },
+{ "vxor",      VX(4, 1220), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+
+{ "mulli",   OP(7),	OP_MASK,	PPCCOM,		{ RT, RA, SI } },
+{ "muli",    OP(7),	OP_MASK,	PWRCOM,		{ RT, RA, SI } },
+
+{ "subfic",  OP(8),	OP_MASK,	PPCCOM,		{ RT, RA, SI } },
+{ "sfi",     OP(8),	OP_MASK,	PWRCOM,		{ RT, RA, SI } },
+
+{ "dozi",    OP(9),	OP_MASK,	M601,		{ RT, RA, SI } },
+
+{ "cmplwi",  OPL(10,0),	OPL_MASK,	PPCCOM,		{ OBF, RA, UI } },
+{ "cmpldi",  OPL(10,1), OPL_MASK,	PPC64,		{ OBF, RA, UI } },
+{ "cmpli",   OP(10),	OP_MASK,	PPCONLY,	{ BF, L, RA, UI } },
+{ "cmpli",   OP(10),	OP_MASK,	PWRCOM,		{ BF, RA, UI } },
+
+{ "cmpwi",   OPL(11,0),	OPL_MASK,	PPCCOM,		{ OBF, RA, SI } },
+{ "cmpdi",   OPL(11,1),	OPL_MASK,	PPC64,		{ OBF, RA, SI } },
+{ "cmpi",    OP(11),	OP_MASK,	PPCONLY,	{ BF, L, RA, SI } },
+{ "cmpi",    OP(11),	OP_MASK,	PWRCOM,		{ BF, RA, SI } },
+
+{ "addic",   OP(12),	OP_MASK,	PPCCOM,		{ RT, RA, SI } },
+{ "ai",	     OP(12),	OP_MASK,	PWRCOM,		{ RT, RA, SI } },
+{ "subic",   OP(12),	OP_MASK,	PPCCOM,		{ RT, RA, NSI } },
+
+{ "addic.",  OP(13),	OP_MASK,	PPCCOM,		{ RT, RA, SI } },
+{ "ai.",     OP(13),	OP_MASK,	PWRCOM,		{ RT, RA, SI } },
+{ "subic.",  OP(13),	OP_MASK,	PPCCOM,		{ RT, RA, NSI } },
+
+{ "li",	     OP(14),	DRA_MASK,	PPCCOM,		{ RT, SI } },
+{ "lil",     OP(14),	DRA_MASK,	PWRCOM,		{ RT, SI } },
+{ "addi",    OP(14),	OP_MASK,	PPCCOM,		{ RT, RA, SI } },
+{ "cal",     OP(14),	OP_MASK,	PWRCOM,		{ RT, D, RA } },
+{ "subi",    OP(14),	OP_MASK,	PPCCOM,		{ RT, RA, NSI } },
+{ "la",	     OP(14),	OP_MASK,	PPCCOM,		{ RT, D, RA } },
+
+{ "lis",     OP(15),	DRA_MASK,	PPCCOM,		{ RT, SISIGNOPT } },
+{ "liu",     OP(15),	DRA_MASK,	PWRCOM,		{ RT, SISIGNOPT } },
+{ "addis",   OP(15),	OP_MASK,	PPCCOM,		{ RT,RA,SISIGNOPT } },
+{ "cau",     OP(15),	OP_MASK,	PWRCOM,		{ RT,RA,SISIGNOPT } },
+{ "subis",   OP(15),	OP_MASK,	PPCCOM,		{ RT, RA, NSI } },
+
+{ "bdnz-",   BBO(16,BODNZ,0,0), BBOYBI_MASK, PPCCOM,	{ BDM } },
+{ "bdnz+",   BBO(16,BODNZ,0,0), BBOYBI_MASK, PPCCOM,	{ BDP } },
+{ "bdnz",    BBO(16,BODNZ,0,0), BBOYBI_MASK, PPCCOM,	{ BD } },
+{ "bdn",     BBO(16,BODNZ,0,0), BBOYBI_MASK, PWRCOM,	{ BD } },
+{ "bdnzl-",  BBO(16,BODNZ,0,1), BBOYBI_MASK, PPCCOM,	{ BDM } },
+{ "bdnzl+",  BBO(16,BODNZ,0,1), BBOYBI_MASK, PPCCOM,	{ BDP } },
+{ "bdnzl",   BBO(16,BODNZ,0,1), BBOYBI_MASK, PPCCOM,	{ BD } },
+{ "bdnl",    BBO(16,BODNZ,0,1), BBOYBI_MASK, PWRCOM,	{ BD } },
+{ "bdnza-",  BBO(16,BODNZ,1,0), BBOYBI_MASK, PPCCOM,	{ BDMA } },
+{ "bdnza+",  BBO(16,BODNZ,1,0), BBOYBI_MASK, PPCCOM,	{ BDPA } },
+{ "bdnza",   BBO(16,BODNZ,1,0), BBOYBI_MASK, PPCCOM,	{ BDA } },
+{ "bdna",    BBO(16,BODNZ,1,0), BBOYBI_MASK, PWRCOM,	{ BDA } },
+{ "bdnzla-", BBO(16,BODNZ,1,1), BBOYBI_MASK, PPCCOM,	{ BDMA } },
+{ "bdnzla+", BBO(16,BODNZ,1,1), BBOYBI_MASK, PPCCOM,	{ BDPA } },
+{ "bdnzla",  BBO(16,BODNZ,1,1), BBOYBI_MASK, PPCCOM,	{ BDA } },
+{ "bdnla",   BBO(16,BODNZ,1,1), BBOYBI_MASK, PWRCOM,	{ BDA } },
+{ "bdz-",    BBO(16,BODZ,0,0),  BBOYBI_MASK, PPCCOM,	{ BDM } },
+{ "bdz+",    BBO(16,BODZ,0,0),  BBOYBI_MASK, PPCCOM,	{ BDP } },
+{ "bdz",     BBO(16,BODZ,0,0),  BBOYBI_MASK, COM,	{ BD } },
+{ "bdzl-",   BBO(16,BODZ,0,1),  BBOYBI_MASK, PPCCOM,	{ BDM } },
+{ "bdzl+",   BBO(16,BODZ,0,1),  BBOYBI_MASK, PPCCOM,	{ BDP } },
+{ "bdzl",    BBO(16,BODZ,0,1),  BBOYBI_MASK, COM,	{ BD } },
+{ "bdza-",   BBO(16,BODZ,1,0),  BBOYBI_MASK, PPCCOM,	{ BDMA } },
+{ "bdza+",   BBO(16,BODZ,1,0),  BBOYBI_MASK, PPCCOM,	{ BDPA } },
+{ "bdza",    BBO(16,BODZ,1,0),  BBOYBI_MASK, COM,	{ BDA } },
+{ "bdzla-",  BBO(16,BODZ,1,1),  BBOYBI_MASK, PPCCOM,	{ BDMA } },
+{ "bdzla+",  BBO(16,BODZ,1,1),  BBOYBI_MASK, PPCCOM,	{ BDPA } },
+{ "bdzla",   BBO(16,BODZ,1,1),  BBOYBI_MASK, COM,	{ BDA } },
+{ "blt-",    BBOCB(16,BOT,CBLT,0,0), BBOYCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "blt+",    BBOCB(16,BOT,CBLT,0,0), BBOYCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "blt",     BBOCB(16,BOT,CBLT,0,0), BBOYCB_MASK, COM,		{ CR, BD } },
+{ "bltl-",   BBOCB(16,BOT,CBLT,0,1), BBOYCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bltl+",   BBOCB(16,BOT,CBLT,0,1), BBOYCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bltl",    BBOCB(16,BOT,CBLT,0,1), BBOYCB_MASK, COM,		{ CR, BD } },
+{ "blta-",   BBOCB(16,BOT,CBLT,1,0), BBOYCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "blta+",   BBOCB(16,BOT,CBLT,1,0), BBOYCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "blta",    BBOCB(16,BOT,CBLT,1,0), BBOYCB_MASK, COM,		{ CR, BDA } },
+{ "bltla-",  BBOCB(16,BOT,CBLT,1,1), BBOYCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bltla+",  BBOCB(16,BOT,CBLT,1,1), BBOYCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bltla",   BBOCB(16,BOT,CBLT,1,1), BBOYCB_MASK, COM,		{ CR, BDA } },
+{ "bgt-",    BBOCB(16,BOT,CBGT,0,0), BBOYCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bgt+",    BBOCB(16,BOT,CBGT,0,0), BBOYCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bgt",     BBOCB(16,BOT,CBGT,0,0), BBOYCB_MASK, COM,		{ CR, BD } },
+{ "bgtl-",   BBOCB(16,BOT,CBGT,0,1), BBOYCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bgtl+",   BBOCB(16,BOT,CBGT,0,1), BBOYCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bgtl",    BBOCB(16,BOT,CBGT,0,1), BBOYCB_MASK, COM,		{ CR, BD } },
+{ "bgta-",   BBOCB(16,BOT,CBGT,1,0), BBOYCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bgta+",   BBOCB(16,BOT,CBGT,1,0), BBOYCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bgta",    BBOCB(16,BOT,CBGT,1,0), BBOYCB_MASK, COM,		{ CR, BDA } },
+{ "bgtla-",  BBOCB(16,BOT,CBGT,1,1), BBOYCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bgtla+",  BBOCB(16,BOT,CBGT,1,1), BBOYCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bgtla",   BBOCB(16,BOT,CBGT,1,1), BBOYCB_MASK, COM,		{ CR, BDA } },
+{ "beq-",    BBOCB(16,BOT,CBEQ,0,0), BBOYCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "beq+",    BBOCB(16,BOT,CBEQ,0,0), BBOYCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "beq",     BBOCB(16,BOT,CBEQ,0,0), BBOYCB_MASK, COM,		{ CR, BD } },
+{ "beql-",   BBOCB(16,BOT,CBEQ,0,1), BBOYCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "beql+",   BBOCB(16,BOT,CBEQ,0,1), BBOYCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "beql",    BBOCB(16,BOT,CBEQ,0,1), BBOYCB_MASK, COM,		{ CR, BD } },
+{ "beqa-",   BBOCB(16,BOT,CBEQ,1,0), BBOYCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "beqa+",   BBOCB(16,BOT,CBEQ,1,0), BBOYCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "beqa",    BBOCB(16,BOT,CBEQ,1,0), BBOYCB_MASK, COM,		{ CR, BDA } },
+{ "beqla-",  BBOCB(16,BOT,CBEQ,1,1), BBOYCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "beqla+",  BBOCB(16,BOT,CBEQ,1,1), BBOYCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "beqla",   BBOCB(16,BOT,CBEQ,1,1), BBOYCB_MASK, COM,		{ CR, BDA } },
+{ "bso-",    BBOCB(16,BOT,CBSO,0,0), BBOYCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bso+",    BBOCB(16,BOT,CBSO,0,0), BBOYCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bso",     BBOCB(16,BOT,CBSO,0,0), BBOYCB_MASK, COM,		{ CR, BD } },
+{ "bsol-",   BBOCB(16,BOT,CBSO,0,1), BBOYCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bsol+",   BBOCB(16,BOT,CBSO,0,1), BBOYCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bsol",    BBOCB(16,BOT,CBSO,0,1), BBOYCB_MASK, COM,		{ CR, BD } },
+{ "bsoa-",   BBOCB(16,BOT,CBSO,1,0), BBOYCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bsoa+",   BBOCB(16,BOT,CBSO,1,0), BBOYCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bsoa",    BBOCB(16,BOT,CBSO,1,0), BBOYCB_MASK, COM,		{ CR, BDA } },
+{ "bsola-",  BBOCB(16,BOT,CBSO,1,1), BBOYCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bsola+",  BBOCB(16,BOT,CBSO,1,1), BBOYCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bsola",   BBOCB(16,BOT,CBSO,1,1), BBOYCB_MASK, COM,		{ CR, BDA } },
+{ "bun-",    BBOCB(16,BOT,CBSO,0,0), BBOYCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bun+",    BBOCB(16,BOT,CBSO,0,0), BBOYCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bun",     BBOCB(16,BOT,CBSO,0,0), BBOYCB_MASK, PPCCOM,	{ CR, BD } },
+{ "bunl-",   BBOCB(16,BOT,CBSO,0,1), BBOYCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bunl+",   BBOCB(16,BOT,CBSO,0,1), BBOYCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bunl",    BBOCB(16,BOT,CBSO,0,1), BBOYCB_MASK, PPCCOM,	{ CR, BD } },
+{ "buna-",   BBOCB(16,BOT,CBSO,1,0), BBOYCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "buna+",   BBOCB(16,BOT,CBSO,1,0), BBOYCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "buna",    BBOCB(16,BOT,CBSO,1,0), BBOYCB_MASK, PPCCOM,	{ CR, BDA } },
+{ "bunla-",  BBOCB(16,BOT,CBSO,1,1), BBOYCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bunla+",  BBOCB(16,BOT,CBSO,1,1), BBOYCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bunla",   BBOCB(16,BOT,CBSO,1,1), BBOYCB_MASK, PPCCOM,	{ CR, BDA } },
+{ "bge-",    BBOCB(16,BOF,CBLT,0,0), BBOYCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bge+",    BBOCB(16,BOF,CBLT,0,0), BBOYCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bge",     BBOCB(16,BOF,CBLT,0,0), BBOYCB_MASK, COM,		{ CR, BD } },
+{ "bgel-",   BBOCB(16,BOF,CBLT,0,1), BBOYCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bgel+",   BBOCB(16,BOF,CBLT,0,1), BBOYCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bgel",    BBOCB(16,BOF,CBLT,0,1), BBOYCB_MASK, COM,		{ CR, BD } },
+{ "bgea-",   BBOCB(16,BOF,CBLT,1,0), BBOYCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bgea+",   BBOCB(16,BOF,CBLT,1,0), BBOYCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bgea",    BBOCB(16,BOF,CBLT,1,0), BBOYCB_MASK, COM,		{ CR, BDA } },
+{ "bgela-",  BBOCB(16,BOF,CBLT,1,1), BBOYCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bgela+",  BBOCB(16,BOF,CBLT,1,1), BBOYCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bgela",   BBOCB(16,BOF,CBLT,1,1), BBOYCB_MASK, COM,		{ CR, BDA } },
+{ "bnl-",    BBOCB(16,BOF,CBLT,0,0), BBOYCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bnl+",    BBOCB(16,BOF,CBLT,0,0), BBOYCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bnl",     BBOCB(16,BOF,CBLT,0,0), BBOYCB_MASK, COM,		{ CR, BD } },
+{ "bnll-",   BBOCB(16,BOF,CBLT,0,1), BBOYCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bnll+",   BBOCB(16,BOF,CBLT,0,1), BBOYCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bnll",    BBOCB(16,BOF,CBLT,0,1), BBOYCB_MASK, COM,		{ CR, BD } },
+{ "bnla-",   BBOCB(16,BOF,CBLT,1,0), BBOYCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bnla+",   BBOCB(16,BOF,CBLT,1,0), BBOYCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bnla",    BBOCB(16,BOF,CBLT,1,0), BBOYCB_MASK, COM,		{ CR, BDA } },
+{ "bnlla-",  BBOCB(16,BOF,CBLT,1,1), BBOYCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bnlla+",  BBOCB(16,BOF,CBLT,1,1), BBOYCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bnlla",   BBOCB(16,BOF,CBLT,1,1), BBOYCB_MASK, COM,		{ CR, BDA } },
+{ "ble-",    BBOCB(16,BOF,CBGT,0,0), BBOYCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "ble+",    BBOCB(16,BOF,CBGT,0,0), BBOYCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "ble",     BBOCB(16,BOF,CBGT,0,0), BBOYCB_MASK, COM,		{ CR, BD } },
+{ "blel-",   BBOCB(16,BOF,CBGT,0,1), BBOYCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "blel+",   BBOCB(16,BOF,CBGT,0,1), BBOYCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "blel",    BBOCB(16,BOF,CBGT,0,1), BBOYCB_MASK, COM,		{ CR, BD } },
+{ "blea-",   BBOCB(16,BOF,CBGT,1,0), BBOYCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "blea+",   BBOCB(16,BOF,CBGT,1,0), BBOYCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "blea",    BBOCB(16,BOF,CBGT,1,0), BBOYCB_MASK, COM,		{ CR, BDA } },
+{ "blela-",  BBOCB(16,BOF,CBGT,1,1), BBOYCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "blela+",  BBOCB(16,BOF,CBGT,1,1), BBOYCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "blela",   BBOCB(16,BOF,CBGT,1,1), BBOYCB_MASK, COM,		{ CR, BDA } },
+{ "bng-",    BBOCB(16,BOF,CBGT,0,0), BBOYCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bng+",    BBOCB(16,BOF,CBGT,0,0), BBOYCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bng",     BBOCB(16,BOF,CBGT,0,0), BBOYCB_MASK, COM,		{ CR, BD } },
+{ "bngl-",   BBOCB(16,BOF,CBGT,0,1), BBOYCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bngl+",   BBOCB(16,BOF,CBGT,0,1), BBOYCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bngl",    BBOCB(16,BOF,CBGT,0,1), BBOYCB_MASK, COM,		{ CR, BD } },
+{ "bnga-",   BBOCB(16,BOF,CBGT,1,0), BBOYCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bnga+",   BBOCB(16,BOF,CBGT,1,0), BBOYCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bnga",    BBOCB(16,BOF,CBGT,1,0), BBOYCB_MASK, COM,		{ CR, BDA } },
+{ "bngla-",  BBOCB(16,BOF,CBGT,1,1), BBOYCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bngla+",  BBOCB(16,BOF,CBGT,1,1), BBOYCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bngla",   BBOCB(16,BOF,CBGT,1,1), BBOYCB_MASK, COM,		{ CR, BDA } },
+{ "bne-",    BBOCB(16,BOF,CBEQ,0,0), BBOYCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bne+",    BBOCB(16,BOF,CBEQ,0,0), BBOYCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bne",     BBOCB(16,BOF,CBEQ,0,0), BBOYCB_MASK, COM,		{ CR, BD } },
+{ "bnel-",   BBOCB(16,BOF,CBEQ,0,1), BBOYCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bnel+",   BBOCB(16,BOF,CBEQ,0,1), BBOYCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bnel",    BBOCB(16,BOF,CBEQ,0,1), BBOYCB_MASK, COM,		{ CR, BD } },
+{ "bnea-",   BBOCB(16,BOF,CBEQ,1,0), BBOYCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bnea+",   BBOCB(16,BOF,CBEQ,1,0), BBOYCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bnea",    BBOCB(16,BOF,CBEQ,1,0), BBOYCB_MASK, COM,		{ CR, BDA } },
+{ "bnela-",  BBOCB(16,BOF,CBEQ,1,1), BBOYCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bnela+",  BBOCB(16,BOF,CBEQ,1,1), BBOYCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bnela",   BBOCB(16,BOF,CBEQ,1,1), BBOYCB_MASK, COM,		{ CR, BDA } },
+{ "bns-",    BBOCB(16,BOF,CBSO,0,0), BBOYCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bns+",    BBOCB(16,BOF,CBSO,0,0), BBOYCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bns",     BBOCB(16,BOF,CBSO,0,0), BBOYCB_MASK, COM,		{ CR, BD } },
+{ "bnsl-",   BBOCB(16,BOF,CBSO,0,1), BBOYCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bnsl+",   BBOCB(16,BOF,CBSO,0,1), BBOYCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bnsl",    BBOCB(16,BOF,CBSO,0,1), BBOYCB_MASK, COM,		{ CR, BD } },
+{ "bnsa-",   BBOCB(16,BOF,CBSO,1,0), BBOYCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bnsa+",   BBOCB(16,BOF,CBSO,1,0), BBOYCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bnsa",    BBOCB(16,BOF,CBSO,1,0), BBOYCB_MASK, COM,		{ CR, BDA } },
+{ "bnsla-",  BBOCB(16,BOF,CBSO,1,1), BBOYCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bnsla+",  BBOCB(16,BOF,CBSO,1,1), BBOYCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bnsla",   BBOCB(16,BOF,CBSO,1,1), BBOYCB_MASK, COM,		{ CR, BDA } },
+{ "bnu-",    BBOCB(16,BOF,CBSO,0,0), BBOYCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bnu+",    BBOCB(16,BOF,CBSO,0,0), BBOYCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bnu",     BBOCB(16,BOF,CBSO,0,0), BBOYCB_MASK, PPCCOM,	{ CR, BD } },
+{ "bnul-",   BBOCB(16,BOF,CBSO,0,1), BBOYCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bnul+",   BBOCB(16,BOF,CBSO,0,1), BBOYCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bnul",    BBOCB(16,BOF,CBSO,0,1), BBOYCB_MASK, PPCCOM,	{ CR, BD } },
+{ "bnua-",   BBOCB(16,BOF,CBSO,1,0), BBOYCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bnua+",   BBOCB(16,BOF,CBSO,1,0), BBOYCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bnua",    BBOCB(16,BOF,CBSO,1,0), BBOYCB_MASK, PPCCOM,	{ CR, BDA } },
+{ "bnula-",  BBOCB(16,BOF,CBSO,1,1), BBOYCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bnula+",  BBOCB(16,BOF,CBSO,1,1), BBOYCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bnula",   BBOCB(16,BOF,CBSO,1,1), BBOYCB_MASK, PPCCOM,	{ CR, BDA } },
+{ "bdnzt-",  BBO(16,BODNZT,0,0), BBOY_MASK, PPCCOM,	{ BI, BDM } },
+{ "bdnzt+",  BBO(16,BODNZT,0,0), BBOY_MASK, PPCCOM,	{ BI, BDP } },
+{ "bdnzt",   BBO(16,BODNZT,0,0), BBOY_MASK, PPCCOM,	{ BI, BD } },
+{ "bdnztl-", BBO(16,BODNZT,0,1), BBOY_MASK, PPCCOM,	{ BI, BDM } },
+{ "bdnztl+", BBO(16,BODNZT,0,1), BBOY_MASK, PPCCOM,	{ BI, BDP } },
+{ "bdnztl",  BBO(16,BODNZT,0,1), BBOY_MASK, PPCCOM,	{ BI, BD } },
+{ "bdnzta-", BBO(16,BODNZT,1,0), BBOY_MASK, PPCCOM,	{ BI, BDMA } },
+{ "bdnzta+", BBO(16,BODNZT,1,0), BBOY_MASK, PPCCOM,	{ BI, BDPA } },
+{ "bdnzta",  BBO(16,BODNZT,1,0), BBOY_MASK, PPCCOM,	{ BI, BDA } },
+{ "bdnztla-",BBO(16,BODNZT,1,1), BBOY_MASK, PPCCOM,	{ BI, BDMA } },
+{ "bdnztla+",BBO(16,BODNZT,1,1), BBOY_MASK, PPCCOM,	{ BI, BDPA } },
+{ "bdnztla", BBO(16,BODNZT,1,1), BBOY_MASK, PPCCOM,	{ BI, BDA } },
+{ "bdnzf-",  BBO(16,BODNZF,0,0), BBOY_MASK, PPCCOM,	{ BI, BDM } },
+{ "bdnzf+",  BBO(16,BODNZF,0,0), BBOY_MASK, PPCCOM,	{ BI, BDP } },
+{ "bdnzf",   BBO(16,BODNZF,0,0), BBOY_MASK, PPCCOM,	{ BI, BD } },
+{ "bdnzfl-", BBO(16,BODNZF,0,1), BBOY_MASK, PPCCOM,	{ BI, BDM } },
+{ "bdnzfl+", BBO(16,BODNZF,0,1), BBOY_MASK, PPCCOM,	{ BI, BDP } },
+{ "bdnzfl",  BBO(16,BODNZF,0,1), BBOY_MASK, PPCCOM,	{ BI, BD } },
+{ "bdnzfa-", BBO(16,BODNZF,1,0), BBOY_MASK, PPCCOM,	{ BI, BDMA } },
+{ "bdnzfa+", BBO(16,BODNZF,1,0), BBOY_MASK, PPCCOM,	{ BI, BDPA } },
+{ "bdnzfa",  BBO(16,BODNZF,1,0), BBOY_MASK, PPCCOM,	{ BI, BDA } },
+{ "bdnzfla-",BBO(16,BODNZF,1,1), BBOY_MASK, PPCCOM,	{ BI, BDMA } },
+{ "bdnzfla+",BBO(16,BODNZF,1,1), BBOY_MASK, PPCCOM,	{ BI, BDPA } },
+{ "bdnzfla", BBO(16,BODNZF,1,1), BBOY_MASK, PPCCOM,	{ BI, BDA } },
+{ "bt-",     BBO(16,BOT,0,0), BBOY_MASK, PPCCOM,	{ BI, BDM } },
+{ "bt+",     BBO(16,BOT,0,0), BBOY_MASK, PPCCOM,	{ BI, BDP } },
+{ "bt",	     BBO(16,BOT,0,0), BBOY_MASK, PPCCOM,	{ BI, BD } },
+{ "bbt",     BBO(16,BOT,0,0), BBOY_MASK, PWRCOM,	{ BI, BD } },
+{ "btl-",    BBO(16,BOT,0,1), BBOY_MASK, PPCCOM,	{ BI, BDM } },
+{ "btl+",    BBO(16,BOT,0,1), BBOY_MASK, PPCCOM,	{ BI, BDP } },
+{ "btl",     BBO(16,BOT,0,1), BBOY_MASK, PPCCOM,	{ BI, BD } },
+{ "bbtl",    BBO(16,BOT,0,1), BBOY_MASK, PWRCOM,	{ BI, BD } },
+{ "bta-",    BBO(16,BOT,1,0), BBOY_MASK, PPCCOM,	{ BI, BDMA } },
+{ "bta+",    BBO(16,BOT,1,0), BBOY_MASK, PPCCOM,	{ BI, BDPA } },
+{ "bta",     BBO(16,BOT,1,0), BBOY_MASK, PPCCOM,	{ BI, BDA } },
+{ "bbta",    BBO(16,BOT,1,0), BBOY_MASK, PWRCOM,	{ BI, BDA } },
+{ "btla-",   BBO(16,BOT,1,1), BBOY_MASK, PPCCOM,	{ BI, BDMA } },
+{ "btla+",   BBO(16,BOT,1,1), BBOY_MASK, PPCCOM,	{ BI, BDPA } },
+{ "btla",    BBO(16,BOT,1,1), BBOY_MASK, PPCCOM,	{ BI, BDA } },
+{ "bbtla",   BBO(16,BOT,1,1), BBOY_MASK, PWRCOM,	{ BI, BDA } },
+{ "bf-",     BBO(16,BOF,0,0), BBOY_MASK, PPCCOM,	{ BI, BDM } },
+{ "bf+",     BBO(16,BOF,0,0), BBOY_MASK, PPCCOM,	{ BI, BDP } },
+{ "bf",	     BBO(16,BOF,0,0), BBOY_MASK, PPCCOM,	{ BI, BD } },
+{ "bbf",     BBO(16,BOF,0,0), BBOY_MASK, PWRCOM,	{ BI, BD } },
+{ "bfl-",    BBO(16,BOF,0,1), BBOY_MASK, PPCCOM,	{ BI, BDM } },
+{ "bfl+",    BBO(16,BOF,0,1), BBOY_MASK, PPCCOM,	{ BI, BDP } },
+{ "bfl",     BBO(16,BOF,0,1), BBOY_MASK, PPCCOM,	{ BI, BD } },
+{ "bbfl",    BBO(16,BOF,0,1), BBOY_MASK, PWRCOM,	{ BI, BD } },
+{ "bfa-",    BBO(16,BOF,1,0), BBOY_MASK, PPCCOM,	{ BI, BDMA } },
+{ "bfa+",    BBO(16,BOF,1,0), BBOY_MASK, PPCCOM,	{ BI, BDPA } },
+{ "bfa",     BBO(16,BOF,1,0), BBOY_MASK, PPCCOM,	{ BI, BDA } },
+{ "bbfa",    BBO(16,BOF,1,0), BBOY_MASK, PWRCOM,	{ BI, BDA } },
+{ "bfla-",   BBO(16,BOF,1,1), BBOY_MASK, PPCCOM,	{ BI, BDMA } },
+{ "bfla+",   BBO(16,BOF,1,1), BBOY_MASK, PPCCOM,	{ BI, BDPA } },
+{ "bfla",    BBO(16,BOF,1,1), BBOY_MASK, PPCCOM,	{ BI, BDA } },
+{ "bbfla",   BBO(16,BOF,1,1), BBOY_MASK, PWRCOM,	{ BI, BDA } },
+{ "bdzt-",   BBO(16,BODZT,0,0), BBOY_MASK, PPCCOM,	{ BI, BDM } },
+{ "bdzt+",   BBO(16,BODZT,0,0), BBOY_MASK, PPCCOM,	{ BI, BDP } },
+{ "bdzt",    BBO(16,BODZT,0,0), BBOY_MASK, PPCCOM,	{ BI, BD } },
+{ "bdztl-",  BBO(16,BODZT,0,1), BBOY_MASK, PPCCOM,	{ BI, BDM } },
+{ "bdztl+",  BBO(16,BODZT,0,1), BBOY_MASK, PPCCOM,	{ BI, BDP } },
+{ "bdztl",   BBO(16,BODZT,0,1), BBOY_MASK, PPCCOM,	{ BI, BD } },
+{ "bdzta-",  BBO(16,BODZT,1,0), BBOY_MASK, PPCCOM,	{ BI, BDMA } },
+{ "bdzta+",  BBO(16,BODZT,1,0), BBOY_MASK, PPCCOM,	{ BI, BDPA } },
+{ "bdzta",   BBO(16,BODZT,1,0), BBOY_MASK, PPCCOM,	{ BI, BDA } },
+{ "bdztla-", BBO(16,BODZT,1,1), BBOY_MASK, PPCCOM,	{ BI, BDMA } },
+{ "bdztla+", BBO(16,BODZT,1,1), BBOY_MASK, PPCCOM,	{ BI, BDPA } },
+{ "bdztla",  BBO(16,BODZT,1,1), BBOY_MASK, PPCCOM,	{ BI, BDA } },
+{ "bdzf-",   BBO(16,BODZF,0,0), BBOY_MASK, PPCCOM,	{ BI, BDM } },
+{ "bdzf+",   BBO(16,BODZF,0,0), BBOY_MASK, PPCCOM,	{ BI, BDP } },
+{ "bdzf",    BBO(16,BODZF,0,0), BBOY_MASK, PPCCOM,	{ BI, BD } },
+{ "bdzfl-",  BBO(16,BODZF,0,1), BBOY_MASK, PPCCOM,	{ BI, BDM } },
+{ "bdzfl+",  BBO(16,BODZF,0,1), BBOY_MASK, PPCCOM,	{ BI, BDP } },
+{ "bdzfl",   BBO(16,BODZF,0,1), BBOY_MASK, PPCCOM,	{ BI, BD } },
+{ "bdzfa-",  BBO(16,BODZF,1,0), BBOY_MASK, PPCCOM,	{ BI, BDMA } },
+{ "bdzfa+",  BBO(16,BODZF,1,0), BBOY_MASK, PPCCOM,	{ BI, BDPA } },
+{ "bdzfa",   BBO(16,BODZF,1,0), BBOY_MASK, PPCCOM,	{ BI, BDA } },
+{ "bdzfla-", BBO(16,BODZF,1,1), BBOY_MASK, PPCCOM,	{ BI, BDMA } },
+{ "bdzfla+", BBO(16,BODZF,1,1), BBOY_MASK, PPCCOM,	{ BI, BDPA } },
+{ "bdzfla",  BBO(16,BODZF,1,1), BBOY_MASK, PPCCOM,	{ BI, BDA } },
+{ "bc-",     B(16,0,0),	B_MASK,		PPCCOM,		{ BOE, BI, BDM } },
+{ "bc+",     B(16,0,0),	B_MASK,		PPCCOM,		{ BOE, BI, BDP } },
+{ "bc",	     B(16,0,0),	B_MASK,		COM,		{ BO, BI, BD } },
+{ "bcl-",    B(16,0,1),	B_MASK,		PPCCOM,		{ BOE, BI, BDM } },
+{ "bcl+",    B(16,0,1),	B_MASK,		PPCCOM,		{ BOE, BI, BDP } },
+{ "bcl",     B(16,0,1),	B_MASK,		COM,		{ BO, BI, BD } },
+{ "bca-",    B(16,1,0),	B_MASK,		PPCCOM,		{ BOE, BI, BDMA } },
+{ "bca+",    B(16,1,0),	B_MASK,		PPCCOM,		{ BOE, BI, BDPA } },
+{ "bca",     B(16,1,0),	B_MASK,		COM,		{ BO, BI, BDA } },
+{ "bcla-",   B(16,1,1),	B_MASK,		PPCCOM,		{ BOE, BI, BDMA } },
+{ "bcla+",   B(16,1,1),	B_MASK,		PPCCOM,		{ BOE, BI, BDPA } },
+{ "bcla",    B(16,1,1),	B_MASK,		COM,		{ BO, BI, BDA } },
+
+{ "sc",      SC(17,1,0), 0xffffffff,	PPC,		{ 0 } },
+{ "svc",     SC(17,0,0), SC_MASK,	POWER,		{ LEV, FL1, FL2 } },
+{ "svcl",    SC(17,0,1), SC_MASK,	POWER,		{ LEV, FL1, FL2 } },
+{ "svca",    SC(17,1,0), SC_MASK,	PWRCOM,		{ SV } },
+{ "svcla",   SC(17,1,1), SC_MASK,	POWER,		{ SV } },
+
+{ "b",	     B(18,0,0),	B_MASK,		COM,	{ LI } },
+{ "bl",      B(18,0,1),	B_MASK,		COM,	{ LI } },
+{ "ba",      B(18,1,0),	B_MASK,		COM,	{ LIA } },
+{ "bla",     B(18,1,1),	B_MASK,		COM,	{ LIA } },
+
+{ "mcrf",    XL(19,0),	XLBB_MASK|(3<<21)|(3<<16), COM,	{ BF, BFA } },
+
+{ "blr",     XLO(19,BOU,16,0), XLBOBIBB_MASK, PPCCOM,	{ 0 } },
+{ "br",      XLO(19,BOU,16,0), XLBOBIBB_MASK, PWRCOM,	{ 0 } },
+{ "blrl",    XLO(19,BOU,16,1), XLBOBIBB_MASK, PPCCOM,	{ 0 } },
+{ "brl",     XLO(19,BOU,16,1), XLBOBIBB_MASK, PWRCOM,	{ 0 } },
+{ "bdnzlr",  XLO(19,BODNZ,16,0), XLBOBIBB_MASK, PPCCOM,	{ 0 } },
+{ "bdnzlr-", XLO(19,BODNZ,16,0), XLBOBIBB_MASK, PPCCOM,	{ 0 } },
+{ "bdnzlr+", XLO(19,BODNZP,16,0), XLBOBIBB_MASK, PPCCOM,	{ 0 } },
+{ "bdnzlrl", XLO(19,BODNZ,16,1), XLBOBIBB_MASK, PPCCOM,	{ 0 } },
+{ "bdnzlrl-",XLO(19,BODNZ,16,1), XLBOBIBB_MASK, PPCCOM,	{ 0 } },
+{ "bdnzlrl+",XLO(19,BODNZP,16,1), XLBOBIBB_MASK, PPCCOM,	{ 0 } },
+{ "bdzlr",   XLO(19,BODZ,16,0), XLBOBIBB_MASK, PPCCOM,	{ 0 } },
+{ "bdzlr-",  XLO(19,BODZ,16,0), XLBOBIBB_MASK, PPCCOM,	{ 0 } },
+{ "bdzlr+",  XLO(19,BODZP,16,0), XLBOBIBB_MASK, PPCCOM,	{ 0 } },
+{ "bdzlrl",  XLO(19,BODZ,16,1), XLBOBIBB_MASK, PPCCOM,	{ 0 } },
+{ "bdzlrl-", XLO(19,BODZ,16,1), XLBOBIBB_MASK, PPCCOM,	{ 0 } },
+{ "bdzlrl+", XLO(19,BODZP,16,1), XLBOBIBB_MASK, PPCCOM,	{ 0 } },
+{ "bltlr",   XLOCB(19,BOT,CBLT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bltlr-",  XLOCB(19,BOT,CBLT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bltlr+",  XLOCB(19,BOTP,CBLT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bltr",    XLOCB(19,BOT,CBLT,16,0), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bltlrl",  XLOCB(19,BOT,CBLT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bltlrl-", XLOCB(19,BOT,CBLT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bltlrl+", XLOCB(19,BOTP,CBLT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bltrl",   XLOCB(19,BOT,CBLT,16,1), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bgtlr",   XLOCB(19,BOT,CBGT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bgtlr-",  XLOCB(19,BOT,CBGT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bgtlr+",  XLOCB(19,BOTP,CBGT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bgtr",    XLOCB(19,BOT,CBGT,16,0), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bgtlrl",  XLOCB(19,BOT,CBGT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bgtlrl-", XLOCB(19,BOT,CBGT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bgtlrl+", XLOCB(19,BOTP,CBGT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bgtrl",   XLOCB(19,BOT,CBGT,16,1), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "beqlr",   XLOCB(19,BOT,CBEQ,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "beqlr-",  XLOCB(19,BOT,CBEQ,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "beqlr+",  XLOCB(19,BOTP,CBEQ,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "beqr",    XLOCB(19,BOT,CBEQ,16,0), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "beqlrl",  XLOCB(19,BOT,CBEQ,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "beqlrl-", XLOCB(19,BOT,CBEQ,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "beqlrl+", XLOCB(19,BOTP,CBEQ,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "beqrl",   XLOCB(19,BOT,CBEQ,16,1), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bsolr",   XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bsolr-",  XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bsolr+",  XLOCB(19,BOTP,CBSO,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bsor",    XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bsolrl",  XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bsolrl-", XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bsolrl+", XLOCB(19,BOTP,CBSO,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bsorl",   XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bunlr",   XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bunlr-",  XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bunlr+",  XLOCB(19,BOTP,CBSO,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bunlrl",  XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bunlrl-", XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bunlrl+", XLOCB(19,BOTP,CBSO,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bgelr",   XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bgelr-",  XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bgelr+",  XLOCB(19,BOFP,CBLT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bger",    XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bgelrl",  XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bgelrl-", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bgelrl+", XLOCB(19,BOFP,CBLT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bgerl",   XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bnllr",   XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnllr-",  XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnllr+",  XLOCB(19,BOFP,CBLT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnlr",    XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bnllrl",  XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnllrl-", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnllrl+", XLOCB(19,BOFP,CBLT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnlrl",   XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "blelr",   XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "blelr-",  XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "blelr+",  XLOCB(19,BOFP,CBGT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bler",    XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "blelrl",  XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "blelrl-", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "blelrl+", XLOCB(19,BOFP,CBGT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "blerl",   XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bnglr",   XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnglr-",  XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnglr+",  XLOCB(19,BOFP,CBGT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bngr",    XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bnglrl",  XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnglrl-", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnglrl+", XLOCB(19,BOFP,CBGT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bngrl",   XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bnelr",   XLOCB(19,BOF,CBEQ,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnelr-",  XLOCB(19,BOF,CBEQ,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnelr+",  XLOCB(19,BOFP,CBEQ,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bner",    XLOCB(19,BOF,CBEQ,16,0), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bnelrl",  XLOCB(19,BOF,CBEQ,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnelrl-", XLOCB(19,BOF,CBEQ,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnelrl+", XLOCB(19,BOFP,CBEQ,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnerl",   XLOCB(19,BOF,CBEQ,16,1), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bnslr",   XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnslr-",  XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnslr+",  XLOCB(19,BOFP,CBSO,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnsr",    XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bnslrl",  XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnslrl-", XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnslrl+", XLOCB(19,BOFP,CBSO,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnsrl",   XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bnulr",   XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnulr-",  XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnulr+",  XLOCB(19,BOFP,CBSO,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnulrl",  XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnulrl-", XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnulrl+", XLOCB(19,BOFP,CBSO,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "btlr",    XLO(19,BOT,16,0), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "btlr-",   XLO(19,BOT,16,0), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "btlr+",   XLO(19,BOTP,16,0), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bbtr",    XLO(19,BOT,16,0), XLBOBB_MASK, PWRCOM,	{ BI } },
+{ "btlrl",   XLO(19,BOT,16,1), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "btlrl-",  XLO(19,BOT,16,1), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "btlrl+",  XLO(19,BOTP,16,1), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bbtrl",   XLO(19,BOT,16,1), XLBOBB_MASK, PWRCOM,	{ BI } },
+{ "bflr",    XLO(19,BOF,16,0), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bflr-",   XLO(19,BOF,16,0), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bflr+",   XLO(19,BOFP,16,0), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bbfr",    XLO(19,BOF,16,0), XLBOBB_MASK, PWRCOM,	{ BI } },
+{ "bflrl",   XLO(19,BOF,16,1), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bflrl-",  XLO(19,BOF,16,1), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bflrl+",  XLO(19,BOFP,16,1), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bbfrl",   XLO(19,BOF,16,1), XLBOBB_MASK, PWRCOM,	{ BI } },
+{ "bdnztlr", XLO(19,BODNZT,16,0), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bdnztlr-",XLO(19,BODNZT,16,0), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bdnztlr+",XLO(19,BODNZTP,16,0), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bdnztlrl",XLO(19,BODNZT,16,1), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bdnztlrl-",XLO(19,BODNZT,16,1), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bdnztlrl+",XLO(19,BODNZTP,16,1), XLBOBB_MASK, PPCCOM,{ BI } },
+{ "bdnzflr", XLO(19,BODNZF,16,0), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bdnzflr-",XLO(19,BODNZF,16,0), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bdnzflr+",XLO(19,BODNZFP,16,0), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bdnzflrl",XLO(19,BODNZF,16,1), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bdnzflrl-",XLO(19,BODNZF,16,1), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bdnzflrl+",XLO(19,BODNZFP,16,1), XLBOBB_MASK, PPCCOM,{ BI } },
+{ "bdztlr",  XLO(19,BODZT,16,0), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bdztlr-", XLO(19,BODZT,16,0), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bdztlr+", XLO(19,BODZTP,16,0), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bdztlrl", XLO(19,BODZT,16,1), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bdztlrl-",XLO(19,BODZT,16,1), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bdztlrl+",XLO(19,BODZTP,16,1), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bdzflr",  XLO(19,BODZF,16,0), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bdzflr-", XLO(19,BODZF,16,0), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bdzflr+", XLO(19,BODZFP,16,0), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bdzflrl", XLO(19,BODZF,16,1), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bdzflrl-",XLO(19,BODZF,16,1), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bdzflrl+",XLO(19,BODZFP,16,1), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bclr",    XLLK(19,16,0), XLYBB_MASK,	PPCCOM,		{ BO, BI } },
+{ "bclrl",   XLLK(19,16,1), XLYBB_MASK,	PPCCOM,		{ BO, BI } },
+{ "bclr+",   XLYLK(19,16,1,0), XLYBB_MASK, PPCCOM,	{ BOE, BI } },
+{ "bclrl+",  XLYLK(19,16,1,1), XLYBB_MASK, PPCCOM,	{ BOE, BI } },
+{ "bclr-",   XLYLK(19,16,0,0), XLYBB_MASK, PPCCOM,	{ BOE, BI } },
+{ "bclrl-",  XLYLK(19,16,0,1), XLYBB_MASK, PPCCOM,	{ BOE, BI } },
+{ "bcr",     XLLK(19,16,0), XLBB_MASK,	PWRCOM,		{ BO, BI } },
+{ "bcrl",    XLLK(19,16,1), XLBB_MASK,	PWRCOM,		{ BO, BI } },
+
+{ "rfid",    XL(19,18),	0xffffffff,	PPC64,		{ 0 } },
+
+{ "crnot",   XL(19,33), XL_MASK,	PPCCOM,		{ BT, BA, BBA } },
+{ "crnor",   XL(19,33),	XL_MASK,	COM,		{ BT, BA, BB } },
+
+{ "rfi",     XL(19,50),	0xffffffff,	COM,		{ 0 } },
+{ "rfci",    XL(19,51),	0xffffffff,	PPC403,		{ 0 } },
+
+{ "rfsvc",   XL(19,82),	0xffffffff,	POWER,		{ 0 } },
+
+{ "crandc",  XL(19,129), XL_MASK,	COM,		{ BT, BA, BB } },
+
+{ "isync",   XL(19,150), 0xffffffff,	PPCCOM,		{ 0 } },
+{ "ics",     XL(19,150), 0xffffffff,	PWRCOM,		{ 0 } },
+
+{ "crclr",   XL(19,193), XL_MASK,	PPCCOM,		{ BT, BAT, BBA } },
+{ "crxor",   XL(19,193), XL_MASK,	COM,		{ BT, BA, BB } },
+
+{ "crnand",  XL(19,225), XL_MASK,	COM,		{ BT, BA, BB } },
+
+{ "crand",   XL(19,257), XL_MASK,	COM,		{ BT, BA, BB } },
+
+{ "crset",   XL(19,289), XL_MASK,	PPCCOM,		{ BT, BAT, BBA } },
+{ "creqv",   XL(19,289), XL_MASK,	COM,		{ BT, BA, BB } },
+
+{ "crorc",   XL(19,417), XL_MASK,	COM,		{ BT, BA, BB } },
+
+{ "crmove",  XL(19,449), XL_MASK,	PPCCOM,		{ BT, BA, BBA } },
+{ "cror",    XL(19,449), XL_MASK,	COM,		{ BT, BA, BB } },
+
+{ "bctr",    XLO(19,BOU,528,0), XLBOBIBB_MASK, COM,	{ 0 } },
+{ "bctrl",   XLO(19,BOU,528,1), XLBOBIBB_MASK, COM,	{ 0 } },
+{ "bltctr",  XLOCB(19,BOT,CBLT,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bltctr-", XLOCB(19,BOT,CBLT,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bltctr+", XLOCB(19,BOTP,CBLT,528,0), XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bltctrl", XLOCB(19,BOT,CBLT,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bltctrl-",XLOCB(19,BOT,CBLT,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bltctrl+",XLOCB(19,BOTP,CBLT,528,1), XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bgtctr",  XLOCB(19,BOT,CBGT,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bgtctr-", XLOCB(19,BOT,CBGT,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bgtctr+", XLOCB(19,BOTP,CBGT,528,0), XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bgtctrl", XLOCB(19,BOT,CBGT,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bgtctrl-",XLOCB(19,BOT,CBGT,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bgtctrl+",XLOCB(19,BOTP,CBGT,528,1), XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "beqctr",  XLOCB(19,BOT,CBEQ,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "beqctr-", XLOCB(19,BOT,CBEQ,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "beqctr+", XLOCB(19,BOTP,CBEQ,528,0), XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "beqctrl", XLOCB(19,BOT,CBEQ,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "beqctrl-",XLOCB(19,BOT,CBEQ,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "beqctrl+",XLOCB(19,BOTP,CBEQ,528,1), XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bsoctr",  XLOCB(19,BOT,CBSO,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bsoctr-", XLOCB(19,BOT,CBSO,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bsoctr+", XLOCB(19,BOTP,CBSO,528,0), XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bsoctrl", XLOCB(19,BOT,CBSO,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bsoctrl-",XLOCB(19,BOT,CBSO,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bsoctrl+",XLOCB(19,BOTP,CBSO,528,1), XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bunctr",  XLOCB(19,BOT,CBSO,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bunctr-", XLOCB(19,BOT,CBSO,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bunctr+", XLOCB(19,BOTP,CBSO,528,0), XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bunctrl", XLOCB(19,BOT,CBSO,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bunctrl-",XLOCB(19,BOT,CBSO,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bunctrl+",XLOCB(19,BOTP,CBSO,528,1), XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bgectr",  XLOCB(19,BOF,CBLT,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bgectr-", XLOCB(19,BOF,CBLT,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bgectr+", XLOCB(19,BOFP,CBLT,528,0), XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bgectrl", XLOCB(19,BOF,CBLT,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bgectrl-",XLOCB(19,BOF,CBLT,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bgectrl+",XLOCB(19,BOFP,CBLT,528,1), XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bnlctr",  XLOCB(19,BOF,CBLT,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bnlctr-", XLOCB(19,BOF,CBLT,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bnlctr+", XLOCB(19,BOFP,CBLT,528,0), XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bnlctrl", XLOCB(19,BOF,CBLT,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bnlctrl-",XLOCB(19,BOF,CBLT,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bnlctrl+",XLOCB(19,BOFP,CBLT,528,1), XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "blectr",  XLOCB(19,BOF,CBGT,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "blectr-", XLOCB(19,BOF,CBGT,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "blectr+", XLOCB(19,BOFP,CBGT,528,0), XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "blectrl", XLOCB(19,BOF,CBGT,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "blectrl-",XLOCB(19,BOF,CBGT,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "blectrl+",XLOCB(19,BOFP,CBGT,528,1), XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bngctr",  XLOCB(19,BOF,CBGT,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bngctr-", XLOCB(19,BOF,CBGT,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bngctr+", XLOCB(19,BOFP,CBGT,528,0), XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bngctrl", XLOCB(19,BOF,CBGT,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bngctrl-",XLOCB(19,BOF,CBGT,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bngctrl+",XLOCB(19,BOFP,CBGT,528,1), XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bnectr",  XLOCB(19,BOF,CBEQ,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bnectr-", XLOCB(19,BOF,CBEQ,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bnectr+", XLOCB(19,BOFP,CBEQ,528,0), XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bnectrl", XLOCB(19,BOF,CBEQ,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bnectrl-",XLOCB(19,BOF,CBEQ,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bnectrl+",XLOCB(19,BOFP,CBEQ,528,1), XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bnsctr",  XLOCB(19,BOF,CBSO,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bnsctr-", XLOCB(19,BOF,CBSO,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bnsctr+", XLOCB(19,BOFP,CBSO,528,0), XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bnsctrl", XLOCB(19,BOF,CBSO,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bnsctrl-",XLOCB(19,BOF,CBSO,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bnsctrl+",XLOCB(19,BOFP,CBSO,528,1), XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bnuctr",  XLOCB(19,BOF,CBSO,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bnuctr-", XLOCB(19,BOF,CBSO,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bnuctr+", XLOCB(19,BOFP,CBSO,528,0), XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bnuctrl", XLOCB(19,BOF,CBSO,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bnuctrl-",XLOCB(19,BOF,CBSO,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bnuctrl+",XLOCB(19,BOFP,CBSO,528,1), XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "btctr",   XLO(19,BOT,528,0),  XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "btctr-",  XLO(19,BOT,528,0),  XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "btctr+",  XLO(19,BOTP,528,0), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "btctrl",  XLO(19,BOT,528,1),  XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "btctrl-", XLO(19,BOT,528,1),  XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "btctrl+", XLO(19,BOTP,528,1), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bfctr",   XLO(19,BOF,528,0),  XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bfctr-",  XLO(19,BOF,528,0),  XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bfctr+",  XLO(19,BOFP,528,0), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bfctrl",  XLO(19,BOF,528,1),  XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bfctrl-", XLO(19,BOF,528,1),  XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bfctrl+", XLO(19,BOFP,528,1), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bcctr",   XLLK(19,528,0),     XLYBB_MASK,  PPCCOM,	{ BO, BI } },
+{ "bcctr-",  XLYLK(19,528,0,0),  XLYBB_MASK,  PPCCOM,	{ BOE, BI } },
+{ "bcctr+",  XLYLK(19,528,1,0),  XLYBB_MASK,  PPCCOM,	{ BOE, BI } },
+{ "bcctrl",  XLLK(19,528,1),     XLYBB_MASK,  PPCCOM,	{ BO, BI } },
+{ "bcctrl-", XLYLK(19,528,0,1),  XLYBB_MASK,  PPCCOM,	{ BOE, BI } },
+{ "bcctrl+", XLYLK(19,528,1,1),  XLYBB_MASK,  PPCCOM,	{ BOE, BI } },
+{ "bcc",     XLLK(19,528,0),     XLBB_MASK,   PWRCOM,	{ BO, BI } },
+{ "bccl",    XLLK(19,528,1),     XLBB_MASK,   PWRCOM,	{ BO, BI } },
+
+{ "rlwimi",  M(20,0),	M_MASK,		PPCCOM,		{ RA,RS,SH,MBE,ME } },
+{ "rlimi",   M(20,0),	M_MASK,		PWRCOM,		{ RA,RS,SH,MBE,ME } },
+
+{ "rlwimi.", M(20,1),	M_MASK,		PPCCOM,		{ RA,RS,SH,MBE,ME } },
+{ "rlimi.",  M(20,1),	M_MASK,		PWRCOM,		{ RA,RS,SH,MBE,ME } },
+
+{ "rotlwi",  MME(21,31,0), MMBME_MASK,	PPCCOM,		{ RA, RS, SH } },
+{ "clrlwi",  MME(21,31,0), MSHME_MASK,	PPCCOM,		{ RA, RS, MB } },
+{ "rlwinm",  M(21,0),	M_MASK,		PPCCOM,		{ RA,RS,SH,MBE,ME } },
+{ "rlinm",   M(21,0),	M_MASK,		PWRCOM,		{ RA,RS,SH,MBE,ME } },
+{ "rotlwi.", MME(21,31,1), MMBME_MASK,	PPCCOM,		{ RA,RS,SH } },
+{ "clrlwi.", MME(21,31,1), MSHME_MASK,	PPCCOM,		{ RA, RS, MB } },
+{ "rlwinm.", M(21,1),	M_MASK,		PPCCOM,		{ RA,RS,SH,MBE,ME } },
+{ "rlinm.",  M(21,1),	M_MASK,		PWRCOM,		{ RA,RS,SH,MBE,ME } },
+
+{ "rlmi",    M(22,0),	M_MASK,		M601,		{ RA,RS,RB,MBE,ME } },
+{ "rlmi.",   M(22,1),	M_MASK,		M601,		{ RA,RS,RB,MBE,ME } },
+
+{ "rotlw",   MME(23,31,0), MMBME_MASK,	PPCCOM,		{ RA, RS, RB } },
+{ "rlwnm",   M(23,0),	M_MASK,		PPCCOM,		{ RA,RS,RB,MBE,ME } },
+{ "rlnm",    M(23,0),	M_MASK,		PWRCOM,		{ RA,RS,RB,MBE,ME } },
+{ "rotlw.",  MME(23,31,1), MMBME_MASK,	PPCCOM,		{ RA, RS, RB } },
+{ "rlwnm.",  M(23,1),	M_MASK,		PPCCOM,		{ RA,RS,RB,MBE,ME } },
+{ "rlnm.",   M(23,1),	M_MASK,		PWRCOM,		{ RA,RS,RB,MBE,ME } },
+
+{ "nop",     OP(24),	0xffffffff,	PPCCOM,		{ 0 } },
+{ "ori",     OP(24),	OP_MASK,	PPCCOM,		{ RA, RS, UI } },
+{ "oril",    OP(24),	OP_MASK,	PWRCOM,		{ RA, RS, UI } },
+
+{ "oris",    OP(25),	OP_MASK,	PPCCOM,		{ RA, RS, UI } },
+{ "oriu",    OP(25),	OP_MASK,	PWRCOM,		{ RA, RS, UI } },
+
+{ "xori",    OP(26),	OP_MASK,	PPCCOM,		{ RA, RS, UI } },
+{ "xoril",   OP(26),	OP_MASK,	PWRCOM,		{ RA, RS, UI } },
+
+{ "xoris",   OP(27),	OP_MASK,	PPCCOM,		{ RA, RS, UI } },
+{ "xoriu",   OP(27),	OP_MASK,	PWRCOM,		{ RA, RS, UI } },
+
+{ "andi.",   OP(28),	OP_MASK,	PPCCOM,		{ RA, RS, UI } },
+{ "andil.",  OP(28),	OP_MASK,	PWRCOM,		{ RA, RS, UI } },
+
+{ "andis.",  OP(29),	OP_MASK,	PPCCOM,		{ RA, RS, UI } },
+{ "andiu.",  OP(29),	OP_MASK,	PWRCOM,		{ RA, RS, UI } },
+
+{ "rotldi",  MD(30,0,0), MDMB_MASK,	PPC64,		{ RA, RS, SH6 } },
+{ "clrldi",  MD(30,0,0), MDSH_MASK,	PPC64,		{ RA, RS, MB6 } },
+{ "rldicl",  MD(30,0,0), MD_MASK,	PPC64,		{ RA, RS, SH6, MB6 } },
+{ "rotldi.", MD(30,0,1), MDMB_MASK,	PPC64,		{ RA, RS, SH6 } },
+{ "clrldi.", MD(30,0,1), MDSH_MASK,	PPC64,		{ RA, RS, MB6 } },
+{ "rldicl.", MD(30,0,1), MD_MASK,	PPC64,		{ RA, RS, SH6, MB6 } },
+
+{ "rldicr",  MD(30,1,0), MD_MASK,	PPC64,		{ RA, RS, SH6, ME6 } },
+{ "rldicr.", MD(30,1,1), MD_MASK,	PPC64,		{ RA, RS, SH6, ME6 } },
+
+{ "rldic",   MD(30,2,0), MD_MASK,	PPC64,		{ RA, RS, SH6, MB6 } },
+{ "rldic.",  MD(30,2,1), MD_MASK,	PPC64,		{ RA, RS, SH6, MB6 } },
+
+{ "rldimi",  MD(30,3,0), MD_MASK,	PPC64,		{ RA, RS, SH6, MB6 } },
+{ "rldimi.", MD(30,3,1), MD_MASK,	PPC64,		{ RA, RS, SH6, MB6 } },
+
+{ "rotld",   MDS(30,8,0), MDSMB_MASK,	PPC64,		{ RA, RS, RB } },
+{ "rldcl",   MDS(30,8,0), MDS_MASK,	PPC64,		{ RA, RS, RB, MB6 } },
+{ "rotld.",  MDS(30,8,1), MDSMB_MASK,	PPC64,		{ RA, RS, RB } },
+{ "rldcl.",  MDS(30,8,1), MDS_MASK,	PPC64,		{ RA, RS, RB, MB6 } },
+
+{ "rldcr",   MDS(30,9,0), MDS_MASK,	PPC64,		{ RA, RS, RB, ME6 } },
+{ "rldcr.",  MDS(30,9,1), MDS_MASK,	PPC64,		{ RA, RS, RB, ME6 } },
+
+{ "cmpw",    XCMPL(31,0,0), XCMPL_MASK, PPCCOM,		{ OBF, RA, RB } },
+{ "cmpd",    XCMPL(31,0,1), XCMPL_MASK, PPC64,		{ OBF, RA, RB } },
+{ "cmp",     X(31,0),	XCMP_MASK,	PPCONLY,	{ BF, L, RA, RB } },
+{ "cmp",     X(31,0),	XCMPL_MASK,	PWRCOM,		{ BF, RA, RB } },
+
+{ "twlgt",   XTO(31,4,TOLGT), XTO_MASK, PPCCOM,		{ RA, RB } },
+{ "tlgt",    XTO(31,4,TOLGT), XTO_MASK, PWRCOM,		{ RA, RB } },
+{ "twllt",   XTO(31,4,TOLLT), XTO_MASK, PPCCOM,		{ RA, RB } },
+{ "tllt",    XTO(31,4,TOLLT), XTO_MASK, PWRCOM,		{ RA, RB } },
+{ "tweq",    XTO(31,4,TOEQ), XTO_MASK,	PPCCOM,		{ RA, RB } },
+{ "teq",     XTO(31,4,TOEQ), XTO_MASK,	PWRCOM,		{ RA, RB } },
+{ "twlge",   XTO(31,4,TOLGE), XTO_MASK, PPCCOM,		{ RA, RB } },
+{ "tlge",    XTO(31,4,TOLGE), XTO_MASK, PWRCOM,		{ RA, RB } },
+{ "twlnl",   XTO(31,4,TOLNL), XTO_MASK, PPCCOM,		{ RA, RB } },
+{ "tlnl",    XTO(31,4,TOLNL), XTO_MASK, PWRCOM,		{ RA, RB } },
+{ "twlle",   XTO(31,4,TOLLE), XTO_MASK, PPCCOM,		{ RA, RB } },
+{ "tlle",    XTO(31,4,TOLLE), XTO_MASK, PWRCOM,		{ RA, RB } },
+{ "twlng",   XTO(31,4,TOLNG), XTO_MASK, PPCCOM,		{ RA, RB } },
+{ "tlng",    XTO(31,4,TOLNG), XTO_MASK, PWRCOM,		{ RA, RB } },
+{ "twgt",    XTO(31,4,TOGT), XTO_MASK,	PPCCOM,		{ RA, RB } },
+{ "tgt",     XTO(31,4,TOGT), XTO_MASK,	PWRCOM,		{ RA, RB } },
+{ "twge",    XTO(31,4,TOGE), XTO_MASK,	PPCCOM,		{ RA, RB } },
+{ "tge",     XTO(31,4,TOGE), XTO_MASK,	PWRCOM,		{ RA, RB } },
+{ "twnl",    XTO(31,4,TONL), XTO_MASK,	PPCCOM,		{ RA, RB } },
+{ "tnl",     XTO(31,4,TONL), XTO_MASK,	PWRCOM,		{ RA, RB } },
+{ "twlt",    XTO(31,4,TOLT), XTO_MASK,	PPCCOM,		{ RA, RB } },
+{ "tlt",     XTO(31,4,TOLT), XTO_MASK,	PWRCOM,		{ RA, RB } },
+{ "twle",    XTO(31,4,TOLE), XTO_MASK,	PPCCOM,		{ RA, RB } },
+{ "tle",     XTO(31,4,TOLE), XTO_MASK,	PWRCOM,		{ RA, RB } },
+{ "twng",    XTO(31,4,TONG), XTO_MASK,	PPCCOM,		{ RA, RB } },
+{ "tng",     XTO(31,4,TONG), XTO_MASK,	PWRCOM,		{ RA, RB } },
+{ "twne",    XTO(31,4,TONE), XTO_MASK,	PPCCOM,		{ RA, RB } },
+{ "tne",     XTO(31,4,TONE), XTO_MASK,	PWRCOM,		{ RA, RB } },
+{ "trap",    XTO(31,4,TOU), 0xffffffff,	PPCCOM,		{ 0 } },
+{ "tw",      X(31,4),	X_MASK,		PPCCOM,		{ TO, RA, RB } },
+{ "t",       X(31,4),	X_MASK,		PWRCOM,		{ TO, RA, RB } },
+
+{ "subfc",   XO(31,8,0,0), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "sf",      XO(31,8,0,0), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "subc",    XO(31,8,0,0), XO_MASK,	PPC,		{ RT, RB, RA } },
+{ "subfc.",  XO(31,8,0,1), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "sf.",     XO(31,8,0,1), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "subc.",   XO(31,8,0,1), XO_MASK,	PPCCOM,		{ RT, RB, RA } },
+{ "subfco",  XO(31,8,1,0), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "sfo",     XO(31,8,1,0), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "subco",   XO(31,8,1,0), XO_MASK,	PPC,		{ RT, RB, RA } },
+{ "subfco.", XO(31,8,1,1), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "sfo.",    XO(31,8,1,1), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "subco.",  XO(31,8,1,1), XO_MASK,	PPC,		{ RT, RB, RA } },
+
+{ "mulhdu",  XO(31,9,0,0), XO_MASK,	PPC64,		{ RT, RA, RB } },
+{ "mulhdu.", XO(31,9,0,1), XO_MASK,	PPC64,		{ RT, RA, RB } },
+
+{ "addc",    XO(31,10,0,0), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "a",       XO(31,10,0,0), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "addc.",   XO(31,10,0,1), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "a.",      XO(31,10,0,1), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "addco",   XO(31,10,1,0), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "ao",      XO(31,10,1,0), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "addco.",  XO(31,10,1,1), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "ao.",     XO(31,10,1,1), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+
+{ "mulhwu",  XO(31,11,0,0), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "mulhwu.", XO(31,11,0,1), XO_MASK,	PPC,		{ RT, RA, RB } },
+
+{ "mfcr",    X(31,19),	XRARB_MASK,	COM,		{ RT } },
+
+{ "lwarx",   X(31,20),	X_MASK,		PPC,		{ RT, RA, RB } },
+
+{ "ldx",     X(31,21),	X_MASK,		PPC64,		{ RT, RA, RB } },
+
+{ "lwzx",    X(31,23),	X_MASK,		PPCCOM,		{ RT, RA, RB } },
+{ "lx",      X(31,23),	X_MASK,		PWRCOM,		{ RT, RA, RB } },
+
+{ "slw",     XRC(31,24,0), X_MASK,	PPCCOM,		{ RA, RS, RB } },
+{ "sl",      XRC(31,24,0), X_MASK,	PWRCOM,		{ RA, RS, RB } },
+{ "slw.",    XRC(31,24,1), X_MASK,	PPCCOM,		{ RA, RS, RB } },
+{ "sl.",     XRC(31,24,1), X_MASK,	PWRCOM,		{ RA, RS, RB } },
+
+{ "cntlzw",  XRC(31,26,0), XRB_MASK,	PPCCOM,		{ RA, RS } },
+{ "cntlz",   XRC(31,26,0), XRB_MASK,	PWRCOM,		{ RA, RS } },
+{ "cntlzw.", XRC(31,26,1), XRB_MASK,	PPCCOM,		{ RA, RS } },
+{ "cntlz.",  XRC(31,26,1), XRB_MASK, 	PWRCOM,		{ RA, RS } },
+
+{ "sld",     XRC(31,27,0), X_MASK,	PPC64,		{ RA, RS, RB } },
+{ "sld.",    XRC(31,27,1), X_MASK,	PPC64,		{ RA, RS, RB } },
+
+{ "and",     XRC(31,28,0), X_MASK,	COM,		{ RA, RS, RB } },
+{ "and.",    XRC(31,28,1), X_MASK,	COM,		{ RA, RS, RB } },
+
+{ "maskg",   XRC(31,29,0), X_MASK,	M601,		{ RA, RS, RB } },
+{ "maskg.",  XRC(31,29,1), X_MASK,	M601,		{ RA, RS, RB } },
+
+{ "cmplw",   XCMPL(31,32,0), XCMPL_MASK, PPCCOM,	{ OBF, RA, RB } },
+{ "cmpld",   XCMPL(31,32,1), XCMPL_MASK, PPC64,		{ OBF, RA, RB } },
+{ "cmpl",    X(31,32),	XCMP_MASK,	 PPCONLY,	{ BF, L, RA, RB } },
+{ "cmpl",    X(31,32),	XCMPL_MASK,	 PWRCOM,	{ BF, RA, RB } },
+
+{ "subf",    XO(31,40,0,0), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "sub",     XO(31,40,0,0), XO_MASK,	PPC,		{ RT, RB, RA } },
+{ "subf.",   XO(31,40,0,1), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "sub.",    XO(31,40,0,1), XO_MASK,	PPC,		{ RT, RB, RA } },
+{ "subfo",   XO(31,40,1,0), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "subo",    XO(31,40,1,0), XO_MASK,	PPC,		{ RT, RB, RA } },
+{ "subfo.",  XO(31,40,1,1), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "subo.",   XO(31,40,1,1), XO_MASK,	PPC,		{ RT, RB, RA } },
+
+{ "ldux",    X(31,53),	X_MASK,		PPC64,		{ RT, RAL, RB } },
+
+{ "dcbst",   X(31,54),	XRT_MASK,	PPC,		{ RA, RB } },
+
+{ "lwzux",   X(31,55),	X_MASK,		PPCCOM,		{ RT, RAL, RB } },
+{ "lux",     X(31,55),	X_MASK,		PWRCOM,		{ RT, RA, RB } },
+
+{ "cntlzd",  XRC(31,58,0), XRB_MASK,	PPC64,		{ RA, RS } },
+{ "cntlzd.", XRC(31,58,1), XRB_MASK,	PPC64,		{ RA, RS } },
+
+{ "andc",    XRC(31,60,0), X_MASK,	COM,	{ RA, RS, RB } },
+{ "andc.",   XRC(31,60,1), X_MASK,	COM,	{ RA, RS, RB } },
+
+{ "tdlgt",   XTO(31,68,TOLGT), XTO_MASK, PPC64,		{ RA, RB } },
+{ "tdllt",   XTO(31,68,TOLLT), XTO_MASK, PPC64,		{ RA, RB } },
+{ "tdeq",    XTO(31,68,TOEQ), XTO_MASK,  PPC64,		{ RA, RB } },
+{ "tdlge",   XTO(31,68,TOLGE), XTO_MASK, PPC64,		{ RA, RB } },
+{ "tdlnl",   XTO(31,68,TOLNL), XTO_MASK, PPC64,		{ RA, RB } },
+{ "tdlle",   XTO(31,68,TOLLE), XTO_MASK, PPC64,		{ RA, RB } },
+{ "tdlng",   XTO(31,68,TOLNG), XTO_MASK, PPC64,		{ RA, RB } },
+{ "tdgt",    XTO(31,68,TOGT), XTO_MASK,  PPC64,		{ RA, RB } },
+{ "tdge",    XTO(31,68,TOGE), XTO_MASK,  PPC64,		{ RA, RB } },
+{ "tdnl",    XTO(31,68,TONL), XTO_MASK,  PPC64,		{ RA, RB } },
+{ "tdlt",    XTO(31,68,TOLT), XTO_MASK,  PPC64,		{ RA, RB } },
+{ "tdle",    XTO(31,68,TOLE), XTO_MASK,  PPC64,		{ RA, RB } },
+{ "tdng",    XTO(31,68,TONG), XTO_MASK,  PPC64,		{ RA, RB } },
+{ "tdne",    XTO(31,68,TONE), XTO_MASK,  PPC64,		{ RA, RB } },
+{ "td",	     X(31,68),	X_MASK,		 PPC64,		{ TO, RA, RB } },
+
+{ "mulhd",   XO(31,73,0,0), XO_MASK,	 PPC64,		{ RT, RA, RB } },
+{ "mulhd.",  XO(31,73,0,1), XO_MASK,	 PPC64,		{ RT, RA, RB } },
+
+{ "mulhw",   XO(31,75,0,0), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "mulhw.",  XO(31,75,0,1), XO_MASK,	PPC,		{ RT, RA, RB } },
+
+{ "mtsrd",   X(31,82),	XRB_MASK|(1<<20), PPC64,	{ SR, RS } },
+
+{ "mfmsr",   X(31,83),	XRARB_MASK,	COM,		{ RT } },
+
+{ "ldarx",   X(31,84),	X_MASK,		PPC64,		{ RT, RA, RB } },
+
+{ "dcbf",    X(31,86),	XRT_MASK,	PPC,		{ RA, RB } },
+
+{ "lbzx",    X(31,87),	X_MASK,		COM,		{ RT, RA, RB } },
+
+{ "neg",     XO(31,104,0,0), XORB_MASK,	COM,		{ RT, RA } },
+{ "neg.",    XO(31,104,0,1), XORB_MASK,	COM,		{ RT, RA } },
+{ "nego",    XO(31,104,1,0), XORB_MASK,	COM,		{ RT, RA } },
+{ "nego.",   XO(31,104,1,1), XORB_MASK,	COM,		{ RT, RA } },
+
+{ "mul",     XO(31,107,0,0), XO_MASK,	M601,		{ RT, RA, RB } },
+{ "mul.",    XO(31,107,0,1), XO_MASK,	M601,		{ RT, RA, RB } },
+{ "mulo",    XO(31,107,1,0), XO_MASK,	M601,		{ RT, RA, RB } },
+{ "mulo.",   XO(31,107,1,1), XO_MASK,	M601,		{ RT, RA, RB } },
+
+{ "mtsrdin", X(31,114),	XRA_MASK,	PPC64,		{ RS, RB } },
+
+{ "clf",     X(31,118), XRB_MASK,	POWER,		{ RT, RA } },
+
+{ "lbzux",   X(31,119),	X_MASK,		COM,		{ RT, RAL, RB } },
+
+{ "not",     XRC(31,124,0), X_MASK,	COM,		{ RA, RS, RBS } },
+{ "nor",     XRC(31,124,0), X_MASK,	COM,		{ RA, RS, RB } },
+{ "not.",    XRC(31,124,1), X_MASK,	COM,		{ RA, RS, RBS } },
+{ "nor.",    XRC(31,124,1), X_MASK,	COM,		{ RA, RS, RB } },
+
+{ "wrtee",   X(31,131),	XRARB_MASK,	PPC403,		{ RS } },
+
+{ "subfe",   XO(31,136,0,0), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "sfe",     XO(31,136,0,0), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "subfe.",  XO(31,136,0,1), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "sfe.",    XO(31,136,0,1), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "subfeo",  XO(31,136,1,0), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "sfeo",    XO(31,136,1,0), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "subfeo.", XO(31,136,1,1), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "sfeo.",   XO(31,136,1,1), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+
+{ "adde",    XO(31,138,0,0), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "ae",      XO(31,138,0,0), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "adde.",   XO(31,138,0,1), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "ae.",     XO(31,138,0,1), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "addeo",   XO(31,138,1,0), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "aeo",     XO(31,138,1,0), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "addeo.",  XO(31,138,1,1), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "aeo.",    XO(31,138,1,1), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+
+{ "mtcr",    XFXM(31,144,0xff), XFXFXM_MASK|FXM_MASK, COM,	{ RS }},
+{ "mtcrf",   X(31,144),	XFXFXM_MASK,	COM,		{ FXM, RS } },
+
+{ "mtmsr",   X(31,146),	XRARB_MASK,	COM,		{ RS } },
+
+{ "stdx",    X(31,149), X_MASK,		PPC64,		{ RS, RA, RB } },
+
+{ "stwcx.",  XRC(31,150,1), X_MASK,	PPC,		{ RS, RA, RB } },
+
+{ "stwx",    X(31,151), X_MASK,		PPCCOM,		{ RS, RA, RB } },
+{ "stx",     X(31,151), X_MASK,		PWRCOM,		{ RS, RA, RB } },
+
+{ "slq",     XRC(31,152,0), X_MASK,	M601,		{ RA, RS, RB } },
+{ "slq.",    XRC(31,152,1), X_MASK,	M601,		{ RA, RS, RB } },
+
+{ "sle",     XRC(31,153,0), X_MASK,	M601,		{ RA, RS, RB } },
+{ "sle.",    XRC(31,153,1), X_MASK,	M601,		{ RA, RS, RB } },
+
+{ "wrteei",  X(31,163),	XE_MASK,	PPC403,		{ E } },
+
+{ "mtmsrd",  X(31,178),	XRARB_MASK,	PPC64,		{ RS } },
+
+{ "stdux",   X(31,181),	X_MASK,		PPC64,		{ RS, RAS, RB } },
+
+{ "stwux",   X(31,183),	X_MASK,		PPCCOM,		{ RS, RAS, RB } },
+{ "stux",    X(31,183),	X_MASK,		PWRCOM,		{ RS, RA, RB } },
+
+{ "sliq",    XRC(31,184,0), X_MASK,	M601,		{ RA, RS, SH } },
+{ "sliq.",   XRC(31,184,1), X_MASK,	M601,		{ RA, RS, SH } },
+
+{ "subfze",  XO(31,200,0,0), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "sfze",    XO(31,200,0,0), XORB_MASK, PWRCOM,		{ RT, RA } },
+{ "subfze.", XO(31,200,0,1), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "sfze.",   XO(31,200,0,1), XORB_MASK, PWRCOM,		{ RT, RA } },
+{ "subfzeo", XO(31,200,1,0), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "sfzeo",   XO(31,200,1,0), XORB_MASK, PWRCOM,		{ RT, RA } },
+{ "subfzeo.",XO(31,200,1,1), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "sfzeo.",  XO(31,200,1,1), XORB_MASK, PWRCOM,		{ RT, RA } },
+
+{ "addze",   XO(31,202,0,0), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "aze",     XO(31,202,0,0), XORB_MASK, PWRCOM,		{ RT, RA } },
+{ "addze.",  XO(31,202,0,1), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "aze.",    XO(31,202,0,1), XORB_MASK, PWRCOM,		{ RT, RA } },
+{ "addzeo",  XO(31,202,1,0), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "azeo",    XO(31,202,1,0), XORB_MASK, PWRCOM,		{ RT, RA } },
+{ "addzeo.", XO(31,202,1,1), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "azeo.",   XO(31,202,1,1), XORB_MASK, PWRCOM,		{ RT, RA } },
+
+{ "mtsr",    X(31,210),	XRB_MASK|(1<<20), COM32,	{ SR, RS } },
+
+{ "stdcx.",  XRC(31,214,1), X_MASK,	PPC64,		{ RS, RA, RB } },
+
+{ "stbx",    X(31,215),	X_MASK,		COM,	{ RS, RA, RB } },
+
+{ "sllq",    XRC(31,216,0), X_MASK,	M601,		{ RA, RS, RB } },
+{ "sllq.",   XRC(31,216,1), X_MASK,	M601,		{ RA, RS, RB } },
+
+{ "sleq",    XRC(31,217,0), X_MASK,	M601,		{ RA, RS, RB } },
+{ "sleq.",   XRC(31,217,1), X_MASK,	M601,		{ RA, RS, RB } },
+
+{ "subfme",  XO(31,232,0,0), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "sfme",    XO(31,232,0,0), XORB_MASK, PWRCOM,		{ RT, RA } },
+{ "subfme.", XO(31,232,0,1), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "sfme.",   XO(31,232,0,1), XORB_MASK, PWRCOM,		{ RT, RA } },
+{ "subfmeo", XO(31,232,1,0), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "sfmeo",   XO(31,232,1,0), XORB_MASK, PWRCOM,		{ RT, RA } },
+{ "subfmeo.",XO(31,232,1,1), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "sfmeo.",  XO(31,232,1,1), XORB_MASK, PWRCOM,		{ RT, RA } },
+
+{ "mulld",   XO(31,233,0,0), XO_MASK,	PPC64,		{ RT, RA, RB } },
+{ "mulld.",  XO(31,233,0,1), XO_MASK,	PPC64,		{ RT, RA, RB } },
+{ "mulldo",  XO(31,233,1,0), XO_MASK,	PPC64,		{ RT, RA, RB } },
+{ "mulldo.", XO(31,233,1,1), XO_MASK,	PPC64,		{ RT, RA, RB } },
+
+{ "addme",   XO(31,234,0,0), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "ame",     XO(31,234,0,0), XORB_MASK, PWRCOM,		{ RT, RA } },
+{ "addme.",  XO(31,234,0,1), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "ame.",    XO(31,234,0,1), XORB_MASK, PWRCOM,		{ RT, RA } },
+{ "addmeo",  XO(31,234,1,0), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "ameo",    XO(31,234,1,0), XORB_MASK, PWRCOM,		{ RT, RA } },
+{ "addmeo.", XO(31,234,1,1), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "ameo.",   XO(31,234,1,1), XORB_MASK, PWRCOM,		{ RT, RA } },
+
+{ "mullw",   XO(31,235,0,0), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "muls",    XO(31,235,0,0), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "mullw.",  XO(31,235,0,1), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "muls.",   XO(31,235,0,1), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "mullwo",  XO(31,235,1,0), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "mulso",   XO(31,235,1,0), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "mullwo.", XO(31,235,1,1), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "mulso.",  XO(31,235,1,1), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+
+{ "mtsrin",  X(31,242),	XRA_MASK,	PPC32,		{ RS, RB } },
+{ "mtsri",   X(31,242),	XRA_MASK,	POWER32,	{ RS, RB } },
+
+{ "dcbtst",  X(31,246),	XRT_MASK,	PPC,		{ RA, RB } },
+
+{ "stbux",   X(31,247),	X_MASK,		COM,		{ RS, RAS, RB } },
+
+{ "slliq",   XRC(31,248,0), X_MASK,	M601,		{ RA, RS, SH } },
+{ "slliq.",  XRC(31,248,1), X_MASK,	M601,		{ RA, RS, SH } },
+
+{ "doz",     XO(31,264,0,0), XO_MASK,	M601,		{ RT, RA, RB } },
+{ "doz.",    XO(31,264,0,1), XO_MASK,	M601,		{ RT, RA, RB } },
+{ "dozo",    XO(31,264,1,0), XO_MASK,	M601,		{ RT, RA, RB } },
+{ "dozo.",   XO(31,264,1,1), XO_MASK,	M601,		{ RT, RA, RB } },
+
+{ "add",     XO(31,266,0,0), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "cax",     XO(31,266,0,0), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "add.",    XO(31,266,0,1), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "cax.",    XO(31,266,0,1), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "addo",    XO(31,266,1,0), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "caxo",    XO(31,266,1,0), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "addo.",   XO(31,266,1,1), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "caxo.",   XO(31,266,1,1), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+
+{ "lscbx",   XRC(31,277,0), X_MASK,	M601,		{ RT, RA, RB } },
+{ "lscbx.",  XRC(31,277,1), X_MASK,	M601,		{ RT, RA, RB } },
+
+{ "dcbt",    X(31,278),	XRT_MASK,	PPC,		{ RA, RB } },
+
+{ "lhzx",    X(31,279),	X_MASK,		COM,		{ RT, RA, RB } },
+
+{ "icbt",    X(31,262),	XRT_MASK,	PPC403,		{ RA, RB } },
+
+{ "eqv",     XRC(31,284,0), X_MASK,	COM,		{ RA, RS, RB } },
+{ "eqv.",    XRC(31,284,1), X_MASK,	COM,		{ RA, RS, RB } },
+
+{ "tlbie",   X(31,306),	XRTRA_MASK,	PPC,		{ RB } },
+{ "tlbi",    X(31,306),	XRT_MASK,	POWER,		{ RA, RB } },
+
+{ "eciwx",   X(31,310), X_MASK,		PPC,		{ RT, RA, RB } },
+
+{ "lhzux",   X(31,311),	X_MASK,		COM,		{ RT, RAL, RB } },
+
+{ "xor",     XRC(31,316,0), X_MASK,	COM,		{ RA, RS, RB } },
+{ "xor.",    XRC(31,316,1), X_MASK,	COM,		{ RA, RS, RB } },
+
+{ "mfexisr", XSPR(31,323,64), XSPR_MASK, PPC403,	{ RT } },
+{ "mfexier", XSPR(31,323,66), XSPR_MASK, PPC403,	{ RT } },
+{ "mfbr0",   XSPR(31,323,128), XSPR_MASK, PPC403,	{ RT } },
+{ "mfbr1",   XSPR(31,323,129), XSPR_MASK, PPC403,	{ RT } },
+{ "mfbr2",   XSPR(31,323,130), XSPR_MASK, PPC403,	{ RT } },
+{ "mfbr3",   XSPR(31,323,131), XSPR_MASK, PPC403,	{ RT } },
+{ "mfbr4",   XSPR(31,323,132), XSPR_MASK, PPC403,	{ RT } },
+{ "mfbr5",   XSPR(31,323,133), XSPR_MASK, PPC403,	{ RT } },
+{ "mfbr6",   XSPR(31,323,134), XSPR_MASK, PPC403,	{ RT } },
+{ "mfbr7",   XSPR(31,323,135), XSPR_MASK, PPC403,	{ RT } },
+{ "mfbear",  XSPR(31,323,144), XSPR_MASK, PPC403,	{ RT } },
+{ "mfbesr",  XSPR(31,323,145), XSPR_MASK, PPC403,	{ RT } },
+{ "mfiocr",  XSPR(31,323,160), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmacr0", XSPR(31,323,192), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmact0", XSPR(31,323,193), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmada0", XSPR(31,323,194), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmasa0", XSPR(31,323,195), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmacc0", XSPR(31,323,196), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmacr1", XSPR(31,323,200), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmact1", XSPR(31,323,201), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmada1", XSPR(31,323,202), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmasa1", XSPR(31,323,203), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmacc1", XSPR(31,323,204), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmacr2", XSPR(31,323,208), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmact2", XSPR(31,323,209), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmada2", XSPR(31,323,210), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmasa2", XSPR(31,323,211), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmacc2", XSPR(31,323,212), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmacr3", XSPR(31,323,216), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmact3", XSPR(31,323,217), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmada3", XSPR(31,323,218), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmasa3", XSPR(31,323,219), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmacc3", XSPR(31,323,220), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmasr", XSPR(31,323,224), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdcr",   X(31,323),	X_MASK,		PPC403,		{ RT, SPR } },
+
+{ "div",     XO(31,331,0,0), XO_MASK,	M601,		{ RT, RA, RB } },
+{ "div.",    XO(31,331,0,1), XO_MASK,	M601,		{ RT, RA, RB } },
+{ "divo",    XO(31,331,1,0), XO_MASK,	M601,		{ RT, RA, RB } },
+{ "divo.",   XO(31,331,1,1), XO_MASK,	M601,		{ RT, RA, RB } },
+
+{ "mfmq",     XSPR(31,339,0),   XSPR_MASK, M601,	{ RT } },
+{ "mfxer",    XSPR(31,339,1),   XSPR_MASK, COM,		{ RT } },
+{ "mfrtcu",   XSPR(31,339,4),   XSPR_MASK, COM,		{ RT } },
+{ "mfrtcl",   XSPR(31,339,5),   XSPR_MASK, COM,		{ RT } },
+{ "mfdec",    XSPR(31,339,6),   XSPR_MASK, MFDEC1,	{ RT } },
+{ "mflr",     XSPR(31,339,8),   XSPR_MASK, COM,		{ RT } },
+{ "mfctr",    XSPR(31,339,9),   XSPR_MASK, COM,		{ RT } },
+{ "mftid",    XSPR(31,339,17),  XSPR_MASK, POWER,	{ RT } },
+{ "mfdsisr",  XSPR(31,339,18),  XSPR_MASK, COM,		{ RT } },
+{ "mfdar",    XSPR(31,339,19),  XSPR_MASK, COM,		{ RT } },
+{ "mfdec",    XSPR(31,339,22),  XSPR_MASK, MFDEC2,	{ RT } },
+{ "mfsdr0",   XSPR(31,339,24),  XSPR_MASK, POWER,	{ RT } },
+{ "mfsdr1",   XSPR(31,339,25),  XSPR_MASK, COM,		{ RT } },
+{ "mfsrr0",   XSPR(31,339,26),  XSPR_MASK, COM,		{ RT } },
+{ "mfsrr1",   XSPR(31,339,27),  XSPR_MASK, COM,		{ RT } },
+{ "mfcmpa",   XSPR(31,339,144), XSPR_MASK, PPC860,	{ RT } },
+{ "mfcmpb",   XSPR(31,339,145), XSPR_MASK, PPC860,	{ RT } },
+{ "mfcmpc",   XSPR(31,339,146), XSPR_MASK, PPC860,	{ RT } },
+{ "mfcmpd",   XSPR(31,339,147), XSPR_MASK, PPC860,	{ RT } },
+{ "mficr",    XSPR(31,339,148), XSPR_MASK, PPC860,	{ RT } },
+{ "mfder",    XSPR(31,339,149), XSPR_MASK, PPC860,	{ RT } },
+{ "mfcounta", XSPR(31,339,150), XSPR_MASK, PPC860,	{ RT } },
+{ "mfcountb", XSPR(31,339,151), XSPR_MASK, PPC860,	{ RT } },
+{ "mfcmpe",   XSPR(31,339,152), XSPR_MASK, PPC860,	{ RT } },
+{ "mfcmpf",   XSPR(31,339,153), XSPR_MASK, PPC860,	{ RT } },
+{ "mfcmpg",   XSPR(31,339,154), XSPR_MASK, PPC860,	{ RT } },
+{ "mfcmph",   XSPR(31,339,155), XSPR_MASK, PPC860,	{ RT } },
+{ "mflctrl1", XSPR(31,339,156), XSPR_MASK, PPC860,	{ RT } },
+{ "mflctrl2", XSPR(31,339,157), XSPR_MASK, PPC860,	{ RT } },
+{ "mfictrl",  XSPR(31,339,158), XSPR_MASK, PPC860,	{ RT } },
+{ "mfbar",    XSPR(31,339,159), XSPR_MASK, PPC860,	{ RT } },
+{ "mfsprg4",  XSPR(31,339,260), XSPR_MASK, PPC405,	{ RT } },
+{ "mfsprg5",  XSPR(31,339,261), XSPR_MASK, PPC405,	{ RT } },
+{ "mfsprg6",  XSPR(31,339,262), XSPR_MASK, PPC405,	{ RT } },
+{ "mfsprg7",  XSPR(31,339,263), XSPR_MASK, PPC405,	{ RT } },
+{ "mfsprg",   XSPR(31,339,272), XSPRG_MASK, PPC,	{ RT, SPRG } },
+{ "mfsprg0",  XSPR(31,339,272), XSPR_MASK, PPC,		{ RT } },
+{ "mfsprg1",  XSPR(31,339,273), XSPR_MASK, PPC,		{ RT } },
+{ "mfsprg2",  XSPR(31,339,274), XSPR_MASK, PPC,		{ RT } },
+{ "mfsprg3",  XSPR(31,339,275), XSPR_MASK, PPC,		{ RT } },
+{ "mfasr",    XSPR(31,339,280), XSPR_MASK, PPC64,	{ RT } },
+{ "mfear",    XSPR(31,339,282), XSPR_MASK, PPC,		{ RT } },
+{ "mfpvr",    XSPR(31,339,287), XSPR_MASK, PPC,		{ RT } },
+{ "mfibatu",  XSPR(31,339,528), XSPRBAT_MASK, PPC,	{ RT, SPRBAT } },
+{ "mfibatl",  XSPR(31,339,529), XSPRBAT_MASK, PPC,	{ RT, SPRBAT } },
+{ "mfdbatu",  XSPR(31,339,536), XSPRBAT_MASK, PPC,	{ RT, SPRBAT } },
+{ "mfdbatl",  XSPR(31,339,537), XSPRBAT_MASK, PPC,	{ RT, SPRBAT } },
+{ "mfic_cst", XSPR(31,339,560), XSPR_MASK, PPC860,	{ RT } },
+{ "mfic_adr", XSPR(31,339,561), XSPR_MASK, PPC860,	{ RT } },
+{ "mfic_dat", XSPR(31,339,562), XSPR_MASK, PPC860,	{ RT } },
+{ "mfdc_cst", XSPR(31,339,568), XSPR_MASK, PPC860,	{ RT } },
+{ "mfdc_adr", XSPR(31,339,569), XSPR_MASK, PPC860,	{ RT } },
+{ "mfdc_dat", XSPR(31,339,570), XSPR_MASK, PPC860,	{ RT } },
+{ "mfdpdr",   XSPR(31,339,630), XSPR_MASK, PPC860,	{ RT } },
+{ "mfdpir",   XSPR(31,339,631), XSPR_MASK, PPC860,	{ RT } },
+{ "mfimmr",   XSPR(31,339,638), XSPR_MASK, PPC860,	{ RT } },
+{ "mfmi_ctr", XSPR(31,339,784), XSPR_MASK, PPC860,	{ RT } },
+{ "mfmi_ap",  XSPR(31,339,786), XSPR_MASK, PPC860,	{ RT } },
+{ "mfmi_epn", XSPR(31,339,787), XSPR_MASK, PPC860,	{ RT } },
+{ "mfmi_twc", XSPR(31,339,789), XSPR_MASK, PPC860,	{ RT } },
+{ "mfmi_rpn", XSPR(31,339,790), XSPR_MASK, PPC860,	{ RT } },
+{ "mfmd_ctr", XSPR(31,339,792), XSPR_MASK, PPC860,	{ RT } },
+{ "mfm_casid",XSPR(31,339,793), XSPR_MASK, PPC860,	{ RT } },
+{ "mfmd_ap",  XSPR(31,339,794), XSPR_MASK, PPC860,	{ RT } },
+{ "mfmd_epn", XSPR(31,339,795), XSPR_MASK, PPC860,	{ RT } },
+{ "mfmd_twb", XSPR(31,339,796), XSPR_MASK, PPC860,	{ RT } },
+{ "mfmd_twc", XSPR(31,339,797), XSPR_MASK, PPC860,	{ RT } },
+{ "mfmd_rpn", XSPR(31,339,798), XSPR_MASK, PPC860,	{ RT } },
+{ "mfm_tw",   XSPR(31,339,799), XSPR_MASK, PPC860,	{ RT } },
+{ "mfmi_dbcam",XSPR(31,339,816), XSPR_MASK, PPC860,	{ RT } },
+{ "mfmi_dbram0",XSPR(31,339,817), XSPR_MASK, PPC860,	{ RT } },
+{ "mfmi_dbram1",XSPR(31,339,818), XSPR_MASK, PPC860,	{ RT } },
+{ "mfmd_dbcam", XSPR(31,339,824), XSPR_MASK, PPC860,	{ RT } },
+{ "mfmd_dbram0",XSPR(31,339,825), XSPR_MASK, PPC860,	{ RT } },
+{ "mfmd_dbram1",XSPR(31,339,826), XSPR_MASK, PPC860,	{ RT } },
+{ "mfzpr",   	XSPR(31,339,944), XSPR_MASK, PPC403,	{ RT } },
+{ "mfpid",   	XSPR(31,339,945), XSPR_MASK, PPC403,	{ RT } },
+{ "mfccr0",  	XSPR(31,339,947), XSPR_MASK, PPC405,	{ RT } },
+{ "mficdbdr",	XSPR(31,339,979), XSPR_MASK, PPC403,	{ RT } },
+{ "mfummcr0",	XSPR(31,339,936),  XSPR_MASK, PPC750,	{ RT } },
+{ "mfupmc1",	XSPR(31,339,937),  XSPR_MASK, PPC750,	{ RT } },
+{ "mfupmc2",	XSPR(31,339,938),  XSPR_MASK, PPC750,	{ RT } },
+{ "mfusia",	XSPR(31,339,939),  XSPR_MASK, PPC750,	{ RT } },
+{ "mfummcr1",	XSPR(31,339,940),  XSPR_MASK, PPC750,	{ RT } },
+{ "mfupmc3",	XSPR(31,339,941),  XSPR_MASK, PPC750,	{ RT } },
+{ "mfupmc4",	XSPR(31,339,942),  XSPR_MASK, PPC750,	{ RT } },
+{ "mfiac3",     XSPR(31,339,948),  XSPR_MASK, PPC405,	{ RT } },
+{ "mfiac4",     XSPR(31,339,949),  XSPR_MASK, PPC405,	{ RT } },
+{ "mfdvc1",     XSPR(31,339,950),  XSPR_MASK, PPC405,	{ RT } },
+{ "mfdvc2",     XSPR(31,339,951),  XSPR_MASK, PPC405,	{ RT } },
+{ "mfmmcr0",	XSPR(31,339,952),  XSPR_MASK, PPC750,	{ RT } },
+{ "mfpmc1",	XSPR(31,339,953),  XSPR_MASK, PPC750,	{ RT } },
+{ "mfsgr",	XSPR(31,339,953),  XSPR_MASK, PPC403,	{ RT } },
+{ "mfpmc2",	XSPR(31,339,954),  XSPR_MASK, PPC750,	{ RT } },
+{ "mfdcwr", 	XSPR(31,339,954),  XSPR_MASK, PPC403,	{ RT } },
+{ "mfsia",	XSPR(31,339,955),  XSPR_MASK, PPC750,	{ RT } },
+{ "mfsler",	XSPR(31,339,955),  XSPR_MASK, PPC405,	{ RT } },
+{ "mfmmcr1",	XSPR(31,339,956),  XSPR_MASK, PPC750,	{ RT } },
+{ "mfsu0r",	XSPR(31,339,956),  XSPR_MASK, PPC405,	{ RT } },
+{ "mfpmc3",	XSPR(31,339,957),  XSPR_MASK, PPC750,	{ RT } },
+{ "mfdbcr1", 	XSPR(31,339,957),  XSPR_MASK, PPC405,	{ RT } },
+{ "mfpmc4",	XSPR(31,339,958),  XSPR_MASK, PPC750,	{ RT } },
+{ "mfesr",   XSPR(31,339,980), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdear",  XSPR(31,339,981), XSPR_MASK, PPC403,	{ RT } },
+{ "mfevpr",  XSPR(31,339,982), XSPR_MASK, PPC403,	{ RT } },
+{ "mfcdbcr", XSPR(31,339,983), XSPR_MASK, PPC403,	{ RT } },
+{ "mftsr",   XSPR(31,339,984), XSPR_MASK, PPC403,	{ RT } },
+{ "mftcr",   XSPR(31,339,986), XSPR_MASK, PPC403,	{ RT } },
+{ "mfpit",   XSPR(31,339,987), XSPR_MASK, PPC403,	{ RT } },
+{ "mftbhi",  XSPR(31,339,988), XSPR_MASK, PPC403,	{ RT } },
+{ "mftblo",  XSPR(31,339,989), XSPR_MASK, PPC403,	{ RT } },
+{ "mfsrr2",  XSPR(31,339,990), XSPR_MASK, PPC403,	{ RT } },
+{ "mfsrr3",  XSPR(31,339,991), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdbsr",  XSPR(31,339,1008), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdbcr0", XSPR(31,339,1010), XSPR_MASK, PPC405,	{ RT } },
+{ "mfiac1",  XSPR(31,339,1012), XSPR_MASK, PPC403,	{ RT } },
+{ "mfiac2",  XSPR(31,339,1013), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdac1",  XSPR(31,339,1014), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdac2",  XSPR(31,339,1015), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdccr",  XSPR(31,339,1018), XSPR_MASK, PPC403,	{ RT } },
+{ "mficcr",  XSPR(31,339,1019), XSPR_MASK, PPC403,	{ RT } },
+{ "mfpbl1",  XSPR(31,339,1020), XSPR_MASK, PPC403,	{ RT } },
+{ "mfpbu1",  XSPR(31,339,1021), XSPR_MASK, PPC403,	{ RT } },
+{ "mfpbl2",  XSPR(31,339,1022), XSPR_MASK, PPC403,	{ RT } },
+{ "mfpbu2",  XSPR(31,339,1023), XSPR_MASK, PPC403,	{ RT } },
+{ "mfl2cr",	XSPR(31,339,1017), XSPR_MASK, PPC750,	{ RT } },
+{ "mfictc",	XSPR(31,339,1019), XSPR_MASK, PPC750,	{ RT } },
+{ "mfthrm1",	XSPR(31,339,1020), XSPR_MASK, PPC750,	{ RT } },
+{ "mfthrm2",	XSPR(31,339,1021), XSPR_MASK, PPC750,	{ RT } },
+{ "mfthrm3",	XSPR(31,339,1022), XSPR_MASK, PPC750,	{ RT } },
+{ "mfspr",   X(31,339),	X_MASK,		COM,		{ RT, SPR } },
+
+{ "lwax",    X(31,341),	X_MASK,		PPC64,		{ RT, RA, RB } },
+
+{ "lhax",    X(31,343),	X_MASK,		COM,		{ RT, RA, RB } },
+
+{ "dccci",   X(31,454),	XRT_MASK,	PPC403,		{ RA, RB } },
+
+{ "abs",     XO(31,360,0,0), XORB_MASK, M601,		{ RT, RA } },
+{ "abs.",    XO(31,360,0,1), XORB_MASK, M601,		{ RT, RA } },
+{ "abso",    XO(31,360,1,0), XORB_MASK, M601,		{ RT, RA } },
+{ "abso.",   XO(31,360,1,1), XORB_MASK, M601,		{ RT, RA } },
+
+{ "divs",    XO(31,363,0,0), XO_MASK,	M601,		{ RT, RA, RB } },
+{ "divs.",   XO(31,363,0,1), XO_MASK,	M601,		{ RT, RA, RB } },
+{ "divso",   XO(31,363,1,0), XO_MASK,	M601,		{ RT, RA, RB } },
+{ "divso.",  XO(31,363,1,1), XO_MASK,	M601,		{ RT, RA, RB } },
+
+{ "tlbia",   X(31,370),	0xffffffff,	PPC,		{ 0 } },
+
+{ "mftbl",   XSPR(31,371,268), XSPR_MASK, PPC,		{ RT } },
+{ "mftbu",   XSPR(31,371,269), XSPR_MASK, PPC,		{ RT } },
+{ "mftb",    X(31,371),	X_MASK,		PPC,		{ RT, TBR } },
+
+{ "lwaux",   X(31,373),	X_MASK,		PPC64,		{ RT, RAL, RB } },
+
+{ "lhaux",   X(31,375),	X_MASK,		COM,		{ RT, RAL, RB } },
+
+{ "sthx",    X(31,407),	X_MASK,		COM,		{ RS, RA, RB } },
+
+{ "lfqx",    X(31,791),	X_MASK,		POWER2,		{ FRT, RA, RB } },
+
+{ "lfqux",   X(31,823),	X_MASK,		POWER2,		{ FRT, RA, RB } },
+
+{ "stfqx",   X(31,919),	X_MASK,		POWER2,		{ FRS, RA, RB } },
+
+{ "stfqux",  X(31,951),	X_MASK,		POWER2,		{ FRS, RA, RB } },
+
+{ "orc",     XRC(31,412,0), X_MASK,	COM,		{ RA, RS, RB } },
+{ "orc.",    XRC(31,412,1), X_MASK,	COM,		{ RA, RS, RB } },
+
+{ "sradi",   XS(31,413,0), XS_MASK,	PPC64,		{ RA, RS, SH6 } },
+{ "sradi.",  XS(31,413,1), XS_MASK,	PPC64,		{ RA, RS, SH6 } },
+
+{ "slbie",   X(31,434),	XRTRA_MASK,	PPC64,		{ RB } },
+
+{ "ecowx",   X(31,438),	X_MASK,		PPC,		{ RT, RA, RB } },
+
+{ "sthux",   X(31,439),	X_MASK,		COM,		{ RS, RAS, RB } },
+
+{ "mr",	     XRC(31,444,0), X_MASK,	COM,		{ RA, RS, RBS } },
+{ "or",      XRC(31,444,0), X_MASK,	COM,		{ RA, RS, RB } },
+{ "mr.",     XRC(31,444,1), X_MASK,	COM,		{ RA, RS, RBS } },
+{ "or.",     XRC(31,444,1), X_MASK,	COM,		{ RA, RS, RB } },
+
+{ "mtexisr", XSPR(31,451,64), XSPR_MASK, PPC403,	{ RT } },
+{ "mtexier", XSPR(31,451,66), XSPR_MASK, PPC403,	{ RT } },
+{ "mtbr0",   XSPR(31,451,128), XSPR_MASK, PPC403,	{ RT } },
+{ "mtbr1",   XSPR(31,451,129), XSPR_MASK, PPC403,	{ RT } },
+{ "mtbr2",   XSPR(31,451,130), XSPR_MASK, PPC403,	{ RT } },
+{ "mtbr3",   XSPR(31,451,131), XSPR_MASK, PPC403,	{ RT } },
+{ "mtbr4",   XSPR(31,451,132), XSPR_MASK, PPC403,	{ RT } },
+{ "mtbr5",   XSPR(31,451,133), XSPR_MASK, PPC403,	{ RT } },
+{ "mtbr6",   XSPR(31,451,134), XSPR_MASK, PPC403,	{ RT } },
+{ "mtbr7",   XSPR(31,451,135), XSPR_MASK, PPC403,	{ RT } },
+{ "mtbear",  XSPR(31,451,144), XSPR_MASK, PPC403,	{ RT } },
+{ "mtbesr",  XSPR(31,451,145), XSPR_MASK, PPC403,	{ RT } },
+{ "mtiocr",  XSPR(31,451,160), XSPR_MASK, PPC403,	{ RT } },
+{ "mtdmacr0", XSPR(31,451,192), XSPR_MASK, PPC403,	{ RT } },
+{ "mtdmact0", XSPR(31,451,193), XSPR_MASK, PPC403,	{ RT } },
+{ "mtdmada0", XSPR(31,451,194), XSPR_MASK, PPC403,	{ RT } },
+{ "mtdmasa0", XSPR(31,451,195), XSPR_MASK, PPC403,	{ RT } },
+{ "mtdmacc0", XSPR(31,451,196), XSPR_MASK, PPC403,	{ RT } },
+{ "mtdmacr1", XSPR(31,451,200), XSPR_MASK, PPC403,	{ RT } },
+{ "mtdmact1", XSPR(31,451,201), XSPR_MASK, PPC403,	{ RT } },
+{ "mtdmada1", XSPR(31,451,202), XSPR_MASK, PPC403,	{ RT } },
+{ "mtdmasa1", XSPR(31,451,203), XSPR_MASK, PPC403,	{ RT } },
+{ "mtdmacc1", XSPR(31,451,204), XSPR_MASK, PPC403,	{ RT } },
+{ "mtdmacr2", XSPR(31,451,208), XSPR_MASK, PPC403,	{ RT } },
+{ "mtdmact2", XSPR(31,451,209), XSPR_MASK, PPC403,	{ RT } },
+{ "mtdmada2", XSPR(31,451,210), XSPR_MASK, PPC403,	{ RT } },
+{ "mtdmasa2", XSPR(31,451,211), XSPR_MASK, PPC403,	{ RT } },
+{ "mtdmacc2", XSPR(31,451,212), XSPR_MASK, PPC403,	{ RT } },
+{ "mtdmacr3", XSPR(31,451,216), XSPR_MASK, PPC403,	{ RT } },
+{ "mtdmact3", XSPR(31,451,217), XSPR_MASK, PPC403,	{ RT } },
+{ "mtdmada3", XSPR(31,451,218), XSPR_MASK, PPC403,	{ RT } },
+{ "mtdmasa3", XSPR(31,451,219), XSPR_MASK, PPC403,	{ RT } },
+{ "mtdmacc3", XSPR(31,451,220), XSPR_MASK, PPC403,	{ RT } },
+{ "mtdmasr", XSPR(31,451,224), XSPR_MASK, PPC403,	{ RT } },
+{ "mtummcr0",	XSPR(31,451,936),  XSPR_MASK, PPC750,	{ RT } },
+{ "mtupmc1",	XSPR(31,451,937),  XSPR_MASK, PPC750,	{ RT } },
+{ "mtupmc2",	XSPR(31,451,938),  XSPR_MASK, PPC750,	{ RT } },
+{ "mtusia",	XSPR(31,451,939),  XSPR_MASK, PPC750,	{ RT } },
+{ "mtummcr1",	XSPR(31,451,940),  XSPR_MASK, PPC750,	{ RT } },
+{ "mtupmc3",	XSPR(31,451,941),  XSPR_MASK, PPC750,	{ RT } },
+{ "mtupmc4",	XSPR(31,451,942),  XSPR_MASK, PPC750,	{ RT } },
+{ "mtmmcr0",	XSPR(31,451,952),  XSPR_MASK, PPC750,	{ RT } },
+{ "mtpmc1",	XSPR(31,451,953),  XSPR_MASK, PPC750,	{ RT } },
+{ "mtpmc2",	XSPR(31,451,954),  XSPR_MASK, PPC750,	{ RT } },
+{ "mtsia",	XSPR(31,451,955),  XSPR_MASK, PPC750,	{ RT } },
+{ "mtmmcr1",	XSPR(31,451,956),  XSPR_MASK, PPC750,	{ RT } },
+{ "mtpmc3",	XSPR(31,451,957),  XSPR_MASK, PPC750,	{ RT } },
+{ "mtpmc4",	XSPR(31,451,958),  XSPR_MASK, PPC750,	{ RT } },
+{ "mtl2cr",	XSPR(31,451,1017), XSPR_MASK, PPC750,	{ RT } },
+{ "mtictc",	XSPR(31,451,1019), XSPR_MASK, PPC750,	{ RT } },
+{ "mtthrm1",	XSPR(31,451,1020), XSPR_MASK, PPC750,	{ RT } },
+{ "mtthrm2",	XSPR(31,451,1021), XSPR_MASK, PPC750,	{ RT } },
+{ "mtthrm3",	XSPR(31,451,1022), XSPR_MASK, PPC750,	{ RT } },
+{ "mtdcr",   X(31,451),	X_MASK,		PPC403,		{ SPR, RS } },
+
+{ "divdu",   XO(31,457,0,0), XO_MASK,	PPC64,		{ RT, RA, RB } },
+{ "divdu.",  XO(31,457,0,1), XO_MASK,	PPC64,		{ RT, RA, RB } },
+{ "divduo",  XO(31,457,1,0), XO_MASK,	PPC64,		{ RT, RA, RB } },
+{ "divduo.", XO(31,457,1,1), XO_MASK,	PPC64,		{ RT, RA, RB } },
+
+{ "divwu",   XO(31,459,0,0), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "divwu.",  XO(31,459,0,1), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "divwuo",  XO(31,459,1,0), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "divwuo.", XO(31,459,1,1), XO_MASK,	PPC,		{ RT, RA, RB } },
+
+{ "mtmq",    XSPR(31,467,0),   XSPR_MASK,    M601,	{ RS } },
+{ "mtxer",   XSPR(31,467,1),   XSPR_MASK,    COM,	{ RS } },
+{ "mtlr",    XSPR(31,467,8),   XSPR_MASK,    COM,	{ RS } },
+{ "mtctr",   XSPR(31,467,9),   XSPR_MASK,    COM,	{ RS } },
+{ "mttid",   XSPR(31,467,17),  XSPR_MASK,    POWER,	{ RS } },
+{ "mtdsisr", XSPR(31,467,18),  XSPR_MASK,    COM,	{ RS } },
+{ "mtdar",   XSPR(31,467,19),  XSPR_MASK,    COM,	{ RS } },
+{ "mtrtcu",  XSPR(31,467,20),  XSPR_MASK,    COM,	{ RS } },
+{ "mtrtcl",  XSPR(31,467,21),  XSPR_MASK,    COM,	{ RS } },
+{ "mtdec",   XSPR(31,467,22),  XSPR_MASK,    COM,	{ RS } },
+{ "mtsdr0",  XSPR(31,467,24),  XSPR_MASK,    POWER,	{ RS } },
+{ "mtsdr1",  XSPR(31,467,25),  XSPR_MASK,    COM,	{ RS } },
+{ "mtsrr0",  XSPR(31,467,26),  XSPR_MASK,    COM,	{ RS } },
+{ "mtsrr1",  XSPR(31,467,27),  XSPR_MASK,    COM,	{ RS } },
+{ "mtcmpa",   XSPR(31,467,144), XSPR_MASK, PPC860,	{ RT } },
+{ "mtcmpb",   XSPR(31,467,145), XSPR_MASK, PPC860,	{ RT } },
+{ "mtcmpc",   XSPR(31,467,146), XSPR_MASK, PPC860,	{ RT } },
+{ "mtcmpd",   XSPR(31,467,147), XSPR_MASK, PPC860,	{ RT } },
+{ "mticr",    XSPR(31,467,148), XSPR_MASK, PPC860,	{ RT } },
+{ "mtder",    XSPR(31,467,149), XSPR_MASK, PPC860,	{ RT } },
+{ "mtcounta", XSPR(31,467,150), XSPR_MASK, PPC860,	{ RT } },
+{ "mtcountb", XSPR(31,467,151), XSPR_MASK, PPC860,	{ RT } },
+{ "mtcmpe",   XSPR(31,467,152), XSPR_MASK, PPC860,	{ RT } },
+{ "mtcmpf",   XSPR(31,467,153), XSPR_MASK, PPC860,	{ RT } },
+{ "mtcmpg",   XSPR(31,467,154), XSPR_MASK, PPC860,	{ RT } },
+{ "mtcmph",   XSPR(31,467,155), XSPR_MASK, PPC860,	{ RT } },
+{ "mtlctrl1", XSPR(31,467,156), XSPR_MASK, PPC860,	{ RT } },
+{ "mtlctrl2", XSPR(31,467,157), XSPR_MASK, PPC860,	{ RT } },
+{ "mtictrl",  XSPR(31,467,158), XSPR_MASK, PPC860,	{ RT } },
+{ "mtbar",    XSPR(31,467,159), XSPR_MASK, PPC860,	{ RT } },
+{ "mtsprg",  XSPR(31,467,272), XSPRG_MASK,   PPC,	{ SPRG, RS } },
+{ "mtsprg0", XSPR(31,467,272), XSPR_MASK,    PPC,	{ RT } },
+{ "mtsprg1", XSPR(31,467,273), XSPR_MASK,    PPC,	{ RT } },
+{ "mtsprg2", XSPR(31,467,274), XSPR_MASK,    PPC,	{ RT } },
+{ "mtsprg3", XSPR(31,467,275), XSPR_MASK,    PPC,	{ RT } },
+{ "mtsprg4", XSPR(31,467,276), XSPR_MASK,    PPC405,	{ RT } },
+{ "mtsprg5", XSPR(31,467,277), XSPR_MASK,    PPC405,	{ RT } },
+{ "mtsprg6", XSPR(31,467,278), XSPR_MASK,    PPC405,	{ RT } },
+{ "mtsprg7", XSPR(31,467,279), XSPR_MASK,    PPC405,	{ RT } },
+{ "mtasr",   XSPR(31,467,280), XSPR_MASK,    PPC64,	{ RS } },
+{ "mtear",   XSPR(31,467,282), XSPR_MASK,    PPC,	{ RS } },
+{ "mttbl",   XSPR(31,467,284), XSPR_MASK,    PPC,	{ RS } },
+{ "mttbu",   XSPR(31,467,285), XSPR_MASK,    PPC,	{ RS } },
+{ "mtibatu", XSPR(31,467,528), XSPRBAT_MASK, PPC,	{ SPRBAT, RS } },
+{ "mtibatl", XSPR(31,467,529), XSPRBAT_MASK, PPC,	{ SPRBAT, RS } },
+{ "mtdbatu", XSPR(31,467,536), XSPRBAT_MASK, PPC,	{ SPRBAT, RS } },
+{ "mtdbatl", XSPR(31,467,537), XSPRBAT_MASK, PPC,	{ SPRBAT, RS } },
+{ "mtzpr",   XSPR(31,467,944), XSPR_MASK, PPC403,	{ RT } },
+{ "mtpid",   XSPR(31,467,945), XSPR_MASK, PPC403,	{ RT } },
+{ "mtccr0",  XSPR(31,467,947), XSPR_MASK, PPC405,	{ RT } },
+{ "mtiac3",  XSPR(31,467,948), XSPR_MASK, PPC405,	{ RT } },
+{ "mtiac4",  XSPR(31,467,949), XSPR_MASK, PPC405,	{ RT } },
+{ "mtdvc1",  XSPR(31,467,950), XSPR_MASK, PPC405,	{ RT } },
+{ "mtdvc2",  XSPR(31,467,951), XSPR_MASK, PPC405,	{ RT } },
+{ "mtsgr",   XSPR(31,467,953), XSPR_MASK, PPC403,	{ RT } },
+{ "mtdcwr",  XSPR(31,467,954), XSPR_MASK, PPC403,	{ RT } },
+{ "mtsler",  XSPR(31,467,955), XSPR_MASK, PPC405,	{ RT } },
+{ "mtsu0r",  XSPR(31,467,956), XSPR_MASK, PPC405,	{ RT } },
+{ "mtdbcr1", XSPR(31,467,957), XSPR_MASK, PPC405,	{ RT } },
+{ "mticdbdr",XSPR(31,467,979), XSPR_MASK, PPC403,	{ RT } },
+{ "mtesr",   XSPR(31,467,980), XSPR_MASK, PPC403,	{ RT } },
+{ "mtdear",  XSPR(31,467,981), XSPR_MASK, PPC403,	{ RT } },
+{ "mtevpr",  XSPR(31,467,982), XSPR_MASK, PPC403,	{ RT } },
+{ "mtcdbcr", XSPR(31,467,983), XSPR_MASK, PPC403,	{ RT } },
+{ "mttsr",   XSPR(31,467,984), XSPR_MASK, PPC403,	{ RT } },
+{ "mttcr",   XSPR(31,467,986), XSPR_MASK, PPC403,	{ RT } },
+{ "mtpit",   XSPR(31,467,987), XSPR_MASK, PPC403,	{ RT } },
+{ "mttbhi",  XSPR(31,467,988), XSPR_MASK, PPC403,	{ RT } },
+{ "mttblo",  XSPR(31,467,989), XSPR_MASK, PPC403,	{ RT } },
+{ "mtsrr2",  XSPR(31,467,990), XSPR_MASK, PPC403,	{ RT } },
+{ "mtsrr3",  XSPR(31,467,991), XSPR_MASK, PPC403,	{ RT } },
+{ "mtdbsr",  XSPR(31,467,1008), XSPR_MASK, PPC403,	{ RT } },
+{ "mtdbcr0", XSPR(31,467,1010), XSPR_MASK, PPC405,	{ RT } },
+{ "mtiac1",  XSPR(31,467,1012), XSPR_MASK, PPC403,	{ RT } },
+{ "mtiac2",  XSPR(31,467,1013), XSPR_MASK, PPC403,	{ RT } },
+{ "mtdac1",  XSPR(31,467,1014), XSPR_MASK, PPC403,	{ RT } },
+{ "mtdac2",  XSPR(31,467,1015), XSPR_MASK, PPC403,	{ RT } },
+{ "mtdccr",  XSPR(31,467,1018), XSPR_MASK, PPC403,	{ RT } },
+{ "mticcr",  XSPR(31,467,1019), XSPR_MASK, PPC403,	{ RT } },
+{ "mtpbl1",  XSPR(31,467,1020), XSPR_MASK, PPC403,	{ RT } },
+{ "mtpbu1",  XSPR(31,467,1021), XSPR_MASK, PPC403,	{ RT } },
+{ "mtpbl2",  XSPR(31,467,1022), XSPR_MASK, PPC403,	{ RT } },
+{ "mtpbu2",  XSPR(31,467,1023), XSPR_MASK, PPC403,	{ RT } },
+{ "mtspr",   X(31,467),	       X_MASK,	     COM,	{ SPR, RS } },
+
+{ "dcbi",    X(31,470),	XRT_MASK,	PPC,		{ RA, RB } },
+
+{ "nand",    XRC(31,476,0), X_MASK,	COM,		{ RA, RS, RB } },
+{ "nand.",   XRC(31,476,1), X_MASK,	COM,		{ RA, RS, RB } },
+
+{ "dcread",  X(31,486),	X_MASK,		PPC403,		{ RT, RA, RB }},
+
+{ "nabs",    XO(31,488,0,0), XORB_MASK, M601,		{ RT, RA } },
+{ "nabs.",   XO(31,488,0,1), XORB_MASK, M601,		{ RT, RA } },
+{ "nabso",   XO(31,488,1,0), XORB_MASK, M601,		{ RT, RA } },
+{ "nabso.",  XO(31,488,1,1), XORB_MASK, M601,		{ RT, RA } },
+
+{ "divd",    XO(31,489,0,0), XO_MASK,	PPC64,		{ RT, RA, RB } },
+{ "divd.",   XO(31,489,0,1), XO_MASK,	PPC64,		{ RT, RA, RB } },
+{ "divdo",   XO(31,489,1,0), XO_MASK,	PPC64,		{ RT, RA, RB } },
+{ "divdo.",  XO(31,489,1,1), XO_MASK,	PPC64,		{ RT, RA, RB } },
+
+{ "divw",    XO(31,491,0,0), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "divw.",   XO(31,491,0,1), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "divwo",   XO(31,491,1,0), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "divwo.",  XO(31,491,1,1), XO_MASK,	PPC,		{ RT, RA, RB } },
+
+{ "slbia",   X(31,498),	0xffffffff,	PPC64,		{ 0 } },
+
+{ "cli",     X(31,502), XRB_MASK,	POWER,		{ RT, RA } },
+
+{ "mcrxr",   X(31,512),	XRARB_MASK|(3<<21), COM,	{ BF } },
+
+{ "clcs",    X(31,531), XRB_MASK,	M601,		{ RT, RA } },
+
+{ "lswx",    X(31,533),	X_MASK,		PPCCOM,		{ RT, RA, RB } },
+{ "lsx",     X(31,533),	X_MASK,		PWRCOM,		{ RT, RA, RB } },
+
+{ "lwbrx",   X(31,534),	X_MASK,		PPCCOM,		{ RT, RA, RB } },
+{ "lbrx",    X(31,534),	X_MASK,		PWRCOM,		{ RT, RA, RB } },
+
+{ "lfsx",    X(31,535),	X_MASK,		COM,		{ FRT, RA, RB } },
+
+{ "srw",     XRC(31,536,0), X_MASK,	PPCCOM,		{ RA, RS, RB } },
+{ "sr",      XRC(31,536,0), X_MASK,	PWRCOM,		{ RA, RS, RB } },
+{ "srw.",    XRC(31,536,1), X_MASK,	PPCCOM,		{ RA, RS, RB } },
+{ "sr.",     XRC(31,536,1), X_MASK,	PWRCOM,		{ RA, RS, RB } },
+
+{ "rrib",    XRC(31,537,0), X_MASK,	M601,		{ RA, RS, RB } },
+{ "rrib.",   XRC(31,537,1), X_MASK,	M601,		{ RA, RS, RB } },
+
+{ "srd",     XRC(31,539,0), X_MASK,	PPC64,		{ RA, RS, RB } },
+{ "srd.",    XRC(31,539,1), X_MASK,	PPC64,		{ RA, RS, RB } },
+
+{ "maskir",  XRC(31,541,0), X_MASK,	M601,		{ RA, RS, RB } },
+{ "maskir.", XRC(31,541,1), X_MASK,	M601,		{ RA, RS, RB } },
+
+{ "tlbsync", X(31,566),	0xffffffff,	PPC,		{ 0 } },
+
+{ "lfsux",   X(31,567),	X_MASK,		COM,		{ FRT, RAS, RB } },
+
+{ "mfsr",    X(31,595),	XRB_MASK|(1<<20), COM32,	{ RT, SR } },
+
+{ "lswi",    X(31,597),	X_MASK,		PPCCOM,		{ RT, RA, NB } },
+{ "lsi",     X(31,597),	X_MASK,		PWRCOM,		{ RT, RA, NB } },
+
+{ "sync",    X(31,598), 0xffffffff,	PPCCOM,		{ 0 } },
+{ "dcs",     X(31,598), 0xffffffff,	PWRCOM,		{ 0 } },
+
+{ "lfdx",    X(31,599), X_MASK,		COM,		{ FRT, RA, RB } },
+
+{ "mfsri",   X(31,627), X_MASK,		PWRCOM,		{ RT, RA, RB } },
+
+{ "dclst",   X(31,630), XRB_MASK,	PWRCOM,		{ RS, RA } },
+
+{ "lfdux",   X(31,631), X_MASK,		COM,		{ FRT, RAS, RB } },
+
+{ "mfsrin",  X(31,659), XRA_MASK,	PPC32,		{ RT, RB } },
+
+{ "stswx",   X(31,661), X_MASK,		PPCCOM,		{ RS, RA, RB } },
+{ "stsx",    X(31,661), X_MASK,		PWRCOM,		{ RS, RA, RB } },
+
+{ "stwbrx",  X(31,662), X_MASK,		PPCCOM,		{ RS, RA, RB } },
+{ "stbrx",   X(31,662), X_MASK,		PWRCOM,		{ RS, RA, RB } },
+
+{ "stfsx",   X(31,663), X_MASK,		COM,		{ FRS, RA, RB } },
+
+{ "srq",     XRC(31,664,0), X_MASK,	M601,		{ RA, RS, RB } },
+{ "srq.",    XRC(31,664,1), X_MASK,	M601,		{ RA, RS, RB } },
+
+{ "sre",     XRC(31,665,0), X_MASK,	M601,		{ RA, RS, RB } },
+{ "sre.",    XRC(31,665,1), X_MASK,	M601,		{ RA, RS, RB } },
+
+{ "stfsux",  X(31,695),	X_MASK,		COM,		{ FRS, RAS, RB } },
+
+{ "sriq",    XRC(31,696,0), X_MASK,	M601,		{ RA, RS, SH } },
+{ "sriq.",   XRC(31,696,1), X_MASK,	M601,		{ RA, RS, SH } },
+
+{ "stswi",   X(31,725),	X_MASK,		PPCCOM,		{ RS, RA, NB } },
+{ "stsi",    X(31,725),	X_MASK,		PWRCOM,		{ RS, RA, NB } },
+
+{ "stfdx",   X(31,727),	X_MASK,		COM,		{ FRS, RA, RB } },
+
+{ "srlq",    XRC(31,728,0), X_MASK,	M601,		{ RA, RS, RB } },
+{ "srlq.",   XRC(31,728,1), X_MASK,	M601,		{ RA, RS, RB } },
+
+{ "sreq",    XRC(31,729,0), X_MASK,	M601,		{ RA, RS, RB } },
+{ "sreq.",   XRC(31,729,1), X_MASK,	M601,		{ RA, RS, RB } },
+
+{ "dcba",    X(31,758),	XRT_MASK,	PPC405,		{ RA, RB } },
+
+{ "stfdux",  X(31,759),	X_MASK,		COM,		{ FRS, RAS, RB } },
+
+{ "srliq",   XRC(31,760,0), X_MASK,	M601,		{ RA, RS, SH } },
+{ "srliq.",  XRC(31,760,1), X_MASK,	M601,		{ RA, RS, SH } },
+
+{ "lhbrx",   X(31,790),	X_MASK,		COM,		{ RT, RA, RB } },
+
+{ "sraw",    XRC(31,792,0), X_MASK,	PPCCOM,		{ RA, RS, RB } },
+{ "sra",     XRC(31,792,0), X_MASK,	PWRCOM,		{ RA, RS, RB } },
+{ "sraw.",   XRC(31,792,1), X_MASK,	PPCCOM,		{ RA, RS, RB } },
+{ "sra.",    XRC(31,792,1), X_MASK,	PWRCOM,		{ RA, RS, RB } },
+
+{ "srad",    XRC(31,794,0), X_MASK,	PPC64,		{ RA, RS, RB } },
+{ "srad.",   XRC(31,794,1), X_MASK,	PPC64,		{ RA, RS, RB } },
+
+{ "rac",     X(31,818),	X_MASK,		PWRCOM,		{ RT, RA, RB } },
+
+{ "srawi",   XRC(31,824,0), X_MASK,	PPCCOM,		{ RA, RS, SH } },
+{ "srai",    XRC(31,824,0), X_MASK,	PWRCOM,		{ RA, RS, SH } },
+{ "srawi.",  XRC(31,824,1), X_MASK,	PPCCOM,		{ RA, RS, SH } },
+{ "srai.",   XRC(31,824,1), X_MASK,	PWRCOM,		{ RA, RS, SH } },
+
+{ "eieio",   X(31,854),	0xffffffff,	PPC,		{ 0 } },
+
+{ "tlbsx",   XRC(31,914,0), X_MASK, PPC403,	{ RT, RA, RB } },
+{ "tlbsx.",  XRC(31,914,1), X_MASK, PPC403,	{ RT, RA, RB } },
+
+{ "sthbrx",  X(31,918),	X_MASK,		COM,		{ RS, RA, RB } },
+
+{ "sraq",    XRC(31,920,0), X_MASK,	M601,		{ RA, RS, RB } },
+{ "sraq.",   XRC(31,920,1), X_MASK,	M601,		{ RA, RS, RB } },
+
+{ "srea",    XRC(31,921,0), X_MASK,	M601,		{ RA, RS, RB } },
+{ "srea.",   XRC(31,921,1), X_MASK,	M601,		{ RA, RS, RB } },
+
+{ "extsh",   XRC(31,922,0), XRB_MASK,	PPCCOM,		{ RA, RS } },
+{ "exts",    XRC(31,922,0), XRB_MASK,	PWRCOM,		{ RA, RS } },
+{ "extsh.",  XRC(31,922,1), XRB_MASK,	PPCCOM,		{ RA, RS } },
+{ "exts.",   XRC(31,922,1), XRB_MASK,	PWRCOM,		{ RA, RS } },
+
+{ "tlbrehi", XTLB(31,946,0), XTLB_MASK,	PPC403,		{ RT, RA } },
+{ "tlbrelo", XTLB(31,946,1), XTLB_MASK,	PPC403,		{ RT, RA } },
+{ "tlbre",   X(31,946),	X_MASK,		PPC403,		{ RT, RA, SH } },
+
+{ "sraiq",   XRC(31,952,0), X_MASK,	M601,		{ RA, RS, SH } },
+{ "sraiq.",  XRC(31,952,1), X_MASK,	M601,		{ RA, RS, SH } },
+
+{ "extsb",   XRC(31,954,0), XRB_MASK,	PPC,		{ RA, RS} },
+{ "extsb.",  XRC(31,954,1), XRB_MASK,	PPC,		{ RA, RS} },
+
+{ "iccci",   X(31,966),	XRT_MASK,	PPC403,		{ RA, RB } },
+
+{ "tlbld",   X(31,978),	XRTRA_MASK,	PPC,		{ RB } },
+
+{ "tlbwehi", XTLB(31,978,0), XTLB_MASK,	PPC403,		{ RT, RA } },
+{ "tlbwelo", XTLB(31,978,1), XTLB_MASK,	PPC403,		{ RT, RA } },
+{ "tlbwe",   X(31,978),	X_MASK,		PPC403,		{ RS, RA, SH } },
+
+{ "icbi",    X(31,982),	XRT_MASK,	PPC,		{ RA, RB } },
+
+{ "stfiwx",  X(31,983),	X_MASK,		PPC,		{ FRS, RA, RB } },
+
+{ "extsw",   XRC(31,986,0), XRB_MASK,	PPC,		{ RA, RS } },
+{ "extsw.",  XRC(31,986,1), XRB_MASK,	PPC,		{ RA, RS } },
+
+{ "icread",  X(31,998),	XRT_MASK,	PPC403,		{ RA, RB } },
+
+{ "tlbli",   X(31,1010), XRTRA_MASK,	PPC,		{ RB } },
+
+{ "dcbz",    X(31,1014), XRT_MASK,	PPC,		{ RA, RB } },
+{ "dclz",    X(31,1014), XRT_MASK,	PPC,		{ RA, RB } },
+
+{ "lvebx",   X(31,   7), X_MASK,	PPCVEC,		{ VD, RA, RB } },
+{ "lvehx",   X(31,  39), X_MASK,	PPCVEC,		{ VD, RA, RB } },
+{ "lvewx",   X(31,  71), X_MASK,	PPCVEC,		{ VD, RA, RB } },
+{ "lvsl",    X(31,   6), X_MASK,	PPCVEC,		{ VD, RA, RB } },
+{ "lvsr",    X(31,  38), X_MASK,	PPCVEC,		{ VD, RA, RB } },
+{ "lvx",     X(31, 103), X_MASK,	PPCVEC,		{ VD, RA, RB } },
+{ "lvxl",    X(31, 359), X_MASK,	PPCVEC,		{ VD, RA, RB } },
+{ "stvebx",  X(31, 135), X_MASK,	PPCVEC,		{ VS, RA, RB } },
+{ "stvehx",  X(31, 167), X_MASK,	PPCVEC,		{ VS, RA, RB } },
+{ "stvewx",  X(31, 199), X_MASK,	PPCVEC,		{ VS, RA, RB } },
+{ "stvx",    X(31, 231), X_MASK,	PPCVEC,		{ VS, RA, RB } },
+{ "stvxl",   X(31, 487), X_MASK,	PPCVEC,		{ VS, RA, RB } },
+
+{ "lwz",     OP(32),	OP_MASK,	PPCCOM,		{ RT, D, RA } },
+{ "l",	     OP(32),	OP_MASK,	PWRCOM,		{ RT, D, RA } },
+
+{ "lwzu",    OP(33),	OP_MASK,	PPCCOM,		{ RT, D, RAL } },
+{ "lu",      OP(33),	OP_MASK,	PWRCOM,		{ RT, D, RA } },
+
+{ "lbz",     OP(34),	OP_MASK,	COM,		{ RT, D, RA } },
+
+{ "lbzu",    OP(35),	OP_MASK,	COM,		{ RT, D, RAL } },
+
+{ "stw",     OP(36),	OP_MASK,	PPCCOM,		{ RS, D, RA } },
+{ "st",      OP(36),	OP_MASK,	PWRCOM,		{ RS, D, RA } },
+
+{ "stwu",    OP(37),	OP_MASK,	PPCCOM,		{ RS, D, RAS } },
+{ "stu",     OP(37),	OP_MASK,	PWRCOM,		{ RS, D, RA } },
+
+{ "stb",     OP(38),	OP_MASK,	COM,		{ RS, D, RA } },
+
+{ "stbu",    OP(39),	OP_MASK,	COM,		{ RS, D, RAS } },
+
+{ "lhz",     OP(40),	OP_MASK,	COM,		{ RT, D, RA } },
+
+{ "lhzu",    OP(41),	OP_MASK,	COM,		{ RT, D, RAL } },
+
+{ "lha",     OP(42),	OP_MASK,	COM,		{ RT, D, RA } },
+
+{ "lhau",    OP(43),	OP_MASK,	COM,		{ RT, D, RAL } },
+
+{ "sth",     OP(44),	OP_MASK,	COM,		{ RS, D, RA } },
+
+{ "sthu",    OP(45),	OP_MASK,	COM,		{ RS, D, RAS } },
+
+{ "lmw",     OP(46),	OP_MASK,	PPCCOM,		{ RT, D, RAM } },
+{ "lm",      OP(46),	OP_MASK,	PWRCOM,		{ RT, D, RA } },
+
+{ "stmw",    OP(47),	OP_MASK,	PPCCOM,		{ RS, D, RA } },
+{ "stm",     OP(47),	OP_MASK,	PWRCOM,		{ RS, D, RA } },
+
+{ "lfs",     OP(48),	OP_MASK,	COM,		{ FRT, D, RA } },
+
+{ "lfsu",    OP(49),	OP_MASK,	COM,		{ FRT, D, RAS } },
+
+{ "lfd",     OP(50),	OP_MASK,	COM,		{ FRT, D, RA } },
+
+{ "lfdu",    OP(51),	OP_MASK,	COM,		{ FRT, D, RAS } },
+
+{ "stfs",    OP(52),	OP_MASK,	COM,		{ FRS, D, RA } },
+
+{ "stfsu",   OP(53),	OP_MASK,	COM,		{ FRS, D, RAS } },
+
+{ "stfd",    OP(54),	OP_MASK,	COM,		{ FRS, D, RA } },
+
+{ "stfdu",   OP(55),	OP_MASK,	COM,		{ FRS, D, RAS } },
+
+{ "lfq",     OP(56),	OP_MASK,	POWER2,		{ FRT, D, RA } },
+
+{ "lfqu",    OP(57),	OP_MASK,	POWER2,		{ FRT, D, RA } },
+
+{ "ld",      DSO(58,0),	DS_MASK,	PPC64,		{ RT, DS, RA } },
+
+{ "ldu",     DSO(58,1), DS_MASK,	PPC64,		{ RT, DS, RAL } },
+
+{ "lwa",     DSO(58,2), DS_MASK,	PPC64,		{ RT, DS, RA } },
+
+{ "fdivs",   A(59,18,0), AFRC_MASK,	PPC,		{ FRT, FRA, FRB } },
+{ "fdivs.",  A(59,18,1), AFRC_MASK,	PPC,		{ FRT, FRA, FRB } },
+
+{ "fsubs",   A(59,20,0), AFRC_MASK,	PPC,		{ FRT, FRA, FRB } },
+{ "fsubs.",  A(59,20,1), AFRC_MASK,	PPC,		{ FRT, FRA, FRB } },
+
+{ "fadds",   A(59,21,0), AFRC_MASK,	PPC,		{ FRT, FRA, FRB } },
+{ "fadds.",  A(59,21,1), AFRC_MASK,	PPC,		{ FRT, FRA, FRB } },
+
+{ "fsqrts",  A(59,22,0), AFRAFRC_MASK,	PPC,		{ FRT, FRB } },
+{ "fsqrts.", A(59,22,1), AFRAFRC_MASK,	PPC,		{ FRT, FRB } },
+
+{ "fres",    A(59,24,0), AFRAFRC_MASK,	PPC,		{ FRT, FRB } },
+{ "fres.",   A(59,24,1), AFRAFRC_MASK,	PPC,		{ FRT, FRB } },
+
+{ "fmuls",   A(59,25,0), AFRB_MASK,	PPC,		{ FRT, FRA, FRC } },
+{ "fmuls.",  A(59,25,1), AFRB_MASK,	PPC,		{ FRT, FRA, FRC } },
+
+{ "fmsubs",  A(59,28,0), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
+{ "fmsubs.", A(59,28,1), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
+
+{ "fmadds",  A(59,29,0), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
+{ "fmadds.", A(59,29,1), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
+
+{ "fnmsubs", A(59,30,0), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
+{ "fnmsubs.",A(59,30,1), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
+
+{ "fnmadds", A(59,31,0), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
+{ "fnmadds.",A(59,31,1), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
+
+{ "stfq",    OP(60),	OP_MASK,	POWER2,		{ FRS, D, RA } },
+
+{ "stfqu",   OP(61),	OP_MASK,	POWER2,		{ FRS, D, RA } },
+
+{ "std",     DSO(62,0),	DS_MASK,	PPC64,		{ RS, DS, RA } },
+
+{ "stdu",    DSO(62,1),	DS_MASK,	PPC64,		{ RS, DS, RAS } },
+
+{ "fcmpu",   X(63,0),	X_MASK|(3<<21),	COM,		{ BF, FRA, FRB } },
+
+{ "frsp",    XRC(63,12,0), XRA_MASK,	COM,		{ FRT, FRB } },
+{ "frsp.",   XRC(63,12,1), XRA_MASK,	COM,		{ FRT, FRB } },
+
+{ "fctiw",   XRC(63,14,0), XRA_MASK,	PPCCOM,		{ FRT, FRB } },
+{ "fcir",    XRC(63,14,0), XRA_MASK,	POWER2,		{ FRT, FRB } },
+{ "fctiw.",  XRC(63,14,1), XRA_MASK,	PPCCOM,		{ FRT, FRB } },
+{ "fcir.",   XRC(63,14,1), XRA_MASK,	POWER2,		{ FRT, FRB } },
+
+{ "fctiwz",  XRC(63,15,0), XRA_MASK,	PPCCOM,		{ FRT, FRB } },
+{ "fcirz",   XRC(63,15,0), XRA_MASK,	POWER2,		{ FRT, FRB } },
+{ "fctiwz.", XRC(63,15,1), XRA_MASK,	PPCCOM,		{ FRT, FRB } },
+{ "fcirz.",  XRC(63,15,1), XRA_MASK,	POWER2,		{ FRT, FRB } },
+
+{ "fdiv",    A(63,18,0), AFRC_MASK,	PPCCOM,		{ FRT, FRA, FRB } },
+{ "fd",      A(63,18,0), AFRC_MASK,	PWRCOM,		{ FRT, FRA, FRB } },
+{ "fdiv.",   A(63,18,1), AFRC_MASK,	PPCCOM,		{ FRT, FRA, FRB } },
+{ "fd.",     A(63,18,1), AFRC_MASK,	PWRCOM,		{ FRT, FRA, FRB } },
+
+{ "fsub",    A(63,20,0), AFRC_MASK,	PPCCOM,		{ FRT, FRA, FRB } },
+{ "fs",      A(63,20,0), AFRC_MASK,	PWRCOM,		{ FRT, FRA, FRB } },
+{ "fsub.",   A(63,20,1), AFRC_MASK,	PPCCOM,		{ FRT, FRA, FRB } },
+{ "fs.",     A(63,20,1), AFRC_MASK,	PWRCOM,		{ FRT, FRA, FRB } },
+
+{ "fadd",    A(63,21,0), AFRC_MASK,	PPCCOM,		{ FRT, FRA, FRB } },
+{ "fa",      A(63,21,0), AFRC_MASK,	PWRCOM,		{ FRT, FRA, FRB } },
+{ "fadd.",   A(63,21,1), AFRC_MASK,	PPCCOM,		{ FRT, FRA, FRB } },
+{ "fa.",     A(63,21,1), AFRC_MASK,	PWRCOM,		{ FRT, FRA, FRB } },
+
+{ "fsqrt",   A(63,22,0), AFRAFRC_MASK,	PPCPWR2,	{ FRT, FRB } },
+{ "fsqrt.",  A(63,22,1), AFRAFRC_MASK,	PPCPWR2,	{ FRT, FRB } },
+
+{ "fsel",    A(63,23,0), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
+{ "fsel.",   A(63,23,1), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
+
+{ "fmul",    A(63,25,0), AFRB_MASK,	PPCCOM,		{ FRT, FRA, FRC } },
+{ "fm",      A(63,25,0), AFRB_MASK,	PWRCOM,		{ FRT, FRA, FRC } },
+{ "fmul.",   A(63,25,1), AFRB_MASK,	PPCCOM,		{ FRT, FRA, FRC } },
+{ "fm.",     A(63,25,1), AFRB_MASK,	PWRCOM,		{ FRT, FRA, FRC } },
+
+{ "frsqrte", A(63,26,0), AFRAFRC_MASK,	PPC,		{ FRT, FRB } },
+{ "frsqrte.",A(63,26,1), AFRAFRC_MASK,	PPC,		{ FRT, FRB } },
+
+{ "fmsub",   A(63,28,0), A_MASK,	PPCCOM,		{ FRT,FRA,FRC,FRB } },
+{ "fms",     A(63,28,0), A_MASK,	PWRCOM,		{ FRT,FRA,FRC,FRB } },
+{ "fmsub.",  A(63,28,1), A_MASK,	PPCCOM,		{ FRT,FRA,FRC,FRB } },
+{ "fms.",    A(63,28,1), A_MASK,	PWRCOM,		{ FRT,FRA,FRC,FRB } },
+
+{ "fmadd",   A(63,29,0), A_MASK,	PPCCOM,		{ FRT,FRA,FRC,FRB } },
+{ "fma",     A(63,29,0), A_MASK,	PWRCOM,		{ FRT,FRA,FRC,FRB } },
+{ "fmadd.",  A(63,29,1), A_MASK,	PPCCOM,		{ FRT,FRA,FRC,FRB } },
+{ "fma.",    A(63,29,1), A_MASK,	PWRCOM,		{ FRT,FRA,FRC,FRB } },
+
+{ "fnmsub",  A(63,30,0), A_MASK,	PPCCOM,		{ FRT,FRA,FRC,FRB } },
+{ "fnms",    A(63,30,0), A_MASK,	PWRCOM,		{ FRT,FRA,FRC,FRB } },
+{ "fnmsub.", A(63,30,1), A_MASK,	PPCCOM,		{ FRT,FRA,FRC,FRB } },
+{ "fnms.",   A(63,30,1), A_MASK,	PWRCOM,		{ FRT,FRA,FRC,FRB } },
+
+{ "fnmadd",  A(63,31,0), A_MASK,	PPCCOM,		{ FRT,FRA,FRC,FRB } },
+{ "fnma",    A(63,31,0), A_MASK,	PWRCOM,		{ FRT,FRA,FRC,FRB } },
+{ "fnmadd.", A(63,31,1), A_MASK,	PPCCOM,		{ FRT,FRA,FRC,FRB } },
+{ "fnma.",   A(63,31,1), A_MASK,	PWRCOM,		{ FRT,FRA,FRC,FRB } },
+
+{ "fcmpo",   X(63,32),	X_MASK|(3<<21),	COM,		{ BF, FRA, FRB } },
+
+{ "mtfsb1",  XRC(63,38,0), XRARB_MASK,	COM,		{ BT } },
+{ "mtfsb1.", XRC(63,38,1), XRARB_MASK,	COM,		{ BT } },
+
+{ "fneg",    XRC(63,40,0), XRA_MASK,	COM,		{ FRT, FRB } },
+{ "fneg.",   XRC(63,40,1), XRA_MASK,	COM,		{ FRT, FRB } },
+
+{ "mcrfs",   X(63,64),	XRB_MASK|(3<<21)|(3<<16), COM,	{ BF, BFA } },
+
+{ "mtfsb0",  XRC(63,70,0), XRARB_MASK,	COM,		{ BT } },
+{ "mtfsb0.", XRC(63,70,1), XRARB_MASK,	COM,		{ BT } },
+
+{ "fmr",     XRC(63,72,0), XRA_MASK,	COM,		{ FRT, FRB } },
+{ "fmr.",    XRC(63,72,1), XRA_MASK,	COM,		{ FRT, FRB } },
+
+{ "mtfsfi",  XRC(63,134,0), XRA_MASK|(3<<21)|(1<<11), COM, { BF, U } },
+{ "mtfsfi.", XRC(63,134,1), XRA_MASK|(3<<21)|(1<<11), COM, { BF, U } },
+
+{ "fnabs",   XRC(63,136,0), XRA_MASK,	COM,		{ FRT, FRB } },
+{ "fnabs.",  XRC(63,136,1), XRA_MASK,	COM,		{ FRT, FRB } },
+
+{ "fabs",    XRC(63,264,0), XRA_MASK,	COM,		{ FRT, FRB } },
+{ "fabs.",   XRC(63,264,1), XRA_MASK,	COM,		{ FRT, FRB } },
+
+{ "mffs",    XRC(63,583,0), XRARB_MASK,	COM,		{ FRT } },
+{ "mffs.",   XRC(63,583,1), XRARB_MASK,	COM,		{ FRT } },
+
+{ "mtfsf",   XFL(63,711,0), XFL_MASK,	COM,		{ FLM, FRB } },
+{ "mtfsf.",  XFL(63,711,1), XFL_MASK,	COM,		{ FLM, FRB } },
+
+{ "fctid",   XRC(63,814,0), XRA_MASK,	PPC64,		{ FRT, FRB } },
+{ "fctid.",  XRC(63,814,1), XRA_MASK,	PPC64,		{ FRT, FRB } },
+
+{ "fctidz",  XRC(63,815,0), XRA_MASK,	PPC64,		{ FRT, FRB } },
+{ "fctidz.", XRC(63,815,1), XRA_MASK,	PPC64,		{ FRT, FRB } },
+
+{ "fcfid",   XRC(63,846,0), XRA_MASK,	PPC64,		{ FRT, FRB } },
+{ "fcfid.",  XRC(63,846,1), XRA_MASK,	PPC64,		{ FRT, FRB } },
+
+};
+
+const int powerpc_num_opcodes =
+  sizeof (powerpc_opcodes) / sizeof (powerpc_opcodes[0]);
+
+/* The macro table.  This is only used by the assembler.  */
+
+/* The expressions of the form (-x ! 31) & (x | 31) have the value 0
+   when x=0; 32-x when x is between 1 and 31; are negative if x is
+   negative; and are 32 or more otherwise.  This is what you want
+   when, for instance, you are emulating a right shift by a
+   rotate-left-and-mask, because the underlying instructions support
+   shifts of size 0 but not shifts of size 32.  By comparison, when
+   extracting x bits from some word you want to use just 32-x, because
+   the underlying instructions don't support extracting 0 bits but do
+   support extracting the whole word (32 bits in this case).  */
+
+const struct powerpc_macro powerpc_macros[] = {
+{ "extldi",  4,   PPC64,	"rldicr %0,%1,%3,(%2)-1" },
+{ "extldi.", 4,   PPC64,	"rldicr. %0,%1,%3,(%2)-1" },
+{ "extrdi",  4,   PPC64,	"rldicl %0,%1,(%2)+(%3),64-(%2)" },
+{ "extrdi.", 4,   PPC64,	"rldicl. %0,%1,(%2)+(%3),64-(%2)" },
+{ "insrdi",  4,   PPC64,	"rldimi %0,%1,64-((%2)+(%3)),%3" },
+{ "insrdi.", 4,   PPC64,	"rldimi. %0,%1,64-((%2)+(%3)),%3" },
+{ "rotrdi",  3,   PPC64,	"rldicl %0,%1,(-(%2)!63)&((%2)|63),0" },
+{ "rotrdi.", 3,   PPC64,	"rldicl. %0,%1,(-(%2)!63)&((%2)|63),0" },
+{ "sldi",    3,   PPC64,	"rldicr %0,%1,%2,63-(%2)" },
+{ "sldi.",   3,   PPC64,	"rldicr. %0,%1,%2,63-(%2)" },
+{ "srdi",    3,   PPC64,	"rldicl %0,%1,(-(%2)!63)&((%2)|63),%2" },
+{ "srdi.",   3,   PPC64,	"rldicl. %0,%1,(-(%2)!63)&((%2)|63),%2" },
+{ "clrrdi",  3,   PPC64,	"rldicr %0,%1,0,63-(%2)" },
+{ "clrrdi.", 3,   PPC64,	"rldicr. %0,%1,0,63-(%2)" },
+{ "clrlsldi",4,   PPC64,	"rldic %0,%1,%3,(%2)-(%3)" },
+{ "clrlsldi.",4,  PPC64,	"rldic. %0,%1,%3,(%2)-(%3)" },
+
+{ "extlwi",  4,   PPCCOM,	"rlwinm %0,%1,%3,0,(%2)-1" },
+{ "extlwi.", 4,   PPCCOM,	"rlwinm. %0,%1,%3,0,(%2)-1" },
+{ "extrwi",  4,   PPCCOM,	"rlwinm %0,%1,(%2)+(%3),32-(%2),31" },
+{ "extrwi.", 4,   PPCCOM,	"rlwinm. %0,%1,(%2)+(%3),32-(%2),31" },
+{ "inslwi",  4,   PPCCOM,	"rlwimi %0,%1,(-(%3)!31)&((%3)|31),%3,(%2)+(%3)-1" },
+{ "inslwi.", 4,   PPCCOM,	"rlwimi. %0,%1,(-(%3)!31)&((%3)|31),%3,(%2)+(%3)-1"},
+{ "insrwi",  4,   PPCCOM,	"rlwimi %0,%1,32-((%2)+(%3)),%3,(%2)+(%3)-1" },
+{ "insrwi.", 4,   PPCCOM,	"rlwimi. %0,%1,32-((%2)+(%3)),%3,(%2)+(%3)-1"},
+{ "rotrwi",  3,   PPCCOM,	"rlwinm %0,%1,(-(%2)!31)&((%2)|31),0,31" },
+{ "rotrwi.", 3,   PPCCOM,	"rlwinm. %0,%1,(-(%2)!31)&((%2)|31),0,31" },
+{ "slwi",    3,   PPCCOM,	"rlwinm %0,%1,%2,0,31-(%2)" },
+{ "sli",     3,   PWRCOM,	"rlinm %0,%1,%2,0,31-(%2)" },
+{ "slwi.",   3,   PPCCOM,	"rlwinm. %0,%1,%2,0,31-(%2)" },
+{ "sli.",    3,   PWRCOM,	"rlinm. %0,%1,%2,0,31-(%2)" },
+{ "srwi",    3,   PPCCOM,	"rlwinm %0,%1,(-(%2)!31)&((%2)|31),%2,31" },
+{ "sri",     3,   PWRCOM,	"rlinm %0,%1,(-(%2)!31)&((%2)|31),%2,31" },
+{ "srwi.",   3,   PPCCOM,	"rlwinm. %0,%1,(-(%2)!31)&((%2)|31),%2,31" },
+{ "sri.",    3,   PWRCOM,	"rlinm. %0,%1,(-(%2)!31)&((%2)|31),%2,31" },
+{ "clrrwi",  3,   PPCCOM,	"rlwinm %0,%1,0,0,31-(%2)" },
+{ "clrrwi.", 3,   PPCCOM,	"rlwinm. %0,%1,0,0,31-(%2)" },
+{ "clrlslwi",4,   PPCCOM,	"rlwinm %0,%1,%3,(%2)-(%3),31-(%3)" },
+{ "clrlslwi.",4,  PPCCOM,	"rlwinm. %0,%1,%3,(%2)-(%3),31-(%3)" },
+
+};
+
+const int powerpc_num_macros =
+  sizeof (powerpc_macros) / sizeof (powerpc_macros[0]);
diff -urN linux-2.4.21-pre3/arch/ppc64/kdb/ppc.h linux-2.4.21-pre4/arch/ppc64/kdb/ppc.h
--- linux-2.4.21-pre3/arch/ppc64/kdb/ppc.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/arch/ppc64/kdb/ppc.h	Tue Jan 28 19:44:29 2003
@@ -0,0 +1,259 @@
+/* ppc.h -- Header file for PowerPC opcode table
+   Copyright 1994, 1995 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Cygnus Support
+
+This file is part of GDB, GAS, and the GNU binutils.
+
+GDB, GAS, and the GNU binutils are free software; you can redistribute
+them and/or modify them under the terms of the GNU General Public
+License as published by the Free Software Foundation; either version
+1, or (at your option) any later version.
+
+GDB, GAS, and the GNU binutils are distributed in the hope that they
+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 file; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifndef PPC_H
+#define PPC_H
+
+/* The opcode table is an array of struct powerpc_opcode.  */
+
+struct powerpc_opcode
+{
+  /* The opcode name.  */
+  const char *name;
+
+  /* The opcode itself.  Those bits which will be filled in with
+     operands are zeroes.  */
+  unsigned long opcode;
+
+  /* The opcode mask.  This is used by the disassembler.  This is a
+     mask containing ones indicating those bits which must match the
+     opcode field, and zeroes indicating those bits which need not
+     match (and are presumably filled in by operands).  */
+  unsigned long mask;
+
+  /* One bit flags for the opcode.  These are used to indicate which
+     specific processors support the instructions.  The defined values
+     are listed below.  */
+  unsigned long flags;
+
+  /* An array of operand codes.  Each code is an index into the
+     operand table.  They appear in the order which the operands must
+     appear in assembly code, and are terminated by a zero.  */
+  unsigned char operands[8];
+};
+
+/* The table itself is sorted by major opcode number, and is otherwise
+   in the order in which the disassembler should consider
+   instructions.  */
+extern const struct powerpc_opcode powerpc_opcodes[];
+extern const int powerpc_num_opcodes;
+
+/* Values defined for the flags field of a struct powerpc_opcode.  */
+
+/* Opcode is defined for the PowerPC architecture.  */
+#define PPC_OPCODE_PPC (01)
+
+/* Opcode is defined for the POWER (RS/6000) architecture.  */
+#define PPC_OPCODE_POWER (02)
+
+/* Opcode is defined for the POWER2 (Rios 2) architecture.  */
+#define PPC_OPCODE_POWER2 (04)
+
+/* Opcode is only defined on 32 bit architectures.  */
+#define PPC_OPCODE_32 (010)
+
+/* Opcode is only defined on 64 bit architectures.  */
+#define PPC_OPCODE_64 (020)
+
+/* Opcode is supported by the Motorola PowerPC 601 processor.  The 601
+   is assumed to support all PowerPC (PPC_OPCODE_PPC) instructions,
+   but it also supports many additional POWER instructions.  */
+#define PPC_OPCODE_601 (040)
+
+/* Opcode is supported in both the Power and PowerPC architectures
+   (ie, compiler's -mcpu=common or assembler's -mcom).  */
+#define PPC_OPCODE_COMMON (0100)
+
+/* Opcode is supported for any Power or PowerPC platform (this is
+   for the assembler's -many option, and it eliminates duplicates).  */
+#define PPC_OPCODE_ANY (0200)
+
+/* Opcode is supported as part of the 64-bit bridge.  */
+#define PPC_OPCODE_64_BRIDGE (0400)
+
+/* Opcode is supported by Altivec Vector Unit */
+#define PPC_OPCODE_ALTIVEC   (01000)
+
+/* A macro to extract the major opcode from an instruction.  */
+#define PPC_OP(i) (((i) >> 26) & 0x3f)
+
+/* The operands table is an array of struct powerpc_operand.  */
+
+struct powerpc_operand
+{
+  /* The number of bits in the operand.  */
+  int bits;
+
+  /* How far the operand is left shifted in the instruction.  */
+  int shift;
+
+  /* Insertion function.  This is used by the assembler.  To insert an
+     operand value into an instruction, check this field.
+
+     If it is NULL, execute
+         i |= (op & ((1 << o->bits) - 1)) << o->shift;
+     (i is the instruction which we are filling in, o is a pointer to
+     this structure, and op is the opcode value; this assumes twos
+     complement arithmetic).
+
+     If this field is not NULL, then simply call it with the
+     instruction and the operand value.  It will return the new value
+     of the instruction.  If the ERRMSG argument is not NULL, then if
+     the operand value is illegal, *ERRMSG will be set to a warning
+     string (the operand will be inserted in any case).  If the
+     operand value is legal, *ERRMSG will be unchanged (most operands
+     can accept any value).  */
+  unsigned long (*insert) PARAMS ((unsigned long instruction, long op,
+				   const char **errmsg));
+
+  /* Extraction function.  This is used by the disassembler.  To
+     extract this operand type from an instruction, check this field.
+
+     If it is NULL, compute
+         op = ((i) >> o->shift) & ((1 << o->bits) - 1);
+	 if ((o->flags & PPC_OPERAND_SIGNED) != 0
+	     && (op & (1 << (o->bits - 1))) != 0)
+	   op -= 1 << o->bits;
+     (i is the instruction, o is a pointer to this structure, and op
+     is the result; this assumes twos complement arithmetic).
+
+     If this field is not NULL, then simply call it with the
+     instruction value.  It will return the value of the operand.  If
+     the INVALID argument is not NULL, *INVALID will be set to
+     non-zero if this operand type can not actually be extracted from
+     this operand (i.e., the instruction does not match).  If the
+     operand is valid, *INVALID will not be changed.  */
+  long (*extract) PARAMS ((unsigned long instruction, int *invalid));
+
+  /* One bit syntax flags.  */
+  unsigned long flags;
+};
+
+/* Elements in the table are retrieved by indexing with values from
+   the operands field of the powerpc_opcodes table.  */
+
+extern const struct powerpc_operand powerpc_operands[];
+
+/* Values defined for the flags field of a struct powerpc_operand.  */
+
+/* This operand takes signed values.  */
+#define PPC_OPERAND_SIGNED (01)
+
+/* This operand takes signed values, but also accepts a full positive
+   range of values when running in 32 bit mode.  That is, if bits is
+   16, it takes any value from -0x8000 to 0xffff.  In 64 bit mode,
+   this flag is ignored.  */
+#define PPC_OPERAND_SIGNOPT (02)
+
+/* This operand does not actually exist in the assembler input.  This
+   is used to support extended mnemonics such as mr, for which two
+   operands fields are identical.  The assembler should call the
+   insert function with any op value.  The disassembler should call
+   the extract function, ignore the return value, and check the value
+   placed in the valid argument.  */
+#define PPC_OPERAND_FAKE (04)
+
+/* The next operand should be wrapped in parentheses rather than
+   separated from this one by a comma.  This is used for the load and
+   store instructions which want their operands to look like
+       reg,displacement(reg)
+   */
+#define PPC_OPERAND_PARENS (010)
+
+/* This operand may use the symbolic names for the CR fields, which
+   are
+       lt  0	gt  1	eq  2	so  3	un  3
+       cr0 0	cr1 1	cr2 2	cr3 3
+       cr4 4	cr5 5	cr6 6	cr7 7
+   These may be combined arithmetically, as in cr2*4+gt.  These are
+   only supported on the PowerPC, not the POWER.  */
+#define PPC_OPERAND_CR (020)
+
+/* This operand names a register.  The disassembler uses this to print
+   register names with a leading 'r'.  */
+#define PPC_OPERAND_GPR (040)
+
+/* This operand names a floating point register.  The disassembler
+   prints these with a leading 'f'.  */
+#define PPC_OPERAND_FPR (0100)
+
+/* This operand is a relative branch displacement.  The disassembler
+   prints these symbolically if possible.  */
+#define PPC_OPERAND_RELATIVE (0200)
+
+/* This operand is an absolute branch address.  The disassembler
+   prints these symbolically if possible.  */
+#define PPC_OPERAND_ABSOLUTE (0400)
+
+/* This operand is optional, and is zero if omitted.  This is used for
+   the optional BF and L fields in the comparison instructions.  The
+   assembler must count the number of operands remaining on the line,
+   and the number of operands remaining for the opcode, and decide
+   whether this operand is present or not.  The disassembler should
+   print this operand out only if it is not zero.  */
+#define PPC_OPERAND_OPTIONAL (01000)
+
+/* This flag is only used with PPC_OPERAND_OPTIONAL.  If this operand
+   is omitted, then for the next operand use this operand value plus
+   1, ignoring the next operand field for the opcode.  This wretched
+   hack is needed because the Power rotate instructions can take
+   either 4 or 5 operands.  The disassembler should print this operand
+   out regardless of the PPC_OPERAND_OPTIONAL field.  */
+#define PPC_OPERAND_NEXT (02000)
+
+/* This operand should be regarded as a negative number for the
+   purposes of overflow checking (i.e., the normal most negative
+   number is disallowed and one more than the normal most positive
+   number is allowed).  This flag will only be set for a signed
+   operand.  */
+#define PPC_OPERAND_NEGATIVE (04000)
+
+/* This operand names a vector unit register.  The disassembler
+   prints these with a leading 'v'.  */
+#define PPC_OPERAND_VR (010000)
+
+
+/* The POWER and PowerPC assemblers use a few macros.  We keep them
+   with the operands table for simplicity.  The macro table is an
+   array of struct powerpc_macro.  */
+
+struct powerpc_macro
+{
+  /* The macro name.  */
+  const char *name;
+
+  /* The number of operands the macro takes.  */
+  unsigned int operands;
+
+  /* One bit flags for the opcode.  These are used to indicate which
+     specific processors support the instructions.  The values are the
+     same as those for the struct powerpc_opcode flags field.  */
+  unsigned long flags;
+
+  /* A format string to turn the macro into a normal instruction.
+     Each %N in the string is replaced with operand number N (zero
+     based).  */
+  const char *format;
+};
+
+extern const struct powerpc_macro powerpc_macros[];
+extern const int powerpc_num_macros;
+
+#endif /* PPC_H */
diff -urN linux-2.4.21-pre3/arch/ppc64/kdb/privinst.h linux-2.4.21-pre4/arch/ppc64/kdb/privinst.h
--- linux-2.4.21-pre3/arch/ppc64/kdb/privinst.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/arch/ppc64/kdb/privinst.h	Tue Jan 28 19:44:29 2003
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 1996 Paul Mackerras.
+ *
+ *      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>
+
+#define GETREG(reg)		\
+    static inline unsigned long get_ ## reg (void)	\
+	{ unsigned long ret; asm volatile ("mf" #reg " %0" : "=r" (ret) :); return ret; }
+
+#define SETREG(reg)		\
+    static inline void set_ ## reg (unsigned long val)	\
+	{ asm volatile ("mt" #reg " %0" : : "r" (val)); }
+
+GETREG(msr)
+SETREG(msr)
+SETREG(msrd)
+GETREG(cr)
+
+#define GSETSPR(n, name)	\
+    static inline long get_ ## name (void) \
+	{ long ret; asm volatile ("mfspr %0," #n : "=r" (ret) : ); return ret; } \
+    static inline void set_ ## name (long val) \
+	{ asm volatile ("mtspr " #n ",%0" : : "r" (val)); }
+
+GSETSPR(0, mq)
+GSETSPR(1, xer)
+GSETSPR(4, rtcu)
+GSETSPR(5, rtcl)
+GSETSPR(8, lr)
+GSETSPR(9, ctr)
+GSETSPR(18, dsisr)
+GSETSPR(19, dar)
+GSETSPR(22, dec)
+GSETSPR(25, sdr1)
+GSETSPR(26, srr0)
+GSETSPR(27, srr1)
+GSETSPR(272, sprg0)
+GSETSPR(273, sprg1)
+GSETSPR(274, sprg2)
+GSETSPR(275, sprg3)
+GSETSPR(282, ear)
+GSETSPR(287, pvr)
+GSETSPR(528, bat0u)
+GSETSPR(529, bat0l)
+GSETSPR(530, bat1u)
+GSETSPR(531, bat1l)
+GSETSPR(532, bat2u)
+GSETSPR(533, bat2l)
+GSETSPR(534, bat3u)
+GSETSPR(535, bat3l)
+GSETSPR(1008, hid0)
+GSETSPR(1009, hid1)
+GSETSPR(1010, iabr)
+GSETSPR(1013, dabr)
+GSETSPR(1023, pir)
+
+static inline int get_sr(int n)
+{
+    int ret;
+
+#if 0
+// DRENG does not assemble 
+    asm (" mfsrin %0,%1" : "=r" (ret) : "r" (n << 28));
+#endif
+    return ret;
+}
+
+static inline void set_sr(int n, int val)
+{
+#if 0
+// DRENG does not assemble 
+    asm ("mtsrin %0,%1" : : "r" (val), "r" (n << 28));
+#endif
+}
+
+static inline void store_inst(void *p)
+{
+    asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p));
+}
+
+static inline void cflush(void *p)
+{
+    asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p));
+}
+
+static inline void cinval(void *p)
+{
+    asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
+}
+
diff -urN linux-2.4.21-pre3/arch/ppc64/kdb/start.c linux-2.4.21-pre4/arch/ppc64/kdb/start.c
--- linux-2.4.21-pre3/arch/ppc64/kdb/start.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/arch/ppc64/kdb/start.c	Tue Jan 28 19:44:29 2003
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+#include <linux/config.h>
+#include <linux/string.h>
+#include <linux/fs.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/page.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#include <linux/cuda.h>
+#include <linux/kernel.h>
+#include <asm/prom.h>
+
+#include <linux/sysrq.h>
+#include <linux/kdb.h>
+#include <asm/kdb.h>
+
+#include <asm/processor.h>
+#include <asm/delay.h>
+#ifdef CONFIG_SMP
+#include <asm/bitops.h>
+#endif
+
+/* kdb will use UDBG */
+#define USE_UDBG
+
+#ifdef USE_UDBG
+#include <asm/udbg.h>
+#endif
+
+
+
+static void sysrq_handle_kdb(int key, struct pt_regs *pt_regs, struct kbd_struct *kbd, struct tty_struct *tty) 
+{
+  kdb(KDB_REASON_KEYBOARD,0,pt_regs);
+}
+
+static struct sysrq_key_op sysrq_kdb_op = 
+{
+	handler:	sysrq_handle_kdb,
+	help_msg:	"kdb",
+	action_msg:	"Entering kdb\n",
+};
+
+
+
+void
+kdb_map_scc(void)
+{
+	/* register sysrq 'x' */
+	__sysrq_put_key_op('x', &sysrq_kdb_op);
+}
+
+
diff -urN linux-2.4.21-pre3/arch/ppc64/kdb/subr_prf.c linux-2.4.21-pre4/arch/ppc64/kdb/subr_prf.c
--- linux-2.4.21-pre3/arch/ppc64/kdb/subr_prf.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/arch/ppc64/kdb/subr_prf.c	Tue Jan 28 19:44:29 2003
@@ -0,0 +1,50 @@
+/*
+ * Written by Cort Dougan to replace the version originally used
+ * by Paul Mackerras, which came from NetBSD and thus had copyright
+ * conflicts with Linux.
+ *
+ * This file makes liberal use of the standard linux utility
+ * routines to reduce the size of the binary.  We assume we can
+ * trust some parts of Linux inside the debugger.
+ *   -- Cort (cort@cs.nmt.edu)
+ *
+ * Copyright (C) 1999 Cort Dougan.
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <stdarg.h>
+#include "nonstdio.h"
+
+extern int xmon_write(void *, void *, int);
+
+void
+xmon_vfprintf(void *f, const char *fmt, va_list ap)
+{
+	static char xmon_buf[2048];
+	int n;
+
+	n = vsprintf(xmon_buf, fmt, ap);
+	xmon_write(f, xmon_buf, n);
+}
+
+void
+xmon_printf(const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	xmon_vfprintf(stdout, fmt, ap);
+	va_end(ap);
+}
+
+void
+xmon_fprintf(void *f, const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	xmon_vfprintf(f, fmt, ap);
+	va_end(ap);
+}
+
diff -urN linux-2.4.21-pre3/arch/ppc64/kdb/symcat.h linux-2.4.21-pre4/arch/ppc64/kdb/symcat.h
--- linux-2.4.21-pre3/arch/ppc64/kdb/symcat.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/arch/ppc64/kdb/symcat.h	Tue Jan 28 19:44:29 2003
@@ -0,0 +1,49 @@
+/* Symbol concatenation utilities.
+
+   Copyright (C) 1998, 2000 Free Software Foundation, 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 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.  */
+
+#ifndef SYM_CAT_H
+#define SYM_CAT_H
+
+#if defined (__STDC__) || defined (ALMOST_STDC) || defined (HAVE_STRINGIZE)
+#define CONCAT2(a,b)	 a##b
+#define CONCAT3(a,b,c)	 a##b##c
+#define CONCAT4(a,b,c,d) a##b##c##d
+#define STRINGX(s) #s
+#else
+/* Note one should never pass extra whitespace to the CONCATn macros,
+   e.g. CONCAT2(foo, bar) because traditonal C will keep the space between
+   the two labels instead of concatenating them.  Instead, make sure to
+   write CONCAT2(foo,bar).  */
+#define CONCAT2(a,b)	 a/**/b
+#define CONCAT3(a,b,c)	 a/**/b/**/c
+#define CONCAT4(a,b,c,d) a/**/b/**/c/**/d
+#define STRINGX(s) "s"
+#endif
+
+#define XCONCAT2(a,b)     CONCAT2(a,b)
+#define XCONCAT3(a,b,c)   CONCAT3(a,b,c)
+#define XCONCAT4(a,b,c,d) CONCAT4(a,b,c,d)
+
+/* Note the layer of indirection here is typically used to allow
+   stringification of the expansion of macros.  I.e. "#define foo
+   bar", "XSTRING(foo)", to yield "bar".  Be aware that this only
+   works for __STDC__, not for traditional C which will still resolve
+   to "foo".  */
+#define XSTRING(s) STRINGX(s) 
+
+#endif /* SYM_CAT_H */
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/ItLpQueue.c linux-2.4.21-pre4/arch/ppc64/kernel/ItLpQueue.c
--- linux-2.4.21-pre3/arch/ppc64/kernel/ItLpQueue.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/ItLpQueue.c	Tue Jan 28 19:44:29 2003
@@ -13,6 +13,8 @@
 #include <linux/sched.h>
 #include <asm/system.h>
 #include <asm/paca.h>
+#include <linux/random.h>
+#include <asm/time.h>
 #include <asm/iSeries/ItLpQueue.h>
 #include <asm/iSeries/HvLpEvent.h>
 #include <asm/iSeries/HvCallEvent.h>
@@ -166,5 +168,12 @@
 
 	get_paca()->lpEvent_count += numIntsProcessed;
 
+	/* Use LPEvents as a source of randomness.  Since there
+	 * Isn't an LPEvent Randomness call, pretend these are
+	 * mouse events (which is fair since we don't have mice
+	 * on the iSeries)
+	 */
+	add_mouse_randomness(get_tb());
+
 	return numIntsProcessed;
 }
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/Makefile linux-2.4.21-pre4/arch/ppc64/kernel/Makefile
--- linux-2.4.21-pre3/arch/ppc64/kernel/Makefile	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/Makefile	Tue Jan 28 19:44:29 2003
@@ -42,6 +42,8 @@
 
 obj-$(CONFIG_RTAS_FLASH) += rtas_flash.o
 
+obj-$(CONFIG_SCANLOG) += scanlog.o
+
 obj-$(CONFIG_KGDB) += ppc-stub.o
 
 obj-$(CONFIG_SMP) += smp.o
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/bitops.c linux-2.4.21-pre4/arch/ppc64/kernel/bitops.c
--- linux-2.4.21-pre3/arch/ppc64/kernel/bitops.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/bitops.c	Tue Jan 28 19:44:29 2003
@@ -39,7 +39,7 @@
  * 64 bit long layout as shown above.  Got that?  Good.
  */
 
-unsigned long find_next_zero_bit(void * addr, unsigned long size,
+unsigned long find_next_zero_bit(unsigned long* addr, unsigned long size,
 				 unsigned long offset)
 {
 	unsigned long *p = ((unsigned long *) addr) + (offset >> 6);
@@ -79,6 +79,99 @@
 	return result + ffz(tmp);
 }
 
+unsigned long find_next_bit(unsigned long *addr, unsigned long size, unsigned long offset)
+{
+        unsigned long *p = addr + (offset >> 6);
+        unsigned long result = offset & ~63UL;
+        unsigned long tmp;
+
+        if (offset >= size)
+                return size;
+        size -= result;
+        offset &= 63UL;
+        if (offset) {
+                tmp = *(p++);
+                tmp &= (~0UL << offset);
+                if (size < 64)
+                        goto found_first;
+                if (tmp)
+                        goto found_middle;
+                size -= 64;
+                result += 64;
+        }
+        while (size & ~63UL) {
+                if ((tmp = *(p++)))
+                        goto found_middle;
+                result += 64;
+                size -= 64;
+        }
+        if (!size)
+                return result;
+        tmp = *p;
+
+found_first:
+        tmp &= (~0UL >> (64 - size));
+        if (tmp == 0UL)        /* Are any bits set? */
+                return result + size; /* Nope. */
+found_middle:
+        return result + __ffs(tmp);
+}
+
+static __inline__ unsigned int ext2_ilog2(unsigned int x)
+{
+        int lz;
+
+        asm("cntlzw %0,%1" : "=r" (lz) : "r" (x));
+        return 31 - lz;
+}
+
+static __inline__ unsigned int ext2_ffz(unsigned int x)
+{
+        u32  tempRC;
+        if ((x = ~x) == 0)
+                return 32;
+        tempRC = ext2_ilog2(x & -x);
+        return tempRC;
+}
+
+unsigned long find_next_zero_le_bit(unsigned long *addr, unsigned long size, unsigned long
+ offset)
+{
+        unsigned int *p = ((unsigned int *) addr) + (offset >> 5);
+        unsigned int result = offset & ~31;
+        unsigned int tmp;
+
+        if (offset >= size)
+                return size;
+        size -= result;
+        offset &= 31;
+        if (offset) {
+                tmp = cpu_to_le32p(p++);
+                tmp |= ~0U >> (32-offset); /* bug or feature ? */
+                if (size < 32)
+                        goto found_first;
+                if (tmp != ~0)
+                        goto found_middle;
+                size -= 32;
+                result += 32;
+        }
+        while (size >= 32) {
+                if ((tmp = cpu_to_le32p(p++)) != ~0)
+                        goto found_middle;
+                result += 32;
+                size -= 32;
+        }
+        if (!size)
+                return result;
+        tmp = cpu_to_le32p(p);
+found_first:
+        tmp |= ~0 << size;
+        if (tmp == ~0)          /* Are any bits zero? */
+                return result + size; /* Nope. */
+found_middle:
+        return result + ext2_ffz(tmp);
+}
+
 void BUG_OUTLINE(char* file, unsigned line) 
 {
 	udbg_printf("BUG - kernel BUG at %s:%d! \n", __FILE__, __LINE__);
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/chrp_setup.c linux-2.4.21-pre4/arch/ppc64/kernel/chrp_setup.c
--- linux-2.4.21-pre3/arch/ppc64/kernel/chrp_setup.c	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/chrp_setup.c	Tue Jan 28 19:44:29 2003
@@ -161,11 +161,12 @@
 
 	fwnmi_init();
 
+#ifndef CONFIG_PPC_ISERIES
 	/* Find and initialize PCI host bridges */
 	/* iSeries needs to be done much later. */
- 	#ifndef CONFIG_PPC_ISERIES
-		find_and_init_phbs();
- 	#endif
+	eeh_init();
+	find_and_init_phbs();
+#endif
 
 	/* Find the Open PIC if present */
 	root = find_path_device("/");
@@ -256,7 +257,7 @@
 #endif /* CONFIG_BLK_DEV_INITRD */
 #endif
 
-	ppc_md.ppc_machine = naca->platform;
+	ppc_md.ppc_machine = systemcfg->platform;
 
 	ppc_md.setup_arch     = chrp_setup_arch;
 	ppc_md.setup_residual = NULL;
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/eeh.c linux-2.4.21-pre4/arch/ppc64/kernel/eeh.c
--- linux-2.4.21-pre3/arch/ppc64/kernel/eeh.c	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/eeh.c	Tue Jan 28 19:44:29 2003
@@ -43,25 +43,25 @@
 static int ibm_set_slot_reset;
 static int ibm_read_slot_reset_state;
 
-int eeh_implemented;
+static int eeh_implemented;
 #define EEH_MAX_OPTS 4096
 static char *eeh_opts;
 static int eeh_opts_last;
-static int eeh_check_opts_config(struct pci_dev *dev, int default_state);
 
+pte_t *find_linux_pte(pgd_t *pgdir, unsigned long va);	/* from htab.c */
+static int eeh_check_opts_config(struct device_node *dn,
+				 int class_code, int vendor_id, int device_id,
+				 int default_state);
 
-unsigned long eeh_token(unsigned long phb, unsigned long bus, unsigned long devfn, unsigned long offset)
+unsigned long eeh_token_to_phys(unsigned long token)
 {
-	if (phb > 0xff)
-		panic("eeh_token: phb 0x%lx is too large\n", phb);
-	if (offset & 0x0fffffff00000000)
-		panic("eeh_token: offset 0x%lx is out of range\n", offset);
-	return ((IO_UNMAPPED_REGION_ID << 60) | (phb << 48UL) | ((bus & 0xff) << 40UL) | (devfn << 32UL) | (offset & 0xffffffff));
-}
-
-int eeh_get_state(unsigned long ea)
-{
-	return 0;
+	if (REGION_ID(token) == EEH_REGION_ID) {
+		unsigned long vaddr = IO_TOKEN_TO_ADDR(token);
+		pte_t *ptep = find_linux_pte(ioremap_mm.pgd, vaddr);
+		unsigned long pa = pte_pagenr(*ptep) << PAGE_SHIFT;
+		return pa | (vaddr & (PAGE_SIZE-1));
+	} else
+		return token;
 }
 
 /* Check for an eeh failure at the given token address.
@@ -73,47 +73,152 @@
  */
 unsigned long eeh_check_failure(void *token, unsigned long val)
 {
-	unsigned long config_addr = (unsigned long)token >> 24;	/* PPBBDDRR */
-	unsigned long phbidx = (config_addr >> 24) & 0xff;
-	struct pci_controller *phb;
+	unsigned long addr;
+	struct pci_dev *dev;
+	struct device_node *dn;
 	unsigned long ret, rets[2];
 
-	config_addr &= 0xffff00;  /* 00BBDD00 */
+	/* IO BAR access could get us here...or if we manually force EEH
+	 * operation on even if the hardware won't support it.
+	 */
+	if (!eeh_implemented || ibm_read_slot_reset_state == RTAS_UNKNOWN_SERVICE)
+		return val;
 
-	if (phbidx >= global_phb_number) {
-		panic("EEH: checking token %p phb index of %ld is greater than max of %d\n", token, phbidx, global_phb_number-1);
+	/* Finding the phys addr + pci device is quite expensive.
+	 * However, the RTAS call is MUCH slower.... :(
+	 */
+	addr = eeh_token_to_phys((unsigned long)token);
+	dev = pci_find_dev_by_addr(addr);
+	if (!dev) {
+		printk("EEH: no pci dev found for addr=0x%lx\n", addr);
+		return val;
+	}
+	dn = pci_device_to_OF_node(dev);
+	if (!dn) {
+		printk("EEH: no pci dn found for addr=0x%lx\n", addr);
+		return val;
 	}
-	phb = phbtab[phbidx];
 
-	ret = rtas_call(ibm_read_slot_reset_state, 3, 3, rets,
-			config_addr, BUID_HI(phb->buid), BUID_LO(phb->buid));
-	if (ret == 0 && rets[1] == 1 && rets[0] >= 2) {
-		struct pci_dev *dev;
-		int bus = ((unsigned long)token >> 40) & 0xffff; /* include PHB# in bus */
-		int devfn = (config_addr >> 8) & 0xff;
-
-		dev = pci_find_slot(bus, devfn);
-		if (dev) {
-			udbg_printf("EEH:  MMIO failure (%ld) on device:\n  %s %s\n",
-			      rets[0], dev->slot_name, dev->name);
-			printk("EEH:  MMIO failure (%ld) on device:\n  %s %s\n",
-			      rets[0], dev->slot_name, dev->name);
-			PPCDBG_ENTER_DEBUGGER();
+	/* Access to IO BARs might get this far and still not want checking. */
+	if (!(dn->eeh_mode & EEH_MODE_SUPPORTED) || dn->eeh_mode & EEH_MODE_NOCHECK)
+		return val;
+
+
+	/* Now test for an EEH failure.  This is VERY expensive.
+	 * Note that the eeh_config_addr may be a parent device
+	 * in the case of a device behind a bridge, or it may be
+	 * function zero of a multi-function device.
+	 * In any case they must share a common PHB.
+	 */
+	if (dn->eeh_config_addr) {
+		ret = rtas_call(ibm_read_slot_reset_state, 3, 3, rets,
+				dn->eeh_config_addr, BUID_HI(dn->phb->buid), BUID_LO(dn->phb->buid));
+		if (ret == 0 && rets[1] == 1 && rets[0] >= 2) {
 			panic("EEH:  MMIO failure (%ld) on device:\n  %s %s\n",
 			      rets[0], dev->slot_name, dev->name);
-		} else {
-			udbg_printf("EEH:  MMIO failure (%ld) on device buid %lx, config_addr %lx\n", rets[0], phb->buid, config_addr);
-			printk("EEH:  MMIO failure (%ld) on device buid %lx, config_addr %lx\n", rets[0], phb->buid, config_addr);
-			PPCDBG_ENTER_DEBUGGER();
-			panic("EEH:  MMIO failure (%ld) on device buid %lx, config_addr %lx\n", rets[0], phb->buid, config_addr);
 		}
 	}
 	eeh_false_positives++;
 	return val;	/* good case */
+
+}
+
+struct eeh_early_enable_info {
+	unsigned int buid_hi;
+	unsigned int buid_lo;
+	int adapters_enabled;
+};
+
+/* Enable eeh for the given device node. */
+static void *early_enable_eeh(struct device_node *dn, void *data)
+{
+	struct eeh_early_enable_info *info = data;
+	long ret;
+	char *status = get_property(dn, "status", 0);
+	u32 *class_code = (u32 *)get_property(dn, "class-code", 0);
+	u32 *vendor_id =(u32 *) get_property(dn, "vendor-id", 0);
+	u32 *device_id = (u32 *)get_property(dn, "device-id", 0);
+	u32 *regs;
+	int enable;
+
+	if (status && strcmp(status, "ok") != 0)
+		return NULL;	/* ignore devices with bad status */
+
+	/* Weed out PHBs or other bad nodes. */
+	if (!class_code || !vendor_id || !device_id)
+		return NULL;
+
+	/* Ignore known PHBs and EADs bridges */
+	if (*vendor_id == PCI_VENDOR_ID_IBM &&
+	    (*device_id == 0x0102 || *device_id == 0x008b ||
+	     *device_id == 0x0188 || *device_id == 0x0302))
+		return NULL;
+
+	/* Now decide if we are going to "Disable" EEH checking
+	 * for this device.  We still run with the EEH hardware active,
+	 * but we won't be checking for ff's.  This means a driver
+	 * could return bad data (very bad!), an interrupt handler could
+	 * hang waiting on status bits that won't change, etc.
+	 * But there are a few cases like display devices that make sense.
+	 */
+	enable = 1;	/* i.e. we will do checking */
+	if ((*class_code >> 16) == PCI_BASE_CLASS_DISPLAY)
+		enable = 0;
+
+	if (!eeh_check_opts_config(dn, *class_code, *vendor_id, *device_id, enable)) {
+		if (enable) {
+			printk(KERN_INFO "EEH: %s user requested to run without EEH.\n", dn->full_name);
+			enable = 0;
+		}
+	}
+
+	if (!enable)
+		dn->eeh_mode = EEH_MODE_NOCHECK;
+
+	/* This device may already have an EEH parent. */
+	if (dn->parent && (dn->parent->eeh_mode & EEH_MODE_SUPPORTED)) {
+		/* Parent supports EEH. */
+		dn->eeh_mode |= EEH_MODE_SUPPORTED;
+		dn->eeh_config_addr = dn->parent->eeh_config_addr;
+		return NULL;
+	}
+
+	/* Ok..see if this device supports EEH. */
+	regs = (u32 *)get_property(dn, "reg", 0);
+	if (regs) {
+		/* First register entry is addr (00BBSS00)  */
+		/* Try to enable eeh */
+		ret = rtas_call(ibm_set_eeh_option, 4, 1, NULL,
+				regs[0], info->buid_hi, info->buid_lo,
+				EEH_ENABLE);
+		if (ret == 0) {
+			info->adapters_enabled++;
+			dn->eeh_mode |= EEH_MODE_SUPPORTED;
+			dn->eeh_config_addr = regs[0];
+		}
+	}
+	return NULL; 
 }
 
+/*
+ * Initialize eeh by trying to enable it for all of the adapters in the system.
+ * As a side effect we can determine here if eeh is supported at all.
+ * Note that we leave EEH on so failed config cycles won't cause a machine
+ * check.  If a user turns off EEH for a particular adapter they are really
+ * telling Linux to ignore errors.
+ *
+ * We should probably distinguish between "ignore errors" and "turn EEH off"
+ * but for now disabling EEH for adapters is mostly to work around drivers that
+ * directly access mmio space (without using the macros).
+ *
+ * The eeh-force-off/on option does literally what it says, so if Linux must
+ * avoid enabling EEH this must be done.
+ */
 void eeh_init(void)
 {
+	struct device_node *phb;
+	struct eeh_early_enable_info info;
+
 	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");
@@ -121,64 +226,51 @@
 	ibm_set_eeh_option = rtas_token("ibm,set-eeh-option");
 	ibm_set_slot_reset = rtas_token("ibm,set-slot-reset");
 	ibm_read_slot_reset_state = rtas_token("ibm,read-slot-reset-state");
-	if (ibm_set_eeh_option != RTAS_UNKNOWN_SERVICE && naca->platform == PLATFORM_PSERIES_LPAR)
+
+	/* Allow user to force eeh mode on or off -- even if the hardware
+	 * doesn't exist.  This allows driver writers to at least test use
+	 * of I/O macros even if we can't actually test for EEH failure.
+	 */
+	if (eeh_force_on > eeh_force_off)
 		eeh_implemented = 1;
+	else if (ibm_set_eeh_option == RTAS_UNKNOWN_SERVICE)
+		return;
 
 	if (eeh_force_off > eeh_force_on) {
 		/* User is forcing EEH off.  Be noisy if it is implemented. */
 		if (eeh_implemented)
-			printk("EEH: WARNING: PCI Enhanced I/O Error Handling is user disabled\n");
+			printk(KERN_WARNING "EEH: WARNING: PCI Enhanced I/O Error Handling is user disabled\n");
 		eeh_implemented = 0;
 		return;
 	}
 
-	if (eeh_force_on > eeh_force_off)
-		eeh_implemented = 1;	/* User is forcing it on. */
 
-	if (eeh_implemented)
-		printk("EEH: PCI Enhanced I/O Error Handling Enabled\n");
+	/* Enable EEH for all adapters.  Note that eeh requires buid's */
+	info.adapters_enabled = 0;
+	for (phb = find_devices("pci"); phb; phb = phb->next) {
+		int len;
+		int *buid_vals = (int *) get_property(phb, "ibm,fw-phb-id", &len);
+		if (!buid_vals)
+			continue;
+		if (len == sizeof(int)) {
+			info.buid_lo = buid_vals[0];
+			info.buid_hi = 0;
+		} else if (len == sizeof(int)*2) {
+			info.buid_hi = buid_vals[0];
+			info.buid_lo = buid_vals[1];
+		} else {
+			printk("EEH: odd ibm,fw-phb-id len returned: %d\n", len);
+			continue;
+		}
+		traverse_pci_devices(phb, early_enable_eeh, NULL, &info);
+	}
+	if (info.adapters_enabled) {
+		printk(KERN_INFO "EEH: PCI Enhanced I/O Error Handling Enabled\n");
+		eeh_implemented = 1;
+	}
 }
 
 
-/* Given a PCI device check if eeh should be configured or not.
- * This may look at firmware properties and/or kernel cmdline options.
- */
-int is_eeh_configured(struct pci_dev *dev)
-{
-	struct device_node *dn = pci_device_to_OF_node(dev);
-	struct pci_controller *phb = PCI_GET_PHB_PTR(dev);
-	unsigned long ret, rets[2];
-	int eeh_capable;
-	int default_state = 1;	/* default enable EEH if we can. */
-
-	if (dn == NULL || phb == NULL || !eeh_implemented)
-		return 0;
-
-	/* Hack: turn off eeh for display class devices by default.
-	 * This fixes matrox accel framebuffer.
-	 */
-	if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY)
-		default_state = 0;
-
-	/* Ignore known PHBs and EADs bridges */
-	if (dev->vendor == PCI_VENDOR_ID_IBM &&
-	    (dev->device == 0x0102 || dev->device == 0x008b))
-		default_state = 0;
-
-	if (!eeh_check_opts_config(dev, default_state)) {
-		if (default_state)
-			printk("EEH: %s %s user requested to run without EEH.\n", dev->slot_name, dev->name);
-		return 0;
-	}
-
-	ret = rtas_call(ibm_read_slot_reset_state, 3, 3, rets,
-			CONFIG_ADDR(dn->busno, dn->devfn),
-			BUID_HI(phb->buid), BUID_LO(phb->buid));
-	eeh_capable = (ret == 0 && rets[1] == 1);
-	printk("EEH: %s %s is%s EEH capable.\n", dev->slot_name, dev->name, eeh_capable ? "" : " not");
-	return eeh_capable;
-}
-
 int eeh_set_option(struct pci_dev *dev, int option)
 {
 	struct device_node *dn = pci_device_to_OF_node(dev);
@@ -193,6 +285,30 @@
 }
 
 
+/* If EEH is implemented, find the PCI device using given phys addr
+ * and check to see if eeh failure checking is disabled.
+ * Remap the addr (trivially) to the EEH region if not.
+ * For addresses not known to PCI the vaddr is simply returned unchanged.
+ */
+void *eeh_ioremap(unsigned long addr, void *vaddr)
+{
+	struct pci_dev *dev;
+	struct device_node *dn;
+
+	if (!eeh_implemented)
+		return vaddr;
+	dev = pci_find_dev_by_addr(addr);
+	if (!dev)
+		return vaddr;
+	dn = pci_device_to_OF_node(dev);
+	if (!dn)
+		return vaddr;
+	if (dn->eeh_mode & EEH_MODE_NOCHECK)
+		return vaddr;
+
+	return (void *)IO_ADDR_TO_TOKEN(vaddr);
+}
+
 static int eeh_proc_falsepositive_read(char *page, char **start, off_t off,
 			 int count, int *eof, void *data)
 {
@@ -223,28 +339,24 @@
  * This lets the user specify stupid combinations of options,
  * but at least the result should be very predictable.
  */
-static int eeh_check_opts_config(struct pci_dev *dev, int default_state)
+static int eeh_check_opts_config(struct device_node *dn,
+				 int class_code, int vendor_id, int device_id,
+				 int default_state)
 {
-	struct device_node *dn = pci_device_to_OF_node(dev);
-	struct pci_controller *phb = PCI_GET_PHB_PTR(dev);
-	char devname[32], classname[32], phbname[32];
+	char devname[32], classname[32];
 	char *strs[8], *s;
 	int nstrs, i;
 	int ret = default_state;
 
-	if (dn == NULL || phb == NULL)
-		return 0;
 	/* Build list of strings to match */
 	nstrs = 0;
 	s = (char *)get_property(dn, "ibm,loc-code", 0);
 	if (s)
 		strs[nstrs++] = s;
-	sprintf(devname, "dev%04x:%04x", dev->vendor, dev->device);
+	sprintf(devname, "dev%04x:%04x", vendor_id, device_id);
 	strs[nstrs++] = devname;
-	sprintf(classname, "class%04x", dev->class);
+	sprintf(classname, "class%04x", class_code);
 	strs[nstrs++] = classname;
-	sprintf(phbname, "pci@%lx", phb->buid);
-	strs[nstrs++] = phbname;
 	strs[nstrs++] = "";	/* yes, this matches the empty string */
 
 	/* Now see if any string matches the eeh_opts list.
@@ -276,7 +388,6 @@
  *
  *	dev#:#    vendor:device id in hex (e.g. dev1022:2000)
  *	class#    class id in hex (e.g. class0200)
- *	pci@buid  all devices under phb (e.g. pci@fef00000)
  *
  * If no location code is specified all devices are assumed
  * so eeh-off means eeh by default is off.
@@ -284,13 +395,11 @@
 
 /* This is implemented as a null separated list of strings.
  * Each string looks like this:  "+X" or "-X"
- * where X is a loc code, dev, class or pci string (as shown above)
+ * where X is a loc code, vendor:device, class (as shown above)
  * or empty which is used to indicate all.
  *
- * We interpret this option string list during the buswalk
- * so that it will literally behave left-to-right even if
- * some combinations don't make sense.  Give the user exactly
- * what they want! :)
+ * We interpret this option string list so that it will literally
+ * behave left-to-right even if some combinations don't make sense.
  */
 
 static int __init eeh_parm(char *str, int state)
@@ -318,7 +427,7 @@
 		if (*cur) {
 			int curlen = curend-cur;
 			if (eeh_opts_last + curlen > EEH_MAX_OPTS-2) {
-				printk("EEH: sorry...too many eeh cmd line options\n");
+				printk(KERN_INFO "EEH: sorry...too many eeh cmd line options\n");
 				return 1;
 			}
 			eeh_opts[eeh_opts_last++] = state ? '+' : '-';
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/entry.S linux-2.4.21-pre4/arch/ppc64/kernel/entry.S
--- linux-2.4.21-pre3/arch/ppc64/kernel/entry.S	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/entry.S	Tue Jan 28 19:44:29 2003
@@ -52,12 +52,12 @@
 	andc	r11,r11,r10
 	std	r11,_CCR(r1)
 #ifdef SHOW_SYSCALLS
-#ifdef SHOW_SYSCALLS_TASK
+# ifdef SHOW_SYSCALLS_TASK
 	LOADBASE(r31,show_syscalls_task)
 	ld	r31,show_syscalls_task@l(r31)
 	cmp	0,r13,r31
 	bne	1f
-#endif
+# endif /* SHOW_SYSCALLS_TASK */
 	LOADADDR(r3,7f)
 	ld	r4,GPR0(r1)
 	ld	r5,GPR3(r1)
@@ -115,16 +115,16 @@
 _GLOBAL(ret_from_syscall_1)
 20:	std	r3,RESULT(r1)	/* Save result */
 #ifdef SHOW_SYSCALLS
-#ifdef SHOW_SYSCALLS_TASK
+# ifdef SHOW_SYSCALLS_TASK
 	cmp	0,r13,r31
 	bne	91f
-#endif
+# endif /* SHOW_SYSCALLS_TASK */
 	mr	r4,r3
 	LOADADDR(r3,79f)
 	bl	.printk
 	ld	r3,RESULT(r1)
 91:
-#endif
+#endif /* SHOW_SYSCALLS */
 	li	r10,-_LAST_ERRNO
 	cmpl	0,r3,r10
 	blt	30f
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/head.S linux-2.4.21-pre4/arch/ppc64/kernel/head.S
--- linux-2.4.21-pre3/arch/ppc64/kernel/head.S	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/head.S	Tue Jan 28 19:44:29 2003
@@ -49,8 +49,9 @@
  * 0x0100 - 0x2fff : pSeries Interrupt prologs
  * 0x3000 - 0x3fff : Interrupt support
  * 0x4000 - 0x4fff : NACA
- * 0x5000 - 0x5fff : Initial segment table
+ * 0x5000 - 0x5fff : SystemCfg
  * 0x6000          : iSeries and common interrupt prologs
+ * 0x9000 - 0x9fff : Initial segment table
  */
 
 /*
@@ -80,6 +81,12 @@
 _stext:
 _STATIC(__start)
 	b .__start_initialization_pSeries
+	.long  0x0
+
+	. = 0x8
+	.globl	__zero
+__zero:
+	.llong	0
 
 	/* At offset 0x20, there is a pointer to iSeries LPAR data.
 	 * This is required by the hypervisor */
@@ -373,21 +380,14 @@
 	.llong 0x0
 	.llong paca
 
-	/*
-	 * Space for the initial segment table
-	 * For LPAR, the hypervisor must fill in at least one entry
-	 * before we get control (with relocate on)
-	 */
 	. = 0x5000
 	.globl __end_naca
-	.globl __start_stab
+	.globl __start_systemcfg
 __end_naca:
-__start_stab:
-
-
+__start_systemcfg:
 	. = 0x6000
-	.globl __end_stab
-__end_stab:
+	.globl __end_systemcfg
+__end_systemcfg:
 
 	/*
 	 * The iSeries LPAR map is at this fixed address
@@ -400,7 +400,7 @@
 
 	.llong	1		/* # ESIDs to be mapped by hypervisor         */
 	.llong	1		/* # memory ranges to be mapped by hypervisor */
-	.llong	5		/* Page # of segment table within load area   */
+	.llong	STAB0_PAGE	/* Page # of segment table within load area   */
 	.llong	0		/* Reserved */
 	.llong  0		/* Reserved */
 	.llong  0		/* Reserved */
@@ -527,6 +527,20 @@
 MachineCheck_FWNMI:
 	EXCEPTION_PROLOG_PSERIES(0x200, MachineCheck_common)
 
+	/*
+	 * Space for the initial segment table
+	 * For LPAR, the hypervisor must fill in at least one entry
+	 * before we get control (with relocate on)
+	 */
+	. = STAB0_PHYS_ADDR
+	.globl __start_stab
+__start_stab:
+
+	. = (STAB0_PHYS_ADDR + PAGE_SIZE)
+	.globl __end_stab
+__end_stab:
+
+
 /*** Common interrupt handlers ***/
 
 	STD_EXCEPTION_COMMON( 0x100, SystemReset, .SystemResetException )
@@ -801,6 +815,7 @@
 	b	fast_exception_return
 	
 _GLOBAL(PerformanceMonitorException)
+	sync
 	mfspr	r7,SPRG3
 	lbz	r8,PACAPROFMODE(r7)
 	cmpi	0,r8,PMC_STATE_PROFILE_KERN
@@ -809,6 +824,8 @@
 	beq 	6f
 	cmpi	0,r8,PMC_STATE_TRACE_USER
 	beq 	9f
+	cmpi	0,r8,PMC_STATE_TIMESLICE
+	beq 	10f
 	blr
 
 	/* PMC Profile Kernel */
@@ -879,6 +896,13 @@
 	addi	r10,r13,THREAD+THREAD_PMC1
 	addi	r7,r13,THREAD+THREAD_PMCC1
 #endif
+	b	7f
+
+	/* PMC Timeslice */
+10:	addi	r10,r7,PACAPMC1
+	addi	r7,r7,PACAPMCC1
+	b	7f
+
 	/* Accumulate counter values for kernel traces */
 7:	ld	r9,0(r7)
 	mfspr   r8,PMC1	
@@ -914,27 +938,27 @@
 	std	r9,56(r7)
 
 	/* Reset all counters for kernel traces */
-	lwz	r9,0(r10)
+	ld	r9,0(r10)
 	mtspr	PMC1,r9
-	lwz	r9,4(r10)
+	ld	r9,8(r10)
 	mtspr	PMC2,r9
-	lwz	r9,8(r10)
+	ld	r9,16(r10)
 	mtspr	PMC3,r9
-	lwz	r9,12(r10)
+	ld	r9,24(r10)
 	mtspr	PMC4,r9
-	lwz	r9,16(r10)
+	ld	r9,32(r10)
 	mtspr	PMC5,r9
-	lwz	r9,20(r10)
+	ld	r9,40(r10)
 	mtspr	PMC6,r9
-	lwz	r9,24(r10)
+	ld	r9,48(r10)
 	mtspr	PMC7,r9
-	lwz	r9,28(r10)
+	ld	r9,56(r10)
 	mtspr	PMC8,r9
-	lwz	r9,32(r10)
+	ld	r9,64(r10)
 	mtspr	MMCR0,r9
-	lwz	r9,36(r10)
+	ld	r9,72(r10)
 	mtspr	MMCR1,r9
-	lwz	r9,40(r10)
+	ld	r9,80(r10)
 	mtspr	MMCRA,r9
 	blr
 
@@ -1363,14 +1387,19 @@
 	addi	r2,r2,0x4000
 	addi	r2,r2,0x4000
 
+	LOADADDR(r9,systemcfg)
+	SET_REG_TO_CONST(r4, KERNELBASE+0x5000)
+	std	r4,0(r9)		/* set the systemcfg pointer */
+
 	LOADADDR(r9,naca)
-	SET_REG_TO_CONST(r4, KERNELBASE)
-	addi	r4,r4,0x4000
+	SET_REG_TO_CONST(r4, KERNELBASE+0x4000)
 	std	r4,0(r9)		/* set the naca pointer */
 
+#if 1 /* DRENG:PPPBBB:TIA This looks like dead code to me -Peter */
 	/* Get the pointer to the segment table */
 	ld	r6,PACA(r4)             /* Get the base paca pointer       */
 	ld	r4,PACASTABVIRT(r6)
+#endif
 
 	bl      .iSeries_fixup_klimit
 
@@ -1398,13 +1427,18 @@
 	/* Relocate the TOC from a virt addr to a real addr */
 	sub	r2,r2,r3
 
+	/* setup the systemcfg pointer which is needed by prom_init       */
+	LOADADDR(r9,systemcfg)
+	sub	r9,r9,r3                /* addr of the variable systemcfg */
+	SET_REG_TO_CONST(r4, KERNELBASE+0x5000)
+	sub	r4,r4,r3
+	std	r4,0(r9)		/* set the value of systemcfg     */
+
 	/* setup the naca pointer which is needed by prom_init            */
 	LOADADDR(r9,naca)
 	sub	r9,r9,r3                /* addr of the variable naca      */
-
-	SET_REG_TO_CONST(r4, KERNELBASE)
+	SET_REG_TO_CONST(r4, KERNELBASE+0x4000)
 	sub	r4,r4,r3
-	addi	r4,r4,0x4000
 	std	r4,0(r9)		/* set the value of naca          */
 
 	/* DRENG / PPPBBB Fix the following comment!!! -Peter */
@@ -1526,11 +1560,13 @@
 copy_to_here:
 
 /*
+ * load_up_fpu(unused, unused, tsk)
  * Disable FP for the task which had the FPU previously,
  * and save its floating-point registers in its thread_struct.
  * Enables the FPU for use in the kernel on return.
  * On SMP we know the fpu is free, since we give it up every
- * switch.  -- Cort
+ * switch (ie, no lazy save of the FP registers).
+ * On entry: r13 == 'current' && last_task_used_math != 'current'
  */
 _STATIC(load_up_fpu)
 	mfmsr	r5                      /* grab the current MSR */
@@ -1548,26 +1584,30 @@
 	ld	r4,last_task_used_math@l(r3)
 	cmpi	0,r4,0
 	beq	1f
-	addi	r4,r4,THREAD	       /* want THREAD of last_task_used_math */
+	/* Save FP state to last_task_used_math's THREAD struct */
+	addi	r4,r4,THREAD
 	SAVE_32FPRS(0, r4)
 	mffs	fr0
-	stfd	fr0,THREAD_FPSCR-4(r4)
+	stfd	fr0,THREAD_FPSCR(r4)
+	/* Disable FP for last_task_used_math */
 	ld	r5,PT_REGS(r4)
 	ld	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
 	li	r20,MSR_FP|MSR_FE0|MSR_FE1
-	andc	r4,r4,r20		/* disable FP for previous task */
+	andc	r4,r4,r20
 	std	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
 1:
 #endif /* CONFIG_SMP */
 	/* enable use of FP after return */
-	ori	r23,r23,MSR_FP|MSR_FE0|MSR_FE1
-	addi	r5,r13,THREAD		/* Get THREAD */
-	lfd	fr0,THREAD_FPSCR-4(r5)
+	addi	r5,r13,THREAD
+	ld	r4,THREAD_FPEXC_MODE(r5)
+	ori	r23,r23,MSR_FP
+	or	r23,r23,r4
+	lfd	fr0,THREAD_FPSCR(r5)
 	mtfsf	0xff,fr0
 	REST_32FPRS(0, r5)
 #ifndef CONFIG_SMP
-	subi	r4,r5,THREAD		/* Back to 'current' */
-	std	r4,last_task_used_math@l(r3)
+	/* Update last_task_used_math to 'current' */
+	std	r13,last_task_used_math@l(r3)
 #endif /* CONFIG_SMP */
 	/* restore registers and return */
 	b	fast_exception_return
@@ -1606,7 +1646,12 @@
 	cmpi	0,r5,0
 	SAVE_32FPRS(0, r3)
 	mffs	fr0
-	stfd	fr0,THREAD_FPSCR-4(r3)
+	stfd	fr0,THREAD_FPSCR(r3)
+#if 0 /* PPPBBB: enable code below if we run with FE0/1 = 0,0 as default */
+	clrrdi	r4,r13,60		/* r4 <- 0xC000000000000000 */
+	lfd	fr0,__zero@l(r4)
+	mtfsf	0xff,fr0
+#endif
 	beq	1f
 	ld	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
 	li	r3,MSR_FP|MSR_FE0|MSR_FE1
@@ -1677,8 +1722,8 @@
 	sc				/* HvCall_setASR */
 #else
 	/* set the ASR */
-	addi	r3,0,0x4000     /* r3 = ptr to naca */
-	lhz   	r3,PLATFORM(r3) /* r3 = platform flags */
+	li	r3,0x5000	/* r3 = ptr to systemcfg  */
+	lwz   	r3,PLATFORM(r3) /* r3 = platform flags */
 	cmpldi 	r3,PLATFORM_PSERIES_LPAR
 	bne   	98f
 	mfspr	r3,PVR
@@ -1753,6 +1798,12 @@
 	bl	.reloc_offset
 	mr	r26,r3
 
+	/* setup the systemcfg pointer which is needed by *tab_initialize  */
+	LOADADDR(r6,systemcfg)
+	sub	r6,r6,r26                /* addr of the variable systemcfg */
+	li	r27,0x5000
+	std	r27,0(r6)	 	 /* set the value of systemcfg     */
+
 	/* setup the naca pointer which is needed by *tab_initialize       */
 	LOADADDR(r6,naca)
 	sub	r6,r6,r26                /* addr of the variable naca      */
@@ -1819,8 +1870,8 @@
 	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 */
+	li	r3,0x5000	/* r3 = ptr to systemcfg */
+	lwz   	r3,PLATFORM(r3) /* r3 = platform flags */
 	cmpldi 	r3,PLATFORM_PSERIES_LPAR
 	bne   	98f
 	mfspr	r3,PVR
@@ -1840,8 +1891,8 @@
 	bl	.stab_initialize
 	bl	.htab_initialize
 
-	addi  r3,0,0x4000     /* r3 = ptr to naca */
-	lhz   r3,PLATFORM(r3) /* r3 = platform flags */
+	li	r3,0x5000	/* r3 = ptr to systemcfg */
+	lwz	r3,PLATFORM(r3) /* r3 = platform flags */
 	cmpldi r3,PLATFORM_PSERIES
 	bne    98f
 	LOADADDR(r6,_SDR1)		/* Only if NOT LPAR */
@@ -1891,11 +1942,14 @@
 	addi    r2,r2,0x4000
 	addi    r2,r2,0x4000
 
+	/* setup the systemcfg pointer                                       */
+	LOADADDR(r9,systemcfg)
+	SET_REG_TO_CONST(r8, KERNELBASE+0x5000)
+	std	r8,0(r9)
+
 	/* setup the naca pointer                                         */
 	LOADADDR(r9,naca)
-
-	SET_REG_TO_CONST(r8, KERNELBASE)
-	addi	r8,r8,0x4000
+	SET_REG_TO_CONST(r8, KERNELBASE+0x4000)
 	std	r8,0(r9)		/* set the value of the naca ptr  */
 
 	LOADADDR(r4,naca)               /* Get naca ptr address           */
@@ -2046,7 +2100,7 @@
 hardware_int_paca0:
 	.space	8*4096
 
-/* 1 page segment table per cpu (max 48, cpu0 allocated at 0x5000) */
+/* 1 page segment table per cpu (max 48, cpu0 allocated at STAB0_PHYS_ADDR) */
 	.globl	stab_array
 stab_array:
         .space	4096 * (48 - 1)
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/htab.c linux-2.4.21-pre4/arch/ppc64/kernel/htab.c
--- linux-2.4.21-pre3/arch/ppc64/kernel/htab.c	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/htab.c	Tue Jan 28 19:44:29 2003
@@ -73,10 +73,17 @@
 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);
+inline unsigned long get_lock_slot(unsigned long vpn);
 
 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 LOCK_SPLIT
+#ifdef LOCK_SPLIT
+hash_table_lock_t hash_table_lock[128] __cacheline_aligned_in_smp = { [0 ... 31] = {SPIN_LOCK_UNLOCKED}};
+#else
+hash_table_lock_t hash_table_lock[1] __cacheline_aligned_in_smp = { [0] = {SPIN_LOCK_UNLOCKED}};
+#endif
 
 #define KB (1024)
 #define MB (1024*KB)
@@ -115,7 +122,7 @@
 {
 	unsigned long table, htab_size_bytes;
 	unsigned long pteg_count;
-	unsigned long mode_rw, mask;
+	unsigned long mode_rw, mask, lock_shift;
 
 #if 0
 	/* Can't really do the call below since it calls the normal RTAS
@@ -141,7 +148,15 @@
 	htab_data.htab_num_ptegs = pteg_count;
 	htab_data.htab_hash_mask = pteg_count - 1;
 
-	if(naca->platform == PLATFORM_PSERIES) {
+	/* 
+	 * Calculate the number of bits to shift the pteg selector such that we
+	 * use the high order 8 bits to select a page table lock.
+	 */
+	asm ("cntlzd %0,%1" : "=r" (lock_shift) : 
+	     "r" (htab_data.htab_hash_mask));
+	htab_data.htab_lock_shift = (64 - lock_shift) - 8;
+
+	if(systemcfg->platform == PLATFORM_PSERIES) {
 		/* Find storage for the HPT.  Must be contiguous in
 		 * the absolute address space.
 		 */
@@ -167,16 +182,16 @@
 	mask = pteg_count-1;
 
 	/* XXX we currently map kernel text rw, should fix this */
-	if ((naca->platform & PLATFORM_PSERIES) &&
-	   cpu_has_largepage() && (naca->physicalMemorySize > 256*MB)) {
+	if ((systemcfg->platform & PLATFORM_PSERIES) &&
+	   cpu_has_largepage() && (systemcfg->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 + (systemcfg->physicalMemorySize), 
 				   mode_rw, mask, 1);
 	} else {
 		create_pte_mapping((unsigned long)KERNELBASE, 
-				   KERNELBASE+(naca->physicalMemorySize), 
+				   KERNELBASE+(systemcfg->physicalMemorySize), 
 				   mode_rw, mask, 0);
 	}
 #if 0
@@ -220,7 +235,7 @@
 	}
 	local_hpte.dw0.dw0.v = 1;
 
-	if (naca->platform == PLATFORM_PSERIES) {
+	if (systemcfg->platform == PLATFORM_PSERIES) {
 		hptep  = htab + ((hash & hash_mask)*HPTES_PER_GROUP);
 
 		for (i = 0; i < 8; ++i, ++hptep) {
@@ -229,7 +244,7 @@
 				return;
 			}
 		}
-	} else if (naca->platform == PLATFORM_PSERIES_LPAR) {
+	} else if (systemcfg->platform == PLATFORM_PSERIES_LPAR) {
 		slot = ((hash & hash_mask)*HPTES_PER_GROUP);
 		
 		/* Set CEC cookie to 0                   */
@@ -242,12 +257,8 @@
 		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) {
+	} else if (systemcfg->platform == PLATFORM_ISERIES_LPAR) {
 		slot = HvCallHpt_findValid(&rhpte, vpn);
 		if (slot < 0) {
 			/* Must find space in primary group */
@@ -305,18 +316,19 @@
 {
 	unsigned long va, vpn;
 	unsigned long newpp, prpn;
-	unsigned long hpteflags;
+	unsigned long hpteflags, lock_slot;
 	long slot;
 	pte_t old_pte, new_pte;
 
 	/* Search the Linux page table for a match with va */
 	va = (vsid << 28) | (ea & 0x0fffffff);
 	vpn = va >> PAGE_SHIFT;
+	lock_slot = get_lock_slot(vpn); 
 
 	/* Acquire the hash table lock to guarantee that the linux
 	 * pte we fetch will not change
 	 */
-	spin_lock( &hash_table_lock );
+	spin_lock(&hash_table_lock[lock_slot].lock);
 	
 	/* 
 	 * Check the user's access rights to the page.  If access should be
@@ -324,7 +336,7 @@
 	 */
 	access |= _PAGE_PRESENT;
 	if (unlikely(access & ~(pte_val(*ptep)))) {
-		spin_unlock( &hash_table_lock );
+		spin_unlock(&hash_table_lock[lock_slot].lock);
 		return 1;
 	}
 
@@ -401,7 +413,7 @@
 		*ptep = new_pte;
 	}
 
-	spin_unlock(&hash_table_lock);
+	spin_unlock(&hash_table_lock[lock_slot].lock);
 
 	return 0;
 }
@@ -435,22 +447,21 @@
 		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 EEH_REGION_ID:
+		/*
+		 * Should only be hit if there is an access to MMIO space
+		 * which is protected by EEH.
+		 * Send the problem up to do_page_fault 
+		 */
 	case KERNEL_REGION_ID:
 		/*
-		 * As htab_initialize is now, we shouldn't ever get here since
-		 * we're bolting the entire 0xC0... region.
+		 * Should never get here - entire 0xC0... region is bolted.
+		 * Send the problem up to do_page_fault 
 		 */
-		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 */
+		/* Not a valid range
+		 * Send the problem up to do_page_fault 
+		 */
 		return 1;
 		break;
 	}
@@ -483,7 +494,7 @@
 
 void flush_hash_page(unsigned long context, unsigned long ea, pte_t *ptep)
 {
-	unsigned long vsid, vpn, va, hash, secondary, slot, flags;
+	unsigned long vsid, vpn, va, hash, secondary, slot, flags, lock_slot;
 	unsigned long large = 0, local = 0;
 	pte_t pte;
 
@@ -497,9 +508,11 @@
 		vpn = va >> LARGE_PAGE_SHIFT;
 	else
 		vpn = va >> PAGE_SHIFT;
+
+	lock_slot = get_lock_slot(vpn); 
 	hash = hpt_hash(vpn, large);
 
-	spin_lock_irqsave( &hash_table_lock, flags);
+	spin_lock_irqsave(&hash_table_lock[lock_slot].lock, flags);
 
 	pte = __pte(pte_update(ptep, _PAGE_HPTEFLAGS, 0));
 	secondary = (pte_val(pte) & _PAGE_SECONDARY) >> 15;
@@ -511,7 +524,7 @@
 		ppc_md.hpte_invalidate(slot, secondary, va, large, local);
 	}
 
-	spin_unlock_irqrestore( &hash_table_lock, flags );
+	spin_unlock_irqrestore(&hash_table_lock[lock_slot].lock, flags);
 }
 
 long plpar_pte_enter(unsigned long flags,
@@ -567,6 +580,26 @@
 }
 
 /*
+ * Calculate which hash_table_lock to use, based on the pteg being used.
+ *
+ * Given a VPN, use the high order 8 bits to select one of 2^7 locks.  The
+ * highest order bit is used to indicate primary vs. secondary group.  If the
+ * secondary is selected, complement the lock select bits.  This results in
+ * both the primary and secondary groups being covered under the same lock.
+ */
+inline unsigned long get_lock_slot(unsigned long vpn)
+{
+	unsigned long lock_slot;
+#ifdef LOCK_SPLIT
+	lock_slot = (hpt_hash(vpn,0) >> htab_data.htab_lock_shift) & 0xff;
+	if(lock_slot & 0x80) lock_slot = (~lock_slot) & 0x7f;
+#else
+	lock_slot = 0;
+#endif
+	return(lock_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 
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/iSeries_IoMmTable.c linux-2.4.21-pre4/arch/ppc64/kernel/iSeries_IoMmTable.c
--- linux-2.4.21-pre3/arch/ppc64/kernel/iSeries_IoMmTable.c	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/iSeries_IoMmTable.c	Tue Jan 28 19:44:29 2003
@@ -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 ROM      */
+/* - Loops through The Bar resources(0 - 5) including the ROM      */
 /*   is resource(6).                                               */
 /*******************************************************************/
 void iSeries_allocateDeviceBars(struct pci_dev* PciDev)
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/iSeries_VpdInfo.c linux-2.4.21-pre4/arch/ppc64/kernel/iSeries_VpdInfo.c
--- linux-2.4.21-pre3/arch/ppc64/kernel/iSeries_VpdInfo.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/iSeries_VpdInfo.c	Tue Jan 28 19:44:29 2003
@@ -164,7 +164,8 @@
 	/* Parse Slot label until we find the one requrested         */
 	/*************************************************************/
 	while (SlotMapLen > 0) {
-		if (SlotMapPtr->AgentId == DevNode->AgentId ) {
+		if ((SlotMapPtr->AgentId == DevNode->AgentId) && 
+		    (SlotMapPtr->SecondaryAgentId == 0x10   ) ) {
 			/*******************************************************/
 			/* If Phb wasn't found, grab the entry first one found.*/ 
 			/*******************************************************/
@@ -300,7 +301,7 @@
 		printk("PCI: Bus VPD Buffer zero length.\n");
 		return;
 	}
-	//printk("PCI: BusVpdPtr: %p, %d\n",BusVpdPtr, BusVpdLen);
+	//printk("PCI: DevNode:0x%p BusVpdPtr:0x%p Length:%d\n",DevNode, BusVpdPtr, BusVpdLen);
 	/*************************************************************/
 	/* Make sure this is what I think it is                      */
 	/*************************************************************/
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/iSeries_pci.c linux-2.4.21-pre4/arch/ppc64/kernel/iSeries_pci.c
--- linux-2.4.21-pre3/arch/ppc64/kernel/iSeries_pci.c	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/iSeries_pci.c	Tue Jan 28 19:44:29 2003
@@ -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
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/iSeries_setup.c linux-2.4.21-pre4/arch/ppc64/kernel/iSeries_setup.c
--- linux-2.4.21-pre3/arch/ppc64/kernel/iSeries_setup.c	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/iSeries_setup.c	Tue Jan 28 19:44:29 2003
@@ -1,6 +1,4 @@
 /*
- * 
- *
  *    Copyright (c) 2000 Mike Corrigan <mikejc@us.ibm.com>
  *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
  *
@@ -431,7 +429,7 @@
 	u32 chunkBit;
 	u64 map;
 	struct MemoryBlock mb[32];
-	unsigned long numMemoryBlocks, curBlock;
+	unsigned long numMemoryBlocks, curBlock, lock_shift;
 
 	/* Chunk size on iSeries is 256K bytes */
 	totalChunks = (u32)HvLpConfig_getMsChunks();
@@ -493,6 +491,13 @@
 	htab_data.htab_num_ptegs = num_ptegs;
 	htab_data.htab_hash_mask = num_ptegs - 1;
 	
+	/* 
+	 * Calculate the number of bits to shift the pteg selector such that we
+	 * use the high order 8 bits to select a page table lock.
+	 */
+	asm ("cntlzd %0,%1" : "=r" (lock_shift) : "r" (htab_data.htab_hash_mask));
+	htab_data.htab_lock_shift = (64 - lock_shift) - 8;
+
 	/* The actual hashed page table is in the hypervisor, we have no direct access */
 	htab_data.htab = NULL;
 
@@ -550,13 +555,13 @@
 	 * which should be equal to 
 	 *   nextPhysChunk
 	 */
-	naca->physicalMemorySize = chunk_to_addr(nextPhysChunk);
+	systemcfg->physicalMemorySize = chunk_to_addr(nextPhysChunk);
 
 	/* Bolt kernel mappings for all of memory */
-	iSeries_bolt_kernel( 0, naca->physicalMemorySize );
+	iSeries_bolt_kernel(0, systemcfg->physicalMemorySize);
 
 	lmb_init();
-	lmb_add( 0, naca->physicalMemorySize );
+	lmb_add(0, systemcfg->physicalMemorySize);
 	lmb_analyze();	/* ?? */
 	lmb_reserve( 0, __pa(klimit));
 
@@ -576,26 +581,24 @@
 	unsigned i,n;
 	unsigned procIx = get_paca()->xLpPaca.xDynHvPhysicalProcIndex;
 
-	naca->iCacheL1LineSize = xIoHriProcessorVpd[procIx].xInstCacheOperandSize;
-	naca->dCacheL1LineSize = xIoHriProcessorVpd[procIx].xDataCacheOperandSize;
-	naca->iCacheL1LinesPerPage = PAGE_SIZE / naca->iCacheL1LineSize;
-	naca->dCacheL1LinesPerPage = PAGE_SIZE / naca->dCacheL1LineSize;
-	i = naca->iCacheL1LineSize;
+	systemcfg->iCacheL1Size = xIoHriProcessorVpd[procIx].xInstCacheSize * 1024;
+	systemcfg->iCacheL1LineSize = xIoHriProcessorVpd[procIx].xInstCacheOperandSize;
+	systemcfg->dCacheL1Size = xIoHriProcessorVpd[procIx].xDataL1CacheSizeKB * 1024;
+	systemcfg->dCacheL1LineSize = xIoHriProcessorVpd[procIx].xDataCacheOperandSize;
+	naca->iCacheL1LinesPerPage = PAGE_SIZE / systemcfg->iCacheL1LineSize;
+	naca->dCacheL1LinesPerPage = PAGE_SIZE / systemcfg->dCacheL1LineSize;
+
+	i = systemcfg->iCacheL1LineSize;
 	n = 0;
 	while ((i=(i/2))) ++n;
 	naca->iCacheL1LogLineSize = n;
-	i = naca->dCacheL1LineSize;
+	i = systemcfg->dCacheL1LineSize;
 	n = 0;
 	while ((i=(i/2))) ++n;
 	naca->dCacheL1LogLineSize = n;
 
-	printk( "D-cache line size = %d  (log = %d)\n",
-			(unsigned)naca->dCacheL1LineSize,
-			(unsigned)naca->dCacheL1LogLineSize );
-	printk( "I-cache line size = %d  (log = %d)\n",
-			(unsigned)naca->iCacheL1LineSize,
-			(unsigned)naca->iCacheL1LogLineSize );
-	
+	printk( "D-cache line size = %d\n", (unsigned)systemcfg->dCacheL1LineSize);
+	printk( "I-cache line size = %d\n", (unsigned)systemcfg->iCacheL1LineSize);
 }
 
 /*
@@ -637,6 +640,12 @@
 	void *	eventStack;
 	unsigned procIx = get_paca()->xLpPaca.xDynHvPhysicalProcIndex;
 
+        /* Add an eye catcher and the systemcfg layout version number */
+        strcpy(systemcfg->eye_catcher, "SYSTEMCFG:PPC64");
+        systemcfg->version.major = SYSTEMCFG_MAJOR;
+        systemcfg->version.minor = SYSTEMCFG_MINOR;
+
+
 	/* Setup the Lp Event Queue */
 
 	/* Allocate a page for the Event Stack
@@ -685,8 +694,8 @@
 	printk("Time base frequency = %lu.%02lu\n",
 			tbFreqMhz,
 			tbFreqMhzHundreths );
-	printk("Processor version = %x\n",
-			xIoHriProcessorVpd[procIx].xPVR );
+	systemcfg->processor = xIoHriProcessorVpd[procIx].xPVR;
+	printk("Processor version = %x\n", systemcfg->processor);
 
 }
 
@@ -715,9 +724,9 @@
 	seq_printf(m,"time base\t: %lu.%02luMHz\n",
 		tbFreqMhz, tbFreqMhzHundreths );
 	seq_printf(m,"i-cache\t\t: %d\n",
-		naca->iCacheL1LineSize);
+		systemcfg->iCacheL1LineSize);
 	seq_printf(m,"d-cache\t\t: %d\n",
-		naca->dCacheL1LineSize);
+		systemcfg->dCacheL1LineSize);
 
 }
 
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/idle.c linux-2.4.21-pre4/arch/ppc64/kernel/idle.c
--- linux-2.4.21-pre3/arch/ppc64/kernel/idle.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/idle.c	Tue Jan 28 19:44:29 2003
@@ -34,36 +34,28 @@
 #include <asm/iSeries/HvCall.h>
 #include <asm/iSeries/ItLpQueue.h>
 
-unsigned long maxYieldTime = 0;
-unsigned long minYieldTime = 0xffffffffffffffffUL;
-
 #ifdef CONFIG_PPC_ISERIES
 static void yield_shared_processor(void)
 {
 	struct paca_struct *lpaca = get_paca();
 	unsigned long tb;
-	unsigned long yieldTime;
 
 	HvCall_setEnabledInterrupts( HvCall_MaskIPI |
 				     HvCall_MaskLpEvent |
 				     HvCall_MaskLpProd |
 				     HvCall_MaskTimeout );
 
-	tb = get_tb();
-	/* Compute future tb value when yield should expire */
-	HvCall_yieldProcessor( HvCall_YieldTimed, tb+tb_ticks_per_jiffy );
-
-	yieldTime = get_tb() - tb;
-	if ( yieldTime > maxYieldTime )
-		maxYieldTime = yieldTime;
-
-	if ( yieldTime < minYieldTime )
-		minYieldTime = yieldTime;
-	
-	/* The decrementer stops during the yield.  Force a fake decrementer
-	 * here and let the timer_interrupt code sort out the actual time.
-	 */
-	lpaca->xLpPaca.xIntDword.xFields.xDecrInt = 1;
+	if ( ! ItLpQueue_isLpIntPending( paca->lpQueuePtr ) ) {
+	  tb = get_tb();
+	  /* Compute future tb value when yield should expire */
+	  HvCall_yieldProcessor( HvCall_YieldTimed, tb+tb_ticks_per_jiffy );
+	  
+	  /* The decrementer stops during the yield.  Force a fake decrementer
+	   * here and let the timer_interrupt code sort out the actual time.
+	   */
+	  lpaca->xLpPaca.xIntDword.xFields.xDecrInt = 1;
+	}
+	  
 	process_iSeries_events();
 }
 #endif /* CONFIG_PPC_ISERIES */
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/ioctl32.c linux-2.4.21-pre4/arch/ppc64/kernel/ioctl32.c
--- linux-2.4.21-pre3/arch/ppc64/kernel/ioctl32.c	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/ioctl32.c	Tue Jan 28 19:44:29 2003
@@ -838,6 +838,34 @@
 	return err ? -EFAULT : 0;
 }
 
+struct hd_big_geometry32 {
+	u8 heads;
+	u8 sectors;
+	u32 cylinders;
+	u32 start;
+};
+
+static int hdio_getgeo_big(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	struct hd_big_geometry geo;
+	int err;
+	
+	set_fs (KERNEL_DS);
+	err = sys_ioctl(fd, HDIO_GETGEO_BIG, (unsigned long)&geo);
+	set_fs (old_fs);
+	if (err)
+		return err;
+	else {
+		struct hd_big_geometry32 *user_geo = (struct hd_big_geometry32 *)arg;
+		err = __put_user (geo.heads, &(user_geo->heads));
+		err |= __put_user (geo.sectors, &(user_geo->sectors));
+		err |= __put_user (geo.cylinders, &(user_geo->cylinders));
+		err |= __put_user (geo.start, &(user_geo->start));
+	}
+	return err ? -EFAULT : 0;
+}
+
 
 static int hdio_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
@@ -3706,6 +3734,39 @@
 	return ((0 == ret) ? 0 : -EFAULT);
 }	
 
+/* Fix sizeof(sizeof()) breakage */
+#define BLKELVGET_32	_IOR(0x12,106,int)
+#define BLKELVSET_32	_IOW(0x12,107,int)
+#define BLKBSZGET_32	_IOR(0x12,112,int)
+#define BLKBSZSET_32	_IOW(0x12,113,int)
+#define BLKGETSIZE64_32	_IOR(0x12,114,int)
+
+static int do_blkelvget(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	return sys_ioctl(fd, BLKELVGET, arg);
+}
+
+static int do_blkelvset(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	return sys_ioctl(fd, BLKELVSET, arg);
+}
+
+static int do_blkbszget(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	return sys_ioctl(fd, BLKBSZGET, arg);
+}
+
+static int do_blkbszset(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	return sys_ioctl(fd, BLKBSZSET, arg);
+}
+
+static int do_blkgetsize64(unsigned int fd, unsigned int cmd,
+			   unsigned long arg)
+{
+	return sys_ioctl(fd, BLKGETSIZE64, arg);
+}
+
 struct ioctl_trans {
 	unsigned long cmd;
 	unsigned long handler;
@@ -4417,6 +4478,8 @@
 HANDLE_IOCTL(SIOCRTMSG, ret_einval),
 HANDLE_IOCTL(SIOCGSTAMP, do_siocgstamp),
 HANDLE_IOCTL(HDIO_GETGEO, hdio_getgeo),
+HANDLE_IOCTL(HDIO_GETGEO_BIG, hdio_getgeo_big),
+HANDLE_IOCTL(HDIO_GETGEO_BIG_RAW, hdio_getgeo_big),
 HANDLE_IOCTL(BLKRAGET, w_long),
 HANDLE_IOCTL(BLKGETSIZE, w_long),
 HANDLE_IOCTL(0x1260, broken_blkgetsize),
@@ -4534,6 +4597,14 @@
 HANDLE_IOCTL(USBDEVFS_REAPURB32, do_usbdevfs_reapurb),
 HANDLE_IOCTL(USBDEVFS_REAPURBNDELAY32, do_usbdevfs_reapurb),
 HANDLE_IOCTL(USBDEVFS_DISCSIGNAL32, do_usbdevfs_discsignal),
+/* take care of sizeof(sizeof()) breakage */
+/* elevator */
+HANDLE_IOCTL(BLKELVGET_32, do_blkelvget),
+HANDLE_IOCTL(BLKELVSET_32, do_blkelvset),
+/* block stuff */
+HANDLE_IOCTL(BLKBSZGET_32, do_blkbszget),
+HANDLE_IOCTL(BLKBSZSET_32, do_blkbszset),
+HANDLE_IOCTL(BLKGETSIZE64_32, do_blkgetsize64),
 };
 
 unsigned long ioctl32_hash_table[1024];
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/misc.S linux-2.4.21-pre4/arch/ppc64/kernel/misc.S
--- linux-2.4.21-pre3/arch/ppc64/kernel/misc.S	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/misc.S	Tue Jan 28 19:44:29 2003
@@ -165,12 +165,14 @@
  */
 	LOADADDR(r10,naca)		/* Get Naca address */
 	ld	r10,0(r10)
-	lhz	r7,DCACHEL1LINESIZE(r10)	/* Get cache line size */
+	LOADADDR(r11,systemcfg)		/* Get systemcfg address */
+	ld	r11,0(r11)
+	lwz	r7,DCACHEL1LINESIZE(r11)	/* Get cache line size */
 	addi	r5,r7,-1
 	andc	r6,r3,r5		/* round low to line bdy */
 	subf	r8,r6,r4		/* compute length */
 	add	r8,r8,r5		/* ensure we get enough */
-	lhz	r9,DCACHEL1LOGLINESIZE(r10)	/* Get log-2 of cache line size */
+	lwz	r9,DCACHEL1LOGLINESIZE(r10)	/* Get log-2 of cache line size */
 	srw.	r8,r8,r9		/* compute line count */
 	beqlr				/* nothing to do? */
 	mtctr	r8
@@ -181,12 +183,12 @@
 
 /* Now invalidate the instruction cache */
 	
-	lhz	r7,ICACHEL1LINESIZE(r10)	/* Get Icache line size */
+	lwz	r7,ICACHEL1LINESIZE(r11)	/* Get Icache line size */
 	addi	r5,r7,-1
 	andc	r6,r3,r5		/* round low to line bdy */
 	subf	r8,r6,r4		/* compute length */
 	add	r8,r8,r5
-	lhz	r9,ICACHEL1LOGLINESIZE(r10)	/* Get log-2 of Icache line size */
+	lwz	r9,ICACHEL1LOGLINESIZE(r10)	/* Get log-2 of Icache line size */
 	srw.	r8,r8,r9		/* compute line count */
 	beqlr				/* nothing to do? */
 	mtctr	r8
@@ -212,12 +214,14 @@
  */
 	LOADADDR(r10,naca)		/* Get Naca address */
 	ld	r10,0(r10)
-	lhz	r7,DCACHEL1LINESIZE(r10)	/* Get dcache line size */
+	LOADADDR(r11,systemcfg)		/* Get systemcfg address */
+	ld	r11,0(r11)
+	lwz	r7,DCACHEL1LINESIZE(r11)	/* Get dcache line size */
 	addi	r5,r7,-1
 	andc	r6,r3,r5		/* round low to line bdy */
 	subf	r8,r6,r4		/* compute length */
 	add	r8,r8,r5		/* ensure we get enough */
-	lhz	r9,DCACHEL1LOGLINESIZE(r10)	/* Get log-2 of dcache line size */
+	lwz	r9,DCACHEL1LOGLINESIZE(r10)	/* Get log-2 of dcache line size */
 	srw.	r8,r8,r9		/* compute line count */
 	beqlr				/* nothing to do? */
 	mtctr	r8
@@ -244,9 +248,11 @@
 /* Flush the dcache */
 	LOADADDR(r7,naca)
 	ld	r7,0(r7)
+	LOADADDR(r8,systemcfg)			/* Get systemcfg address */
+	ld	r8,0(r8)
 	clrrdi	r3,r3,12           	    /* Page align */
-	lhz	r4,DCACHEL1LINESPERPAGE(r7)	/* Get # dcache lines per page */
-	lhz	r5,DCACHEL1LINESIZE(r7)		/* Get dcache line size */
+	lwz	r4,DCACHEL1LINESPERPAGE(r7)	/* Get # dcache lines per page */
+	lwz	r5,DCACHEL1LINESIZE(r8)		/* Get dcache line size */
 	mr	r6,r3
 	mtctr	r4
 0:	dcbst	0,r6
@@ -256,8 +262,8 @@
 
 /* Now invalidate the icache */	
 
-	lhz	r4,ICACHEL1LINESPERPAGE(r7)	/* Get # icache lines per page */
-	lhz	r5,ICACHEL1LINESIZE(r7)		/* Get icache line size */
+	lwz	r4,ICACHEL1LINESPERPAGE(r7)	/* Get # icache lines per page */
+	lwz	r5,ICACHEL1LINESIZE(r8)		/* Get icache line size */
 	mtctr	r4
 1:	icbi	0,r3
 	add	r3,r3,r5
@@ -266,24 +272,6 @@
 	blr
 	
 /*
- * Copy a whole page.  Assumes a 4096B page size.
- */
-_GLOBAL(copy_page)
-	clrrdi	r3,r3,12           	    /* Page align */
-	clrrdi	r4,r4,12           	    /* Page align */
-	li	r5,256
-	mtctr	r5
-	addi	r3,r3,-8
-	addi	r4,r4,-8
-
-1:      ld 	r6,8(r4)
-        ldu	r7,16(r4)
-	std     r6,8(r3) 
-	stdu    r7,16(r3) 
-	bdnz+	1b
-	blr  
-
-/*
  * I/O string operations
  *
  * insb(port, buf, len)
@@ -474,21 +462,21 @@
 	blr
 
 _GLOBAL(cvt_fd)
-	lfd	0,-4(r5)	/* load up fpscr value */
+	lfd	0,0(r5)		/* load up fpscr value */
 	mtfsf	0xff,0
 	lfs	0,0(r3)
 	stfd	0,0(r4)
 	mffs	0		/* save new fpscr value */
-	stfd	0,-4(r5)
+	stfd	0,0(r5)
 	blr
 
 _GLOBAL(cvt_df)
-	lfd	0,-4(r5)	/* load up fpscr value */
+	lfd	0,0(r5)		/* load up fpscr value */
 	mtfsf	0xff,0
 	lfd	0,0(r3)
 	stfs	0,0(r4)
 	mffs	0		/* save new fpscr value */
-	stfd	0,-4(r5)
+	stfd	0,0(r5)
 	blr
 
 /*
@@ -535,8 +523,8 @@
 	.llong .sys32_execve
 	.llong .sys_chdir
 	.llong .sys32_time
-	.llong .sys32_mknod
-	.llong .sys32_chmod		/* 15 */
+	.llong .sys_mknod
+	.llong .sys_chmod		/* 15 */
 	.llong .sys_lchown
 	.llong .sys_ni_syscall			/* old break syscall holder */
 	.llong .sys32_stat
@@ -603,7 +591,7 @@
 	.llong .sys32_settimeofday
 	.llong .sys32_getgroups	        /* 80 */
 	.llong .sys32_setgroups
-	.llong .ppc32_select
+	.llong .sys_ni_syscall		/* old select syscall */
 	.llong .sys_symlink
 	.llong .sys32_lstat
 	.llong .sys32_readlink	        /* 85 */
@@ -622,7 +610,7 @@
 	.llong .sys_ni_syscall			/* old profil syscall holder */
 	.llong .sys32_statfs
 	.llong .sys32_fstatfs	/* 100 */
-	.llong .sys32_ioperm
+	.llong .sys_ioperm
 	.llong .sys32_socketcall
 	.llong .sys32_syslog
 	.llong .sys32_setitimer
@@ -631,10 +619,10 @@
 	.llong .sys32_newlstat
 	.llong .sys32_newfstat
 	.llong .sys_uname
-	.llong .sys32_iopl		/* 110 */
+	.llong .sys_ni_syscall		/* 110 old iopl syscall */
 	.llong .sys_vhangup
 	.llong .sys_ni_syscall	/* old 'idle' syscall */
-	.llong .sys32_vm86
+	.llong .sys_ni_syscall		/* old vm86 syscall */
 	.llong .sys32_wait4
 	.llong .sys_swapoff	/* 115 */
 	.llong .sys32_sysinfo
@@ -644,7 +632,7 @@
 	.llong .sys32_clone		/* 120 */
 	.llong .sys32_setdomainname
 	.llong .ppc64_newuname
-	.llong .sys32_modify_ldt
+	.llong .sys_ni_syscall		/* old modify_ldt syscall */
 	.llong .sys32_adjtimex
 	.llong .sys_mprotect	/* 125 */
 	.llong .sys32_sigprocmask
@@ -712,8 +700,8 @@
 	.llong .sys_ni_syscall		/* streams2 */
 	.llong .sys32_vfork
 	.llong .sys32_getrlimit	        /* 190 */
-	.llong .sys_ni_syscall		/* 191 */	/* Unused */
-	.llong .sys_ni_syscall		/* 192 - reserved - mmap2 */
+	.llong .sys32_readahead
+	.llong .ppc32_mmap2
 	.llong .sys32_truncate64	/* 193 - truncate64 */
 	.llong .sys32_ftruncate64	/* 194 - ftruncate64 */
 	.llong .sys_stat64      	/* 195 - stat64 */
@@ -774,7 +762,7 @@
 	.llong .sys_lseek
 	.llong .sys_getpid	/* 20 */
 	.llong .sys_mount
-	.llong .sys_oldumount
+	.llong .sys_ni_syscall		/* old umount syscall */
 	.llong .sys_setuid
 	.llong .sys_getuid
 	.llong .ppc64_sys_stime		/* 25 */
@@ -811,7 +799,7 @@
 	.llong .sys_ni_syscall			/* old mpx syscall holder */
 	.llong .sys_setpgid
 	.llong .sys_ni_syscall			/* old ulimit syscall holder */
-	.llong .sys_olduname
+	.llong .sys_ni_syscall		/* old uname syscall */
 	.llong .sys_umask		/* 60 */
 	.llong .sys_chroot
 	.llong .sys_ustat
@@ -828,20 +816,20 @@
 	.llong .sys_sigpending
 	.llong .sys_sethostname
 	.llong .sys_setrlimit	/* 75 */
-	.llong .sys_old_getrlimit
+	.llong .sys_ni_syscall		/* old getrlimit syscall */
 	.llong .sys_getrusage
 	.llong .sys_gettimeofday
 	.llong .sys_settimeofday
 	.llong .sys_getgroups	/* 80 */
 	.llong .sys_setgroups
-	.llong .sys_select
+	.llong .sys_ni_syscall		/* old select syscall */
 	.llong .sys_symlink
 	.llong .sys_lstat
 	.llong .sys_readlink	/* 85 */
 	.llong .sys_uselib
 	.llong .sys_swapon
 	.llong .sys_reboot
-	.llong .old_readdir
+	.llong .sys_ni_syscall		/* old readdir syscall */
 	.llong .sys_mmap	/* 90 */
 	.llong .sys_munmap
 	.llong .sys_truncate
@@ -862,10 +850,10 @@
 	.llong .sys_newlstat
 	.llong .sys_newfstat
 	.llong .sys_uname
-	.llong .sys_iopl		/* 110 */
+	.llong .sys_ni_syscall		/* 110 old iopl syscall */
 	.llong .sys_vhangup
 	.llong .sys_ni_syscall	/* old 'idle' syscall */
-	.llong .sys_vm86
+	.llong .sys_ni_syscall		/* old vm86 syscall */
 	.llong .sys_wait4
 	.llong .sys_swapoff	/* 115 */
 	.llong .sys_sysinfo
@@ -875,7 +863,7 @@
 	.llong .sys_clone		/* 120 */
 	.llong .sys_setdomainname
 	.llong .ppc64_newuname
-	.llong .sys_modify_ldt
+	.llong .sys_ni_syscall		/* old modify_ldt syscall */
 	.llong .sys_adjtimex
 	.llong .sys_mprotect	/* 125 */
 	.llong .sys_sigprocmask
@@ -943,7 +931,7 @@
 	.llong .sys_ni_syscall		/* streams2 */
 	.llong .sys_vfork
 	.llong .sys_getrlimit	        /* 190 */
-	.llong .sys_ni_syscall		/* 191 */	/* Unused */
+	.llong .sys_readahead
 	.llong .sys_ni_syscall		/* 192 - reserved - mmap2 */
 	.llong .sys_ni_syscall		/* 193 - reserved - truncate64 */
 	.llong .sys_ni_syscall		/* 194 - reserved - ftruncate64 */
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/mk_defs.c linux-2.4.21-pre4/arch/ppc64/kernel/mk_defs.c
--- linux-2.4.21-pre3/arch/ppc64/kernel/mk_defs.c	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/mk_defs.c	Tue Jan 28 19:44:29 2003
@@ -39,7 +39,7 @@
 #include <asm/rtas.h>
 
 #define DEFINE(sym, val) \
-	        asm volatile("\n#define\t" #sym "\t%0" : : "i" (val))
+	asm volatile("\n#define\t" #sym "\t%0" : : "i" (val))
 
 int
 main(void)
@@ -50,29 +50,28 @@
 	DEFINE(TASK_STRUCT_SIZE, sizeof(struct task_struct));
 	DEFINE(KSP, offsetof(struct thread_struct, ksp));
 
-        DEFINE(PACA, offsetof(struct naca_struct, paca));
-        DEFINE(PACA_SIZE, sizeof(struct paca_struct));
-
-        DEFINE(DCACHEL1LINESIZE, offsetof(struct naca_struct, dCacheL1LineSize));
-        DEFINE(DCACHEL1LOGLINESIZE, offsetof(struct naca_struct, dCacheL1LogLineSize));
-        DEFINE(DCACHEL1LINESPERPAGE, offsetof(struct naca_struct, dCacheL1LinesPerPage));
-
-        DEFINE(ICACHEL1LINESIZE, offsetof(struct naca_struct, iCacheL1LineSize));
-        DEFINE(ICACHEL1LOGLINESIZE, offsetof(struct naca_struct, iCacheL1LogLineSize));
-        DEFINE(ICACHEL1LINESPERPAGE, offsetof(struct naca_struct, iCacheL1LinesPerPage));
+	DEFINE(PACA, offsetof(struct naca_struct, paca));
 	DEFINE(SLBSIZE, offsetof(struct naca_struct, slb_size));
-	DEFINE(PLATFORM, offsetof(struct naca_struct, platform));
-
-        DEFINE(PACAPACAINDEX, offsetof(struct paca_struct, xPacaIndex));
-        DEFINE(PACAPROCSTART, offsetof(struct paca_struct, xProcStart));
-        DEFINE(PACAKSAVE, offsetof(struct paca_struct, xKsave));
+	DEFINE(DCACHEL1LOGLINESIZE, offsetof(struct naca_struct, dCacheL1LogLineSize));
+	DEFINE(DCACHEL1LINESPERPAGE, offsetof(struct naca_struct, dCacheL1LinesPerPage));
+	DEFINE(ICACHEL1LOGLINESIZE, offsetof(struct naca_struct, iCacheL1LogLineSize));
+	DEFINE(ICACHEL1LINESPERPAGE, offsetof(struct naca_struct, iCacheL1LinesPerPage));
+
+	DEFINE(DCACHEL1LINESIZE, offsetof(struct systemcfg, dCacheL1LineSize));
+	DEFINE(ICACHEL1LINESIZE, offsetof(struct systemcfg, iCacheL1LineSize));
+	DEFINE(PLATFORM, offsetof(struct systemcfg, platform));
+
+	DEFINE(PACA_SIZE, sizeof(struct paca_struct));
+	DEFINE(PACAPACAINDEX, offsetof(struct paca_struct, xPacaIndex));
+	DEFINE(PACAPROCSTART, offsetof(struct paca_struct, xProcStart));
+	DEFINE(PACAKSAVE, offsetof(struct paca_struct, xKsave));
 	DEFINE(PACACURRENT, offsetof(struct paca_struct, xCurrent));
-        DEFINE(PACASAVEDMSR, offsetof(struct paca_struct, xSavedMsr));
-        DEFINE(PACASTABREAL, offsetof(struct paca_struct, xStab_data.real));
-        DEFINE(PACASTABVIRT, offsetof(struct paca_struct, xStab_data.virt));
+	DEFINE(PACASAVEDMSR, offsetof(struct paca_struct, xSavedMsr));
+	DEFINE(PACASTABREAL, offsetof(struct paca_struct, xStab_data.real));
+	DEFINE(PACASTABVIRT, offsetof(struct paca_struct, xStab_data.virt));
 	DEFINE(PACASTABRR, offsetof(struct paca_struct, xStab_data.next_round_robin));
-        DEFINE(PACAR1, offsetof(struct paca_struct, xR1));
-        DEFINE(PACALPQUEUE, offsetof(struct paca_struct, lpQueuePtr));
+	DEFINE(PACAR1, offsetof(struct paca_struct, xR1));
+	DEFINE(PACALPQUEUE, offsetof(struct paca_struct, lpQueuePtr));
 	DEFINE(PACATOC, offsetof(struct paca_struct, xTOC));
 	DEFINE(PACAEXCSP, offsetof(struct paca_struct, exception_sp));
 	DEFINE(PACAHRDWINTSTACK, offsetof(struct paca_struct, xHrdIntStack));
@@ -107,18 +106,18 @@
 	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));
-        DEFINE(PACAEXC, offsetof(struct paca_struct, exception_stack));
-        DEFINE(PACAGUARD, offsetof(struct paca_struct, guard));
-        DEFINE(LPPACASRR0, offsetof(struct ItLpPaca, xSavedSrr0));
-        DEFINE(LPPACASRR1, offsetof(struct ItLpPaca, xSavedSrr1));
+	DEFINE(LPPACA, offsetof(struct paca_struct, xLpPaca));
+	DEFINE(PACAREGSAV, offsetof(struct paca_struct, xRegSav));
+	DEFINE(PACAEXC, offsetof(struct paca_struct, exception_stack));
+	DEFINE(PACAGUARD, offsetof(struct paca_struct, guard));
+	DEFINE(LPPACASRR0, offsetof(struct ItLpPaca, xSavedSrr0));
+	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));
+	DEFINE(LPQCUREVENTPTR, offsetof(struct ItLpQueue, xSlicCurEventPtr));
+	DEFINE(LPQOVERFLOW, offsetof(struct ItLpQueue, xPlicOverflowIntPending));
+	DEFINE(LPEVENTFLAGS, offsetof(struct HvLpEvent, xFlags));
 	DEFINE(PROMENTRY, offsetof(struct prom_t, entry));
 
 	DEFINE(RTASBASE, offsetof(struct rtas_t, base));
@@ -131,18 +130,25 @@
 	DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
 	DEFINE(NEED_RESCHED, offsetof(struct task_struct, need_resched));
 	DEFINE(THREAD_FPR0, offsetof(struct thread_struct, fpr[0]));
+	DEFINE(THREAD_FPEXC_MODE, offsetof(struct thread_struct, fpexc_mode));
 	DEFINE(THREAD_FPSCR, offsetof(struct thread_struct, fpscr));
 	DEFINE(THREAD_FLAGS, offsetof(struct thread_struct, flags));
 	DEFINE(PPC_FLAG_32BIT, PPC_FLAG_32BIT);
-	/* Interrupt register frame */
+	/*
+	 * Interrupt register frame
+	 */
 	DEFINE(TASK_UNION_SIZE, sizeof(union task_union));
 	DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD);
-        /* 288 = # of volatile regs, int & fp, for leaf routines */
-        /* which do not stack a frame.  See the PPC64 ABI.       */
-        DEFINE(INT_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 288);
-	/* Create extra stack space for SRR0 and SRR1 when calling prom/rtas. */
-        DEFINE(PROM_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16 + 288);
-        DEFINE(RTAS_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16 + 288);
+	/*
+	 * 288 = # of volatile regs, int & fp, for leaf routines
+	 * which do not stack a frame.  See the PPC64 ABI.
+	 */
+	DEFINE(INT_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 288);
+	/*
+	 * Create extra stack space for SRR0 and SRR1 when calling prom/rtas.
+	 */
+	DEFINE(PROM_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16 + 288);
+	DEFINE(RTAS_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16 + 288);
 	DEFINE(GPR0, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[0]));
 	DEFINE(GPR1, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[1]));
 	DEFINE(GPR2, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[2]));
@@ -157,7 +163,8 @@
 	DEFINE(GPR21, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[21]));
 	DEFINE(GPR22, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[22]));
 	DEFINE(GPR23, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[23]));
-	/* Note: these symbols include _ because they overlap with special
+	/*
+	 * Note: these symbols include _ because they overlap with special
 	 * register names
 	 */
 	DEFINE(_NIP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, nip));
@@ -173,7 +180,9 @@
 	DEFINE(TRAP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap));
 	DEFINE(SOFTE, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, softe));
 
-	/* These _only_ to be used with {PROM,RTAS}_FRAME_SIZE!!! */
+	/*
+	 * These _only_ to be used with {PROM,RTAS}_FRAME_SIZE!!!
+	 */
 	DEFINE(_SRR0, STACK_FRAME_OVERHEAD+sizeof(struct pt_regs));
 	DEFINE(_SRR1, STACK_FRAME_OVERHEAD+sizeof(struct pt_regs)+8);
 
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/nvram.c linux-2.4.21-pre4/arch/ppc64/kernel/nvram.c
--- linux-2.4.21-pre3/arch/ppc64/kernel/nvram.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/nvram.c	Tue Jan 28 19:44:29 2003
@@ -99,11 +99,11 @@
 }
 
 struct file_operations nvram_fops = {
-	owner:		THIS_MODULE,
-	llseek:		nvram_llseek,
-	read:		read_nvram,
-	write:		write_nvram,
-	ioctl:		nvram_ioctl,
+	.owner =	THIS_MODULE,
+	.llseek =	nvram_llseek,
+	.read =		read_nvram,
+	.write =	write_nvram,
+	.ioctl =	nvram_ioctl,
 };
 
 static struct miscdevice nvram_dev = {
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/pSeries_pci.c linux-2.4.21-pre4/arch/ppc64/kernel/pSeries_pci.c
--- linux-2.4.21-pre3/arch/ppc64/kernel/pSeries_pci.c	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/pSeries_pci.c	Tue Jan 28 19:44:29 2003
@@ -1,7 +1,7 @@
 /*
  * pSeries_pci.c
  *
- * pSeries_pcibios_init(void)opyright (C) 2001 Dave Engebretsen, IBM Corporation
+ * Copyright (C) 2001 Dave Engebretsen, IBM Corporation
  *
  * pSeries specific routines for PCI.
  * 
@@ -39,7 +39,6 @@
 #include <asm/ppcdebug.h>
 #include <asm/naca.h>
 #include <asm/pci_dma.h>
-#include <asm/eeh.h>
 
 #include "xics.h"
 #include "open_pic.h"
@@ -78,6 +77,8 @@
 	 \
 	if (dn == NULL) { \
 		ret = -2; \
+	} else if (dn->status) { \
+		ret = -1; \
 	} else { \
 		addr = (dn->busno << 16) | (dn->devfn << 8) | offset; \
 		buid = dn->phb->buid; \
@@ -109,6 +110,8 @@
 	 \
 	if (dn == NULL) { \
 		ret = -2; \
+	} else if (dn->status) { \
+		ret = -1; \
 	} else { \
 		buid = dn->phb->buid; \
 		addr = (dn->busno << 16) | (dn->devfn << 8) | offset; \
@@ -252,8 +255,6 @@
 	ibm_read_pci_config = rtas_token("ibm,read-pci-config");
 	ibm_write_pci_config = rtas_token("ibm,write-pci-config");
 
-	eeh_init();
-
 	if (naca->interrupt_controller == IC_OPEN_PIC) {
 		opprop = (unsigned int *)get_property(find_path_device("/"),
 				"platform-open-pic", NULL);
@@ -352,24 +353,15 @@
 				res = &phb->io_resource;
 				res->name = Pci_Node->full_name;
 				res->flags = IORESOURCE_IO;
-				if (is_eeh_implemented()) {
-					if (!isa_io_base && has_isa) {
-						/* map a page for ISA ports.  Not EEH protected. */
-						isa_io_base = (unsigned long)__ioremap(phb->io_base_phys, PAGE_SIZE, _PAGE_NO_CACHE);
-					}
-					res->start = phb->io_base_virt = eeh_token(index, 0, 0, 0);
-					res->end = eeh_token(index, 0xff, 0xff, 0xffffffff);
-				} else {
-					phb->io_base_virt = ioremap(phb->io_base_phys, range.size);
-					if (!pci_io_base) {
-						pci_io_base = (unsigned long)phb->io_base_virt;
-						if (has_isa)
-							isa_io_base = pci_io_base;
-					}
-					res->start = ((((unsigned long) range.child_addr.a_mid) << 32) | (range.child_addr.a_lo));
-					res->start += (unsigned long)phb->io_base_virt;
-					res->end =   res->start + range.size - 1;
+				phb->io_base_virt = __ioremap(phb->io_base_phys, range.size, _PAGE_NO_CACHE);
+				if (!pci_io_base) {
+					pci_io_base = (unsigned long)phb->io_base_virt;
+					if (has_isa)
+						isa_io_base = pci_io_base;
 				}
+				res->start = ((((unsigned long) range.child_addr.a_mid) << 32) | (range.child_addr.a_lo));
+				res->start += (unsigned long)phb->io_base_virt - pci_io_base;
+				res->end =   res->start + range.size - 1;
 				res->parent = NULL;
 				res->sibling = NULL;
 				res->child = NULL;
@@ -393,13 +385,8 @@
 					++memno;
 					res->name = Pci_Node->full_name;
 					res->flags = IORESOURCE_MEM;
-					if (is_eeh_implemented()) {
-						res->start = eeh_token(index, 0, 0, 0);
-						res->end =   eeh_token(index, 0xff, 0xff, 0xffffffff);
-					} else {
-						res->start = range.parent_addr;
-						res->end =   range.parent_addr + range.size - 1;
-					}
+					res->start = range.parent_addr;
+					res->end =   range.parent_addr + range.size - 1;
 					res->parent = NULL;
 					res->sibling = NULL;
 					res->child = NULL;
@@ -433,6 +420,7 @@
 	struct pci_controller *phb;
 	unsigned int *ui_ptr = NULL, len;
 	struct reg_property64 reg_struct;
+	struct property *of_prop;
 	int *bus_range;
 	int *buid_vals;
 
@@ -517,7 +505,7 @@
 	        phb = pci_alloc_pci_controller("PHB SW",phb_type_speedwagon);
 		if (phb == NULL) return NULL;
 
-		if (naca->platform == PLATFORM_PSERIES) {
+		if (systemcfg->platform == PLATFORM_PSERIES) {
 			phb->cfg_addr = (volatile unsigned long *) 
 			  ioremap(reg_struct.address + 0x140, PAGE_SIZE);
 			phb->cfg_data = (char*)(phb->cfg_addr - 0x02); /* minus is correct */
@@ -545,6 +533,21 @@
 		return NULL;
 	}
 
+	/* Add a linux,phbnum property to the device tree so user code
+	 * can translate bus numbers.
+	 */
+	of_prop = (struct property *) alloc_bootmem(sizeof(struct property) +
+						    sizeof(phb->global_number));
+	if (of_prop) {
+		memset(of_prop, 0, sizeof(struct property));
+		of_prop->name = "linux,phbnum";
+		of_prop->length = sizeof(phb->global_number);
+		of_prop->value = (unsigned char *)&of_prop[1];
+		memcpy(of_prop->value, &phb->global_number,
+		       sizeof(phb->global_number));
+		prom_add_property(dev, of_prop);
+	}
+
 	bus_range = (int *) get_property(dev, "bus-range", &len);
 	if (bus_range == NULL || len < 2 * sizeof(int)) {
 		PPCDBG(PPCDBG_PHBINIT, "Can't get bus-range for %s\n", dev->full_name);
@@ -600,7 +603,6 @@
  	int i;
  	struct pci_controller *phb = PCI_GET_PHB_PTR(dev);
 	struct device_node *dn;
-	unsigned long eeh_disable_bit;
 
 	/* Add IBM loc code (slot) as a prefix to the device names for service */
 	dn = pci_device_to_OF_node(dev);
@@ -617,20 +619,6 @@
 		}
 	}
 
-	if (is_eeh_implemented()) {
-		if (is_eeh_configured(dev)) {
-			eeh_disable_bit = 0;
-			if (eeh_set_option(dev, EEH_ENABLE) != 0) {
-				printk("PCI: failed to enable EEH for %s %s\n", dev->slot_name, dev->name);
-				eeh_disable_bit = EEH_TOKEN_DISABLED;
-			}
-		} else {
-			/* Assume device is by default EEH_DISABLE'd */
-			printk("PCI: eeh NOT configured for %s %s\n", dev->slot_name, dev->name);
-			eeh_disable_bit = EEH_TOKEN_DISABLED;
-		}
-	}
-
 	PPCDBG(PPCDBG_PHBINIT, "fixup_resources:\n"); 
 	PPCDBG(PPCDBG_PHBINIT, "\tphb                 = 0x%016LX\n", phb); 
 	PPCDBG(PPCDBG_PHBINIT, "\tphb->pci_io_offset  = 0x%016LX\n", phb->pci_io_offset); 
@@ -661,19 +649,9 @@
 
 
 		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: 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 {
-				unsigned long offset = (unsigned long)phb->io_base_virt;
-				dev->resource[i].start += offset;
-				dev->resource[i].end += offset;
-			}
+			unsigned long offset = (unsigned long)phb->io_base_virt - pci_io_base;
+			dev->resource[i].start += offset;
+			dev->resource[i].end += offset;
 			PPCDBG(PPCDBG_PHBINIT, "\t\t-> now [%lx .. %lx]\n",
 			       dev->resource[i].start, dev->resource[i].end);
 		} else if (dev->resource[i].flags & IORESOURCE_MEM) {
@@ -681,18 +659,8 @@
 				/* Bogus.  Probably an unused bridge. */
 				dev->resource[i].end = 0;
 			} else {
-				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->pci_mem_offset, size, _PAGE_NO_CACHE);
-					if (!addr)
-						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 {
-					dev->resource[i].start += phb->pci_mem_offset;
-					dev->resource[i].end += phb->pci_mem_offset;
-				}
+				dev->resource[i].start += phb->pci_mem_offset;
+				dev->resource[i].end += phb->pci_mem_offset;
 			}
 			PPCDBG(PPCDBG_PHBINIT, "\t\t-> now [%lx..%lx]\n",
 			       dev->resource[i].start, dev->resource[i].end);
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/pacaData.c linux-2.4.21-pre4/arch/ppc64/kernel/pacaData.c
--- linux-2.4.21-pre3/arch/ppc64/kernel/pacaData.c	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/pacaData.c	Tue Jan 28 19:44:29 2003
@@ -12,6 +12,8 @@
 #include <stddef.h>
 #include <linux/config.h>
 #include <linux/threads.h>
+#include <asm/page.h>
+#include <asm/mmu.h>
 #include <asm/processor.h>
 #include <asm/ptrace.h>
 
@@ -20,6 +22,7 @@
 #include <asm/paca.h>
 
 struct naca_struct *naca;
+struct systemcfg *systemcfg;
 
 /* The Paca is an array with one entry per processor.  Each contains an 
  * ItLpPaca, which contains the information shared between the 
@@ -65,9 +68,9 @@
 
 struct paca_struct paca[MAX_PACAS] __page_aligned = {
 #ifdef CONFIG_PPC_ISERIES
-	PACAINITDATA( 0, 1, &xItLpQueue, 0, 0xc000000000005000),
+	PACAINITDATA( 0, 1, &xItLpQueue, 0, STAB0_VIRT_ADDR),
 #else
-	PACAINITDATA( 0, 1, 0, 0x5000, 0xc000000000005000),
+	PACAINITDATA( 0, 1, 0, STAB0_PHYS_ADDR, STAB0_VIRT_ADDR),
 #endif
 	PACAINITDATA( 1, 0, 0, 0, 0),
 	PACAINITDATA( 2, 0, 0, 0, 0),
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/pci.c linux-2.4.21-pre4/arch/ppc64/kernel/pci.c
--- linux-2.4.21-pre3/arch/ppc64/kernel/pci.c	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/pci.c	Tue Jan 28 19:44:29 2003
@@ -1,6 +1,4 @@
 /*
- * 
- *
  * Port for PPC64 David Engebretsen, IBM Corp.
  *   Contains common pci routines for ppc64 platform, pSeries and iSeries brands. 
  * 
@@ -33,7 +31,6 @@
 #include <asm/naca.h>
 #include <asm/pci_dma.h>
 #include <asm/machdep.h>
-#include <asm/eeh.h>
 
 #include "pci.h"
 
@@ -123,12 +120,48 @@
 }
 
 
+/* Given an mmio phys address, find a pci device that implements
+ * this address.  This is of course expensive, but only used
+ * for device initialization or error paths.
+ * For io BARs it is assumed the pci_io_base has already been added
+ * into addr.
+ *
+ * Bridges are ignored although they could be used to optimize the search.
+ */
+struct pci_dev *pci_find_dev_by_addr(unsigned long addr)
+{
+	struct pci_dev *dev;
+	int i;
+	unsigned long ioaddr;
+
+	ioaddr = (addr > _IO_BASE) ? addr - _IO_BASE : 0;
+
+	pci_for_each_dev(dev) {
+		if ((dev->class >> 8) == PCI_BASE_CLASS_BRIDGE)
+			continue;
+		for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+			unsigned long start = pci_resource_start(dev,i);
+			unsigned long end = pci_resource_end(dev,i);
+			unsigned int flags = pci_resource_flags(dev,i);
+			if (start == 0 || ~start == 0 ||
+			    end == 0 || ~end == 0)
+				continue;
+			if ((flags & IORESOURCE_IO) &&
+			    (ioaddr >= start && ioaddr <= end))
+				return dev;
+			else if ((flags & IORESOURCE_MEM) &&
+				 (addr >= start && addr <= end))
+				return dev;
+		}
+	}
+	return NULL;
+}
+
 void pcibios_fixup_pbus_ranges(struct pci_bus *pbus,
 				struct pbus_set_ranges_data *pranges)
 {
 }
 
-
 void
 pcibios_update_resource(struct pci_dev *dev, struct resource *root,
 			     struct resource *res, int resource)
@@ -182,6 +215,7 @@
 void
 pcibios_align_resource(void *data, struct resource *res, unsigned long size,
 		       unsigned long align)
+
 {
 	struct pci_dev *dev = data;
 
@@ -200,7 +234,6 @@
 	}
 }
 
-
 /*
  *  Handle resources of PCI devices.  If the world were perfect, we could
  *  just allocate all the resource regions and do nothing more.  It isn't.
@@ -409,8 +442,10 @@
                 return NULL;
         }
         memset(hose, 0, sizeof(struct pci_controller));
-        if(strlen(model) < 8) strcpy(hose->what,model);
-        else                  memcpy(hose->what,model,7);
+        if(strlen(model) < 8)
+		strcpy(hose->what,model);
+        else
+		memcpy(hose->what,model,7);
         hose->type = controller_type;
         hose->global_number = global_phb_number;
 	phbtab[global_phb_number++] = hose;
@@ -469,7 +504,7 @@
 			next_busno = hose->last_busno+1;
 	}
 	pci_bus_count = next_busno;
-		
+
 	/* Call machine dependant fixup */
 	if (ppc_md.pcibios_fixup) {
 		ppc_md.pcibios_fixup();
@@ -549,21 +584,15 @@
 				/* Transparent resource -- don't try to "fix" it. */
 				continue;
 			}
-			if (is_eeh_implemented()) {
-				if (res->flags & (IORESOURCE_IO|IORESOURCE_MEM)) {
-					res->start = eeh_token(phb->global_number, bus->number, 0, 0);
-					res->end = eeh_token(phb->global_number, bus->number, 0xff, 0xffffffff);
-				}
-			} else {
-				if (res->flags & IORESOURCE_IO) {
-					res->start += (unsigned long)phb->io_base_virt;
-					res->end += (unsigned long)phb->io_base_virt;
-				} else if (phb->pci_mem_offset
-					   && (res->flags & IORESOURCE_MEM)) {
-					if (res->start < phb->pci_mem_offset) {
-						res->start += phb->pci_mem_offset;
-						res->end += phb->pci_mem_offset;
-					}
+			if (res->flags & IORESOURCE_IO) {
+				unsigned long offset = (unsigned long)phb->io_base_virt - pci_io_base;
+				res->start += offset;
+				res->end += offset;
+			} else if (phb->pci_mem_offset
+				   && (res->flags & IORESOURCE_MEM)) {
+				if (res->start < phb->pci_mem_offset) {
+					res->start += phb->pci_mem_offset;
+					res->end += phb->pci_mem_offset;
 				}
 			}
 		}
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/pci.h linux-2.4.21-pre4/arch/ppc64/kernel/pci.h
--- linux-2.4.21-pre3/arch/ppc64/kernel/pci.h	Fri Aug  2 17:39:43 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/pci.h	Tue Jan 28 19:44:29 2003
@@ -56,6 +56,7 @@
 void *traverse_pci_devices(struct device_node *start, traverse_func pre, traverse_func post, void *data);
 void *traverse_all_pci_devices(traverse_func pre);
 
+struct pci_dev *pci_find_dev_by_addr(unsigned long addr);
 void pci_devs_phb_init(void);
 void pci_fix_bus_sysdata(void);
 struct device_node *fetch_dev_dn(struct pci_dev *dev);
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/pci_dma.c linux-2.4.21-pre4/arch/ppc64/kernel/pci_dma.c
--- linux-2.4.21-pre3/arch/ppc64/kernel/pci_dma.c	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/pci_dma.c	Tue Jan 28 19:44:29 2003
@@ -146,7 +146,7 @@
 		dev = ppc64_isabridge_dev;
 	if (!dev)
 		return NULL;
-	if (naca->platform == PLATFORM_ISERIES_LPAR) {
+	if (systemcfg->platform == PLATFORM_ISERIES_LPAR) {
  		return ISERIES_DEVNODE(dev)->DevTceTable;
 	} else {
 		return PCI_GET_DN(dev)->tce_table;
@@ -735,7 +735,7 @@
 	struct pci_dev *dev;
 	struct device_node *dn, *mydn;
 
-	if (naca->platform == PLATFORM_PSERIES_LPAR) {
+	if (systemcfg->platform == PLATFORM_PSERIES_LPAR) {
 		create_tce_tables_for_busesLP(&pci_root_buses);
 	}
 	else {
@@ -776,7 +776,7 @@
  	/* - Tce Table Share between buses,                              */
  	/* - Tce Table per logical slot.                                 */
 	/*****************************************************************/
-	if(naca->platform == PLATFORM_ISERIES_LPAR) {
+	if(systemcfg->platform == PLATFORM_ISERIES_LPAR) {
 
 		struct iSeries_Device_Node* DevNode = (struct iSeries_Device_Node*)token;
 		getTceTableParmsiSeries(DevNode,newTceTable);
@@ -800,7 +800,7 @@
 
 		dn = (struct device_node *)token;
 		phb = dn->phb;
-		if (naca->platform == PLATFORM_PSERIES)
+		if (systemcfg->platform == PLATFORM_PSERIES)
 			getTceTableParmsPSeries(phb, dn, newTceTable);
 		else
 			getTceTableParmsPSeriesLP(phb, dn, newTceTable);
@@ -1409,7 +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: dma_start_page:0x%x  dma_end_page:0x%x\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.21-pre3/arch/ppc64/kernel/pci_dn.c linux-2.4.21-pre4/arch/ppc64/kernel/pci_dn.c
--- linux-2.4.21-pre3/arch/ppc64/kernel/pci_dn.c	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/pci_dn.c	Tue Jan 28 19:44:29 2003
@@ -50,6 +50,7 @@
 	struct pci_controller *phb = (struct pci_controller *)data;
 	u32 *regs;
 	char *device_type = get_property(dn, "device_type", 0);
+	char *status = get_property(dn, "status", 0);
 
 	dn->phb = phb;
 	if (device_type && strcmp(device_type, "pci") == 0 && get_property(dn, "class-code", 0) == 0) {
@@ -65,6 +66,11 @@
 			dn->devfn = (regs[0] >> 8) & 0xff;
 		}
 	}
+	if (status && strcmp(status, "ok") != 0) {
+		char *name = get_property(dn, "name", 0);
+		printk(KERN_ERR "PCI: %04x:%02x.%x %s (%s) has bad status from firmware! (%s)", dn->busno, PCI_SLOT(dn->devfn), PCI_FUNC(dn->devfn), name ? name : "<no name>", device_type ? device_type : "<unknown type>", status);
+		dn->status = 1;
+	}
 	return NULL;
 }
 
@@ -75,9 +81,11 @@
 static void * __init
 write_OF_bars(struct device_node *dn, void *data)
 {
+#ifdef CONFIG_PPC_PSERIES
 	int i;
 	u32 oldbar, newbar, newbartest;
 	u8  config_offset;
+#endif
 	char *name = get_property(dn, "name", 0);
 	char *device_type = get_property(dn, "device_type", 0);
 	char devname[128];
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/perfmon.c linux-2.4.21-pre4/arch/ppc64/kernel/perfmon.c
--- linux-2.4.21-pre3/arch/ppc64/kernel/perfmon.c	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/perfmon.c	Tue Jan 28 19:44:29 2003
@@ -1,5 +1,11 @@
 /*
- * This file contains the code to configure and utilize the ppc64 pmc hardware
+ * Code to configure and utilize the ppc64 pmc hardware.  Generally, the
+ * following functions are supported:
+ *    1. Kernel profile based on decrementer ticks
+ *    2. Kernel profile based on PMC execution cycles
+ *    3. Trace based on arbitrary PMC counter
+ *    4. Timeslice data capture of arbitrary collections of PMCs
+ *
  * Copyright (C) 2002 David Engebretsen <engebret@us.ibm.com>
  */
 
@@ -14,24 +20,60 @@
 #include <asm/uaccess.h>
 #include <asm/naca.h>
 #include <asm/perfmon.h>
+#include <asm/iSeries/HvCall.h>
+#include <asm/hvcall.h>
 
 extern char _stext[], _etext[], _end[];
-struct perfmon_base_struct perfmon_base = {0, 0, 0, 0, 0, PMC_STATE_INITIAL};
+struct perfmon_base_struct perfmon_base = {0, 0, 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_clear(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  decr_profile(void *data);
 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);
+int pmc_timeslice_enable(struct perfmon_struct *perfdata);
+int pmc_timeslice_disable(struct perfmon_struct *perfdata);
+int pmc_timeslice_set(struct perfmon_struct *perfdata);
+void pmc_dump_timeslice(struct perfmon_struct *perfdata);
+void pmc_trace_rec_type(unsigned long type);
+void pmc_timeslice_data_collect(void *data);
+int pmc_timeslice_tick(void);
+int perfmon_buffer_ctl(void *data);
+int perfmon_dump_ctl(void *data);
+int perfmon_profile_ctl(void *data);
+int perfmon_trace_ctl(void *data);
+int perfmon_timeslice_ctl(void *data);
+
+#define PMC_MAX_CPUS     48
+#define PMC_MAX_COUNTERS 8
+#define PMC_SLICES_STAR  64
+#define PMC_SLICES_GP    28
+#define PMC_SLICES_MAX   64
+#define PMC_TICK_FACTOR  10
 
+int pmc_timeslice_enabled = 0, pmc_timeslice_top = 0;
+int pmc_tick_count[PMC_MAX_CPUS], pmc_timeslice[PMC_MAX_CPUS];
+
+unsigned long pmc_timeslice_data[PMC_SLICES_MAX*PMC_MAX_COUNTERS*PMC_MAX_CPUS];
+
+/*
+ * DRENG: todo:
+ * add api to add config entries (entry, values), and bump pmc_timeslice_top
+ *   value
+ * add api to get data from kernel (entry, values)
+ */
+unsigned long pmc_timeslice_config[PMC_SLICES_MAX * 5];
+
+static spinlock_t pmc_lock = SPIN_LOCK_UNLOCKED;
 asmlinkage int
 sys_perfmonctl (int cmd, void *data) 
 { 
@@ -42,37 +84,35 @@
 	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); 
+	case PMC_CMD_BUFFER:
+		perfmon_buffer_ctl(data); 
 		break;
-	case PMC_OP_FREE:
-		free_perf_buffer(); 
-		break;
-	case PMC_OP_CLEAR:
-		clear_buffers();
+	case PMC_CMD_DUMP:
+		perfmon_dump_ctl(data); 
 		break;
-	case PMC_OP_DUMP:
-		dump_pmc_struct(pdata);
-		copy_to_user(data, pdata, sizeof(struct perfmon_struct));
+	case PMC_CMD_DECR_PROFILE: /* NIA time sampling */
+		decr_profile(data); 
 		break;
-	case PMC_OP_DUMP_HARDWARE:
-		dump_hardware_pmc_struct(pdata);
-		smp_call_function(dump_hardware_pmc_struct, (void *)pdata, 0, 1);
+	case PMC_CMD_PROFILE:
+		perfmon_profile_ctl(pdata); 
 		break;
-	case PMC_OP_DECR_PROFILE: /* NIA time sampling */
-		decr_profile(pdata); 
+	case PMC_CMD_TRACE:
+		perfmon_trace_ctl(pdata); 
 		break;
-	case PMC_OP_PMC_PROFILE:
-		pmc_profile(pdata); 
+	case PMC_CMD_TIMESLICE:
+		perfmon_timeslice_ctl(pdata); 
 		break;
-	case PMC_OP_SET:
-		pmc_set_general(pdata); 
+#if 0
+	case PMC_OP_TIMESLICE:
+		pmc_enable_timeslice(pdata); 
 		break;
-	case PMC_OP_SET_USER:
-		pmc_set_user_general(pdata); 
+	case PMC_OP_DUMP_TIMESLICE:
+		pmc_dump_timeslice(pdata); 
+		smp_call_function(pmc_dump_timeslice, (void *)pdata, 0, 1);
 		break;
+#endif
 	default:
-		printk("Perfmon: Unknown operation\n");
+		printk("Perfmon: Unknown command\n");
 		break;
 	}
 
@@ -80,6 +120,30 @@
 	return 0;
 }
 
+int perfmon_buffer_ctl(void *data) {
+	struct perfmon_struct *pdata;
+	int err;
+
+	pdata = kmalloc(sizeof(struct perfmon_struct), GFP_USER);
+	err = __copy_from_user(pdata, data, sizeof(struct perfmon_struct));
+
+	switch(pdata->header.subcmd) {
+	case PMC_SUBCMD_BUFFER_ALLOC:
+		alloc_perf_buffer(0); 
+		break;
+	case PMC_SUBCMD_BUFFER_FREE:
+		free_perf_buffer(); 
+		break;
+	case PMC_SUBCMD_BUFFER_CLEAR:
+		clear_buffers();
+		break;
+	default:
+		return(-1); 
+	}
+
+	return(0); 
+}
+
 int alloc_perf_buffer(int size) 
 {
 	int i;
@@ -92,6 +156,9 @@
 		perfmon_base.trace_length = 1024*1024*16;
 		perfmon_base.trace_buffer = (unsigned long)btmalloc(perfmon_base.trace_length);
 
+		perfmon_base.timeslice_length = PMC_SLICES_MAX*PMC_MAX_COUNTERS*PMC_MAX_CPUS;
+		perfmon_base.timeslice_buffer = (unsigned long)pmc_timeslice_data;
+
 		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",
@@ -145,6 +212,8 @@
 
 int clear_buffers() 
 {
+	int i, j;
+
 	if(perfmon_base.state == PMC_STATE_INITIAL) {
 		printk("Perfmon: clear buffer failed - no buffer was allocated.\n"); 
 		return -1;
@@ -152,17 +221,29 @@
 
 	printk("Perfmon: clear buffer\n");
 	
-	/* Stop counters on all processors -- blocking */
+	/* Stop counters on all [PMC_MAX_CPUS]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);
+	memset((char *)perfmon_base.timeslice_buffer, 0, perfmon_base.timeslice_length);
 	
 	/* Reset the trace buffer point */
 	perfmon_base.trace_end = 0;
 	
+	for (i=0; i<MAX_PACAS; ++i) {
+		for(j=0; j<8; j++) {
+			paca[i].pmcc[j] = 0;
+		}
+	}
+#if 0
+	/* Reset the timeslice data */
+	for(i=0; i<(PMC_MAX_CPUS*PMC_MAX_COUNTERS*PMC_SLICES_MAX); i++) {
+		pmc_timeslice_data[i] = 0;
+	}
+#endif
 	/* Restart counters on all processors -- blocking */
 	pmc_start(NULL); 
 	smp_call_function(pmc_start, (void *)NULL, 0, 1);
@@ -173,13 +254,22 @@
 void pmc_stop(void *data) 
 {
 	/* Freeze all counters, leave everything else alone */
-	mtspr( MMCR0, mfspr( MMCR0 ) | 0x80000000 );
+	mtspr(MMCR0, mfspr( MMCR0 ) | 0x80000000);
+}
+
+void pmc_clear(void *data) 
+{
+	mtspr(PMC1, 0); mtspr(PMC2, 0);
+	mtspr(PMC3, 0); mtspr(PMC4, 0);
+	mtspr(PMC5, 0); mtspr(PMC6, 0);
+	mtspr(PMC7, 0); mtspr(PMC8, 0);
+	mtspr(MMCR0, 0); mtspr(MMCR1, 0); mtspr(MMCRA, 0);
 }
 
 void pmc_start(void *data) 
 {
 	/* Free all counters, leave everything else alone */
-	mtspr( MMCR0, mfspr( MMCR0 ) & 0x7fffffff );
+	mtspr(MMCR0, mfspr( MMCR0 ) & 0x7fffffff);
 }
 
 void pmc_touch_bolted(void *data) 
@@ -190,6 +280,27 @@
 	touch = *((int *)(perfmon_base.profile_buffer));
 }
 
+int perfmon_dump_ctl(void *data) {
+	struct perfmon_struct *pdata;
+	int err;
+
+	pdata = kmalloc(sizeof(struct perfmon_struct), GFP_USER);
+	err = __copy_from_user(pdata, data, sizeof(struct perfmon_struct));
+
+	switch(pdata->header.subcmd) {
+	case PMC_SUBCMD_DUMP_COUNTERS:
+		dump_pmc_struct(pdata);
+		// copy_to_user(data, pdata, sizeof(struct perfmon_struct));
+		break;
+	case PMC_SUBCMD_DUMP_HARDWARE:
+		dump_hardware_pmc_struct(pdata);
+		smp_call_function(dump_hardware_pmc_struct, (void *)pdata, 0, 1);
+		break;
+	}
+
+	return(0); 
+}
+
 void dump_pmc_struct(struct perfmon_struct *perfdata) 
 {
 	unsigned int cpu = perfdata->vdata.pmc_info.cpu, i;
@@ -226,7 +337,7 @@
 	       cpu, (u32) mfspr(MMCR0),(u32) mfspr(MMCR1),(u32) mfspr(MMCRA));
 }
 
-int decr_profile(struct perfmon_struct *perfdata) 
+int decr_profile(void *data)
 {
 	int i;
 
@@ -251,12 +362,79 @@
 	return 0;
 }
 
+int perfmon_profile_ctl(void *data) {
+	struct perfmon_struct *pdata;
+	int err;
+
+	pdata = kmalloc(sizeof(struct perfmon_struct), GFP_USER);
+	err = __copy_from_user(pdata, data, sizeof(struct perfmon_struct));
+
+	switch(pdata->header.subcmd) {
+	case PMC_SUBCMD_PROFILE_CYCLE:
+		pmc_profile(pdata); 
+		break;
+	default:
+		return(-1);
+	}
+
+	return(0); 
+}
+
+int perfmon_trace_ctl(void *data) {
+	struct perfmon_struct *pdata;
+	int err;
+
+	pdata = kmalloc(sizeof(struct perfmon_struct), GFP_USER);
+	err = __copy_from_user(pdata, data, sizeof(struct perfmon_struct));
+
+	pmc_set_general(pdata); 
+
+#if 0
+        /* Reimplement at some point ... */
+	pmc_set_user_general(pdata); 
+#endif
+	return(0); 
+}
+
+int perfmon_timeslice_ctl(void *data) {
+	struct perfmon_struct *pdata;
+	int err;
+
+	pdata = kmalloc(sizeof(struct perfmon_struct), GFP_USER);
+	err = __copy_from_user(pdata, data, sizeof(struct perfmon_struct));
+
+	switch(pdata->header.subcmd) {
+	case PMC_SUBCMD_TIMESLICE_ENABLE:
+		pmc_timeslice_enable(pdata); 
+		break;
+	case PMC_SUBCMD_TIMESLICE_DISABLE:
+		pmc_timeslice_disable(pdata); 
+		break;
+	case PMC_SUBCMD_TIMESLICE_SET:
+		pmc_timeslice_set(pdata); 
+		break;
+	default:
+		return(-1);
+	}
+
+	return(0); 
+}
+/*
+ * pmc_profile
+ *
+ * Profile the kernel based on cycle counts.  This is made a special case of the more 
+ * general trace functions because it is high use.  Benefits of special casing this
+ * include a buffer of sufficient size to profile the entire kernel is available, and CPI
+ * can be collected along with the profile.
+ */
 int pmc_profile(struct perfmon_struct *perfdata) 
 {
 	struct pmc_struct *pdata = &(perfdata->vdata.pmc);
 	int i;
 
-	printk("Perfmon: NIA PMC profile and CPI\n");
+	printk("Perfmon: NIA PMC profile\n");
+
+	pmc_timeslice_disable(NULL); // fixme
 
 	if(perfmon_base.state == PMC_STATE_INITIAL) {
 		printk("Perfmon: failed - no buffer was allocated.\n"); 
@@ -272,15 +450,33 @@
 	}
 	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));
+	if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p)) {
+		for(i = 0; i < 8; i++) 
+			pdata->pmc[i] = 0x0;
+		pdata->pmc[1] = 0x7f000000;
+		/* Freeze in problem state, exception enable, freeze on event, */
+		/*   enable counter negative condition, PMC1, PMC2             */
+		pdata->pmc[8] = 0x2600cd0e;
+		pdata->pmc[9] = 0x4a5675ac;
+
+		/* Freeze while in wait state */
+		pdata->pmc[10] = 0x00022002;
+	} else {
+		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 */
+
+		/* Freeze while in wait state */
+		pdata->pmc[10] = 0x00000000 | (0x1 << (31 - 30));
+	}
+
+	pmc_configure_hardware();
 
 	mb();
 
+	pmc_trace_rec_type(perfdata->header.vdata.type);
 	pmc_configure((void *)perfdata);
 	smp_call_function(pmc_configure, (void *)perfdata, 0, 0);
 
@@ -308,6 +504,7 @@
 	perfmon_base.state = PMC_STATE_TRACE_KERN; 
 	mb();
 
+	pmc_trace_rec_type(perfdata->header.vdata.type);
 	pmc_configure((void *)perfdata);
 	smp_call_function(pmc_configure, (void *)perfdata, 0, 0);
 
@@ -316,8 +513,10 @@
 
 int pmc_set_user_general(struct perfmon_struct *perfdata) 
 {
+#if 0
 	struct pmc_struct *pdata = &(perfdata->vdata.pmc);
-	int pid = perfdata->header.pid;
+#endif
+	int pid = perfdata->header.vdata.pid;
 	struct task_struct *task;
 	int i;
 
@@ -357,38 +556,49 @@
 	perfmon_base.state = PMC_STATE_TRACE_USER; 
 	mb();
 
+	pmc_trace_rec_type(perfdata->header.vdata.type);
 	pmc_configure((void *)perfdata);
 	smp_call_function(pmc_configure, (void *)perfdata, 0, 0);
 
 	return 0;
 }
 
+void pmc_trace_rec_type(unsigned long type)
+{
+	unsigned long cmd_rec;
+
+	cmd_rec = 0xFFUL << 56;
+	cmd_rec |= type;
+	*((unsigned long *)(perfmon_base.trace_buffer + 
+			    perfmon_base.trace_end)) = cmd_rec;
+	perfmon_base.trace_end += 8;
+	if(perfmon_base.trace_end >= perfmon_base.trace_length)
+		perfmon_base.trace_end = 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;
+	unsigned long i;
 
 	/* Indicate to hypervisor that we are using the PMCs */
-	if(naca->platform == PLATFORM_ISERIES_LPAR)
+	if(systemcfg->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;
+	mtspr(MMCR0, 0x80000000); mtspr(MMCR1, 0x00000000);
 
 	/* 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 );
+	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++)
+	/* Set the PMCs to the new values */
+	for(i = 0; i < 11; i++) {
 		lpaca->pmc[i]  = pdata->pmc[i];
+		printk("pmc_configure: 0x%lx\n", pdata->pmc[i]);
+	}
 
 	mtspr(PMC1, lpaca->pmc[0]); mtspr(PMC2, lpaca->pmc[1]);
 	mtspr(PMC3, lpaca->pmc[2]); mtspr(PMC4, lpaca->pmc[3]);
@@ -398,7 +608,203 @@
 
 	mb();
 	
-	/* Start all counters */
-	mtspr( MMCR0, lpaca->pmc[8]);
+	/* Start all counters - MMCR0 contains the PMC enable control bit */
+	mtspr(MMCR0, lpaca->pmc[8]);
+}
+
+/* Increment the timeslice counters for the current timeslice */ 
+void pmc_timeslice_data_collect(void *data) {
+	struct paca_struct *lpaca = get_paca();
+	int i, cpu = smp_processor_id(); 
+	int slice_rec = cpu*PMC_MAX_COUNTERS*PMC_SLICES_MAX +
+		        pmc_timeslice[cpu]*PMC_MAX_COUNTERS;
+
+	/* First get any cumulative data that may have accrued */
+	for(i=0; i<8; i++) {
+		pmc_timeslice_data[slice_rec + i] += lpaca->pmcc[i];
+		lpaca->pmcc[i] = 0;
+		lpaca->pmc[i]  = 0;
+	}
+
+	/* Next get current hardware values */
+	pmc_timeslice_data[slice_rec + 0] += ((u32)mfspr(PMC1));
+	pmc_timeslice_data[slice_rec + 1] += ((u32)mfspr(PMC2));
+	pmc_timeslice_data[slice_rec + 2] += ((u32)mfspr(PMC3));
+	pmc_timeslice_data[slice_rec + 3] += ((u32)mfspr(PMC4));
+	pmc_timeslice_data[slice_rec + 4] += ((u32)mfspr(PMC5));
+	pmc_timeslice_data[slice_rec + 5] += ((u32)mfspr(PMC6));
+	pmc_timeslice_data[slice_rec + 6] += ((u32)mfspr(PMC7));
+	pmc_timeslice_data[slice_rec + 7] += ((u32)mfspr(PMC8));
+}
+
+/* Handle a timeslice tick.  Each processor executes independantly */
+int pmc_timeslice_tick() {
+	int i;
+	struct perfmon_struct perfdata;
+	unsigned int cpu = smp_processor_id();
+
+	/* Switch timeslice every decrementer, reduced by some factor */
+	pmc_tick_count[cpu]++;
+	if(!pmc_timeslice_enabled || pmc_tick_count[cpu] < PMC_TICK_FACTOR) 
+		return 0;
+	pmc_tick_count[cpu] = 0;
+
+	/* Stop counters and collect current state */
+	pmc_stop(NULL); 
+	pmc_timeslice_data_collect(NULL); 
+
+	/* Move on to the next timeslice */
+	pmc_timeslice[cpu]++; 
+	if(pmc_timeslice[cpu] >= pmc_timeslice_top) pmc_timeslice[cpu] = 0;
+
+	/* Set up the counters to reflect the new data to collect */
+	for(i = 0; i < 8; i++) {
+		perfdata.vdata.pmc.pmc[i] = 0;
+	}
+	for(i = 0; i < 3; i++) {
+		perfdata.vdata.pmc.pmc[i+8] = 
+			pmc_timeslice_config[pmc_timeslice[cpu]*5+i];
+	}
+	mb();
+
+	/* Configure the new counters */
+	pmc_configure((void *)&perfdata);
+
+	return 0;
+}
+
+int pmc_timeslice_set(struct perfmon_struct *perfdata) 
+{
+	int slice; 
+
+	printk("Perfmon: Timeslice set\n");
+
+	slice = perfdata->header.vdata.slice;
+	if(slice >= PMC_SLICES_MAX) {
+		printk("Perfmon: invalid timeslice specified %d\n", slice);
+		return(-1); 
+	}
+
+	if(slice > pmc_timeslice_top) pmc_timeslice_top = slice;
+
+	pmc_timeslice_config[slice * 5 + 0] = perfdata->vdata.pmc.pmc[0];
+	pmc_timeslice_config[slice * 5 + 1] = perfdata->vdata.pmc.pmc[1];
+	pmc_timeslice_config[slice * 5 + 2] = perfdata->vdata.pmc.pmc[2];
+	pmc_timeslice_config[slice * 5 + 3] = perfdata->vdata.pmc.pmc[3];
+	pmc_timeslice_config[slice * 5 + 4] = perfdata->vdata.pmc.pmc[4];
 }
 
+int pmc_timeslice_enable(struct perfmon_struct *perfdata) 
+{
+	int i, j;
+
+	printk("Perfmon: Timeslice mode\n");
+
+	if(perfmon_base.state == PMC_STATE_INITIAL) {
+		printk("Perfmon: failed - no buffer was allocated.\n"); 
+		return -1;
+	}
+
+	pmc_timeslice_disable(NULL); // fixme
+	mb();
+
+	for (i=0; i<MAX_PACAS; ++i) {
+		paca[i].prof_mode = PMC_STATE_TIMESLICE;
+	}
+	perfmon_base.state = PMC_STATE_TIMESLICE; 
+
+	pmc_configure_hardware(); 
+
+	for(i=0; i<PMC_MAX_CPUS; i++) {
+		pmc_tick_count[i] = 0;
+		pmc_timeslice[i]  = 0;
+	}
+
+	/* Stop counters on all processors -- blocking */
+	pmc_stop(NULL); 
+	smp_call_function(pmc_stop, (void *)NULL, 0, 1);
+
+	/* Clear out the PMC counters, cumulative and current */
+	for (i=0; i<MAX_PACAS; ++i) {
+		paca[i].prof_mode = PMC_STATE_TIMESLICE;
+		for(j=0; j<8; j++) {
+			paca[i].pmcc[j] = 0;
+		}
+		for(j=0; j<11; j++) {
+			paca[i].pmc[j] = 0;
+		}
+	}	
+
+	memset((char *)perfmon_base.timeslice_buffer, 
+	       0, perfmon_base.timeslice_length);
+
+	pmc_trace_rec_type(PMC_TYPE_TIMESLICE);
+
+	/* Clear counters on all processors -- blocking */
+	pmc_clear(NULL); 
+	smp_call_function(pmc_clear, (void *)NULL, 0, 1);
+
+	mb();
+
+	pmc_timeslice_enabled  = 1;
+
+	/* 
+	 * We do not actually setup the PMC hardware here.  That occurs
+	 * after the first timeslice tick occurs. Close enough.
+	 */
+	return 0;
+}
+
+int pmc_timeslice_disable(struct perfmon_struct *perfdata) 
+{
+	pmc_timeslice_enabled = 0;
+}
+
+void pmc_dump_timeslice(struct perfmon_struct *perfdata) 
+{
+	unsigned long rec, i, j, idx;
+	int cpu = smp_processor_id(); 
+
+	spin_lock(&pmc_lock);
+
+	pmc_trace_rec_type(PMC_TYPE_TIMESLICE_DUMP); /* DRENG put cpu num in */
+	for(i=0; i<pmc_timeslice_top; i++) {
+		for(j=0; j<8; j++) {
+			idx = cpu*PMC_MAX_COUNTERS*PMC_SLICES_MAX +
+				i*PMC_MAX_COUNTERS + j;
+			rec = pmc_timeslice_data[idx];
+			*((unsigned long *)(perfmon_base.trace_buffer + 
+					    perfmon_base.trace_end)) = rec;
+			perfmon_base.trace_end += 8;
+			if(perfmon_base.trace_end >= perfmon_base.trace_length)
+				perfmon_base.trace_end = 0;
+		}
+	}
+	spin_unlock(&pmc_lock);
+}
+
+long plpar_perfmon(int mode)
+{
+        return plpar_hcall_norets(H_PERFMON, mode, 0); 
+}
+
+void pmc_configure_hardware() {
+	/* 
+	 * Debug bus enabled is required on GP for timeslice mode.
+	 * Flood enabled is required on GP for PMC cycle profile mode
+	 *   iSeries SP sets this by default.  pSeries requires the OS to enable.
+	 */
+	if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p)) {
+		/* Set up the debug bus to pmc mode - a feature of GP */
+		switch(systemcfg->platform) {
+		case PLATFORM_ISERIES_LPAR:
+			HvCall_setDebugBus(1);
+			break;
+		case PLATFORM_PSERIES_LPAR:
+			plpar_perfmon(1);
+			break;
+		case PLATFORM_PSERIES:
+			mtspr(HID0, mfspr(HID0) | 0x0000080000000000);
+		} 
+	} 
+}
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/pmc.c linux-2.4.21-pre4/arch/ppc64/kernel/pmc.c
--- linux-2.4.21-pre3/arch/ppc64/kernel/pmc.c	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/pmc.c	Tue Jan 28 19:44:29 2003
@@ -73,7 +73,8 @@
 struct mm_struct btmalloc_mm = {pgd             : bolted_dir,
                                 page_table_lock : SPIN_LOCK_UNLOCKED};
 
-extern spinlock_t hash_table_lock;
+extern spinlock_t hash_table_lock[];
+extern inline unsigned long get_lock_slot(unsigned long vpn);
 
 char *
 ppc64_pmc_stab(int file)
@@ -211,15 +212,14 @@
 	pgd_t *pgdp;
 	pmd_t *pmdp;
 	pte_t *ptep, pte;
-	unsigned long ea_base, ea, hpteflags;
+	unsigned long ea_base, ea, hpteflags, lock_slot;
 	struct vm_struct *area;
-	unsigned long pa, pg_count, page, vsid, slot, va, arpn, vpn;
+	unsigned long pa, pg_count, page, vsid, slot, va, rpn, 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);
@@ -236,10 +236,12 @@
 		pa = get_free_page(GFP_KERNEL) - PAGE_OFFSET; 
 		ea = ea_base + (page * PAGE_SIZE);
 		vsid = get_kernel_vsid(ea);
-		va = ( vsid << 28 ) | ( pa & 0xfffffff );
+		va = ( vsid << 28 ) | ( ea & 0xfffffff );
 		vpn = va >> PAGE_SHIFT;
-		arpn = ((unsigned long)__v2a(ea)) >> PAGE_SHIFT;
+		lock_slot = get_lock_slot(vpn); 
+		rpn = pa >> PAGE_SHIFT;
 
+		spin_lock(&hash_table_lock[lock_slot].lock);
 		/* Get a pointer to the linux page table entry for this page
 		 * allocating pmd or pte pages along the way as needed.  Note
 		 * that the pmd & pte pages are not themselfs bolted.
@@ -257,13 +259,16 @@
 		pte_val(pte) &= ~_PAGE_HPTEFLAGS;
 		pte_val(pte) |= _PAGE_HASHPTE;
 
-		slot = ppc_md.hpte_insert(vpn, arpn, hpteflags, 1, 0);  
+		slot = ppc_md.hpte_insert(vpn, rpn, hpteflags, 1, 0);  
 
 		pte_val(pte) |= ((slot<<12) & 
 				 (_PAGE_GROUP_IX | _PAGE_SECONDARY));
+
+		*ptep = pte;
+
+		spin_unlock(&hash_table_lock[lock_slot].lock);
 	}
 
-	spin_unlock(&hash_table_lock);
 	spin_unlock(&btmalloc_mm.page_table_lock);
 	return (void*)ea_base;
 }
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/ppc_ksyms.c linux-2.4.21-pre4/arch/ppc64/kernel/ppc_ksyms.c
--- linux-2.4.21-pre3/arch/ppc64/kernel/ppc_ksyms.c	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/ppc_ksyms.c	Tue Jan 28 19:44:29 2003
@@ -106,6 +106,7 @@
 EXPORT_SYMBOL(pci_dram_offset);
 
 EXPORT_SYMBOL(find_next_zero_bit);
+EXPORT_SYMBOL(find_next_zero_le_bit);
 
 EXPORT_SYMBOL(strcpy);
 EXPORT_SYMBOL(strncpy);
@@ -124,6 +125,7 @@
 EXPORT_SYMBOL(__down_interruptible);
 EXPORT_SYMBOL(__up);
 EXPORT_SYMBOL(naca);
+EXPORT_SYMBOL(systemcfg);
 EXPORT_SYMBOL(__down);
 
 /* EXPORT_SYMBOL(csum_partial); already in net/netsyms.c */
@@ -252,6 +254,8 @@
 EXPORT_SYMBOL(rtas_firmware_flash_list);
 EXPORT_SYMBOL(rtas_token);
 EXPORT_SYMBOL(rtas_call);
+EXPORT_SYMBOL(rtas_data_buf);
+EXPORT_SYMBOL(rtas_data_buf_lock);
 #endif
 
 #ifndef CONFIG_PPC_ISERIES
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/proc_pmc.c linux-2.4.21-pre4/arch/ppc64/kernel/proc_pmc.c
--- linux-2.4.21-pre3/arch/ppc64/kernel/proc_pmc.c	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/proc_pmc.c	Tue Jan 28 19:44:29 2003
@@ -110,6 +110,9 @@
 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 ssize_t read_timeslice(struct file *file, char *buf, size_t count, loff_t *ppos);
+static ssize_t write_timeslice(struct file * file, const char * buf,
+			     size_t count, loff_t *ppos);
 
 static struct file_operations proc_profile_operations = {
 	read:		read_profile,
@@ -121,6 +124,11 @@
 	write:		write_trace,
 };
 
+static struct file_operations proc_timeslice_operations = {
+	read:		read_timeslice,
+	write:		write_timeslice,
+};
+
 extern struct perfmon_base_struct perfmon_base;
 
 void proc_ppc64_init(void)
@@ -144,7 +152,15 @@
 	ent = create_proc_entry("naca", S_IFREG|S_IRUGO, proc_ppc64_root);
 	if ( ent ) {
 		ent->nlink = 1;
-		ent->data = 0;
+		ent->data = naca;
+		ent->size = 4096;
+		ent->proc_fops = &nacamap_fops;
+	}
+	
+	ent = create_proc_entry("systemcfg", S_IFREG|S_IRUGO, proc_ppc64_root);
+	if ( ent ) {
+		ent->nlink = 1;
+		ent->data = systemcfg;
 		ent->size = 4096;
 		ent->proc_fops = &nacamap_fops;
 	}
@@ -152,7 +168,7 @@
 	/* /proc/ppc64/paca/XX -- raw paca contents.  Only readable to root */
 	ent = proc_mkdir("paca", proc_ppc64_root);
 	if (ent) {
-		for (i = 0; i < naca->processorCount; i++)
+		for (i = 0; i < systemcfg->processorCount; i++)
 			proc_ppc64_create_paca(i, ent);
 	}
 
@@ -165,14 +181,14 @@
 	proc_ppc64_pmc_root = proc_mkdir("pmc", proc_ppc64_root);
 
 	proc_ppc64_pmc_system_root = proc_mkdir("system", proc_ppc64_pmc_root);
-	for (i = 0; i < naca->processorCount; i++) {
+	for (i = 0; i < systemcfg->processorCount; i++) {
 		sprintf(buf, "cpu%ld", i); 
 		proc_ppc64_pmc_cpu_root[i] = proc_mkdir(buf, proc_ppc64_pmc_root);
 	}
 
 
 	/* Create directories for the software counters. */
-	for (i = 0; i < naca->processorCount; i++) {
+	for (i = 0; i < systemcfg->processorCount; i++) {
 		ent = create_proc_entry("stab", S_IRUGO | S_IWUSR, 
 					proc_ppc64_pmc_cpu_root[i]);
 		if (ent) {
@@ -224,8 +240,14 @@
 		/* ent->size = (1+prof_len) * sizeof(unsigned int); */
 	}
 
+	ent = create_proc_entry("timeslice", S_IWUSR | S_IRUGO, proc_ppc64_pmc_system_root);
+	if (ent) {
+		ent->nlink = 1;
+		ent->proc_fops = &proc_timeslice_operations;
+	}
+
 	/* Create directories for the hardware counters. */
-	for (i = 0; i < naca->processorCount; i++) {
+	for (i = 0; i < systemcfg->processorCount; i++) {
 		ent = create_proc_entry("hardware", S_IRUGO | S_IWUSR, 
 					proc_ppc64_pmc_cpu_root[i]);
 		if (ent) {
@@ -299,7 +321,7 @@
 	   (unsigned long) proc_ppc64_pmc_system_root) {
 		return(-1); 
 	} else {
-		for (i = 0; i < naca->processorCount; i++) {
+		for (i = 0; i < systemcfg->processorCount; i++) {
 			if ((unsigned long)data ==
 			   (unsigned long)proc_ppc64_pmc_cpu_root[i]) {
 				return(i); 
@@ -417,20 +439,24 @@
 	return read;
 }
 
+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)
 {
 	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);
+	pnt = (char *)(perfmon_base.trace_buffer) + p;
 	copy_to_user(buf,(void *)pnt,count);
 	read += count;
 	*ppos += read;
@@ -442,8 +468,28 @@
 {
 }
 
-static ssize_t write_profile(struct file * file, const char * buf,
-			     size_t count, loff_t *ppos)
+static ssize_t read_timeslice(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.timeslice_length)) return 0;
+	if (count > (perfmon_base.timeslice_length) - p)
+		count = (perfmon_base.timeslice_length) - p;
+	read = 0;
+
+	pnt = (char *)(perfmon_base.timeslice_buffer) + p;
+	copy_to_user(buf,(void *)pnt,count);
+	read += count;
+	*ppos += read;
+	return read;
+}
+
+static ssize_t write_timeslice(struct file * file, const char * buf,
+			       size_t count, loff_t *ppos)
 {
 }
 
@@ -545,7 +591,7 @@
 			(unsigned long)xItLpQueue.xLpIntCountByType[i] );
 	}
 	len += sprintf( page+len, "\n  events processed by processor:\n" );
-	for (i=0; i<naca->processorCount; ++i) {
+	for (i=0; i<systemcfg->processorCount; ++i) {
 		len += sprintf( page+len, "    CPU%02d  %10u\n",
 			i, paca[i].lpEvent_count );
 	}
@@ -978,45 +1024,33 @@
 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 )
+	if ( pos >= dp->size )
 		return 0;
-	if ( nbytes >= size )
-		nbytes = size;
-	if ( pos + nbytes > size )
-		nbytes = size - pos;
-	fromaddr = (char *)(KERNELBASE + 0x4000 + pos);
+	if ( nbytes >= dp->size )
+		nbytes = dp->size;
+	if ( pos + nbytes > dp->size )
+		nbytes = dp->size - pos;
 
-	copy_to_user( buf, fromaddr, nbytes );
+	copy_to_user( buf, (char *)dp->data + pos, 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 )
+	if ((vma->vm_end - vma->vm_start) > dp->size)
 		return -EINVAL;
 
-	remap_page_range( vma->vm_start, pa, 4096, vma->vm_page_prot );
+	remap_page_range( vma->vm_start, __pa(dp->data), dp->size, vma->vm_page_prot );
 	return 0;
 }
-
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/process.c linux-2.4.21-pre4/arch/ppc64/kernel/process.c
--- linux-2.4.21-pre3/arch/ppc64/kernel/process.c	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/process.c	Tue Jan 28 19:44:29 2003
@@ -241,6 +241,7 @@
 	}
 	memcpy(&p->thread.fpr, &current->thread.fpr, sizeof(p->thread.fpr));
 	p->thread.fpscr = current->thread.fpscr;
+	p->thread.fpexc_mode = current->thread.fpexc_mode;
 
 	return 0;
 }
@@ -278,6 +279,32 @@
 	current->thread.fpscr = 0;
 }
 
+# define PR_FP_EXC_DISABLED     0       /* FP exceptions disabled */
+# define PR_FP_EXC_NONRECOV     1       /* async non-recoverable exc. mode */
+# define PR_FP_EXC_ASYNC        2       /* async recoverable exception mode */
+# define PR_FP_EXC_PRECISE      3       /* precise exception mode */
+
+int set_fpexc_mode(struct task_struct *tsk, unsigned int val)
+{
+	struct pt_regs *regs = tsk->thread.regs;
+
+	if (val > PR_FP_EXC_PRECISE)
+		return -EINVAL;
+	tsk->thread.fpexc_mode = __pack_fe01(val);
+	if (regs != NULL && (regs->msr & MSR_FP) != 0)
+		regs->msr = (regs->msr & ~(MSR_FE0|MSR_FE1))
+			| tsk->thread.fpexc_mode;
+	return 0;
+}
+
+int get_fpexc_mode(struct task_struct *tsk, unsigned long adr)
+{
+	unsigned int val;
+
+	val = __unpack_fe01(tsk->thread.fpexc_mode);
+	return put_user(val, (unsigned int *) adr);
+}
+
 int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6,
 	      struct pt_regs *regs)
 {
@@ -337,13 +364,13 @@
 
 void initialize_paca_hardware_interrupt_stack(void)
 {
-	extern struct naca_struct *naca;
+	extern struct systemcfg *systemcfg;
 
 	int i;
 	unsigned long stack;
 	unsigned long end_of_stack =0;
 
-	for (i=1; i < naca->processorCount; i++) {
+	for (i=1; i < systemcfg->processorCount; i++) {
 		/* Carve out storage for the hardware interrupt stack */
 		stack = __get_free_pages(GFP_KERNEL, get_order(8*PAGE_SIZE));
 
@@ -366,7 +393,7 @@
 	if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p))
 		return;
 
-	for (i=0; i < naca->processorCount; i++) {
+	for (i=0; i < systemcfg->processorCount; i++) {
 		/* set page at the top of stack to be protected - prevent overflow */
 		end_of_stack = paca[i].xHrdIntStack - (8*PAGE_SIZE - STACK_FRAME_OVERHEAD);
 		ppc_md.hpte_updateboltedpp(PP_RXRX,end_of_stack);
@@ -461,6 +488,10 @@
 			return 0;
 		if (count > 0) {
 			ip = *(unsigned long *)(sp + 16);
+			/*
+			 * XXX we mask the upper 32 bits until procps
+			 * gets fixed.
+			 */
 			if (ip < first_sched || ip >= last_sched)
 				return (ip & 0xFFFFFFFF);
 		}
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/prom.c linux-2.4.21-pre4/arch/ppc64/kernel/prom.c
--- linux-2.4.21-pre3/arch/ppc64/kernel/prom.c	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/prom.c	Tue Jan 28 19:44:29 2003
@@ -342,6 +342,7 @@
         unsigned long offset = reloc_offset();
 	struct prom_t *_prom = PTRRELOC(&prom);
         struct naca_struct *_naca = RELOC(naca);
+        struct systemcfg *_systemcfg = RELOC(systemcfg);
 
 	/* NOTE: _naca->debug_switch is already initialized. */
 #ifdef DEBUG_PROM
@@ -372,35 +373,25 @@
 					  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);
+				_systemcfg->dCacheL1Size = size;
+				_systemcfg->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"),
+					  RELOC("i-cache-size"),
 					  &size, sizeof(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);
+				_systemcfg->iCacheL1Size = size;
+				_systemcfg->iCacheL1LineSize = lsize;
+				_naca->iCacheL1LogLineSize = __ilog2(lsize);
 				_naca->iCacheL1LinesPerPage = PAGE_SIZE/lsize;
-				_naca->iCacheL1Assoc = size / lsize / sets;
 
-				if (_naca->platform == PLATFORM_PSERIES_LPAR) {
+				if (_systemcfg->platform == PLATFORM_PSERIES_LPAR) {
 					u32 pft_size[2];
 					call_prom(RELOC("getprop"), 4, 1, node, 
 						  RELOC("ibm,pft-size"),
@@ -470,17 +461,17 @@
 	}
 
 	/* We gotta have at least 1 cpu... */
-        if ( (_naca->processorCount = num_cpus) < 1 )
+        if ( (_systemcfg->processorCount = num_cpus) < 1 )
                 PROM_BUG();
 
-	_naca->physicalMemorySize = lmb_phys_mem_size();
+	_systemcfg->physicalMemorySize = lmb_phys_mem_size();
 
-	if (_naca->platform == PLATFORM_PSERIES) {
+	if (_systemcfg->platform == PLATFORM_PSERIES) {
 		unsigned long rnd_mem_size, pteg_count;
 
 		/* round mem_size up to next power of 2 */
-		rnd_mem_size = 1UL << __ilog2(_naca->physicalMemorySize);
-		if (rnd_mem_size < _naca->physicalMemorySize)
+		rnd_mem_size = 1UL << __ilog2(_systemcfg->physicalMemorySize);
+		if (rnd_mem_size < _systemcfg->physicalMemorySize)
 			rnd_mem_size <<= 1;
 
 		/* # pages / 2 */
@@ -501,58 +492,43 @@
 	 */
 	_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;
+	/* Add an eye catcher and the systemcfg layout version number */
+	strcpy(_systemcfg->eye_catcher, RELOC("SYSTEMCFG:PPC64"));
+	_systemcfg->version.major = SYSTEMCFG_MAJOR;
+	_systemcfg->version.minor = SYSTEMCFG_MINOR;
+	_systemcfg->processor = _get_PVR();
 
 #ifdef DEBUG_PROM
-        prom_print(RELOC("naca->processorCount       = 0x"));
-        prom_print_hex(_naca->processorCount);
+        prom_print(RELOC("systemcfg->processorCount       = 0x"));
+        prom_print_hex(_systemcfg->processorCount);
         prom_print_nl();
 
-        prom_print(RELOC("naca->physicalMemorySize   = 0x"));
-        prom_print_hex(_naca->physicalMemorySize);
+        prom_print(RELOC("systemcfg->physicalMemorySize   = 0x"));
+        prom_print_hex(_systemcfg->physicalMemorySize);
         prom_print_nl();
 
-        prom_print(RELOC("naca->pftSize              = 0x"));
+        prom_print(RELOC("naca->pftSize                   = 0x"));
         prom_print_hex(_naca->pftSize);
         prom_print_nl();
 
-        prom_print(RELOC("naca->dCacheL1LineSize     = 0x"));
-        prom_print_hex(_naca->dCacheL1LineSize);
-        prom_print_nl();
-
-        prom_print(RELOC("naca->dCacheL1LogLineSize  = 0x"));
-        prom_print_hex(_naca->dCacheL1LogLineSize);
-        prom_print_nl();
-
-        prom_print(RELOC("naca->dCacheL1LinesPerPage = 0x"));
-        prom_print_hex(_naca->dCacheL1LinesPerPage);
+        prom_print(RELOC("systemcfg->dCacheL1LineSize     = 0x"));
+        prom_print_hex(_systemcfg->dCacheL1LineSize);
         prom_print_nl();
 
-        prom_print(RELOC("naca->iCacheL1LineSize     = 0x"));
-        prom_print_hex(_naca->iCacheL1LineSize);
+        prom_print(RELOC("systemcfg->iCacheL1LineSize     = 0x"));
+        prom_print_hex(_systemcfg->iCacheL1LineSize);
         prom_print_nl();
 
-        prom_print(RELOC("naca->iCacheL1LogLineSize  = 0x"));
-        prom_print_hex(_naca->iCacheL1LogLineSize);
-        prom_print_nl();
-
-        prom_print(RELOC("naca->iCacheL1LinesPerPage = 0x"));
-        prom_print_hex(_naca->iCacheL1LinesPerPage);
-        prom_print_nl();
-
-        prom_print(RELOC("naca->serialPortAddr       = 0x"));
+        prom_print(RELOC("naca->serialPortAddr            = 0x"));
         prom_print_hex(_naca->serialPortAddr);
         prom_print_nl();
 
-        prom_print(RELOC("naca->interrupt_controller = 0x"));
+        prom_print(RELOC("naca->interrupt_controller      = 0x"));
         prom_print_hex(_naca->interrupt_controller);
         prom_print_nl();
 
-        prom_print(RELOC("naca->platform             = 0x"));
-        prom_print_hex(_naca->platform);
+        prom_print(RELOC("systemcfg->platform             = 0x"));
+        prom_print_hex(_systemcfg->platform);
         prom_print_nl();
 
 	prom_print(RELOC("prom_initialize_naca: end...\n"));
@@ -656,6 +632,7 @@
 	struct prom_t *_prom = PTRRELOC(&prom);
 	struct rtas_t *_rtas = PTRRELOC(&rtas);
 	struct naca_struct *_naca = RELOC(naca);
+	struct systemcfg *_systemcfg = RELOC(systemcfg);
 	ihandle prom_rtas;
         u32 getprop_rval;
 
@@ -672,7 +649,7 @@
 				  RELOC("ibm,hypertas-functions"), 
 				  hypertas_funcs, 
 				  sizeof(hypertas_funcs))) > 0) {
-			_naca->platform = PLATFORM_PSERIES_LPAR;
+			_systemcfg->platform = PLATFORM_PSERIES_LPAR;
 		}
 
 		call_prom(RELOC("getprop"), 
@@ -689,7 +666,7 @@
 			 * of physical memory (or within the RMO region) because RTAS
 			 * runs in 32-bit mode and relocate off.
 			 */
-			if ( _naca->platform == PLATFORM_PSERIES_LPAR ) {
+			if ( _systemcfg->platform == PLATFORM_PSERIES_LPAR ) {
 				struct lmb *_lmb  = PTRRELOC(&lmb);
 				rtas_region = min(_lmb->rmo_size, RTAS_INSTANTIATE_MAX);
 			}
@@ -1084,11 +1061,12 @@
         unsigned long *acknowledge  = __v2a(&__secondary_hold_acknowledge);
         unsigned long secondary_hold = (unsigned long)__v2a(*PTRRELOC((unsigned long *)__secondary_hold));
         struct naca_struct *_naca = RELOC(naca);
+        struct systemcfg *_systemcfg = RELOC(systemcfg);
 	struct paca_struct *_xPaca = PTRRELOC(&paca[0]);
 	struct prom_t *_prom = PTRRELOC(&prom);
 
 	/* Initially, we must have one active CPU. */
-	_naca->processorCount = 1;
+	_systemcfg->processorCount = 1;
 
 #ifdef DEBUG_PROM
 	prom_print(RELOC("prom_hold_cpus: start...\n"));
@@ -1206,7 +1184,7 @@
 		if (*acknowledge == cpuid) {
 			prom_print(RELOC("ok\n"));
 			/* Set the number of active processors. */
-			_naca->processorCount++;
+			_systemcfg->processorCount++;
 		} else {
 			prom_print(RELOC("failed: "));
 			prom_print_hex(*acknowledge);
@@ -1220,8 +1198,8 @@
 	    __is_processor(PV_SSTAR)) {
 		prom_print(RELOC("    starting secondary threads\n"));
 
-		for (i=0; i < _naca->processorCount ;i++) {
-			unsigned long threadid = _naca->processorCount*2-1-i;
+		for (i=0; i < _systemcfg->processorCount ;i++) {
+			unsigned long threadid = _systemcfg->processorCount*2-1-i;
 			
 			if (i == 0) {
 				unsigned long pir = _get_PIR();
@@ -1247,7 +1225,7 @@
 #endif
 			_xPaca[threadid].xHwProcNum = _xPaca[i].xHwProcNum+1;
 		}
-		_naca->processorCount *= 2;
+		_systemcfg->processorCount *= 2;
 	} else {
 		prom_print(RELOC("Processor is not HMT capable\n"));
 	}
@@ -1381,13 +1359,14 @@
 	char *p, *d;
  	unsigned long phys;
         u32 getprop_rval;
-        struct naca_struct   *_naca = RELOC(naca);
+        struct naca_struct *_naca = RELOC(naca);
+        struct systemcfg *_systemcfg = RELOC(systemcfg);
 	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;
+	_systemcfg->platform = PLATFORM_PSERIES;
 	/* Reset klimit to take into account the embedded system map */
 	if (RELOC(embedded_sysmap_end))
 		RELOC(klimit) = __va(PAGE_ALIGN(RELOC(embedded_sysmap_end)));
@@ -1475,6 +1454,8 @@
 			    sizeof(cmd_line)-1);
 	if (sz > 0)
 		_cmd_line[sz] = '\0';
+        if (sz <=1 )
+                strcpy(_cmd_line,RELOC(CONFIG_CMDLINE));
 
 	prom_parse_cmd_line(_cmd_line);
 
@@ -1544,6 +1525,8 @@
 
 	mem = prom_bi_rec_reserve(mem);
 
+	mem = check_display(mem);
+
 	prom_instantiate_rtas();
         
         /* Initialize some system info into the Naca early... */
@@ -1553,11 +1536,9 @@
          * following, regardless of whether we have an SMP
          * kernel or not.
          */
-        if ( _naca->processorCount > 1 )
+        if (_systemcfg->processorCount > 1)
 	        prom_hold_cpus(mem);
 
-	mem = check_display(mem);
-
 #ifdef DEBUG_PROM
 	prom_print(RELOC("copying OF device tree...\n"));
 #endif
@@ -1567,7 +1548,7 @@
 
 	lmb_reserve(0, __pa(RELOC(klimit)));
 
-	if (_naca->platform == PLATFORM_PSERIES)
+	if (_systemcfg->platform == PLATFORM_PSERIES)
 		prom_initialize_tce_table();
 
  	if ((long) call_prom(RELOC("getprop"), 4, 1,
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/ptrace.c linux-2.4.21-pre4/arch/ppc64/kernel/ptrace.c
--- linux-2.4.21-pre3/arch/ppc64/kernel/ptrace.c	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/ptrace.c	Tue Jan 28 19:44:29 2003
@@ -252,50 +252,68 @@
 		break;
 
 	case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */
-		u64 tmp;
-		u64 cntr;
-
-		ret = 0; 
-		for (cntr=0; cntr<32 && ret==0; ++cntr) {
-			tmp = ((u64*)child->thread.regs)[cntr];
-			ret = put_user(tmp, (u64*)(data+cntr));
+		int i;
+		unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
+		unsigned long *tmp = (unsigned long *)addr;
+
+		for (i = 0; i < 32; i++) {
+			ret = put_user(*reg, tmp);
+			if (ret)
+				break;
+			reg++;
+			tmp++;
 		}
 		break;
 	}
 
 	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));
+		int i;
+		unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
+		unsigned long *tmp = (unsigned long *)addr;
+
+		for (i = 0; i < 32; i++) {
+			ret = get_user(*reg, tmp);
+			if (ret)
+				break;
+			reg++;
+			tmp++;
+		}
 		break;
 	}
 
 	case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */
-		u64 tmp;
-		u64 cntr;
+		int i;
+		unsigned long *reg = &((unsigned long *)child->thread.fpr)[0];
+		unsigned long *tmp = (unsigned long *)addr;
 
-		ret = -EIO;
 		if (child->thread.regs->msr & MSR_FP)
 			giveup_fpu(child);
-		ret = 0; 
-		for (cntr=0; cntr<32 && ret==0; ++cntr) {
-			tmp = ((u64*)child->thread.fpr)[cntr];
-			ret = put_user(tmp, (u64*)(data+cntr));
+
+		for (i = 0; i < 32; i++) {
+			ret = put_user(*reg, tmp);
+			if (ret)
+				break;
+			reg++;
+			tmp++;
 		}
 		break;
 	}
 
 	case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */
-		u64 cntr;
+		int i;
+		unsigned long *reg = &((unsigned long *)child->thread.fpr)[0];
+		unsigned long *tmp = (unsigned long *)addr;
 
-		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; 
+
+		for (i = 0; i < 32; i++) {
+			ret = get_user(*reg, tmp);
+			if (ret)
+				break;
+			reg++;
+			tmp++;
+		}
 		break;
 	}
 
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/ptrace32.c linux-2.4.21-pre4/arch/ppc64/kernel/ptrace32.c
--- linux-2.4.21-pre3/arch/ppc64/kernel/ptrace32.c	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/ptrace32.c	Tue Jan 28 19:44:29 2003
@@ -228,9 +228,9 @@
 			if (child->thread.regs->msr & MSR_FP)
 				giveup_fpu(child);
 		        if (numReg == PT_FPSCR) 
-			        tmp_reg_value = ((unsigned int *)child->thread.fpscr);
+			        tmp_reg_value = ((unsigned long *)child->thread.fpscr);
 		        else 
-			        tmp_reg_value = ((unsigned long int *)child->thread.fpr)[numReg - PT_FPR0];
+			        tmp_reg_value = ((unsigned long *)child->thread.fpr)[numReg - PT_FPR0];
 		} else { /* register within PT_REGS struct */
 		    tmp_reg_value = get_reg(child, numReg);
 		} 
@@ -395,6 +395,74 @@
 		ret = ptrace_detach(child, data);
 		break;
 
+	case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */
+		int i;
+		unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
+		unsigned int *tmp = (unsigned int *)addr;
+
+		for (i = 0; i < 32; i++) {
+			ret = put_user(*reg, tmp);
+			if (ret)
+				break;
+			reg++;
+			tmp++;
+		}
+		break;
+	}
+
+	case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */
+		int i;
+		unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
+		unsigned int *tmp = (unsigned int *)addr;
+
+		for (i = 0; i < 32; i++) {
+			ret = get_user(*reg, tmp);
+			if (ret)
+				break;
+			reg++;
+			tmp++;
+		}
+		break;
+	}
+
+	case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */
+		int i;
+		unsigned long *reg = &((unsigned long *)child->thread.fpr)[0];
+		unsigned int *tmp = (unsigned int *)addr;
+
+		if (child->thread.regs->msr & MSR_FP)
+			giveup_fpu(child);
+
+		for (i = 0; i < 32; i++) {
+			ret = put_user(*reg, tmp);
+			if (ret)
+				break;
+			reg++;
+			tmp++;
+		}
+		break;
+	}
+
+	case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */
+		int i;
+		unsigned long *reg = &((unsigned long *)child->thread.fpr)[0];
+		unsigned int *tmp = (unsigned int *)addr;
+
+		if (child->thread.regs->msr & MSR_FP)
+			giveup_fpu(child);
+
+		for (i = 0; i < 32; i++) {
+			ret = get_user(*reg, tmp);
+			if (ret)
+				break;
+			reg++;
+			tmp++;
+		}
+		break;
+	}
+
+
+
 	default:
 		ret = -EIO;
 		break;
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/rtas-proc.c linux-2.4.21-pre4/arch/ppc64/kernel/rtas-proc.c
--- linux-2.4.21-pre3/arch/ppc64/kernel/rtas-proc.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/rtas-proc.c	Tue Jan 28 19:44:29 2003
@@ -162,26 +162,26 @@
 		size_t count, loff_t *ppos);
 
 struct file_operations ppc_rtas_poweron_operations = {
-	read:		ppc_rtas_poweron_read,
-	write:		ppc_rtas_poweron_write
+	.read =		ppc_rtas_poweron_read,
+	.write =	ppc_rtas_poweron_write
 };
 struct file_operations ppc_rtas_progress_operations = {
-	read:		ppc_rtas_progress_read,
-	write:		ppc_rtas_progress_write
+	.read =		ppc_rtas_progress_read,
+	.write =	ppc_rtas_progress_write
 };
 
 struct file_operations ppc_rtas_clock_operations = {
-	read:		ppc_rtas_clock_read,
-	write:		ppc_rtas_clock_write
+	.read =		ppc_rtas_clock_read,
+	.write =	ppc_rtas_clock_write
 };
 
 struct file_operations ppc_rtas_tone_freq_operations = {
-	read:		ppc_rtas_tone_freq_read,
-	write:		ppc_rtas_tone_freq_write
+	.read =		ppc_rtas_tone_freq_read,
+	.write =	ppc_rtas_tone_freq_write
 };
 struct file_operations ppc_rtas_tone_volume_operations = {
-	read:		ppc_rtas_tone_volume_read,
-	write:		ppc_rtas_tone_volume_write
+	.read =		ppc_rtas_tone_volume_read,
+	.write =	ppc_rtas_tone_volume_write
 };
 
 int ppc_rtas_find_all_sensors (void);
@@ -200,7 +200,7 @@
 	struct proc_dir_entry *entry;
 
 	rtas_node = find_devices("rtas");
-	if ((rtas_node == 0) || (naca->platform == PLATFORM_ISERIES_LPAR)) {
+	if ((rtas_node == 0) || (systemcfg->platform == PLATFORM_ISERIES_LPAR)) {
 		return;
 	}
 	
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/rtas.c linux-2.4.21-pre4/arch/ppc64/kernel/rtas.c
--- linux-2.4.21-pre3/arch/ppc64/kernel/rtas.c	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/rtas.c	Tue Jan 28 19:44:29 2003
@@ -53,11 +53,14 @@
  */
 
 struct rtas_t rtas = { 
-	lock: SPIN_LOCK_UNLOCKED
+	.lock = SPIN_LOCK_UNLOCKED
 };
 
 extern unsigned long reloc_offset(void);
 
+spinlock_t rtas_data_buf_lock = SPIN_LOCK_UNLOCKED;
+char rtas_data_buf[RTAS_DATA_BUF_SIZE];
+
 void
 phys_call_rtas(int token, int nargs, int nret, ...)
 {
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/rtasd.c linux-2.4.21-pre4/arch/ppc64/kernel/rtasd.c
--- linux-2.4.21-pre3/arch/ppc64/kernel/rtasd.c	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/rtasd.c	Tue Jan 28 19:44:29 2003
@@ -113,10 +113,10 @@
 }
 
 struct file_operations proc_rtas_log_operations = {
-	read:		rtas_log_read,
-	poll:		rtas_log_poll,
-	open:		rtas_log_open,
-	release:	rtas_log_release,
+	.read =		rtas_log_read,
+	.poll =		rtas_log_poll,
+	.open =		rtas_log_open,
+	.release =	rtas_log_release,
 };
 
 
@@ -623,25 +623,27 @@
 }
 
 #define MAX_LOG_DEBUG 10
+#define MAX_LOG_DEBUG_LEN 900
 /* 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);
+	unsigned char *p = (unsigned char *)_ALIGN((unsigned long)buf, 4);
 	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]);
+	while ((logged < MAX_LOG_DEBUG) && (len = ((p[0] << 8) | p[1])) >= 4) {
+		if (len > MAX_LOG_DEBUG_LEN)
+			len = MAX_LOG_DEBUG_LEN;	/* bound it */
+		printk("RTAS: Log Debug: %c%c ", p[2], p[3]);
 		for (n=4; n < len; n++)
 			printk("%02x", p[n]);
 		printk("\n");
-		p += len;
+		p = (unsigned char *)_ALIGN((unsigned long)p+len, 4);
 		logged++;
+		if (len == MAX_LOG_DEBUG_LEN)
+			return;	/* no point continuing */
 	}
 	if (logged == 0)
 		printk("RTAS: no log debug data present\n");
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/rtc.c linux-2.4.21-pre4/arch/ppc64/kernel/rtc.c
--- linux-2.4.21-pre3/arch/ppc64/kernel/rtc.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/rtc.c	Tue Jan 28 19:44:29 2003
@@ -178,12 +178,12 @@
  *	The various file operations we support.
  */
 static struct file_operations rtc_fops = {
-	owner:		THIS_MODULE,
-	llseek:		rtc_llseek,
-	read:		rtc_read,
-	ioctl:		rtc_ioctl,
-	open:		rtc_open,
-	release:	rtc_release,
+	.owner =	THIS_MODULE,
+	.llseek =	rtc_llseek,
+	.read =		rtc_read,
+	.ioctl =	rtc_ioctl,
+	.open =		rtc_open,
+	.release =	rtc_release,
 };
 
 static struct miscdevice rtc_dev=
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/scanlog.c linux-2.4.21-pre4/arch/ppc64/kernel/scanlog.c
--- linux-2.4.21-pre3/arch/ppc64/kernel/scanlog.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/arch/ppc64/kernel/scanlog.c	Tue Jan 28 19:44:29 2003
@@ -0,0 +1,234 @@
+/*
+ *  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.
+ *
+ * scan-log-data driver for PPC64  Todd Inglett <tinglett@vnet.ibm.com>
+ *
+ * When ppc64 hardware fails the service processor dumps internal state
+ * of the system.  After a reboot the operating system can access a dump
+ * of this data using this driver.  A dump exists if the device-tree
+ * /chosen/ibm,scan-log-data property exists.
+ *
+ * This driver exports /proc/ppc64/scan-log-dump which can be read.
+ * The driver supports only sequential reads.
+ *
+ * The driver looks at a write to the driver for the single word "reset".
+ * If given, the driver will reset the scanlog so the platform can free it.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <asm/rtas.h>
+#include <asm/prom.h>
+
+#define MODULE_VERSION "1.0"
+#define MODULE_NAME "scanlog"
+
+/* Status returns from ibm,scan-log-dump */
+#define SCANLOG_COMPLETE 0
+#define SCANLOG_HWERROR -1
+#define SCANLOG_CONTINUE 1
+
+#define DEBUG(A...) do { if (scanlog_debug) printk(KERN_ERR "scanlog: " A); } while (0)
+
+static int scanlog_debug;
+static unsigned int ibm_scan_log_dump;			/* RTAS token */
+static struct proc_dir_entry *proc_ppc64_scan_log_dump;	/* The proc file */
+
+
+static ssize_t scanlog_read(struct file *file, char *buf,
+			    size_t count, loff_t *ppos)
+{
+	struct proc_dir_entry *dp = file->f_dentry->d_inode->u.generic_ip;
+	unsigned int *data = (unsigned int *)dp->data;
+	unsigned long status;
+	unsigned long len, off;
+	unsigned int wait_time;
+
+	if (!data) {
+		printk(KERN_ERR "scanlog: read failed no data\n");
+		return -EIO;
+	}
+
+	if (count > RTAS_DATA_BUF_SIZE)
+		count = RTAS_DATA_BUF_SIZE;
+
+	if (count < 1024) {
+		/* This is the min supported by this RTAS call.  Rather
+		 * than do all the buffering we insist the user code handle
+		 * larger reads.  As long as cp works... :)
+		 */
+		printk(KERN_ERR "scanlog: cannot perform a small read (%ld)\n", count);
+		return -EINVAL;
+	}
+
+	if (verify_area(VERIFY_WRITE, buf, count))
+		return -EFAULT;
+
+	for (;;) {
+		wait_time = HZ/2;	/* default wait if no data */
+		spin_lock(&rtas_data_buf_lock);
+		memcpy(rtas_data_buf, data, RTAS_DATA_BUF_SIZE);
+		status = rtas_call(ibm_scan_log_dump, 2, 1, NULL,
+				   __pa(rtas_data_buf), count);
+		memcpy(data, rtas_data_buf, RTAS_DATA_BUF_SIZE);
+		spin_unlock(&rtas_data_buf_lock);
+
+		DEBUG("status=%ld, data[0]=%x, data[1]=%x, data[2]=%x\n",
+		      status, data[0], data[1], data[2]);
+		switch (status) {
+		    case SCANLOG_COMPLETE:
+			DEBUG("hit eof\n");
+			return 0;
+		    case SCANLOG_HWERROR:
+			DEBUG("hardware error reading scan log data\n");
+			return -EIO;
+		    case SCANLOG_CONTINUE:
+			/* We may or may not have data yet */
+			len = data[1];
+			off = data[2];
+			if (len > 0) {
+				if (copy_to_user(buf, ((char *)data)+off, len))
+					return -EFAULT;
+				return len;
+			}
+			/* Break to sleep default time */
+			break;
+		    default:
+			if (status > 9900 && status <= 9905) {
+				/* No data.  RTAS is hinting at a delay required
+				 * between 1-100000 milliseconds
+				 */
+				int ms = 1;
+				for (; status > 9900; status--)
+					ms = ms * 10;
+				/* Use microseconds for reasonable accuracy */
+				ms *= 1000;
+				wait_time = ms / (1000000/HZ); /* round down is fine */
+				/* Fall through to sleep */
+			} else {
+				printk(KERN_ERR "scanlog: unknown error from rtas: %ld\n", status);
+				return -EIO;
+			}
+		}
+		/* Apparently no data yet.  Wait and try again. */
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(wait_time);
+	}
+	/*NOTREACHED*/
+}
+
+static ssize_t scanlog_write(struct file * file, const char * buf,
+			     size_t count, loff_t *ppos)
+{
+	unsigned long status;
+
+	if (buf) {
+		if (strncmp(buf, "reset", 5) == 0) {
+			DEBUG("reset scanlog\n");
+			status = rtas_call(ibm_scan_log_dump, 2, 1, NULL, NULL, 0);
+			DEBUG("rtas returns %ld\n", status);
+		} else if (strncmp(buf, "debugon", 7) == 0) {
+			printk(KERN_ERR "scanlog: debug on\n");
+			scanlog_debug = 1;
+		} else if (strncmp(buf, "debugoff", 8) == 0) {
+			printk(KERN_ERR "scanlog: debug off\n");
+			scanlog_debug = 0;
+		}
+	}
+	return count;
+}
+
+static int scanlog_open(struct inode * inode, struct file * file)
+{
+	struct proc_dir_entry *dp = file->f_dentry->d_inode->u.generic_ip;
+	unsigned int *data = (unsigned int *)dp->data;
+
+	if (!data) {
+		printk(KERN_ERR "scanlog: open failed no data\n");
+		return -EIO;
+	}
+	if (data[0] != 0) {
+		/* This imperfect test stops a second copy of the
+		 * data (or a reset while data is being copied)
+		 */
+		return -EBUSY;
+	}
+
+	data[0] = 0;	/* re-init so we restart the scan */
+
+	return 0;
+}
+
+static int scanlog_release(struct inode * inode, struct file * file)
+{
+	struct proc_dir_entry *dp = file->f_dentry->d_inode->u.generic_ip;
+	unsigned int *data = (unsigned int *)dp->data;
+
+	if (!data) {
+		printk(KERN_ERR "scanlog: release failed no data\n");
+		return -EIO;
+	}
+	data[0] = 0;
+
+	return 0;
+}
+
+struct file_operations scanlog_fops = {
+	owner:		THIS_MODULE,
+	read:		scanlog_read,
+	write:		scanlog_write,
+	open:		scanlog_open,
+	release:	scanlog_release,
+};
+
+int __init scanlog_init(void)
+{
+	struct proc_dir_entry *ent;
+
+	ibm_scan_log_dump = rtas_token("ibm,scan-log-dump");
+	if (ibm_scan_log_dump == RTAS_UNKNOWN_SERVICE) {
+		printk(KERN_ERR "scan-log-dump not implemented on this system\n");
+		return -EIO;
+	}
+
+	ent = create_proc_entry("ppc64/scan-log-dump", S_IRUSR, NULL);
+	if (ent) {
+		ent->proc_fops = &scanlog_fops;
+		/* Ideally we could allocate a buffer < 4G */
+		ent->data = kmalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL);
+		if (!ent->data) {
+			printk(KERN_ERR "Failed to allocate a buffer\n");
+			remove_proc_entry("scan-log-dump", ent->parent);
+			return -ENOMEM;
+		}
+		((unsigned int *)ent->data)[0] = 0;
+	} else {
+		printk(KERN_ERR "Failed to create ppc64/scan-log-dump proc entry\n");
+		return -EIO;
+	}
+	proc_ppc64_scan_log_dump = ent;
+
+	return 0;
+}
+
+void __exit scanlog_cleanup(void)
+{
+	if (proc_ppc64_scan_log_dump) {
+		if (proc_ppc64_scan_log_dump->data)
+		    kfree(proc_ppc64_scan_log_dump->data);
+		remove_proc_entry("scan-log-dump", proc_ppc64_scan_log_dump->parent);
+	}
+}
+
+module_init(scanlog_init);
+module_exit(scanlog_cleanup);
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/setup.c linux-2.4.21-pre4/arch/ppc64/kernel/setup.c
--- linux-2.4.21-pre3/arch/ppc64/kernel/setup.c	Tue Jan 28 19:44:25 2003
+++ linux-2.4.21-pre4/arch/ppc64/kernel/setup.c	Tue Jan 28 19:44:29 2003
@@ -37,12 +37,16 @@
 #include <asm/paca.h>
 #include <asm/ppcdebug.h>
 #include <asm/time.h>
+#ifdef CONFIG_KDB
+#include <linux/kdb.h>
+#endif
 
 extern unsigned long klimit;
 /* extern void *stab; */
 extern HTAB htab_data;
 extern unsigned long loops_per_jiffy;
 extern int preferred_console;	/* from kernel/printk.c */
+extern int blk_nohighio;
 
 extern unsigned long embedded_sysmap_start;
 extern unsigned long embedded_sysmap_end;
@@ -116,7 +120,7 @@
 int icache_bsize;
 int ucache_bsize;
 
-static struct console udbg_console = {
+struct console udbg_console = {
 	name:	"udbg",
 	write:	udbg_console_write,
 	flags:	CON_PRINTBUFFER,
@@ -135,9 +139,9 @@
 
 	/* pSeries systems are identified in prom.c via OF. */
 	if ( itLpNaca.xLparInstalled == 1 )
-		naca->platform = PLATFORM_ISERIES_LPAR;
+		systemcfg->platform = PLATFORM_ISERIES_LPAR;
 	
-	switch (naca->platform) {
+	switch (systemcfg->platform) {
 	case PLATFORM_ISERIES_LPAR:
 		iSeries_init_early();
 		break;
@@ -161,42 +165,40 @@
 #endif
 	}
 
-	if (naca->platform & PLATFORM_PSERIES) {
+	if (systemcfg->platform & PLATFORM_PSERIES) {
 		register_console(&udbg_console);
 		preferred_console = -1;
+		udbg_printf("---- start early boot console ----\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("naca                          = 0x%p\n", naca);
+	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("systemcf                      = 0x%p\n", systemcfg);
+	printk("systemcfg->processorCount     = 0x%x\n", systemcfg->processorCount);
+	printk("systemcfg->physicalMemorySize = 0x%lx\n", systemcfg->physicalMemorySize);
+	printk("systemcfg->dCacheL1LineSize   = 0x%x\n", systemcfg->dCacheL1LineSize);
+	printk("systemcfg->iCacheL1LineSize   = 0x%x\n", systemcfg->iCacheL1LineSize);
+	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) {
+	if (systemcfg->platform & PLATFORM_PSERIES) {
 		finish_device_tree();
 		chrp_init(r3, r4, r5, r6, r7);
 	}
 
 	mm_init_ppc64();
 
-	switch (naca->platform) {
-	    case PLATFORM_ISERIES_LPAR:
+	switch (systemcfg->platform) {
+	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);
@@ -210,10 +212,12 @@
  */
 void setup_before_console_init(void)
 {
-	if (naca->platform & PLATFORM_PSERIES) {
+	if (systemcfg->platform & PLATFORM_PSERIES) {
 		int save = preferred_console;
 		unregister_console(&udbg_console);
+		udbg_console.next = NULL;
 		preferred_console = save;
+		udbg_printf("---- end early boot console ----\n");
 	}
 }
 
@@ -298,7 +302,7 @@
 	 * Assume here that all clock rates are the same in a
 	 * smp system.  -- Cort
 	 */
-	if (naca->platform != PLATFORM_ISERIES_LPAR) {
+	if (systemcfg->platform != PLATFORM_ISERIES_LPAR) {
 		struct device_node *cpu_node;
 		int *fp;
 
@@ -333,10 +337,10 @@
 {
 }
 struct seq_operations cpuinfo_op = {
-	start:	c_start,
-	next:	c_next,
-	stop:	c_stop,
-	show:	show_cpuinfo,
+	.start =c_start,
+	.next =	c_next,
+	.stop =	c_stop,
+	.show =	show_cpuinfo,
 };
 
 /*
@@ -356,6 +360,40 @@
 	}
 #endif
 
+	/* Hack -- add console=ttySn,9600 if necessary */
+	if(strstr(cmd_line, "console=") == NULL) {
+		struct device_node *prom_stdout = find_path_device(of_stdout_device);
+		u32 *reg;
+		int i;
+		char *name, *val = NULL;
+		printk("of_stdout_device %s\n", of_stdout_device);
+		if (prom_stdout) {
+			name = (char *)get_property(prom_stdout, "name", NULL);
+			if (name) {
+				if (strcmp(name, "serial") == 0) {
+					reg = (u32 *)get_property(prom_stdout, "reg", &i);
+					if (i > 8) {
+						switch (reg[1]) {
+						    case 0x3f8: val = "ttyS0,9600"; break; 
+						    case 0x2f8: val = "ttyS1,9600"; break; 
+						    case 0x898: val = "ttyS2,9600"; break; 
+						    case 0x890: val = "ttyS3,9600"; break; 
+						}
+					}
+				} else if (strcmp(name, "vty") == 0) {
+					/* pSeries LPAR virtual console */
+					val = "hvc0";
+				}
+				if (val) {
+					i = strlen(cmd_line);
+					sprintf(cmd_line + i, " AUTOCONSOLE console=%s", val);
+					printk("console= not found, add console=%s\ncmd_line is now %s\n",
+					       val, cmd_line);
+				}
+			}
+		}
+	}	
+
 	/* Look for mem= option on command line */
 	if (strstr(cmd_line, "mem=")) {
 		char *q;
@@ -457,6 +495,7 @@
 }	
 
 extern void (*calibrate_delay)(void);
+extern void sort_exception_table(void);
 
 /*
  * Called into from start_kernel, after lock_kernel has been called.
@@ -469,6 +508,8 @@
 	extern char _etext[], _edata[];
 	extern void do_init_bootmem(void);
 
+	blk_nohighio = 1;
+
 	calibrate_delay = ppc64_calibrate_delay;
 
 	ppc64_boot_msg(0x12, "Setup Arch");
@@ -494,8 +535,8 @@
 	 * Systems with OF can look in the properties on the cpu node(s)
 	 * for a possibly more accurate value.
 	 */
-	dcache_bsize = naca->dCacheL1LineSize; 
-	icache_bsize = naca->iCacheL1LineSize; 
+	dcache_bsize = systemcfg->dCacheL1LineSize; 
+	icache_bsize = systemcfg->iCacheL1LineSize; 
 
 	/* reboot on panic */
 	panic_timeout = 180;
@@ -515,108 +556,10 @@
 	ppc_md.setup_arch();
 
 	paging_init();
+	sort_exception_table();
 	ppc64_boot_msg(0x15, "Setup Done");
 }
 
-#ifdef CONFIG_IDE
-
-/* Convert the shorts/longs in hd_driveid from little to big endian;
- * chars are endian independant, of course, but strings need to be flipped.
- * (Despite what it says in drivers/block/ide.h, they come up as little
- * endian...)
- *
- * Changes to linux/hdreg.h may require changes here. */
-void ppc64_ide_fix_driveid(struct hd_driveid *id)
-{
-        int i;
-	unsigned short *stringcast;
-
-	id->config         = __le16_to_cpu(id->config);
-	id->cyls           = __le16_to_cpu(id->cyls);
-	id->reserved2      = __le16_to_cpu(id->reserved2);
-	id->heads          = __le16_to_cpu(id->heads);
-	id->track_bytes    = __le16_to_cpu(id->track_bytes);
-	id->sector_bytes   = __le16_to_cpu(id->sector_bytes);
-	id->sectors        = __le16_to_cpu(id->sectors);
-	id->vendor0        = __le16_to_cpu(id->vendor0);
-	id->vendor1        = __le16_to_cpu(id->vendor1);
-	id->vendor2        = __le16_to_cpu(id->vendor2);
-	stringcast = (unsigned short *)&id->serial_no[0];
-	for (i = 0; i < (20/2); i++)
-	        stringcast[i] = __le16_to_cpu(stringcast[i]);
-	id->buf_type       = __le16_to_cpu(id->buf_type);
-	id->buf_size       = __le16_to_cpu(id->buf_size);
-	id->ecc_bytes      = __le16_to_cpu(id->ecc_bytes);
-	stringcast = (unsigned short *)&id->fw_rev[0];
-	for (i = 0; i < (8/2); i++)
-	        stringcast[i] = __le16_to_cpu(stringcast[i]);
-	stringcast = (unsigned short *)&id->model[0];
-	for (i = 0; i < (40/2); i++)
-	        stringcast[i] = __le16_to_cpu(stringcast[i]);
-	id->dword_io       = __le16_to_cpu(id->dword_io);
-	id->reserved50     = __le16_to_cpu(id->reserved50);
-	id->field_valid    = __le16_to_cpu(id->field_valid);
-	id->cur_cyls       = __le16_to_cpu(id->cur_cyls);
-	id->cur_heads      = __le16_to_cpu(id->cur_heads);
-	id->cur_sectors    = __le16_to_cpu(id->cur_sectors);
-	id->cur_capacity0  = __le16_to_cpu(id->cur_capacity0);
-	id->cur_capacity1  = __le16_to_cpu(id->cur_capacity1);
-	id->lba_capacity   = __le32_to_cpu(id->lba_capacity);
-	id->dma_1word      = __le16_to_cpu(id->dma_1word);
-	id->dma_mword      = __le16_to_cpu(id->dma_mword);
-	id->eide_pio_modes = __le16_to_cpu(id->eide_pio_modes);
-	id->eide_dma_min   = __le16_to_cpu(id->eide_dma_min);
-	id->eide_dma_time  = __le16_to_cpu(id->eide_dma_time);
-	id->eide_pio       = __le16_to_cpu(id->eide_pio);
-	id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy);
-	for (i = 0; i < 2; i++)
-		id->words69_70[i] = __le16_to_cpu(id->words69_70[i]);
-        for (i = 0; i < 4; i++)
-                id->words71_74[i] = __le16_to_cpu(id->words71_74[i]);
-	id->queue_depth	   = __le16_to_cpu(id->queue_depth);
-	for (i = 0; i < 4; i++)
-		id->words76_79[i] = __le16_to_cpu(id->words76_79[i]);
-	id->major_rev_num  = __le16_to_cpu(id->major_rev_num);
-	id->minor_rev_num  = __le16_to_cpu(id->minor_rev_num);
-	id->command_set_1  = __le16_to_cpu(id->command_set_1);
-	id->command_set_2  = __le16_to_cpu(id->command_set_2);
-	id->cfsse          = __le16_to_cpu(id->cfsse);
-	id->cfs_enable_1   = __le16_to_cpu(id->cfs_enable_1);
-	id->cfs_enable_2   = __le16_to_cpu(id->cfs_enable_2);
-	id->csf_default    = __le16_to_cpu(id->csf_default);
-	id->dma_ultra      = __le16_to_cpu(id->dma_ultra);
-	id->trseuc         = __le16_to_cpu(id->trseuc);
-	id->trsEuc         = __le16_to_cpu(id->trsEuc);
-	id->CurAPMvalues   = __le16_to_cpu(id->CurAPMvalues);
-	id->mprc           = __le16_to_cpu(id->mprc);
-	id->hw_config      = __le16_to_cpu(id->hw_config);
-	id->acoustic       = __le16_to_cpu(id->acoustic);
-	id->msrqs          = __le16_to_cpu(id->msrqs);
-	id->sxfert         = __le16_to_cpu(id->sxfert);
-	id->sal            = __le16_to_cpu(id->sal);
-	id->spg            = __le32_to_cpu(id->spg);
-	id->lba_capacity_2 = __le64_to_cpu(id->lba_capacity_2);
-	for (i = 0; i < 22; i++)
-		id->words104_125[i]   = __le16_to_cpu(id->words104_125[i]);
-	id->last_lun       = __le16_to_cpu(id->last_lun);
-	id->word127        = __le16_to_cpu(id->word127);
-	id->dlf            = __le16_to_cpu(id->dlf);
-	id->csfo           = __le16_to_cpu(id->csfo);
-	for (i = 0; i < 26; i++)
-		id->words130_155[i] = __le16_to_cpu(id->words130_155[i]);
-	id->word156        = __le16_to_cpu(id->word156);
-	for (i = 0; i < 3; i++)
-		id->words157_159[i] = __le16_to_cpu(id->words157_159[i]);
-	id->cfa_power      = __le16_to_cpu(id->cfa_power);
-	for (i = 0; i < 14; i++)
-		id->words161_175[i] = __le16_to_cpu(id->words161_175[i]);
-	for (i = 0; i < 31; i++)
-		id->words176_205[i] = __le16_to_cpu(id->words176_205[i]);
-	for (i = 0; i < 48; i++)
-		id->words206_254[i] = __le16_to_cpu(id->words206_254[i]);
-	id->integrity_word  = __le16_to_cpu(id->integrity_word);
-}
-#endif
 
 /* ToDo: do something useful if ppc_md is not yet setup. */
 #define PPC64_LINUX_FUNCTION 0x0f000000
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/signal.c linux-2.4.21-pre4/arch/ppc64/kernel/signal.c
--- linux-2.4.21-pre3/arch/ppc64/kernel/signal.c	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/signal.c	Tue Jan 28 19:44:29 2003
@@ -43,24 +43,42 @@
 #endif
 
 #define GP_REGS_SIZE	MIN(sizeof(elf_gregset_t), sizeof(struct pt_regs))
+#define FP_REGS_SIZE	sizeof(elf_fpregset_t)
 
-/* 
- * These are the flags in the MSR that the user is allowed to change
- * by modifying the saved value of the MSR on the stack.  SE and BE
- * should not be in this list since gdb may want to change these.  I.e,
- * you should be able to step out of a signal handler to see what
- * instruction executes next after the signal handler completes.
- * Alternately, if you stepped into a signal handler, you should be
- * able to continue 'til the next breakpoint from within the signal
- * handler, even if the handler returns.
+#define TRAMP_TRACEBACK	2
+#define TRAMP_SIZE	6
+
+/*
+ * When we have signals to deliver, we set up on the user stack,
+ * going down from the original stack pointer:
+ *	1) a sigframe/rt_sigframe struct which contains the sigcontext/ucontext	
+ *	2) a gap of __SIGNAL_FRAMESIZE bytes which acts as a dummy caller
+ *	   frame for the signal handler.
  */
-#define MSR_USERCHANGE	(MSR_FE0 | MSR_FE1)
 
-int do_signal(sigset_t *oldset, struct pt_regs *regs);
+struct sigframe {
+	struct sigcontext sc;
+	unsigned int tramp[TRAMP_SIZE];
+	/* 64 bit ABI allows for 288 bytes below sp before decrementing it. */
+	char abigap[288];
+};
+
+struct rt_sigframe {
+	unsigned long _unused[2];
+	unsigned int tramp[TRAMP_SIZE];
+	struct siginfo *pinfo;
+	void *puc;
+	struct siginfo info;
+	struct ucontext uc;
+	/* 64 bit ABI allows for 288 bytes below sp before decrementing it. */
+	char abigap[288];
+};
+
 extern long sys_wait4(pid_t pid, unsigned int *stat_addr,
 		     int options, /*unsigned long*/ struct rusage *ru);
 
-int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
+int
+copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
 {
 	if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
 		return -EFAULT;
@@ -95,18 +113,16 @@
 	}
 }
 
+int do_signal(sigset_t *oldset, struct pt_regs *regs);
+
 /*
  * Atomically swap in the new signal mask, and wait for a signal.
  */
-long sys_sigsuspend(old_sigset_t mask, int p2, int p3, int p4, int p6, int p7,
+asmlinkage long
+sys_sigsuspend(old_sigset_t mask, int p2, int p3, int p4, int p6, int p7,
 	       struct pt_regs *regs)
 {
 	sigset_t saveset;
-  
-        PPCDBG(PPCDBG_SYS64X, "sys_sigsuspend - running - pid=%ld current=%lx comm=%s \n",
-                current->pid, current, current->comm);
-
-
 
 	mask &= _BLOCKABLE;
 	spin_lock_irq(&current->sigmask_lock);
@@ -115,7 +131,9 @@
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
 
-	regs->gpr[3] = -EINTR;
+	regs->result = -EINTR;
+	regs->gpr[3] = EINTR;
+	regs->ccr |= 0x10000000;
 	while (1) {
 		current->state = TASK_INTERRUPTIBLE;
 		schedule();
@@ -132,16 +150,13 @@
 	}
 }
 
-long sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, int p3, int p4, int p6,
+asmlinkage long
+sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, int p3, int p4, int p6,
 		  int p7, struct pt_regs *regs)
 {
 	sigset_t saveset, newset;
 
-  
-        PPCDBG(PPCDBG_SYS64X, "sys_rt_sigsuspend - running - pid=%ld current=%lx comm=%s \n",
-                current->pid, current, current->comm);
-	
-  /* XXX: Don't preclude handling different sized sigset_t's.  */
+	/* XXX: Don't preclude handling different sized sigset_t's.  */
 	if (sigsetsize != sizeof(sigset_t))
 		return -EINVAL;
 
@@ -155,7 +170,9 @@
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
 
-	regs->gpr[3] = -EINTR;
+	regs->result = -EINTR;
+	regs->gpr[3] = EINTR;
+	regs->ccr |= 0x10000000;
 	while (1) {
 		current->state = TASK_INTERRUPTIBLE;
 		schedule();
@@ -164,31 +181,24 @@
 	}
 }
 
-
-
-asmlinkage long sys_sigaltstack(const stack_t *uss, stack_t *uoss)
+asmlinkage long
+sys_sigaltstack(const stack_t *uss, stack_t *uoss, unsigned long r5,
+		unsigned long r6, unsigned long r7, unsigned long r8,
+		struct pt_regs *regs)
 {
-  struct pt_regs *regs = (struct pt_regs *) &uss;
-  
-  PPCDBG(PPCDBG_SYS64X, "sys_sigaltstack - running - pid=%ld current=%lx comm=%s \n",
-          current->pid, current, current->comm);
-
-  return do_sigaltstack(uss, uoss, regs->gpr[1]);
+        return do_sigaltstack(uss, uoss, regs->gpr[1]);
 }
 
-long sys_sigaction(int sig, const struct old_sigaction *act,
+asmlinkage long
+sys_sigaction(int sig, const struct old_sigaction *act,
 	      struct old_sigaction *oact)
 {
 	struct k_sigaction new_ka, old_ka;
 	int ret;
 
-        PPCDBG(PPCDBG_SYS64X, "sys_sigaction - running - pid=%ld current=%lx comm=%s \n",
-                current->pid, current, current->comm);
-
- 
-
 	if (act) {
 		old_sigset_t mask;
+
 		if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
 		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
 		    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
@@ -199,7 +209,6 @@
 	}
 
 	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
-
 	if (!ret && oact) {
 		if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
 		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
@@ -209,193 +218,199 @@
 		__put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
 	}
 
-
- 
-
 	return ret;
 }
 
 /*
- * When we have signals to deliver, we set up on the
- * user stack, going down from the original stack pointer:
- *	a sigregs struct
- *	one or more sigcontext structs
- *	a gap of __SIGNAL_FRAMESIZE bytes
- *
- * Each of these things must be a multiple of 16 bytes in size.
- *
- * XXX ultimately we will have to stack up a siginfo and ucontext
- * for each rt signal.
+ * Set up the sigcontext for the signal frame.
  */
-struct sigregs {
-	elf_gregset_t	gp_regs;
-	double		fp_regs[ELF_NFPREG];
-	unsigned int	tramp[2];
-	/* 64 bit API allows for 288 bytes below sp before 
-	   decrementing it. */
-	int		abigap[72];
-};
 
+static int
+setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
+		 int signr, sigset_t *set, unsigned long handler)
+{
+	int err = 0;
+
+	if (regs->msr & MSR_FP)
+		giveup_fpu(current);
+
+	current->thread.saved_msr = regs->msr & ~(MSR_FP | MSR_FE0 | MSR_FE1);
+	regs->msr = current->thread.saved_msr | current->thread.fpexc_mode;
+	current->thread.saved_softe = regs->softe;
+
+	err |= __put_user(&sc->gp_regs, &sc->regs);
+	err |= __copy_to_user(&sc->gp_regs, regs, GP_REGS_SIZE);
+	err |= __copy_to_user(&sc->fp_regs, &current->thread.fpr, FP_REGS_SIZE);
+	err |= __put_user(signr, &sc->signal);
+	err |= __put_user(handler, &sc->handler);
+	if (set != NULL)
+		err |=  __put_user(set->sig[0], &sc->oldmask);
 
+	regs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1);
+	current->thread.fpscr = 0;
 
-struct rt_sigframe
+	return err;
+}
+
+/*
+ * Restore the sigcontext from the signal frame.
+ */
+
+static int
+restore_sigcontext(struct pt_regs *regs, sigset_t *set, struct sigcontext *sc)
 {
-	unsigned long	_unused[2];
-	struct siginfo *pinfo;
-	void *puc;
-	struct siginfo info;
-	struct ucontext uc;
-};
+	unsigned int err = 0;
 
+	if (regs->msr & MSR_FP)
+		giveup_fpu(current);
+
+	err |= __copy_from_user(regs, &sc->gp_regs, GP_REGS_SIZE);
+	err |= __copy_from_user(&current->thread.fpr, &sc->fp_regs, FP_REGS_SIZE);
+	current->thread.fpexc_mode = regs->msr & (MSR_FE0 | MSR_FE1);
+	if (set != NULL)
+		err |=  __get_user(set->sig[0], &sc->oldmask);
+
+	/* Don't allow the signal handler to change these modulo FE{0,1} */
+	regs->msr = current->thread.saved_msr & ~(MSR_FP | MSR_FE0 | MSR_FE1);
+	regs->softe = current->thread.saved_softe;
+
+	return err;
+}
 
 /*
- *  When we have rt signals to deliver, we set up on the
- *  user stack, going down from the original stack pointer:
- *	   a sigregs struct
- *	   one rt_sigframe struct (siginfo + ucontext)
- *	   a gap of __SIGNAL_FRAMESIZE bytes
- *
- *  Each of these things must be a multiple of 16 bytes in size.
- *
+ * Allocate space for the signal frame
  */
+static inline void *
+get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
+{
+        unsigned long newsp;
 
-int sys_rt_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5,
-		     unsigned long r6, unsigned long r7, unsigned long r8,
-		     struct pt_regs *regs)
-{
-	struct rt_sigframe *rt_sf;
-	struct sigcontext_struct sigctx;
-	struct sigregs *sr;
-	int ret;
-	elf_gregset_t saved_regs;  /* an array of ELF_NGREG unsigned longs */
+        /* Default to using normal stack */
+        newsp = regs->gpr[1];
+
+	if (ka->sa.sa_flags & SA_ONSTACK) {
+		if (! on_sig_stack(regs->gpr[1]))
+			newsp = (current->sas_ss_sp + current->sas_ss_size);
+	}
+
+        return (void *)((newsp - frame_size) & -8ul);
+}
+
+asmlinkage int
+sys_rt_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5,
+		 unsigned long r6, unsigned long r7, unsigned long r8,
+		 struct pt_regs *regs)
+{
+	struct rt_sigframe *frame;
 	sigset_t set;
 	stack_t st;
-	unsigned long prevsp;
 
-	rt_sf = (struct rt_sigframe *)(regs->gpr[1] + __SIGNAL_FRAMESIZE);
-	if (copy_from_user(&sigctx, &rt_sf->uc.uc_mcontext, sizeof(sigctx))
-	    || copy_from_user(&set, &rt_sf->uc.uc_sigmask, sizeof(set))
-	    || copy_from_user(&st, &rt_sf->uc.uc_stack, sizeof(st)))
+	frame = (struct rt_sigframe *)(regs->gpr[1] + __SIGNAL_FRAMESIZE);
+
+	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
+
+	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
+		goto badframe;
+
 	sigdelsetmask(&set, ~_BLOCKABLE);
 	spin_lock_irq(&current->sigmask_lock);
 	current->blocked = set;
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
 
-	rt_sf++;			/* Look at next rt_sigframe */
-	if (rt_sf == (struct rt_sigframe *)(sigctx.regs)) {
-		/* Last stacked signal - restore registers -
-		 * sigctx is initialized to point to the 
-		 * preamble frame (where registers are stored) 
-		 * see handle_signal()
-		 */
-		sr = (struct sigregs *) sigctx.regs;
-		if (regs->msr & MSR_FP )
-			giveup_fpu(current);
-		if (copy_from_user(saved_regs, &sr->gp_regs,
-				   sizeof(sr->gp_regs)))
-			goto badframe;
-		saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE)
-			| (saved_regs[PT_MSR] & MSR_USERCHANGE);
-		saved_regs[PT_SOFTE] = regs->softe;
-		memcpy(regs, saved_regs, GP_REGS_SIZE);
-		if (copy_from_user(current->thread.fpr, &sr->fp_regs,
-				   sizeof(sr->fp_regs)))
-			goto badframe;
-		/* This function sets back the stack flags into
-		   the current task structure.  */
-		sys_sigaltstack(&st, NULL);
-
-		ret = regs->result;
-	} else {
-		/* More signals to go */
-		/* Set up registers for next signal handler */
-		regs->gpr[1] = (unsigned long)rt_sf - __SIGNAL_FRAMESIZE;
-		if (copy_from_user(&sigctx, &rt_sf->uc.uc_mcontext, sizeof(sigctx)))
-			goto badframe;
-		sr = (struct sigregs *) sigctx.regs;
-		regs->gpr[3] = ret = sigctx.signal;
-		/* Get the siginfo   */
-		get_user(regs->gpr[4], (unsigned long *)&rt_sf->pinfo);
-		/* Get the ucontext */
-		get_user(regs->gpr[5], (unsigned long *)&rt_sf->puc);
-		regs->gpr[6] = (unsigned long) rt_sf;
-
-		regs->link = (unsigned long) &sr->tramp;
-		regs->nip = sigctx.handler;
-		if (get_user(prevsp, &sr->gp_regs[PT_R1])
-		    || put_user(prevsp, (unsigned long *) regs->gpr[1]))
-			goto badframe;
-	}
-	return ret;
+	if (restore_sigcontext(regs, NULL, &frame->uc.uc_mcontext))
+		goto badframe;
+
+	if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
+		goto badframe;
+
+	/* This function sets back the stack flags into
+	   the current task structure.  */
+	sys_sigaltstack(&st, NULL, 0, 0, 0, 0, regs);
+
+	return regs->result;
 
 badframe:
 	do_exit(SIGSEGV);
 }
 
 static void
-setup_rt_frame(struct pt_regs *regs, struct sigregs *frame,
-	       signed long newsp)
+setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info,
+		sigset_t *set, struct pt_regs *regs)
 {
-	struct rt_sigframe *rt_sf = (struct rt_sigframe *) newsp;
 	/* Handler is *really* a pointer to the function descriptor for
 	 * the signal routine.  The first entry in the function
 	 * descriptor is the entry address of signal and the second
 	 * entry is the TOC value we need to use.
 	 */
-        struct funct_descr_entry {
-                     unsigned long entry;
-                     unsigned long toc;
-	};
-  
-	struct funct_descr_entry * funct_desc_ptr;
-	unsigned long temp_ptr;
+	func_descr_t *funct_desc_ptr;
+	struct rt_sigframe *frame;
+	unsigned long newsp;
+	int i, err = 0;
+
+	frame = get_sigframe(ka, regs, sizeof(*frame));
 
-	/* Set up preamble frame */
 	if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
-		goto badframe;
-	if (regs->msr & MSR_FP)
-		giveup_fpu(current);
-	if (__copy_to_user(&frame->gp_regs, regs, GP_REGS_SIZE)
-	    || __copy_to_user(&frame->fp_regs, current->thread.fpr,
-			      ELF_NFPREG * sizeof(double))
-	    || __put_user(0x38000000UL + __NR_rt_sigreturn, &frame->tramp[0])	/* li r0, __NR_rt_sigreturn */
-	    || __put_user(0x44000002UL, &frame->tramp[1]))	/* sc */
-		goto badframe;
-	flush_icache_range((unsigned long) &frame->tramp[0],
-			   (unsigned long) &frame->tramp[2]);
+		goto give_sigsegv;
 
-	/* Retrieve rt_sigframe from stack and
-	   set up registers for signal handler
-	*/
-	newsp -= __SIGNAL_FRAMESIZE;
+	err |= __put_user(&frame->info, &frame->pinfo);
+	err |= __put_user(&frame->uc, &frame->puc);
+	err |= copy_siginfo_to_user(&frame->info, info);
+	if (err)
+		goto give_sigsegv;
+
+	/* Create the ucontext.  */
+	err |= __put_user(0, &frame->uc.uc_flags);
+	err |= __put_user(0, &frame->uc.uc_link);
+	err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
+	err |= __put_user(sas_ss_flags(regs->gpr[1]),
+			  &frame->uc.uc_stack.ss_flags);
+	err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+	err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, signr, NULL,
+				(unsigned long)ka->sa.sa_handler);
+	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+	if (err)
+		goto give_sigsegv;
+
+	/* Set up to return from userspace. */
+	/* li r0, __NR_rt_sigreturn */
+	err |= __put_user(0x38000000UL + __NR_rt_sigreturn, &frame->tramp[0]);
+	/* sc */
+	err |= __put_user(0x44000002UL, &frame->tramp[1]);
+	/* Minimal traceback info */
+	for (i=TRAMP_TRACEBACK; i < TRAMP_SIZE ;i++)
+		err |= __put_user(0, &frame->tramp[i]);
+	if (err)
+		goto give_sigsegv;
 
-        if ( get_user(temp_ptr, &rt_sf->uc.uc_mcontext.handler)) {
-		goto badframe;
-	}
+	flush_icache_range((unsigned long) &frame->tramp[0],
+			   (unsigned long) &frame->tramp[TRAMP_SIZE]);
 
-        funct_desc_ptr = ( struct funct_descr_entry *) temp_ptr;
-        
-	if (put_user(regs->gpr[1], (unsigned long *)newsp)
-	    || get_user(regs->nip, &funct_desc_ptr->entry)
-            || get_user(regs->gpr[2], &funct_desc_ptr->toc)
-	    || get_user(regs->gpr[3], &rt_sf->uc.uc_mcontext.signal)
-	    || get_user(regs->gpr[4], (unsigned long *)&rt_sf->pinfo)
-	    || get_user(regs->gpr[5], (unsigned long *)&rt_sf->puc))
-		goto badframe;
+	funct_desc_ptr = (func_descr_t *) ka->sa.sa_handler;
 
+	/* Allocate a dummy caller frame for the signal handler. */
+	newsp = (unsigned long)frame - __SIGNAL_FRAMESIZE;
+	err |= put_user(0, (unsigned long *)newsp);
+
+	/* Set up "regs" so we "return" to the signal handler. */
+	err |= get_user(regs->nip, &funct_desc_ptr->entry);
+	regs->link = (unsigned long) &frame->tramp[0];
 	regs->gpr[1] = newsp;
-	regs->gpr[6] = (unsigned long) rt_sf;
-	regs->link = (unsigned long) frame->tramp;
+	err |= get_user(regs->gpr[2], &funct_desc_ptr->toc);
+	regs->gpr[3] = signr;
+	err |= get_user(regs->gpr[4], (unsigned long *)&frame->pinfo);
+	err |= get_user(regs->gpr[5], (unsigned long *)&frame->puc);
+	regs->gpr[6] = (unsigned long) frame;
+	if (err)
+		goto give_sigsegv;
 
-	
 	return;
 
-badframe:
+give_sigsegv:
 #if DEBUG_SIG
-	printk("badframe in setup_rt_frame, regs=%p frame=%p newsp=%lx\n",
-	       regs, frame, newsp);
+	printk("badframe in setup_rt_frame, regs=%p frame=%p, newsp=0x%lx\n",
+		regs, frame, newsp);
 #endif
 	do_exit(SIGSEGV);
 }
@@ -403,131 +418,90 @@
 /*
  * Do a signal return; undo the signal stack.
  */
-long sys_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5,
-		   unsigned long r6, unsigned long r7, unsigned long r8,
-		   struct pt_regs *regs)
-{
-	struct sigcontext_struct *sc, sigctx;
-	struct sigregs *sr;
-	long ret;
-	elf_gregset_t saved_regs;  /* an array of ELF_NGREG unsigned longs */
+asmlinkage long
+sys_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5,
+	      unsigned long r6, unsigned long r7, unsigned long r8,
+	      struct pt_regs *regs)
+{
+	struct sigframe *frame;
 	sigset_t set;
-	unsigned long prevsp;
 
-        sc = (struct sigcontext_struct *)(regs->gpr[1] + __SIGNAL_FRAMESIZE);
-	if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
+        frame = (struct sigframe *)(regs->gpr[1] + __SIGNAL_FRAMESIZE);
+
+	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+		goto badframe;
+
+	if (restore_sigcontext(regs, &set, &frame->sc))
 		goto badframe;
 
-	set.sig[0] = sigctx.oldmask;
-#if _NSIG_WORDS > 1
-	set.sig[1] = sigctx._unused[3];
-#endif
 	sigdelsetmask(&set, ~_BLOCKABLE);
 	spin_lock_irq(&current->sigmask_lock);
 	current->blocked = set;
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
 
-	sc++;			/* Look at next sigcontext */
-	if (sc == (struct sigcontext_struct *)(sigctx.regs)) {
-		/* Last stacked signal - restore registers */
-		sr = (struct sigregs *) sigctx.regs;
-		if (regs->msr & MSR_FP )
-			giveup_fpu(current);
-		if (copy_from_user(saved_regs, &sr->gp_regs,
-				   sizeof(sr->gp_regs)))
-			goto badframe;
-		saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE)
-			| (saved_regs[PT_MSR] & MSR_USERCHANGE);
-		saved_regs[PT_SOFTE] = regs->softe;
-		memcpy(regs, saved_regs, GP_REGS_SIZE);
-
-		if (copy_from_user(current->thread.fpr, &sr->fp_regs,
-				   sizeof(sr->fp_regs)))
-			goto badframe;
-
-		ret = regs->result;
-
-	} else {
-		/* More signals to go */
-		regs->gpr[1] = (unsigned long)sc - __SIGNAL_FRAMESIZE;
-		if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
-			goto badframe;
-		sr = (struct sigregs *) sigctx.regs;
-		regs->gpr[3] = ret = sigctx.signal;
-		regs->gpr[4] = (unsigned long) sc;
-		regs->link = (unsigned long) &sr->tramp;
-		regs->nip = sigctx.handler;
-
-		if (get_user(prevsp, &sr->gp_regs[PT_R1])
-		    || put_user(prevsp, (unsigned long *) regs->gpr[1]))
-			goto badframe;
-	}
-	return ret;
+	return regs->result;
 
 badframe:
 	do_exit(SIGSEGV);
 }	
 
-/*
- * Set up a signal frame.
- */
+
 static void
-setup_frame(struct pt_regs *regs, struct sigregs *frame,
-            unsigned long newsp)
+setup_frame(int signr, struct k_sigaction *ka, sigset_t *set,
+	    struct pt_regs *regs)
 {
-
 	/* Handler is *really* a pointer to the function descriptor for
 	 * the signal routine.  The first entry in the function
 	 * descriptor is the entry address of signal and the second
 	 * entry is the TOC value we need to use.
 	 */
-	struct funct_descr_entry {
-		unsigned long entry;
-		unsigned long toc;
-	};
-  
-	struct funct_descr_entry * funct_desc_ptr;
-	unsigned long temp_ptr;
+	func_descr_t *funct_desc_ptr;
+	struct sigframe *frame;
+	unsigned long newsp;
+	int i, err = 0;
+
+	frame = get_sigframe(ka, regs, sizeof(*frame));
 
-	struct sigcontext_struct *sc = (struct sigcontext_struct *) newsp;
-  
 	if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
 		goto badframe;
-	if (regs->msr & MSR_FP)
-		giveup_fpu(current);
-	if (__copy_to_user(&frame->gp_regs, regs, GP_REGS_SIZE)
-	    || __copy_to_user(&frame->fp_regs, current->thread.fpr,
-			      ELF_NFPREG * sizeof(double))
-	    || __put_user(0x38000000UL + __NR_sigreturn, &frame->tramp[0])    /* li r0, __NR_sigreturn */
-	    || __put_user(0x44000002UL, &frame->tramp[1]))   /* sc */
-		goto badframe;
-	flush_icache_range((unsigned long) &frame->tramp[0],
-			   (unsigned long) &frame->tramp[2]);
 
-	newsp -= __SIGNAL_FRAMESIZE;
-	if ( get_user(temp_ptr, &sc->handler))
-		goto badframe;
-  
-	funct_desc_ptr = ( struct funct_descr_entry *) temp_ptr;
+	err |= setup_sigcontext(&frame->sc, regs, signr, set,
+				(unsigned long)ka->sa.sa_handler);
 
-	if (put_user(regs->gpr[1], (unsigned long *)newsp)
-	    || get_user(regs->nip, & funct_desc_ptr ->entry)
-	    || get_user(regs->gpr[2],& funct_desc_ptr->toc)
-	    || get_user(regs->gpr[3], &sc->signal))
+	/* Set up to return from userspace. */
+	/* li r0, __NR_rt_sigreturn */
+	err |= __put_user(0x38000000UL + __NR_sigreturn, &frame->tramp[0]);
+	/* sc */
+	err |= __put_user(0x44000002UL, &frame->tramp[1]);
+	/* Minimal traceback info */
+	for (i=TRAMP_TRACEBACK; i < TRAMP_SIZE ;i++)
+		err |= __put_user(0, &frame->tramp[i]);
+	if (err)
 		goto badframe;
-	regs->gpr[1] = newsp;
-	regs->gpr[4] = (unsigned long) sc;
-	regs->link = (unsigned long) frame->tramp;
 
+	flush_icache_range((unsigned long) &frame->tramp[0],
+			   (unsigned long) &frame->tramp[TRAMP_SIZE]);
+
+	funct_desc_ptr = (func_descr_t *) ka->sa.sa_handler;
+
+	/* Allocate a dummy caller frame for the signal handler. */
+	newsp = (unsigned long)frame - __SIGNAL_FRAMESIZE;
+	err |= put_user(0, (unsigned long *)newsp);
 
-	PPCDBG(PPCDBG_SIGNAL, "setup_frame - returning - regs->gpr[1]=%lx, regs->gpr[4]=%lx, regs->link=%lx \n",
-	       regs->gpr[1], regs->gpr[4], regs->link);
+	/* Set up "regs" so we "return" to the signal handler. */
+	err |= get_user(regs->nip, &funct_desc_ptr->entry);
+	regs->link = (unsigned long) &frame->tramp[0];
+	regs->gpr[1] = newsp;
+	err |= get_user(regs->gpr[2], &funct_desc_ptr->toc);
+	regs->gpr[3] = signr;
+	regs->gpr[4] = (unsigned long) &frame->sc;
+	if (err)
+		goto badframe;
 
 	return;
 
- badframe:
-	PPCDBG(PPCDBG_SIGNAL, "setup_frame - badframe in setup_frame, regs=%p frame=%p newsp=%lx\n", regs, frame, newsp);  PPCDBG_ENTER_DEBUGGER();
+badframe:
 #if DEBUG_SIG
 	printk("badframe in setup_frame, regs=%p frame=%p newsp=%lx\n",
 	       regs, frame, newsp);
@@ -540,61 +514,20 @@
  */
 static void
 handle_signal(unsigned long sig, struct k_sigaction *ka,
-	      siginfo_t *info, sigset_t *oldset, struct pt_regs * regs,
-	      unsigned long *newspp, unsigned long frame)
+	      siginfo_t *info, sigset_t *oldset, struct pt_regs *regs)
 {
-	struct sigcontext_struct *sc;
-        struct rt_sigframe *rt_sf;
-
-	if (regs->trap == 0x0C00 /* System Call! */
+	/* Are we from a system call? */
+	if (regs->trap == 0x0C00
 	    && ((int)regs->result == -ERESTARTNOHAND ||
 		((int)regs->result == -ERESTARTSYS &&
 		 !(ka->sa.sa_flags & SA_RESTART))))
 		regs->result = -EINTR;
-        /* Set up Signal Frame */
-     
-	if (ka->sa.sa_flags & SA_SIGINFO) {
-		/* Put a Real Time Context onto stack */
-		*newspp -= sizeof(*rt_sf);
-		rt_sf = (struct rt_sigframe *) *newspp;
-		if (verify_area(VERIFY_WRITE, rt_sf, sizeof(*rt_sf)))
-			goto badframe;
-                
-
-		if (__put_user((unsigned long) ka->sa.sa_handler, &rt_sf->uc.uc_mcontext.handler)
-		    || __put_user(&rt_sf->info, &rt_sf->pinfo)
-		    || __put_user(&rt_sf->uc, &rt_sf->puc)
-		    /* Put the siginfo */
-		    || __copy_to_user(&rt_sf->info, info, sizeof(*info))
-		    /* Create the ucontext */
-		    || __put_user(0, &rt_sf->uc.uc_flags)
-		    || __put_user(0, &rt_sf->uc.uc_link)
-		    || __put_user(current->sas_ss_sp, &rt_sf->uc.uc_stack.ss_sp)
-		    || __put_user(sas_ss_flags(regs->gpr[1]), 
-				  &rt_sf->uc.uc_stack.ss_flags)
-		    || __put_user(current->sas_ss_size, &rt_sf->uc.uc_stack.ss_size)
-		    || __copy_to_user(&rt_sf->uc.uc_sigmask, oldset, sizeof(*oldset))
-		    /* mcontext.regs points to preamble register frame */
-		    || __put_user((struct pt_regs *)frame, &rt_sf->uc.uc_mcontext.regs)
-		    || __put_user(sig, &rt_sf->uc.uc_mcontext.signal))
-			goto badframe;
-               
-	} else {
-	        /* Put another sigcontext on the stack */
-                *newspp -= sizeof(*sc);
-        	sc = (struct sigcontext_struct *) *newspp;
-        	if (verify_area(VERIFY_WRITE, sc, sizeof(*sc)))
-	        	goto badframe;
-
-        	if (__put_user((unsigned long) ka->sa.sa_handler, &sc->handler)
-	           || __put_user(oldset->sig[0], &sc->oldmask)
-#if _NSIG_WORDS > 1
-	           || __put_user(oldset->sig[1], &sc->_unused[3])
-#endif
-	           || __put_user((struct pt_regs *)frame, &sc->regs)
-	           || __put_user(sig, &sc->signal))
-	        	goto badframe;
-	}
+
+	/* Set up Signal Frame */
+	if (ka->sa.sa_flags & SA_SIGINFO)
+		setup_rt_frame(sig, ka, info, oldset, regs);
+	else
+		setup_frame(sig, ka, oldset, regs);
 
 	if (ka->sa.sa_flags & SA_ONESHOT)
 		ka->sa.sa_handler = SIG_DFL;
@@ -606,49 +539,18 @@
 		recalc_sigpending(current);
 		spin_unlock_irq(&current->sigmask_lock);
 	}
-	return;
-
-badframe:
-#if DEBUG_SIG
-	printk("badframe in handle_signal, regs=%p frame=%lx newsp=%lx\n",
-	       regs, frame, *newspp);
-	printk("sc=%p sig=%d ka=%p info=%p oldset=%p\n", sc, sig, ka, info, oldset);
-#endif
-	do_exit(SIGSEGV);
 }
 
-/*
- * Note that 'init' is a special process: it doesn't get signals it doesn't
- * want to handle. Thus you cannot kill init even with a SIGKILL even by
- * mistake.
- */
-extern int do_signal32(sigset_t *oldset, struct pt_regs *regs);
-int do_signal(sigset_t *oldset, struct pt_regs *regs)
+static int
+get_signal_to_deliver(siginfo_t *info, struct pt_regs *regs)
 {
-	siginfo_t info;
-	struct k_sigaction *ka;
-	unsigned long frame, newsp;
-
-	/*
-	 * If the current thread is 32 bit - invoke the
-	 * 32 bit signal handling code
-	 */
-	if (current->thread.flags & PPC_FLAG_32BIT)
-		return do_signal32(oldset, regs);
-
-        if (!oldset)
-		oldset = &current->blocked;
-
-	newsp = frame = 0;
-
 	for (;;) {
 		unsigned long signr;
+		struct k_sigaction *ka;
 
-                PPCDBG(PPCDBG_SIGNAL, "do_signal - (pre) dequeueing signal - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
 		spin_lock_irq(&current->sigmask_lock);
-		signr = dequeue_signal(&current->blocked, &info);
+		signr = dequeue_signal(&current->blocked, info);
 		spin_unlock_irq(&current->sigmask_lock);
-                PPCDBG(PPCDBG_SIGNAL, "do_signal - (aft) dequeueing signal - signal=%lx - pid=%ld current=%lx comm=%s \n", signr, current->pid, current, current->comm);
 
 		if (!signr)
 			break;
@@ -661,7 +563,8 @@
 			schedule();
 
 			/* We're back.  Did the debugger cancel the sig?  */
-			if (!(signr = current->exit_code))
+			signr = current->exit_code;
+			if (signr == 0)
 				continue;
 			current->exit_code = 0;
 
@@ -670,28 +573,24 @@
 				continue;
 
 			/* Update the siginfo structure.  Is this good?  */
-			if (signr != info.si_signo) {
-				info.si_signo = signr;
-				info.si_errno = 0;
-				info.si_code = SI_USER;
-				info.si_pid = current->p_pptr->pid;
-				info.si_uid = current->p_pptr->uid;
+			if (signr != info->si_signo) {
+				info->si_signo = signr;
+				info->si_errno = 0;
+				info->si_code = SI_USER;
+				info->si_pid = current->p_pptr->pid;
+				info->si_uid = current->p_pptr->uid;
 			}
 
 			/* If the (new) signal is now blocked, requeue it.  */
 			if (sigismember(&current->blocked, signr)) {
-				send_sig_info(signr, &info, current);
+				send_sig_info(signr, info, current);
 				continue;
 			}
 		}
 
 		ka = &current->sig->action[signr-1];
 
-  
-                PPCDBG(PPCDBG_SIGNAL, "do_signal - ka=%p, action handler=%lx \n", ka, ka->sa.sa_handler);
-
 		if (ka->sa.sa_handler == SIG_IGN) {
-                        PPCDBG(PPCDBG_SIGNAL, "do_signal - into SIG_IGN logic \n");
 			if (signr != SIGCHLD)
 				continue;
 			/* Check for SIGCHLD: it's special.  */
@@ -702,7 +601,6 @@
 
 		if (ka->sa.sa_handler == SIG_DFL) {
 			int exit_code = signr;
-                        PPCDBG(PPCDBG_SIGNAL, "do_signal - into SIG_DFL logic \n");
 
 			/* Init gets no signals it doesn't want.  */
 			if (current->pid == 1)
@@ -736,48 +634,58 @@
 				/* FALLTHRU */
 
 			default:
-				sig_exit(signr, exit_code, &info);
+				sig_exit(signr, exit_code, info);
 				/* NOTREACHED */
 			}
 		}
+		return signr;
+	}
+	return 0;
+}
 
-		if ( (ka->sa.sa_flags & SA_ONSTACK)
-		     && (! on_sig_stack(regs->gpr[1])))
-			newsp = (current->sas_ss_sp + current->sas_ss_size);
-		else
-			newsp = regs->gpr[1];
-		newsp = frame = newsp - sizeof(struct sigregs);
+/*
+ * Note that 'init' is a special process: it doesn't get signals it doesn't
+ * want to handle. Thus you cannot kill init even with a SIGKILL even by
+ * mistake.
+ */
+extern int do_signal32(sigset_t *oldset, struct pt_regs *regs);
+
+int
+do_signal(sigset_t *oldset, struct pt_regs *regs)
+{
+	siginfo_t info;
+	int signr;
+
+	/*
+	 * If the current thread is 32 bit - invoke the
+	 * 32 bit signal handling code
+	 */
+	if (current->thread.flags & PPC_FLAG_32BIT)
+		return do_signal32(oldset, regs);
+
+        if (!oldset)
+		oldset = &current->blocked;
+
+	signr = get_signal_to_deliver(&info, regs);
+	if (signr > 0) {
+		struct k_sigaction *ka = &current->sig->action[signr-1];
 
 		/* Whee!  Actually deliver the signal.  */
-  
-                PPCDBG(PPCDBG_SIGNAL, "do_signal - GOING TO RUN SIGNAL HANDLER - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-		handle_signal(signr, ka, &info, oldset, regs, &newsp, frame);
-                PPCDBG(PPCDBG_SIGNAL, "do_signal - after running signal handler - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-                break;
+		handle_signal(signr, ka, &info, oldset, regs);
+		return 1;
 	}
 
 	if (regs->trap == 0x0C00 /* System Call! */ &&
 	    ((int)regs->result == -ERESTARTNOHAND ||
 	     (int)regs->result == -ERESTARTSYS ||
 	     (int)regs->result == -ERESTARTNOINTR)) {
-                PPCDBG(PPCDBG_SIGNAL, "do_signal - going to back up & retry system call \n");
 		regs->gpr[3] = regs->orig_gpr3;
 		regs->nip -= 4;		/* Back up & retry system call */
 		regs->result = 0;
 	}
 
-	if (newsp == frame)
-          {
-             PPCDBG(PPCDBG_SIGNAL, "do_signal - returning w/ no signal delivered \n");
-             return 0;		/* no signals delivered */
-           }
-  
-     
-
-        if (ka->sa.sa_flags & SA_SIGINFO)
-             setup_rt_frame(regs, (struct sigregs *) frame, newsp);
-        else        
-	    setup_frame(regs, (struct sigregs *) frame, newsp);
-        PPCDBG(PPCDBG_SIGNAL, "do_signal - returning a signal was delivered \n");
-	return 1;
+	return 0;
 }
+
+
+
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/signal32.c linux-2.4.21-pre4/arch/ppc64/kernel/signal32.c
--- linux-2.4.21-pre3/arch/ppc64/kernel/signal32.c	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/signal32.c	Tue Jan 28 19:44:29 2003
@@ -71,34 +71,41 @@
 };
 
 struct sigregs32 {
-    /***********************************************************************/
-    /* the gp_regs array is 32 bit representation of the pt_regs structure */
-    /*  that was stored on the kernle stack during the system call that    */
-    /*  was interrupted for the signal.                                    */
-    /*                                                                     */
-    /* Note that the entire pt_regs regs structure will fit in the gp_regs */
-    /*   structure because the ELF_NREG value is 48 for PPC and the pt_regs*/
-    /*   structure contains 44 registers                                   */
-    /*                                                                     */ 
-    /***********************************************************************/ 
+	/*
+	 * the gp_regs array is 32 bit representation of the pt_regs
+	 * structure that was stored on the kernle stack during the
+	 * system call that was interrupted for the signal.
+	 *
+	 * Note that the entire pt_regs regs structure will fit in
+	 * the gp_regs structure because the ELF_NREG value is 48 for
+	 * PPC and the pt_regs structure contains 44 registers
+	 */
 	elf_gregset_t32	gp_regs;
 	double		fp_regs[ELF_NFPREG];
 	unsigned int	tramp[2];
-	/* Programs using the rs6000/xcoff abi can save up to 19 gp regs
-	   and 18 fp regs below sp before decrementing it. */
+	/*
+	 * Programs using the rs6000/xcoff abi can save up to 19 gp
+	 * regs and 18 fp regs below sp before decrementing it.
+	 */
 	int		abigap[56];
 };
 
 
 struct rt_sigframe_32 {
-	/* Unused space at start of frame to allow for storing of stack pointers */
+	/*
+	 * Unused space at start of frame to allow for storing of
+	 * stack pointers
+	 */
 	unsigned long _unused;
-	/* This is a 32 bit pointer in user address space 
+	/*
+	 * This is a 32 bit pointer in user address space 
 	 *     it is a pointer to the siginfo stucture in the rt stack frame 
 	 */
 	u32 pinfo;
-	/* This is a 32 bit pointer in user address space */
-	/*     it is a pointer to the user context in the rt stack frame  */
+	/*
+	 * This is a 32 bit pointer in user address space
+	 * it is a pointer to the user context in the rt stack frame
+	 */
 	u32 puc;
 	struct siginfo32  info;
 	struct ucontext32 uc;
@@ -138,12 +145,9 @@
 	PPCDBG(PPCDBG_SYS32, "sys32_sigaction - entered - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
 
 	if (sig < 0)
-	{
 		sig = -sig;
-	}
 
-	if (act)
-	{
+	if (act) {
 		old_sigset_t32 mask;
 
 		ret = get_user((long)new_ka.sa.sa_handler, &act->sa_handler);
@@ -214,15 +218,18 @@
 	
 	PPCDBG(PPCDBG_SYS32, "sys32_sigprocmask - entered - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
 	
-	if (set && get_user (s, set)) return -EFAULT;
+	if (set && get_user(s, set))
+		return -EFAULT;
 	set_fs (KERNEL_DS);
 	ret = sys_sigprocmask((int)how, set ? &s : NULL, oset ? &s : NULL);
 	set_fs (old_fs);
-	if (ret) return ret;
-	if (oset && put_user (s, oset)) return -EFAULT;
 	
 	PPCDBG(PPCDBG_SYS32, "sys32_sigprocmask - exited - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
 
+	if (ret)
+		return ret;
+	if (oset && put_user (s, oset))
+		return -EFAULT;
 	return 0;
 }
 
@@ -247,21 +254,24 @@
 		     unsigned long r6, unsigned long r7, unsigned long r8,
 		     struct pt_regs *regs)
 {
-	struct sigcontext32_struct *sc, sigctx;
+	struct sigcontext32 *sc, sigctx;
 	struct sigregs32 *sr;
 	int ret;
 	elf_gregset_t32 saved_regs;  /* an array of ELF_NGREG unsigned ints (32 bits) */
 	sigset_t set;
 	unsigned int prevsp;
+	int i;
 
 	PPCDBG(PPCDBG_SIGNAL, "sys32_sigreturn - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
 
-	sc = (struct sigcontext32_struct *)(regs->gpr[1] + __SIGNAL_FRAMESIZE32);
+	sc = (struct sigcontext32 *)(regs->gpr[1] + __SIGNAL_FRAMESIZE32);
 	if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
 		goto badframe;
 
-	/* Note that PPC32 puts the upper 32 bits of the sigmask in the  */
-	/*   unused part of the signal stackframe                        */
+	/*
+	 * Note that PPC32 puts the upper 32 bits of the sigmask in the
+	 * unused part of the signal stackframe
+	 */
 	set.sig[0] = sigctx.oldmask + ((long)(sigctx._unused[3])<< 32);
 	sigdelsetmask(&set, ~_BLOCKABLE);
 	spin_lock_irq(&current->sigmask_lock);
@@ -272,77 +282,50 @@
 	sc++;			/* Look at next sigcontext */
 	/* If the next sigcontext is actually the sigregs (frame)  */
 	/*   - then no more sigcontexts on the user stack          */  
-	if (sc == (struct sigcontext32_struct*)(u64)sigctx.regs)
+	if (sc == (struct sigcontext32*)(u64)sigctx.regs)
 	{
 		/* Last stacked signal - restore registers */
 		sr = (struct sigregs32*)(u64)sigctx.regs;
 		if (regs->msr & MSR_FP )
 			giveup_fpu(current);
-		/* copy the 32 bit register values off the user stack */
-		/*   into the 32 bit register area                    */
+		/* 
+		 * Copy the 32 bit register values off the user stack
+		 * into the 32 bit register area
+		 */
 		if (copy_from_user(saved_regs, &sr->gp_regs,sizeof(sr->gp_regs)))
 			goto badframe;
-		/**********************************************************************/
-		/* The saved reg structure in the frame is an elf_grepset_t32, it is  */
-		/*   a 32 bit register save of the registers in the pt_regs structure */
-		/*   that was stored on the kernel stack during the system call       */
-		/*   when the system call was interrupted for the signal. Only 32 bits*/
-		/*   are saved because the sigcontext contains a pointer to the regs  */
-		/*   and the sig context address is passed as a pointer to the signal */
-		/*   handler.                                                         */
-		/*                                                                    */
-		/* The entries in the elf_grepset have the same index as the elements */
-		/*   in the pt_regs structure.                                        */
-		/*                                                                    */
-		/**********************************************************************/
-
+		/*
+		 * The saved reg structure in the frame is an elf_grepset_t32,
+		 * it is a 32 bit register save of the registers in the
+		 * pt_regs structure that was stored on the kernel stack
+		 * during the system call when the system call was interrupted
+		 * for the signal. Only 32 bits are saved because the
+		 * sigcontext contains a pointer to the regs and the sig
+		 * context address is passed as a pointer to the signal
+		 * handler.  
+		 *
+		 * The entries in the elf_grepset have the same index as the
+		 * elements in the pt_regs structure.
+		 */
 		saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE)
 			| (saved_regs[PT_MSR] & MSR_USERCHANGE);
-		regs->gpr[0] = (u64)(saved_regs[0]) & 0xFFFFFFFF;
-		regs->gpr[1] = (u64)(saved_regs[1]) & 0xFFFFFFFF;
-		/**********************************************************************/
-		/* Register 2 is the kernel toc - should be reset on any calls into   */
-		/*  the kernel                                                        */
-		/**********************************************************************/
-		regs->gpr[2] = (u64)(saved_regs[2]) & 0xFFFFFFFF;
-
-		regs->gpr[3] = (u64)(saved_regs[3]) & 0xFFFFFFFF;
-		regs->gpr[4] = (u64)(saved_regs[4]) & 0xFFFFFFFF;
-		regs->gpr[5] = (u64)(saved_regs[5]) & 0xFFFFFFFF;
-		regs->gpr[6] = (u64)(saved_regs[6]) & 0xFFFFFFFF;
-		regs->gpr[7] = (u64)(saved_regs[7]) & 0xFFFFFFFF;
-		regs->gpr[8] = (u64)(saved_regs[8]) & 0xFFFFFFFF;
-		regs->gpr[9] = (u64)(saved_regs[9]) & 0xFFFFFFFF;
-		regs->gpr[10] = (u64)(saved_regs[10]) & 0xFFFFFFFF;
-		regs->gpr[11] = (u64)(saved_regs[11]) & 0xFFFFFFFF;
-		regs->gpr[12] = (u64)(saved_regs[12]) & 0xFFFFFFFF;
-		regs->gpr[13] = (u64)(saved_regs[13]) & 0xFFFFFFFF;
-		regs->gpr[14] = (u64)(saved_regs[14]) & 0xFFFFFFFF;
-		regs->gpr[15] = (u64)(saved_regs[15]) & 0xFFFFFFFF;
-		regs->gpr[16] = (u64)(saved_regs[16]) & 0xFFFFFFFF;
-		regs->gpr[17] = (u64)(saved_regs[17]) & 0xFFFFFFFF;
-		regs->gpr[18] = (u64)(saved_regs[18]) & 0xFFFFFFFF;
-		regs->gpr[19] = (u64)(saved_regs[19]) & 0xFFFFFFFF;
-		regs->gpr[20] = (u64)(saved_regs[20]) & 0xFFFFFFFF;
-		regs->gpr[21] = (u64)(saved_regs[21]) & 0xFFFFFFFF;
-		regs->gpr[22] = (u64)(saved_regs[22]) & 0xFFFFFFFF;
-		regs->gpr[23] = (u64)(saved_regs[23]) & 0xFFFFFFFF;
-		regs->gpr[24] = (u64)(saved_regs[24]) & 0xFFFFFFFF;
-		regs->gpr[25] = (u64)(saved_regs[25]) & 0xFFFFFFFF;
-		regs->gpr[26] = (u64)(saved_regs[26]) & 0xFFFFFFFF;
-		regs->gpr[27] = (u64)(saved_regs[27]) & 0xFFFFFFFF;
-		regs->gpr[28] = (u64)(saved_regs[28]) & 0xFFFFFFFF;
-		regs->gpr[29] = (u64)(saved_regs[29]) & 0xFFFFFFFF;
-		regs->gpr[30] = (u64)(saved_regs[30]) & 0xFFFFFFFF;
-		regs->gpr[31] = (u64)(saved_regs[31]) & 0xFFFFFFFF;
-		/****************************************************/
-		/*  restore the non gpr registers                   */
-		/****************************************************/
+		/*
+		 * Register 2 is the kernel toc - should be reset on
+		 * any calls into the kernel 
+		 */
+		for (i = 0; i < 32; i++)
+			regs->gpr[i] = (u64)(saved_regs[i]) & 0xFFFFFFFF;
+
+		/*
+		 *  restore the non gpr registers 
+		 */
 		regs->msr = (u64)(saved_regs[PT_MSR]) & 0xFFFFFFFF;
-		/* Insure that the interrupt mode is 64 bit, during 32 bit execution.
-		 * (This is necessary because we only saved lower 32 bits of msr.)
+		/*
+		 * Insure that the interrupt mode is 64 bit, during 32 bit
+		 * execution. (This is necessary because we only saved
+		 * lower 32 bits of msr.)
 		 */
-		regs->msr = regs->msr | MSR_ISF;  /* When this thread is interrupted it should run in 64 bit mode. */
+		regs->msr = regs->msr | MSR_ISF;
 
 		regs->nip = (u64)(saved_regs[PT_NIP]) & 0xFFFFFFFF;
 		regs->orig_gpr3 = (u64)(saved_regs[PT_ORIG_R3]) & 0xFFFFFFFF; 
@@ -378,6 +361,7 @@
 		if (get_user(prevsp, &sr->gp_regs[PT_R1])
 		    || put_user(prevsp, (unsigned int*) regs->gpr[1]))
 			goto badframe;
+		current->thread.fpscr = 0;
 	}
   
 	PPCDBG(PPCDBG_SIGNAL, "sys32_sigreturn - normal exit returning %ld - pid=%ld current=%lx comm=%s \n", ret, current->pid, current, current->comm);
@@ -395,67 +379,37 @@
 setup_frame32(struct pt_regs *regs, struct sigregs32 *frame,
             unsigned int newsp)
 {
-	struct sigcontext32_struct *sc = (struct sigcontext32_struct *)(u64)newsp;
+	struct sigcontext32 *sc = (struct sigcontext32 *)(u64)newsp;
+	int i;
 
 	if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
 		goto badframe;
 	if (regs->msr & MSR_FP)
 		giveup_fpu(current);
 
-	/***************************************************************/
-	/*                                                             */ 
-	/* Copy the register contents for the pt_regs structure on the */
-	/*   kernel stack to the elf_gregset_t32 structure on the user */
-	/*   stack. This is a copy of 64 bit register values to 32 bit */
-	/*   register values. The high order 32 bits of the 64 bit     */
-	/*   registers are not needed since a 32 bit application is    */
-	/*   running and the saved registers are the contents of the   */
-	/*   user registers at the time of a system call.              */
-	/*                                                             */
-	/* The values saved on the user stack will be restored into    */
-	/*  the registers during the signal return processing          */
-	/*                                                             */
-	/* Note the +1 is needed in order to get the lower 32 bits     */
-	/*  of 64 bit register                                         */
-	/***************************************************************/
-	if (__copy_to_user(&frame->gp_regs[0], (u32*)(&regs->gpr[0])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[1], (u32*)(&regs->gpr[1])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[2], (u32*)(&regs->gpr[2])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[3], (u32*)(&regs->gpr[3])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[4], (u32*)(&regs->gpr[4])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[5], (u32*)(&regs->gpr[5])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[6], (u32*)(&regs->gpr[6])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[7], (u32*)(&regs->gpr[7])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[8], (u32*)(&regs->gpr[8])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[9], (u32*)(&regs->gpr[9])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[10], (u32*)(&regs->gpr[10])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[11], (u32*)(&regs->gpr[11])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[12], (u32*)(&regs->gpr[12])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[13], (u32*)(&regs->gpr[13])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[14], (u32*)(&regs->gpr[14])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[15], (u32*)(&regs->gpr[15])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[16], (u32*)(&regs->gpr[16])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[17], (u32*)(&regs->gpr[17])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[18], (u32*)(&regs->gpr[18])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[19], (u32*)(&regs->gpr[19])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[20], (u32*)(&regs->gpr[20])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[21], (u32*)(&regs->gpr[21])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[22], (u32*)(&regs->gpr[22])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[23], (u32*)(&regs->gpr[23])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[24], (u32*)(&regs->gpr[24])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[25], (u32*)(&regs->gpr[25])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[26], (u32*)(&regs->gpr[26])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[27], (u32*)(&regs->gpr[27])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[28], (u32*)(&regs->gpr[28])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[29], (u32*)(&regs->gpr[29])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[30], (u32*)(&regs->gpr[30])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[31], (u32*)(&regs->gpr[31])+1, sizeof(u32))) 
-		goto badframe;
-
-  /*****************************************************************************/
-  /* Copy the non gpr registers to the user stack                              */
-  /*****************************************************************************/
+	/*
+	 * Copy the register contents for the pt_regs structure on the
+	 *   kernel stack to the elf_gregset_t32 structure on the user
+	 *   stack. This is a copy of 64 bit register values to 32 bit
+	 *   register values. The high order 32 bits of the 64 bit
+	 *   registers are not needed since a 32 bit application is
+	 *   running and the saved registers are the contents of the
+	 *   user registers at the time of a system call.
+	 * 
+	 * The values saved on the user stack will be restored into
+	 *  the registers during the signal return processing
+	 *
+	 * Note the +1 is needed in order to get the lower 32 bits
+	 * of 64 bit register
+	 */
+	for (i = 0; i < 32; i++) {
+		if (__copy_to_user(&frame->gp_regs[i], (u32*)(&regs->gpr[i])+1, sizeof(u32)))
+			goto badframe;
+	}
 
+  	/*
+  	 * Copy the non gpr registers to the user stack
+  	 */
 	if (__copy_to_user(&frame->gp_regs[PT_NIP], (u32*)(&regs->gpr[PT_NIP])+1, sizeof(u32))
 	    || __copy_to_user(&frame->gp_regs[PT_MSR], (u32*)(&regs->gpr[PT_MSR])+1, sizeof(u32))
 	    || __copy_to_user(&frame->gp_regs[PT_ORIG_R3], (u32*)(&regs->gpr[PT_ORIG_R3])+1,
@@ -471,21 +425,23 @@
 			      sizeof(u32)))
 		goto badframe;
 
-
-	/*****************************************************************************/
-	/* Now copy the floating point registers onto the user stack                 */
-	/*                                                                           */
-	/* Also set up so on the completion of the signal handler, the sys_sigreturn */
-	/*   will get control to reset the stack                                     */
-	/*****************************************************************************/
+	/*
+	 * Now copy the floating point registers onto the user stack 
+	 *
+	 * Also set up so on the completion of the signal handler, the
+	 * sys_sigreturn will get control to reset the stack
+	 */
 	if (__copy_to_user(&frame->fp_regs, current->thread.fpr,
 			   ELF_NFPREG * sizeof(double))
-	    || __put_user(0x38000000U + __NR_sigreturn, &frame->tramp[0])    /* li r0, __NR_sigreturn */
-	    || __put_user(0x44000002U, &frame->tramp[1]))   /* sc */
+	    /* li r0, __NR_sigreturn */
+	    || __put_user(0x38000000U + __NR_sigreturn, &frame->tramp[0])
+	    /* sc */
+	    || __put_user(0x44000002U, &frame->tramp[1]))
 		goto badframe;
 
 	flush_icache_range((unsigned long) &frame->tramp[0],
 			   (unsigned long) &frame->tramp[2]);
+	current->thread.fpscr = 0;      /* turn off all fp exceptions */
 
 	newsp -= __SIGNAL_FRAMESIZE32;
 	if (put_user(regs->gpr[1], (u32*)(u64)newsp)
@@ -494,12 +450,12 @@
 		goto badframe;
 
 	regs->gpr[1] = newsp & 0xFFFFFFFF;
-	/**************************************************************/
-	/* first parameter to the signal handler is the signal number */
-	/*  - the value is in gpr3                                    */  
-	/* second parameter to the signal handler is the sigcontext   */
-	/*   - set the value into gpr4                                */ 
-	/**************************************************************/
+	/*
+	 * first parameter to the signal handler is the signal number
+	 *  - the value is in gpr3
+	 * second parameter to the signal handler is the sigcontext
+	 *   - set the value into gpr4
+	 */
 	regs->gpr[4] = (unsigned long) sc;
 	regs->link = (unsigned long) frame->tramp;
 	return;
@@ -514,40 +470,40 @@
 }
 
 
-/****************************************************************************/
-/*  Start of RT signal support                                              */
-/*                                                                          */
-/*     sigset_t is 64 bits for rt signals                                   */
-/*                                                                          */
-/*  System Calls                                                            */
-/*       sigaction                sys32_rt_sigaction                        */
-/*       sigpending               sys32_rt_sigpending                       */
-/*       sigprocmask              sys32_rt_sigprocmask                      */
-/*       sigreturn                sys32_rt_sigreturn                        */
-/*       sigtimedwait             sys32_rt_sigtimedwait                     */
-/*       sigqueueinfo             sys32_rt_sigqueueinfo                     */
-/*       sigsuspend               sys32_rt_sigsuspend                       */ 
-/*                                                                          */
-/*  Other routines                                                          */
-/*        setup_rt_frame32                                                  */
-/*        siginfo64to32                                                     */
-/*        siginfo32to64                                                     */
-/*                                                                          */
-/*                                                                          */
-/****************************************************************************/
+/*
+ *  Start of RT signal support
+ *
+ *     sigset_t is 64 bits for rt signals
+ *
+ *  System Calls
+ *       sigaction                sys32_rt_sigaction
+ *       sigpending               sys32_rt_sigpending
+ *       sigprocmask              sys32_rt_sigprocmask
+ *       sigreturn                sys32_rt_sigreturn
+ *       sigtimedwait             sys32_rt_sigtimedwait
+ *       sigqueueinfo             sys32_rt_sigqueueinfo
+ *       sigsuspend               sys32_rt_sigsuspend
+ *
+ *  Other routines
+ *        setup_rt_frame32
+ *        copy_siginfo_to_user32
+ *        siginfo32to64
+ */
 
 
-// This code executes after the rt signal handler in 32 bit mode has completed and 
-//  returned  
+/*
+ * This code executes after the rt signal handler in 32 bit mode has
+ * completed and returned  
+ */
 long sys32_rt_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5,
 			unsigned long r6, unsigned long r7, unsigned long r8,
 			struct pt_regs * regs)
 {
 	struct rt_sigframe_32 *rt_stack_frame;
-	struct sigcontext32_struct sigctx;
+	struct sigcontext32 sigctx;
 	struct sigregs32 *signalregs;
  
-	int ret;
+	int i, ret;
 	elf_gregset_t32 saved_regs;   /* an array of 32 bit register values */
 	sigset_t signal_set; 
 	stack_t stack;
@@ -560,12 +516,11 @@
 	if (copy_from_user(&sigctx, &rt_stack_frame->uc.uc_mcontext,sizeof(sigctx))
 	    || copy_from_user(&signal_set, &rt_stack_frame->uc.uc_sigmask,sizeof(signal_set))
 	    || copy_from_user(&stack,&rt_stack_frame->uc.uc_stack,sizeof(stack)))
-	{
 		/* unable to copy from user storage */
 		goto badframe;
-	}
 
-	/* Unblock the signal that was processed 
+	/*
+	 * Unblock the signal that was processed 
 	 *   After a signal handler runs - 
 	 *     if the signal is blockable - the signal will be unblocked  
 	 *       ( sigkill and sigstop are not blockable)
@@ -582,76 +537,39 @@
 	 */
 	rt_stack_frame ++;
 
-	if (rt_stack_frame == (struct rt_sigframe_32 *)(u64)(sigctx.regs))
-	{
+	if (rt_stack_frame == (struct rt_sigframe_32 *)(u64)(sigctx.regs)) {
 		signalregs = (struct sigregs32 *) (u64)sigctx.regs;
 		/* If currently owning the floating point - give them up */
 		if (regs->msr & MSR_FP)
-		{
 			giveup_fpu(current);
-		}
+
 		if (copy_from_user(saved_regs,&signalregs->gp_regs,sizeof(signalregs->gp_regs))) 
-		{
 			goto badframe;
-		}
-		/**********************************************************************/
-		/* The saved reg structure in the frame is an elf_grepset_t32, it is  */
-		/*   a 32 bit register save of the registers in the pt_regs structure */
-		/*   that was stored on the kernel stack during the system call       */
-		/*   when the system call was interrupted for the signal. Only 32 bits*/
-		/*   are saved because the sigcontext contains a pointer to the regs  */
-		/*   and the sig context address is passed as a pointer to the signal */
-		/*   handler.                                                         */
-		/*                                                                    */
-		/* The entries in the elf_grepset have the same index as the elements */
-		/*   in the pt_regs structure.                                        */
-		/*                                                                    */
-		/**********************************************************************/
 
+		/*
+		 * The saved reg structure in the frame is an elf_grepset_t32,
+		 * it is a 32 bit register save of the registers in the
+		 * pt_regs structure that was stored on the kernel stack
+		 * during the system call when the system call was interrupted
+		 * for the signal. Only 32 bits are saved because the
+		 * sigcontext contains a pointer to the regs and the sig
+		 * context address is passed as a pointer to the signal handler
+		 *
+		 * The entries in the elf_grepset have the same index as
+		 * the elements in the pt_regs structure.
+		 */
 		saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE)
 			| (saved_regs[PT_MSR] & MSR_USERCHANGE);
-		regs->gpr[0] = (u64)(saved_regs[0]) & 0xFFFFFFFF;
-		regs->gpr[1] = (u64)(saved_regs[1]) & 0xFFFFFFFF;
-		/**********************************************************************/
-		/* Register 2 is the kernel toc - should be reset on any calls into   */
-		/*  the kernel                                                        */
-		/**********************************************************************/
-		regs->gpr[2] = (u64)(saved_regs[2]) & 0xFFFFFFFF;
- 
-		regs->gpr[3] = (u64)(saved_regs[3]) & 0xFFFFFFFF;
-		regs->gpr[4] = (u64)(saved_regs[4]) & 0xFFFFFFFF;
-		regs->gpr[5] = (u64)(saved_regs[5]) & 0xFFFFFFFF;
-		regs->gpr[6] = (u64)(saved_regs[6]) & 0xFFFFFFFF;
-		regs->gpr[7] = (u64)(saved_regs[7]) & 0xFFFFFFFF;
-		regs->gpr[8] = (u64)(saved_regs[8]) & 0xFFFFFFFF;
-		regs->gpr[9] = (u64)(saved_regs[9]) & 0xFFFFFFFF;
-		regs->gpr[10] = (u64)(saved_regs[10]) & 0xFFFFFFFF;
-		regs->gpr[11] = (u64)(saved_regs[11]) & 0xFFFFFFFF;
-		regs->gpr[12] = (u64)(saved_regs[12]) & 0xFFFFFFFF;
-		regs->gpr[13] = (u64)(saved_regs[13]) & 0xFFFFFFFF;
-		regs->gpr[14] = (u64)(saved_regs[14]) & 0xFFFFFFFF;
-		regs->gpr[15] = (u64)(saved_regs[15]) & 0xFFFFFFFF;
-		regs->gpr[16] = (u64)(saved_regs[16]) & 0xFFFFFFFF;
-		regs->gpr[17] = (u64)(saved_regs[17]) & 0xFFFFFFFF;
-		regs->gpr[18] = (u64)(saved_regs[18]) & 0xFFFFFFFF;
-		regs->gpr[19] = (u64)(saved_regs[19]) & 0xFFFFFFFF;
-		regs->gpr[20] = (u64)(saved_regs[20]) & 0xFFFFFFFF;
-		regs->gpr[21] = (u64)(saved_regs[21]) & 0xFFFFFFFF;
-		regs->gpr[22] = (u64)(saved_regs[22]) & 0xFFFFFFFF;
-		regs->gpr[23] = (u64)(saved_regs[23]) & 0xFFFFFFFF;
-		regs->gpr[24] = (u64)(saved_regs[24]) & 0xFFFFFFFF;
-		regs->gpr[25] = (u64)(saved_regs[25]) & 0xFFFFFFFF;
-		regs->gpr[26] = (u64)(saved_regs[26]) & 0xFFFFFFFF;
-		regs->gpr[27] = (u64)(saved_regs[27]) & 0xFFFFFFFF;
-		regs->gpr[28] = (u64)(saved_regs[28]) & 0xFFFFFFFF;
-		regs->gpr[29] = (u64)(saved_regs[29]) & 0xFFFFFFFF;
-		regs->gpr[30] = (u64)(saved_regs[30]) & 0xFFFFFFFF;
-		regs->gpr[31] = (u64)(saved_regs[31]) & 0xFFFFFFFF;
-		/****************************************************/
-		/*  restore the non gpr registers                   */
-		/****************************************************/
+		/*
+		 * Register 2 is the kernel toc - should be reset on any
+		 * calls into the kernel
+		 */
+		for (i = 0; i < 32; i++)
+			regs->gpr[i] = (u64)(saved_regs[i]) & 0xFFFFFFFF;
+		/*
+		 * restore the non gpr registers
+		 */
 		regs->msr = (u64)(saved_regs[PT_MSR]) & 0xFFFFFFFF;
-
 		regs->nip = (u64)(saved_regs[PT_NIP]) & 0xFFFFFFFF;
 		regs->orig_gpr3 = (u64)(saved_regs[PT_ORIG_R3]) & 0xFFFFFFFF; 
 		regs->ctr = (u64)(saved_regs[PT_CTR]) & 0xFFFFFFFF; 
@@ -659,14 +577,18 @@
 		regs->xer = (u64)(saved_regs[PT_XER]) & 0xFFFFFFFF; 
 		regs->ccr = (u64)(saved_regs[PT_CCR]) & 0xFFFFFFFF;
 		/* regs->softe is left unchanged (like MSR.EE) */
-		/******************************************************/
-		/* the DAR and the DSISR are only relevant during a   */
-		/*   data or instruction storage interrupt. The value */
-		/*   will be set to zero.                             */
-		/******************************************************/
+		/*
+		 * the DAR and the DSISR are only relevant during a
+		 *   data or instruction storage interrupt. The value
+		 *   will be set to zero.
+		 */
 		regs->dar = 0; 
 		regs->dsisr = 0;
 		regs->result = (u64)(saved_regs[PT_RESULT]) & 0xFFFFFFFF;
+
+		if (copy_from_user(current->thread.fpr, &signalregs->fp_regs, sizeof(signalregs->fp_regs))) 
+			goto badframe;
+
 		ret = regs->result;
 	}
 	else  /* more signals to go  */
@@ -696,6 +618,7 @@
 		{
 			goto badframe;
 		}
+		current->thread.fpscr = 0;
 
 	}
 
@@ -772,10 +695,12 @@
 extern asmlinkage long sys_rt_sigprocmask(int how, sigset_t *set, sigset_t *oset,
 					  size_t sigsetsize);
 
-/* Note: it is necessary to treat how 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)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
+/*
+ * Note: it is necessary to treat how 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) and the register representation
+ * of a signed int (msr in 64-bit mode) is performed.
  */
 asmlinkage long sys32_rt_sigprocmask(u32 how, sigset32_t *set, sigset32_t *oset, size_t sigsetsize)
 {
@@ -802,7 +727,8 @@
 	ret = sys_rt_sigprocmask((int)how, set ? &s : NULL, oset ? &s : NULL,
 				 sigsetsize); 
 	set_fs (old_fs);
-	if (ret) return ret;
+	if (ret)
+		return ret;
 	if (oset) {
 		switch (_NSIG_WORDS) {
 		case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3];
@@ -853,7 +779,7 @@
 	memset (d, 0, sizeof(siginfo_t32));
 	d->si_signo = s->si_signo;
 	d->si_errno = s->si_errno;
-	d->si_code = s->si_code;
+	d->si_code = s->si_code & 0xffff;
 	if (s->si_signo >= SIGRTMIN) {
 		d->si_pid = s->si_pid;
 		d->si_uid = s->si_uid;
@@ -917,12 +843,10 @@
 	}
 	set_fs (KERNEL_DS);
 	if (uts) 
-	{
 		ret = sys_rt_sigtimedwait(&s, &info, &t, sigsetsize);
-	} else {
-		ret = sys_rt_sigtimedwait(&s, &info, (struct timespec *)uts, sigsetsize);
-	}
-	
+	else
+		ret = sys_rt_sigtimedwait(&s, &info, (struct timespec *)uts,
+				sigsetsize);
 	set_fs (old_fs);
 	if (ret >= 0 && uinfo) {
 		if (copy_to_user (uinfo, siginfo64to32(&info32, &info),
@@ -974,10 +898,12 @@
 
 extern asmlinkage long sys_rt_sigqueueinfo(int pid, int sig, siginfo_t *uinfo);
 
-/* Note: it is necessary to treat pid and sig as unsigned ints,
- * 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)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
+/*
+ * Note: it is necessary to treat pid and sig as unsigned ints, 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) and the register representation of a signed int
+ * (msr in 64-bit mode) is performed.
  */
 asmlinkage long sys32_rt_sigqueueinfo(u32 pid, u32 sig, siginfo_t32 *uinfo)
 {
@@ -1012,9 +938,11 @@
 	if (copy_from_user(&s32, unewset, sizeof(s32)))
 		return -EFAULT;
 
-	/* Swap the 2 words of the 64-bit sigset_t (they are stored in the "wrong" endian in 32-bit user storage). */
-	switch (_NSIG_WORDS) 
-	{
+	/*
+	 * Swap the 2 words of the 64-bit sigset_t (they are stored
+	 * in the "wrong" endian in 32-bit user storage).
+	 */
+	switch (_NSIG_WORDS) {
 		case 4: newset.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32);
 		case 3: newset.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32);
 		case 2: newset.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32);
@@ -1029,22 +957,26 @@
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
 
-	regs->gpr[3] = -EINTR;
+	regs->result = -EINTR;
+	regs->gpr[3] = EINTR;
+	regs->ccr |= 0x10000000;
 	while (1) {
 		current->state = TASK_INTERRUPTIBLE;
 		schedule();
 		if (do_signal(&saveset, regs))
+			/*
+			 * If a signal handler needs to be called,
+			 * do_signal() has set R3 to the signal number (the
+			 * first argument of the signal handler), so don't
+			 * overwrite that with EINTR !
+			 * In the other cases, do_signal() doesn't touch 
+			 * R3, so it's still set to -EINTR (see above).
+			 */
 			return regs->gpr[3];
 	}
 }
 
 
-
-
-
-
-
-
 /*
  * Set up a rt signal frame.
  */
@@ -1054,66 +986,36 @@
 {
 	unsigned int copyreg4,copyreg5;
 	struct rt_sigframe_32 * rt_sf = (struct rt_sigframe_32 *) (u64)newsp;
-
+	int i;
   
 	if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
 		goto badframe;
 	if (regs->msr & MSR_FP)
 		giveup_fpu(current);
-	/***************************************************************/
-	/*                                                             */ 
-	/* Copy the register contents for the pt_regs structure on the */
-	/*   kernel stack to the elf_gregset_t32 structure on the user */
-	/*   stack. This is a copy of 64 bit register values to 32 bit */
-	/*   register values. The high order 32 bits of the 64 bit     */
-	/*   registers are not needed since a 32 bit application is    */
-	/*   running and the saved registers are the contents of the   */
-	/*   user registers at the time of a system call.              */
-	/*                                                             */
-	/* The values saved on the user stack will be restored into    */
-	/*  the registers during the signal return processing          */
-	/*                                                             */
-	/* Note the +1 is needed in order to get the lower 32 bits     */
-	/*  of 64 bit register                                         */
-	/***************************************************************/
-	if (__copy_to_user(&frame->gp_regs[0], (u32*)(&regs->gpr[0])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[1], (u32*)(&regs->gpr[1])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[2], (u32*)(&regs->gpr[2])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[3], (u32*)(&regs->gpr[3])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[4], (u32*)(&regs->gpr[4])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[5], (u32*)(&regs->gpr[5])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[6], (u32*)(&regs->gpr[6])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[7], (u32*)(&regs->gpr[7])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[8], (u32*)(&regs->gpr[8])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[9], (u32*)(&regs->gpr[9])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[10], (u32*)(&regs->gpr[10])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[11], (u32*)(&regs->gpr[11])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[12], (u32*)(&regs->gpr[12])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[13], (u32*)(&regs->gpr[13])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[14], (u32*)(&regs->gpr[14])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[15], (u32*)(&regs->gpr[15])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[16], (u32*)(&regs->gpr[16])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[17], (u32*)(&regs->gpr[17])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[18], (u32*)(&regs->gpr[18])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[19], (u32*)(&regs->gpr[19])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[20], (u32*)(&regs->gpr[20])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[21], (u32*)(&regs->gpr[21])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[22], (u32*)(&regs->gpr[22])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[23], (u32*)(&regs->gpr[23])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[24], (u32*)(&regs->gpr[24])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[25], (u32*)(&regs->gpr[25])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[26], (u32*)(&regs->gpr[26])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[27], (u32*)(&regs->gpr[27])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[28], (u32*)(&regs->gpr[28])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[29], (u32*)(&regs->gpr[29])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[30], (u32*)(&regs->gpr[30])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[31], (u32*)(&regs->gpr[31])+1, sizeof(u32))) 
-		goto badframe;
 
-	/*****************************************************************************/
-	/* Copy the non gpr registers to the user stack                              */
-	/*****************************************************************************/
+	/*
+	 * Copy the register contents for the pt_regs structure on the
+	 *   kernel stack to the elf_gregset_t32 structure on the user
+	 *   stack. This is a copy of 64 bit register values to 32 bit
+	 *   register values. The high order 32 bits of the 64 bit
+	 *   registers are not needed since a 32 bit application is
+	 *   running and the saved registers are the contents of the
+	 *   user registers at the time of a system call.
+	 *
+	 * The values saved on the user stack will be restored into
+	 *  the registers during the signal return processing.
+	 *
+	 * Note the +1 is needed in order to get the lower 32 bits
+	 * of 64 bit register
+	 */
+	for (i = 0; i < 32; i++) {
+		if (__copy_to_user(&frame->gp_regs[i], (u32*)(&regs->gpr[i])+1, sizeof(u32)))
+			goto badframe;
+	}
 
+	/*
+	 * Copy the non gpr registers to the user stack
+	 */
 	if (__copy_to_user(&frame->gp_regs[PT_NIP], (u32*)(&regs->gpr[PT_NIP])+1, sizeof(u32))
 	    || __copy_to_user(&frame->gp_regs[PT_MSR], (u32*)(&regs->gpr[PT_MSR])+1, sizeof(u32))
 	    || __copy_to_user(&frame->gp_regs[PT_ORIG_R3], (u32*)(&regs->gpr[PT_ORIG_R3])+1,
@@ -1127,14 +1029,12 @@
 		goto badframe;
 
 
-	/*****************************************************************************/
-	/* Now copy the floating point registers onto the user stack                 */
-	/*                                                                           */
-	/* Also set up so on the completion of the signal handler, the sys_sigreturn */
-	/*   will get control to reset the stack                                     */
-	/*****************************************************************************/
-
-
+	/*
+	 * Now copy the floating point registers onto the user stack
+	 *
+	 * Also set up so on the completion of the signal handler, the
+	 * sys_sigreturn will get control to reset the stack
+	 */
 	if (__copy_to_user(&frame->fp_regs, current->thread.fpr,
 			   ELF_NFPREG * sizeof(double))
 	    || __put_user(0x38000000U + __NR_rt_sigreturn, &frame->tramp[0])    /* li r0, __NR_rt_sigreturn */
@@ -1143,10 +1043,11 @@
 
 	flush_icache_range((unsigned long) &frame->tramp[0],
 			   (unsigned long) &frame->tramp[2]);
-
+	current->thread.fpscr = 0;	/* turn off all fp exceptions */
   
-	/* Retrieve rt_sigframe from stack and
-	   set up registers for signal handler
+	/*
+	 * Retrieve rt_sigframe from stack and
+	 * set up registers for signal handler
 	*/
 	newsp -= __SIGNAL_FRAMESIZE32;
       
@@ -1160,17 +1061,12 @@
 
 	regs->gpr[4] = copyreg4;
 	regs->gpr[5] = copyreg5;
-
-   
 	regs->gpr[1] = newsp;
 	regs->gpr[6] = (unsigned long) rt_sf;
-
-
 	regs->link = (unsigned long) frame->tramp;
 
 	return;
 
-
  badframe:
 	udbg_printf("setup_frame32 - badframe in setup_frame, regs=%p frame=%p newsp=%lx\n", regs, frame, newsp);  PPCDBG_ENTER_DEBUGGER();
 #if DEBUG_SIG
@@ -1189,7 +1085,7 @@
 	      siginfo_t *info, sigset_t *oldset, struct pt_regs * regs,
 	      unsigned int *newspp, unsigned int frame)
 {
-	struct sigcontext32_struct *sc;
+	struct sigcontext32 *sc;
 	struct rt_sigframe_32 *rt_stack_frame;
 	siginfo_t32 siginfo32bit;
 
@@ -1231,14 +1127,15 @@
 			goto badframe; 
 		}
 	} else {
-		/* Put another sigcontext on the stack */
+		/* Put a sigcontext on the stack */
 		*newspp -= sizeof(*sc);
-		sc = (struct sigcontext32_struct *)(u64)*newspp;
+		sc = (struct sigcontext32 *)(u64)*newspp;
 		if (verify_area(VERIFY_WRITE, sc, sizeof(*sc)))
 			goto badframe;
-
-		/* Note the upper 32 bits of the signal mask are stored in the */
-		/*   unused part of the signal stack frame                     */  
+		/*
+		 * Note the upper 32 bits of the signal mask are stored
+		 * in the unused part of the signal stack frame
+		 */
 		if (__put_user((u32)(u64)ka->sa.sa_handler, &sc->handler)
 		    || __put_user(oldset->sig[0], &sc->oldmask)
 		    || __put_user((oldset->sig[0] >> 32), &sc->_unused[3])
@@ -1270,15 +1167,12 @@
 }
 
 
-/****************************************************************************/
-/*  Start Alternate signal stack support                                    */
-/*                                                                          */
-/*                                                                          */
-/*                                                                          */
-/*  System Calls                                                            */
-/*       sigaltatck               sys32_sigaltstack                         */
-/*                                                                          */
-/****************************************************************************/
+/*
+ *  Start Alternate signal stack support
+ *
+ *  System Calls
+ *       sigaltatck               sys32_sigaltstack
+ */
 
 
 asmlinkage int sys32_sigaltstack(u32 newstack, u32 oldstack, int p3, int p4, int p6,
@@ -1289,8 +1183,10 @@
 	mm_segment_t old_fs;
 	unsigned long sp;
 
-	/* set sp to the user stack on entry to the system call                  */
-	/*   the system call router sets R9 to the saved registers               */
+	/*
+	 * set sp to the user stack on entry to the system call
+	 * the system call router sets R9 to the saved registers
+	 */
 	sp = regs->gpr[1];
 
 	/*  Put new stack info in local 64 bit stack struct                      */ 
@@ -1314,15 +1210,14 @@
 
 
 
-/****************************************************************************/
-/*  Start of do_signal32 routine                                            */
-/*                                                                          */
-/*   This routine gets control when a pemding signal needs to be processed  */
-/*     in the 32 bit target thread -                                        */
-/*                                                                          */
-/*   It handles both rt and non-rt signals                                  */
-/*                                                                          */
-/****************************************************************************/
+/*
+ *  Start of do_signal32 routine
+ *
+ *   This routine gets control when a pending signal needs to be processed
+ *     in the 32 bit target thread -
+ *
+ *   It handles both rt and non-rt signals
+ */
 
 /*
  * Note that 'init' is a special process: it doesn't get signals it doesn't
@@ -1445,9 +1340,8 @@
 
 		if ( (ka->sa.sa_flags & SA_ONSTACK)
 		     && (! on_sig_stack(regs->gpr[1])))
-		{
 			newsp = (current->sas_ss_sp + current->sas_ss_size);
-		} else
+		else
 			newsp = regs->gpr[1];
 		newsp = frame = newsp - sizeof(struct sigregs32);
 
@@ -1466,15 +1360,12 @@
 	}
 
 	if (newsp == frame)
-	{
 		return 0;		/* no signals delivered */
-	}
-	// Invoke correct stack setup routine 
+
+	/* Invoke correct stack setup routine */
 	if (ka->sa.sa_flags & SA_SIGINFO) 
 		setup_rt_frame32(regs, (struct sigregs32*)(u64)frame, newsp);
 	else
 		setup_frame32(regs, (struct sigregs32*)(u64)frame, newsp);
-
 	return 1;
-
 }
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/smp.c linux-2.4.21-pre4/arch/ppc64/kernel/smp.c
--- linux-2.4.21-pre3/arch/ppc64/kernel/smp.c	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/smp.c	Tue Jan 28 19:44:29 2003
@@ -224,7 +224,7 @@
 	ppc_md.smp_kick_cpu     = smp_iSeries_kick_cpu;
 	ppc_md.smp_setup_cpu    = smp_iSeries_setup_cpu;
 
-	naca->processorCount	= smp_iSeries_numProcs();
+	systemcfg->processorCount	= smp_iSeries_numProcs();
 }
 
 
@@ -255,10 +255,10 @@
 static int
 smp_chrp_probe(void)
 {
-	if (naca->processorCount > 1)
+	if (systemcfg->processorCount > 1)
 		openpic_request_IPIs();
 
-	return naca->processorCount;
+	return systemcfg->processorCount;
 }
 
 static void
@@ -299,11 +299,11 @@
 	static atomic_t ready = ATOMIC_INIT(1);
 	static volatile int frozen = 0;
 
-	if (naca->platform == PLATFORM_PSERIES_LPAR) {
+	if (systemcfg->platform == PLATFORM_PSERIES_LPAR) {
 		/* timebases already synced under the hypervisor. */
 		paca[cpu_nr].next_jiffy_update_tb = tb_last_stamp = get_tb();
 		if (cpu_nr == 0) {
-			naca->tb_orig_stamp = tb_last_stamp;
+			systemcfg->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()
@@ -330,7 +330,7 @@
 			mb();
 			frozen = 0;
 			tb_last_stamp = get_tb();
-			naca->tb_orig_stamp = tb_last_stamp;
+			systemcfg->tb_orig_stamp = tb_last_stamp;
 			smp_tb_synchronized = 1;
 		} else {
 			atomic_inc(&ready);
@@ -371,7 +371,7 @@
 static int
 smp_xics_probe(void)
 {
-	return naca->processorCount;
+	return systemcfg->processorCount;
 }
 
 /* This is called very early */
@@ -621,7 +621,7 @@
 		if(i != 0) {
 		        /*
 			 * Processor 0's segment table is statically 
-			 * initialized to real address 0x5000.  The
+			 * initialized to real address STAB0_PHYS_ADDR.  The
 			 * Other processor's tables are created and
 			 * initialized here.
 			 */
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/sys32.S linux-2.4.21-pre4/arch/ppc64/kernel/sys32.S
--- linux-2.4.21-pre3/arch/ppc64/kernel/sys32.S	Fri Aug  2 17:39:43 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/sys32.S	Tue Jan 28 19:44:29 2003
@@ -19,8 +19,6 @@
 #include <asm/errno.h>
 #include <asm/processor.h>
 
-/* NOTE: call as jump breaks return stack, we have to avoid that */
-
 	.text
 
 _GLOBAL(sys32_mmap)
@@ -32,14 +30,6 @@
 	extsw		r4,r4		/* sign extend off_t offset parm */
 	b		.sys_lseek
 
-_GLOBAL(sys32_chmod)
-/* Ken Aaker.. hmmm maybe I don't need to do anything here */
-	b		.sys_chmod
-
-_GLOBAL(sys32_mknod)
-/* Ken Aaker.. hmmm maybe I don't need to do anything here */
-	b		.sys_mknod
-
 _GLOBAL(sys32_sendto)
 	clrldi		r7, r7, 32	/* struct sockaddr *addr parm */
 	clrldi		r8, r8, 32	/* int addr_len parm */
@@ -58,10 +48,10 @@
 	extsw		r4,r4		/* sign extend long data parm */
 	b		.sys_bdflush
 
-_GLOBAL(sys32_mmap2)
+_GLOBAL(ppc32_mmap2)
 	clrldi		r7, r7, 32	/* unsigned long fd parm */
-	extsw		r8, r8		/* off_t offset */
-	b		.sys_mmap
+	clrldi		r8, r8, 32	/* unsigned long pgoff */
+	b		.sys32_mmap2
 
 _GLOBAL(sys32_socketcall)	/* r3=call, r4=args */
 	cmpwi		r3, 1
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/sys_ppc32.c linux-2.4.21-pre4/arch/ppc64/kernel/sys_ppc32.c
--- linux-2.4.21-pre3/arch/ppc64/kernel/sys_ppc32.c	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/sys_ppc32.c	Tue Jan 28 19:44:29 2003
@@ -69,17 +69,6 @@
 extern unsigned long wall_jiffies;
 #define USEC_PER_SEC (1000000)
 
-/* 
- * These are the flags in the MSR that the user is allowed to change
- * by modifying the saved value of the MSR on the stack.  SE and BE
- * should not be in this list since gdb may want to change these.  I.e,
- * you should be able to step out of a signal handler to see what
- * instruction executes next after the signal handler completes.
- * Alternately, if you stepped into a signal handler, you should be
- * able to continue 'til the next breakpoint from within the signal
- * handler, even if the handler returns.
- */
-#define MSR_USERCHANGE	(MSR_FE0 | MSR_FE1)
 
 extern asmlinkage long sys_utime(char * filename, struct utimbuf * times);
 
@@ -135,10 +124,10 @@
 	 */
 	if (!count)
 		return 0;
-	if(verify_area(VERIFY_READ, vector, sizeof(struct iovec32)*count))
-		return -EFAULT;
 	if (count > UIO_MAXIOV)
 		return -EINVAL;
+	if(verify_area(VERIFY_READ, vector, sizeof(struct iovec32)*count))
+		return -EFAULT;
 	if (count > UIO_FASTIOV) {
 		iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
 		if (!iov)
@@ -546,7 +535,6 @@
 	u32		d_ino;
 	u32		d_offset;
 	unsigned short	d_namlen;
-  /* unsigned char	d_type; */
 	char		d_name[1];
 };
 
@@ -639,7 +627,6 @@
 	buf->previous = dirent;
 	put_user(ino, &dirent->d_ino);
 	put_user(reclen, &dirent->d_reclen);
-	/* put_user(d_type, &dirent->d_type); */
 	copy_to_user(dirent->d_name, name, namlen);
 	put_user(0, dirent->d_name + namlen);
 	((char *) dirent) += reclen;
@@ -837,7 +824,7 @@
 		put_user(usec, &tvp->tv_usec);
 	}
 
-  if (ret < 0)
+	if (ret < 0)
 		goto out;
 	if (!ret) {
 		ret = -ERESTARTNOHAND;
@@ -2448,8 +2435,10 @@
 struct msgbuf32 { s32 mtype; char mtext[1]; };
 
 struct semid_ds32 {
-	struct ipc_perm sem_perm;
+	struct ipc_perm32 sem_perm;
+	unsigned int _pad0;
 	__kernel_time_t32 sem_otime;
+	unsigned int _pad1;
 	__kernel_time_t32 sem_ctime;
 	u32 sem_base;
 	u32 sem_pending;
@@ -2459,7 +2448,7 @@
 };
 
 struct semid64_ds32 {
-	struct ipc64_perm sem_perm;
+	struct ipc64_perm32 sem_perm;
 	unsigned int __unused1;
 	__kernel_time_t32 sem_otime;
 	unsigned int __unused2;
@@ -2471,7 +2460,7 @@
 
 struct msqid_ds32
 {
-	struct ipc_perm msg_perm;
+	struct ipc_perm32 msg_perm;
 	u32 msg_first;
 	u32 msg_last;
 	__kernel_time_t32 msg_stime;
@@ -2487,7 +2476,7 @@
 };
 
 struct msqid64_ds32 {
-	struct ipc64_perm msg_perm;
+	struct ipc64_perm32 msg_perm;
 	unsigned int __unused1;
 	__kernel_time_t32 msg_stime;
 	unsigned int __unused2;
@@ -2504,7 +2493,7 @@
 };
 
 struct shmid_ds32 {
-	struct ipc_perm shm_perm;
+	struct ipc_perm32 shm_perm;
 	int shm_segsz;
 	__kernel_time_t32 shm_atime;
 	__kernel_time_t32 shm_dtime;
@@ -2518,7 +2507,7 @@
 };
 
 struct shmid64_ds32 {
-	struct ipc64_perm shm_perm;
+	struct ipc64_perm32 shm_perm;
 	unsigned int __unused1;
 	__kernel_time_t32 shm_atime;
 	unsigned int __unused2;
@@ -2584,7 +2573,7 @@
 			err = sys_semctl(first, second, third, fourth);
 			set_fs(old_fs);
 			err2 = copy_to_user(&usp->sem_perm, &s64.sem_perm,
-					    sizeof(struct ipc64_perm));
+					    sizeof(struct ipc64_perm32));
 			err2 |= __put_user(s64.sem_otime, &usp->sem_otime);
 			err2 |= __put_user(s64.sem_ctime, &usp->sem_ctime);
 			err2 |= __put_user(s64.sem_nsems, &usp->sem_nsems);
@@ -2601,7 +2590,7 @@
 			err = sys_semctl(first, second, third, fourth);
 			set_fs(old_fs);
 			err2 = copy_to_user(&usp->sem_perm, &s.sem_perm,
-					    sizeof(struct ipc_perm));
+					    sizeof(struct ipc_perm32));
 			err2 |= __put_user(s.sem_otime, &usp->sem_otime);
 			err2 |= __put_user(s.sem_ctime, &usp->sem_ctime);
 			err2 |= __put_user(s.sem_nsems, &usp->sem_nsems);
@@ -2652,11 +2641,15 @@
 			set_fs(old_fs);
 		}
 		break;
+	default:
+		err = -EINVAL;
 	}
 out:
 	return err;
 }
 
+#define MAXBUF (64*1024)
+
 static int 
 do_sys32_msgsnd(int first, int second, int third, void *uptr)
 {
@@ -2665,14 +2658,14 @@
 	mm_segment_t old_fs;
 	int err;
 
-	if (second < 0)
+	if (second < 0 || (second >= MAXBUF-sizeof(struct msgbuf)))
 		return -EINVAL;
 
-	p = kmalloc(second + sizeof(struct msgbuf) + 4, GFP_USER);
+	p = kmalloc(second + sizeof(struct msgbuf), GFP_USER);
 	if (!p)
 		return -ENOMEM;
 	err = get_user(p->mtype, &up->mtype);
-	err |= __copy_from_user(p->mtext, &up->mtext, second);
+	err |= copy_from_user(p->mtext, &up->mtext, second);
 	if (err) {
 		err = -EFAULT;
 		goto out;
@@ -2695,35 +2688,35 @@
 	mm_segment_t old_fs;
 	int err;
 
-	if (second < 0)
+	if (second < 0 || (second >= MAXBUF-sizeof(struct msgbuf)))
 		return -EINVAL;
 
 	if (!version) {
-		struct ipc_kludge *uipck = (struct ipc_kludge *)uptr;
-		struct ipc_kludge ipck;
+		struct ipc_kludge_32 *uipck = (struct ipc_kludge_32 *)uptr;
+		struct ipc_kludge_32 ipck;
 
 		err = -EINVAL;
 		if (!uptr)
 			goto out;
 		err = -EFAULT;
-		if (copy_from_user(&ipck, uipck, sizeof(struct ipc_kludge)))
+		if (copy_from_user(&ipck, uipck, sizeof(struct ipc_kludge_32)))
 			goto out;
 		uptr = (void *)A(ipck.msgp);
 		msgtyp = ipck.msgtyp;
 	}
 	err = -ENOMEM;
-	p = kmalloc(second + sizeof (struct msgbuf) + 4, GFP_USER);
+	p = kmalloc(second + sizeof (struct msgbuf), GFP_USER);
 	if (!p)
 		goto out;
 	old_fs = get_fs();
 	set_fs(KERNEL_DS);
-	err = sys_msgrcv(first, p, second + 4, msgtyp, third);
+	err = sys_msgrcv(first, p, second, msgtyp, third);
 	set_fs(old_fs);
 	if (err < 0)
 		goto free_then_out;
 	up = (struct msgbuf32 *)uptr;
 	if (put_user(p->mtype, &up->mtype) ||
-	    __copy_to_user(&up->mtext, p->mtext, err))
+	    copy_to_user(&up->mtext, p->mtext, err))
 		err = -EFAULT;
 free_then_out:
 	kfree(p);
@@ -2751,7 +2744,7 @@
 			struct msqid64_ds32 *up = (struct msqid64_ds32 *)uptr;
 
 			err2 = copy_from_user(&m64.msg_perm, &up->msg_perm,
-					      sizeof(struct ipc64_perm));
+					      sizeof(struct ipc64_perm32));
 			err2 |= __get_user(m64.msg_qbytes, &up->msg_qbytes);
 			if (err2) {
 				err = -EFAULT;
@@ -2767,7 +2760,7 @@
 			struct msqid_ds32 *up = (struct msqid_ds32 *)uptr;
 
 			err2 = copy_from_user(&m.msg_perm, &up->msg_perm,
-					      sizeof(struct ipc_perm));
+					      sizeof(struct ipc_perm32));
 			err2 |= __get_user(m.msg_qbytes, &up->msg_qbytes);
 			if (err2) {
 				err = -EFAULT;
@@ -2793,7 +2786,7 @@
 			set_fs(old_fs);
 
 			err2 = copy_to_user(&up->msg_perm, &m64.msg_perm,
-					    sizeof(struct ipc64_perm));
+					    sizeof(struct ipc64_perm32));
  			err2 |= __put_user(m64.msg_stime, &up->msg_stime);
 			err2 |= __put_user(m64.msg_rtime, &up->msg_rtime);
 			err2 |= __put_user(m64.msg_ctime, &up->msg_ctime);
@@ -2814,7 +2807,7 @@
 			set_fs(old_fs);
 
 			err2 = copy_to_user(&up->msg_perm, &m.msg_perm,
-					    sizeof(struct ipc_perm));
+					    sizeof(struct ipc_perm32));
  			err2 |= __put_user(m.msg_stime, &up->msg_stime);
 			err2 |= __put_user(m.msg_rtime, &up->msg_rtime);
 			err2 |= __put_user(m.msg_ctime, &up->msg_ctime);
@@ -2850,7 +2843,7 @@
 static int
 do_sys32_shmctl(int first, int second, void *uptr)
 {
-	int err = -EFAULT, err2;
+	int err = -EINVAL, err2;
 	mm_segment_t old_fs;
 
 	switch (second & (~IPC_64)) {
@@ -2908,7 +2901,7 @@
 				break;
 
 			err2 = copy_to_user(&up->shm_perm, &s64.shm_perm,
-					    sizeof(struct ipc64_perm));
+					    sizeof(struct ipc64_perm32));
 			err2 |= __put_user(s64.shm_atime, &up->shm_atime);
 			err2 |= __put_user(s64.shm_dtime, &up->shm_dtime);
 			err2 |= __put_user(s64.shm_ctime, &up->shm_ctime);
@@ -2930,7 +2923,7 @@
 				break;
 
 			err2 = copy_to_user(&up->shm_perm, &s.shm_perm,
-					    sizeof(struct ipc_perm));
+					    sizeof(struct ipc_perm32));
 			err2 |= __put_user (s.shm_atime, &up->shm_atime);
 			err2 |= __put_user (s.shm_dtime, &up->shm_dtime);
 			err2 |= __put_user (s.shm_ctime, &up->shm_ctime);
@@ -4241,32 +4234,6 @@
 }
 
 
-extern asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on);
-
-/* Note: it is necessary to treat on 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)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage long sys32_ioperm(unsigned long from, unsigned long num, u32 on)
-{
-	return sys_ioperm(from, num, (int)on);
-}
-
-
-extern asmlinkage int sys_iopl(int a1, int a2, int a3, int a4);
-
-/* Note: it is necessary to treat a1, a2, a3, and a4 as unsigned ints,
- * 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)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage int sys32_iopl(u32 a1, u32 a2, u32 a3, u32 a4)
-{
-	return sys_iopl((int)a1, (int)a2, (int)a3, (int)a4);
-}
-
-
 extern asmlinkage long sys_kill(int pid, int sig);
 
 /* Note: it is necessary to treat pid and sig as unsigned ints,
@@ -4306,19 +4273,6 @@
 }
 
 
-extern asmlinkage int sys_modify_ldt(int a1, int a2, int a3, int a4);
-
-/* Note: it is necessary to treat a1, a2, a3, and a4 as unsigned ints,
- * 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)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage int sys32_modify_ldt(u32 a1, u32 a2, u32 a3, u32 a4)
-{
-	return sys_modify_ldt((int)a1, (int)a2, (int)a3, (int)a4);
-}
-
-
 extern asmlinkage long sys_msync(unsigned long start, size_t len, int flags);
 
 /* Note: it is necessary to treat flags as an unsigned int,
@@ -4344,19 +4298,36 @@
 	return sys_nice((int)increment);
 }
 
-
-extern asmlinkage long sys_open(const char * filename, int flags, int mode);
-
-/* Note: it is necessary to treat flags and mode as unsigned ints,
- * 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)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
+/*
+ * This is just a version for 32-bit applications which does
+ * not force O_LARGEFILE on.
  */
-asmlinkage long sys32_open(const char * filename, int flags, int mode)
+long sys32_open(const char * filename, int flags, int mode)
 {
-	return sys_open(filename, (int)flags, (int)mode);
-}
+	char * tmp;
+	int fd, error;
+
+	tmp = getname(filename);
+	fd = PTR_ERR(tmp);
+	if (!IS_ERR(tmp)) {
+		fd = get_unused_fd();
+		if (fd >= 0) {
+			struct file * f = filp_open(tmp, flags, mode);
+			error = PTR_ERR(f);
+			if (IS_ERR(f))
+				goto out_error;
+			fd_install(fd, f);
+		}
+out:
+		putname(tmp);
+	}
+	return fd;
 
+out_error:
+	put_unused_fd(fd);
+	fd = error;
+	goto out;
+}
 
 extern asmlinkage long sys_readlink(const char * path, char * buf, int bufsiz);
 
@@ -4604,23 +4575,6 @@
 	return sys_vfork((int)p1, (int)p2, (int)p3, (int)p4, (int)p5, (int)p6, regs);
 }
 
-
-extern asmlinkage int sys_vm86(int a1, int a2, int a3, int a4);
-
-/* Note: it is necessary to treat a1, a2, a3, and a4 as unsigned ints,
- * 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)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage int sys32_vm86(u32 a1, u32 a2, u32 a3, u32 a4)
-{
-	return sys_vm86((int)a1, (int)a2, (int)a3, (int)a4);
-}
-
-
-
-
-
 extern asmlinkage ssize_t sys_pread(unsigned int fd, char * buf,
 				    size_t count, loff_t pos);
 
@@ -4641,6 +4595,12 @@
 	return sys_pwrite(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo));
 }
 
+extern ssize_t sys_readahead(int fd, loff_t offset, size_t count);
+
+ssize_t32 sys32_readahead(int fd, u32 r4, u32 offhi, u32 offlo, u32 count)
+{
+        return sys_readahead(fd, ((loff_t)offhi << 32) | offlo, AA(count));
+}
 
 extern asmlinkage long sys_truncate(const char * path, unsigned long length);
 extern asmlinkage long sys_ftruncate(unsigned int fd, unsigned long length);
@@ -4737,3 +4697,15 @@
 
 	return secs;
 }
+
+extern unsigned long sys_mmap(unsigned long addr, size_t len,
+			      unsigned long prot, unsigned long flags,
+			      unsigned long fd, off_t offset);
+
+unsigned long sys32_mmap2(unsigned long addr, size_t len,
+			  unsigned long prot, unsigned long flags,
+			  unsigned long fd, unsigned long pgoff)
+{
+	/* This should remain 12 even if PAGE_SIZE changes */
+	return sys_mmap(addr, len, prot, flags, fd, pgoff << 12);
+}
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/syscalls.c linux-2.4.21-pre4/arch/ppc64/kernel/syscalls.c
--- linux-2.4.21-pre3/arch/ppc64/kernel/syscalls.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/syscalls.c	Tue Jan 28 19:44:29 2003
@@ -54,28 +54,9 @@
 
 asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
 {
-	printk(KERN_ERR "sys_ioperm()\n");
 	return -EIO;
 }
 
-int sys_iopl(int a1, int a2, int a3, int a4)
-{
-	printk(KERN_ERR "sys_iopl(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
-	return (-ENOSYS);
-}
-
-int sys_vm86(int a1, int a2, int a3, int a4)
-{
-	printk(KERN_ERR "sys_vm86(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
-	return (-ENOSYS);
-}
-
-int sys_modify_ldt(int a1, int a2, int a3, int a4)
-{
-	printk(KERN_ERR "sys_modify_ldt(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
-	return (-ENOSYS);
-}
-
 /*
  * sys_ipc() is the de-multiplexer for the SysV IPC calls..
  *
@@ -125,7 +106,7 @@
 						(struct ipc_kludge *) ptr,
 						sizeof (tmp))))
 				break;
-			ret = sys_msgrcv (first, (struct msgbuf *)(unsigned long)tmp.msgp,
+			ret = sys_msgrcv (first, (struct msgbuf *)tmp.msgp,
 						second, tmp.msgtyp, third);
 			break;
 		}
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/time.c linux-2.4.21-pre4/arch/ppc64/kernel/time.c
--- linux-2.4.21-pre3/arch/ppc64/kernel/time.c	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/time.c	Tue Jan 28 19:44:29 2003
@@ -212,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 );
-				naca->tb_ticks_per_sec = tb_ticks_per_sec;
+				systemcfg->tb_ticks_per_sec = tb_ticks_per_sec;
 				tb_to_xs = divres.result_low;
-				naca->tb_to_xs = tb_to_xs;
+				systemcfg->tb_to_xs = tb_to_xs;
 			}
 			else {
 				printk( "Titan recalibrate: FAILED (difference > 4 percent)\n"
@@ -258,6 +258,8 @@
 	if ((!user_mode(regs)) && (prof_buffer))
 		ppc_do_profile(instruction_pointer(regs));
 
+	pmc_timeslice_tick(); /* Hack this in for now */
+
 	lpaca->xLpPaca.xIntDword.xFields.xDecrInt = 0;
 
 	while (lpaca->next_jiffy_update_tb <= (cur_tb = get_tb())) {
@@ -306,9 +308,9 @@
 	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;
+	struct systemcfg *gtdp;
 	
-	gtdp = (struct naca_struct *)0xC000000000004000;
+	gtdp = systemcfg;
 	/* 
 	 * The following loop guarantees that we see a consistent view of the
 	 * tb_to_xs and stamp_xsec variables.  These two variables can change
@@ -412,23 +414,23 @@
 	time_maxerror = NTP_PHASE_LIMIT;
 	time_esterror = NTP_PHASE_LIMIT;
 
-	delta_xsec = mulhdu( (tb_last_stamp-naca->tb_orig_stamp), naca->tb_to_xs );
+	delta_xsec = mulhdu( (tb_last_stamp-systemcfg->tb_orig_stamp), systemcfg->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 ) {
-		naca->stamp_xsec = new_xsec - delta_xsec;
+		systemcfg->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 */
-		naca->stamp_xsec = new_xsec;
-		naca->tb_orig_stamp = tb_last_stamp;
+		systemcfg->stamp_xsec = new_xsec;
+		systemcfg->tb_orig_stamp = tb_last_stamp;
 	}
 
-	naca->tz_minuteswest = sys_tz.tz_minuteswest;
-	naca->tz_dsttime = sys_tz.tz_dsttime;
+	systemcfg->tz_minuteswest = sys_tz.tz_minuteswest;
+	systemcfg->tz_dsttime = sys_tz.tz_dsttime;
 
 	write_unlock_irqrestore(&xtime_lock, flags);
 }
@@ -498,11 +500,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();
-	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;
+	systemcfg->tb_orig_stamp = tb_last_stamp;
+	systemcfg->tb_update_count = 0;
+	systemcfg->tb_ticks_per_sec = tb_ticks_per_sec;
+	systemcfg->stamp_xsec = xtime.tv_sec * XSEC_PER_SEC;
+	systemcfg->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;
@@ -614,14 +616,14 @@
 	 * tb_to_xs) and so guarantees that the current time remains the same
 	 *
 	 */ 
-	tb_ticks = get_tb() - naca->tb_orig_stamp;
+	tb_ticks = get_tb() - systemcfg->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, naca->tb_to_xs );
-	new_stamp_xsec = naca->stamp_xsec + old_xsec - new_xsec;
+	old_xsec = mulhdu( tb_ticks, systemcfg->tb_to_xs );
+	new_stamp_xsec = systemcfg->stamp_xsec + old_xsec - new_xsec;
 
 	/*
 	 * tb_update_count is used to allow the problem state gettimeofday code
@@ -632,12 +634,12 @@
 	 * 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);
+	++(systemcfg->tb_update_count);
 	wmb();
-	naca->tb_to_xs = new_tb_to_xs;
-	naca->stamp_xsec = new_stamp_xsec;
+	systemcfg->tb_to_xs = new_tb_to_xs;
+	systemcfg->stamp_xsec = new_stamp_xsec;
 	wmb();
-	++(naca->tb_update_count);
+	++(systemcfg->tb_update_count);
 
 	write_unlock_irqrestore( &xtime_lock, flags );
 
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/traps.c linux-2.4.21-pre4/arch/ppc64/kernel/traps.c
--- linux-2.4.21-pre3/arch/ppc64/kernel/traps.c	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/traps.c	Tue Jan 28 19:44:29 2003
@@ -1,5 +1,5 @@
 /*
- *  linux/arch/ppc/kernel/traps.c
+ *  linux/arch/ppc64/kernel/traps.c
  *
  *  Copyright (C) 1995-1996  Gary Thomas (gdt@linuxppc.org)
  *
@@ -94,8 +94,8 @@
  * Trap & Exception support
  */
 
-void
-_exception(int signr, struct pt_regs *regs)
+static void
+_exception(int signr, siginfo_t *info, struct pt_regs *regs)
 {
 	if (!user_mode(regs))
 	{
@@ -115,7 +115,7 @@
 			debugger(regs);
 #endif
 	}
-	force_sig(signr, current);
+	force_sig_info(signr, info, current);
 }
 
 /* Get the error information for errors coming through the
@@ -155,35 +155,47 @@
 SystemResetException(struct pt_regs *regs)
 {
 	char *msg = "System Reset in kernel mode.\n";
-	udbg_printf(msg); printk(msg);
+	printk(msg);
 	if (fwnmi_active) {
 		unsigned long *r3 = __va(regs->gpr[3]); /* for FWNMI debug */
-		struct rtas_error_log *errlog;
-
-		msg = "FWNMI is active with save area at %016lx\n";
-		udbg_printf(msg, r3); printk(msg, r3);
-		errlog = FWNMI_get_errinfo(regs);
+		printk("FWNMI is active with save area at %p\n", r3);
+		FWNMI_release_errinfo();
 	}
 #if defined(CONFIG_XMON)
 	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");
+	{
+		int cpu = smp_processor_id();
+		static int reset_cpu = -1;
+		static spinlock_t reset_lock = SPIN_LOCK_UNLOCKED;
+
+		/* Give kdb some help serializing the reset */
+		spin_lock(&reset_lock);
+		if (reset_cpu == -1) {
+			reset_cpu = cpu;
+			spin_unlock(&reset_lock);
+			kdb(KDB_REASON_ENTER, regs->trap, (kdb_eframe_t) regs);
+			reset_cpu = -1;
+		} else {
+			spin_unlock(&reset_lock);
+			/* Let kdb catch this cpu with an IPI.
+			 * Ideally we need a way to enter kdb w/o it becoming
+			 * confused so we can precisely capture reset state.
+			 */
+			return;
+		}
+	}
 #endif
-
-/*
-allow system to resume after reset.
-	for(;;);
-*/
-
 }
 
 
 void
 MachineCheckException(struct pt_regs *regs)
 {
+	siginfo_t info;
+
 	if (fwnmi_active) {
 		struct rtas_error_log *errhdr = FWNMI_get_errinfo(regs);
 		if (errhdr) {
@@ -191,8 +203,8 @@
 		}
 		FWNMI_release_errinfo();
 	}
-	if ( !user_mode(regs) )
-	{
+
+	if ( !user_mode(regs) ) {
 #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
 		if (debugger_fault_handler) {
 			debugger_fault_handler(regs);
@@ -216,7 +228,17 @@
 		print_backtrace((unsigned long *)regs->gpr[1]);
 		panic("machine check");
 	}
-	_exception(SIGSEGV, regs);	
+	
+	/*
+	 * XXX we should check RI bit on exception exit and kill the
+	 * task if it was cleared
+	 */
+	info.si_signo = SIGBUS;
+	info.si_errno = 0;
+	info.si_code = BUS_ADRERR;
+	info.si_addr = (void *)regs->nip;
+	_exception(SIGSEGV, &info, regs);
+
 }
 
 void
@@ -242,14 +264,23 @@
 void
 UnknownException(struct pt_regs *regs)
 {
+	siginfo_t info;
+
 	printk("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
 	       regs->nip, regs->msr, regs->trap);
-	_exception(SIGTRAP, regs);	
+
+	info.si_signo = SIGTRAP;
+	info.si_errno = 0;
+	info.si_code = 0;
+	info.si_addr = 0;
+	_exception(SIGTRAP, &info, regs);	
 }
 
 void
 InstructionBreakpointException(struct pt_regs *regs)
 {
+	siginfo_t info;
+	
 #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
 	if (debugger_iabr_match(regs))
 		return;
@@ -258,17 +289,73 @@
 	if (kdb(KDB_REASON_BREAK, 0, regs))
 		return ;
 #endif
-	_exception(SIGTRAP, regs);
+
+	info.si_signo = SIGTRAP;
+	info.si_errno = 0;
+	info.si_code = TRAP_BRKPT;
+	info.si_addr = (void *)regs->nip;
+	_exception(SIGTRAP, &info, regs);
+}
+
+static void
+parse_fpe(siginfo_t *info, struct pt_regs *regs)
+{
+	unsigned long fpscr;
+
+	if (regs->msr & MSR_FP)
+		giveup_fpu(current);
+
+	fpscr = current->thread.fpscr;
+
+	/* Invalid operation */
+	if ((fpscr & FPSCR_VE) && (fpscr & FPSCR_VX))
+		info->si_code = FPE_FLTINV;
+
+	/* Overflow */
+	else if ((fpscr & FPSCR_OE) && (fpscr & FPSCR_OX))
+		info->si_code = FPE_FLTOVF;
+
+	/* Underflow */
+	else if ((fpscr & FPSCR_UE) && (fpscr & FPSCR_UX))
+		info->si_code = FPE_FLTUND;
+
+	/* Divide by zero */
+	else if ((fpscr & FPSCR_ZE) && (fpscr & FPSCR_ZX))
+		info->si_code = FPE_FLTDIV;
+
+	/* Inexact result */
+	else if ((fpscr & FPSCR_XE) && (fpscr & FPSCR_XX))
+		info->si_code = FPE_FLTRES;
+
+	else
+		info->si_code = 0;
+
+	info->si_signo = SIGFPE;
+	info->si_errno = 0;
+	info->si_addr = (void *)regs->nip;
+	_exception(SIGFPE, info, regs);
 }
 
 void
 ProgramCheckException(struct pt_regs *regs)
 {
+	siginfo_t info;
+
 	if (regs->msr & 0x100000) {
 		/* IEEE FP exception */
-		_exception(SIGFPE, regs);
+
+		parse_fpe(&info, regs);
+	} else if (regs->msr & 0x40000) {
+		/* Privileged instruction */
+
+		info.si_signo = SIGILL;
+		info.si_errno = 0;
+		info.si_code = ILL_PRVOPC;
+		info.si_addr = (void *)regs->nip;
+		_exception(SIGILL, &info, regs);
 	} else if (regs->msr & 0x20000) {
 		/* trap exception */
+
 #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
 		if (debugger_bpt(regs))
 			return;
@@ -277,16 +364,29 @@
 		if (kdb(KDB_REASON_BREAK, 0, regs))
 			return;
 #endif
-		_exception(SIGTRAP, regs);
+		info.si_signo = SIGTRAP;
+		info.si_errno = 0;
+		info.si_code = TRAP_BRKPT;
+		info.si_addr = (void *)regs->nip;
+		_exception(SIGTRAP, &info, regs);
 	} else {
-		_exception(SIGILL, regs);
+		/* Illegal instruction */
+
+		info.si_signo = SIGILL;
+		info.si_errno = 0;
+		info.si_code = ILL_ILLTRP;
+		info.si_addr = (void *)regs->nip;
+		_exception(SIGILL, &info, regs);
 	}
 }
 
 void
 SingleStepException(struct pt_regs *regs)
 {
+	siginfo_t info;
+
 	regs->msr &= ~MSR_SE;  /* Turn off 'trace' bit */
+
 #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
 	if (debugger_sstep(regs))
 		return;
@@ -295,13 +395,19 @@
 	if (kdb(KDB_REASON_DEBUG, 0, regs))
 		return;
 #endif
-	_exception(SIGTRAP, regs);	
+
+	info.si_signo = SIGTRAP;
+	info.si_errno = 0;
+	info.si_code = TRAP_TRACE;
+	info.si_addr = (void *)regs->nip;
+	_exception(SIGTRAP, &info, regs);	
 }
 
 void
 AlignmentException(struct pt_regs *regs)
 {
 	int fixed;
+	siginfo_t info;
 
 	fixed = fix_alignment(regs);
 	if (fixed == 1) {
@@ -311,15 +417,28 @@
 		regs->nip += 4;	/* skip over emulated instruction */
 		return;
 	}
+	
+	/* Operand address was bad */
 	if (fixed == -EFAULT) {
-		/* fixed == -EFAULT means the operand address was bad */
-		if (user_mode(regs))
-			force_sig(SIGSEGV, current);
-		else
+		if (user_mode(regs)) {
+			info.si_signo = SIGSEGV;
+			info.si_errno = 0;
+			info.si_code = SEGV_MAPERR;
+			info.si_addr = (void *)regs->dar;
+			force_sig_info(SIGSEGV, &info, current);
+		} else {
+			/* Search exception table */
 			bad_page_fault(regs, regs->dar);
+		}
+
 		return;
 	}
-	_exception(SIGBUS, regs);	
+
+	info.si_signo = SIGBUS;
+	info.si_errno = 0;
+	info.si_code = BUS_ADRALN;
+	info.si_addr = (void *)regs->nip;
+	_exception(SIGBUS, &info, regs);
 }
 
 void __init trap_init(void)
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/udbg.c linux-2.4.21-pre4/arch/ppc64/kernel/udbg.c
--- linux-2.4.21-pre3/arch/ppc64/kernel/udbg.c	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/udbg.c	Tue Jan 28 19:44:29 2003
@@ -82,7 +82,7 @@
 				/* wait for idle */;
 			udbg_comport->thr = '\r'; eieio();
 		}
-	} else if (naca->platform == PLATFORM_ISERIES_LPAR) {
+	} else if (systemcfg->platform == PLATFORM_ISERIES_LPAR) {
 		/* ToDo: switch this via ppc_md */
 		printk("%c", c);
 	}
@@ -119,8 +119,6 @@
 		if (s && *s != '\0') {
 			while ((c = *s++) != '\0')
 				ppc_md.udbg_putc(c);
-		} else {
-			udbg_puts("NULL");
 		}
 	} else {
 		printk("%s", s);
@@ -138,8 +136,7 @@
 		while ( (( c = *s++ ) != '\0') && (remain-- > 0)) {
 			ppc_md.udbg_putc(c);
 		}
-	} else
-		udbg_puts("NULL");
+	}
 	return n - remain;
 }
 
@@ -182,7 +179,7 @@
 void
 udbg_printSP(const char *s)
 {
-	if (naca->platform == PLATFORM_PSERIES) {
+	if (systemcfg->platform == PLATFORM_PSERIES) {
 		unsigned long sp;
 		asm("mr %0,1" : "=r" (sp) :);
 		if (s)
diff -urN linux-2.4.21-pre3/arch/ppc64/kernel/xics.c linux-2.4.21-pre4/arch/ppc64/kernel/xics.c
--- linux-2.4.21-pre3/arch/ppc64/kernel/xics.c	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/kernel/xics.c	Tue Jan 28 19:44:29 2003
@@ -88,6 +88,7 @@
 /* RTAS service tokens */
 int ibm_get_xive;
 int ibm_set_xive;
+int ibm_int_on;
 int ibm_int_off;
 
 struct xics_interrupt_node {
@@ -159,6 +160,14 @@
 		       irq, call_status, status);
 		return;
 	}
+	/* Now unmask the interrupt (often a no-op) */
+	call_status = rtas_call(ibm_int_on, 1, 1, (unsigned long*)&status, 
+				irq);
+	if( call_status != 0 ) {
+		printk("xics_disable_irq on: irq=%x: rtas_call failed, retn=%lx\n",
+		       irq, call_status);
+		return;
+	}
 }
 
 void
@@ -289,6 +298,7 @@
 
 	ibm_get_xive = rtas_token("ibm,get-xive");
 	ibm_set_xive = rtas_token("ibm,set-xive");
+	ibm_int_on  = rtas_token("ibm,int-on");
 	ibm_int_off = rtas_token("ibm,int-off");
 
 	np = find_type_devices("PowerPC-External-Interrupt-Presentation");
@@ -362,9 +372,9 @@
 		xics_irq_8259_cascade = virt_irq_create_mapping(xics_irq_8259_cascade_real);
 	}
 
-	if (naca->platform == PLATFORM_PSERIES) {
+	if (systemcfg->platform == PLATFORM_PSERIES) {
 #ifdef CONFIG_SMP
-		for (i = 0; i < naca->processorCount; ++i) {
+		for (i = 0; i < systemcfg->processorCount; ++i) {
 			xics_info.per_cpu[i] =
 			  __ioremap((ulong)inodes[get_hard_smp_processor_id(i)].addr, 
 				  (ulong)inodes[get_hard_smp_processor_id(i)].size, _PAGE_NO_CACHE);
@@ -376,7 +386,7 @@
 	/* actually iSeries does not use any of xics...but it has link dependencies
 	 * for now, except this new one...
 	 */
-	} else if (naca->platform == PLATFORM_PSERIES_LPAR) {
+	} else if (systemcfg->platform == PLATFORM_PSERIES_LPAR) {
 		ops = &pSeriesLP_ops;
 #endif
 	}
diff -urN linux-2.4.21-pre3/arch/ppc64/lib/Makefile linux-2.4.21-pre4/arch/ppc64/lib/Makefile
--- linux-2.4.21-pre3/arch/ppc64/lib/Makefile	Fri Aug  2 17:39:43 2002
+++ linux-2.4.21-pre4/arch/ppc64/lib/Makefile	Tue Jan 28 19:44:29 2003
@@ -6,6 +6,9 @@
 
 O_TARGET = lib.o
 
-obj-y           := checksum.o dec_and_lock.o string.o strcase.o
+export-objs     := dec_and_lock.o
+
+obj-y           := checksum.o dec_and_lock.o string.o strcase.o copypage.o \
+		   memcpy.o copyuser.o
 
 include $(TOPDIR)/Rules.make
diff -urN linux-2.4.21-pre3/arch/ppc64/lib/copypage.S linux-2.4.21-pre4/arch/ppc64/lib/copypage.S
--- linux-2.4.21-pre3/arch/ppc64/lib/copypage.S	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/arch/ppc64/lib/copypage.S	Tue Jan 28 19:44:29 2003
@@ -0,0 +1,121 @@
+/*
+ * arch/ppc64/lib/copypage.S
+ *
+ * Copyright (C) 2002 Paul Mackerras, 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.
+ */
+#include <asm/processor.h>
+#include <asm/ppc_asm.tmpl>
+
+_GLOBAL(copy_page)
+	std	r31,-8(1)
+	std	r30,-16(1)
+	std	r29,-24(1)
+	std	r28,-32(1)
+	std	r27,-40(1)
+	std	r26,-48(1)
+	std	r25,-56(1)
+	std	r24,-64(1)
+	std	r23,-72(1)
+	std	r22,-80(1)
+	std	r21,-88(1)
+	std	r20,-96(1)
+	li	r5,4096/32 - 1
+	addi	r3,r3,-8
+	li	r12,5
+0:	addi	r5,r5,-24
+	mtctr	r12
+	ld	r22,640(4)
+	ld	r21,512(4)
+	ld	r20,384(4)
+	ld	r11,256(4)
+	ld	r9,128(4)
+	ld	r7,0(4)
+	ld	r25,648(4)
+	ld	r24,520(4)
+	ld	r23,392(4)
+	ld	r10,264(4)
+	ld	r8,136(4)
+	ldu	r6,8(4)
+	cmpwi	r5,24
+1:	std	r22,648(3)
+	std	r21,520(3)
+	std	r20,392(3)
+	std	r11,264(3)
+	std	r9,136(3)
+	std	r7,8(3)
+	ld	r28,648(4)
+	ld	r27,520(4)
+	ld	r26,392(4)
+	ld	r31,264(4)
+	ld	r30,136(4)
+	ld	r29,8(4)
+	std	r25,656(3)
+	std	r24,528(3)
+	std	r23,400(3)
+	std	r10,272(3)
+	std	r8,144(3)
+	std	r6,16(3)
+	ld	r22,656(4)
+	ld	r21,528(4)
+	ld	r20,400(4)
+	ld	r11,272(4)
+	ld	r9,144(4)
+	ld	r7,16(4)
+	std	r28,664(3)
+	std	r27,536(3)
+	std	r26,408(3)
+	std	r31,280(3)
+	std	r30,152(3)
+	stdu	r29,24(3)
+	ld	r25,664(4)
+	ld	r24,536(4)
+	ld	r23,408(4)
+	ld	r10,280(4)
+	ld	r8,152(4)
+	ldu	r6,24(4)
+	bdnz	1b
+	std	r22,648(3)
+	std	r21,520(3)
+	std	r20,392(3)
+	std	r11,264(3)
+	std	r9,136(3)
+	std	r7,8(3)
+	addi	r4,r4,640
+	addi	r3,r3,648
+	bge	0b
+	mtctr	r5
+	ld	r7,0(4)
+	ld	r8,8(4)
+	ldu	r9,16(4)
+3:	ld	r10,8(4)
+	std	r7,8(3)
+	ld	r7,16(4)
+	std	r8,16(3)
+	ld	r8,24(4)
+	std	r9,24(3)
+	ldu	r9,32(4)
+	stdu	r10,32(3)
+	bdnz	3b
+4:	ld	r10,8(4)
+	std	r7,8(3)
+	std	r8,16(3)
+	std	r9,24(3)
+	std	r10,32(3)
+9:	ld	r20,-96(1)
+	ld	r21,-88(1)
+	ld	r22,-80(1)
+	ld	r23,-72(1)
+	ld	r24,-64(1)
+	ld	r25,-56(1)
+	ld	r26,-48(1)
+	ld	r27,-40(1)
+	ld	r28,-32(1)
+	ld	r29,-24(1)
+	ld	r30,-16(1)
+	ld	r31,-8(1)
+	blr
diff -urN linux-2.4.21-pre3/arch/ppc64/lib/copyuser.S linux-2.4.21-pre4/arch/ppc64/lib/copyuser.S
--- linux-2.4.21-pre3/arch/ppc64/lib/copyuser.S	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/arch/ppc64/lib/copyuser.S	Tue Jan 28 19:44:29 2003
@@ -0,0 +1,564 @@
+/*
+ * arch/ppc64/lib/copyuser.S
+ *
+ * Copyright (C) 2002 Paul Mackerras, 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.
+ */
+#include <asm/processor.h>
+#include <asm/ppc_asm.tmpl>
+
+	.align	7
+_GLOBAL(__copy_tofrom_user)
+	/* first check for a whole page copy on a page boundary */
+	cmpldi	cr1,r5,16
+	cmpdi	cr6,r5,4096
+	or	r0,r3,r4
+	neg	r6,r3		/* LS 3 bits = # bytes to 8-byte dest bdry */
+	andi.	r0,r0,4095
+	std	r3,-24(r1)
+	crand	cr0*4+2,cr0*4+2,cr6*4+2
+	std	r4,-16(r1)
+	std	r5,-8(r1)
+	dcbt	0,r4
+	beq	.Lcopy_page
+	andi.	r6,r6,7
+	mtcrf	0x01,r5
+	blt	cr1,.Lshort_copy
+	bne	.Ldst_unaligned
+.Ldst_aligned:
+	andi.	r0,r4,7
+	addi	r3,r3,-16
+	bne	.Lsrc_unaligned
+	srdi	r7,r5,4
+20:	ld	r9,0(r4)
+	addi	r4,r4,-8
+	mtctr	r7
+	andi.	r5,r5,7
+	bf	cr7*4+0,22f
+	addi	r3,r3,8
+	addi	r4,r4,8
+	mr	r8,r9
+	blt	cr1,72f
+21:	ld	r9,8(r4)
+70:	std	r8,8(r3)
+22:	ldu	r8,16(r4)
+71:	stdu	r9,16(r3)
+	bdnz	21b
+72:	std	r8,8(r3)
+	beq+	3f
+	addi	r3,r3,16
+23:	ld	r9,8(r4)
+.Ldo_tail:
+	bf	cr7*4+1,1f
+	rotldi	r9,r9,32
+73:	stw	r9,0(r3)
+	addi	r3,r3,4
+1:	bf	cr7*4+2,2f
+	rotldi	r9,r9,16
+74:	sth	r9,0(r3)
+	addi	r3,r3,2
+2:	bf	cr7*4+3,3f
+	rotldi	r9,r9,8
+75:	stb	r9,0(r3)
+3:	li	r3,0
+	blr
+
+.Lsrc_unaligned:
+	srdi	r6,r5,3
+	addi	r5,r5,-16
+	subf	r4,r0,r4
+	srdi	r7,r5,4
+	sldi	r10,r0,3
+	cmpldi	cr6,r6,3
+	andi.	r5,r5,7
+	mtctr	r7
+	subfic	r11,r10,64
+	add	r5,r5,r0
+	bt	cr7*4+0,28f
+
+24:	ld	r9,0(r4)	/* 3+2n loads, 2+2n stores */
+25:	ld	r0,8(r4)
+	sld	r6,r9,r10
+26:	ldu	r9,16(r4)
+	srd	r7,r0,r11
+	sld	r8,r0,r10
+	or	r7,r7,r6
+	blt	cr6,79f
+27:	ld	r0,8(r4)
+	b	2f
+
+28:	ld	r0,0(r4)	/* 4+2n loads, 3+2n stores */
+29:	ldu	r9,8(r4)
+	sld	r8,r0,r10
+	addi	r3,r3,-8
+	blt	cr6,5f
+30:	ld	r0,8(r4)
+	srd	r12,r9,r11
+	sld	r6,r9,r10
+31:	ldu	r9,16(r4)
+	or	r12,r8,r12
+	srd	r7,r0,r11
+	sld	r8,r0,r10
+	addi	r3,r3,16
+	beq	cr6,78f
+
+1:	or	r7,r7,r6
+32:	ld	r0,8(r4)
+76:	std	r12,8(r3)
+2:	srd	r12,r9,r11
+	sld	r6,r9,r10
+33:	ldu	r9,16(r4)
+	or	r12,r8,r12
+77:	stdu	r7,16(r3)
+	srd	r7,r0,r11
+	sld	r8,r0,r10
+	bdnz	1b
+
+78:	std	r12,8(r3)
+	or	r7,r7,r6
+79:	std	r7,16(r3)
+5:	srd	r12,r9,r11
+	or	r12,r8,r12
+80:	std	r12,24(r3)
+	bne	6f
+	li	r3,0
+	blr
+6:	cmpwi	cr1,r5,8
+	addi	r3,r3,32
+	sld	r9,r9,r10
+	blt	cr1,.Ldo_tail
+34:	ld	r0,8(r4)
+	srd	r7,r0,r11
+	or	r9,r7,r9
+	b	.Ldo_tail
+
+.Ldst_unaligned:
+	mtcrf	0x01,r6		/* put #bytes to 8B bdry into cr7 */
+	subf	r5,r6,r5
+	li	r7,0
+	cmpldi	r1,r5,16
+	bf	cr7*4+3,1f
+35:	lbz	r0,0(r4)
+81:	stb	r0,0(r3)
+	addi	r7,r7,1
+1:	bf	cr7*4+2,2f
+36:	lhzx	r0,r7,r4
+82:	sthx	r0,r7,r3
+	addi	r7,r7,2
+2:	bf	cr7*4+1,3f
+37:	lwzx	r0,r7,r4
+83:	stwx	r0,r7,r3
+3:	mtcrf	0x01,r5
+	add	r4,r6,r4
+	add	r3,r6,r3
+	b	.Ldst_aligned
+
+.Lshort_copy:
+	bf	cr7*4+0,1f
+38:	lwz	r0,0(r4)
+39:	lwz	r9,4(r4)
+	addi	r4,r4,8
+84:	stw	r0,0(r3)
+85:	stw	r9,4(r3)
+	addi	r3,r3,8
+1:	bf	cr7*4+1,2f
+40:	lwz	r0,0(r4)
+	addi	r4,r4,4
+86:	stw	r0,0(r3)
+	addi	r3,r3,4
+2:	bf	cr7*4+2,3f
+41:	lhz	r0,0(r4)
+	addi	r4,r4,2
+87:	sth	r0,0(r3)
+	addi	r3,r3,2
+3:	bf	cr7*4+3,4f
+42:	lbz	r0,0(r4)
+88:	stb	r0,0(r3)
+4:	li	r3,0
+	blr
+
+/*
+ * exception handlers follow
+ * we have to return the number of bytes not copied
+ * for an exception on a load, we set the rest of the destination to 0
+ */
+
+136:
+137:
+	add	r3,r3,r7
+	b	1f
+130:
+131:
+	addi	r3,r3,8
+120:
+122:
+124:
+125:
+126:
+127:
+128:
+129:
+133:
+	addi	r3,r3,8
+121:
+132:
+	addi	r3,r3,8
+123:
+134:
+135:
+138:
+139:
+140:
+141:
+142:
+
+/*
+ * here we have had a fault on a load and r3 points to the first
+ * unmodified byte of the destination
+ */
+1:	ld	r6,-24(r1)
+	ld	r4,-16(r1)
+	ld	r5,-8(r1)
+	subf	r6,r6,r3
+	add	r4,r4,r6
+	subf	r5,r6,r5	/* #bytes left to go */
+
+/*
+ * first see if we can copy any more bytes before hitting another exception
+ */
+	mtctr	r5
+43:	lbz	r0,0(r4)
+	addi	r4,r4,1
+89:	stb	r0,0(r3)
+	addi	r3,r3,1
+	bdnz	43b
+	li	r3,0		/* huh? all copied successfully this time? */
+	blr
+
+/*
+ * here we have trapped again, need to clear ctr bytes starting at r3
+ */
+143:	mfctr	r5
+	li	r0,0
+	mr	r4,r3
+	mr	r3,r5		/* return the number of bytes not copied */
+1:	andi.	r9,r4,7
+	beq	3f
+90:	stb	r0,0(r4)
+	addic.	r5,r5,-1
+	addi	r4,r4,1
+	bne	1b
+	blr
+3:	cmpldi	cr1,r5,8
+	srdi	r9,r5,3
+	andi.	r5,r5,7
+	blt	cr1,93f
+	mtctr	r9
+91:	std	r0,0(r4)
+	addi	r4,r4,8
+	bdnz	91b
+93:	beqlr
+	mtctr	r5	
+92:	stb	r0,0(r4)
+	addi	r4,r4,1
+	bdnz	92b
+	blr
+
+/*
+ * exception handlers for stores: we just need to work
+ * out how many bytes weren't copied
+ */
+182:
+183:
+	add	r3,r3,r7
+	b	1f
+180:
+	addi	r3,r3,8
+171:
+177:
+	addi	r3,r3,8
+170:
+172:
+176:
+178:
+	addi	r3,r3,4
+185:
+	addi	r3,r3,4
+173:
+174:
+175:
+179:
+181:
+184:
+186:
+187:
+188:
+189:	
+1:
+	ld	r6,-24(r1)
+	ld	r5,-8(r1)
+	add	r6,r6,r5
+	subf	r3,r3,r6	/* #bytes not copied */
+190:
+191:
+192:
+	blr			/* #bytes not copied in r3 */
+
+	.section __ex_table,"a"
+	.align	3
+	.llong	20b,120b
+	.llong	21b,121b
+	.llong	70b,170b
+	.llong	22b,122b
+	.llong	71b,171b
+	.llong	72b,172b
+	.llong	23b,123b
+	.llong	73b,173b
+	.llong	74b,174b
+	.llong	75b,175b
+	.llong	24b,124b
+	.llong	25b,125b
+	.llong	26b,126b
+	.llong	27b,127b
+	.llong	28b,128b
+	.llong	29b,129b
+	.llong	30b,130b
+	.llong	31b,131b
+	.llong	32b,132b
+	.llong	76b,176b
+	.llong	33b,133b
+	.llong	77b,177b
+	.llong	78b,178b
+	.llong	79b,179b
+	.llong	80b,180b
+	.llong	34b,134b
+	.llong	35b,135b
+	.llong	81b,181b
+	.llong	36b,136b
+	.llong	82b,182b
+	.llong	37b,137b
+	.llong	83b,183b
+	.llong	38b,138b
+	.llong	39b,139b
+	.llong	84b,184b
+	.llong	85b,185b
+	.llong	40b,140b
+	.llong	86b,186b
+	.llong	41b,141b
+	.llong	87b,187b
+	.llong	42b,142b
+	.llong	88b,188b
+	.llong	43b,143b
+	.llong	89b,189b
+	.llong	90b,190b
+	.llong	91b,191b
+	.llong	92b,192b
+	
+	.text
+
+/*
+ * Routine to copy a whole page of data, optimized for POWER4.
+ * On POWER4 it is more than 50% faster than the simple loop
+ * above (following the .Ldst_aligned label) but it runs slightly
+ * slower on POWER3.
+ */
+.Lcopy_page:
+	std	r31,-32(1)
+	std	r30,-40(1)
+	std	r29,-48(1)
+	std	r28,-56(1)
+	std	r27,-64(1)
+	std	r26,-72(1)
+	std	r25,-80(1)
+	std	r24,-88(1)
+	std	r23,-96(1)
+	std	r22,-104(1)
+	std	r21,-112(1)
+	std	r20,-120(1)
+	li	r5,4096/32 - 1
+	addi	r3,r3,-8
+	li	r0,5
+0:	addi	r5,r5,-24
+	mtctr	r0
+20:	ld	r22,640(4)
+21:	ld	r21,512(4)
+22:	ld	r20,384(4)
+23:	ld	r11,256(4)
+24:	ld	r9,128(4)
+25:	ld	r7,0(4)
+26:	ld	r25,648(4)
+27:	ld	r24,520(4)
+28:	ld	r23,392(4)
+29:	ld	r10,264(4)
+30:	ld	r8,136(4)
+31:	ldu	r6,8(4)
+	cmpwi	r5,24
+1:
+32:	std	r22,648(3)
+33:	std	r21,520(3)
+34:	std	r20,392(3)
+35:	std	r11,264(3)
+36:	std	r9,136(3)
+37:	std	r7,8(3)
+38:	ld	r28,648(4)
+39:	ld	r27,520(4)
+40:	ld	r26,392(4)
+41:	ld	r31,264(4)
+42:	ld	r30,136(4)
+43:	ld	r29,8(4)
+44:	std	r25,656(3)
+45:	std	r24,528(3)
+46:	std	r23,400(3)
+47:	std	r10,272(3)
+48:	std	r8,144(3)
+49:	std	r6,16(3)
+50:	ld	r22,656(4)
+51:	ld	r21,528(4)
+52:	ld	r20,400(4)
+53:	ld	r11,272(4)
+54:	ld	r9,144(4)
+55:	ld	r7,16(4)
+56:	std	r28,664(3)
+57:	std	r27,536(3)
+58:	std	r26,408(3)
+59:	std	r31,280(3)
+60:	std	r30,152(3)
+61:	stdu	r29,24(3)
+62:	ld	r25,664(4)
+63:	ld	r24,536(4)
+64:	ld	r23,408(4)
+65:	ld	r10,280(4)
+66:	ld	r8,152(4)
+67:	ldu	r6,24(4)
+	bdnz	1b
+68:	std	r22,648(3)
+69:	std	r21,520(3)
+70:	std	r20,392(3)
+71:	std	r11,264(3)
+72:	std	r9,136(3)
+73:	std	r7,8(3)
+74:	addi	r4,r4,640
+75:	addi	r3,r3,648
+	bge	0b
+	mtctr	r5
+76:	ld	r7,0(4)
+77:	ld	r8,8(4)
+78:	ldu	r9,16(4)
+3:
+79:	ld	r10,8(4)
+80:	std	r7,8(3)
+81:	ld	r7,16(4)
+82:	std	r8,16(3)
+83:	ld	r8,24(4)
+84:	std	r9,24(3)
+85:	ldu	r9,32(4)
+86:	stdu	r10,32(3)
+	bdnz	3b
+4:
+87:	ld	r10,8(4)
+88:	std	r7,8(3)
+89:	std	r8,16(3)
+90:	std	r9,24(3)
+91:	std	r10,32(3)
+9:	ld	r20,-120(1)
+	ld	r21,-112(1)
+	ld	r22,-104(1)
+	ld	r23,-96(1)
+	ld	r24,-88(1)
+	ld	r25,-80(1)
+	ld	r26,-72(1)
+	ld	r27,-64(1)
+	ld	r28,-56(1)
+	ld	r29,-48(1)
+	ld	r30,-40(1)
+	ld	r31,-32(1)
+	li	r3,0
+	blr
+
+/*
+ * on an exception, reset to the beginning and jump back into the
+ * standard __copy_tofrom_user
+ */
+100:	ld	r3,-24(r1)
+	ld	r4,-24(r1)
+	li	r5,4096
+	b	.Ldst_aligned
+
+	.section __ex_table,"a"
+	.align	3
+	.llong	20b,100b
+	.llong	21b,100b
+	.llong	22b,100b
+	.llong	23b,100b
+	.llong	24b,100b
+	.llong	25b,100b
+	.llong	26b,100b
+	.llong	27b,100b
+	.llong	28b,100b
+	.llong	29b,100b
+	.llong	30b,100b
+	.llong	31b,100b
+	.llong	32b,100b
+	.llong	33b,100b
+	.llong	34b,100b
+	.llong	35b,100b
+	.llong	36b,100b
+	.llong	37b,100b
+	.llong	38b,100b
+	.llong	39b,100b
+	.llong	40b,100b
+	.llong	41b,100b
+	.llong	42b,100b
+	.llong	43b,100b
+	.llong	44b,100b
+	.llong	45b,100b
+	.llong	46b,100b
+	.llong	47b,100b
+	.llong	48b,100b
+	.llong	49b,100b
+	.llong	50b,100b
+	.llong	51b,100b
+	.llong	52b,100b
+	.llong	53b,100b
+	.llong	54b,100b
+	.llong	55b,100b
+	.llong	56b,100b
+	.llong	57b,100b
+	.llong	58b,100b
+	.llong	59b,100b
+	.llong	60b,100b
+	.llong	61b,100b
+	.llong	62b,100b
+	.llong	63b,100b
+	.llong	64b,100b
+	.llong	65b,100b
+	.llong	66b,100b
+	.llong	67b,100b
+	.llong	68b,100b
+	.llong	69b,100b
+	.llong	70b,100b
+	.llong	71b,100b
+	.llong	72b,100b
+	.llong	73b,100b
+	.llong	74b,100b
+	.llong	75b,100b
+	.llong	76b,100b
+	.llong	77b,100b
+	.llong	78b,100b
+	.llong	79b,100b
+	.llong	80b,100b
+	.llong	81b,100b
+	.llong	82b,100b
+	.llong	83b,100b
+	.llong	84b,100b
+	.llong	85b,100b
+	.llong	86b,100b
+	.llong	87b,100b
+	.llong	88b,100b
+	.llong	89b,100b
+	.llong	90b,100b
+	.llong	91b,100b
diff -urN linux-2.4.21-pre3/arch/ppc64/lib/dec_and_lock.c linux-2.4.21-pre4/arch/ppc64/lib/dec_and_lock.c
--- linux-2.4.21-pre3/arch/ppc64/lib/dec_and_lock.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.21-pre4/arch/ppc64/lib/dec_and_lock.c	Tue Jan 28 19:44:29 2003
@@ -7,32 +7,48 @@
  * 2 of the License, or (at your option) any later version.
  */
 
+#include <linux/module.h>
 #include <linux/spinlock.h>
-#include <asm/system.h>
 #include <asm/atomic.h>
+#include <asm/system.h>
 
+/*
+ * This is an implementation of the notion of "decrement a
+ * reference count, and return locked if it decremented to zero".
+ *
+ * This implementation can be used on any architecture that
+ * has a cmpxchg, and where atomic->value is an int holding
+ * the value of the atomic (i.e. the high bits aren't used
+ * for a lock or anything like that).
+ *
+ * N.B. ATOMIC_DEC_AND_LOCK gets defined in include/linux/spinlock.h
+ * if spinlocks are empty and thus atomic_dec_and_lock is defined
+ * to be atomic_dec_and_test - in that case we don't need it
+ * defined here as well.
+ */
+
+#ifndef ATOMIC_DEC_AND_LOCK
 int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
 {
 	int counter;
 	int newcount;
 
-repeat:
-	counter = atomic_read(atomic);
-	newcount = counter-1;
-
-	if (!newcount)
-		goto slow_path;
+	for (;;) {
+		counter = atomic_read(atomic);
+		newcount = counter - 1;
+		if (!newcount)
+			break;		/* do it the slow way */
+
+		newcount = cmpxchg(&atomic->counter, counter, newcount);
+		if (newcount == counter)
+			return 0;
+	}
 
-	newcount = cmpxchg(&atomic->counter, counter, newcount);
-
-	if (newcount != counter)
-		goto repeat;
-	return 0;
-
-slow_path:
 	spin_lock(lock);
 	if (atomic_dec_and_test(atomic))
 		return 1;
 	spin_unlock(lock);
 	return 0;
 }
+
+#endif /* ATOMIC_DEC_AND_LOCK */
diff -urN linux-2.4.21-pre3/arch/ppc64/lib/memcpy.S linux-2.4.21-pre4/arch/ppc64/lib/memcpy.S
--- linux-2.4.21-pre3/arch/ppc64/lib/memcpy.S	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/arch/ppc64/lib/memcpy.S	Tue Jan 28 19:44:29 2003
@@ -0,0 +1,172 @@
+/*
+ * arch/ppc64/lib/memcpy.S
+ *
+ * Copyright (C) 2002 Paul Mackerras, 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.
+ */
+#include <asm/processor.h>
+#include <asm/ppc_asm.tmpl>
+
+	.align	7
+_GLOBAL(memcpy)
+	mtcrf	0x01,r5
+	cmpldi	cr1,r5,16
+	neg	r6,r3		# LS 3 bits = # bytes to 8-byte dest bdry
+	andi.	r6,r6,7
+	dcbt	0,r4
+	blt	cr1,.Lshort_copy
+	bne	.Ldst_unaligned
+.Ldst_aligned:
+	andi.	r0,r4,7
+	addi	r3,r3,-16
+	bne	.Lsrc_unaligned
+	srdi	r7,r5,4
+	ld	r9,0(r4)
+	addi	r4,r4,-8
+	mtctr	r7
+	andi.	r5,r5,7
+	bf	cr7*4+0,2f
+	addi	r3,r3,8
+	addi	r4,r4,8
+	mr	r8,r9
+	blt	cr1,3f
+1:	ld	r9,8(r4)
+	std	r8,8(r3)
+2:	ldu	r8,16(r4)
+	stdu	r9,16(r3)
+	bdnz	1b
+3:	std	r8,8(r3)
+	beqlr
+	addi	r3,r3,16
+	ld	r9,8(r4)
+.Ldo_tail:
+	bf	cr7*4+1,1f
+	rotldi	r9,r9,32
+	stw	r9,0(r3)
+	addi	r3,r3,4
+1:	bf	cr7*4+2,2f
+	rotldi	r9,r9,16
+	sth	r9,0(r3)
+	addi	r3,r3,2
+2:	bf	cr7*4+3,3f
+	rotldi	r9,r9,8
+	stb	r9,0(r3)
+3:	blr
+
+.Lsrc_unaligned:
+	srdi	r6,r5,3
+	addi	r5,r5,-16
+	subf	r4,r0,r4
+	srdi	r7,r5,4
+	sldi	r10,r0,3
+	cmpdi	cr6,r6,3
+	andi.	r5,r5,7
+	mtctr	r7
+	subfic	r11,r10,64
+	add	r5,r5,r0
+
+	bt	cr7*4+0,0f
+
+	ld	r9,0(r4)	# 3+2n loads, 2+2n stores
+	ld	r0,8(r4)
+	sld	r6,r9,r10
+	ldu	r9,16(r4)
+	srd	r7,r0,r11
+	sld	r8,r0,r10
+	or	r7,r7,r6
+	blt	cr6,4f
+	ld	r0,8(r4)
+	# s1<< in r8, d0=(s0<<|s1>>) in r7, s3 in r0, s2 in r9, nix in r6 & r12
+	b	2f
+
+0:	ld	r0,0(r4)	# 4+2n loads, 3+2n stores
+	ldu	r9,8(r4)
+	sld	r8,r0,r10
+	addi	r3,r3,-8
+	blt	cr6,5f
+	ld	r0,8(r4)
+	srd	r12,r9,r11
+	sld	r6,r9,r10
+	ldu	r9,16(r4)
+	or	r12,r8,r12
+	srd	r7,r0,r11
+	sld	r8,r0,r10
+	addi	r3,r3,16
+	beq	cr6,3f
+
+	# d0=(s0<<|s1>>) in r12, s1<< in r6, s2>> in r7, s2<< in r8, s3 in r9
+1:	or	r7,r7,r6
+	ld	r0,8(r4)
+	std	r12,8(r3)
+2:	srd	r12,r9,r11
+	sld	r6,r9,r10
+	ldu	r9,16(r4)
+	or	r12,r8,r12
+	stdu	r7,16(r3)
+	srd	r7,r0,r11
+	sld	r8,r0,r10
+	bdnz	1b
+
+3:	std	r12,8(r3)
+	or	r7,r7,r6
+4:	std	r7,16(r3)
+5:	srd	r12,r9,r11
+	or	r12,r8,r12
+	std	r12,24(r3)
+	beqlr
+	cmpwi	cr1,r5,8
+	addi	r3,r3,32
+	sld	r9,r9,r10
+	ble	cr1,.Ldo_tail
+	ld	r0,8(r4)
+	srd	r7,r0,r11
+	or	r9,r7,r9
+	b	.Ldo_tail
+
+.Ldst_unaligned:
+	mtcrf	0x01,r6		# put #bytes to 8B bdry into cr7
+	subf	r5,r6,r5
+	li	r7,0
+	cmpldi	r1,r5,16
+	bf	cr7*4+3,1f
+	lbz	r0,0(r4)
+	stb	r0,0(r3)
+	addi	r7,r7,1
+1:	bf	cr7*4+2,2f
+	lhzx	r0,r7,r4
+	sthx	r0,r7,r3
+	addi	r7,r7,2
+2:	bf	cr7*4+1,3f
+	lwzx	r0,r7,r4
+	stwx	r0,r7,r3
+3:	mtcrf	0x01,r5
+	add	r4,r6,r4
+	add	r3,r6,r3
+	b	.Ldst_aligned
+
+.Lshort_copy:
+	bf	cr7*4+0,1f
+	lwz	r0,0(r4)
+	lwz	r9,4(r4)
+	addi	r4,r4,8
+	stw	r0,0(r3)
+	stw	r9,4(r3)
+	addi	r3,r3,8
+1:	bf	cr7*4+1,2f
+	lwz	r0,0(r4)
+	addi	r4,r4,4
+	stw	r0,0(r3)
+	addi	r3,r3,4
+2:	bf	cr7*4+2,3f
+	lhz	r0,0(r4)
+	addi	r4,r4,2
+	sth	r0,0(r3)
+	addi	r3,r3,2
+3:	bf	cr7*4+3,4f
+	lbz	r0,0(r4)
+	stb	r0,0(r3)
+4:	blr
diff -urN linux-2.4.21-pre3/arch/ppc64/lib/string.S linux-2.4.21-pre4/arch/ppc64/lib/string.S
--- linux-2.4.21-pre3/arch/ppc64/lib/string.S	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/lib/string.S	Tue Jan 28 19:44:29 2003
@@ -12,61 +12,6 @@
 #include <asm/processor.h>
 #include <asm/errno.h>
 
-#define CACHE_LINE_SIZE		128
-#define LG_CACHE_LINE_SIZE	7
-#define MAX_COPY_PREFETCH	1
-
-#define COPY_16_BYTES		\
-	lwz	r7,4(r4);	\
-	lwz	r8,8(r4);	\
-	lwz	r9,12(r4);	\
-	lwzu	r10,16(r4);	\
-	stw	r7,4(r6);	\
-	stw	r8,8(r6);	\
-	stw	r9,12(r6);	\
-	stwu	r10,16(r6)
-
-#define COPY_16_BYTES_WITHEX(n)	\
-8 ## n ## 0:			\
-	lwz	r7,4(r4);	\
-8 ## n ## 1:			\
-	lwz	r8,8(r4);	\
-8 ## n ## 2:			\
-	lwz	r9,12(r4);	\
-8 ## n ## 3:			\
-	lwzu	r10,16(r4);	\
-8 ## n ## 4:			\
-	stw	r7,4(r6);	\
-8 ## n ## 5:			\
-	stw	r8,8(r6);	\
-8 ## n ## 6:			\
-	stw	r9,12(r6);	\
-8 ## n ## 7:			\
-	stwu	r10,16(r6)
-
-#define COPY_16_BYTES_EXCODE(n)			\
-9 ## n ## 0:					\
-	addi	r5,r5,-(16 * n);		\
-	b	104f;				\
-9 ## n ## 1:					\
-	addi	r5,r5,-(16 * n);		\
-	b	105f;				\
-.section __ex_table,"a";			\
-	.align	3;				\
-	.llong	8 ## n ## 0b,9 ## n ## 0b;	\
-	.llong	8 ## n ## 1b,9 ## n ## 0b;	\
-	.llong	8 ## n ## 2b,9 ## n ## 0b;	\
-	.llong	8 ## n ## 3b,9 ## n ## 0b;	\
-	.llong	8 ## n ## 4b,9 ## n ## 1b;	\
-	.llong	8 ## n ## 5b,9 ## n ## 1b;	\
-	.llong	8 ## n ## 6b,9 ## n ## 1b;	\
-	.llong	8 ## n ## 7b,9 ## n ## 1b;	\
-.text
-
-CACHELINE_BYTES = CACHE_LINE_SIZE
-LG_CACHELINE_BYTES = LG_CACHE_LINE_SIZE
-CACHELINE_MASK = (CACHE_LINE_SIZE-1)
-
 _GLOBAL(strcpy)
 	addi	r5,r3,-1
 	addi	r4,r4,-1
@@ -120,54 +65,6 @@
 	subf	r3,r3,r4
 	blr
 
-/*
- * Use dcbz on the complete cache lines in the destination
- * to set them to zero.  This requires that the destination
- * area is cacheable.  -- paulus
- */
-_GLOBAL(cacheable_memzero)
-	mr	r5,r4
-	li	r4,0
-	addi	r6,r3,-4
-	cmplwi	0,r5,4
-	blt	7f
-	stwu	r4,4(r6)
-	beqlr
-	andi.	r0,r6,3
-	add	r5,r0,r5
-	subf	r6,r0,r6
-	clrlwi	r7,r6,32-LG_CACHELINE_BYTES
-	add	r8,r7,r5
-	srwi	r9,r8,LG_CACHELINE_BYTES
-	addic.	r9,r9,-1	/* total number of complete cachelines */
-	ble	2f
-	xori	r0,r7,CACHELINE_MASK & ~3
-	srwi.	r0,r0,2
-	beq	3f
-	mtctr	r0
-4:	stwu	r4,4(r6)
-	bdnz	4b
-3:	mtctr	r9
-	li	r7,4
-10:	dcbz	r7,r6
-	addi	r6,r6,CACHELINE_BYTES
-	bdnz	10b
-	clrlwi	r5,r8,32-LG_CACHELINE_BYTES
-	addi	r5,r5,4
-2:	srwi	r0,r5,2
-	mtctr	r0
-	bdz	6f
-1:	stwu	r4,4(r6)
-	bdnz	1b
-6:	andi.	r5,r5,3
-7:	cmpwi	0,r5,0
-	beqlr
-	mtctr	r5
-	addi	r6,r6,3
-8:	stbu	r4,1(r6)
-	bdnz	8b
-	blr
-
 _GLOBAL(memset)
 	rlwimi	r4,r4,8,16,23
 	rlwimi	r4,r4,16,0,15
@@ -196,48 +93,7 @@
 _GLOBAL(memmove)
 	cmplw	0,r3,r4
 	bgt	.backwards_memcpy
-	/* fall through */
-
-_GLOBAL(memcpy)
-	srwi.	r7,r5,3
-	addi	r6,r3,-4
-	addi	r4,r4,-4
-	beq	2f			/* if less than 8 bytes to do */
-	andi.	r0,r6,3			/* get dest word aligned */
-	mtctr	r7
-	bne	5f
-1:	lwz	r7,4(r4)
-	lwzu	r8,8(r4)
-	stw	r7,4(r6)
-	stwu	r8,8(r6)
-	bdnz	1b
-	andi.	r5,r5,7
-2:	cmplwi	0,r5,4
-	blt	3f
-	lwzu	r0,4(r4)
-	addi	r5,r5,-4
-	stwu	r0,4(r6)
-3:	cmpwi	0,r5,0
-	beqlr
-	mtctr	r5
-	addi	r4,r4,3
-	addi	r6,r6,3
-4:	lbzu	r0,1(r4)
-	stbu	r0,1(r6)
-	bdnz	4b
-	blr
-5:	subfic	r0,r0,4
-	mtctr	r0
-6:	lbz	r7,4(r4)
-	addi	r4,r4,1
-	stb	r7,4(r6)
-	addi	r6,r6,1
-	bdnz	6b
-	subf	r5,r0,r5
-	rlwinm.	r7,r5,32-3,3,31
-	beq	2b
-	mtctr	r7
-	b	1b
+	b	.memcpy
 
 _GLOBAL(backwards_memcpy)
 	rlwinm.	r7,r5,32-3,3,31		/* r0 = r5 >> 3 */
@@ -301,195 +157,6 @@
 2:	li	r3,0
 	blr
 
-_GLOBAL(__copy_tofrom_user)
-	addi	r4,r4,-4
-	addi	r6,r3,-4
-	neg	r0,r3
-	andi.	r0,r0,CACHELINE_MASK	/* # bytes to start of cache line */
-	beq	58f
-
-	cmplw	0,r5,r0			/* is this more than total to do? */
-	blt	63f			/* if not much to do */
-	andi.	r8,r0,3			/* get it word-aligned first */
-	mtctr	r8
-	beq+	61f
-70:	lbz	r9,4(r4)		/* do some bytes */
-71:	stb	r9,4(r6)
-	addi	r4,r4,1
-	addi	r6,r6,1
-	bdnz	70b
-61:	subf	r5,r0,r5
-	srwi.	r0,r0,2
-	mtctr	r0
-	beq	58f
-72:	lwzu	r9,4(r4)		/* do some words */
-73:	stwu	r9,4(r6)
-	bdnz	72b
-
-58:	srwi.	r0,r5,LG_CACHELINE_BYTES /* # complete cachelines */
-	clrlwi	r5,r5,32-LG_CACHELINE_BYTES
-	li	r11,4
-	beq	63f
-
-	/* Here we decide how far ahead to prefetch the source */
-#if MAX_COPY_PREFETCH > 1
-	/* Heuristically, for large transfers we prefetch
-	   MAX_COPY_PREFETCH cachelines ahead.  For small transfers
-	   we prefetch 1 cacheline ahead. */
-	cmpwi	r0,MAX_COPY_PREFETCH
-	li	r7,1
-	li	r3,4
-	ble	111f
-	li	r7,MAX_COPY_PREFETCH
-111:	mtctr	r7
-112:	dcbt	r3,r4
-	addi	r3,r3,CACHELINE_BYTES
-	bdnz	112b
-#else /* MAX_COPY_PREFETCH == 1 */
-	li	r3,CACHELINE_BYTES + 4
-	dcbt	r11,r4
-#endif /* MAX_COPY_PREFETCH */
-
-	mtctr	r0
-	dcbt	r3,r4
-53:
-54:	dcbz	r11,r6
-/* had to move these to keep extable in order */
-	.section __ex_table,"a"
-	.align	3
-	.llong	70b,100f
-	.llong	71b,101f
-	.llong	72b,102f
-	.llong	73b,103f
-	.llong	54b,105f
-	.text
-/* the main body of the cacheline loop */
-	COPY_16_BYTES_WITHEX(0)
-#if CACHE_LINE_SIZE >= 32
-	COPY_16_BYTES_WITHEX(1)
-#if CACHE_LINE_SIZE >= 64
-	COPY_16_BYTES_WITHEX(2)
-	COPY_16_BYTES_WITHEX(3)
-#if CACHE_LINE_SIZE >= 128
-	COPY_16_BYTES_WITHEX(4)
-	COPY_16_BYTES_WITHEX(5)
-	COPY_16_BYTES_WITHEX(6)
-	COPY_16_BYTES_WITHEX(7)
-#endif
-#endif
-#endif
-	bdnz	53b
-
-63:	srwi.	r0,r5,2
-	mtctr	r0
-	beq	64f
-30:	lwzu	r0,4(r4)
-31:	stwu	r0,4(r6)
-	bdnz	30b
-
-64:	andi.	r0,r5,3
-	mtctr	r0
-	beq+	65f
-40:	lbz	r0,4(r4)
-41:	stb	r0,4(r6)
-	addi	r4,r4,1
-	addi	r6,r6,1
-	bdnz	40b
-65:	li	r3,0
-	blr
-
-/* read fault, initial single-byte copy */
-100:	li	r4,0
-	b	90f
-/* write fault, initial single-byte copy */
-101:	li	r4,1
-90:	subf	r5,r8,r5
-	li	r3,0
-	b	99f
-/* read fault, initial word copy */
-102:	li	r4,0
-	b	91f
-/* write fault, initial word copy */
-103:	li	r4,1
-91:	li	r3,2
-	b	99f
-
-/*
- * this stuff handles faults in the cacheline loop and branches to either
- * 104f (if in read part) or 105f (if in write part), after updating r5
- */
-	COPY_16_BYTES_EXCODE(0)
-#if CACHE_LINE_SIZE >= 32
-	COPY_16_BYTES_EXCODE(1)
-#if CACHE_LINE_SIZE >= 64
-	COPY_16_BYTES_EXCODE(2)
-	COPY_16_BYTES_EXCODE(3)
-#if CACHE_LINE_SIZE >= 128
-	COPY_16_BYTES_EXCODE(4)
-	COPY_16_BYTES_EXCODE(5)
-	COPY_16_BYTES_EXCODE(6)
-	COPY_16_BYTES_EXCODE(7)
-#endif
-#endif
-#endif
-
-/* read fault in cacheline loop */
-104:	li	r4,0
-	b	92f
-/* fault on dcbz (effectively a write fault) */
-/* or write fault in cacheline loop */
-105:	li	r4,1
-92:	li	r3,LG_CACHELINE_BYTES
-	b	99f
-/* read fault in final word loop */
-108:	li	r4,0
-	b	93f
-/* write fault in final word loop */
-109:	li	r4,1
-93:	andi.	r5,r5,3
-	li	r3,2
-	b	99f
-/* read fault in final byte loop */
-110:	li	r4,0
-	b	94f
-/* write fault in final byte loop */
-111:	li	r4,1
-94:	li	r5,0
-	li	r3,0
-/*
- * At this stage the number of bytes not copied is
- * r5 + (ctr << r3), and r4 is 0 for read or 1 for write.
- */
-99:	mfctr	r0
-	slw	r3,r0,r3
-	add	r3,r3,r5
-	cmpwi	0,r4,0
-	bne	120f
-/* for read fault, clear out the destination: r3 bytes starting at 4(r6) */
-	srwi.	r0,r3,2
-	li	r9,0
-	mtctr	r0
-	beq	113f
-112:	stwu	r9,4(r6)
-	bdnz	112b
-113:	andi.	r0,r3,3
-	mtctr	r0
-	beq	120f
-114:	stb	r9,4(r6)
-	addi	r6,r6,1
-	bdnz	114b
-120:	blr
-
-	.section __ex_table,"a"
-	.align	3
-	.llong	30b,108b
-	.llong	31b,109b
-	.llong	40b,110b
-	.llong	41b,111b
-	.llong	112b,120b
-	.llong	114b,120b
-	.text
-
 _GLOBAL(__clear_user)
 	addi	r6,r3,-4
 	li	r3,0
diff -urN linux-2.4.21-pre3/arch/ppc64/mm/extable.c linux-2.4.21-pre4/arch/ppc64/mm/extable.c
--- linux-2.4.21-pre3/arch/ppc64/mm/extable.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.21-pre4/arch/ppc64/mm/extable.c	Tue Jan 28 19:44:29 2003
@@ -1,5 +1,5 @@
 /*
- * linux/arch/ppc/mm/extable.c
+ * linux/arch/ppc64/mm/extable.c
  *
  * from linux/arch/i386/mm/extable.c
  *
@@ -9,54 +9,95 @@
  *      2 of the License, or (at your option) any later version.
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
+#include <linux/spinlock.h>
 #include <asm/uaccess.h>
 
-extern const struct exception_table_entry __start___ex_table[];
-extern const struct exception_table_entry __stop___ex_table[];
+extern struct exception_table_entry __start___ex_table[];
+extern struct exception_table_entry __stop___ex_table[];
+
+/*
+ * The exception table needs to be sorted because we use the macros
+ * which put things into the exception table in a variety of segments
+ * as well as the init segment and the main kernel text segment.
+ */
+static inline void
+sort_ex_table(struct exception_table_entry *start,
+	      struct exception_table_entry *finish)
+{
+	struct exception_table_entry el, *p, *q;
+
+	/* insertion sort */
+	for (p = start + 1; p < finish; ++p) {
+		/* start .. p-1 is sorted */
+		if (p[0].insn < p[-1].insn) {
+			/* move element p down to its right place */
+			el = *p;
+			q = p;
+			do {
+				/* el comes before q[-1], move q[-1] up one */
+				q[0] = q[-1];
+				--q;
+			} while (q > start && el.insn < q[-1].insn);
+			*q = el;
+		}
+	}
+}
+
+void
+sort_exception_table(void)
+{
+	sort_ex_table(__start___ex_table, __stop___ex_table);
+}
 
 static inline unsigned long
 search_one_table(const struct exception_table_entry *first,
 		 const struct exception_table_entry *last,
 		 unsigned long value)
 {
-        while (first <= last) {
+	while (first <= last) {
 		const struct exception_table_entry *mid;
 		long diff;
 
 		mid = (last - first) / 2 + first;
 		diff = mid->insn - value;
-                if (diff == 0)
-                        return mid->fixup;
-                else if (diff < 0)
-                        first = mid+1;
-                else
-                        last = mid-1;
-        }
-        return 0;
+		if (diff == 0)
+			return mid->fixup;
+		else if (diff < 0)
+			first = mid+1;
+		else
+			last = mid-1;
+	}
+	return 0;
 }
 
+extern spinlock_t modlist_lock;
+
 unsigned long
 search_exception_table(unsigned long addr)
 {
-	unsigned long ret;
+	unsigned long ret = 0;
 
 #ifndef CONFIG_MODULES
 	/* There is only the kernel to search.  */
 	ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr);
-	if (ret) return ret;
+	return ret;
 #else
+	unsigned long flags;
 	/* The kernel is the last "module" -- no need to treat it special.  */
 	struct module *mp;
+
+	spin_lock_irqsave(&modlist_lock, flags);
 	for (mp = module_list; mp != NULL; mp = mp->next) {
-		if (mp->ex_table_start == NULL)
+		if (mp->ex_table_start == NULL || !(mp->flags&(MOD_RUNNING|MOD_INITIALIZING)))
 			continue;
 		ret = search_one_table(mp->ex_table_start,
 				       mp->ex_table_end - 1, addr);
 		if (ret)
-			return ret;
+			break;
 	}
+	spin_unlock_irqrestore(&modlist_lock, flags);
+	return ret;
 #endif
-
-	return 0;
 }
diff -urN linux-2.4.21-pre3/arch/ppc64/mm/fault.c linux-2.4.21-pre4/arch/ppc64/mm/fault.c
--- linux-2.4.21-pre3/arch/ppc64/mm/fault.c	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/mm/fault.c	Tue Jan 28 19:44:29 2003
@@ -84,11 +84,19 @@
 
 #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
 	if (debugger_fault_handler && (regs->trap == 0x300 ||
-				regs->trap == 0x380)) {
+				       regs->trap == 0x380)) {
 		debugger_fault_handler(regs);
 		return;
 	}
+#endif /* CONFIG_XMON || CONFIG_KGDB */
 
+	/* On an SLB miss we can only check for a valid exception entry */
+	if (regs->trap == 0x380) {
+		bad_page_fault(regs, address);
+		return;
+	}
+
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
 	if (error_code & 0x00400000) {
 		/* DABR match */
 		if (debugger_dabr_match(regs))
@@ -136,6 +144,7 @@
 			goto bad_area;
 	}
 
+ survive:
 	/*
 	 * If for any reason at all we couldn't handle the fault,
 	 * make sure we exit gracefully rather than endlessly redo
@@ -189,6 +198,11 @@
  */
 out_of_memory:
 	up_read(&mm->mmap_sem);
+	if (current->pid == 1) {
+		yield();
+		down_read(&mm->mmap_sem);
+		goto survive;
+	}
 	printk("VM: killing process %s\n", current->comm);
 	if (user_mode(regs))
 		do_exit(SIGKILL);
diff -urN linux-2.4.21-pre3/arch/ppc64/mm/init.c linux-2.4.21-pre4/arch/ppc64/mm/init.c
--- linux-2.4.21-pre3/arch/ppc64/mm/init.c	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/mm/init.c	Tue Jan 28 19:44:29 2003
@@ -82,11 +82,6 @@
 extern char _stext[], etext[];
 extern struct task_struct *current_set[NR_CPUS];
 
-void mm_init_ppc64(void);
-
-unsigned long *pmac_find_end_of_memory(void);
-extern unsigned long *find_end_of_memory(void);
-
 extern pgd_t ioremap_dir[];
 pgd_t * ioremap_pgd = (pgd_t *)&ioremap_dir;
 
@@ -171,12 +166,10 @@
 #ifdef CONFIG_PPC_ISERIES
 	return (void*)addr;
 #else
-	if(mem_init_done && (addr >> 60UL)) {
-		if (IS_EEH_TOKEN_DISABLED(addr))
-			return IO_TOKEN_TO_ADDR(addr);
-		return (void*)addr; /* already mapped address or EEH token. */
-	}
-	return __ioremap(addr, size, _PAGE_NO_CACHE);
+	void *ret = __ioremap(addr, size, _PAGE_NO_CACHE);
+	if(mem_init_done)
+		return eeh_ioremap(addr, ret);	/* may remap the addr */
+	return ret;
 #endif
 }
 
@@ -272,6 +265,14 @@
 	}
 }
 
+#ifndef CONFIG_PPC_ISERIES
+int
+io_remap_page_range(unsigned long from, unsigned long to, unsigned long size, pgprot_t prot)
+{
+	return remap_page_range(from, eeh_token_to_phys(to), size, prot);
+}
+#endif
+
 void
 local_flush_tlb_all(void)
 {
@@ -284,6 +285,8 @@
 void
 local_flush_tlb_mm(struct mm_struct *mm)
 {
+	spin_lock(&mm->page_table_lock);
+
 	if ( mm->map_count ) {
 		struct vm_area_struct *mp;
 		for ( mp = mm->mmap; mp != NULL; mp = mp->vm_next )
@@ -294,6 +297,8 @@
 		 * when an address space (represented by an mm_struct)
 		 * is being destroyed. */
 		local_flush_tlb_range( mm, USER_START, USER_END );
+
+	spin_unlock(&mm->page_table_lock);
 }
 
 /*
@@ -446,12 +451,12 @@
 	 * The range of contexts [FIRST_USER_CONTEXT, NUM_USER_CONTEXT)
 	 * are stored on a stack/queue for easy allocation and deallocation.
 	 */
-        mmu_context_queue.lock = SPIN_LOCK_UNLOCKED;
-        mmu_context_queue.head = 0;
-        mmu_context_queue.tail = NUM_USER_CONTEXT-1;
-        mmu_context_queue.size = NUM_USER_CONTEXT;
+	mmu_context_queue.lock = SPIN_LOCK_UNLOCKED;
+	mmu_context_queue.head = 0;
+	mmu_context_queue.tail = NUM_USER_CONTEXT-1;
+	mmu_context_queue.size = NUM_USER_CONTEXT;
 	for(index=0; index < NUM_USER_CONTEXT ;index++) {
-                mmu_context_queue.elements[index] = index+FIRST_USER_CONTEXT;
+		mmu_context_queue.elements[index] = index+FIRST_USER_CONTEXT;
 	}
 
 	/* Setup guard pages for the Paca's */
@@ -491,7 +496,7 @@
 
 	PPCDBG(PPCDBG_MMINIT, "\tstart               = 0x%lx\n", start);
 	PPCDBG(PPCDBG_MMINIT, "\tbootmap_pages       = 0x%lx\n", bootmap_pages);
-	PPCDBG(PPCDBG_MMINIT, "\tphysicalMemorySize  = 0x%lx\n", naca->physicalMemorySize);
+	PPCDBG(PPCDBG_MMINIT, "\tphysicalMemorySize  = 0x%lx\n", systemcfg->physicalMemorySize);
 
 	boot_mapsize = init_bootmem(start >> PAGE_SHIFT, total_pages);
 	PPCDBG(PPCDBG_MMINIT, "\tboot_mapsize        = 0x%lx\n", boot_mapsize);
@@ -585,7 +590,7 @@
 			datapages++;
 	}
 
-        printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%08lx,%08lx]\n",
+	printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%08lx,%08lx]\n",
 	       (unsigned long)nr_free_pages()<< (PAGE_SHIFT-10),
 	       codepages<< (PAGE_SHIFT-10), datapages<< (PAGE_SHIFT-10),
 	       initpages<< (PAGE_SHIFT-10),
@@ -622,6 +627,7 @@
 void clear_user_page(void *page, unsigned long vaddr)
 {
 	clear_page(page);
+	__flush_dcache_icache(page);
 }
 
 void copy_user_page(void *vto, void *vfrom, unsigned long vaddr)
diff -urN linux-2.4.21-pre3/arch/ppc64/vmlinux.lds linux-2.4.21-pre4/arch/ppc64/vmlinux.lds
--- linux-2.4.21-pre3/arch/ppc64/vmlinux.lds	Fri Aug  2 17:39:43 2002
+++ linux-2.4.21-pre4/arch/ppc64/vmlinux.lds	Tue Jan 28 19:44:29 2003
@@ -1,4 +1,4 @@
-OUTPUT_ARCH(powerpc)
+OUTPUT_ARCH(powerpc:common64)
 SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib);
 /* Do we need any of these for elf?
    __DYNAMIC = 0;    */
diff -urN linux-2.4.21-pre3/arch/ppc64/xmon/start.c linux-2.4.21-pre4/arch/ppc64/xmon/start.c
--- linux-2.4.21-pre3/arch/ppc64/xmon/start.c	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/xmon/start.c	Tue Jan 28 19:44:29 2003
@@ -59,9 +59,9 @@
 }
 static struct sysrq_key_op sysrq_xmon_op = 
 {
-	handler:	sysrq_handle_xmon,
-	help_msg:	"xmon",
-	action_msg:	"Entering xmon\n",
+	.handler =	sysrq_handle_xmon,
+	.help_msg =	"xmon",
+	.action_msg =	"Entering xmon\n",
 };
 
 void
diff -urN linux-2.4.21-pre3/arch/ppc64/xmon/xmon.c linux-2.4.21-pre4/arch/ppc64/xmon/xmon.c
--- linux-2.4.21-pre3/arch/ppc64/xmon/xmon.c	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre4/arch/ppc64/xmon/xmon.c	Tue Jan 28 19:44:29 2003
@@ -14,6 +14,7 @@
 #include <linux/smp.h>
 #include <linux/mm.h>
 #include <linux/reboot.h>
+#include <linux/delay.h>
 #include <asm/ptrace.h>
 #include <asm/string.h>
 #include <asm/prom.h>
@@ -48,11 +49,6 @@
 #define setjmp xmon_setjmp
 #define longjmp xmon_longjmp
 
-#define memlist_entry list_entry
-#define memlist_next(x) ((x)->next)
-#define memlist_prev(x) ((x)->prev)
-
-
 /* Max number of stack frames we are willing to produce on a backtrace. */
 #define MAXFRAMECOUNT 50
 
@@ -119,15 +115,12 @@
 static void cpu_cmd(void);
 #endif /* CONFIG_SMP */
 static void csum(void);
+static void bootcmds(void);
 static void mem_translate(void);
 static void mem_check(void);
 static void mem_find_real(void);
 static void mem_find_vsid(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_check_dup_rpn (void);
 static void debug_trace(void);
 
 extern int print_insn_big_powerpc(FILE *, unsigned long, unsigned long);
@@ -144,6 +137,14 @@
 
 #define GETWORD(v)	(((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
 
+#define isxdigit(c)	(('0' <= (c) && (c) <= '9') \
+			 || ('a' <= (c) && (c) <= 'f') \
+			 || ('A' <= (c) && (c) <= 'F'))
+#define isalnum(c)	(('0' <= (c) && (c) <= '9') \
+			 || ('a' <= (c) && (c) <= 'z') \
+			 || ('A' <= (c) && (c) <= 'Z'))
+#define isspace(c)	(c == ' ' || c == '\t' || c == 10 || c == 13 || c == 0)
+
 static char *help_string = "\
 Commands:\n\
   b	show breakpoints\n\
@@ -173,14 +174,14 @@
   t	print backtrace\n\
   T	Enable/Disable PPCDBG flags\n\
   x	exit monitor\n\
-  z	reboot\n\
-  Z	halt\n\
 ";
 
 static int xmon_trace[NR_CPUS];
 #define SSTEP	1		/* stepping because of 's' command */
 #define BRSTEP	2		/* stepping over breakpoint */
 
+static struct pt_regs *xmon_regs[NR_CPUS];
+
 /*
  * Stuff for reading and writing memory safely
  */
@@ -292,7 +293,6 @@
 			std	29,232(%0)\n\
 			std	30,240(%0)\n\
 			std	31,248(%0)" : : "b" (&regs));
-		printf("xmon called\n");
 		/* Fetch the link reg for this stack frame.
 		 NOTE: the prev printf fills in the lr. */
 		regs.nip = regs.link = ((unsigned long *)(regs.gpr[1]))[2];
@@ -306,6 +306,7 @@
 
 	msr = get_msr();
 	set_msrd(msr & ~MSR_EE);	/* disable interrupts */
+	xmon_regs[smp_processor_id()] = excp;
 	excprint(excp);
 #ifdef CONFIG_SMP
 	if (test_and_set_bit(smp_processor_id(), &cpus_in_xmon))
@@ -325,14 +326,15 @@
 	cmd = cmds(excp);
 	if (cmd == 's') {
 		xmon_trace[smp_processor_id()] = SSTEP;
-		excp->msr |= 0x400;
+		excp->msr |= MSR_SE;
 	} else if (at_breakpoint(excp->nip)) {
 		xmon_trace[smp_processor_id()] = BRSTEP;
-		excp->msr |= 0x400;
+		excp->msr |= MSR_SE;
 	} else {
 		xmon_trace[smp_processor_id()] = 0;
 		insert_bpts();
 	}
+	xmon_regs[smp_processor_id()] = 0;
 #ifdef CONFIG_SMP
 	clear_bit(0, &got_xmon);
 	clear_bit(smp_processor_id(), &cpus_in_xmon);
@@ -340,85 +342,6 @@
 	set_msrd(msr);		/* restore interrupt enable */
 }
 
-/* Code can call this to get a backtrace and continue. */
-void
-xmon_backtrace(const char *fmt, ...)
-{
-	va_list ap;
-	struct pt_regs regs;
-
-
-	/* Ok, grab regs as they are now.
-	 This won't do a particularily good job because the
-	 prologue has already been executed.
-	 ToDo: We could reach back into the callers save
-	 area to do a better job of representing the
-	 caller's state.
-	 */
-	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)" : : "b" (&regs));
-	/* Fetch the link reg for this stack frame.
-	 NOTE: the prev printf fills in the lr. */
-	regs.nip = regs.link = ((unsigned long *)(regs.gpr[1]))[2];
-	regs.msr = get_msr();
-	regs.ctr = get_ctr();
-	regs.xer = get_xer();
-	regs.ccr = get_cr();
-	regs.trap = 0;
-
-	va_start(ap, fmt);
-	xmon_vfprintf(stdout, fmt, ap);
-	xmon_putc('\n', stdout);
-	va_end(ap);
-	take_input("\n");
-	backtrace(&regs);
-}
-
-/* Call this to poll for ^C during busy operations.
- * Returns true if the user has hit ^C.
- */
-int
-xmon_interrupted(void)
-{
-	int ret = xmon_read_poll();
-	if (ret == 3) {
-		printf("\n^C interrupted.\n");
-		return 1;
-	}
-	return 0;
-}
-
-
 void
 xmon_irq(int irq, void *d, struct pt_regs *regs)
 {
@@ -443,7 +366,7 @@
 		remove_bpts();
 		excprint(regs);
 		xmon_trace[smp_processor_id()] = BRSTEP;
-		regs->msr |= 0x400;
+		regs->msr |= MSR_SE;
 	} else {
 		printf("Stopped at breakpoint %x (%lx %s)\n", (bp - bpts)+1, bp->address, bp->funcname);
 		xmon(regs);
@@ -473,7 +396,7 @@
 		remove_bpts();
 		excprint(regs);
 		xmon_trace[smp_processor_id()] = BRSTEP;
-		regs->msr |= 0x400;
+		regs->msr |= MSR_SE;
 	} else {
 		dabr.instr = regs->nip;
 		xmon(regs);
@@ -489,7 +412,7 @@
 		remove_bpts();
 		excprint(regs);
 		xmon_trace[smp_processor_id()] = BRSTEP;
-		regs->msr |= 0x400;
+		regs->msr |= MSR_SE;
 	} else {
 		xmon(regs);
 	}
@@ -519,7 +442,7 @@
 	int i;
 	struct bpt *bp;
 
-	if (naca->platform != PLATFORM_PSERIES)
+	if (systemcfg->platform != PLATFORM_PSERIES)
 		return;
 	bp = bpts;
 	for (i = 0; i < NBPTS; ++i, ++bp) {
@@ -550,7 +473,7 @@
 	struct bpt *bp;
 	unsigned instr;
 
-	if (naca->platform != PLATFORM_PSERIES)
+	if (systemcfg->platform != PLATFORM_PSERIES)
 		return;
 	if (!__is_processor(PV_POWER4) && !__is_processor(PV_POWER4p)) {
 		set_dabr(0);
@@ -597,14 +520,6 @@
 			cmd = inchar();
 		}
 		switch (cmd) {
-		case 'z':
-			printf("Rebooting machine now...");
-			machine_restart(NULL);
-			break;
-		case 'Z':
-			printf("Halting machine now...");
-			machine_halt();
-			break;
 		case 'm':
 			cmd = inchar();
 			switch (cmd) {
@@ -625,27 +540,15 @@
 			case 'c':
 				mem_check();
 				break;
-			case 'j':
-				mem_map_check_slab();
-				break;
 			case 'f':
 				mem_find_real();
 				break;
 			case 'e':
 				mem_find_vsid();
 				break;
-			case 'r':
-				mem_check_dup_rpn();
-				break;           
 			case 'i':
 				show_mem();
 				break;
-			case 'o':
-				mem_check_pagetable_vsids ();
-				break;
-			case 'q':
-				mem_map_lock_pages() ;
-				break;
 			default:
 				termch = cmd;
 				memex();
@@ -700,6 +603,8 @@
 			cpu_cmd();
 			break;
 #endif /* CONFIG_SMP */
+		case 'z':
+			bootcmds();
 		case 'T':
 			debug_trace();
 			break;
@@ -718,6 +623,19 @@
 	}
 }
 
+static void bootcmds(void)
+{
+	int cmd;
+
+	cmd = inchar();
+	if (cmd == 'r')
+		ppc_md.restart(NULL);
+	else if (cmd == 'h')
+		ppc_md.halt();
+	else if (cmd == 'p')
+		ppc_md.power_off();
+}
+
 #ifdef CONFIG_SMP
 static void cpu_cmd(void)
 {
@@ -739,7 +657,7 @@
 		printf("cpus stopped:");
 		for (cpu = 0; cpu < NR_CPUS; ++cpu) {
 			if (test_bit(cpu, &cpus_in_xmon)) {
-				printf(" %d", cpu);
+				printf(" %x", cpu);
 				if (cpu == smp_processor_id())
 					printf("*", cpu);
 			}
@@ -870,6 +788,7 @@
 		break;
 	case 'i':	/* bi - hardware instr breakpoint */
 		if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p)) {
+			printf("Not implemented on POWER4\n");
 			break;
 		}
 		iabr.address = 0;
@@ -972,7 +891,9 @@
 	case 0x100:	ret = "(System Reset)"; break; 
 	case 0x200:	ret = "(Machine Check)"; break; 
 	case 0x300:	ret = "(Data Access)"; break; 
+	case 0x380:	ret = "(Data SLB Access)"; break;
 	case 0x400:	ret = "(Instruction Access)"; break; 
+	case 0x480:	ret = "(Instruction SLB Access)"; break;
 	case 0x500:	ret = "(Hardware Interrupt)"; break; 
 	case 0x600:	ret = "(Alignment)"; break; 
 	case 0x700:	ret = "(Program Check)"; break; 
@@ -1120,7 +1041,7 @@
 	printf("    sp: %lx\n", fp->gpr[1]);
 	printf("   msr: %lx\n", fp->msr);
 
-	if (fp->trap == 0x300 || fp->trap == 0x600) {
+	if (fp->trap == 0x300 || fp->trap == 0x380 || fp->trap == 0x600) {
 		printf("   dar: %lx\n", fp->dar);
 		printf(" dsisr: %lx\n", fp->dsisr);
 	}
@@ -1296,34 +1217,6 @@
 	scannl();
 }
 
-#if 0
-static void
-openforth()
-{
-	int c;
-	char *p;
-	char cmd[1024];
-	int args[5];
-	extern int (*prom_entry)(int *);
-
-	p = cmd;
-	c = skipbl();
-	while (c != '\n') {
-		*p++ = c;
-		c = inchar();
-	}
-	*p = 0;
-	args[0] = (int) "interpret";
-	args[1] = 1;
-	args[2] = 1;
-	args[3] = (int) cmd;
-	(*prom_entry)(args);
-	printf("\n");
-	if (args[4] != 0)
-		printf("error %x\n", args[4]);
-}
-#endif
-
 #ifndef CONFIG_PPC64BRIDGE
 static void
 dump_hash_table_seg(unsigned seg, unsigned start, unsigned end)
@@ -1538,7 +1431,18 @@
 static void
 handle_fault(struct pt_regs *regs)
 {
-	fault_type = regs->trap == 0x200? 0: regs->trap == 0x300? 1: 2;
+	switch (regs->trap) {
+	case 0x200:
+		fault_type = 0;
+		break;
+	case 0x300:
+	case 0x380:
+		fault_type = 1;
+		break;
+	default:
+		fault_type = 2;
+	}
+
 	longjmp(bus_error_jmp, 1);
 }
 
@@ -2011,6 +1915,16 @@
 	return c;
 }
 
+#define N_PTREGS	44
+static char *regnames[N_PTREGS] = {
+	"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+	"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+	"r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+	"r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
+	"pc", "msr", "or3", "ctr", "lr", "xer", "ccr", "mq",
+	"trap", "dar", "dsisr", "res"
+};
+
 int
 scanhex(vp)
 unsigned long *vp;
@@ -2019,6 +1933,36 @@
 	unsigned long v;
 
 	c = skipbl();
+	if (c == '%') {
+		/* parse register name */
+		char regname[8];
+		int i;
+
+		for (i = 0; i < sizeof(regname) - 1; ++i) {
+			c = inchar();
+			if (!isalnum(c)) {
+				termch = c;
+				break;
+			}
+			regname[i] = c;
+		}
+		regname[i] = 0;
+		for (i = 0; i < N_PTREGS; ++i) {
+			if (strcmp(regnames[i], regname) == 0) {
+				unsigned long *rp = (unsigned long *)
+					xmon_regs[smp_processor_id()];
+				if (rp == NULL) {
+					printf("regs not available\n");
+					return 0;
+				}
+				*vp = rp[i];
+				return 1;
+			}
+		}
+		printf("invalid register name '%%%s'\n", regname);
+		return 0;
+	}
+
 	d = hexdigit(c);
 	if( d == EOF ){
 		termch = c;
@@ -2440,249 +2384,6 @@
 	printf("\nDone -------------------\n");
 }
 
-void mem_map_check_slab()
-{
-	int i, slab_count;
-
-	i = max_mapnr;
-	slab_count = 0;
-	
-	while (i-- > 0)  {
-		if (PageSlab(mem_map+i)){
-			printf(" slab entry - mem_map entry =%p  \n", mem_map+i);
-			slab_count ++;
-		}
-	}
-
-	printf(" count of pages for slab = %d \n", slab_count);
-}
-
-void mem_map_lock_pages()
-{
-	int i, lock_count;
-
-	i = max_mapnr;
-	lock_count = 0;
-	
-	while (i-- > 0)  {
-		if (PageLocked(mem_map+i)){
-			printf(" locked entry - mem_map entry =%p  \n", mem_map+i);
-			lock_count ++;
-		}
-	}
-
-	printf(" count of locked pages = %d \n", lock_count); 
-}
-
-void mem_check_dup_rpn ()
-{
-	unsigned long htab_size_bytes;
-	unsigned long htab_end;
-	unsigned long last_rpn;
-	HPTE *hpte1, *hpte2;
-	int dup_count;
-	struct task_struct *p;
-	unsigned long kernel_vsid_c0,kernel_vsid_c1,kernel_vsid_c2,kernel_vsid_c3;
-	unsigned long kernel_vsid_c4,kernel_vsid_c5,kernel_vsid_d,kernel_vsid_e;
-	unsigned long kernel_vsid_f;
-	unsigned long vsid0,vsid1,vsidB,vsid2;
-
-	htab_size_bytes = htab_data.htab_num_ptegs * 128; // 128B / PTEG
-	htab_end = (unsigned long)htab_data.htab + htab_size_bytes;
-	// last_rpn = (naca->physicalMemorySize-1) >> PAGE_SHIFT;
-	last_rpn = 0xfffff;
-
-	printf("\nHardware Page Table Check\n-------------------\n");
-	printf("htab base      : %.16lx\n", htab_data.htab);
-	printf("htab size      : %.16lx\n", htab_size_bytes);
-
-
-	for(hpte1 = htab_data.htab; hpte1 < (HPTE *)htab_end; hpte1++) {
-		if ( hpte1->dw0.dw0.v != 0 ) {
-			if ( hpte1->dw1.dw1.rpn <= last_rpn ) {
-				dup_count = 0;
-				for(hpte2 = hpte1+1; hpte2 < (HPTE *)htab_end; hpte2++) {
-					if ( hpte2->dw0.dw0.v != 0 ) {
-						if(hpte1->dw1.dw1.rpn == hpte2->dw1.dw1.rpn) {
-							dup_count++;
-						}
-					}
-				}
-				if(dup_count > 5) {
-					printf(" Duplicate rpn: %.13lx \n", (hpte1->dw1.dw1.rpn));
-					printf("    mem map array entry %p count = %d \n",
-					       (mem_map+(hpte1->dw1.dw1.rpn)), (mem_map+(hpte1->dw1.dw1.rpn))->count);
-					for(hpte2 = hpte1+1; hpte2 < (HPTE *)htab_end; hpte2++) {
-						if ( hpte2->dw0.dw0.v != 0 ) {
-							if(hpte1->dw1.dw1.rpn == hpte2->dw1.dw1.rpn) {
-								printf("   hpte2: %16.16lx  *hpte2: %16.16lx %16.16lx\n",
-								       hpte2, hpte2->dw0.dword0, hpte2->dw1.dword1);
-							}
-						}
-					}
-				}
-			} else {
-				printf(" Bogus rpn: %.13lx \n", (hpte1->dw1.dw1.rpn));
-				printf("   hpte: %16.16lx  *hpte: %16.16lx %16.16lx\n",
-				       hpte1, hpte1->dw0.dword0, hpte1->dw1.dword1);
-			}
-		}
-		if (xmon_interrupted())
-			return;
-	}                                                                     
-
-
-
-	// print the kernel vsids
-	kernel_vsid_c0 =  get_kernel_vsid(0xC000000000000000);
-	kernel_vsid_c1 =  get_kernel_vsid(0xC000000010000000);
-	kernel_vsid_c2 =  get_kernel_vsid(0xC000000020000000);
-	kernel_vsid_c3 =  get_kernel_vsid(0xC000000030000000);
-	kernel_vsid_c4 =  get_kernel_vsid(0xC000000040000000);
-	kernel_vsid_c5 =  get_kernel_vsid(0xC000000050000000);
-	kernel_vsid_d  =  get_kernel_vsid(0xD000000000000000);
-	kernel_vsid_e  =  get_kernel_vsid(0xE000000000000000);
-	kernel_vsid_f  =  get_kernel_vsid(0xF000000000000000);
-
-	printf(" kernel vsid -  seg c0  = %lx\n",  kernel_vsid_c0 );
-	printf(" kernel vsid -  seg c1  = %lx\n",  kernel_vsid_c1 );
-	printf(" kernel vsid -  seg c2  = %lx\n",  kernel_vsid_c2 );
-	printf(" kernel vsid -  seg c3  = %lx\n",  kernel_vsid_c3 );
-	printf(" kernel vsid -  seg c4  = %lx\n",  kernel_vsid_c4 );
-	printf(" kernel vsid -  seg c5  = %lx\n",  kernel_vsid_c5 );
-	printf(" kernel vsid -  seg d   = %lx\n",  kernel_vsid_d );
-	printf(" kernel vsid -  seg e   = %lx\n",  kernel_vsid_e );
-	printf(" kernel vsid -  seg f   = %lx\n",  kernel_vsid_f );
-
-
-  // print a list of valid vsids for the tasks
-	read_lock(&tasklist_lock);
-	for_each_task(p)
-		if(p->mm) {
-			struct mm_struct *mm = p->mm; 
-			printf(" task = %p  mm =  %lx  pgd   %lx\n", 
-			       p, mm, mm->pgd);
-			vsid0 = get_vsid( mm->context, 0 );
-			vsid1 = get_vsid( mm->context, 0x10000000 );
-			vsid2 = get_vsid( mm->context, 0x20000000 );
-			vsidB = get_vsid( mm->context, 0xB0000000 );
-			printf("            context = %lx  vsid seg 0  = %lx\n",  mm->context, vsid0 );
-			printf("                           vsid seg 1  = %lx\n",  vsid1 );
-			printf("                           vsid seg 2  = %lx\n",  vsid2 );
-			printf("                           vsid seg 2  = %lx\n",  vsidB );
-	  
-			printf("\n");
-		};
-	read_unlock(&tasklist_lock);
-
-	printf("\nDone -------------------\n");
-}
-
-
-
-void mem_check_pagetable_vsids ()
-{
-	unsigned long htab_size_bytes;
-	unsigned long htab_end;
-	unsigned long last_rpn;
-	struct task_struct *p;
-	unsigned long valid_table_count,invalid_table_count,bogus_rpn_count;
-	int found;
-	unsigned long user_address_table_count,kernel_page_table_count;
-	unsigned long pt_vsid;
-	HPTE *hpte1;
-
-
-	htab_size_bytes = htab_data.htab_num_ptegs * 128; // 128B / PTEG
-	htab_end = (unsigned long)htab_data.htab + htab_size_bytes;
-	// last_rpn = (naca->physicalMemorySize-1) >> PAGE_SHIFT;
-	last_rpn = 0xfffff;
-
-	printf("\nHardware Page Table Check\n-------------------\n");
-	printf("htab base      : %.16lx\n", htab_data.htab);
-	printf("htab size      : %.16lx\n", htab_size_bytes);
-
-	valid_table_count = 0;
-	invalid_table_count = 0;
-	bogus_rpn_count = 0;
-	user_address_table_count = 0;
-	kernel_page_table_count = 0;
-	for(hpte1 = htab_data.htab; hpte1 < (HPTE *)htab_end; hpte1++) {
-		if ( hpte1->dw0.dw0.v != 0 ) {
-			valid_table_count++;
-			if ( hpte1->dw1.dw1.rpn <= last_rpn ) {
-				pt_vsid =  (hpte1->dw0.dw0.avpn) >> 5;
-				if ((pt_vsid == get_kernel_vsid(0xC000000000000000)) |
-				    (pt_vsid == get_kernel_vsid(0xC000000010000000)) |
-				    (pt_vsid == get_kernel_vsid(0xC000000020000000)) |
-				    (pt_vsid == get_kernel_vsid(0xC000000030000000)) |
-				    (pt_vsid == get_kernel_vsid(0xC000000040000000)) |
-				    (pt_vsid == get_kernel_vsid(0xC000000050000000)) |
-				    (pt_vsid == get_kernel_vsid(0xD000000000000000)) |
-				    (pt_vsid == get_kernel_vsid(0xE000000000000000)) |
-				    (pt_vsid == get_kernel_vsid(0xF000000000000000)) ) {
-					kernel_page_table_count ++;
-				} else {
-					read_lock(&tasklist_lock);
-					found = 0;
-					for_each_task(p) {
-						if(p->mm && (found == 0)) {
-							struct mm_struct *mm = p->mm; 
-	     
-							if ((pt_vsid == get_vsid( mm->context, 0 )) |
-							    (pt_vsid == get_vsid( mm->context, 0x10000000 )) |
-							    (pt_vsid == get_vsid( mm->context, 0x20000000 )) |
-							    (pt_vsid == get_vsid( mm->context, 0x30000000 )) |
-							    (pt_vsid == get_vsid( mm->context, 0x40000000 )) |
-							    (pt_vsid == get_vsid( mm->context, 0x50000000 )) |
-							    (pt_vsid == get_vsid( mm->context, 0x60000000 )) |
-							    (pt_vsid == get_vsid( mm->context, 0x70000000 )) |
-							    (pt_vsid == get_vsid( mm->context, 0x80000000 )) |
-							    (pt_vsid == get_vsid( mm->context, 0x90000000 )) |
-							    (pt_vsid == get_vsid( mm->context, 0xA0000000 )) |
-							    (pt_vsid == get_vsid( mm->context, 0xB0000000 ))) {
-								user_address_table_count ++;
-								found = 1;
-							}
-						}
-					}
-					read_unlock(&tasklist_lock);
-					if (found == 0)
-					{
-						printf(" vsid not found vsid = %lx, hpte = %p  \n", 
-						       pt_vsid,hpte1);
-						printf("    rpn in entry = %lx \n", hpte1->dw1.dw1.rpn);
-						printf("    mem map address = %lx  \n", mem_map + (hpte1->dw1.dw1.rpn));
-           
-					} else //  found
-					{
-					}
-
-				}  // good rpn
-       
-			} else {
-				bogus_rpn_count ++;
-			}
-		} else {
-			invalid_table_count++;
-		}
-	}                                                                     
-
-
-	printf(" page table valid counts - valid entries = %lx  invalid entries =  %lx \n",
-	       valid_table_count, invalid_table_count);
-
-	printf("  bogus rpn entries ( probably io) = %lx \n", bogus_rpn_count);
-
- 
-  
-	printf(" page table counts - kernel entries = %lx  user entries =  %lx \n",
-	       kernel_page_table_count, user_address_table_count); 
-
-	printf("\nDone -------------------\n");
-
-}
-
 static void debug_trace(void) {
         unsigned long val, cmd, on;
 
diff -urN linux-2.4.21-pre3/arch/sparc64/kernel/ioctl32.c linux-2.4.21-pre4/arch/sparc64/kernel/ioctl32.c
--- linux-2.4.21-pre3/arch/sparc64/kernel/ioctl32.c	Tue Jan 28 19:44:25 2003
+++ linux-2.4.21-pre4/arch/sparc64/kernel/ioctl32.c	Tue Jan 28 19:44:29 2003
@@ -99,6 +99,7 @@
 
 #include <linux/usb.h>
 #include <linux/usbdevice_fs.h>
+#include <linux/usb_scanner_ioctl.h>
 #include <linux/nbd.h>
 #include <linux/random.h>
 #include <linux/filter.h>
@@ -5008,6 +5009,10 @@
 COMPATIBLE_IOCTL(BNEPCONNDEL)
 COMPATIBLE_IOCTL(BNEPGETCONNLIST)
 COMPATIBLE_IOCTL(BNEPGETCONNINFO)
+/* Scanner */
+COMPATIBLE_IOCTL(SCANNER_IOCTL_VENDOR)
+COMPATIBLE_IOCTL(SCANNER_IOCTL_PRODUCT)
+COMPATIBLE_IOCTL(SCANNER_IOCTL_CTRLMSG)
 /* Misc. */
 COMPATIBLE_IOCTL(0x41545900)		/* ATYIO_CLKR */
 COMPATIBLE_IOCTL(0x41545901)		/* ATYIO_CLKW */
diff -urN linux-2.4.21-pre3/arch/sparc64/kernel/sys_sparc32.c linux-2.4.21-pre4/arch/sparc64/kernel/sys_sparc32.c
--- linux-2.4.21-pre3/arch/sparc64/kernel/sys_sparc32.c	Tue Jan 28 19:44:25 2003
+++ linux-2.4.21-pre4/arch/sparc64/kernel/sys_sparc32.c	Tue Jan 28 19:44:29 2003
@@ -50,6 +50,7 @@
 #include <linux/icmpv6.h>
 #include <linux/sysctl.h>
 #include <linux/dnotify.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
 
 #include <asm/types.h>
 #include <asm/ipc.h>
@@ -2618,10 +2619,28 @@
 		__get_user(kcmsg32->cmsg_type, &ucmsg->cmsg_type);
 
 		clen64 = kcmsg32->cmsg_len;
-		copy_from_user(CMSG32_DATA(kcmsg32), CMSG_DATA(ucmsg),
-			       clen64 - CMSG_ALIGN(sizeof(*ucmsg)));
-		clen32 = ((clen64 - CMSG_ALIGN(sizeof(*ucmsg))) +
-			  CMSG32_ALIGN(sizeof(struct cmsghdr32)));
+		if (kcmsg32->cmsg_level == SOL_SOCKET &&
+			kcmsg32->cmsg_type == SO_TIMESTAMP) {
+			struct timeval tv;
+			struct timeval32 *tv32;
+
+			if (clen64 != CMSG_LEN(sizeof(struct timeval))) {
+				kfree(workbuf);
+				goto fail;
+			}
+
+			copy_from_user(&tv, CMSG_DATA(ucmsg), sizeof(tv));
+			tv32 = (struct timeval32 *)CMSG32_DATA(kcmsg32);
+			tv32->tv_sec = tv.tv_sec;
+			tv32->tv_usec = tv.tv_usec;
+			clen32 = sizeof(*tv32) +
+				  CMSG32_ALIGN(sizeof(struct cmsghdr32));
+		} else {
+			copy_from_user(CMSG32_DATA(kcmsg32), CMSG_DATA(ucmsg),
+				       clen64 - CMSG_ALIGN(sizeof(*ucmsg)));
+			clen32 = ((clen64 - CMSG_ALIGN(sizeof(*ucmsg))) +
+				  CMSG32_ALIGN(sizeof(struct cmsghdr32)));
+		}
 		kcmsg32->cmsg_len = clen32;
 
 		ucmsg = (struct cmsghdr *) (((char *)ucmsg) + CMSG_ALIGN(clen64));
@@ -2777,6 +2796,78 @@
 extern asmlinkage int sys_setsockopt(int fd, int level, int optname,
 				     char *optval, int optlen);
 
+static int do_netfilter_replace(int fd, int level, int optname,
+				char *optval, int optlen)
+{
+	struct ipt_replace32 {
+		char name[IPT_TABLE_MAXNAMELEN];
+		__u32 valid_hooks;
+		__u32 num_entries;
+		__u32 size;
+		__u32 hook_entry[NF_IP_NUMHOOKS];
+		__u32 underflow[NF_IP_NUMHOOKS];
+		__u32 num_counters;
+		__u32 counters;
+		struct ipt_entry entries[0];
+	} *repl32 = (struct ipt_replace32 *)optval;
+	struct ipt_replace *krepl;
+	struct ipt_counters *counters32;
+	__u32 origsize;
+	unsigned int kreplsize, kcountersize;
+	mm_segment_t old_fs;
+	int ret;
+
+	if (optlen < sizeof(repl32))
+		return -EINVAL;
+
+	if (copy_from_user(&origsize,
+			&repl32->size,
+			sizeof(origsize)))
+		return -EFAULT;
+
+	kreplsize = sizeof(*krepl) + origsize;
+	kcountersize = krepl->num_counters * sizeof(struct ipt_counters);
+
+	/* Hack: Causes ipchains to give correct error msg --RR */
+	if (optlen != kreplsize)
+		return -ENOPROTOOPT;
+
+	krepl = (struct ipt_replace *)kmalloc(kreplsize, GFP_KERNEL);
+	if (krepl == NULL)
+		return -ENOMEM;
+
+	if (copy_from_user(krepl, optval, kreplsize)) {
+		kfree(krepl);
+		return -EFAULT;
+	}
+
+	counters32 = (struct ipt_counters *)AA(
+		((struct ipt_replace32 *)krepl)->counters);
+
+	kcountersize = krepl->num_counters * sizeof(struct ipt_counters);
+	krepl->counters = (struct ipt_counters *)kmalloc(
+					kcountersize, GFP_KERNEL);
+	if (krepl->counters == NULL) {
+		kfree(krepl);
+		return -ENOMEM;
+	}
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_setsockopt(fd, level, optname,
+			     (char *)krepl, kreplsize);
+	set_fs(old_fs);
+
+	if (ret == 0 &&
+		copy_to_user(counters32, krepl->counters, kcountersize))
+			ret = -EFAULT;
+
+	kfree(krepl->counters);
+	kfree(krepl);
+
+	return ret;
+}
+
 static int do_set_attach_filter(int fd, int level, int optname,
 				char *optval, int optlen)
 {
@@ -2870,6 +2961,9 @@
 asmlinkage int sys32_setsockopt(int fd, int level, int optname,
 				char *optval, int optlen)
 {
+	if (optname == IPT_SO_SET_REPLACE)
+		return do_netfilter_replace(fd, level, optname,
+					    optval, optlen);
 	if (optname == SO_ATTACH_FILTER)
 		return do_set_attach_filter(fd, level, optname,
 					    optval, optlen);
diff -urN linux-2.4.21-pre3/arch/x86_64/boot/compressed/misc.c linux-2.4.21-pre4/arch/x86_64/boot/compressed/misc.c
--- linux-2.4.21-pre3/arch/x86_64/boot/compressed/misc.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/arch/x86_64/boot/compressed/misc.c	Tue Jan 28 19:44:29 2003
@@ -335,6 +335,8 @@
 void check_cpu(void)
 {
 	int res = 0;
+	int tmp, flags;
+	
 	asm volatile( " \n\
 	movl $3,%%edx		# at least 386 \n\
 	pushfl			# push EFLAGS \n\
@@ -400,6 +402,44 @@
 	}
 	if (res !=7)
 		error( "Sorry, your CPU is not capable of running 64-bit kernel." );
+
+	/* check required feature flags */ 
+	/* see http://www.x86-64.org/lists/discuss/msg02971.html */
+#define REQUIRED_MASK1 ((1<<0)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<8)|(1<<11)| \
+					   (1<<13)|(1<<15)|(1<<24))
+	
+	asm("cpuid" : "=d" (flags), "=a" (tmp) : "1" (0x80000001) : "ebx", "ecx"); 
+	flags &= REQUIRED_MASK1;
+	flags ^= REQUIRED_MASK1; 
+	if (flags & (1<<0))
+		error("CPU misses x87"); 
+	if (flags & (1<<3)) 
+		error("CPU doesn't support page size extension (PSE)");
+	if (flags & (1<<4))
+		error("CPU misses an time stamp counter"); 
+	if (flags & (1<<5))
+		error("CPU misses AMD style MSRs"); 
+	if (flags & (1<<6))
+		error("CPU misses physical address extension (PAE)"); 
+	if (flags & (1<<8))
+		error("CPU misses cmpxchg8"); 
+	if (flags & (1<<11))
+		error("CPU doesn't support SYSCALL/SYSRET");
+	if (flags & (1<<13))
+		error("CPU doesn't support PGE"); 
+	if (flags & (1<<15))
+		error("CPU doesn't support CMOV"); 
+	if (flags & (1<<24))
+		error("CPU doesn't support FXSAVE/FXRSTOR"); 
+	
+#define REQUIRED_MASK2 ((1<<25)|(1<<26))	
+	asm("cpuid" : "=d" (flags), "=a" (tmp) : "1" (1) : "ebx", "ecx"); 
+	flags &= REQUIRED_MASK2; 
+	flags ^= REQUIRED_MASK2; 
+	if (flags & (1<<25))
+		error("CPU doesn't support SSE1");
+	if (flags & (1<<26))
+		error("CPU doesn't support SSE2");
 }
 
 int decompress_kernel(struct moveparams *mv, void *rmode)
diff -urN linux-2.4.21-pre3/arch/x86_64/config.in linux-2.4.21-pre4/arch/x86_64/config.in
--- linux-2.4.21-pre3/arch/x86_64/config.in	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/arch/x86_64/config.in	Tue Jan 28 19:44:29 2003
@@ -241,7 +241,7 @@
    bool '  Spinlock debugging' CONFIG_DEBUG_SPINLOCK
    bool '  Additional run-time checks' CONFIG_CHECKING
    bool '  Debug __init statements' CONFIG_INIT_DEBUG
-   bool '  IOMMU leak tracing' CONFIG_IOMMU_LEAK
+   bool '  IOMMU debugging' CONFIG_IOMMU_DEBUG
    bool '  Probalistic stack overflow check' CONFIG_DEBUG_STACKOVERFLOW
 fi
 endmenu
diff -urN linux-2.4.21-pre3/arch/x86_64/defconfig linux-2.4.21-pre4/arch/x86_64/defconfig
--- linux-2.4.21-pre3/arch/x86_64/defconfig	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/arch/x86_64/defconfig	Tue Jan 28 19:44:29 2003
@@ -42,8 +42,7 @@
 CONFIG_MTRR=y
 # CONFIG_SMP is not set
 CONFIG_HPET_TIMER=y
-# CONFIG_GART_IOMMU is not set
-CONFIG_DUMMY_IOMMU=y
+CONFIG_GART_IOMMU=y
 CONFIG_X86_UP_IOAPIC=y
 CONFIG_MCE=y
 # CONFIG_K8_NUMA is not set
@@ -195,21 +194,13 @@
 CONFIG_BLK_DEV_IDEDISK=y
 # 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
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
 # CONFIG_BLK_DEV_IDECS is not set
 CONFIG_BLK_DEV_IDECD=y
 # 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
+# CONFIG_IDE_TASKFILE_IO is not set
 
 #
 # IDE chipset support/bugfixes
@@ -217,8 +208,8 @@
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
 CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_BLK_DEV_GENERIC=y
 # CONFIG_IDEPCI_SHARE_IRQ is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
@@ -227,30 +218,31 @@
 # 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
 # CONFIG_WDC_ALI15X3 is not set
 CONFIG_BLK_DEV_AMD74XX=y
 # CONFIG_AMD74XX_OVERRIDE is not set
 # CONFIG_BLK_DEV_CMD64X is not set
-# CONFIG_BLK_DEV_CMD680 is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
 # CONFIG_BLK_DEV_CS5530 is not set
 # CONFIG_BLK_DEV_HPT34X is not set
 # CONFIG_HPT34X_AUTODMA is not set
 # CONFIG_BLK_DEV_HPT366 is not set
 # CONFIG_BLK_DEV_PIIX is not set
-# CONFIG_PIIX_TUNING is not set
+# CONFIG_BLK_DEV_NFORCE is not set
 # CONFIG_BLK_DEV_NS87415 is not set
 # CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_PDC202XX is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
 # CONFIG_PDC202XX_BURST is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
 # CONFIG_PDC202XX_FORCE is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
 # CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
 # CONFIG_BLK_DEV_SIS5513 is not set
 # CONFIG_BLK_DEV_SLC90E66 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
@@ -302,10 +294,8 @@
 CONFIG_AIC7XXX_RESET_DELAY_MS=15000
 # CONFIG_AIC7XXX_PROBE_EISA_VL is not set
 # CONFIG_AIC7XXX_BUILD_FIRMWARE is not set
-# CONFIG_SCSI_DPT_I2O is not set
 # CONFIG_SCSI_ADVANSYS is not set
 # CONFIG_SCSI_IN2000 is not set
-# CONFIG_SCSI_AM53C974 is not set
 # CONFIG_SCSI_MEGARAID is not set
 # CONFIG_SCSI_BUSLOGIC is not set
 # CONFIG_SCSI_CPQFCTS is not set
@@ -333,13 +323,11 @@
 # CONFIG_SCSI_QLOGIC_ISP is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
-# CONFIG_SCSI_SEAGATE is not set
-# CONFIG_SCSI_SIM710 is not set
 # CONFIG_SCSI_SYM53C416 is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_ULTRASTOR is not set
+# CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
 
 #
@@ -401,11 +389,12 @@
 #
 # CONFIG_ACENIC is not set
 # CONFIG_DL2K is not set
-# CONFIG_E1000 is not set
+CONFIG_E1000=m
 # CONFIG_MYRI_SBUS is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 CONFIG_TIGON3=y
 # CONFIG_FDDI is not set
@@ -501,8 +490,10 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
 # CONFIG_AMD_RNG is not set
 # CONFIG_INTEL_RNG is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -514,6 +505,7 @@
 #
 # CONFIG_FTAPE is not set
 CONFIG_AGP=y
+CONFIG_AGP_AMD_8151=y
 CONFIG_AGP_INTEL=y
 CONFIG_AGP_I810=y
 CONFIG_AGP_VIA=y
@@ -592,6 +584,7 @@
 # CONFIG_UDF_RW is not set
 # CONFIG_UFS_FS is not set
 # CONFIG_UFS_FS_WRITE is not set
+CONFIG_SIMICSFS=y
 
 #
 # Network File Systems
@@ -603,7 +596,7 @@
 # CONFIG_ROOT_NFS is not set
 CONFIG_NFSD=y
 CONFIG_NFSD_V3=y
-# CONFIG_NFSD_TCP is not set
+CONFIG_NFSD_TCP=y
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
@@ -700,5 +693,5 @@
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_CHECKING is not set
 # CONFIG_INIT_DEBUG is not set
-# CONFIG_IOMMU_LEAK is not set
+# CONFIG_IOMMU_DEBUG is not set
 CONFIG_DEBUG_STACKOVERFLOW=y
diff -urN linux-2.4.21-pre3/arch/x86_64/ia32/fpu32.c linux-2.4.21-pre4/arch/x86_64/ia32/fpu32.c
--- linux-2.4.21-pre3/arch/x86_64/ia32/fpu32.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/arch/x86_64/ia32/fpu32.c	Tue Jan 28 19:44:29 2003
@@ -2,7 +2,7 @@
  * Copyright 2002 Andi Kleen, SuSE Labs.
  * FXSAVE<->i387 conversion support. Based on code by Gareth Hughes.
  * This is used for ptrace, signals and coredumps in 32bit emulation.
- * $Id: fpu32.c,v 1.1 2002/03/21 14:16:32 ak Exp $
+ * $Id: fpu32.c,v 1.2 2003/01/10 15:11:11 ak Exp $
  */ 
 
 #include <linux/sched.h>
@@ -80,9 +80,9 @@
 	int err; 
 	__u32 v;
 
-	err = __get_user(fxsave->cwd, (u16 *)&buf->cw); 
-	err |= __get_user(fxsave->swd, (u16 *)&buf->sw);
-	err |= __get_user(fxsave->twd, (u16 *)&buf->tag);
+	err = __get_user(fxsave->cwd, &buf->cw); 
+	err |= __get_user(fxsave->swd, &buf->sw);
+	err |= __get_user(fxsave->twd, &buf->tag);
 	fxsave->twd = twd_i387_to_fxsr(fxsave->twd);
 	err |= __get_user(fxsave->rip, &buf->ipoff); 
 	err |= __get_user(fxsave->rdp, &buf->dataoff); 
diff -urN linux-2.4.21-pre3/arch/x86_64/ia32/ia32_binfmt.c linux-2.4.21-pre4/arch/x86_64/ia32/ia32_binfmt.c
--- linux-2.4.21-pre3/arch/x86_64/ia32/ia32_binfmt.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/arch/x86_64/ia32/ia32_binfmt.c	Tue Jan 28 19:44:29 2003
@@ -25,7 +25,9 @@
 
 #define IA32_EMULATOR 1
 
-#define IA32_PAGE_OFFSET 0xFFFFF000
+#define ELF_NAME "elf/i386"
+
+#define IA32_PAGE_OFFSET 0xFFFFe000
 #define IA32_STACK_TOP IA32_PAGE_OFFSET
 #define ELF_ET_DYN_BASE		(IA32_PAGE_OFFSET/3 + 0x1000000)
 
@@ -163,11 +165,13 @@
 #define ELF_PLAT_INIT(r)		elf32_init(r)
 #define setup_arg_pages(bprm)		ia32_setup_arg_pages(bprm)
 
+extern void load_gs_index(unsigned);
+
 #undef start_thread
 #define start_thread(regs,new_rip,new_rsp) do { \
-	__asm__("movl %0,%%fs": :"r" (0)); \
-	__asm__("movl %0,%%es; movl %0,%%ds": :"r" (__USER32_DS)); \
-	wrmsrl(MSR_KERNEL_GS_BASE, 0); \
+	asm volatile("movl %0,%%fs": :"r" (0)); \
+	load_gs_index(0);	\
+	asm volatile("movl %0,%%es; movl %0,%%ds": :"r" (__USER32_DS)); \
 	(regs)->rip = (new_rip); \
 	(regs)->rsp = (new_rsp); \
 	(regs)->eflags = 0x200; \
@@ -203,6 +207,8 @@
 	regs->rax = 0;
 	regs->rbx = 0; 
 	regs->rbp = 0; 
+	regs->r8 = regs->r9 = regs->r10 = regs->r11 = regs->r12 = regs->r13 =
+		regs->r14 = regs->r15 = 0;	
 	me->thread.fs = 0; 
 	me->thread.gs = 0;
 	me->thread.fsindex = 0; 
@@ -237,7 +243,7 @@
 		mpnt->vm_mm = current->mm;
 		mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p;
 		mpnt->vm_end = IA32_STACK_TOP;
-		mpnt->vm_page_prot = PAGE_COPY;
+		mpnt->vm_page_prot = PAGE_COPY_EXEC;
 		mpnt->vm_flags = VM_STACK_FLAGS;
 		mpnt->vm_ops = NULL;
 		mpnt->vm_pgoff = 0;
diff -urN linux-2.4.21-pre3/arch/x86_64/ia32/ia32_ioctl.c linux-2.4.21-pre4/arch/x86_64/ia32/ia32_ioctl.c
--- linux-2.4.21-pre3/arch/x86_64/ia32/ia32_ioctl.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/arch/x86_64/ia32/ia32_ioctl.c	Tue Jan 28 19:44:29 2003
@@ -1,4 +1,4 @@
-/* $Id: ia32_ioctl.c,v 1.24 2002/09/17 15:23:41 ak Exp $
+/* $Id: ia32_ioctl.c,v 1.27 2002/11/28 06:03:48 ak Exp $
  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
  *
  * Copyright (C) 1997-2000  Jakub Jelinek  (jakub@redhat.com)
@@ -56,6 +56,8 @@
 #include <linux/module.h>
 #include <linux/serial.h>
 #include <linux/reiserfs_fs.h>
+#include <linux/if_tun.h>
+#include <linux/ctype.h>
 #if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE)
 /* Ugh. This header really is not clean */
 #define min min
@@ -74,9 +76,14 @@
 #include <asm/ia32.h>
 #include <asm/uaccess.h>
 #include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/if_bonding.h>
+#include <linux/watchdog.h>
+
 #include <asm/module.h>
 #include <asm/ioctl32.h>
 #include <linux/soundcard.h>
+#include <linux/lp.h>
 
 #include <linux/atm.h>
 #include <linux/atmarp.h>
@@ -89,6 +96,19 @@
 #include <linux/atm_tcp.h>
 #include <linux/sonet.h>
 #include <linux/atm_suni.h>
+#include <linux/mtd/mtd.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci.h>
+
+#include <linux/usb.h>
+#include <linux/usbdevice_fs.h>
+#include <linux/nbd.h>
+#include <linux/random.h>
+#include <linux/filter.h>
+
+#include <asm/mtrr.h>
+
 
 #define A(__x) ((void *)(unsigned long)(__x))
 #define AA(__x)	A(__x)
@@ -442,6 +462,7 @@
         __kernel_caddr_t32  ifcbuf;
 };
 
+#ifdef CONFIG_NET
 static int dev_ifname32(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
 	struct net_device *dev;
@@ -457,10 +478,12 @@
 
 	strncpy(ifr32.ifr_name, dev->name, sizeof(ifr32.ifr_name)-1);
 	ifr32.ifr_name[sizeof(ifr32.ifr_name)-1] = 0; 
+	dev_put(dev);
 	
 	err = copy_to_user((struct ifreq32 *)arg, &ifr32, sizeof(struct ifreq32));
 	return (err ? -EFAULT : 0);
 }
+#endif
 
 static int dev_ifconf(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
@@ -557,9 +580,25 @@
 	}
 	switch (ethcmd) {
 	case ETHTOOL_GDRVINFO:	len = sizeof(struct ethtool_drvinfo); break;
+	case ETHTOOL_GMSGLVL:
+	case ETHTOOL_SMSGLVL:
+	case ETHTOOL_GLINK:
+	case ETHTOOL_NWAY_RST:  len = sizeof(struct ethtool_value); break;
+	case ETHTOOL_GREGS: {
+		struct ethtool_regs *regaddr = (struct ethtool_regs *)A(data);
+		/* darned variable size arguments */
+		if (get_user(len, (u32 *)&regaddr->len)) {
+			err = -EFAULT;
+			goto out;
+		}
+		len += sizeof(struct ethtool_regs);
+		break;
+	}
 	case ETHTOOL_GSET:
-	case ETHTOOL_SSET:
-	default:		len = sizeof(struct ethtool_cmd); break;
+	case ETHTOOL_SSET:      len = sizeof(struct ethtool_cmd); break;
+	default:
+               err = -EOPNOTSUPP;
+               goto out;
 	}
 
 	if (copy_from_user(ifr.ifr_data, (char *)A(data), len)) {
@@ -585,6 +624,91 @@
 	return err;
 }
 
+
+static int bond_ioctl(unsigned long fd, unsigned int cmd, unsigned long arg)
+{
+	struct ifreq ifr;
+	mm_segment_t old_fs;
+	int err, len;
+	u32 data;
+	
+	if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
+		return -EFAULT;
+	ifr.ifr_data = (__kernel_caddr_t)get_free_page(GFP_KERNEL);
+	if (!ifr.ifr_data)
+		return -EAGAIN;
+
+	switch (cmd) {
+	case SIOCBONDENSLAVE:
+	case SIOCBONDRELEASE:
+	case SIOCBONDSETHWADDR:
+	case SIOCBONDCHANGEACTIVE:
+		len = IFNAMSIZ * sizeof(char);
+		break;
+	case SIOCBONDSLAVEINFOQUERY:
+		len = sizeof(struct ifslave);
+		break;
+	case SIOCBONDINFOQUERY:
+		len = sizeof(struct ifbond);
+		break;
+	default:
+		err = -EINVAL;
+		goto out;
+	};
+
+	__get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data));
+	if (copy_from_user(ifr.ifr_data, (char *)A(data), len)) {
+		err = -EFAULT;
+		goto out;
+	}
+
+	old_fs = get_fs();
+	set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, cmd, (unsigned long)&ifr);
+	set_fs (old_fs);
+	if (!err) {
+		len = copy_to_user((char *)A(data), ifr.ifr_data, len);
+		if (len)
+			err = -EFAULT;
+	}
+
+out:
+	free_page((unsigned long)ifr.ifr_data);
+	return err;
+}
+
+static __inline__ void *alloc_user_space(long len)
+{
+	struct pt_regs *regs = (void *)current->thread.rsp0 - sizeof(struct pt_regs); 
+	return (void *)regs->rsp - len; 
+}
+
+static int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct ifreq *u_ifreq64;
+	struct ifreq32 *u_ifreq32 = (struct ifreq32 *) arg;
+	char tmp_buf[IFNAMSIZ];
+	void *data64;
+	u32 data32;
+
+	if (copy_from_user(&tmp_buf[0], &(u_ifreq32->ifr_ifrn.ifrn_name[0]),
+			   IFNAMSIZ))
+		return -EFAULT;
+	if (__get_user(data32, &u_ifreq32->ifr_ifru.ifru_data))
+		return -EFAULT;
+	data64 = (void *) A(data32);
+
+	u_ifreq64 = alloc_user_space(sizeof(*u_ifreq64));
+
+	/* Don't check these user accesses, just let that get trapped
+	 * in the ioctl handler instead.
+	 */
+	copy_to_user(&u_ifreq64->ifr_ifrn.ifrn_name[0], &tmp_buf[0], IFNAMSIZ);
+	__put_user(data64, &u_ifreq64->ifr_ifru.ifru_data);
+
+	return sys_ioctl(fd, cmd, (unsigned long) u_ifreq64);
+}
+
 static int dev_ifsioc(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
 	struct ifreq ifr;
@@ -603,15 +727,6 @@
 		if (err)
 			return -EFAULT;
 		break;
-	case SIOCGPPPSTATS:
-	case SIOCGPPPCSTATS:
-	case SIOCGPPPVER:
-		if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
-			return -EFAULT;
-		ifr.ifr_data = (__kernel_caddr_t)get_free_page(GFP_KERNEL);
-		if (!ifr.ifr_data)
-			return -EAGAIN;
-		break;
 	default:
 		if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
 			return -EFAULT;
@@ -637,27 +752,6 @@
 			if (copy_to_user((struct ifreq32 *)arg, &ifr, sizeof(struct ifreq32)))
 				return -EFAULT;
 			break;
-		case SIOCGPPPSTATS:
-		case SIOCGPPPCSTATS:
-		case SIOCGPPPVER:
-		{
-			u32 data;
-			int len;
-
-			__get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data));
-			if(cmd == SIOCGPPPVER)
-				len = strlen((char *)ifr.ifr_data) + 1;
-			else if(cmd == SIOCGPPPCSTATS)
-				len = sizeof(struct ppp_comp_stats);
-			else
-				len = sizeof(struct ppp_stats);
-
-			len = copy_to_user((char *)A(data), ifr.ifr_data, len);
-			free_page((unsigned long)ifr.ifr_data);
-			if(len)
-				return -EFAULT;
-			break;
-		}
 		case SIOCGIFMAP:
 			err = copy_to_user((struct ifreq32 *)arg, &ifr, sizeof(ifr.ifr_name));
 			err |= __put_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_start));
@@ -670,14 +764,6 @@
 				err = -EFAULT;
 			break;
 		}
-	} else {
-		switch (cmd) {
-		case SIOCGPPPSTATS:
-		case SIOCGPPPCSTATS:
-		case SIOCGPPPVER:
-			free_page((unsigned long)ifr.ifr_data);
-			break;
-		}
 	}
 	return err;
 }
@@ -716,11 +802,6 @@
 
 extern struct socket *sockfd_lookup(int fd, int *err);
 
-extern __inline__ void sockfd_put(struct socket *sock)
-{
-	fput(sock->file);
-}
-
 static int routing_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
 	int ret;
@@ -769,9 +850,6 @@
 	ret = sys_ioctl (fd, cmd, (long) r);
 	set_fs (old_fs);
 
-	if (mysock)
-		sockfd_put(mysock);
-
 	return ret;
 }
 
@@ -798,14 +876,6 @@
 	return err ? -EFAULT : 0;
 }
 
-struct  fbcmap32 {
-	int             index;          /* first element (0 origin) */
-	int             count;
-	u32		red;
-	u32		green;
-	u32		blue;
-};
-
 struct fb_fix_screeninfo32 {
 	char			id[16];
         __kernel_caddr_t32	smem_start;
@@ -889,7 +959,7 @@
 		break;
 	default:
 		do {
-			static int count = 0;
+			static int count;
 			if (++count <= 20)
 				printk("%s: Unknown fb ioctl cmd fd(%d) "
 				       "cmd(%08x) arg(%08lx)\n",
@@ -1268,6 +1338,269 @@
 	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 sock_fprog32 {
+	__u16	len;
+	__u32	filter;
+};
+
+#define PPPIOCSPASS32	_IOW('t', 71, struct sock_fprog32)
+#define PPPIOCSACTIVE32	_IOW('t', 70, struct sock_fprog32)
+
+static int ppp_sock_fprog_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct sock_fprog32 *u_fprog32 = (struct sock_fprog32 *) arg;
+	struct sock_fprog *u_fprog64 = alloc_user_space(sizeof(struct sock_fprog));
+	void *fptr64;
+	u32 fptr32;
+	u16 flen;
+
+	if (get_user(flen, &u_fprog32->len) ||
+	    get_user(fptr32, &u_fprog32->filter))
+		return -EFAULT;
+
+	fptr64 = (void *) A(fptr32);
+
+	if (put_user(flen, &u_fprog64->len) ||
+	    put_user(fptr64, &u_fprog64->filter))
+		return -EFAULT;
+
+	if (cmd == PPPIOCSPASS32)
+		cmd = PPPIOCSPASS;
+	else
+		cmd = PPPIOCSACTIVE;
+
+	return sys_ioctl(fd, cmd, (unsigned long) u_fprog64);
+}
+
 struct ppp_option_data32 {
 	__kernel_caddr_t32	ptr;
 	__u32			length;
@@ -1314,7 +1647,7 @@
 		break;
 	default:
 		do {
-			static int count = 0;
+			static int count;
 			if (++count <= 20)
 				printk("ppp_ioctl: Unknown cmd fd(%d) "
 				       "cmd(%08x) arg(%08x)\n",
@@ -1424,7 +1757,7 @@
 		break;
 	default:
 		do {
-			static int count = 0;
+			static int count;
 			if (++count <= 20)
 				printk("mt_ioctl: Unknown cmd fd(%d) "
 				       "cmd(%08x) arg(%08x)\n",
@@ -1542,7 +1875,7 @@
 		break;
 	default:
 		do {
-			static int count = 0;
+			static int count;
 			if (++count <= 20)
 				printk("cdrom_ioctl: Unknown cmd fd(%d) "
 				       "cmd(%08x) arg(%08x)\n",
@@ -1629,7 +1962,7 @@
 		}
 		break;
 	default: {
-		static int count = 0;
+		static int count;
 		if (++count <= 20)
 			printk("%s: Unknown loop ioctl cmd, fd(%d) "
 			       "cmd(%08x) arg(%08lx)\n",
@@ -2443,602 +2776,63 @@
 }
 #endif
 
-#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
-/* This really belongs in include/linux/drm.h -DaveM */
-#include "../../../drivers/char/drm/drm.h"
-
-typedef struct drm32_version {
-	int    version_major;	  /* Major version			    */
-	int    version_minor;	  /* Minor version			    */
-	int    version_patchlevel;/* Patch level			    */
-	int    name_len;	  /* Length of name buffer		    */
-	u32    name;		  /* Name of driver			    */
-	int    date_len;	  /* Length of date buffer		    */
-	u32    date;		  /* User-space buffer to hold date	    */
-	int    desc_len;	  /* Length of desc buffer		    */
-	u32    desc;		  /* User-space buffer to hold desc	    */
-} drm32_version_t;
-#define DRM32_IOCTL_VERSION    DRM_IOWR(0x00, drm32_version_t)
-
-static int drm32_version(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	drm32_version_t *uversion = (drm32_version_t *)arg;
-	char *name_ptr, *date_ptr, *desc_ptr;
-	u32 tmp1, tmp2, tmp3;
-	drm_version_t kversion;
-	mm_segment_t old_fs;
-	int ret;
-
-	memset(&kversion, 0, sizeof(kversion));
-	if (get_user(kversion.name_len, &uversion->name_len) ||
-	    get_user(kversion.date_len, &uversion->date_len) ||
-	    get_user(kversion.desc_len, &uversion->desc_len) ||
-	    get_user(tmp1, &uversion->name) ||
-	    get_user(tmp2, &uversion->date) ||
-	    get_user(tmp3, &uversion->desc))
-		return -EFAULT;
+static int ret_einval(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	return -EINVAL;
+}
 
-	name_ptr = (char *) A(tmp1);
-	date_ptr = (char *) A(tmp2);
-	desc_ptr = (char *) A(tmp3);
-
-	ret = -ENOMEM;
-	if (kversion.name_len && name_ptr) {
-		kversion.name = kmalloc(kversion.name_len, GFP_KERNEL);
-		if (!kversion.name)
-			goto out;
-	}
-	if (kversion.date_len && date_ptr) {
-		kversion.date = kmalloc(kversion.date_len, GFP_KERNEL);
-		if (!kversion.date)
-			goto out;
-	}
-	if (kversion.desc_len && desc_ptr) {
-		kversion.desc = kmalloc(kversion.desc_len, GFP_KERNEL);
-		if (!kversion.desc)
-			goto out;
-	}
+static int broken_blkgetsize(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	/* The mkswap binary hard codes it to Intel value :-((( */
+	return w_long(fd, BLKGETSIZE, arg);
+}
 
-        old_fs = get_fs();
-	set_fs(KERNEL_DS);
-        ret = sys_ioctl (fd, DRM_IOCTL_VERSION, (unsigned long)&kversion);
-        set_fs(old_fs);
+struct blkpg_ioctl_arg32 {
+	int op;
+	int flags;
+	int datalen;
+	u32 data;
+};
 
-	if (!ret) {
-		if ((kversion.name &&
-		     copy_to_user(name_ptr, kversion.name, kversion.name_len)) ||
-		    (kversion.date &&
-		     copy_to_user(date_ptr, kversion.date, kversion.date_len)) ||
-		    (kversion.desc &&
-		     copy_to_user(desc_ptr, kversion.desc, kversion.desc_len)))
-			ret = -EFAULT;
-		if (put_user(kversion.version_major, &uversion->version_major) ||
-		    put_user(kversion.version_minor, &uversion->version_minor) ||
-		    put_user(kversion.version_patchlevel, &uversion->version_patchlevel) ||
-		    put_user(kversion.name_len, &uversion->name_len) ||
-		    put_user(kversion.date_len, &uversion->date_len) ||
-		    put_user(kversion.desc_len, &uversion->desc_len))
-			ret = -EFAULT;
-	}
+static int blkpg_ioctl_trans(unsigned int fd, unsigned int cmd, struct blkpg_ioctl_arg32 *arg)
+{
+	struct blkpg_ioctl_arg a;
+	struct blkpg_partition p;
+	int err;
+	mm_segment_t old_fs = get_fs();
 
-out:
-	if (kversion.name)
-		kfree(kversion.name);
-	if (kversion.date)
-		kfree(kversion.date);
-	if (kversion.desc)
-		kfree(kversion.desc);
-	return ret;
+	err = get_user(a.op, &arg->op);
+	err |= __get_user(a.flags, &arg->flags);
+	err |= __get_user(a.datalen, &arg->datalen);
+	err |= __get_user((long)a.data, &arg->data);
+	if (err) return err;
+	switch (a.op) {
+	case BLKPG_ADD_PARTITION:
+	case BLKPG_DEL_PARTITION:
+		if (a.datalen < sizeof(struct blkpg_partition))
+			return -EINVAL;
+                if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition)))
+			return -EFAULT;
+		a.data = &p;
+		set_fs (KERNEL_DS);
+		err = sys_ioctl(fd, cmd, (unsigned long)&a);
+		set_fs (old_fs);
+	default:
+		return -EINVAL;
+	}                                        
+	return err;
 }
 
-typedef struct drm32_unique {
-	int	unique_len;	  /* Length of unique			    */
-	u32	unique;		  /* Unique name for driver instantiation   */
-} drm32_unique_t;
-#define DRM32_IOCTL_GET_UNIQUE DRM_IOWR(0x01, drm32_unique_t)
-#define DRM32_IOCTL_SET_UNIQUE DRM_IOW( 0x10, drm32_unique_t)
-
-static int drm32_getsetunique(unsigned int fd, unsigned int cmd, unsigned long arg)
+static int ioc_settimeout(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
-	drm32_unique_t *uarg = (drm32_unique_t *)arg;
-	drm_unique_t karg;
-	mm_segment_t old_fs;
-	char *uptr;
-	u32 tmp;
-	int ret;
+	return rw_long(fd, AUTOFS_IOC_SETTIMEOUT, arg);
+}
 
-	if (get_user(karg.unique_len, &uarg->unique_len))
-		return -EFAULT;
-	karg.unique = NULL;
-
-	if (get_user(tmp, &uarg->unique))
-		return -EFAULT;
-
-	uptr = (char *) A(tmp);
-
-	if (uptr) {
-		karg.unique = kmalloc(karg.unique_len, GFP_KERNEL);
-		if (!karg.unique)
-			return -ENOMEM;
-		if (cmd == DRM32_IOCTL_SET_UNIQUE &&
-		    copy_from_user(karg.unique, uptr, karg.unique_len)) {
-			kfree(karg.unique);
-			return -EFAULT;
-		}
-	}
-
-	old_fs = get_fs();
-	set_fs(KERNEL_DS);
-	if (cmd == DRM32_IOCTL_GET_UNIQUE)
-		ret = sys_ioctl (fd, DRM_IOCTL_GET_UNIQUE, (unsigned long)&karg);
-	else
-		ret = sys_ioctl (fd, DRM_IOCTL_SET_UNIQUE, (unsigned long)&karg);
-        set_fs(old_fs);
-
-	if (!ret) {
-		if (cmd == DRM32_IOCTL_GET_UNIQUE &&
-		    uptr != NULL &&
-		    copy_to_user(uptr, karg.unique, karg.unique_len))
-			ret = -EFAULT;
-		if (put_user(karg.unique_len, &uarg->unique_len))
-			ret = -EFAULT;
-	}
-
-	if (karg.unique != NULL)
-		kfree(karg.unique);
-
-	return ret;
-}
-
-typedef struct drm32_map {
-	u32		offset;	 /* Requested physical address (0 for SAREA)*/
-	u32		size;	 /* Requested physical size (bytes)	    */
-	drm_map_type_t	type;	 /* Type of memory to map		    */
-	drm_map_flags_t flags;	 /* Flags				    */
-	u32		handle;  /* User-space: "Handle" to pass to mmap    */
-				 /* Kernel-space: kernel-virtual address    */
-	int		mtrr;	 /* MTRR slot used			    */
-				 /* Private data			    */
-} drm32_map_t;
-#define DRM32_IOCTL_ADD_MAP    DRM_IOWR(0x15, drm32_map_t)
-
-static int drm32_addmap(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	drm32_map_t *uarg = (drm32_map_t *) arg;
-	drm_map_t karg;
-	mm_segment_t old_fs;
-	u32 tmp;
-	int ret;
-
-	ret  = get_user(karg.offset, &uarg->offset);
-	ret |= get_user(karg.size, &uarg->size);
-	ret |= get_user(karg.type, &uarg->type);
-	ret |= get_user(karg.flags, &uarg->flags);
-	ret |= get_user(tmp, &uarg->handle);
-	ret |= get_user(karg.mtrr, &uarg->mtrr);
-	if (ret)
-		return -EFAULT;
-
-	karg.handle = (void *) A(tmp);
-
-	old_fs = get_fs();
-	set_fs(KERNEL_DS);
-	ret = sys_ioctl(fd, DRM_IOCTL_ADD_MAP, (unsigned long) &karg);
-	set_fs(old_fs);
-
-	if (!ret) {
-		ret  = put_user(karg.offset, &uarg->offset);
-		ret |= put_user(karg.size, &uarg->size);
-		ret |= put_user(karg.type, &uarg->type);
-		ret |= put_user(karg.flags, &uarg->flags);
-		tmp = (u32) (long)karg.handle;
-		ret |= put_user(tmp, &uarg->handle);
-		ret |= put_user(karg.mtrr, &uarg->mtrr);
-		if (ret)
-			ret = -EFAULT;
-	}
-
-	return ret;
-}
-
-typedef struct drm32_buf_info {
-	int	       count;	/* Entries in list			     */
-	u32	       list;    /* (drm_buf_desc_t *) */ 
-} drm32_buf_info_t;
-#define DRM32_IOCTL_INFO_BUFS  DRM_IOWR(0x18, drm32_buf_info_t)
-
-static int drm32_info_bufs(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	drm32_buf_info_t *uarg = (drm32_buf_info_t *)arg;
-	drm_buf_desc_t *ulist;
-	drm_buf_info_t karg;
-	mm_segment_t old_fs;
-	int orig_count, ret;
-	u32 tmp;
-
-	if (get_user(karg.count, &uarg->count) ||
-	    get_user(tmp, &uarg->list))
-		return -EFAULT;
-
-	ulist = (drm_buf_desc_t *) A(tmp);
-
-	orig_count = karg.count;
-
-	karg.list = kmalloc(karg.count * sizeof(drm_buf_desc_t), GFP_KERNEL);
-	if (!karg.list)
-		return -EFAULT;
-
-	old_fs = get_fs();
-	set_fs(KERNEL_DS);
-	ret = sys_ioctl(fd, DRM_IOCTL_INFO_BUFS, (unsigned long) &karg);
-	set_fs(old_fs);
-
-	if (!ret) {
-		if (karg.count <= orig_count &&
-		    (copy_to_user(ulist, karg.list,
-				  karg.count * sizeof(drm_buf_desc_t))))
-			ret = -EFAULT;
-		if (put_user(karg.count, &uarg->count))
-			ret = -EFAULT;
-	}
-
-	kfree(karg.list);
-
-	return ret;
-}
-
-typedef struct drm32_buf_free {
-	int	       count;
-	u32	       list;	/* (int *) */
-} drm32_buf_free_t;
-#define DRM32_IOCTL_FREE_BUFS  DRM_IOW( 0x1a, drm32_buf_free_t)
-
-static int drm32_free_bufs(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	drm32_buf_free_t *uarg = (drm32_buf_free_t *)arg;
-	drm_buf_free_t karg;
-	mm_segment_t old_fs;
-	int *ulist;
-	int ret;
-	u32 tmp;
-
-	if (get_user(karg.count, &uarg->count) ||
-	    get_user(tmp, &uarg->list))
-		return -EFAULT;
-
-	ulist = (int *) A(tmp);
-
-	karg.list = kmalloc(karg.count * sizeof(int), GFP_KERNEL);
-	if (!karg.list)
-		return -ENOMEM;
-
-	ret = -EFAULT;
-	if (copy_from_user(karg.list, ulist, (karg.count * sizeof(int))))
-		goto out;
-
-	old_fs = get_fs();
-	set_fs(KERNEL_DS);
-	ret = sys_ioctl(fd, DRM_IOCTL_FREE_BUFS, (unsigned long) &karg);
-	set_fs(old_fs);
-
-out:
-	kfree(karg.list);
-
-	return ret;
-}
-
-typedef struct drm32_buf_pub {
-	int		  idx;	       /* Index into master buflist	     */
-	int		  total;       /* Buffer size			     */
-	int		  used;	       /* Amount of buffer in use (for DMA)  */
-	u32		  address;     /* Address of buffer (void *)	     */
-} drm32_buf_pub_t;
-
-typedef struct drm32_buf_map {
-	int	      count;	/* Length of buflist			    */
-	u32	      virtual;	/* Mmaped area in user-virtual (void *)	    */
-	u32 	      list;	/* Buffer information (drm_buf_pub_t *)	    */
-} drm32_buf_map_t;
-#define DRM32_IOCTL_MAP_BUFS   DRM_IOWR(0x19, drm32_buf_map_t)
-
-static int drm32_map_bufs(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	drm32_buf_map_t *uarg = (drm32_buf_map_t *)arg;
-	drm32_buf_pub_t *ulist;
-	drm_buf_map_t karg;
-	mm_segment_t old_fs;
-	int orig_count, ret, i;
-	u32 tmp1, tmp2;
-
-	if (get_user(karg.count, &uarg->count) ||
-	    get_user(tmp1, &uarg->virtual) ||
-	    get_user(tmp2, &uarg->list))
-		return -EFAULT;
-
-	karg.virtual = (void *) A(tmp1);
-	ulist = (drm32_buf_pub_t *) A(tmp2);
-
-	orig_count = karg.count;
-
-	karg.list = kmalloc(karg.count * sizeof(drm_buf_pub_t), GFP_KERNEL);
-	if (!karg.list)
-		return -ENOMEM;
-
-	ret = -EFAULT;
-	for (i = 0; i < karg.count; i++) {
-		if (get_user(karg.list[i].idx, &ulist[i].idx) ||
-		    get_user(karg.list[i].total, &ulist[i].total) ||
-		    get_user(karg.list[i].used, &ulist[i].used) ||
-		    get_user(tmp1, &ulist[i].address))
-			goto out;
-
-		karg.list[i].address = (void *) A(tmp1);
-	}
-
-	old_fs = get_fs();
-	set_fs(KERNEL_DS);
-	ret = sys_ioctl(fd, DRM_IOCTL_MAP_BUFS, (unsigned long) &karg);
-	set_fs(old_fs);
-
-	if (!ret) {
-		for (i = 0; i < orig_count; i++) {
-			tmp1 = (u32) (long) karg.list[i].address;
-			if (put_user(karg.list[i].idx, &ulist[i].idx) ||
-			    put_user(karg.list[i].total, &ulist[i].total) ||
-			    put_user(karg.list[i].used, &ulist[i].used) ||
-			    put_user(tmp1, &ulist[i].address)) {
-				ret = -EFAULT;
-				goto out;
-			}
-		}
-		if (put_user(karg.count, &uarg->count))
-			ret = -EFAULT;
-	}
-
-out:
-	kfree(karg.list);
-	return ret;
-}
-
-typedef struct drm32_dma {
-				/* Indices here refer to the offset into
-				   buflist in drm_buf_get_t.  */
-	int		context;	  /* Context handle		    */
-	int		send_count;	  /* Number of buffers to send	    */
-	u32		send_indices;	  /* List of handles to buffers (int *) */
-	u32		send_sizes;	  /* Lengths of data to send (int *) */
-	drm_dma_flags_t flags;		  /* Flags			    */
-	int		request_count;	  /* Number of buffers requested    */
-	int		request_size;	  /* Desired size for buffers	    */
-	u32		request_indices;  /* Buffer information (int *)	    */
-	u32		request_sizes;    /* (int *) */
-	int		granted_count;	  /* Number of buffers granted	    */
-} drm32_dma_t;
-#define DRM32_IOCTL_DMA	     DRM_IOWR(0x29, drm32_dma_t)
-
-/* RED PEN	The DRM layer blindly dereferences the send/request
- * 		indice/size arrays even though they are userland
- * 		pointers.  -DaveM
- */
-static int drm32_dma(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	drm32_dma_t *uarg = (drm32_dma_t *) arg;
-	int *u_si, *u_ss, *u_ri, *u_rs;
-	drm_dma_t karg;
-	mm_segment_t old_fs;
-	int ret;
-	u32 tmp1, tmp2, tmp3, tmp4;
-
-	karg.send_indices = karg.send_sizes = NULL;
-	karg.request_indices = karg.request_sizes = NULL;
-
-	if (get_user(karg.context, &uarg->context) ||
-	    get_user(karg.send_count, &uarg->send_count) ||
-	    get_user(tmp1, &uarg->send_indices) ||
-	    get_user(tmp2, &uarg->send_sizes) ||
-	    get_user(karg.flags, &uarg->flags) ||
-	    get_user(karg.request_count, &uarg->request_count) ||
-	    get_user(karg.request_size, &uarg->request_size) ||
-	    get_user(tmp3, &uarg->request_indices) ||
-	    get_user(tmp4, &uarg->request_sizes) ||
-	    get_user(karg.granted_count, &uarg->granted_count))
-		return -EFAULT;
-
-	u_si = (int *) A(tmp1);
-	u_ss = (int *) A(tmp2);
-	u_ri = (int *) A(tmp3);
-	u_rs = (int *) A(tmp4);
-
-	if (karg.send_count) {
-		karg.send_indices = kmalloc(karg.send_count * sizeof(int), GFP_KERNEL);
-		karg.send_sizes = kmalloc(karg.send_count * sizeof(int), GFP_KERNEL);
-
-		ret = -ENOMEM;
-		if (!karg.send_indices || !karg.send_sizes)
-			goto out;
-
-		ret = -EFAULT;
-		if (copy_from_user(karg.send_indices, u_si,
-				   (karg.send_count * sizeof(int))) ||
-		    copy_from_user(karg.send_sizes, u_ss,
-				   (karg.send_count * sizeof(int))))
-			goto out;
-	}
-
-	if (karg.request_count) {
-		karg.request_indices = kmalloc(karg.request_count * sizeof(int), GFP_KERNEL);
-		karg.request_sizes = kmalloc(karg.request_count * sizeof(int), GFP_KERNEL);
-
-		ret = -ENOMEM;
-		if (!karg.request_indices || !karg.request_sizes)
-			goto out;
-
-		ret = -EFAULT;
-		if (copy_from_user(karg.request_indices, u_ri,
-				   (karg.request_count * sizeof(int))) ||
-		    copy_from_user(karg.request_sizes, u_rs,
-				   (karg.request_count * sizeof(int))))
-			goto out;
-	}
-
-	old_fs = get_fs();
-	set_fs(KERNEL_DS);
-	ret = sys_ioctl(fd, DRM_IOCTL_DMA, (unsigned long) &karg);
-	set_fs(old_fs);
-
-	if (!ret) {
-		if (put_user(karg.context, &uarg->context) ||
-		    put_user(karg.send_count, &uarg->send_count) ||
-		    put_user(karg.flags, &uarg->flags) ||
-		    put_user(karg.request_count, &uarg->request_count) ||
-		    put_user(karg.request_size, &uarg->request_size) ||
-		    put_user(karg.granted_count, &uarg->granted_count))
-			ret = -EFAULT;
-
-		if (karg.send_count) {
-			if (copy_to_user(u_si, karg.send_indices,
-					 (karg.send_count * sizeof(int))) ||
-			    copy_to_user(u_ss, karg.send_sizes,
-					 (karg.send_count * sizeof(int))))
-				ret = -EFAULT;
-		}
-		if (karg.request_count) {
-			if (copy_to_user(u_ri, karg.request_indices,
-					 (karg.request_count * sizeof(int))) ||
-			    copy_to_user(u_rs, karg.request_sizes,
-					 (karg.request_count * sizeof(int))))
-				ret = -EFAULT;
-		}
-	}
-
-out:
-	if (karg.send_indices)
-		kfree(karg.send_indices);
-	if (karg.send_sizes)
-		kfree(karg.send_sizes);
-	if (karg.request_indices)
-		kfree(karg.request_indices);
-	if (karg.request_sizes)
-		kfree(karg.request_sizes);
-
-	return ret;
-}
-
-typedef struct drm32_ctx_res {
-	int		count;
-	u32		contexts; /* (drm_ctx_t *) */
-} drm32_ctx_res_t;
-#define DRM32_IOCTL_RES_CTX    DRM_IOWR(0x26, drm32_ctx_res_t)
-
-static int drm32_res_ctx(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	drm32_ctx_res_t *uarg = (drm32_ctx_res_t *) arg;
-	drm_ctx_t *ulist;
-	drm_ctx_res_t karg;
-	mm_segment_t old_fs;
-	int orig_count, ret;
-	u32 tmp;
-
-	karg.contexts = NULL;
-	if (get_user(karg.count, &uarg->count) ||
-	    get_user(tmp, &uarg->contexts))
-		return -EFAULT;
-
-	ulist = (drm_ctx_t *) A(tmp);
-
-	orig_count = karg.count;
-	if (karg.count && ulist) {
-		karg.contexts = kmalloc((karg.count * sizeof(drm_ctx_t)), GFP_KERNEL);
-		if (!karg.contexts)
-			return -ENOMEM;
-		if (copy_from_user(karg.contexts, ulist,
-				   (karg.count * sizeof(drm_ctx_t)))) {
-			kfree(karg.contexts);
-			return -EFAULT;
-		}
-	}
-
-	old_fs = get_fs();
-	set_fs(KERNEL_DS);
-	ret = sys_ioctl(fd, DRM_IOCTL_RES_CTX, (unsigned long) &karg);
-	set_fs(old_fs);
-
-	if (!ret) {
-		if (orig_count) {
-			if (copy_to_user(ulist, karg.contexts,
-					 (orig_count * sizeof(drm_ctx_t))))
-				ret = -EFAULT;
-		}
-		if (put_user(karg.count, &uarg->count))
-			ret = -EFAULT;
-	}
-
-	if (karg.contexts)
-		kfree(karg.contexts);
-
-	return ret;
-}
-
-#endif
-
-static int ret_einval(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	return -EINVAL;
-}
-
-static int broken_blkgetsize(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	/* The mkswap binary hard codes it to Intel value :-((( */
-	return w_long(fd, BLKGETSIZE, arg);
-}
-
-struct blkpg_ioctl_arg32 {
-	int op;
-	int flags;
-	int datalen;
-	u32 data;
-};
-                                
-static int blkpg_ioctl_trans(unsigned int fd, unsigned int cmd, struct blkpg_ioctl_arg32 *arg)
-{
-	struct blkpg_ioctl_arg a;
-	struct blkpg_partition p;
-	int err;
-	mm_segment_t old_fs = get_fs();
-	
-	err = get_user(a.op, &arg->op);
-	err |= __get_user(a.flags, &arg->flags);
-	err |= __get_user(a.datalen, &arg->datalen);
-	err |= __get_user((long)a.data, &arg->data);
-	if (err) return err;
-	switch (a.op) {
-	case BLKPG_ADD_PARTITION:
-	case BLKPG_DEL_PARTITION:
-		if (a.datalen < sizeof(struct blkpg_partition))
-			return -EINVAL;
-                if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition)))
-			return -EFAULT;
-		a.data = &p;
-		set_fs (KERNEL_DS);
-		err = sys_ioctl(fd, cmd, (unsigned long)&a);
-		set_fs (old_fs);
-	default:
-		return -EINVAL;
-	}                                        
-	return err;
-}
-
-static int ioc_settimeout(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	return rw_long(fd, AUTOFS_IOC_SETTIMEOUT, arg);
-}
-
-/* SuSE extension */ 
-#ifndef TIOCGDEV
-#define TIOCGDEV       _IOR('T',0x32, unsigned int)
-#endif
-static int tiocgdev(unsigned fd, unsigned cmd,  unsigned int *ptr) 
-{ 
+#ifndef TIOCGDEV
+#define TIOCGDEV       _IOR('T',0x32, unsigned int)
+#endif
+static int tiocgdev(unsigned fd, unsigned cmd,  unsigned int *ptr) 
+{ 
 
 	struct file *file = fget(fd);
 	struct tty_struct *real_tty;
@@ -3230,6 +3024,571 @@
 	return sys_ioctl(fd,cmd,arg); 
 } 
 
+/* Fix sizeof(sizeof()) breakage */
+#define BLKELVGET_32   _IOR(0x12,106,int)
+#define BLKELVSET_32   _IOW(0x12,107,int)
+#define BLKBSZGET_32   _IOR(0x12,112,int)
+#define BLKBSZSET_32   _IOW(0x12,113,int)
+#define BLKGETSIZE64_32        _IOR(0x12,114,int)
+
+static int do_blkelvget(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+       return sys_ioctl(fd, BLKELVGET, arg);
+}
+
+static int do_blkelvset(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+       return sys_ioctl(fd, BLKELVSET, arg);
+}
+
+static int do_blkbszget(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+       return sys_ioctl(fd, BLKBSZGET, arg);
+}
+
+static int do_blkbszset(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+       return sys_ioctl(fd, BLKBSZSET, arg);
+}
+
+static int do_blkgetsize64(unsigned int fd, unsigned int cmd,
+                          unsigned long arg)
+{
+       return sys_ioctl(fd, BLKGETSIZE64, arg);
+}
+
+
+struct usbdevfs_ctrltransfer32 {
+	__u8 requesttype;
+	__u8 request;
+	__u16 value;
+	__u16 index;
+	__u16 length;
+	__u32 timeout;  /* in milliseconds */
+	__u32 data;
+};
+
+#define USBDEVFS_CONTROL32           _IOWR('U', 0, struct usbdevfs_ctrltransfer32)
+
+static int do_usbdevfs_control(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct usbdevfs_ctrltransfer kctrl;
+	struct usbdevfs_ctrltransfer32 *uctrl;
+	mm_segment_t old_fs;
+	__u32 udata;
+	void *uptr, *kptr;
+	int err;
+
+	uctrl = (struct usbdevfs_ctrltransfer32 *) arg;
+
+	if (copy_from_user(&kctrl, uctrl,
+			   (sizeof(struct usbdevfs_ctrltransfer) -
+			    sizeof(void *))))
+		return -EFAULT;
+
+	if (get_user(udata, &uctrl->data))
+		return -EFAULT;
+	uptr = (void *) A(udata);
+
+	/* In usbdevice_fs, it limits the control buffer to a page,
+	 * for simplicity so do we.
+	 */
+	if (!uptr || kctrl.length > PAGE_SIZE)
+		return -EINVAL;
+
+	kptr = (void *)__get_free_page(GFP_KERNEL);
+
+	if ((kctrl.requesttype & 0x80) == 0) {
+		err = -EFAULT;
+		if (copy_from_user(kptr, uptr, kctrl.length))
+			goto out;
+	}
+
+	kctrl.data = kptr;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, USBDEVFS_CONTROL, (unsigned long)&kctrl);
+	set_fs(old_fs);
+
+	if (err >= 0 &&
+	    ((kctrl.requesttype & 0x80) != 0)) {
+		if (copy_to_user(uptr, kptr, kctrl.length))
+			err = -EFAULT;
+	}
+
+out:
+	free_page((unsigned long) kptr);
+	return err;
+}
+
+struct usbdevfs_bulktransfer32 {
+	unsigned int ep;
+	unsigned int len;
+	unsigned int timeout; /* in milliseconds */
+	__u32 data;
+};
+
+#define USBDEVFS_BULK32              _IOWR('U', 2, struct usbdevfs_bulktransfer32)
+
+static int do_usbdevfs_bulk(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct usbdevfs_bulktransfer kbulk;
+	struct usbdevfs_bulktransfer32 *ubulk;
+	mm_segment_t old_fs;
+	__u32 udata;
+	void *uptr, *kptr;
+	int err;
+
+	ubulk = (struct usbdevfs_bulktransfer32 *) arg;
+
+	if (get_user(kbulk.ep, &ubulk->ep) ||
+	    get_user(kbulk.len, &ubulk->len) ||
+	    get_user(kbulk.timeout, &ubulk->timeout) ||
+	    get_user(udata, &ubulk->data))
+		return -EFAULT;
+
+	uptr = (void *) A(udata);
+
+	/* In usbdevice_fs, it limits the control buffer to a page,
+	 * for simplicity so do we.
+	 */
+	if (!uptr || kbulk.len > PAGE_SIZE)
+		return -EINVAL;
+
+	kptr = (void *) __get_free_page(GFP_KERNEL);
+
+	if ((kbulk.ep & 0x80) == 0) {
+		err = -EFAULT;
+		if (copy_from_user(kptr, uptr, kbulk.len))
+			goto out;
+	}
+
+	kbulk.data = kptr;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, USBDEVFS_BULK, (unsigned long) &kbulk);
+	set_fs(old_fs);
+
+	if (err >= 0 &&
+	    ((kbulk.ep & 0x80) != 0)) {
+		if (copy_to_user(uptr, kptr, kbulk.len))
+			err = -EFAULT;
+	}
+
+out:
+	free_page((unsigned long) kptr);
+	return err;
+}
+
+/* This needs more work before we can enable it.  Unfortunately
+ * because of the fancy asynchronous way URB status/error is written
+ * back to userspace, we'll need to fiddle with USB devio internals
+ * and/or reimplement entirely the frontend of it ourselves. -DaveM
+ *
+ * The issue is:
+ *
+ *	When an URB is submitted via usbdevicefs it is put onto an
+ *	asynchronous queue.  When the URB completes, it may be reaped
+ *	via another ioctl.  During this reaping the status is written
+ *	back to userspace along with the length of the transfer.
+ *
+ *	We must translate into 64-bit kernel types so we pass in a kernel
+ *	space copy of the usbdevfs_urb structure.  This would mean that we
+ *	must do something to deal with the async entry reaping.  First we
+ *	have to deal somehow with this transitory memory we've allocated.
+ *	This is problematic since there are many call sites from which the
+ *	async entries can be destroyed (and thus when we'd need to free up
+ *	this kernel memory).  One of which is the close() op of usbdevicefs.
+ *	To handle that we'd need to make our own file_operations struct which
+ *	overrides usbdevicefs's release op with our own which runs usbdevicefs's
+ *	real release op then frees up the kernel memory.
+ *
+ *	But how to keep track of these kernel buffers?  We'd need to either
+ *	keep track of them in some table _or_ know about usbdevicefs internals
+ *	(ie. the exact layout of it's file private, which is actually defined
+ *	in linux/usbdevice_fs.h, the layout of the async queues are private to
+ *	devio.c)
+ *
+ * There is one possible other solution I considered, also involving knowledge
+ * of usbdevicefs internals:
+ *
+ *	After an URB is submitted, we "fix up" the address back to the user
+ *	space one.  This would work if the status/length fields written back
+ *	by the async URB completion lines up perfectly in the 32-bit type with
+ *	the 64-bit kernel type.  Unfortunately, it does not because the iso
+ *	frame descriptors, at the end of the struct, can be written back.
+ *
+ * I think we'll just need to simply duplicate the devio URB engine here.
+ */
+#if 0
+struct usbdevfs_urb32 {
+	__u8 type;
+	__u8 endpoint;
+	__s32 status;
+	__u32 flags;
+	__u32 buffer;
+	__s32 buffer_length;
+	__s32 actual_length;
+	__s32 start_frame;
+	__s32 number_of_packets;
+	__s32 error_count;
+	__u32 signr;
+	__u32 usercontext; /* unused */
+	struct usbdevfs_iso_packet_desc iso_frame_desc[0];
+};
+
+#define USBDEVFS_SUBMITURB32       _IOR('U', 10, struct usbdevfs_urb32)
+
+static int get_urb32(struct usbdevfs_urb *kurb,
+		     struct usbdevfs_urb32 *uurb)
+{
+	if (get_user(kurb->type, &uurb->type) ||
+	    __get_user(kurb->endpoint, &uurb->endpoint) ||
+	    __get_user(kurb->status, &uurb->status) ||
+	    __get_user(kurb->flags, &uurb->flags) ||
+	    __get_user(kurb->buffer_length, &uurb->buffer_length) ||
+	    __get_user(kurb->actual_length, &uurb->actual_length) ||
+	    __get_user(kurb->start_frame, &uurb->start_frame) ||
+	    __get_user(kurb->number_of_packets, &uurb->number_of_packets) ||
+	    __get_user(kurb->error_count, &uurb->error_count) ||
+	    __get_user(kurb->signr, &uurb->signr))
+		return -EFAULT;
+
+	kurb->usercontext = 0; /* unused currently */
+
+	return 0;
+}
+
+/* Just put back the values which usbdevfs actually changes. */
+static int put_urb32(struct usbdevfs_urb *kurb,
+		     struct usbdevfs_urb32 *uurb)
+{
+	if (put_user(kurb->status, &uurb->status) ||
+	    __put_user(kurb->actual_length, &uurb->actual_length) ||
+	    __put_user(kurb->error_count, &uurb->error_count))
+		return -EFAULT;
+
+	if (kurb->number_of_packets != 0) {
+		int i;
+
+		for (i = 0; i < kurb->number_of_packets; i++) {
+			if (__put_user(kurb->iso_frame_desc[i].actual_length,
+				       &uurb->iso_frame_desc[i].actual_length) ||
+			    __put_user(kurb->iso_frame_desc[i].status,
+				       &uurb->iso_frame_desc[i].status))
+				return -EFAULT;
+		}
+	}
+
+	return 0;
+}
+
+static int get_urb32_isoframes(struct usbdevfs_urb *kurb,
+			       struct usbdevfs_urb32 *uurb)
+{
+	unsigned int totlen;
+	int i;
+
+	if (kurb->type != USBDEVFS_URB_TYPE_ISO) {
+		kurb->number_of_packets = 0;
+		return 0;
+	}
+
+	if (kurb->number_of_packets < 1 ||
+	    kurb->number_of_packets > 128)
+		return -EINVAL;
+
+	if (copy_from_user(&kurb->iso_frame_desc[0],
+			   &uurb->iso_frame_desc[0],
+			   sizeof(struct usbdevfs_iso_packet_desc) *
+			   kurb->number_of_packets))
+		return -EFAULT;
+
+	totlen = 0;
+	for (i = 0; i < kurb->number_of_packets; i++) {
+		unsigned int this_len;
+
+		this_len = kurb->iso_frame_desc[i].length;
+		if (this_len > 1023)
+			return -EINVAL;
+
+		totlen += this_len;
+	}
+
+	if (totlen > 32768)
+		return -EINVAL;
+
+	kurb->buffer_length = totlen;
+
+	return 0;
+}
+
+static int do_usbdevfs_urb(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct usbdevfs_urb *kurb;
+	struct usbdevfs_urb32 *uurb;
+	mm_segment_t old_fs;
+	__u32 udata;
+	void *uptr, *kptr;
+	unsigned int buflen;
+	int err;
+
+	uurb = (struct usbdevfs_urb32 *) arg;
+
+	err = -ENOMEM;
+	kurb = kmalloc(sizeof(struct usbdevfs_urb) +
+		       (sizeof(struct usbdevfs_iso_packet_desc) * 128),
+		       GFP_KERNEL);
+	if (!kurb)
+		goto out;
+
+	err = -EFAULT;
+	if (get_urb32(kurb, uurb))
+		goto out;
+
+	err = get_urb32_isoframes(kurb, uurb);
+	if (err)
+		goto out;
+
+	err = -EFAULT;
+	if (__get_user(udata, &uurb->buffer))
+		goto out;
+	uptr = (void *) A(udata);
+
+	err = -ENOMEM;
+	buflen = kurb->buffer_length;
+	kptr = kmalloc(buflen, GFP_KERNEL);
+	if (!kptr)
+		goto out;
+
+	kurb->buffer = kptr;
+
+	err = -EFAULT;
+	if (copy_from_user(kptr, uptr, buflen))
+		goto out_kptr;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, USBDEVFS_SUBMITURB, (unsigned long) kurb);
+	set_fs(old_fs);
+
+	if (err >= 0) {
+		/* XXX Shit, this doesn't work for async URBs :-( XXX */
+		if (put_urb32(kurb, uurb)) {
+			err = -EFAULT;
+		} else if ((kurb->endpoint & USB_DIR_IN) != 0) {
+			if (copy_to_user(uptr, kptr, buflen))
+				err = -EFAULT;
+		}
+	}
+
+out_kptr:
+	kfree(kptr);
+
+out:
+	kfree(kurb);
+	return err;
+}
+#endif
+
+#define USBDEVFS_REAPURB32         _IOW('U', 12, u32)
+#define USBDEVFS_REAPURBNDELAY32   _IOW('U', 13, u32)
+
+static int do_usbdevfs_reapurb(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs;
+	void *kptr;
+	int err;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd,
+			(cmd == USBDEVFS_REAPURB32 ?
+			 USBDEVFS_REAPURB :
+			 USBDEVFS_REAPURBNDELAY),
+			(unsigned long) &kptr);
+	set_fs(old_fs);
+
+	if (err >= 0 &&
+	    put_user(((u32)(long)kptr), (u32 *) A(arg)))
+		err = -EFAULT;
+
+	return err;
+}
+
+struct usbdevfs_disconnectsignal32 {
+	unsigned int signr;
+	u32 context;
+};
+
+#define USBDEVFS_DISCSIGNAL32      _IOR('U', 14, struct usbdevfs_disconnectsignal32)
+
+static int do_usbdevfs_discsignal(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct usbdevfs_disconnectsignal kdis;
+	struct usbdevfs_disconnectsignal32 *udis;
+	mm_segment_t old_fs;
+	u32 uctx;
+	int err;
+
+	udis = (struct usbdevfs_disconnectsignal32 *) arg;
+
+	if (get_user(kdis.signr, &udis->signr) ||
+	    __get_user(uctx, &udis->context))
+		return -EFAULT;
+
+	kdis.context = (void *) (long)uctx;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, USBDEVFS_DISCSIGNAL, (unsigned long) &kdis);
+	set_fs(old_fs);
+
+	return err;
+}
+
+struct mtd_oob_buf32 {
+	u32 start;
+	u32 length;
+	u32 ptr;	/* unsigned char* */
+};
+
+#define MEMWRITEOOB32 	_IOWR('M',3,struct mtd_oob_buf32)
+#define MEMREADOOB32 	_IOWR('M',4,struct mtd_oob_buf32)
+
+static int mtd_rw_oob(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t 			old_fs 	= get_fs();
+	struct mtd_oob_buf32	*uarg 	= (struct mtd_oob_buf32 *)arg;
+	struct mtd_oob_buf		karg;
+	u32 tmp;
+	char *ptr;
+	int ret;
+
+	if (get_user(karg.start, &uarg->start) 		||
+	    get_user(karg.length, &uarg->length)	||
+	    get_user(tmp, &uarg->ptr))
+		return -EFAULT;
+
+	ptr = (char *)A(tmp);
+	if (0 >= karg.length) 
+		return -EINVAL;
+
+	karg.ptr = kmalloc(karg.length, GFP_KERNEL);
+	if (NULL == karg.ptr)
+		return -ENOMEM;
+
+	if (copy_from_user(karg.ptr, ptr, karg.length)) {
+		kfree(karg.ptr);
+		return -EFAULT;
+	}
+
+	set_fs(KERNEL_DS);
+	if (MEMREADOOB32 == cmd) 
+		ret = sys_ioctl(fd, MEMREADOOB, (unsigned long)&karg);
+	else if (MEMWRITEOOB32 == cmd)
+		ret = sys_ioctl(fd, MEMWRITEOOB, (unsigned long)&karg);
+	else
+		ret = -EINVAL;
+	set_fs(old_fs);
+
+	if (0 == ret && cmd == MEMREADOOB32) {
+		ret = copy_to_user(ptr, karg.ptr, karg.length);
+		ret |= put_user(karg.start, &uarg->start);
+		ret |= put_user(karg.length, &uarg->length);
+	}
+
+	kfree(karg.ptr);
+	return ((0 == ret) ? 0 : -EFAULT);
+}	
+
+/* /proc/mtrr ioctls */
+
+
+struct mtrr_sentry32
+{
+    unsigned int base;    /*  Base address     */
+    unsigned int size;    /*  Size of region   */
+    unsigned int type;     /*  Type of region   */
+};
+
+struct mtrr_gentry32
+{
+    unsigned int regnum;   /*  Register number  */
+    unsigned int base;    /*  Base address     */
+    unsigned int size;    /*  Size of region   */
+    unsigned int type;     /*  Type of region   */
+};
+
+#define	MTRR_IOCTL_BASE	'M'
+
+#define MTRRIOC32_ADD_ENTRY        _IOW(MTRR_IOCTL_BASE,  0, struct mtrr_sentry32)
+#define MTRRIOC32_SET_ENTRY        _IOW(MTRR_IOCTL_BASE,  1, struct mtrr_sentry32)
+#define MTRRIOC32_DEL_ENTRY        _IOW(MTRR_IOCTL_BASE,  2, struct mtrr_sentry32)
+#define MTRRIOC32_GET_ENTRY        _IOWR(MTRR_IOCTL_BASE, 3, struct mtrr_gentry32)
+#define MTRRIOC32_KILL_ENTRY       _IOW(MTRR_IOCTL_BASE,  4, struct mtrr_sentry32)
+#define MTRRIOC32_ADD_PAGE_ENTRY   _IOW(MTRR_IOCTL_BASE,  5, struct mtrr_sentry32)
+#define MTRRIOC32_SET_PAGE_ENTRY   _IOW(MTRR_IOCTL_BASE,  6, struct mtrr_sentry32)
+#define MTRRIOC32_DEL_PAGE_ENTRY   _IOW(MTRR_IOCTL_BASE,  7, struct mtrr_sentry32)
+#define MTRRIOC32_GET_PAGE_ENTRY   _IOWR(MTRR_IOCTL_BASE, 8, struct mtrr_gentry32)
+#define MTRRIOC32_KILL_PAGE_ENTRY  _IOW(MTRR_IOCTL_BASE,  9, struct mtrr_sentry32)
+
+
+static int mtrr_ioctl32(unsigned int fd, unsigned int cmd, unsigned long arg)
+{ 
+	struct mtrr_gentry g;
+	struct mtrr_sentry s;
+	int get = 0, err = 0; 
+	struct mtrr_gentry32 *g32 = (struct mtrr_gentry32 *)arg; 
+	mm_segment_t oldfs = get_fs(); 
+
+	switch (cmd) { 
+#define SET(x) case MTRRIOC32_ ## x ## _ENTRY: cmd = MTRRIOC_ ## x ## _ENTRY; break 
+#define GET(x) case MTRRIOC32_ ## x ## _ENTRY: cmd = MTRRIOC_ ## x ## _ENTRY; get=1; break
+		SET(ADD);
+		SET(SET); 
+		SET(DEL);
+		GET(GET); 
+		SET(KILL);
+		SET(ADD_PAGE); 
+		SET(SET_PAGE); 
+		SET(DEL_PAGE); 
+		GET(GET_PAGE); 
+		SET(KILL_PAGE); 
+	} 
+	
+	if (get) { 
+		err = get_user(g.regnum, &g32->regnum);
+		err |= get_user(g.base, &g32->base);
+		err |= get_user(g.size, &g32->size);
+		err |= get_user(g.type, &g32->type); 
+
+		arg = (unsigned long)&g; 
+	} else { 
+		struct mtrr_sentry32 *s32 = (struct mtrr_sentry32 *)arg;
+		err = get_user(s.base, &s32->base);
+		err |= get_user(s.size, &s32->size);
+		err |= get_user(s.type, &s32->type);
+
+		arg = (unsigned long)&s; 
+	} 
+	if (err) return err;
+	
+	set_fs(KERNEL_DS); 
+	err = sys_ioctl(fd, cmd, arg); 
+	set_fs(oldfs); 
+		
+	if (!err && get) { 
+		err = put_user(g.base, &g32->base);
+		err |= put_user(g.size, &g32->size);
+		err |= put_user(g.regnum, &g32->regnum);
+		err |= put_user(g.type, &g32->type); 
+	} 
+	return err;
+} 
+
 struct ioctl_trans {
 	unsigned long cmd;
 	int (*handler)(unsigned int, unsigned int, unsigned long, struct file * filp);
@@ -3260,7 +3619,6 @@
 COMPATIBLE_IOCTL(TCSETSW)
 COMPATIBLE_IOCTL(TCSETSF)
 COMPATIBLE_IOCTL(TIOCLINUX)
-HANDLE_IOCTL(TIOCGDEV, tiocgdev)
 /* Little t */
 COMPATIBLE_IOCTL(TIOCGETD)
 COMPATIBLE_IOCTL(TIOCSETD)
@@ -3285,6 +3643,7 @@
 COMPATIBLE_IOCTL(TIOCGPTN)
 COMPATIBLE_IOCTL(TIOCSPTLCK)
 COMPATIBLE_IOCTL(TIOCSERGETLSR)
+/* Big F */
 COMPATIBLE_IOCTL(FBIOGET_VSCREENINFO)
 COMPATIBLE_IOCTL(FBIOPUT_VSCREENINFO)
 COMPATIBLE_IOCTL(FBIOPAN_DISPLAY)
@@ -3344,7 +3703,6 @@
 COMPATIBLE_IOCTL(BLKFRASET)
 COMPATIBLE_IOCTL(BLKSECTSET)
 COMPATIBLE_IOCTL(BLKSSZGET)
-
 /* RAID */
 COMPATIBLE_IOCTL(RAID_VERSION)
 COMPATIBLE_IOCTL(GET_ARRAY_INFO)
@@ -3365,7 +3723,6 @@
 COMPATIBLE_IOCTL(STOP_ARRAY)
 COMPATIBLE_IOCTL(STOP_ARRAY_RO)
 COMPATIBLE_IOCTL(RESTART_ARRAY_RW)
-
 /* Big K */
 COMPATIBLE_IOCTL(PIO_FONT)
 COMPATIBLE_IOCTL(GIO_FONT)
@@ -3387,6 +3744,7 @@
 COMPATIBLE_IOCTL(KDSKBSENT)
 COMPATIBLE_IOCTL(KDGKBDIACR)
 COMPATIBLE_IOCTL(KDSKBDIACR)
+COMPATIBLE_IOCTL(KDKBDREP)
 COMPATIBLE_IOCTL(KDGKBLED)
 COMPATIBLE_IOCTL(KDSKBLED)
 COMPATIBLE_IOCTL(KDGETLED)
@@ -3406,6 +3764,14 @@
 COMPATIBLE_IOCTL(SCSI_IOCTL_TAGGED_DISABLE)
 COMPATIBLE_IOCTL(SCSI_IOCTL_GET_BUS_NUMBER)
 COMPATIBLE_IOCTL(SCSI_IOCTL_SEND_COMMAND)
+COMPATIBLE_IOCTL(SCSI_IOCTL_PROBE_HOST)
+COMPATIBLE_IOCTL(SCSI_IOCTL_GET_PCI)
+/* 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)
@@ -3419,7 +3785,8 @@
 COMPATIBLE_IOCTL(VT_RESIZEX)
 COMPATIBLE_IOCTL(VT_LOCKSWITCH)
 COMPATIBLE_IOCTL(VT_UNLOCKSWITCH)
-/* Little v, the video4linux ioctls */
+/* Little v */
+/* Little v, the video4linux ioctls (conflict?) */
 COMPATIBLE_IOCTL(VIDIOCGCAP)
 COMPATIBLE_IOCTL(VIDIOCGCHAN)
 COMPATIBLE_IOCTL(VIDIOCSCHAN)
@@ -3459,11 +3826,6 @@
 COMPATIBLE_IOCTL(RTC_SET_TIME)
 COMPATIBLE_IOCTL(RTC_WKALM_SET)
 COMPATIBLE_IOCTL(RTC_WKALM_RD)
-HANDLE_IOCTL(RTC_IRQP_READ,  rtc32_ioctl)
-HANDLE_IOCTL(RTC_IRQP_READ32,rtc32_ioctl)
-HANDLE_IOCTL(RTC_IRQP_SET32, rtc32_ioctl)
-HANDLE_IOCTL(RTC_EPOCH_READ32, rtc32_ioctl)
-HANDLE_IOCTL(RTC_EPOCH_SET32, rtc32_ioctl)
 /* Little m */
 COMPATIBLE_IOCTL(MTIOCTOP)
 /* Socket level stuff */
@@ -3485,6 +3847,11 @@
 COMPATIBLE_IOCTL(SIOCDRARP)
 COMPATIBLE_IOCTL(SIOCADDDLCI)
 COMPATIBLE_IOCTL(SIOCDELDLCI)
+COMPATIBLE_IOCTL(SIOCGMIIPHY)
+COMPATIBLE_IOCTL(SIOCGMIIREG)
+COMPATIBLE_IOCTL(SIOCSMIIREG)
+COMPATIBLE_IOCTL(SIOCGIFVLAN)
+COMPATIBLE_IOCTL(SIOCSIFVLAN)
 /* SG stuff */
 COMPATIBLE_IOCTL(SG_SET_TIMEOUT)
 COMPATIBLE_IOCTL(SG_GET_TIMEOUT)
@@ -3506,7 +3873,6 @@
 COMPATIBLE_IOCTL(SG_GET_VERSION_NUM)
 COMPATIBLE_IOCTL(SG_NEXT_CMD_LEN)
 COMPATIBLE_IOCTL(SG_SCSI_RESET)
-COMPATIBLE_IOCTL(SG_IO)
 COMPATIBLE_IOCTL(SG_GET_REQUEST_TABLE)
 COMPATIBLE_IOCTL(SG_SET_KEEP_ORPHAN)
 COMPATIBLE_IOCTL(SG_GET_KEEP_ORPHAN)
@@ -3524,10 +3890,14 @@
 COMPATIBLE_IOCTL(PPPIOCGXASYNCMAP)
 COMPATIBLE_IOCTL(PPPIOCSXASYNCMAP)
 COMPATIBLE_IOCTL(PPPIOCXFERUNIT)
+/* PPPIOCSCOMPRESS is translated */
 COMPATIBLE_IOCTL(PPPIOCGNPMODE)
 COMPATIBLE_IOCTL(PPPIOCSNPMODE)
 COMPATIBLE_IOCTL(PPPIOCGDEBUG)
 COMPATIBLE_IOCTL(PPPIOCSDEBUG)
+/* PPPIOCSPASS is translated */
+/* PPPIOCSACTIVE is translated */
+/* PPPIOCGIDLE is translated */
 COMPATIBLE_IOCTL(PPPIOCNEWUNIT)
 COMPATIBLE_IOCTL(PPPIOCATTACH)
 COMPATIBLE_IOCTL(PPPIOCDETACH)
@@ -3537,8 +3907,10 @@
 COMPATIBLE_IOCTL(PPPIOCATTCHAN)
 COMPATIBLE_IOCTL(PPPIOCGCHAN)
 /* PPPOX */
-COMPATIBLE_IOCTL(PPPOEIOCSFWD);
-COMPATIBLE_IOCTL(PPPOEIOCDFWD);
+COMPATIBLE_IOCTL(PPPOEIOCSFWD)
+COMPATIBLE_IOCTL(PPPOEIOCDFWD)
+/* LP */
+COMPATIBLE_IOCTL(LPGETSTATUS)
 /* CDROM stuff */
 COMPATIBLE_IOCTL(CDROMPAUSE)
 COMPATIBLE_IOCTL(CDROMRESUME)
@@ -3570,9 +3942,15 @@
 COMPATIBLE_IOCTL(CDROM_LOCKDOOR)
 COMPATIBLE_IOCTL(CDROM_DEBUG)
 COMPATIBLE_IOCTL(CDROM_GET_CAPABILITY)
+/* DVD ioctls */
+COMPATIBLE_IOCTL(DVD_READ_STRUCT)
+COMPATIBLE_IOCTL(DVD_WRITE_STRUCT)
+COMPATIBLE_IOCTL(DVD_AUTH)
 /* Big L */
 COMPATIBLE_IOCTL(LOOP_SET_FD)
 COMPATIBLE_IOCTL(LOOP_CLR_FD)
+/* Big A */
+/* sparc only */
 /* Big Q for sound/OSS */
 COMPATIBLE_IOCTL(SNDCTL_SEQ_RESET)
 COMPATIBLE_IOCTL(SNDCTL_SEQ_SYNC)
@@ -3776,64 +4154,68 @@
 COMPATIBLE_IOCTL(LV_BMAP)
 COMPATIBLE_IOCTL(LV_SNAPSHOT_USE_RATE)
 #endif /* LVM */
-#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
-COMPATIBLE_IOCTL(DRM_IOCTL_GET_MAGIC)
-COMPATIBLE_IOCTL(DRM_IOCTL_IRQ_BUSID)
-COMPATIBLE_IOCTL(DRM_IOCTL_AUTH_MAGIC)
-COMPATIBLE_IOCTL(DRM_IOCTL_BLOCK)
-COMPATIBLE_IOCTL(DRM_IOCTL_UNBLOCK)
-COMPATIBLE_IOCTL(DRM_IOCTL_CONTROL)
-COMPATIBLE_IOCTL(DRM_IOCTL_ADD_BUFS)
-COMPATIBLE_IOCTL(DRM_IOCTL_MARK_BUFS)
-COMPATIBLE_IOCTL(DRM_IOCTL_ADD_CTX)
-COMPATIBLE_IOCTL(DRM_IOCTL_RM_CTX)
-COMPATIBLE_IOCTL(DRM_IOCTL_MOD_CTX)
-COMPATIBLE_IOCTL(DRM_IOCTL_GET_CTX)
-COMPATIBLE_IOCTL(DRM_IOCTL_SWITCH_CTX)
-COMPATIBLE_IOCTL(DRM_IOCTL_NEW_CTX)
-COMPATIBLE_IOCTL(DRM_IOCTL_ADD_DRAW)
-COMPATIBLE_IOCTL(DRM_IOCTL_RM_DRAW)
-COMPATIBLE_IOCTL(DRM_IOCTL_LOCK)
-COMPATIBLE_IOCTL(DRM_IOCTL_UNLOCK)
-COMPATIBLE_IOCTL(DRM_IOCTL_FINISH)
-#endif /* DRM */
 #ifdef CONFIG_AUTOFS_FS
-COMPATIBLE_IOCTL(AUTOFS_IOC_READY);
-COMPATIBLE_IOCTL(AUTOFS_IOC_FAIL);
-COMPATIBLE_IOCTL(AUTOFS_IOC_CATATONIC);
-COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOVER);
-COMPATIBLE_IOCTL(AUTOFS_IOC_SETTIMEOUT);
-COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE);
+COMPATIBLE_IOCTL(AUTOFS_IOC_READY)
+COMPATIBLE_IOCTL(AUTOFS_IOC_FAIL)
+COMPATIBLE_IOCTL(AUTOFS_IOC_CATATONIC)
+COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOVER)
+COMPATIBLE_IOCTL(AUTOFS_IOC_SETTIMEOUT)
+COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE)
 #endif
 #ifdef CONFIG_RTC
-COMPATIBLE_IOCTL(RTC_AIE_ON);
-COMPATIBLE_IOCTL(RTC_AIE_OFF);
-COMPATIBLE_IOCTL(RTC_UIE_ON);
-COMPATIBLE_IOCTL(RTC_UIE_OFF);
-COMPATIBLE_IOCTL(RTC_PIE_ON);
-COMPATIBLE_IOCTL(RTC_PIE_OFF);
-COMPATIBLE_IOCTL(RTC_WIE_ON);
-COMPATIBLE_IOCTL(RTC_WIE_OFF);
-COMPATIBLE_IOCTL(RTC_ALM_SET);
-COMPATIBLE_IOCTL(RTC_ALM_READ);
-COMPATIBLE_IOCTL(RTC_RD_TIME);
-COMPATIBLE_IOCTL(RTC_SET_TIME);
-COMPATIBLE_IOCTL(RTC_IRQP_READ);
-COMPATIBLE_IOCTL(RTC_IRQP_SET);
-COMPATIBLE_IOCTL(RTC_EPOCH_READ);
-COMPATIBLE_IOCTL(RTC_EPOCH_SET);
-COMPATIBLE_IOCTL(RTC_WKALM_SET);
-COMPATIBLE_IOCTL(RTC_WKALM_RD);
+COMPATIBLE_IOCTL(RTC_AIE_ON)
+COMPATIBLE_IOCTL(RTC_AIE_OFF)
+COMPATIBLE_IOCTL(RTC_UIE_ON)
+COMPATIBLE_IOCTL(RTC_UIE_OFF)
+COMPATIBLE_IOCTL(RTC_PIE_ON)
+COMPATIBLE_IOCTL(RTC_PIE_OFF)
+COMPATIBLE_IOCTL(RTC_WIE_ON)
+COMPATIBLE_IOCTL(RTC_WIE_OFF)
+COMPATIBLE_IOCTL(RTC_ALM_SET)
+COMPATIBLE_IOCTL(RTC_ALM_READ)
+COMPATIBLE_IOCTL(RTC_RD_TIME)
+COMPATIBLE_IOCTL(RTC_SET_TIME)
+COMPATIBLE_IOCTL(RTC_WKALM_SET)
+COMPATIBLE_IOCTL(RTC_WKALM_RD)
 #endif
-HANDLE_IOCTL(REISERFS_IOC_UNPACK32, reiserfs_ioctl32);
-HANDLE_IOCTL(VFAT_IOCTL_READDIR_BOTH32, vfat_ioctl32);
-HANDLE_IOCTL(VFAT_IOCTL_READDIR_SHORT32, vfat_ioctl32);
-/* serial driver */ 
-HANDLE_IOCTL(TIOCGSERIAL, serial_struct_ioctl);
-HANDLE_IOCTL(TIOCSSERIAL, serial_struct_ioctl);
-/* elevator */
-COMPATIBLE_IOCTL(BLKELVGET)
-COMPATIBLE_IOCTL(BLKELVSET)
+/* Big W */
+/* WIOC_GETSUPPORT not yet implemented -E */
+COMPATIBLE_IOCTL(WDIOC_GETSTATUS)
+COMPATIBLE_IOCTL(WDIOC_GETBOOTSTATUS)
+COMPATIBLE_IOCTL(WDIOC_GETTEMP)
+COMPATIBLE_IOCTL(WDIOC_SETOPTIONS)
+COMPATIBLE_IOCTL(WDIOC_KEEPALIVE)
+#if 0 /* sparc only ? */
+COMPATIBLE_IOCTL(WIOCSTART)
+COMPATIBLE_IOCTL(WIOCSTOP)
+COMPATIBLE_IOCTL(WIOCGSTAT)
+#endif
+/* 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(HCIGETDEVLIST)
+COMPATIBLE_IOCTL(HCIGETDEVINFO)
+COMPATIBLE_IOCTL(HCIGETCONNLIST)
+COMPATIBLE_IOCTL(HCIGETCONNINFO)
+COMPATIBLE_IOCTL(HCISETRAW)
+COMPATIBLE_IOCTL(HCISETSCAN)
+COMPATIBLE_IOCTL(HCISETAUTH)
+COMPATIBLE_IOCTL(HCISETENCRYPT)
+COMPATIBLE_IOCTL(HCISETPTYPE)
+COMPATIBLE_IOCTL(HCISETLINKPOL)
+COMPATIBLE_IOCTL(HCISETLINKMODE)
+COMPATIBLE_IOCTL(HCISETACLMTU)
+COMPATIBLE_IOCTL(HCISETSCOMTU)
+COMPATIBLE_IOCTL(HCIINQUIRY)
 /* Misc. */
 COMPATIBLE_IOCTL(0x41545900)		/* ATYIO_CLKR */
 COMPATIBLE_IOCTL(0x41545901)		/* ATYIO_CLKW */
@@ -3841,8 +4223,46 @@
 COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_IO)
 COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_MEM)
 COMPATIBLE_IOCTL(PCIIOC_WRITE_COMBINE)
+COMPATIBLE_IOCTL(0x4B50);   /* KDGHWCLK - not in the kernel, but don't complain */
+COMPATIBLE_IOCTL(0x4B51);   /* KDSHWCLK - not in the kernel, but don't complain */
+/* USB */
+COMPATIBLE_IOCTL(USBDEVFS_RESETEP)
+COMPATIBLE_IOCTL(USBDEVFS_SETINTERFACE)
+COMPATIBLE_IOCTL(USBDEVFS_SETCONFIGURATION)
+COMPATIBLE_IOCTL(USBDEVFS_GETDRIVER)
+COMPATIBLE_IOCTL(USBDEVFS_DISCARDURB)
+COMPATIBLE_IOCTL(USBDEVFS_CLAIMINTERFACE)
+COMPATIBLE_IOCTL(USBDEVFS_RELEASEINTERFACE)
+COMPATIBLE_IOCTL(USBDEVFS_CONNECTINFO)
+COMPATIBLE_IOCTL(USBDEVFS_HUB_PORTINFO)
+COMPATIBLE_IOCTL(USBDEVFS_RESET)
+COMPATIBLE_IOCTL(USBDEVFS_CLEAR_HALT)
+/* MTD */
+COMPATIBLE_IOCTL(MEMGETINFO)
+COMPATIBLE_IOCTL(MEMERASE)
+COMPATIBLE_IOCTL(MEMLOCK)
+COMPATIBLE_IOCTL(MEMUNLOCK)
+COMPATIBLE_IOCTL(MEMGETREGIONCOUNT)
+COMPATIBLE_IOCTL(MEMGETREGIONINFO)
+/* NBD */
+COMPATIBLE_IOCTL(NBD_SET_SOCK)
+COMPATIBLE_IOCTL(NBD_SET_BLKSIZE)
+COMPATIBLE_IOCTL(NBD_SET_SIZE)
+COMPATIBLE_IOCTL(NBD_DO_IT)
+COMPATIBLE_IOCTL(NBD_CLEAR_SOCK)
+COMPATIBLE_IOCTL(NBD_CLEAR_QUE)
+COMPATIBLE_IOCTL(NBD_PRINT_DEBUG)
+COMPATIBLE_IOCTL(NBD_SET_SIZE_BLOCKS)
+COMPATIBLE_IOCTL(NBD_DISCONNECT)
 /* And these ioctls need translation */
+HANDLE_IOCTL(TIOCGDEV, tiocgdev)
+HANDLE_IOCTL(TIOCGSERIAL, serial_struct_ioctl)
+HANDLE_IOCTL(TIOCSSERIAL, serial_struct_ioctl)
+HANDLE_IOCTL(MEMREADOOB32, mtd_rw_oob)
+HANDLE_IOCTL(MEMWRITEOOB32, mtd_rw_oob)
+#ifdef CONFIG_NET
 HANDLE_IOCTL(SIOCGIFNAME, dev_ifname32)
+#endif
 HANDLE_IOCTL(SIOCGIFCONF, dev_ifconf)
 HANDLE_IOCTL(SIOCGIFFLAGS, dev_ifsioc)
 HANDLE_IOCTL(SIOCSIFFLAGS, dev_ifsioc)
@@ -3869,14 +4289,26 @@
 HANDLE_IOCTL(SIOCSIFNETMASK, dev_ifsioc)
 HANDLE_IOCTL(SIOCSIFPFLAGS, dev_ifsioc)
 HANDLE_IOCTL(SIOCGIFPFLAGS, dev_ifsioc)
-HANDLE_IOCTL(SIOCGPPPSTATS, dev_ifsioc)
-HANDLE_IOCTL(SIOCGPPPCSTATS, dev_ifsioc)
-HANDLE_IOCTL(SIOCGPPPVER, dev_ifsioc)
 HANDLE_IOCTL(SIOCGIFTXQLEN, dev_ifsioc)
 HANDLE_IOCTL(SIOCSIFTXQLEN, dev_ifsioc)
 HANDLE_IOCTL(SIOCETHTOOL, ethtool_ioctl)
+HANDLE_IOCTL(SIOCBONDENSLAVE, bond_ioctl)
+HANDLE_IOCTL(SIOCBONDRELEASE, bond_ioctl)
+HANDLE_IOCTL(SIOCBONDSETHWADDR, bond_ioctl)
+HANDLE_IOCTL(SIOCBONDSLAVEINFOQUERY, bond_ioctl)
+HANDLE_IOCTL(SIOCBONDINFOQUERY, bond_ioctl)
+HANDLE_IOCTL(SIOCBONDCHANGEACTIVE, bond_ioctl)
 HANDLE_IOCTL(SIOCADDRT, routing_ioctl)
 HANDLE_IOCTL(SIOCDELRT, routing_ioctl)
+/* realtime device */
+HANDLE_IOCTL(RTC_IRQP_READ,  rtc32_ioctl)
+HANDLE_IOCTL(RTC_IRQP_READ32,rtc32_ioctl)
+HANDLE_IOCTL(RTC_IRQP_SET32, rtc32_ioctl)
+HANDLE_IOCTL(RTC_EPOCH_READ32, rtc32_ioctl)
+HANDLE_IOCTL(RTC_EPOCH_SET32, rtc32_ioctl)
+HANDLE_IOCTL(REISERFS_IOC_UNPACK32, reiserfs_ioctl32)
+HANDLE_IOCTL(VFAT_IOCTL_READDIR_BOTH32, vfat_ioctl32)
+HANDLE_IOCTL(VFAT_IOCTL_READDIR_SHORT32, vfat_ioctl32)
 /* Raw devices */
 HANDLE_IOCTL(RAW_SETBIND, raw_ioctl)
 /* Note SIOCRTMSG is no longer, so this is safe and * the user would have seen just an -EINVAL anyways. */
@@ -3888,6 +4320,7 @@
 HANDLE_IOCTL(0x1260, broken_blkgetsize)
 HANDLE_IOCTL(BLKFRAGET, w_long)
 HANDLE_IOCTL(BLKSECTGET, w_long)
+HANDLE_IOCTL(FBIOGET_FSCREENINFO, fb_ioctl_trans)
 HANDLE_IOCTL(BLKPG, blkpg_ioctl_trans)
 HANDLE_IOCTL(FBIOGETCMAP, fb_ioctl_trans)
 HANDLE_IOCTL(FBIOPUTCMAP, fb_ioctl_trans)
@@ -3907,8 +4340,11 @@
 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(PPPIOCSPASS32, ppp_sock_fprog_ioctl_trans)
+HANDLE_IOCTL(PPPIOCSACTIVE32, ppp_sock_fprog_ioctl_trans)
 HANDLE_IOCTL(MTIOCGET32, mt_ioctl_trans)
 HANDLE_IOCTL(MTIOCPOS32, mt_ioctl_trans)
 HANDLE_IOCTL(MTIOCGETCONFIG32, mt_ioctl_trans)
@@ -3982,20 +4418,37 @@
 HANDLE_IOCTL(LV_STATUS_BYINDEX, do_lvm_ioctl)
 HANDLE_IOCTL(PV_CHANGE, do_lvm_ioctl)
 HANDLE_IOCTL(PV_STATUS, do_lvm_ioctl)
+HANDLE_IOCTL(VG_CREATE_OLD, do_lvm_ioctl)
+HANDLE_IOCTL(LV_STATUS_BYDEV, do_lvm_ioctl)
 #endif /* LVM */
-#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
-HANDLE_IOCTL(DRM32_IOCTL_VERSION, drm32_version);
-HANDLE_IOCTL(DRM32_IOCTL_GET_UNIQUE, drm32_getsetunique);
-HANDLE_IOCTL(DRM32_IOCTL_SET_UNIQUE, drm32_getsetunique);
-HANDLE_IOCTL(DRM32_IOCTL_ADD_MAP, drm32_addmap);
-HANDLE_IOCTL(DRM32_IOCTL_INFO_BUFS, drm32_info_bufs);
-HANDLE_IOCTL(DRM32_IOCTL_FREE_BUFS, drm32_free_bufs);
-HANDLE_IOCTL(DRM32_IOCTL_MAP_BUFS, drm32_map_bufs);
-HANDLE_IOCTL(DRM32_IOCTL_DMA, drm32_dma);
-HANDLE_IOCTL(DRM32_IOCTL_RES_CTX, drm32_res_ctx);
-#endif /* DRM */
-HANDLE_IOCTL(VFAT_IOCTL_READDIR_BOTH32, vfat_ioctl32);
-HANDLE_IOCTL(VFAT_IOCTL_READDIR_SHORT32, vfat_ioctl32);
+/* VFAT */
+HANDLE_IOCTL(VFAT_IOCTL_READDIR_BOTH32, vfat_ioctl32)
+HANDLE_IOCTL(VFAT_IOCTL_READDIR_SHORT32, vfat_ioctl32)
+HANDLE_IOCTL(USBDEVFS_CONTROL32, do_usbdevfs_control)
+HANDLE_IOCTL(USBDEVFS_BULK32, do_usbdevfs_bulk)
+/*HANDLE_IOCTL(USBDEVFS_SUBMITURB32, do_usbdevfs_urb)*/
+HANDLE_IOCTL(USBDEVFS_REAPURB32, do_usbdevfs_reapurb)
+HANDLE_IOCTL(USBDEVFS_REAPURBNDELAY32, do_usbdevfs_reapurb)
+HANDLE_IOCTL(USBDEVFS_DISCSIGNAL32, do_usbdevfs_discsignal)
+/* take care of sizeof(sizeof()) breakage */
+/* elevator */
+HANDLE_IOCTL(BLKELVGET_32, do_blkelvget)
+HANDLE_IOCTL(BLKELVSET_32, do_blkelvset)
+/* block stuff */
+HANDLE_IOCTL(BLKBSZGET_32, do_blkbszget)
+HANDLE_IOCTL(BLKBSZSET_32, do_blkbszset)
+HANDLE_IOCTL(BLKGETSIZE64_32, do_blkgetsize64)
+/* mtrr */
+HANDLE_IOCTL(MTRRIOC32_ADD_ENTRY, mtrr_ioctl32)
+HANDLE_IOCTL(MTRRIOC32_SET_ENTRY, mtrr_ioctl32)
+HANDLE_IOCTL(MTRRIOC32_DEL_ENTRY, mtrr_ioctl32)
+HANDLE_IOCTL(MTRRIOC32_GET_ENTRY, mtrr_ioctl32)
+HANDLE_IOCTL(MTRRIOC32_KILL_ENTRY, mtrr_ioctl32)
+HANDLE_IOCTL(MTRRIOC32_ADD_PAGE_ENTRY, mtrr_ioctl32)
+HANDLE_IOCTL(MTRRIOC32_SET_PAGE_ENTRY, mtrr_ioctl32)
+HANDLE_IOCTL(MTRRIOC32_DEL_PAGE_ENTRY, mtrr_ioctl32)
+HANDLE_IOCTL(MTRRIOC32_GET_PAGE_ENTRY, mtrr_ioctl32)
+HANDLE_IOCTL(MTRRIOC32_KILL_PAGE_ENTRY, mtrr_ioctl32)
 IOCTL_TABLE_END
 
 #define IOCTL_HASHSIZE 256
@@ -4099,7 +4552,7 @@
 /* Problem: 
    This function cannot unregister duplicate ioctls, because they are not
    unique.
-   When they happen we need to extend the prototype to pass handler too. */
+   When they happen we need to extend the prototype to pass the handler too. */
 
 int unregister_ioctl32_conversion(unsigned int cmd)
 {
@@ -4150,10 +4603,10 @@
 EXPORT_SYMBOL(register_ioctl32_conversion); 
 EXPORT_SYMBOL(unregister_ioctl32_conversion); 
 
-asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+asmlinkage long sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
 	struct file * filp;
-	int error = -EBADF;
+	long error = -EBADF;
 	int (*handler)(unsigned int, unsigned int, unsigned long, struct file * filp);
 	struct ioctl_trans *t;
 
@@ -4173,13 +4626,35 @@
 	if (t) {
 		handler = t->handler;
 		error = handler(fd, cmd, arg, filp);
+	} else if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) {
+		error = siocdevprivate_ioctl(fd, cmd, arg);
 	} else {
-		static int count = 0;
-		if (++count <= 50)
-			printk("sys32_ioctl(%s:%d): Unknown cmd fd(%d) "
-			       "cmd(%08x) arg(%08x)\n",
+		static int count;
+		if (++count <= 50) { 
+			char buf[10];
+			char *path = (char *)__get_free_page(GFP_KERNEL), *fn = "?"; 
+
+			/* find the name of the device. */
+			if (path) {
+				struct file *f = fget(fd); 
+				if (f) {
+					fn = d_path(f->f_dentry, f->f_vfsmnt, 
+						    path, PAGE_SIZE);
+					fput(f);
+				}
+			}
+
+			sprintf(buf,"'%c'", (cmd>>24) & 0x3f); 
+			if (!isprint(buf[1]))
+			    sprintf(buf, "%02x", buf[1]);
+			printk("ioctl32(%s:%d): Unknown cmd fd(%d) "
+			       "cmd(%08x){%s} arg(%08x) on %s\n",
 			       current->comm, current->pid,
-			       (int)fd, (unsigned int)cmd, (unsigned int)arg);
+			       (int)fd, (unsigned int)cmd, buf, (unsigned int)arg,
+			       fn);
+			if (path) 
+				free_page((unsigned long)path); 
+		}
 		error = -EINVAL;
 	}
 out:
diff -urN linux-2.4.21-pre3/arch/x86_64/ia32/ia32_signal.c linux-2.4.21-pre4/arch/x86_64/ia32/ia32_signal.c
--- linux-2.4.21-pre3/arch/x86_64/ia32/ia32_signal.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/arch/x86_64/ia32/ia32_signal.c	Tue Jan 28 19:44:29 2003
@@ -7,7 +7,7 @@
  *  2000-06-20  Pentium III FXSR, SSE support by Gareth Hughes
  *  2000-12-*   x86-64 compatibility mode signal handling by Andi Kleen
  * 
- *  $Id: ia32_signal.c,v 1.22 2002/07/29 10:34:03 ak Exp $
+ *  $Id: ia32_signal.c,v 1.25 2002/11/28 06:05:28 ak Exp $
  */
 
 #include <linux/sched.h>
@@ -76,7 +76,7 @@
 	}
 }
 
-asmlinkage int
+asmlinkage long
 sys32_sigsuspend(int history0, int history1, old_sigset_t mask, struct pt_regs regs)
 {
 	sigset_t saveset;
@@ -97,7 +97,7 @@
 	}
 }
 
-asmlinkage int
+asmlinkage long
 sys32_sigaltstack(const stack_ia32_t *uss_ptr, stack_ia32_t *uoss_ptr, 
 				  struct pt_regs regs)
 {
@@ -173,31 +173,29 @@
 	  if (pre != cur) loadsegment(seg,pre); }
 
 	/* Reload fs and gs if they have changed in the signal handler.
-	   This does not handle long fs/gs base changes in the handler, but 
-	   does not clobber them at least in the normal case. */ 
+	   This does not handle long gs base changes in the handler, but 
+	   does not clobber it at least in the normal case. */ 
 	
 	{
 		unsigned short gs; 
+		unsigned int curgs;
 		err |= __get_user(gs, &sc->gs);
-		load_gs_index(gs); 
+		asm volatile("movl %%gs,%0" : "=r" (curgs)); 		
+		if (gs != curgs) 
+			load_gs_index(gs | 3); 
 	} 
-	RELOAD_SEG(fs,0);
-	RELOAD_SEG(ds,0);
-	RELOAD_SEG(es,0);
+	RELOAD_SEG(fs,3);
+	RELOAD_SEG(ds,3);
+	RELOAD_SEG(es,3);
 
 	COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
 	COPY(dx); COPY(cx); COPY(ip);
 	/* Don't touch extended registers */ 
 
-#if 1	/* not ready for this yet */ 
 	err |= __get_user(regs->cs, &sc->cs); 
-	regs->cs |= 2; 	
+	regs->cs |= 3; 	
 	err |= __get_user(regs->ss, &sc->ss); 
-	regs->ss |= 2; 
-#else
-	regs->cs = __USER32_CS;
-	regs->ss = __USER32_DS; 
-#endif
+	regs->ss |= 3; 
 	
 	{
 		unsigned int tmpflags;
@@ -213,7 +211,7 @@
 		buf = (struct _fpstate_ia32 *) (u64)tmp;
 		if (buf) {
 			if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
-				goto badframe;
+				return 1;
 			err |= restore_i387_ia32(current, buf, 0);
 		}
 	}
@@ -224,12 +222,9 @@
 		*peax = tmp;
 	}
 	return err;
-
-badframe:
-	return 1;
 }
 
-asmlinkage int sys32_sigreturn(struct pt_regs regs)
+asmlinkage long sys32_sigreturn(struct pt_regs regs)
 {
 	struct sigframe *frame = (struct sigframe *)(regs.rsp - 8);
 	sigset_t set;
@@ -258,7 +253,7 @@
 	return 0;
 }	
 
-asmlinkage int sys32_rt_sigreturn(struct pt_regs regs)
+asmlinkage long sys32_rt_sigreturn(struct pt_regs regs)
 {
 	struct rt_sigframe *frame = (struct rt_sigframe *)(regs.rsp - 4);
 	sigset_t set;
diff -urN linux-2.4.21-pre3/arch/x86_64/ia32/ia32entry.S linux-2.4.21-pre4/arch/x86_64/ia32/ia32entry.S
--- linux-2.4.21-pre3/arch/x86_64/ia32/ia32entry.S	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/arch/x86_64/ia32/ia32entry.S	Tue Jan 28 19:44:29 2003
@@ -3,7 +3,7 @@
  * 		
  * Copyright 2000,2001 Andi Kleen, SuSE Labs.
  * 
- * $Id: ia32entry.S,v 1.36 2002/09/12 12:55:05 ak Exp $ 		
+ * $Id: ia32entry.S,v 1.39 2003/01/14 14:29:59 ak Exp $ 		
  */		 
 
 #include <asm/calling.h>
@@ -86,6 +86,7 @@
 		
 ia32_badsys:
 	movq $-ENOSYS,RAX-ARGOFFSET(%rsp)
+	movq $0,ORIG_RAX-ARGOFFSET(%rsp)
 	jmp int_ret_from_sys_call
 
 ni_syscall:
@@ -133,7 +134,7 @@
 	.quad stub32_fork
 	.quad sys_read
 	.quad sys_write
-	.quad sys_open		/* 5 */
+	.quad sys32_open		/* 5 */
 	.quad sys_close
 	.quad sys32_waitpid
 	.quad sys_creat
@@ -176,7 +177,7 @@
 	.quad sys_brk		/* 45 */
 	.quad sys_setgid16
 	.quad sys_getgid16
-	.quad ni_syscall	/* signal */
+	.quad sys_signal
 	.quad sys_geteuid16
 	.quad sys_getegid16	/* 50 */
 	.quad sys_acct
@@ -241,7 +242,7 @@
 	.quad stub32_iopl		/* 110 */
 	.quad sys_vhangup
 	.quad ni_syscall	/* old "idle" system call */
-	.quad ni_syscall	/* vm86old */ 
+	.quad sys32_vm86_warning	/* vm86old */ 
 	.quad sys32_wait4
 	.quad sys_swapoff		/* 115 */
 	.quad sys32_sysinfo
@@ -251,7 +252,7 @@
 	.quad stub32_clone		/* 120 */
 	.quad sys_setdomainname
 	.quad sys_uname
-	.quad sys_modify_ldt
+	.quad sys32_modify_ldt
 	.quad sys32_adjtimex
 	.quad sys32_mprotect		/* 125 */
 	.quad sys32_sigprocmask
@@ -294,7 +295,7 @@
 	.quad sys_mremap
 	.quad sys_setresuid16
 	.quad sys_getresuid16	/* 165 */
-	.quad ni_syscall	/* vm86 */ 
+	.quad sys32_vm86_warning	/* vm86 */ 
 	.quad quiet_ni_syscall	/* query_module */
 	.quad sys_poll
 	.quad sys32_nfsservctl
@@ -354,34 +355,23 @@
 	.quad sys_ni_syscall    /* security */
 	.quad sys_gettid	
 	.quad sys_readahead	/* 225 */ 
-	.quad sys_setxattr
-	.quad sys_lsetxattr
-	.quad sys_fsetxattr
-	.quad sys_getxattr
-	.quad sys_lgetxattr	/* 230 */
-	.quad sys_fgetxattr
-	.quad sys_listxattr
-	.quad sys_llistxattr
-	.quad sys_flistxattr
-	.quad sys_removexattr	/* 235 */
-	.quad sys_lremovexattr
-	.quad sys_fremovexattr
-	.quad sys_tkill		/* 238 */ 
-	.quad sys_ni_syscall	/* sendfile64 */
-	.quad sys_ni_syscall	/* futex */
-	.quad sys_ni_syscall	/* sched_setaffinity */
-	.quad sys_ni_syscall	/* sched_getaffinity */
-	.quad sys_ni_syscall	/* set_threadarea */
-	.quad sys_ni_syscall	/* get_threadarea */
-	.quad sys_ni_syscall	/* io_setup */
-	.quad sys_ni_syscall	/* io_destroy */
-	.quad sys_ni_syscall	/* io_getevents */
-	.quad sys_ni_syscall	/* io_submit */
-	.quad sys_ni_syscall	/* io_cancel */
-	.quad sys_ni_syscall	/* alloc_hugepages */
-	.quad sys_ni_syscall	/* free_hugepages */
-	.quad sys_ni_syscall	/* exit_group */
-
+	.quad quiet_ni_syscall  /* xattr syscalls 226-237 */
+	.quad quiet_ni_syscall
+	.quad quiet_ni_syscall
+	.quad quiet_ni_syscall
+	.quad quiet_ni_syscall  /* 230 */
+	.quad quiet_ni_syscall  
+	.quad quiet_ni_syscall  
+	.quad quiet_ni_syscall  
+	.quad quiet_ni_syscall  
+	.quad quiet_ni_syscall  /* 235 */
+	.quad quiet_ni_syscall  
+	.quad quiet_ni_syscall  /* fremovexattr - 237 */
+	.quad sys_tkill
+	.quad quiet_ni_syscall  /* sendfile64 - 2.5 only */
+	.quad quiet_ni_syscall  /* futex */
+	.quad quiet_ni_syscall  /* sched_setaffinity */
+	.quad quiet_ni_syscall  /* sched_getaffinity */	
 ia32_syscall_end:		
 	.rept IA32_NR_syscalls-(ia32_syscall_end-ia32_sys_call_table)/8
 		.quad ni_syscall
diff -urN linux-2.4.21-pre3/arch/x86_64/ia32/ipc32.c linux-2.4.21-pre4/arch/x86_64/ia32/ipc32.c
--- linux-2.4.21-pre3/arch/x86_64/ia32/ipc32.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/arch/x86_64/ia32/ipc32.c	Tue Jan 28 19:44:29 2003
@@ -264,6 +264,9 @@
 		if (err2)
 		    err = -EFAULT;
 		break;
+	default:
+		err = -EINVAL;
+		break;
 	}
 	return err;
 }
@@ -284,7 +287,7 @@
 	if (!p)
 		return -ENOMEM;
 	err = get_user(p->mtype, &up->mtype);
-	err |= copy_from_user(p->mtext, &up->mtext, second);
+	err |= (copy_from_user(p->mtext, &up->mtext, second) ? -EFAULT : 0);
 	if (err)
 		goto out;
 	old_fs = get_fs();
diff -urN linux-2.4.21-pre3/arch/x86_64/ia32/socket32.c linux-2.4.21-pre4/arch/x86_64/ia32/socket32.c
--- linux-2.4.21-pre3/arch/x86_64/ia32/socket32.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/arch/x86_64/ia32/socket32.c	Tue Jan 28 19:44:29 2003
@@ -362,7 +362,7 @@
 	kmsg->msg_control = (void *) orig_cmsg_uptr;
 }
 
-asmlinkage int sys32_sendmsg(int fd, struct msghdr32 *user_msg, unsigned user_flags)
+asmlinkage long sys32_sendmsg(int fd, struct msghdr32 *user_msg, unsigned user_flags)
 {
 	struct socket *sock;
 	char address[MAX_SOCK_ADDR];
@@ -407,7 +407,7 @@
 	return err;
 }
 
-asmlinkage int sys32_recvmsg(int fd, struct msghdr32 *user_msg, unsigned int user_flags)
+asmlinkage long sys32_recvmsg(int fd, struct msghdr32 *user_msg, unsigned int user_flags)
 {
 	struct iovec iovstack[UIO_FASTIOV];
 	struct msghdr kern_msg;
@@ -561,7 +561,7 @@
 	return ret;
 }
 
-asmlinkage int sys32_setsockopt(int fd, int level, int optname,
+asmlinkage long sys32_setsockopt(int fd, int level, int optname,
 				char *optval, int optlen)
 {
 	if (optname == SO_ATTACH_FILTER)
@@ -664,7 +664,7 @@
 			ret = sys_shutdown(a0,a1);
 			break;
 		case SYS_SETSOCKOPT:
-			ret = sys_setsockopt(a0, a1, a[2], (char *)A(a[3]),
+			ret = sys32_setsockopt(a0, a1, a[2], (char *)A(a[3]),
 					      a[4]);
 			break;
 		case SYS_GETSOCKOPT:
diff -urN linux-2.4.21-pre3/arch/x86_64/ia32/sys_ia32.c linux-2.4.21-pre4/arch/x86_64/ia32/sys_ia32.c
--- linux-2.4.21-pre3/arch/x86_64/ia32/sys_ia32.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/arch/x86_64/ia32/sys_ia32.c	Tue Jan 28 19:44:29 2003
@@ -9,13 +9,13 @@
  * Copyright (C) 1997 		David S. Miller (davem@caip.rutgers.edu)
  * Copyright (C) 2000		Hewlett-Packard Co.
  * Copyright (C) 2000		David Mosberger-Tang <davidm@hpl.hp.com>
- * Copyright (C) 2000,2001	Andi Kleen, SuSE Labs (x86-64 port) 
+ * Copyright (C) 2000,2001,2002	Andi Kleen, SuSE Labs (x86-64 port) 
  *
  * These routines maintain argument size conversion between 32bit and 64bit
  * environment. In 2.5 most of this should be moved to a generic directory. 
  *
  * This file assumes that there is a hole at the end of user address space.
- * $Id: sys_ia32.c,v 1.42 2002/09/17 15:23:41 ak Exp $
+ * $Id: sys_ia32.c,v 1.49 2003/01/14 14:29:59 ak Exp $
  */
 
 #include <linux/config.h>
@@ -61,6 +61,7 @@
 #include <asm/semaphore.h>
 #include <asm/ipc.h>
 #include <asm/atomic.h>
+#include <asm/ldt.h>
 
 #include <net/scm.h>
 #include <net/sock.h>
@@ -225,7 +226,33 @@
 	return ret;
 }
 
+/* Don't set O_LARGEFILE implicitely. */
+asmlinkage long sys32_open(const char * filename, int flags, int mode)
+{
+	char * tmp;
+	int fd, error;
 
+	tmp = getname(filename);
+	fd = PTR_ERR(tmp);
+	if (!IS_ERR(tmp)) {
+		fd = get_unused_fd();
+		if (fd >= 0) {
+			struct file *f = filp_open(tmp, flags, mode);
+			error = PTR_ERR(f);
+			if (IS_ERR(f))
+				goto out_error;
+			fd_install(fd, f);
+		}
+out:
+		putname(tmp);
+	}
+	return fd;
+
+out_error:
+	put_unused_fd(fd);
+	fd = error;
+	goto out;
+}
 
 /*
  * Linux/i386 didn't use to be able to handle more than
@@ -242,7 +269,7 @@
 	unsigned int offset;
 };
 
-asmlinkage __u32
+asmlinkage long
 sys32_mmap(struct mmap_arg_struct *arg)
 {
 	struct mmap_arg_struct a;
@@ -261,22 +288,16 @@
 		if (!file)
 			return -EBADF;
 	}
+	
 	if (a.prot & PROT_READ) 
 		a.prot |= PROT_EXEC; 
 
-	a.flags |= MAP_32BIT;
-
 	mm = current->mm; 
 	down_write(&mm->mmap_sem); 
 	retval = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags, a.offset>>PAGE_SHIFT);
 	if (file)
 		fput(file);
 
-	/* Should not happen */
-	if (retval >= 0xFFFFFFFF && (long)retval > 0) { 
-		do_munmap(mm, retval, a.len); 
-		retval = -ENOMEM; 
-	} 
 	up_write(&mm->mmap_sem); 
 
 	return retval;
@@ -284,7 +305,7 @@
 
 extern asmlinkage long sys_mprotect(unsigned long start,size_t len,unsigned long prot);
 
-asmlinkage int sys32_mprotect(unsigned long start, size_t len, unsigned long prot)
+asmlinkage long sys32_mprotect(unsigned long start, size_t len, unsigned long prot)
 {
 	if (prot & PROT_READ) 
 		prot |= PROT_EXEC; 
@@ -503,7 +524,7 @@
     struct timeval32 it_value;
 };
 
-static inline long
+static long
 get_tv32(struct timeval *o, struct timeval32 *i)
 {
 	int err = -EFAULT; 
@@ -514,7 +535,7 @@
 	return err; 
 }
 
-static inline long
+static long
 put_tv32(struct timeval32 *o, struct timeval *i)
 {
 	int err = -EFAULT;
@@ -525,7 +546,7 @@
 	return err; 
 }
 
-static inline long
+static long
 get_it32(struct itimerval *o, struct itimerval32 *i)
 {
 	int err = -EFAULT; 
@@ -538,7 +559,7 @@
 	return err;
 }
 
-static inline long
+static long
 put_it32(struct itimerval32 *o, struct itimerval *i)
 {
 	int err = -EFAULT;
@@ -589,7 +610,8 @@
 	return 0;
 
 }
-asmlinkage unsigned long 
+
+asmlinkage long 
 sys32_alarm(unsigned int seconds)
 {
 	struct itimerval it_new, it_old;
@@ -935,22 +957,24 @@
 asmlinkage ssize_t sys_readv(unsigned long,const struct iovec *,unsigned long);
 asmlinkage ssize_t sys_writev(unsigned long,const struct iovec *,unsigned long);
 
-struct iovec *
-get_iovec32(struct iovec32 *iov32, struct iovec *iov_buf, u32 count, int type)
+static struct iovec *
+get_iovec32(struct iovec32 *iov32, struct iovec *iov_buf, u32 count, int type, int *errp)
 {
 	int i;
 	u32 buf, len;
 	struct iovec *ivp, *iov;
+	unsigned long totlen; 
 
 	/* Get the "struct iovec" from user memory */
 
 	if (!count)
 		return 0;
-	if(verify_area(VERIFY_READ, iov32, sizeof(struct iovec32)*count))
-		return(struct iovec *)0;
 	if (count > UIO_MAXIOV)
 		return(struct iovec *)0;
+	if(verify_area(VERIFY_READ, iov32, sizeof(struct iovec32)*count))
+		return(struct iovec *)0;
 	if (count > UIO_FASTIOV) {
+		*errp = -ENOMEM; 
 		iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
 		if (!iov)
 			return((struct iovec *)0);
@@ -958,24 +982,33 @@
 		iov = iov_buf;
 
 	ivp = iov;
+	totlen = 0;
 	for (i = 0; i < count; i++) {
-		if (__get_user(len, &iov32->iov_len) ||
-		    __get_user(buf, &iov32->iov_base)) {
-			if (iov != iov_buf)
-				kfree(iov);
-			return((struct iovec *)0);
-		}
-		if (verify_area(type, (void *)A(buf), len)) {
-			if (iov != iov_buf)
-				kfree(iov);
-			return((struct iovec *)0);
-		}
+		*errp = __get_user(len, &iov32->iov_len) |
+		  	__get_user(buf, &iov32->iov_base);	
+		if (*errp)
+			goto error;
+		*errp = verify_area(type, (void *)A(buf), len);
+		if (*errp) 
+			goto error;
+		/* SuS checks: */
+		*errp = -EINVAL; 
+		if ((int)len < 0)
+			goto error;
+		if ((totlen += len) >= 0x7fffffff)
+			goto error;			
 		ivp->iov_base = (void *)A(buf);
 		ivp->iov_len = (__kernel_size_t)len;
 		iov32++;
 		ivp++;
 	}
+	*errp = 0;
 	return(iov);
+
+error:
+	if (iov != iov_buf)
+		kfree(iov);
+	return NULL;
 }
 
 asmlinkage long
@@ -986,8 +1019,8 @@
 	int ret;
 	mm_segment_t old_fs = get_fs();
 
-	if ((iov = get_iovec32(vector, iovstack, count, VERIFY_WRITE)) == (struct iovec *)0)
-		return -EFAULT;
+	if ((iov = get_iovec32(vector, iovstack, count, VERIFY_WRITE, &ret)) == NULL)
+		return ret;
 	set_fs(KERNEL_DS);
 	ret = sys_readv(fd, iov, count);
 	set_fs(old_fs);
@@ -1004,8 +1037,8 @@
 	int ret;
 	mm_segment_t old_fs = get_fs();
 
-	if ((iov = get_iovec32(vector, iovstack, count, VERIFY_READ)) == (struct iovec *)0)
-		return -EFAULT;
+	if ((iov = get_iovec32(vector, iovstack, count, VERIFY_READ, &ret)) == NULL)
+		return ret;
 	set_fs(KERNEL_DS);
 	ret = sys_writev(fd, iov, count);
 	set_fs(old_fs);
@@ -1092,7 +1125,7 @@
 
 /*
  * sys_time() can be implemented in user-level using
- * sys_gettimeofday().  IA64 did this but i386 Linux did not
+ * sys_gettimeofday().  x86-64 did this but i386 Linux did not
  * so we have to implement this system call here.
  */
 asmlinkage long sys32_time(int * tloc)
@@ -1354,7 +1387,7 @@
 	return ret; 
 }
 
-int sys32_ni_syscall(int call)
+asmlinkage long sys32_ni_syscall(int call)
 { 
 	printk(KERN_INFO "IA32 syscall %d from %s not implemented\n", call,
 	       current->comm);
@@ -1812,7 +1845,7 @@
 
 
 /* warning: next two assume little endian */ 
-asmlinkage ssize_t32
+asmlinkage long
 sys32_pread(unsigned int fd, char *ubuf, __kernel_size_t32 count,
 	    u32 poslo, u32 poshi)
 {
@@ -1820,7 +1853,7 @@
 			 ((loff_t)AA(poshi) << 32) | AA(poslo));
 }
 
-asmlinkage ssize_t32
+asmlinkage long
 sys32_pwrite(unsigned int fd, char *ubuf, __kernel_size_t32 count,
 	     u32 poslo, u32 poshi)
 {
@@ -1867,6 +1900,30 @@
 	return ret;
 }
 
+extern long sys_modify_ldt(int,void*,unsigned long);
+
+asmlinkage long sys32_modify_ldt(int func, void *ptr, unsigned long bytecount)
+{
+        long ret;
+        if (func == 0x1 || func == 0x11) { 
+				struct modify_ldt_ldt_s info;
+                mm_segment_t old_fs = get_fs();
+                if (bytecount != sizeof(struct modify_ldt_ldt_s))
+                        return -EINVAL;
+                if (copy_from_user(&info, ptr, sizeof(struct modify_ldt_ldt_s)))
+                        return -EFAULT;
+                /* lm bit was undefined in the 32bit ABI and programs
+                   give it random values. Force it to zero here. */
+                info.lm = 0; 
+                set_fs(KERNEL_DS);
+                ret = sys_modify_ldt(func, &info, bytecount);
+                set_fs(old_fs);
+        }  else { 
+                ret = sys_modify_ldt(func, ptr, bytecount); 
+        }
+        return ret;
+}
+
 /* Handle adjtimex compatability. */
 
 struct timex32 {
@@ -1943,41 +2000,33 @@
 	return ret;
 }
 
-
-/* common code for old and new mmaps */
-static inline long do_mmap2(
-	unsigned long addr, unsigned long len,
+asmlinkage long sys32_mmap2(unsigned long addr, unsigned long len,
 	unsigned long prot, unsigned long flags,
 	unsigned long fd, unsigned long pgoff)
 {
-	int error = -EBADF;
+	struct mm_struct *mm = current->mm;
+	unsigned long error;
 	struct file * file = NULL;
 
 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 	if (!(flags & MAP_ANONYMOUS)) {
 		file = fget(fd);
 		if (!file)
-			goto out;
+			return -EBADF;
 	}
 
-	down_write(&current->mm->mmap_sem);
-	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-	up_write(&current->mm->mmap_sem);
+	if (prot & PROT_READ)
+		prot |= PROT_EXEC;
+
+	down_write(&mm->mmap_sem);
+	error = do_mmap_pgoff(file, addr, len, prot, flags|MAP_32BIT, pgoff);
+	up_write(&mm->mmap_sem);
 
 	if (file)
 		fput(file);
-out:
 	return error;
 }
 
-asmlinkage long sys32_mmap2(unsigned long addr, unsigned long len,
-	unsigned long prot, unsigned long flags,
-	unsigned long fd, unsigned long pgoff)
-{
-	return do_mmap2(addr, len, prot, flags, fd, pgoff);
-}
-
-
 asmlinkage long sys32_olduname(struct oldold_utsname * name)
 {
 	int error;
@@ -2024,7 +2073,7 @@
 
 extern int sys_ustat(dev_t, struct ustat *);
 
-int sys32_ustat(dev_t dev, struct ustat32 *u32p)
+asmlinkage long sys32_ustat(dev_t dev, struct ustat32 *u32p)
 {
 	struct ustat u;
 	mm_segment_t seg;
@@ -2067,7 +2116,7 @@
 	return cnt; 
 } 
 
-int sys32_execve(char *name, u32 argv, u32 envp, struct pt_regs regs)
+asmlinkage long sys32_execve(char *name, u32 argv, u32 envp, struct pt_regs regs)
 { 
 	mm_segment_t oldseg; 
 	char **buf; 
@@ -2121,12 +2170,12 @@
 	return ret; 
 } 
 
-asmlinkage int sys32_fork(struct pt_regs regs)
+asmlinkage long sys32_fork(struct pt_regs regs)
 {
 	return do_fork(SIGCHLD, regs.rsp, &regs, 0);
 }
 
-asmlinkage int sys32_clone(unsigned int clone_flags, unsigned int newsp, struct pt_regs regs)
+asmlinkage long sys32_clone(unsigned int clone_flags, unsigned int newsp, struct pt_regs regs)
 {
 	if (!newsp)
 		newsp = regs.rsp;
@@ -2143,7 +2192,7 @@
  * do not have enough call-clobbered registers to hold all
  * the information you need.
  */
-asmlinkage int sys32_vfork(struct pt_regs regs)
+asmlinkage long sys32_vfork(struct pt_regs regs)
 {
 	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.rsp, &regs, 0);
 }
@@ -2154,14 +2203,14 @@
 
 extern off_t sys_lseek (unsigned int fd, off_t offset, unsigned int origin);
 
-int sys32_lseek (unsigned int fd, int offset, unsigned int whence)
+asmlinkage long sys32_lseek (unsigned int fd, int offset, unsigned int whence)
 {
 	return sys_lseek(fd, offset, whence);
 }
 
 extern int sys_kill(pid_t pid, int sig); 
 
-int sys32_kill(int pid, int sig)
+asmlinkage long sys32_kill(int pid, int sig)
 {
 	return sys_kill(pid, sig);
 }
@@ -2306,54 +2355,6 @@
 	return err;
 }
 
-static int nfs_uud32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
-{
-	u32 uaddr;
-	int i;
-	int err;
-
-	memset(karg, 0, sizeof(*karg));
-	if(get_user(karg->ca_version, &arg32->ca32_version))
-		return -EFAULT;
-	karg->ca_umap.ug_ident = (char *)get_free_page(GFP_USER);
-	if(!karg->ca_umap.ug_ident)
-		return -ENOMEM;
-	err = get_user(uaddr, &arg32->ca32_umap.ug32_ident);
-	if(strncpy_from_user(karg->ca_umap.ug_ident,
-			     (char *)A(uaddr), PAGE_SIZE) <= 0)
-		return -EFAULT;
-	err |= __get_user(karg->ca_umap.ug_uidbase,
-		      &arg32->ca32_umap.ug32_uidbase);
-	err |= __get_user(karg->ca_umap.ug_uidlen,
-		      &arg32->ca32_umap.ug32_uidlen);
-	err |= __get_user(uaddr, &arg32->ca32_umap.ug32_udimap);
-	if (err)
-		return -EFAULT;
-	karg->ca_umap.ug_udimap = kmalloc((sizeof(uid_t) * karg->ca_umap.ug_uidlen),
-					  GFP_USER);
-	if(!karg->ca_umap.ug_udimap)
-		return -ENOMEM;
-	for(i = 0; i < karg->ca_umap.ug_uidlen; i++)
-		err |= __get_user(karg->ca_umap.ug_udimap[i],
-			      &(((__kernel_uid_t32 *)A(uaddr))[i]));
-	err |= __get_user(karg->ca_umap.ug_gidbase,
-		      &arg32->ca32_umap.ug32_gidbase);
-	err |= __get_user(karg->ca_umap.ug_uidlen,
-		      &arg32->ca32_umap.ug32_gidlen);
-	err |= __get_user(uaddr, &arg32->ca32_umap.ug32_gdimap);
-	if (err)
-		return -EFAULT;
-	karg->ca_umap.ug_gdimap = kmalloc((sizeof(gid_t) * karg->ca_umap.ug_uidlen),
-					  GFP_USER);
-	if(!karg->ca_umap.ug_gdimap)
-		return -ENOMEM;
-	for(i = 0; i < karg->ca_umap.ug_gidlen; i++)
-		err |= __get_user(karg->ca_umap.ug_gdimap[i],
-			      &(((__kernel_gid_t32 *)A(uaddr))[i]));
-
-	return err;
-}
-
 static int nfs_getfh32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
 {
 	int err;
@@ -2411,7 +2412,7 @@
 	return copy_to_user(res32, kres, sizeof(*res32));
 }
 
-int asmlinkage sys32_nfsservctl(int cmd, struct nfsctl_arg32 *arg32, union nfsctl_res32 *res32)
+long asmlinkage sys32_nfsservctl(int cmd, struct nfsctl_arg32 *arg32, union nfsctl_res32 *res32)
 {
 	struct nfsctl_arg *karg = NULL;
 	union nfsctl_res *kres = NULL;
@@ -2442,10 +2443,6 @@
 	case NFSCTL_UNEXPORT:
 		err = nfs_exp32_trans(karg, arg32);
 		break;
-	/* This one is unimplemented, be we're ready for it. */
-	case NFSCTL_UGIDUPDATE:
-		err = nfs_uud32_trans(karg, arg32);
-		break;
 	case NFSCTL_GETFH:
 		err = nfs_getfh32_trans(karg, arg32);
 		break;
@@ -2492,13 +2489,13 @@
 }
 #else /* !NFSD */
 extern asmlinkage long sys_ni_syscall(void);
-int asmlinkage sys32_nfsservctl(int cmd, void *notused, void *notused2)
+long asmlinkage sys32_nfsservctl(int cmd, void *notused, void *notused2)
 {
 	return sys_ni_syscall();
 }
 #endif
 
-int sys32_module_warning(void)
+long sys32_module_warning(void)
 { 
 	static long warn_time = -(60*HZ); 
 	if (time_before(warn_time + 60*HZ,jiffies) && strcmp(current->comm,"klogd")) { 
@@ -2509,15 +2506,27 @@
 	return -ENOSYS ;
 } 
 
+long sys32_vm86_warning(void)
+{ 
+	static long warn_time = -(60*HZ); 
+	if (time_before(warn_time + 60*HZ,jiffies)) { 
+		printk(KERN_INFO "%s: vm86 mode not supported on 64 bit kernel\n",
+		       current->comm);
+		warn_time = jiffies;
+	} 
+	return -ENOSYS ;
+} 
+
+/* This only triggers an i686 uname */
 struct exec_domain ia32_exec_domain = { 
-	name: "linux/x86",
+	name: "linux/uname-i686",
 	pers_low: PER_LINUX32,
 	pers_high: PER_LINUX32,
 };      
 
 static int __init ia32_init (void)
 {
-	printk("IA32 emulation $Id: sys_ia32.c,v 1.42 2002/09/17 15:23:41 ak Exp $\n");  
+	printk("IA32 emulation $Id: sys_ia32.c,v 1.49 2003/01/14 14:29:59 ak Exp $\n");  
 	ia32_exec_domain.signal_map = default_exec_domain.signal_map;
 	ia32_exec_domain.signal_invmap = default_exec_domain.signal_invmap;
 	register_exec_domain(&ia32_exec_domain);
diff -urN linux-2.4.21-pre3/arch/x86_64/kernel/acpitable.c linux-2.4.21-pre4/arch/x86_64/kernel/acpitable.c
--- linux-2.4.21-pre3/arch/x86_64/kernel/acpitable.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/arch/x86_64/kernel/acpitable.c	Tue Jan 28 19:44:29 2003
@@ -282,9 +282,9 @@
 		return -1;
 	}
 
-	hpet.address = hpet_tbl->addr.addrl | ((long) hpet_tbl->addr.addrh << 32);
+	hpet_address = hpet_tbl->addr.addrl | ((long) hpet_tbl->addr.addrh << 32);
 
-	printk(KERN_INFO "acpi: HPET id: %#x base: %#lx\n", hpet_tbl->id, hpet.address);
+	printk(KERN_INFO "acpi: HPET id: %#x base: %#lx\n", hpet_tbl->id, hpet_address);
 
 	return 0;
 }
diff -urN linux-2.4.21-pre3/arch/x86_64/kernel/aperture.c linux-2.4.21-pre4/arch/x86_64/kernel/aperture.c
--- linux-2.4.21-pre3/arch/x86_64/kernel/aperture.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/arch/x86_64/kernel/aperture.c	Tue Jan 28 19:44:29 2003
@@ -8,7 +8,7 @@
  * the bootmem allocator can allocate 32+MB. 
  * 
  * Copyright 2002 Andi Kleen, SuSE Labs.
- * $Id: aperture.c,v 1.2 2002/09/19 19:25:32 ak Exp $
+ * $Id: aperture.c,v 1.4 2002/11/28 06:05:58 ak Exp $
  */
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -47,10 +47,9 @@
 	aper_size = (32 * 1024 * 1024) << fallback_aper_order; 
 
 	/* 
-         * Aperture has to be naturally aligned it seems. This means an
-	 * 2GB aperture won't have much changes to succeed in the lower 4GB of 
-	 * memory. Unfortunately we cannot move it up because that would make
-	 * the IOMMU useless.
+         * Aperture has to be naturally aligned. This means an 2GB aperture won't 
+         * have much chances to find a place in the lower 4GB of memory. Unfortunately 
+         * we cannot move it up because that would make the IOMMU useless.
 	 */
 	p = __alloc_bootmem_node(nd0, aper_size, aper_size, 0); 
 	if (!p || __pa(p)+aper_size > 0xffffffff) {
@@ -105,7 +104,8 @@
 	if (!fix && !fallback_aper_force) 
 		return; 
 
-	printk("Your BIOS is broken and doesn't leave a aperture memory hole\n");
+	printk("Your BIOS doesn't leave a aperture memory hole\n");
+	printk("Please enable the IOMMU option in the BIOS setup\n"); 
 	aper_alloc = allocate_aperture(); 
 	if (!aper_alloc) 
 		return; 
diff -urN linux-2.4.21-pre3/arch/x86_64/kernel/apic.c linux-2.4.21-pre4/arch/x86_64/kernel/apic.c
--- linux-2.4.21-pre3/arch/x86_64/kernel/apic.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/arch/x86_64/kernel/apic.c	Tue Jan 28 19:44:29 2003
@@ -31,6 +31,8 @@
 #include <asm/pgalloc.h>
 #include <asm/timex.h>
 
+extern spinlock_t i8253_lock;
+
 /* Using APIC to generate smp_local_timer_interrupt? */
 int using_apic_timer = 0;
 
@@ -766,12 +768,13 @@
 	 * Wait for timer IRQ slice:
 	 */
 
-	if (hpet.address) {
+	if (hpet_address) {
 		int trigger = hpet_readl(HPET_T0_CMP);
 		while (hpet_readl(HPET_COUNTER) >= trigger);
 		while (hpet_readl(HPET_COUNTER) <  trigger);
 	} else {
 		int c1, c2;
+		spin_lock(&i8253_lock);
 		outb_p(0x00, 0x43);
 		c2 = inb_p(0x40);
 		c2 |= inb_p(0x40) << 8;
@@ -781,6 +784,7 @@
 			c2 = inb_p(0x40);
 			c2 |= inb_p(0x40) << 8;
 		} while (c2 - c1 < 300);
+		spin_unlock(&i8253_lock);
 	}
 
 	__setup_APIC_LVTT(clocks);
@@ -1018,6 +1022,7 @@
 		printk(KERN_INFO "spurious APIC interrupt on CPU#%d, %ld skipped.\n",
 		       smp_processor_id(), skipped);
 		last_warning = jiffies;
+		skipped = 0;
 	} else {
 		skipped++;
 	}
@@ -1084,9 +1089,10 @@
 	if (nmi_watchdog == NMI_LOCAL_APIC)
 		check_nmi_watchdog();
 #ifdef CONFIG_X86_IO_APIC
-	if (smp_found_config)
-		if (!skip_ioapic_setup && nr_ioapics)
+	if (smp_found_config && !skip_ioapic_setup && nr_ioapics)
 			setup_IO_APIC();
+	else
+		nr_ioapics = 0;
 #endif
 	setup_APIC_clocks();
 
diff -urN linux-2.4.21-pre3/arch/x86_64/kernel/e820.c linux-2.4.21-pre4/arch/x86_64/kernel/e820.c
--- linux-2.4.21-pre3/arch/x86_64/kernel/e820.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/arch/x86_64/kernel/e820.c	Tue Jan 28 19:44:29 2003
@@ -1,7 +1,7 @@
 /* 
  * Handle the memory map.
  * The functions here do the job until bootmem takes over.
- * $Id: e820.c,v 1.4 2002/09/19 19:25:32 ak Exp $
+ * $Id: e820.c,v 1.6 2002/10/15 09:35:16 ak Exp $
  */
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -122,27 +122,51 @@
 }
 
 /*
+ * end_pfn only includes RAM, while end_pfn_map includes all e820 entries.
+ * The direct mapping extends to end_pfn_map, so that we can directly access
+ * ACPI and other tables without having to play with fixmaps.
+ */ 
+unsigned long end_pfn_map; 
+
+/* 
+ * Last pfn which the user wants to use.
+ */
+unsigned long end_user_pfn = MAXMEM>>PAGE_SHIFT;  
+
+/*
  * Find the highest page frame number we have available
  */
+
 void __init e820_end_of_ram(void)
 {
 	int i;
 	end_pfn = 0;
+	
 	for (i = 0; i < e820.nr_map; i++) {
 		struct e820entry *ei = &e820.map[i]; 
 		unsigned long start, end;
 
-		/* count all types of areas for now to map ACPI easily */
 		start = round_up(ei->addr, PAGE_SIZE); 
 		end = round_down(ei->addr + ei->size, PAGE_SIZE); 
 		if (start >= end)
 			continue;
+		if (ei->type == E820_RAM) { 
 		if (end > end_pfn<<PAGE_SHIFT)
 			end_pfn = end>>PAGE_SHIFT;
+		} else { 
+			if (end > end_pfn_map<<PAGE_SHIFT) 
+				end_pfn_map = end>>PAGE_SHIFT;
+		} 
 	}
 
-	if (end_pfn > MAXMEM >> PAGE_SHIFT)
-		end_pfn = MAXMEM >> PAGE_SHIFT;
+	if (end_pfn > end_pfn_map) 
+		end_pfn_map = end_pfn;
+	if (end_pfn_map > MAXMEM>>PAGE_SHIFT)
+		end_pfn_map = MAXMEM>>PAGE_SHIFT;
+	if (end_pfn > end_user_pfn)
+		end_pfn = end_user_pfn;
+	if (end_pfn > end_pfn_map) 
+		end_pfn = end_pfn_map; 
 }
 
 /* 
@@ -481,7 +505,6 @@
 {
 	char c = ' ', *to = command_line, *from = COMMAND_LINE;
 	int len = 0;
-	int usermem = 0;
 
 	/* Save unparsed command line copy for /proc/cmdline */
 	memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE);
@@ -492,44 +515,23 @@
 			goto next;
 
 		/*
-		 * "mem=XXX[kKmM]" defines a memory region from HIGH_MEM
-		 * to <mem>, overriding the bios size.
-		 * "mem=XXX[KkmM]@XXX[KkmM]" defines a memory region from
-		 * <start> to <start>+<mem>, overriding the bios size.
+		 * mem=XXX[kKmM] limits kernel memory to XXX+1MB
+		 *
+		 * It would be more logical to count from 0 instead of from
+		 * HIGH_MEMORY, but we keep that for now for i386 compatibility. -AK
 		 */
 		if (!memcmp(from, "mem=", 4)) {
-			if (to != command_line)
-				to--;
-			else if (!memcmp(from+4, "exactmap", 8)) {
-				from += 8+4;
-				e820.nr_map = 0;
-				usermem = 1;
-			} else {
-				/* If the user specifies memory size, we
-				 * blow away any automatically generated
-				 * size
-				 */
-				unsigned long long start_at, mem_size;
- 
-				if (usermem == 0) {
-					/* first time in: zap the whitelist
-					 * and reinitialize it with the
-					 * standard low-memory region.
+			/* 
+			 * No support for custom mapping like i386.
+			 * The reason is that we need to read the e820 map
+			 * anyways to handle the ACPI mappings in the 
+			 * direct map.
+			 * Also on x86-64 there should be always a good e820
+			 * map. This is only an upper limit, you cannot force
+			 * usage of memory not in e820.
 					 */
-					e820.nr_map = 0;
-					usermem = 1;
-					add_memory_region(0, LOWMEMSIZE(), E820_RAM);
-				}
-				mem_size = memparse(from+4, &from);
-				if (*from == '@')
-					start_at = memparse(from+1, &from);
-				else {
-					start_at = HIGH_MEMORY;
-					mem_size -= HIGH_MEMORY;
-					usermem=0;
-				}
-				add_memory_region(start_at, mem_size, E820_RAM);
-			}
+			end_user_pfn = memparse(from+4, &from) + HIGH_MEMORY;
+			end_user_pfn >>= PAGE_SHIFT;
 		}
 #ifdef CONFIG_GART_IOMMU 
 		else if (!memcmp(from,"iommu=",6)) { 
@@ -547,8 +549,4 @@
 	}
 	*to = '\0';
 	*cmdline_p = command_line;
-	if (usermem) {
-		printk(KERN_INFO "user-defined physical RAM map:\n");
-		e820_print_map("user");
-	}
 }
diff -urN linux-2.4.21-pre3/arch/x86_64/kernel/entry.S linux-2.4.21-pre4/arch/x86_64/kernel/entry.S
--- linux-2.4.21-pre3/arch/x86_64/kernel/entry.S	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/arch/x86_64/kernel/entry.S	Tue Jan 28 19:44:29 2003
@@ -5,7 +5,7 @@
  *  Copyright (C) 2000, 2001, 2002  Andi Kleen SuSE Labs
  *  Copyright (C) 2000  Pavel Machek <pavel@suse.cz>
  * 
- *  $Id: entry.S,v 1.81 2002/09/12 12:55:25 ak Exp $		
+ *  $Id: entry.S,v 1.87 2003/01/14 14:37:08 ak Exp $		
  */
 
 /*
@@ -34,6 +34,7 @@
 #include <asm/offset.h>
 #include <asm/msr.h>
 #include <asm/unistd.h>
+#include <asm/hw_irq.h>
 
 	.code64
 
@@ -187,6 +188,7 @@
 	jmp ret_from_sys_call
 		
 badsys:
+	movq $0,ORIG_RAX-ARGOFFSET(%rsp)
 	movq $-ENOSYS,RAX-ARGOFFSET(%rsp)
 	jmp ret_from_sys_call
 
@@ -227,6 +229,7 @@
 	je   retint_restore_args_swapgs
 	sti
 	call schedule
+	# RED-PEN: can we lose signals here?
 	jmp  intret_signal_test
 	
 /* 
@@ -369,6 +372,48 @@
 	cli
 	jmp retint_with_reschedule
 		
+/* IF:off, stack contains irq number on origrax */ 	
+	.macro IRQ_ENTER	
+	cld
+	pushq %rdi
+	pushq %rsi
+	pushq %rdx
+	pushq %rcx
+	pushq %rax
+	pushq %r8
+	pushq %r9
+	pushq %r10
+	pushq %r11
+	leaq -48(%rsp),%rdi
+	testl $3,136(%rdi)
+	je 1f
+	swapgs
+1:	addl $1,%gs:pda_irqcount
+	movq %gs:pda_irqstackptr,%rax
+	cmoveq %rax,%rsp
+	pushq %rdi
+	.endm	
+
+	.macro BUILD_SMP_INTERRUPT x,v
+ENTRY(\x)
+	push $\v-256
+	IRQ_ENTER
+	call smp_\x
+	jmp ret_from_intr
+	.endm
+
+#ifdef CONFIG_SMP				
+	BUILD_SMP_INTERRUPT reschedule_interrupt,RESCHEDULE_VECTOR
+	BUILD_SMP_INTERRUPT invalidate_interrupt,INVALIDATE_TLB_VECTOR
+	BUILD_SMP_INTERRUPT call_function_interrupt,CALL_FUNCTION_VECTOR
+#endif
+#ifdef CONFIG_X86_LOCAL_APIC
+	BUILD_SMP_INTERRUPT apic_timer_interrupt,LOCAL_TIMER_VECTOR
+	BUILD_SMP_INTERRUPT error_interrupt,ERROR_APIC_VECTOR
+	BUILD_SMP_INTERRUPT spurious_interrupt,SPURIOUS_APIC_VECTOR
+#endif
+		
+		
 /*
  * Exception entry points.
  */ 		
@@ -407,8 +452,8 @@
 	je error_kernelspace
 	swapgs	
 	movl $1,%r15d	
-error_action:		
 	sti	
+error_action:
 	movq  %rdi,RDI(%rsp) 	
 	movq %rsp,%rdi
 	movq ORIG_RAX(%rsp),%rsi	/* get error code */ 
@@ -432,11 +477,15 @@
 	jmp retint_restore_args
 	
 error_reschedule:
+	cmpl $2,%r15d
+	je  error_restore_swapgs
 	sti
 	call schedule
 	jmp  error_test
 
 error_signal:	
+	cmpl $2,%r15d
+	je  error_restore_swapgs	
 	sti
 	xorq %rsi,%rsi
 	movq %rsp,%rdi
@@ -452,12 +501,37 @@
 	
 error_kernelspace:	
 	xorl %r15d,%r15d
+	/* There are two places in the kernel that can potentially fault with
+	   usergs. Handle them here. */	   
 	cmpq $iret_label,RIP(%rsp)
+	je   1f
+	cmpq $gs_change,RIP(%rsp)
 	jne  error_action
-	movl $1,%r15d
+1:	movl $2,%r15d
 	swapgs
 	jmp error_action
 
+	/* Reload gs selector with exception handling */
+	/* edi:	 new selector */ 
+ENTRY(load_gs_index)
+	pushf
+	cli
+	swapgs
+gs_change:	
+	movl %edi,%gs	
+2:	swapgs
+	popf
+	ret
+	
+	.section __ex_table,"a"
+	.align 8
+	.quad gs_change,bad_gs
+	.previous
+
+bad_gs:
+	xorl %eax,%eax
+	movl %eax,%gs
+	jmp 2b
 /*
  * Create a kernel thread.
  *
diff -urN linux-2.4.21-pre3/arch/x86_64/kernel/head.S linux-2.4.21-pre4/arch/x86_64/kernel/head.S
--- linux-2.4.21-pre3/arch/x86_64/kernel/head.S	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/arch/x86_64/kernel/head.S	Tue Jan 28 19:44:29 2003
@@ -6,7 +6,7 @@
  *  Copyright (C) 2000 Karsten Keil <kkeil@suse.de>
  *  Copyright (C) 2001,2002 Andi Kleen <ak@suse.de>
  *
- *  $Id: head.S,v 1.53 2002/07/18 09:49:42 ak Exp $
+ *  $Id: head.S,v 1.54 2002/11/14 16:26:55 ak Exp $
  */
 
 
@@ -76,13 +76,11 @@
 	/* Enable System Call */
 	btsl	$_EFER_SCE, %eax
 
-#if 0
 	/* No Execute supported? */	
 	btl	$20,%edi
 	jnc     1f
 	btsl	$_EFER_NX, %eax
 1:
-#endif
 	
 	/* Make changes effective */
 	wrmsr
diff -urN linux-2.4.21-pre3/arch/x86_64/kernel/i8259.c linux-2.4.21-pre4/arch/x86_64/kernel/i8259.c
--- linux-2.4.21-pre3/arch/x86_64/kernel/i8259.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/arch/x86_64/kernel/i8259.c	Tue Jan 28 19:44:29 2003
@@ -40,8 +40,6 @@
  * interrupt-controller happy.
  */
 
-BUILD_COMMON_IRQ()
-
 #define BI(x,y) \
 	BUILD_IRQ(x##y)
 
@@ -77,24 +75,6 @@
 #undef BUILD_16_IRQS
 #undef BI
 
-
-/*
- * The following vectors are part of the Linux architecture, there
- * is no hardware IRQ pin equivalent for them, they are triggered
- * through the ICC by us (IPIs)
- */
-#ifdef CONFIG_SMP
-BUILD_SMP_INTERRUPT(reschedule_interrupt,RESCHEDULE_VECTOR);
-BUILD_SMP_INTERRUPT(invalidate_interrupt,INVALIDATE_TLB_VECTOR);
-BUILD_SMP_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR);
-#endif
-
-#ifdef CONFIG_X86_LOCAL_APIC
-BUILD_SMP_INTERRUPT(apic_timer_interrupt,LOCAL_TIMER_VECTOR);
-BUILD_SMP_INTERRUPT(error_interrupt,ERROR_APIC_VECTOR);
-BUILD_SMP_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR);
-#endif
-
 #define IRQ(x,y) \
 	IRQ##x##y##_interrupt
 
diff -urN linux-2.4.21-pre3/arch/x86_64/kernel/ldt.c linux-2.4.21-pre4/arch/x86_64/kernel/ldt.c
--- linux-2.4.21-pre3/arch/x86_64/kernel/ldt.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/arch/x86_64/kernel/ldt.c	Tue Jan 28 19:44:29 2003
@@ -85,11 +85,6 @@
 			goto out;
 	}
 
-	me->thread.fsindex = 0; 
-	me->thread.gsindex = 0; 
-	me->thread.gs = 0; 
-	me->thread.fs = 0; 
-
 	/*
 	 * the GDT index of the LDT is allocated dynamically, and is
 	 * limited by MAX_LDT_DESCRIPTORS.
@@ -142,10 +137,8 @@
 
 	/* Install the new entry ...  */
 install:
-	write_lock(&mm->context.ldtlock);
 	*lp	= entry_1;
 	*(lp+1)	= entry_2;
-	write_unlock(&mm->context.ldtlock);
 	error = 0;
 
 out_unlock:
diff -urN linux-2.4.21-pre3/arch/x86_64/kernel/msr.c linux-2.4.21-pre4/arch/x86_64/kernel/msr.c
--- linux-2.4.21-pre3/arch/x86_64/kernel/msr.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/arch/x86_64/kernel/msr.c	Tue Jan 28 19:44:29 2003
@@ -1,4 +1,4 @@
-#ident "$Id: msr.c,v 1.7 2002/02/14 10:20:47 ak Exp $"
+#ident "$Id: msr.c,v 1.8 2003/01/10 15:17:43 ak Exp $"
 /* ----------------------------------------------------------------------- *
  *   
  *   Copyright 2000 H. Peter Anvin - All Rights Reserved
@@ -55,7 +55,7 @@
 	       "	jmp 2b\n"
 	       ".previous\n"
 	       ".section __ex_table,\"a\"\n"
-	       "	.align 4\n"
+	       "	.align 8\n"
 	       "	.quad 1b,3b\n"
 	       ".previous"
 	       : "=&bDS" (err)
@@ -76,7 +76,7 @@
 	       "	jmp 2b\n"
 	       ".previous\n"
 	       ".section __ex_table,\"a\"\n"
-	       "	.align 4\n"
+	       "	.align 8\n"
 	       "	.quad 1b,3b\n"
 	       ".previous"
 	       : "=&bDS" (err), "=a" (*eax), "=d" (*edx)
diff -urN linux-2.4.21-pre3/arch/x86_64/kernel/pci-dma.c linux-2.4.21-pre4/arch/x86_64/kernel/pci-dma.c
--- linux-2.4.21-pre3/arch/x86_64/kernel/pci-dma.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/arch/x86_64/kernel/pci-dma.c	Tue Jan 28 19:44:29 2003
@@ -37,16 +37,16 @@
  	 */
  	for (i = 0; i < nents; i++ ) {
 		struct scatterlist *s = &sg[i];
- 		if (s->address) {
+		int flush = (i == nents-1);
+		void *addr = s->address; 
+		if (addr) 
 			BUG_ON(s->page || s->offset); 
- 			s->dma_address = pci_map_single(hwdev, s->address, s->length, 
-							direction); 
- 		} else if (s->page) { 
-			s->dma_address = pci_map_page(hwdev, s->page, s->offset,
-						      s->length, direction); 
-		} else
+		else if (s->page)
+			addr = page_address(s->page) + s->offset; 
+		else
 			BUG(); 
-
+		s->dma_address = __pci_map_single(hwdev, addr, s->length,
+						  direction, flush); 
 		if (unlikely(s->dma_address == bad_dma_address))
 			goto error; 
  	}
diff -urN linux-2.4.21-pre3/arch/x86_64/kernel/pci-gart.c linux-2.4.21-pre4/arch/x86_64/kernel/pci-gart.c
--- linux-2.4.21-pre3/arch/x86_64/kernel/pci-gart.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/arch/x86_64/kernel/pci-gart.c	Tue Jan 28 19:44:29 2003
@@ -8,7 +8,7 @@
  * See Documentation/DMA-mapping.txt for the interface specification.
  * 
  * Copyright 2002 Andi Kleen, SuSE Labs.
- * $Id: pci-gart.c,v 1.12 2002/09/19 19:25:32 ak Exp $
+ * $Id: pci-gart.c,v 1.18 2002/11/30 03:46:14 ak Exp $
  */
 
 /* 
@@ -19,9 +19,12 @@
 
 possible future tuning: 
  fast path for sg streaming mappings 
- more intelligent flush strategy - flush only a single NB?
+ more intelligent flush strategy - flush only a single NB? flush only when
+ gart area fills up and alloc_iommu wraps. 
+ don't flush on allocation - need to unmap the gart area first to avoid prefetches
+ by the CPU
  move boundary between IOMMU and AGP in GART dynamically
- could use exact fit in the gart in alloc_consistent, not order of two.
+  
 */ 
 
 #include <linux/config.h>
@@ -49,7 +52,11 @@
 
 int no_iommu; 
 static int no_agp; 
+#ifdef CONFIG_IOMMU_DEBUG
 int force_mmu = 1;
+#else
+int force_mmu = 0;
+#endif
 
 extern int fallback_aper_order;
 extern int fallback_aper_force;
@@ -58,11 +65,10 @@
 static spinlock_t iommu_bitmap_lock = SPIN_LOCK_UNLOCKED;
 static unsigned long *iommu_gart_bitmap; /* guarded by iommu_bitmap_lock */
 
-#define GPTE_MASK 0xfffffff000
 #define GPTE_VALID    1
 #define GPTE_COHERENT 2
-#define GPTE_ENCODE(x,flag) (((x) & 0xfffffff0) | ((x) >> 28) | GPTE_VALID | (flag))
-#define GPTE_DECODE(x) (((x) & 0xfffff000) | (((x) & 0xff0) << 28))
+#define GPTE_ENCODE(x) (((x) & 0xfffff000) | (((x) >> 32) << 4) | GPTE_VALID | GPTE_COHERENT)
+#define GPTE_DECODE(x) (((x) & 0xfffff000) | (((u64)(x) & 0xff0) << 28))
 
 #define for_all_nb(dev) \
 	pci_for_each_dev(dev) \
@@ -129,7 +135,7 @@
 {
 	void *memory;
 	int gfp = GFP_ATOMIC;
-	int order, i;
+	int i;
 	unsigned long iommu_page;
 
 	if (hwdev == NULL || hwdev->dma_mask < 0xffffffff || no_iommu)
@@ -139,8 +145,8 @@
 	 * First try to allocate continuous and use directly if already 
 	 * in lowmem. 
 	 */ 
-	order = get_order(size);
-	memory = (void *)__get_free_pages(gfp, order);
+	size = round_up(size, PAGE_SIZE); 
+	memory = (void *)__get_free_pages(gfp, get_order(size));
 	if (memory == NULL) {
 		return NULL; 
 	} else {
@@ -160,19 +166,21 @@
 		}
 	} 
 
-	iommu_page = alloc_iommu(1<<order);
+	size >>= PAGE_SHIFT;
+
+	iommu_page = alloc_iommu(size);
 	if (iommu_page == -1)
 		goto error; 
 
    	/* Fill in the GATT, allocating pages as needed. */
-	for (i = 0; i < 1<<order; i++) { 
+	for (i = 0; i < size; i++) { 
 		unsigned long phys_mem; 
 		void *mem = memory + i*PAGE_SIZE;
 		if (i > 0) 
 			atomic_inc(&virt_to_page(mem)->count); 
 		phys_mem = virt_to_phys(mem); 
-		BUG_ON(phys_mem & ~PTE_MASK); 
-		iommu_gatt_base[iommu_page + i] = GPTE_ENCODE(phys_mem,GPTE_COHERENT); 
+		BUG_ON(phys_mem & ~PHYSICAL_PAGE_MASK); 
+		iommu_gatt_base[iommu_page + i] = GPTE_ENCODE(phys_mem); 
 	} 
 
 	flush_gart();
@@ -180,7 +188,7 @@
 	return memory; 
 	
  error:
-	free_pages((unsigned long)memory, order); 
+	free_pages((unsigned long)memory, get_order(size)); 
 	return NULL; 
 }
 
@@ -192,30 +200,32 @@
 			 void *vaddr, dma_addr_t bus)
 {
 	u64 pte;
-	int order = get_order(size);
 	unsigned long iommu_page;
 	int i;
 
+	size = round_up(size, PAGE_SIZE); 
 	if (bus < iommu_bus_base || bus > iommu_bus_base + iommu_size) { 
-		free_pages((unsigned long)vaddr, order); 		
+		free_pages((unsigned long)vaddr, get_order(size)); 		
 		return;
 	} 
+	size >>= PAGE_SHIFT;
 	iommu_page = (bus - iommu_bus_base) / PAGE_SIZE;
-	for (i = 0; i < 1<<order; i++) {
+	for (i = 0; i < size; i++) {
 		pte = iommu_gatt_base[iommu_page + i];
 		BUG_ON((pte & GPTE_VALID) == 0); 
 		iommu_gatt_base[iommu_page + i] = 0; 		
 		free_page((unsigned long) __va(GPTE_DECODE(pte)));
 	} 
 	flush_gart(); 
-	free_iommu(iommu_page, 1<<order);
+	free_iommu(iommu_page, size);
 }
 
-#ifdef CONFIG_IOMMU_LEAK
+#ifdef CONFIG_IOMMU_DEBUG
 /* Debugging aid for drivers that don't free their IOMMU tables */
 static void **iommu_leak_tab; 
 static int leak_trace;
-int iommu_leak_dumppages = 20; 
+int iommu_leak_pages = 20; 
+extern unsigned long printk_address(unsigned long);
 void dump_leak(void)
 {
 	int i;
@@ -223,10 +233,13 @@
 	if (dump || !iommu_leak_tab) return;
 	dump = 1;
 	show_stack(NULL);
-	printk("Dumping %d pages from end of IOMMU:\n", iommu_leak_dumppages); 
-	for (i = 0; i < iommu_leak_dumppages; i++) 
-		printk("[%lu: %lx] ",
-		       iommu_pages-i,(unsigned long) iommu_leak_tab[iommu_pages-i]); 
+	/* Very crude. dump some from the end of the table too */ 
+	printk("Dumping %d pages from end of IOMMU:\n", iommu_leak_pages); 
+	for (i = 0; i < iommu_leak_pages; i+=2) {
+		printk("%lu: ", iommu_pages-i);
+		printk_address((unsigned long) iommu_leak_tab[iommu_pages-i]);
+		printk("%c", (i+1)%2 == 0 ? '\n' : ' '); 
+	} 
 	printk("\n");
 }
 #endif
@@ -254,7 +267,7 @@
 			panic("PCI-DMA: Random memory will be DMAed\n"); 
 	} 
 
-#ifdef CONFIG_IOMMU_LEAK
+#ifdef CONFIG_IOMMU_DEBUG
 	dump_leak(); 
 #endif
 } 
@@ -274,7 +287,8 @@
 	return mmu; 
 }
 
-dma_addr_t pci_map_single(struct pci_dev *dev, void *addr, size_t size,int dir)
+dma_addr_t __pci_map_single(struct pci_dev *dev, void *addr, size_t size,
+			    int dir, int flush)
 { 
 	unsigned long iommu_page;
 	unsigned long phys_mem, bus;
@@ -286,7 +300,7 @@
 	if (!need_iommu(dev, phys_mem, size))
 		return phys_mem; 
 
-	npages = round_up(size, PAGE_SIZE) >> PAGE_SHIFT;
+	npages = round_up(size + ((u64)addr & ~PAGE_MASK), PAGE_SIZE) >> PAGE_SHIFT;
 
 	iommu_page = alloc_iommu(npages); 
 	if (iommu_page == -1) {
@@ -296,20 +310,24 @@
 
 	phys_mem &= PAGE_MASK;
 	for (i = 0; i < npages; i++, phys_mem += PAGE_SIZE) {
-		BUG_ON(phys_mem & ~PTE_MASK); 
+		BUG_ON(phys_mem & ~PHYSICAL_PAGE_MASK); 
 		
 		/* 
 		 * Set coherent mapping here to avoid needing to flush
 		 * the caches on mapping.
 		 */
-		iommu_gatt_base[iommu_page + i] = GPTE_ENCODE(phys_mem, GPTE_COHERENT);
+		iommu_gatt_base[iommu_page + i] = GPTE_ENCODE(phys_mem);
+
+#ifdef CONFIG_IOMMU_DEBUG
+		/* paranoia check */
+		BUG_ON(GPTE_DECODE(iommu_gatt_base[iommu_page+i]) != phys_mem); 
 
-#ifdef CONFIG_IOMMU_LEAK
 		/* XXX need eventually caller of pci_map_sg */
 		if (iommu_leak_tab) 
 			iommu_leak_tab[iommu_page + i] = __builtin_return_address(0); 
 #endif
 	}
+	if (flush)
 	flush_gart(); 
 
 	bus = iommu_bus_base + iommu_page*PAGE_SIZE; 
@@ -328,10 +346,10 @@
 	    dma_addr > iommu_bus_base + iommu_size)
 		return;
 	iommu_page = (dma_addr - iommu_bus_base)>>PAGE_SHIFT;	
-	npages = round_up(size, PAGE_SIZE) >> PAGE_SHIFT;
+	npages = round_up(size + (dma_addr & ~PAGE_MASK), PAGE_SIZE) >> PAGE_SHIFT;
 	for (i = 0; i < npages; i++) { 
 		iommu_gatt_base[iommu_page + i] = 0; 
-#ifdef CONFIG_IOMMU_LEAK
+#ifdef CONFIG_IOMMU_DEBUG
 		if (iommu_leak_tab)
 			iommu_leak_tab[iommu_page + i] = 0; 
 #endif
@@ -340,7 +358,7 @@
 	free_iommu(iommu_page, npages);
 }
 
-EXPORT_SYMBOL(pci_map_single);
+EXPORT_SYMBOL(__pci_map_single);
 EXPORT_SYMBOL(pci_unmap_single);
 
 static __init unsigned long check_iommu_size(unsigned long aper, u64 aper_size)
@@ -488,7 +506,7 @@
 		panic("Cannot allocate iommu bitmap\n"); 
 	memset(iommu_gart_bitmap, 0, iommu_pages/8);
 
-#ifdef CONFIG_IOMMU_LEAK
+#ifdef CONFIG_IOMMU_DEBUG
 	if (leak_trace) { 
 		iommu_leak_tab = (void *)__get_free_pages(GFP_KERNEL, 
 				  get_order(iommu_pages*sizeof(void *)));
@@ -523,6 +541,8 @@
    off   don't use the IOMMU
    leak  turn on simple iommu leak tracing (only when CONFIG_IOMMU_LEAK is on)
    memaper[=order] allocate an own aperture over RAM with size 32MB^order.
+   noforce don't force IOMMU usage. Should be fastest.
+   force  Force IOMMU and turn on unmap debugging.
 */
 __init int iommu_setup(char *opt) 
 { 
@@ -544,9 +564,14 @@
 		    if (*p == '=' && get_option(&p, &arg))
 			    fallback_aper_order = arg;
 	    } 
-#ifdef CONFIG_IOMMU_LEAK
-	    if (!memcmp(p,"leak", 4))
+#ifdef CONFIG_IOMMU_DEBUG
+	    if (!memcmp(p,"leak", 4)) { 
 		    leak_trace = 1;
+		    p += 4; 
+		    if (*p == '=') ++p;
+		    if (isdigit(*p) && get_option(&p, &arg))
+			    iommu_leak_pages = arg;
+	    } else
 #endif
 	    if (isdigit(*p) && get_option(&p, &arg)) 
 		    iommu_size = arg;
diff -urN linux-2.4.21-pre3/arch/x86_64/kernel/pci-x86_64.c linux-2.4.21-pre4/arch/x86_64/kernel/pci-x86_64.c
--- linux-2.4.21-pre3/arch/x86_64/kernel/pci-x86_64.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/arch/x86_64/kernel/pci-x86_64.c	Tue Jan 28 19:44:29 2003
@@ -136,8 +136,7 @@
  * which might have be mirrored at 0x0100-0x03ff..
  */
 void
-pcibios_align_resource(void *data, struct resource *res, unsigned long size,
-		       unsigned long align)
+pcibios_align_resource(void *data, struct resource *res, unsigned long size, unsigned long align)
 {
 	if (res->flags & IORESOURCE_IO) {
 		unsigned long start = res->start;
@@ -313,9 +312,9 @@
 	pci_read_config_word(dev, PCI_COMMAND, &cmd);
 	old_cmd = cmd;
 	for(idx=0; idx<6; idx++) {
+		r = &dev->resource[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);
 			return -EINVAL;
diff -urN linux-2.4.21-pre3/arch/x86_64/kernel/pci-x86_64.h linux-2.4.21-pre4/arch/x86_64/kernel/pci-x86_64.h
--- linux-2.4.21-pre3/arch/x86_64/kernel/pci-x86_64.h	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/arch/x86_64/kernel/pci-x86_64.h	Tue Jan 28 19:44:29 2003
@@ -29,7 +29,7 @@
 extern unsigned int pcibios_max_latency;
 
 void pcibios_resource_survey(void);
-int pcibios_enable_resources(struct pci_dev *, int);
+int pcibios_enable_resources(struct pci_dev *, int mask);
 
 /* pci-pc.c */
 
diff -urN linux-2.4.21-pre3/arch/x86_64/kernel/process.c linux-2.4.21-pre4/arch/x86_64/kernel/process.c
--- linux-2.4.21-pre3/arch/x86_64/kernel/process.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/arch/x86_64/kernel/process.c	Tue Jan 28 19:44:29 2003
@@ -9,7 +9,7 @@
  *  X86-64 port
  *	Andi Kleen.
  * 
- *  $Id: process.c,v 1.57 2002/09/12 12:56:36 ak Exp $
+ *  $Id: process.c,v 1.60 2003/01/10 15:16:30 ak Exp $
  */
 
 /*
@@ -275,6 +275,8 @@
 		pm_power_off();
 }
 
+extern int printk_address(unsigned long); 
+
 /* Prints also some state that isn't saved in the pt_regs */ 
 void show_regs(struct pt_regs * regs)
 {
@@ -284,8 +286,9 @@
 
 	printk("\n");
 	printk("Pid: %d, comm: %.20s %s\n", current->pid, current->comm, print_tainted());
-	printk("RIP: %04lx:[<%016lx>]\n", regs->cs & 0xffff, regs->rip);
-	printk("RSP: %04lx:%016lx  EFLAGS: %08lx\n", regs->ss, regs->rsp, regs->eflags);
+	printk("RIP: %04lx:", regs->cs & 0xffff);
+	printk_address(regs->rip); 
+	printk("\nRSP: %04lx:%016lx  EFLAGS: %08lx\n", regs->ss, regs->rsp, regs->eflags);
 	printk("RAX: %016lx RBX: %016lx RCX: %016lx\n",
 	       regs->rax, regs->rbx, regs->rcx);
 	printk("RDX: %016lx RSI: %016lx RDI: %016lx\n",
@@ -336,37 +339,6 @@
 }
 
 /* 
- * Reloading %gs is a bit complicated because the kernel relies on it 
- * This includes the exception handlers, so we cannot take any exceptions
- * while doing this. Check the new gs value manually for validity and only
- * then load it. This needs locking again parallel CPUs that share the same
- * LDT. This has to be done in the context switch iff %gs changes.
- */
-void load_gs_index(unsigned gs)
-{
-	struct mm_struct *mm = current->mm;
-	int access; 
-	/* paranoia: */
-	if ((gs & 3) != 2) gs = 0;
-	if (mm) 
-		read_lock(&mm->context.ldtlock); 
-	asm volatile("pushf\n\t" 
-		     "cli\n\t"
-		     "swapgs\n\t"
-		     /* cannot take any exception until the next swapgs */
-		     "lar %1,%0\n\t"
-		     "jnz 1f\n\t"
-		     "movl %1,%%eax\n\t"
-		     "movl %%eax,%%gs\n\t"
-		     "jmp 2f\n\t"
-		     "1: movl %2,%%gs\n\t"
-		     "2: swapgs\n\t"
-		     "popf" : "=g" (access) : "g" (gs), "r" (0) : "rax"); 
-	if (mm)
-		read_unlock(&mm->context.ldtlock);
-}
-	
-/*
  * Free current thread data structures etc..
  */
 void exit_thread(void)
@@ -486,10 +458,6 @@
 /*
  *	switch_to(x,y) should switch tasks from x to y.
  *
- * We fsave/fwait so that an exception goes off at the right time
- * (as a call from the fsave or fwait in effect) rather than to
- * the wrong process. 
- * 
  * This could still be optimized: 
  * - fold all the options into a flag word and test it with a single test.
  * - could test fs/gs bitsliced
@@ -520,29 +488,33 @@
 
 	/* 
 	 * Switch FS and GS.
-	 * XXX Check if this is safe on SMP (!= -> |)
 	 */
 	{ 
-		unsigned int fsindex;
-
+		unsigned fsindex;
 		asm volatile("movl %%fs,%0" : "=g" (fsindex)); 
-		if (unlikely(fsindex != next->fsindex)) /* or likely? */
+		/* segment register != 0 always requires a reload. 
+		   also reload when it has changed. 
+		   when prev process used 64bit base always reload
+		   to avoid an information leak. */
+		if (unlikely((fsindex | next->fsindex) || prev->fs))
 			loadsegment(fs, next->fsindex);
+		/* check if the user changed the selector
+		   if yes clear 64bit base. */
 		if (unlikely(fsindex != prev->fsindex))
 			prev->fs = 0; 
-		if ((fsindex != prev->fsindex) || (prev->fs != next->fs))
+		/* when next process has a 64bit base use it */
+		if (next->fs) 
 			wrmsrl(MSR_FS_BASE, next->fs); 
 		prev->fsindex = fsindex;
 	}
 	{
-		unsigned int gsindex;
-
+		unsigned gsindex;
 		asm volatile("movl %%gs,%0" : "=g" (gsindex)); 
-		if (unlikely(gsindex != next->gsindex))
-			load_gs_index(next->gs); 
+		if (unlikely((gsindex | next->gsindex) || prev->gs))
+			load_gs_index(next->gsindex);
 		if (unlikely(gsindex != prev->gsindex)) 
 			prev->gs = 0;				
-		if (gsindex != prev->gsindex || prev->gs != next->gs)
+		if (next->gs)
 			wrmsrl(MSR_KERNEL_GS_BASE, next->gs); 
 		prev->gsindex = gsindex;
 	}
@@ -693,18 +665,26 @@
 
 	switch (code) { 
 	case ARCH_SET_GS:
+#ifndef GS_SWITCH_WORKING
+		/* Disabled for now because we still have one unexplained bug
+		   in the context switch for this. */ 
+		return -EINVAL; 
+#else
 		if (addr >= TASK_SIZE) 
 			return -EPERM; 
 		asm volatile("movw %%gs,%0" : "=g" (current->thread.gsindex)); 
+		asm volatile("movl %0,%%gs" :: "r" (0)); 
 		current->thread.gs = addr;
 		ret = checking_wrmsrl(MSR_KERNEL_GS_BASE, addr); 
 		break;
+#endif
 	case ARCH_SET_FS:
 		/* Not strictly needed for fs, but do it for symmetry
-		   with gs */
+		   with gs. */
 		if (addr >= TASK_SIZE)
 			return -EPERM; 
 		asm volatile("movw %%fs,%0" : "=g" (current->thread.fsindex)); 
+		asm volatile("movl %0,%%fs" :: "r" (0)); 
 		current->thread.fs = addr;
 		ret = checking_wrmsrl(MSR_FS_BASE, addr); 
 		break;
@@ -726,4 +706,3 @@
 	} 
 	return ret;	
 } 
-
diff -urN linux-2.4.21-pre3/arch/x86_64/kernel/ptrace.c linux-2.4.21-pre4/arch/x86_64/kernel/ptrace.c
--- linux-2.4.21-pre3/arch/x86_64/kernel/ptrace.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/arch/x86_64/kernel/ptrace.c	Tue Jan 28 19:44:29 2003
@@ -90,6 +90,8 @@
 	unsigned long regno, unsigned long value)
 {
 	unsigned long tmp; 
+	if (child->thread.flags & THREAD_IA32)
+		value &= 0xffffffff;
 	switch (regno) {
 		case offsetof(struct user_regs_struct,fs):
 			if (value && (value & 3) != 3)
@@ -144,6 +146,7 @@
 
 static unsigned long getreg(struct task_struct *child, unsigned long regno)
 {
+	unsigned long val; 
 	switch (regno) {
 		case offsetof(struct user_regs_struct, fs):
 			return child->thread.fsindex;
@@ -159,7 +162,10 @@
 			return child->thread.gs;
 		default:
 			regno = regno - sizeof(struct pt_regs);
-			return get_stack_long(child, regno);
+			val = get_stack_long(child, regno);
+			if (child->thread.flags & THREAD_IA32) 
+				val &= 0xffffffff;
+			return val;
 	}
 
 }
diff -urN linux-2.4.21-pre3/arch/x86_64/kernel/setup64.c linux-2.4.21-pre4/arch/x86_64/kernel/setup64.c
--- linux-2.4.21-pre3/arch/x86_64/kernel/setup64.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/arch/x86_64/kernel/setup64.c	Tue Jan 28 19:44:29 2003
@@ -3,7 +3,7 @@
  * Copyright (C) 1995  Linus Torvalds
  * Copyright 2001, 2002 SuSE Labs / Andi Kleen.
  * See setup.c for older changelog.
- * $Id: setup64.c,v 1.15 2002/09/05 15:25:43 ak Exp $
+ * $Id: setup64.c,v 1.17 2002/11/14 17:07:03 ak Exp $
  */ 
 #include <linux/config.h>
 #include <linux/init.h>
@@ -31,18 +31,17 @@
 struct desc_ptr gdt_descr = { 0 /* filled in */, (unsigned long) gdt_table }; 
 struct desc_ptr idt_descr = { 256 * 16, (unsigned long) idt_table }; 
 
-unsigned long __supported_pte_mask = ~_PAGE_NX; 
-static int do_not_nx = 1; 
+unsigned long __supported_pte_mask = ~0UL; 
+static int do_not_nx = 0; 
 
 char boot_cpu_stack[IRQSTACKSIZE] __cacheline_aligned;
 
-
 static int __init nonx_setup(char *str)
 {
-	if (strstr(str,"off")) { 
+	if (!strncmp(str,"off",3)) { 
 		__supported_pte_mask &= ~_PAGE_NX; 
 		do_not_nx = 1; 
-	} else if (strstr(str, "on")) { 
+	} else if (!strncmp(str, "on",3)) { 
 		do_not_nx = 0; 
 		__supported_pte_mask |= _PAGE_NX; 
 	} 
@@ -145,12 +144,10 @@
 	wrmsrl(MSR_CSTAR, ia32_cstar_target); 
 #endif
 
-	if (!do_not_nx) { 
 		rdmsrl(MSR_EFER, efer); 
-		if (!(efer & EFER_NX)) { 
+	if (!(efer & EFER_NX) || do_not_nx) { 
 			__supported_pte_mask &= ~_PAGE_NX; 
 		} 
-	}
 
 	t->io_map_base = INVALID_IO_BITMAP_OFFSET;	
 	memset(t->io_bitmap, 0xff, sizeof(t->io_bitmap));
diff -urN linux-2.4.21-pre3/arch/x86_64/kernel/signal.c linux-2.4.21-pre4/arch/x86_64/kernel/signal.c
--- linux-2.4.21-pre3/arch/x86_64/kernel/signal.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/arch/x86_64/kernel/signal.c	Tue Jan 28 19:44:29 2003
@@ -8,7 +8,7 @@
  *  2000-06-20  Pentium III FXSR, SSE support by Gareth Hughes
  *  2000-2001   x86-64 support by Andi Kleen
  * 
- *  $Id: signal.c,v 1.35 2002/07/29 10:34:03 ak Exp $
+ *  $Id: signal.c,v 1.40 2002/11/28 06:06:43 ak Exp $
  */
 
 #include <linux/sched.h>
@@ -29,6 +29,7 @@
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 #include <asm/i387.h>
+#include <asm/proto.h>
 
 #define DEBUG_SIG 0
 
@@ -63,8 +64,6 @@
 		/* First 32bits of unions are always present.  */
 		err |= __put_user(from->si_pid, &to->si_pid);
 		switch (from->si_code >> 16) {
-		case __SI_FAULT >> 16:
-			break;
 		case __SI_CHLD >> 16:
 			err |= __put_user(from->si_utime, &to->si_utime);
 			err |= __put_user(from->si_stime, &to->si_stime);
@@ -140,10 +139,15 @@
 				regs->x = 0; 
 
 	{ 
-		unsigned int seg; 
+		unsigned int seg, oldseg; 
 		err |= __get_user(seg, &sc->gs); 
+		asm("movl %%gs,%0" : "=r" (oldseg)); 
+		if (oldseg != seg) {
+			seg |= 3;		       
 		load_gs_index(seg); 
+		}
 		err |= __get_user(seg, &sc->fs);
+		seg |= 3; 
 		loadsegment(fs,seg);
 	}
 
@@ -264,12 +268,6 @@
 	return err;
 }
 
-/*
- * Determine which stack to use..
- */
-#define round_down(p, r) ((void *)  ((unsigned long)((p) - (r) + 1) & ~((r)-1)))
-
-
 static void * 
 get_stack(struct k_sigaction *ka, struct pt_regs *regs, unsigned long size)
 {
@@ -279,34 +277,35 @@
 	rsp = regs->rsp - 128;
 
 	/* This is the X/Open sanctioned signal stack switching.  */
+	/* may need to subtract redzone there too */
 	if (ka->sa.sa_flags & SA_ONSTACK) {
-		if (! sas_ss_flags(rsp) == 0)
+		if (sas_ss_flags(rsp) == 0)
 			rsp = current->sas_ss_sp + current->sas_ss_size;
 	}
 
-	return round_down(rsp - size, 16); 	
+	return (void *)round_down(rsp - size, 16); 	
 }
 
 static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 			   sigset_t *set, struct pt_regs * regs)
 {
-	struct rt_sigframe *frame = NULL;
-	struct _fpstate *fp = NULL; 
+	struct rt_sigframe *frame;
+	struct _fpstate *fp; 
 	int err = 0;
 
 	if (current->used_math) {
 		fp = get_stack(ka, regs, sizeof(struct _fpstate)); 
-		frame = round_down((char *)fp - sizeof(struct rt_sigframe), 16) - 8;
+		frame = (void *)round_down((unsigned long)fp - sizeof(struct rt_sigframe), 16) - 8;
 
 		if (!access_ok(VERIFY_WRITE, fp, sizeof(struct _fpstate))) { 
 			goto give_sigsegv;
 		}
 		if (save_i387(fp) < 0) 
 			err |= -1; 
-	}
-
-	if (!frame)
+	} else {
 		frame = get_stack(ka, regs, sizeof(struct rt_sigframe)) - 8;
+		fp = NULL;
+	}
 
 	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) {
 		goto give_sigsegv;
@@ -400,7 +399,7 @@
 #endif
 
 	/* Are we from a system call? */
-	if (regs->orig_rax >= 0) {
+	if ((long)regs->orig_rax >= 0) {
 		/* If so, check system call restarting.. */
 		switch (regs->rax) {
 			case -ERESTARTNOHAND:
@@ -563,8 +562,7 @@
 		 * have been cleared if the watchpoint triggered
 		 * inside the kernel.
 		 */
-		__asm__("movq %0,%%db7"	: : "r" (current->thread.debugreg[7]));
-
+		asm volatile("movq %0,%%db7"::"r"(current->thread.debugreg[7]));
 		/* Whee!  Actually deliver the signal.  */
 		handle_signal(signr, ka, &info, oldset, regs);
 		return 1;
diff -urN linux-2.4.21-pre3/arch/x86_64/kernel/smpboot.c linux-2.4.21-pre4/arch/x86_64/kernel/smpboot.c
--- linux-2.4.21-pre3/arch/x86_64/kernel/smpboot.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/arch/x86_64/kernel/smpboot.c	Tue Jan 28 19:44:29 2003
@@ -76,6 +76,9 @@
 /* Set when the idlers are all forked */
 int smp_threads_ready;
 
+extern int last_tsc;
+extern void time_init_smp(void);
+
 /*
  * Setup routine for controlling SMP activation
  *
@@ -237,11 +240,15 @@
 		atomic_inc(&tsc_count_start);
 
 		rdtscll(tsc_values[smp_processor_id()]);
+
 		/*
 		 * We clear the TSC in the last loop:
 		 */
-		if (i == NR_LOOPS-1)
+
+		if (i == NR_LOOPS-1) {
 			write_tsc(0, 0);
+			last_tsc = 0;
+		}
 
 		/*
 		 * Wait for all APs to leave the synchronization point:
@@ -772,7 +779,7 @@
 static __init void smp_tune_scheduling (void)
 {
 	unsigned long cachesize;       /* kB   */
-	unsigned long bandwidth = 350; /* MB/s */
+	unsigned long bandwidth = 2000; /* MB/s */
 	/*
 	 * Rough estimation for SMP scheduling, this is the number of
 	 * cycles it takes for a fully memory-limited process to flush
@@ -801,6 +808,8 @@
 		cacheflush_time = (cpu_khz>>10) * (cachesize<<10) / bandwidth;
 	}
 
+	cacheflush_time *= 10;  /* Add an NUMA factor */
+
 	printk("per-CPU timeslice cutoff: %ld.%02ld usecs.\n",
 		(long)cacheflush_time/(cpu_khz/1000),
 		((long)cacheflush_time*100/(cpu_khz/1000)) % 100);
@@ -989,6 +998,8 @@
 	 */
 	if (!skip_ioapic_setup && nr_ioapics)
 		setup_IO_APIC();
+	else
+		nr_ioapics = 0;
 
 	/*
 	 * Set up all local APIC timers in the system:
@@ -1003,4 +1014,5 @@
 
 smp_done:
 	zap_low_mappings();
+	time_init_smp();
 }
diff -urN linux-2.4.21-pre3/arch/x86_64/kernel/sys_x86_64.c linux-2.4.21-pre4/arch/x86_64/kernel/sys_x86_64.c
--- linux-2.4.21-pre3/arch/x86_64/kernel/sys_x86_64.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/arch/x86_64/kernel/sys_x86_64.c	Tue Jan 28 19:44:29 2003
@@ -65,23 +65,34 @@
 	return error;
 }
 
+
 unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags)
 {
 	struct vm_area_struct *vma;
 	unsigned long end = TASK_SIZE;
 
-	if (current->thread.flags & THREAD_IA32)
-		flags |= MAP_32BIT; 
-	if (flags & MAP_32BIT)
-		end = 0xffffffff-1;
-	if (len > end)
-		return -ENOMEM;
-	if (!addr) { 
-		addr = TASK_UNMAPPED_64;
-		if (flags & MAP_32BIT) {
+	if (current->thread.flags & THREAD_IA32) {
+		if (!addr) 
 			addr = TASK_UNMAPPED_32;
+		end = 0xffff0000;
+	} else if (flags & MAP_32BIT) { 
+		/* This is usually used needed to map code in small
+		   model: it needs to be in the first 31bit. Limit it
+		   to that.  This means we need to move the unmapped
+		   base down for this case.  This may give conflicts
+		   with the heap, but we assume that malloc falls back
+		   to mmap. Give it 1GB of playground for now. -AK */ 
+		if (!addr) 
+			addr = 0x40000000; 
+		end = 0x80000000;		
+	} else { 
+		if (!addr) 
+			addr = TASK_UNMAPPED_64; 
+		end = TASK_SIZE; 
 		}
-	} 
+
+	if (len > end)
+		return -ENOMEM;
 	addr = PAGE_ALIGN(addr);
 
 	for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) {
diff -urN linux-2.4.21-pre3/arch/x86_64/kernel/syscall.c linux-2.4.21-pre4/arch/x86_64/kernel/syscall.c
--- linux-2.4.21-pre3/arch/x86_64/kernel/syscall.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/arch/x86_64/kernel/syscall.c	Tue Jan 28 19:44:29 2003
@@ -3,6 +3,7 @@
 #include <linux/linkage.h>
 #include <linux/sys.h>
 #include <linux/cache.h>
+#include <linux/config.h>
 
 #define __NO_STUBS
 
diff -urN linux-2.4.21-pre3/arch/x86_64/kernel/time.c linux-2.4.21-pre4/arch/x86_64/kernel/time.c
--- linux-2.4.21-pre3/arch/x86_64/kernel/time.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/arch/x86_64/kernel/time.c	Tue Jan 28 19:44:29 2003
@@ -12,8 +12,6 @@
  *
  */
 
-#define HPET_BIOS_SUPPORT_WORKING
-
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
@@ -26,39 +24,64 @@
 
 extern rwlock_t xtime_lock;
 spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t i8253_lock = SPIN_LOCK_UNLOCKED;
 
 unsigned int cpu_khz;					/* TSC clocks / usec, not used here */
+unsigned long hpet_address;
 unsigned long hpet_period;				/* fsecs / HPET clock */
-unsigned long hpet_tick;				/* HPET clocks / interrupt */
-int hpet_report_lost_ticks;				/* command line option */
+unsigned int hpet_tick;					/* HPET clocks / interrupt */
+unsigned long vxtime_hz = 1193182;
+int report_lost_ticks;					/* command line option */
 
-struct hpet_data __hpet __section_hpet;			/* address, quotient, trigger, hz */
+struct vxtime_data __vxtime __section_vxtime;		/* data for vsyscall */
 
 volatile unsigned long __jiffies __section_jiffies;
 unsigned long __wall_jiffies __section_wall_jiffies;
 struct timeval __xtime __section_xtime;
 struct timezone __sys_tz __section_sys_tz;
 
+long last_tsc;
+spinlock_t last_tsc_lock = SPIN_LOCK_UNLOCKED;
+
+void rdtscll_safe(long *x)
+{
+	long temp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&last_tsc_lock, flags);
+	rdtscll(temp);
+	if (last_tsc - temp < 0L) last_tsc = temp;
+	*x = last_tsc;
+	spin_unlock_irqrestore(&last_tsc_lock, flags);
+}
+
 /*
  * do_gettimeoffset() returns microseconds since last timer interrupt was
- * triggered by hardware. A memory read of HPET is slower than a register read
- * of TSC, but much more reliable. It's also synchronized to the timer
- * interrupt. Note that do_gettimeoffset() may return more than hpet_tick, if a
- * timer interrupt has happened already, but hpet.trigger wasn't updated yet.
- * This is not a problem, because jiffies hasn't updated either. They are bound
- * together by xtime_lock.
+ * triggered by hardware. 
  */
 
-static spinlock_t time_offset_lock = SPIN_LOCK_UNLOCKED;
-static unsigned long timeoffset = 0;
-
-inline unsigned int do_gettimeoffset(void)
+static unsigned int do_gettimeoffset_tsc(void)
 {
 	unsigned long t;
 	rdtscll(t);	
-	return (t  - hpet.last_tsc) * (1000000L / HZ) / hpet.ticks + hpet.offset;
+	return ((t  - vxtime.last_tsc) * vxtime.tsc_quot) >> 32;
+}
+
+static unsigned int do_gettimeoffset_tsc_safe(void)
+{
+	unsigned long t;
+	rdtscll_safe(&t);	
+	return ((t  - vxtime.last_tsc) * vxtime.tsc_quot) >> 32;
 }
 
+static unsigned int do_gettimeoffset_hpet(void)
+{
+	return ((hpet_readl(HPET_COUNTER) - vxtime.last) * vxtime.quot) >> 32;
+}
+
+unsigned int (*do_gettimeoffset)(void) = do_gettimeoffset_tsc;
+unsigned int (*do_gettimeoffset_safe)(void) = do_gettimeoffset_tsc_safe;
+
 /*
  * This version of gettimeofday() has microsecond resolution and better than
  * microsecond precision, as we're using at least a 10 MHz (usually 14.31818
@@ -67,20 +90,16 @@
 
 void do_gettimeofday(struct timeval *tv)
 {
-	unsigned long flags, t;
+	unsigned long flags;
  	unsigned int sec, usec;
 
 	read_lock_irqsave(&xtime_lock, flags);
-	spin_lock(&time_offset_lock);
 
 	sec = xtime.tv_sec;
-	usec = xtime.tv_usec;
-
-	t = (jiffies - wall_jiffies) * (1000000L / HZ) + do_gettimeoffset();
-	if (t > timeoffset) timeoffset = t;
-	usec += timeoffset;
+	usec = xtime.tv_usec
+		+ (jiffies - wall_jiffies) * tick
+		+ do_gettimeoffset_safe();
 
-	spin_unlock(&time_offset_lock);
 	read_unlock_irqrestore(&xtime_lock, flags);
 
 	tv->tv_sec = sec + usec / 1000000;
@@ -98,8 +117,8 @@
 	write_lock_irq(&xtime_lock);
 	vxtime_lock();
 
-	tv->tv_usec -= do_gettimeoffset() +
-		(jiffies - wall_jiffies) * tick;
+	tv->tv_usec -= (jiffies - wall_jiffies) * tick
+			+ do_gettimeoffset_safe();
 
 	while (tv->tv_usec < 0) {
 		tv->tv_usec += 1000000;
@@ -201,15 +220,55 @@
 	vxtime_lock();
 
 	{
-		unsigned long t;
+		long tsc;
+		int delay, offset = 0;
+
+		if (hpet_address) {
+
+			offset = hpet_readl(HPET_T0_CMP) - hpet_tick;
+			delay = hpet_readl(HPET_COUNTER) - offset;
+
+		} else {
+
+			spin_lock(&i8253_lock);
+			outb_p(0x00, 0x43);
+			delay = inb_p(0x40);
+			delay |= inb(0x40) << 8;
+			spin_unlock(&i8253_lock);
+			delay = LATCH - 1 - delay;
+		}
+
+		rdtscll_safe(&tsc);
+
+		if (vxtime.mode == VXTIME_HPET) {
 
-		rdtscll(t);
-		hpet.offset = (t  - hpet.last_tsc) * (1000000L / HZ) / hpet.ticks + hpet.offset - 1000000L / HZ;
-		if (hpet.offset >= 1000000L / HZ)
-			hpet.offset = 0;
-		hpet.ticks = min_t(long, max_t(long, (t  - hpet.last_tsc) * (1000000L / HZ) / (1000000L / HZ - hpet.offset),
-				cpu_khz * 1000/HZ * 15 / 16), cpu_khz * 1000/HZ * 16 / 15); 
-		hpet.last_tsc = t;
+			if (offset - vxtime.last > hpet_tick) {
+				if (report_lost_ticks)
+					printk(KERN_WARNING "time.c: Lost %d timer tick(s)! (rip %016lx)\n",
+						(offset - vxtime.last) / hpet_tick - 1, regs->rip);
+				jiffies += (offset - vxtime.last) / hpet_tick - 1;
+			}
+
+			vxtime.last = offset;
+
+		} else {
+
+			offset = (((tsc - vxtime.last_tsc) * vxtime.tsc_quot) >> 32) - tick;
+
+			if (offset > tick) {
+				if (report_lost_ticks)
+					printk(KERN_WARNING "time.c: lost %ld tick(s) (rip %016lx)\n",
+						 offset / tick, regs->rip);
+				jiffies += offset / tick;
+				offset %= tick;
+			}
+
+			vxtime.last_tsc = tsc - vxtime.quot * delay / vxtime.tsc_quot;
+
+			if ((((tsc - vxtime.last_tsc) * vxtime.tsc_quot) >> 32) < offset)
+				vxtime.last_tsc = tsc - (((long)offset << 32) / vxtime.tsc_quot) - 1;
+
+		}
 	}
 
 /*
@@ -337,12 +396,10 @@
 static unsigned int __init pit_calibrate_tsc(void)
 {
 	unsigned long start, end;
-	unsigned long flags;
 
 	outb((inb(0x61) & ~0x02) | 0x01, 0x61);
 
-	__save_flags(flags);
-	__cli();
+	spin_lock_irq(&i8253_lock);
 
 	outb(0xb0, 0x43);
 	outb((1193182 / (1000 / 50)) & 0xff, 0x42);
@@ -352,7 +409,7 @@
 	while ((inb(0x61) & 0x20) == 0);
 	rdtscll(end);
 
-	__restore_flags(flags);
+	spin_unlock_irq(&i8253_lock);
 
 	return (end - start) / 50;
 }
@@ -361,9 +418,9 @@
 {
 	unsigned int cfg, id;
 
-	if (!hpet.address)
+	if (!hpet_address)
 		return -1;
-	set_fixmap_nocache(FIX_HPET_BASE, hpet.address);
+	set_fixmap_nocache(FIX_HPET_BASE, hpet_address);
 
 /*
  * Read the period, compute tick and quotient.
@@ -411,14 +468,16 @@
 
 void __init pit_init(void)
 {
+	spin_lock_irq(&i8253_lock);
 	outb_p(0x34, 0x43);		/* binary, mode 2, LSB/MSB, ch 0 */
 	outb_p(LATCH & 0xff, 0x40);	/* LSB */
 	outb_p(LATCH >> 8, 0x40);	/* MSB */
+	spin_unlock_irq(&i8253_lock);
 }
 
 int __init time_setup(char *str)
 {
-	hpet_report_lost_ticks = 1;
+	report_lost_ticks = 1;
 	return 1;
 }
 
@@ -428,18 +487,81 @@
 
 void __init time_init(void)
 {
+	char *timename;
+
+	config_acpi_tables();
+
+#ifdef HPET_HACK_ENABLE_DANGEROUS
+        if (!hpet_address) {
+		printk(KERN_WARNING "time.c: WARNING: Enabling HPET base manually!\n");
+                outl(0x800038a0, 0xcf8);
+                outl(0xff000001, 0xcfc);
+                outl(0x800038a0, 0xcf8);
+                hpet_address = inl(0xcfc) & 0xfffffffe;
+		printk(KERN_WARNING "time.c: WARNING: Enabled HPET at at %#lx.\n", hpet_address);
+        }
+#endif
+
+#ifndef CONFIG_HPET_TIMER
+        hpet_address = 0;
+#endif
+
+	write_lock(&xtime_lock);
 	xtime.tv_sec = get_cmos_time();
 	xtime.tv_usec = 0;
+	write_unlock(&xtime_lock);
 
-		printk(KERN_WARNING "time.c: HPET timer not found, precise timing unavailable.\n");
+	if (!hpet_init()) {
+                vxtime_hz = (1000000000000000L + hpet_period / 2) / hpet_period;
+                cpu_khz = hpet_calibrate_tsc();
+		timename = "HPET";
+	} else {
 		pit_init();
-		printk(KERN_INFO "time.c: Using 1.1931816 MHz PIT timer.\n");
-		setup_irq(0, &irq0);
 		cpu_khz = pit_calibrate_tsc();
-		printk(KERN_INFO "time.c: Detected %d.%03d MHz processor.\n",
+		timename = "PIT";
+	}
+
+	vxtime.mode = VXTIME_TSC_SAFE;
+	vxtime.quot = (1000000L << 32) / vxtime_hz;
+	vxtime.tsc_quot = (1000L << 32) / cpu_khz;
+	rdtscll_safe(&vxtime.last_tsc);
+
+	setup_irq(0, &irq0);
+
+        printk(KERN_INFO "time.c: Detected %ld.%06ld MHz %s timer.\n",
+		vxtime_hz / 1000000, vxtime_hz % 1000000, timename);
+	printk(KERN_INFO "time.c: Detected %d.%03d MHz TSC timer.\n",
 			cpu_khz / 1000, cpu_khz % 1000);
-	hpet.ticks = cpu_khz * (1000 / HZ);
-	rdtscll(hpet.last_tsc);
+}
+
+void __init time_init_smp(void)
+{
+	char *timetype;
+
+	if (hpet_address) {
+		if (smp_num_cpus > 1) {
+			timetype = "HPET";
+			vxtime.last = hpet_readl(HPET_T0_CMP) - hpet_tick;
+			vxtime.mode = VXTIME_HPET;
+			do_gettimeoffset = do_gettimeoffset_hpet;
+			do_gettimeoffset_safe = do_gettimeoffset_hpet;
+		} else {
+			timetype = "HPET/TSC";
+			vxtime.mode = VXTIME_TSC;
+			do_gettimeoffset = do_gettimeoffset_tsc;
+			do_gettimeoffset_safe = do_gettimeoffset_tsc;
+		}		
+	} else {
+		if (smp_num_cpus > 1) {
+			timetype = "PIT/TSC/SpinLock";
+		} else {
+			timetype = "PIT/TSC";
+			vxtime.mode = VXTIME_TSC;
+			do_gettimeoffset_safe = do_gettimeoffset_tsc;
+		}
+	}
+
+	printk(KERN_INFO "time.c: Using %s based timekeeping.\n", timetype);
 }
 
 __setup("report_lost_ticks", time_setup);
diff -urN linux-2.4.21-pre3/arch/x86_64/kernel/traps.c linux-2.4.21-pre4/arch/x86_64/kernel/traps.c
--- linux-2.4.21-pre3/arch/x86_64/kernel/traps.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/arch/x86_64/kernel/traps.c	Tue Jan 28 19:44:29 2003
@@ -7,7 +7,7 @@
  *  Pentium III FXSR, SSE support
  *	Gareth Hughes <gareth@valinux.com>, May 2000
  *
- *  $Id: traps.c,v 1.51 2002/09/12 12:57:46 ak Exp $
+ *  $Id: traps.c,v 1.54 2003/01/10 15:12:03 ak Exp $
  */
 
 /*
@@ -95,7 +95,7 @@
 	} 
 	if (!strcmp(modname, "kernel"))
 		modname = delim = ""; 		
-        return printk("[%016lx%s%s%s%s%+ld]",
+        return printk("[<%016lx>]{%s%s%s%s%+ld}",
 		      address,delim,modname,delim,symname,address-symstart); 
 } 
 #else
@@ -165,7 +165,7 @@
 
 	printk("\nCall Trace: ");
 
-	i = 1;
+	i = 12;
 	estack_end = in_exception_stack(cpu, (unsigned long)stack); 
 	if (estack_end) { 
 		while (stack < estack_end) { 
@@ -271,11 +271,6 @@
 	show_trace((unsigned long *)rsp);
 }
 
-void dump_stack(void)
-{
-	show_stack(0);
-} 
-
 void show_registers(struct pt_regs *regs)
 {
 	int i;
@@ -407,7 +402,7 @@
 		struct task_struct *tsk = current;
 		tsk->thread.error_code = error_code;
 		tsk->thread.trap_no = trapnr;
-		if (exception_trace)
+		if (exception_trace && trapnr != 3)
 			printk("%s[%d] trap %s rip:%lx rsp:%lx error:%lx\n",
 			       tsk->comm, tsk->pid, str,
 			       regs->rip,regs->rsp,error_code); 
@@ -610,11 +605,6 @@
 	if (notify_die(DIE_DEBUG, "debug", regs, error_code) == NOTIFY_BAD)
 		return; 
 
-	/* If the user set TF, it's simplest to clear it right away. */
-	/* AK: dubious check, likely wrong */
-	if ((regs->cs & 3) == 0 && (regs->eflags & TF_MASK))
-		goto clear_TF;
-
 	/* Mask out spurious debug traps due to lazy DR7 setting */
 	if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
 		if (!tsk->thread.debugreg[7]) { 
diff -urN linux-2.4.21-pre3/arch/x86_64/kernel/vsyscall.c linux-2.4.21-pre4/arch/x86_64/kernel/vsyscall.c
--- linux-2.4.21-pre3/arch/x86_64/kernel/vsyscall.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/arch/x86_64/kernel/vsyscall.c	Tue Jan 28 19:44:29 2003
@@ -12,7 +12,7 @@
  *  vsyscalls. One vsyscall can reserve more than 1 slot to avoid
  *  jumping out of line if necessary.
  *
- *  $Id: vsyscall.c,v 1.19 2002/07/19 02:24:08 vojtech Exp $
+ *  $Id: vsyscall.c,v 1.23 2003/01/10 15:20:52 ak Exp $
  */
 
 /*
@@ -45,15 +45,12 @@
 #include <asm/errno.h>
 #include <asm/io.h>
 #include <asm/msr.h>
+#include <asm/unistd.h>
 
 #define __vsyscall(nr) __attribute__ ((unused,__section__(".vsyscall_" #nr)))
 
 long __vxtime_sequence[2] __section_vxtime_sequence;
 
-#undef USE_VSYSCALL
-
-#ifdef USE_VSYSCALL
-
 static inline void do_vgettimeofday(struct timeval * tv)
 {
 	long sequence, t;
@@ -63,11 +60,21 @@
 		sequence = __vxtime_sequence[1];
 		rmb();
 
-		rdtscll(t);
 		sec = __xtime.tv_sec;
-		usec = __xtime.tv_usec +
-			(__jiffies - __wall_jiffies) * (1000000 / HZ) +
-			(t  - __hpet.last_tsc) * (1000000 / HZ) / __hpet.ticks + __hpet.offset;
+		usec = __xtime.tv_usec + (__jiffies - __wall_jiffies) * (1000000 / HZ);
+
+		switch (__vxtime.mode) {
+
+			case VXTIME_TSC:
+				rdtscll(t);
+				usec += (((t  - __vxtime.last_tsc) * __vxtime.tsc_quot) >> 32);
+				break;
+
+			case VXTIME_HPET:
+				usec += ((readl(fix_to_virt(VSYSCALL_HPET) + 0xf0) - __vxtime.last) * __vxtime.quot) >> 32;
+				break;
+
+		}
 
 		rmb();
 	} while (sequence != __vxtime_sequence[0]);
@@ -76,6 +83,17 @@
 	tv->tv_usec = usec % 1000000;
 }
 
+static inline int do_sgettimeofday(struct timeval * tv)
+{
+	int r;
+	asm volatile("syscall"
+		: "=a" (r)
+		: "0" (__NR_gettimeofday), "D" (tv), "S" (NULL)
+		: "r11", "rcx","memory");
+	return r;
+
+}
+
 static inline void do_get_tz(struct timezone * tz)
 {
 	long sequence;
@@ -92,27 +110,19 @@
 
 static long __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz)
 {
-	if (tv) do_vgettimeofday(tv);
-	if (tz) do_get_tz(tz);
-	return 0;
-}
+	if (tv) {
+		if (__vxtime.mode)
+			do_vgettimeofday(tv);
+		else
+			do_sgettimeofday(tv);
+	}
 
-#else
+	if (tz)
+		do_get_tz(tz);
 
-#include <asm/unistd.h>
-
-static long __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz)
-{
-	int r;
-	asm volatile("syscall"
-		     : "=a" (r)
-		     : "0" (__NR_gettimeofday), "D" (tv), "S" (tz)
-		     : "r11", "rcx","memory");
-	return r;
+	return 0;
 }
 
-#endif
-
 static time_t __vsyscall(1) vtime(time_t * tp)
 {
 	struct timeval tv;
@@ -137,13 +147,12 @@
 	unsigned long physaddr_page0 = (unsigned long) &__vsyscall_0 - __START_KERNEL_map;
 
 	__set_fixmap(VSYSCALL_FIRST_PAGE, physaddr_page0, PAGE_KERNEL_VSYSCALL);
-	if (hpet.address)
-		__set_fixmap(VSYSCALL_HPET, hpet.address, PAGE_KERNEL_VSYSCALL);
+	if (hpet_address)
+		__set_fixmap(VSYSCALL_HPET, hpet_address, PAGE_KERNEL_VSYSCALL);
 }
 
 static int __init vsyscall_init(void)
 {
-	printk("VSYSCALL: consistency checks...");
 	if ((unsigned long) &vgettimeofday != VSYSCALL_ADDR(__NR_vgettimeofday))
 		panic("vgettimeofday link addr broken");
 	if ((unsigned long) &vtime != VSYSCALL_ADDR(__NR_vtime))
@@ -151,10 +160,7 @@
 	if (VSYSCALL_ADDR(0) != __fix_to_virt(VSYSCALL_FIRST_PAGE))
 		panic("fixmap first vsyscall %lx should be %lx", __fix_to_virt(VSYSCALL_FIRST_PAGE),
 			VSYSCALL_ADDR(0));
-	printk("passed...mapping...");
 	map_vsyscall();
-	printk("done.\n");
-
 	return 0;
 }
 
diff -urN linux-2.4.21-pre3/arch/x86_64/kernel/x8664_ksyms.c linux-2.4.21-pre4/arch/x86_64/kernel/x8664_ksyms.c
--- linux-2.4.21-pre3/arch/x86_64/kernel/x8664_ksyms.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/arch/x86_64/kernel/x8664_ksyms.c	Tue Jan 28 19:44:29 2003
@@ -220,3 +220,6 @@
 EXPORT_SYMBOL(plat_node_data);
 EXPORT_SYMBOL(fake_node);
 #endif
+
+extern void int_ret_from_sys_call(void);
+EXPORT_SYMBOL(int_ret_from_sys_call); 
diff -urN linux-2.4.21-pre3/arch/x86_64/lib/usercopy.c linux-2.4.21-pre4/arch/x86_64/lib/usercopy.c
--- linux-2.4.21-pre3/arch/x86_64/lib/usercopy.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/arch/x86_64/lib/usercopy.c	Tue Jan 28 19:44:29 2003
@@ -30,7 +30,7 @@
 		"	jmp 2b\n"					   \
 		".previous\n"						   \
 		".section __ex_table,\"a\"\n"				   \
-		"	.align 4\n"					   \
+		"	.align 8\n"					   \
 		"	.quad 0b,3b\n"					   \
 		".previous"						   \
 		: "=r"(res), "=c"(count), "=&a" (__d0), "=&S" (__d1),	   \
diff -urN linux-2.4.21-pre3/arch/x86_64/mm/fault.c linux-2.4.21-pre4/arch/x86_64/mm/fault.c
--- linux-2.4.21-pre3/arch/x86_64/mm/fault.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/arch/x86_64/mm/fault.c	Tue Jan 28 19:44:29 2003
@@ -30,9 +30,6 @@
 #include <asm/proto.h>
 #include <asm/kdebug.h>
 
-spinlock_t pcrash_lock; 
-int crashing_cpu;
-
 extern spinlock_t console_lock, timerlist_lock;
 
 void bust_spinlocks(int yes)
@@ -114,9 +111,8 @@
 
 #ifdef CONFIG_CHECKING
 	if (page_fault_trace) 
-		printk("pfault %d rip:%lx rsp:%lx cs:%lu ss:%lu addr %lx error %lx\n",
-		       stack_smp_processor_id(), regs->rip,regs->rsp,regs->cs,
-			   regs->ss,address,error_code); 
+		printk("pagefault rip:%lx rsp:%lx cs:%lu ss:%lu address %lx error %lx\n",
+		       regs->rip,regs->rsp,regs->cs,regs->ss,address,error_code); 
 
 	{ 
 		unsigned long gs; 
@@ -129,6 +125,8 @@
 	}
 #endif
 			
+
+
 	tsk = current;
 	mm = tsk->mm;
 	info.si_code = SEGV_MAPERR;
@@ -217,14 +215,11 @@
 
 	/* User mode accesses just cause a SIGSEGV */
 	if (error_code & 4) {
-		if (exception_trace) {
-#if 1
-			dump_pagetable(address);
-#endif	
+		if (exception_trace) 
 			printk("%s[%d]: segfault at %016lx rip %016lx rsp %016lx error %lx\n",
 					current->comm, current->pid, address, regs->rip,
 					regs->rsp, error_code);
-		}
+	
 		tsk->thread.cr2 = address;
 		tsk->thread.error_code = error_code;
 		tsk->thread.trap_no = 14;
@@ -256,14 +251,6 @@
 	console_verbose();
 	bust_spinlocks(1); 
 
-	if (!in_interrupt()) { 
-		if (!spin_trylock(&pcrash_lock)) { 
-			if (crashing_cpu != smp_processor_id()) 
-				spin_lock(&pcrash_lock);  		    
-		} 
-		crashing_cpu = smp_processor_id();
-	} 
-
 	if (address < PAGE_SIZE)
 		printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
 	else
@@ -272,14 +259,7 @@
 	printk(" printing rip:\n");
 	printk("%016lx\n", regs->rip);
 	dump_pagetable(address);
-
 	die("Oops", regs, error_code);
-
-	if (!in_interrupt()) { 
-		crashing_cpu = -1;  /* small harmless window */ 
-		spin_unlock(&pcrash_lock);
-	}
-
 	bust_spinlocks(0); 
 	do_exit(SIGKILL);
 
diff -urN linux-2.4.21-pre3/arch/x86_64/mm/init.c linux-2.4.21-pre4/arch/x86_64/mm/init.c
--- linux-2.4.21-pre3/arch/x86_64/mm/init.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/arch/x86_64/mm/init.c	Tue Jan 28 19:44:29 2003
@@ -189,7 +189,7 @@
 	unsigned long pfn = table_end++, paddr; 
 	void *adr;
 
-	if (table_end >= end_pfn) 
+	if (table_end >= end_pfn_map) 
 		panic("alloc_low_page: ran out of page mappings"); 
 	for (i = 0; temp_mappings[i].allocated; i++) {
 		if (!temp_mappings[i].pmd) 
@@ -246,7 +246,8 @@
 					set_pmd(pmd,  __pmd(0)); 
 				break;
 			}
-			pe = _PAGE_PSE | _KERNPG_TABLE | _PAGE_GLOBAL | paddr;
+			pe = _PAGE_PSE | _KERNPG_TABLE | _PAGE_NX | _PAGE_GLOBAL | paddr;
+			pe &= __supported_pte_mask; 
 			set_pmd(pmd, __pmd(pe));
 		}
 		unmap_low_page(map);
@@ -264,7 +265,7 @@
 	unsigned long next; 
 	unsigned long pgds, pmds, tables; 
 
-	end = end_pfn << PAGE_SHIFT; 
+	end = end_pfn_map << PAGE_SHIFT; 
 
 	/* 
 	 * Find space for the kernel direct mapping tables.
diff -urN linux-2.4.21-pre3/arch/x86_64/mm/modutil.c linux-2.4.21-pre4/arch/x86_64/mm/modutil.c
--- linux-2.4.21-pre3/arch/x86_64/mm/modutil.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/arch/x86_64/mm/modutil.c	Tue Jan 28 19:44:29 2003
@@ -10,11 +10,23 @@
  
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
+#include <linux/init.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
+#include <asm/proto.h>
 
-static struct vm_struct * modvmlist = NULL;
+extern char _text[], _end[]; 
+
+/* Kernel mapping to make the kernel alias visible to 
+   /proc/kcore and /dev/mem 
+
+   RED-PEN may want vsyscall mappings too 
+ */
+
+static struct vm_struct kernel_mapping = { 
+	.addr = (void *)KERNEL_TEXT_START, 
+}; 
 
 void module_unmap (void * addr)
 {
@@ -26,9 +38,11 @@
 		printk("Trying to unmap module with bad address (%p)\n", addr);
 		return;
 	}
-	for (p = &modvmlist ; (tmp = *p) ; p = &tmp->next) {
+	write_lock(&vmlist_lock); 
+	for (p = &vmlist ; (tmp = *p) ; p = &tmp->next) {
 		if (tmp->addr == addr) {
 			*p = tmp->next;
+			write_unlock(&vmlist_lock); 
 			vmfree_area_pages(VMALLOC_VMADDR(tmp->addr), tmp->size);
 			kfree(tmp);
 			return;
@@ -45,24 +59,55 @@
 	size = PAGE_ALIGN(size);
 	if (!size || size > MODULES_LEN) return NULL;
 		
+	area = (struct vm_struct *) kmalloc(sizeof(*area), GFP_KERNEL);
+	if (!area) return NULL; 
+
+	memset(area, 0, sizeof(struct vm_struct));
+
+	size = round_up(size, PAGE_SIZE); 
+
 	addr = (void *) MODULES_VADDR;
-	for (p = &modvmlist; (tmp = *p) ; p = &tmp->next) {
+	write_lock(&vmlist_lock); 
+	for (p = &vmlist; (tmp = *p) ; p = &tmp->next) {
+		void *next;
 		if (size + (unsigned long) addr < (unsigned long) tmp->addr)
 			break;
-		addr = (void *) (tmp->size + (unsigned long) tmp->addr);
+		next = (void *) (tmp->size + (unsigned long) tmp->addr);
+		if (next > addr)
+			addr = next;
+	}
+	if ((unsigned long) addr + size >= MODULES_END) { 
+		write_unlock(&vmlist_lock); 
+		kfree(area);
+		return NULL;
 	}
-	if ((unsigned long) addr + size >= MODULES_END) return NULL;
 	
-	area = (struct vm_struct *) kmalloc(sizeof(*area), GFP_KERNEL);
-	if (!area) return NULL;
-	area->size = size + PAGE_SIZE;
+	area->size = size;
 	area->addr = addr;
 	area->next = *p;
 	*p = area;
+	write_unlock(&vmlist_lock); 
 
-	if (vmalloc_area_pages(VMALLOC_VMADDR(addr), size, GFP_KERNEL, PAGE_KERNEL)) {
+	if (vmalloc_area_pages(VMALLOC_VMADDR(addr), size, GFP_KERNEL, PAGE_KERNEL_EXECUTABLE)) {
 		module_unmap(addr);
 		return NULL;
 	}
 	return addr;
 }
+
+static int __init mod_vmlist_init(void)
+{
+	struct vm_struct *vm, **base;
+	write_lock(&vmlist_lock); 
+	for (base = &vmlist, vm = *base; vm; base = &vm->next, vm = *base) { 
+		if (vm->addr > (void *)KERNEL_TEXT_START) 
+			break; 
+	}  
+	kernel_mapping.size = _end - _text;
+	kernel_mapping.next = vm; 
+	*base = &kernel_mapping; 
+	write_unlock(&vmlist_lock); 
+	return 0;
+} 
+
+__initcall(mod_vmlist_init);
diff -urN linux-2.4.21-pre3/arch/x86_64/mm/numa.c linux-2.4.21-pre4/arch/x86_64/mm/numa.c
--- linux-2.4.21-pre3/arch/x86_64/mm/numa.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/arch/x86_64/mm/numa.c	Tue Jan 28 19:44:29 2003
@@ -1,7 +1,7 @@
 /* 
  * Generic VM initialization for x86-64 NUMA setups.
  * Copyright 2002 Andi Kleen, SuSE Labs.
- * $Id: numa.c,v 1.4 2002/09/05 15:28:12 ak Exp $
+ * $Id: numa.c,v 1.5 2002/10/23 05:27:46 ak Exp $
  */ 
 #include <linux/kernel.h>
 #include <linux/mm.h>
@@ -185,7 +185,7 @@
 /* [numa=off] */
 static __init int numa_setup(char *opt) 
 { 
-	if (!strcmp(opt,"off"))
+	if (!strncmp(opt,"off",3))
 		numa_off = 1;
 	return 1;
 } 
diff -urN linux-2.4.21-pre3/arch/x86_64/vmlinux.lds linux-2.4.21-pre4/arch/x86_64/vmlinux.lds
--- linux-2.4.21-pre3/arch/x86_64/vmlinux.lds	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/arch/x86_64/vmlinux.lds	Tue Jan 28 19:44:29 2003
@@ -55,10 +55,10 @@
   .vxtime_sequence : AT ((LOADADDR(.vsyscall_0) + SIZEOF(.vsyscall_0) + 63) & ~(63)) { *(.vxtime_sequence) }
   vxtime_sequence = LOADADDR(.vxtime_sequence);
   . = ALIGN(16);
-  .hpet : AT ((LOADADDR(.vxtime_sequence) + SIZEOF(.vxtime_sequence) + 15) & ~(15)) { *(.hpet) }
-  hpet = LOADADDR(.hpet);
+  .vxtime : AT ((LOADADDR(.vxtime_sequence) + SIZEOF(.vxtime_sequence) + 15) & ~(15)) { *(.vxtime) }
+  vxtime = LOADADDR(.vxtime);
   . = ALIGN(16);
-  .wall_jiffies : AT ((LOADADDR(.hpet) + SIZEOF(.hpet) + 15) & ~(15)) { *(.wall_jiffies) }
+  .wall_jiffies : AT ((LOADADDR(.vxtime) + SIZEOF(.vxtime) + 15) & ~(15)) { *(.wall_jiffies) }
   wall_jiffies = LOADADDR(.wall_jiffies);
   . = ALIGN(16);
   .sys_tz : AT ((LOADADDR(.wall_jiffies) + SIZEOF(.wall_jiffies) + 15) & ~(15)) { *(.sys_tz) }
@@ -98,6 +98,7 @@
   /DISCARD/ : {
 	*(.data.exit)
 	*(.exitcall.exit)
+	*(.eh_frame)
 	}
 
   /* DWARF 2 */
diff -urN linux-2.4.21-pre3/drivers/block/Makefile linux-2.4.21-pre4/drivers/block/Makefile
--- linux-2.4.21-pre3/drivers/block/Makefile	Fri Aug  2 17:39:43 2002
+++ linux-2.4.21-pre4/drivers/block/Makefile	Tue Jan 28 19:44:29 2003
@@ -10,7 +10,7 @@
 
 O_TARGET := block.o
 
-export-objs	:= ll_rw_blk.o blkpg.o loop.o DAC960.o genhd.o
+export-objs	:= ll_rw_blk.o blkpg.o loop.o DAC960.o genhd.o acsi.o
 
 obj-y	:= ll_rw_blk.o blkpg.o genhd.o elevator.o
 
diff -urN linux-2.4.21-pre3/drivers/block/amiflop.c linux-2.4.21-pre4/drivers/block/amiflop.c
--- linux-2.4.21-pre3/drivers/block/amiflop.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.21-pre4/drivers/block/amiflop.c	Tue Jan 28 19:44:29 2003
@@ -333,7 +333,7 @@
 
 	get_fdc(drive);
 	save_flags (flags);
-	sti();
+	cli();
 
 	selected = -1;
 
diff -urN linux-2.4.21-pre3/drivers/block/cciss.c linux-2.4.21-pre4/drivers/block/cciss.c
--- linux-2.4.21-pre3/drivers/block/cciss.c	Tue Jan 28 19:44:25 2003
+++ linux-2.4.21-pre4/drivers/block/cciss.c	Tue Jan 28 19:44:29 2003
@@ -505,16 +505,12 @@
 			return  -EFAULT;
 		return 0;
 	}
-	case BLKGETSIZE:
-		put_user(hba[ctlr]->hd[MINOR(inode->i_rdev)].nr_sects, (unsigned long *)arg);
-		return 0;
-	case BLKGETSIZE64:
-		put_user((u64)hba[ctlr]->hd[MINOR(inode->i_rdev)].nr_sects << 9, (u64*)arg);
-		return 0;
 	case BLKRRPART:
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
 		return revalidate_logvol(inode->i_rdev, 1);
+	case BLKGETSIZE:
+	case BLKGETSIZE64:
 	case BLKFLSBUF:
 	case BLKBSZSET:
 	case BLKBSZGET:
diff -urN linux-2.4.21-pre3/drivers/block/cpqarray.c linux-2.4.21-pre4/drivers/block/cpqarray.c
--- linux-2.4.21-pre3/drivers/block/cpqarray.c	Tue Jan 28 19:44:25 2003
+++ linux-2.4.21-pre4/drivers/block/cpqarray.c	Tue Jan 28 19:44:29 2003
@@ -1279,13 +1279,6 @@
 		ida_ioctl_t *io = (ida_ioctl_t*)arg;
 		return copy_to_user(&io->c.drv,&hba[ctlr]->drv[dsk],sizeof(drv_info_t));
 	}
-	case BLKGETSIZE:
-		if (!arg) 
-			return -EINVAL;
-		return put_user(hba[ctlr]->hd[MINOR(inode->i_rdev)].nr_sects, 
-			(unsigned long *)arg);
-	case BLKGETSIZE64:
-		return put_user((u64)(hba[ctlr]->hd[MINOR(inode->i_rdev)].nr_sects) << 9, (u64*)arg);
 	case BLKRRPART:
 		return revalidate_logvol(inode->i_rdev, 1);
 	case IDAPASSTHRU:
@@ -1379,6 +1372,8 @@
 		return(0);
 	}
 
+	case BLKGETSIZE:
+	case BLKGETSIZE64:
 	case BLKFLSBUF:
 	case BLKBSZSET:
 	case BLKBSZGET:
diff -urN linux-2.4.21-pre3/drivers/char/Config.in linux-2.4.21-pre4/drivers/char/Config.in
--- linux-2.4.21-pre3/drivers/char/Config.in	Tue Jan 28 19:44:25 2003
+++ linux-2.4.21-pre4/drivers/char/Config.in	Tue Jan 28 19:44:29 2003
@@ -199,6 +199,12 @@
    fi
 fi
 
+tristate 'IPMI top-level message handler' CONFIG_IPMI_HANDLER
+dep_mbool '  Generate a panic event to all BMCs on a panic' CONFIG_IPMI_PANIC_EVENT $CONFIG_IPMI_HANDLER
+dep_tristate '  Device interface for IPMI' CONFIG_IPMI_DEVICE_INTERFACE $CONFIG_IPMI_HANDLER
+dep_tristate '  IPMI KCS handler' CONFIG_IPMI_KCS $CONFIG_IPMI_HANDLER
+dep_tristate '  IPMI Watchdog Timer' CONFIG_IPMI_WATCHDOG $CONFIG_IPMI_HANDLER
+
 mainmenu_option next_comment
 comment 'Watchdog Cards'
 bool 'Watchdog Timer Support'	CONFIG_WATCHDOG
diff -urN linux-2.4.21-pre3/drivers/char/Makefile linux-2.4.21-pre4/drivers/char/Makefile
--- linux-2.4.21-pre3/drivers/char/Makefile	Tue Jan 28 19:44:25 2003
+++ linux-2.4.21-pre4/drivers/char/Makefile	Tue Jan 28 19:44:29 2003
@@ -66,6 +66,20 @@
    SERIAL   =
 endif
 
+ifeq ($(ARCH),parisc)
+   ifdef CONFIG_GSC_PS2
+      KEYBD   = hp_psaux.o hp_keyb.o
+   else
+      KEYBD   =
+   endif
+   ifdef CONFIG_SERIAL_MUX
+      CONSOLE += mux.o
+   endif
+   ifdef CONFIG_PDC_CONSOLE
+      CONSOLE += pdc_console.o
+   endif
+endif
+
 ifdef CONFIG_Q40
   KEYBD += q40_keyb.o
   SERIAL = serial.o
@@ -292,6 +306,11 @@
   obj-y += mwave/mwave.o
 endif
 
+subdir-$(CONFIG_IPMI_HANDLER) += ipmi
+ifeq ($(CONFIG_IPMI_HANDLER),y)
+  obj-y += ipmi/ipmi.o
+endif
+
 include $(TOPDIR)/Rules.make
 
 fastdep:
diff -urN linux-2.4.21-pre3/drivers/char/drm-4.0/i810_dma.c linux-2.4.21-pre4/drivers/char/drm-4.0/i810_dma.c
--- linux-2.4.21-pre3/drivers/char/drm-4.0/i810_dma.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/drivers/char/drm-4.0/i810_dma.c	Tue Jan 28 19:44:29 2003
@@ -231,7 +231,7 @@
 #else
         	retcode = do_munmap(current->mm, 
 				    (unsigned long)buf_priv->virtual, 
-				    (size_t) buf->total);
+				    (size_t) buf->total, 1);
 #endif
    		up_write(&current->mm->mmap_sem);
 	}
diff -urN linux-2.4.21-pre3/drivers/char/ipmi/Makefile linux-2.4.21-pre4/drivers/char/ipmi/Makefile
--- linux-2.4.21-pre3/drivers/char/ipmi/Makefile	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/drivers/char/ipmi/Makefile	Tue Jan 28 19:44:29 2003
@@ -0,0 +1,20 @@
+#
+# Makefile for the ipmi drivers.
+#
+
+O_TARGET	:= ipmi.o
+
+export-objs	:= ipmi_msghandler.o ipmi_watchdog.o
+
+list-multi := ipmi_kcs_drv.o
+ipmi_kcs_drv-objs := ipmi_kcs_sm.o ipmi_kcs_intf.o
+
+obj-$(CONFIG_IPMI_HANDLER) += ipmi_msghandler.o
+obj-$(CONFIG_IPMI_DEVICE_INTERFACE) += ipmi_devintf.o
+obj-$(CONFIG_IPMI_KCS) += ipmi_kcs_drv.o
+obj-$(CONFIG_IPMI_WATCHDOG) += ipmi_watchdog.o
+
+include $(TOPDIR)/Rules.make
+
+ipmi_kcs_drv.o:	$(ipmi_kcs_drv-objs)
+	$(LD) -r -o $@ $(ipmi_kcs_drv-objs) 
diff -urN linux-2.4.21-pre3/drivers/char/ipmi/ipmi_devintf.c linux-2.4.21-pre4/drivers/char/ipmi/ipmi_devintf.c
--- linux-2.4.21-pre3/drivers/char/ipmi/ipmi_devintf.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/drivers/char/ipmi/ipmi_devintf.c	Tue Jan 28 19:44:29 2003
@@ -0,0 +1,532 @@
+/*
+ * ipmi_devintf.c
+ *
+ * Linux device interface for the IPMI message handler.
+ *
+ * Author: MontaVista Software, Inc.
+ *         Corey Minyard <minyard@mvista.com>
+ *         source@mvista.com
+ *
+ * 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.
+ *
+ *
+ *  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/module.h>
+#include <linux/errno.h>
+#include <asm/system.h>
+#include <linux/sched.h>
+#include <linux/poll.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/ipmi.h>
+#include <asm/semaphore.h>
+#include <linux/init.h>
+
+struct ipmi_file_private
+{
+	ipmi_user_t          user;
+	spinlock_t           recv_msg_lock;
+	struct list_head     recv_msgs;
+	struct file          *file;
+	struct fasync_struct *fasync_queue;
+	wait_queue_head_t    wait;
+	struct semaphore     recv_sem;
+};
+
+static void file_receive_handler(struct ipmi_recv_msg *msg,
+				 void                 *handler_data)
+{
+	struct ipmi_file_private *priv = handler_data;
+	int                      was_empty;
+	unsigned long            flags;
+
+	spin_lock_irqsave(&(priv->recv_msg_lock), flags);
+
+	was_empty = list_empty(&(priv->recv_msgs));
+	list_add_tail(&(msg->link), &(priv->recv_msgs));
+
+	if (was_empty) {
+		wake_up_interruptible(&priv->wait);
+		kill_fasync(&priv->fasync_queue, SIGIO, POLL_IN);
+	}
+
+	spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
+}
+
+static unsigned int ipmi_poll(struct file *file, poll_table *wait)
+{
+	struct ipmi_file_private *priv = file->private_data;
+	unsigned int             mask = 0;
+	unsigned long            flags;
+
+	spin_lock_irqsave(&priv->recv_msg_lock, flags);
+
+	poll_wait(file, &priv->wait, wait);
+
+	if (! list_empty(&(priv->recv_msgs)))
+		mask |= (POLLIN | POLLRDNORM);
+
+	spin_unlock_irqrestore(&priv->recv_msg_lock, flags);
+
+	return mask;
+}
+
+static int ipmi_fasync(int fd, struct file *file, int on)
+{
+	struct ipmi_file_private *priv = file->private_data;
+	int                      result;
+
+	result = fasync_helper(fd, file, on, &priv->fasync_queue);
+
+	return (result);
+}
+
+static struct ipmi_user_hndl ipmi_hndlrs =
+{
+	ipmi_recv_hndl : file_receive_handler
+};
+
+static int ipmi_open(struct inode *inode, struct file *file)
+{
+	int                      if_num = minor(inode->i_rdev);
+	int                      rv;
+	struct ipmi_file_private *priv;
+
+
+	priv = kmalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->file = file;
+
+	rv = ipmi_create_user(if_num,
+			      &ipmi_hndlrs,
+			      priv,
+			      &(priv->user));
+	if (rv) {
+		kfree(priv);
+		return rv;
+	}
+
+	file->private_data = priv;
+
+	spin_lock_init(&(priv->recv_msg_lock));
+	INIT_LIST_HEAD(&(priv->recv_msgs));
+	init_waitqueue_head(&priv->wait);
+	priv->fasync_queue = NULL;
+	sema_init(&(priv->recv_sem), 1);
+
+	return 0;
+}
+
+static int ipmi_release(struct inode *inode, struct file *file)
+{
+	struct ipmi_file_private *priv = file->private_data;
+	int                      rv;
+
+	rv = ipmi_destroy_user(priv->user);
+	if (rv)
+		return rv;
+
+	ipmi_fasync (-1, file, 0);
+
+	/* FIXME - free the messages in the list. */
+	kfree(priv);
+
+	return 0;
+}
+
+static int ipmi_ioctl(struct inode  *inode,
+		      struct file   *file,
+		      unsigned int  cmd,
+		      unsigned long data)
+{
+	int                      rv = -EINVAL;
+	struct ipmi_file_private *priv = file->private_data;
+
+	switch (cmd) 
+	{
+	case IPMICTL_SEND_COMMAND:
+	{
+		struct ipmi_req    req;
+		struct ipmi_addr   addr;
+		unsigned char msgdata[IPMI_MAX_MSG_LENGTH];
+
+		if (copy_from_user(&req, (void *) data, sizeof(req))) {
+			rv = -EFAULT;
+			break;
+		}
+
+		if (req.addr_len > sizeof(struct ipmi_addr))
+		{
+			rv = -EINVAL;
+			break;
+		}
+
+		if (copy_from_user(&addr, req.addr, req.addr_len)) {
+			rv = -EFAULT;
+			break;
+		}
+
+		rv = ipmi_validate_addr(&addr, req.addr_len);
+		if (rv)
+			break;
+
+		if (req.msg.data != NULL) {
+			if (req.msg.data_len > IPMI_MAX_MSG_LENGTH) {
+				rv = -EMSGSIZE;
+				break;
+			}
+
+			if (copy_from_user(&msgdata,
+					   req.msg.data,
+					   req.msg.data_len))
+			{
+				rv = -EFAULT;
+				break;
+			}
+		} else {
+			req.msg.data_len = 0;
+		}
+
+		req.msg.data = msgdata;
+
+		rv = ipmi_request(priv->user,
+				  &addr,
+				  req.msgid,
+				  &(req.msg),
+				  0);
+		break;
+	}
+
+	case IPMICTL_RECEIVE_MSG:
+	case IPMICTL_RECEIVE_MSG_TRUNC:
+	{
+		struct ipmi_recv      rsp;
+		int              addr_len;
+		struct list_head *entry;
+		struct ipmi_recv_msg  *msg;
+		unsigned long    flags;
+		
+
+		rv = 0;
+		if (copy_from_user(&rsp, (void *) data, sizeof(rsp))) {
+			rv = -EFAULT;
+			break;
+		}
+
+		/* We claim a semaphore because we don't want two
+                   users getting something from the queue at a time.
+                   Since we have to release the spinlock before we can
+                   copy the data to the user, it's possible another
+                   user will grab something from the queue, too.  Then
+                   the messages might get out of order if something
+                   fails and the message gets put back onto the
+                   queue.  This semaphore prevents that problem. */
+		down(&(priv->recv_sem));
+
+		/* Grab the message off the list. */
+		spin_lock_irqsave(&(priv->recv_msg_lock), flags);
+		if (list_empty(&(priv->recv_msgs))) {
+			spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
+			rv = -EAGAIN;
+			goto recv_err;
+		}
+		entry = priv->recv_msgs.next;
+		msg = list_entry(entry, struct ipmi_recv_msg, link);
+		list_del(entry);
+		spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
+
+		addr_len = ipmi_addr_length(msg->addr.addr_type);
+		if (rsp.addr_len < addr_len)
+		{
+			rv = -EINVAL;
+			goto recv_putback_on_err;
+		}
+
+		if (copy_to_user(rsp.addr, &(msg->addr), addr_len)) {
+			rv = -EFAULT;
+			goto recv_putback_on_err;
+		}
+		rsp.addr_len = addr_len;
+
+		rsp.recv_type = msg->recv_type;
+		rsp.msgid = msg->msgid;
+		rsp.msg.netfn = msg->msg.netfn;
+		rsp.msg.cmd = msg->msg.cmd;
+
+		if (msg->msg.data_len > 0) {
+			if (rsp.msg.data_len < msg->msg.data_len) {
+				rv = -EMSGSIZE;
+				if (cmd == IPMICTL_RECEIVE_MSG_TRUNC) {
+					msg->msg.data_len = rsp.msg.data_len;
+				} else {
+					goto recv_putback_on_err;
+				}
+			}
+
+			if (copy_to_user(rsp.msg.data,
+					 msg->msg.data,
+					 msg->msg.data_len))
+			{
+				rv = -EFAULT;
+				goto recv_putback_on_err;
+			}
+			rsp.msg.data_len = msg->msg.data_len;
+		} else {
+			rsp.msg.data_len = 0;
+		}
+
+		if (copy_to_user((void *) data, &rsp, sizeof(rsp))) {
+			rv = -EFAULT;
+			goto recv_putback_on_err;
+		}
+
+		up(&(priv->recv_sem));
+		ipmi_free_recv_msg(msg);
+		break;
+
+	recv_putback_on_err:
+		/* If we got an error, put the message back onto
+		   the head of the queue. */
+		spin_lock_irqsave(&(priv->recv_msg_lock), flags);
+		list_add(entry, &(priv->recv_msgs));
+		spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
+		up(&(priv->recv_sem));
+		break;
+
+	recv_err:
+		up(&(priv->recv_sem));
+		break;
+	}
+
+	case IPMICTL_REGISTER_FOR_CMD:
+	{
+		struct ipmi_cmdspec val;
+
+		if (copy_from_user(&val, (void *) data, sizeof(val))) {
+			rv = -EFAULT;
+			break;
+		}
+
+		rv = ipmi_register_for_cmd(priv->user, val.netfn, val.cmd);
+		break;
+	}
+
+	case IPMICTL_UNREGISTER_FOR_CMD:
+	{
+		struct ipmi_cmdspec   val;
+
+		if (copy_from_user(&val, (void *) data, sizeof(val))) {
+			rv = -EFAULT;
+			break;
+		}
+
+		rv = ipmi_unregister_for_cmd(priv->user, val.netfn, val.cmd);
+		break;
+	}
+
+	case IPMICTL_SET_GETS_EVENTS_CMD:
+	{
+		int val;
+
+		if (copy_from_user(&val, (void *) data, sizeof(val))) {
+			rv = -EFAULT;
+			break;
+		}
+
+		rv = ipmi_set_gets_events(priv->user, val);
+		break;
+	}
+
+	case IPMICTL_SET_MY_ADDRESS_CMD:
+	{
+		unsigned int val;
+
+		if (copy_from_user(&val, (void *) data, sizeof(val))) {
+			rv = -EFAULT;
+			break;
+		}
+
+		ipmi_set_my_address(priv->user, val);
+		rv = 0;
+		break;
+	}
+
+	case IPMICTL_GET_MY_ADDRESS_CMD:
+	{
+		unsigned int val;
+
+		val = ipmi_get_my_address(priv->user);
+
+		if (copy_to_user((void *) data, &val, sizeof(val))) {
+			rv = -EFAULT;
+			break;
+		}
+		rv = 0;
+		break;
+	}
+
+	case IPMICTL_SET_MY_LUN_CMD:
+	{
+		unsigned int val;
+
+		if (copy_from_user(&val, (void *) data, sizeof(val))) {
+			rv = -EFAULT;
+			break;
+		}
+
+		ipmi_set_my_LUN(priv->user, val);
+		rv = 0;
+		break;
+	}
+
+	case IPMICTL_GET_MY_LUN_CMD:
+	{
+		unsigned int val;
+
+		val = ipmi_get_my_LUN(priv->user);
+
+		if (copy_to_user((void *) data, &val, sizeof(val))) {
+			rv = -EFAULT;
+			break;
+		}
+		rv = 0;
+		break;
+	}
+
+	}
+  
+	return rv;
+}
+
+
+static struct file_operations ipmi_fops = {
+	owner:   THIS_MODULE,
+	ioctl:   ipmi_ioctl,
+	open:    ipmi_open,
+	release: ipmi_release,
+	fasync:  ipmi_fasync,
+	poll:    ipmi_poll
+};
+
+#define DEVICE_NAME     "ipmidev"
+
+static int ipmi_major = 0;
+MODULE_PARM(ipmi_major, "i");
+
+static devfs_handle_t devfs_handle;
+
+#define MAX_DEVICES 10
+static devfs_handle_t handles[MAX_DEVICES];
+
+static void ipmi_new_smi(int if_num)
+{
+	char name[2];
+
+	if (if_num > MAX_DEVICES)
+		return;
+
+	name[0] = if_num + '0';
+	name[1] = '\0';
+
+	handles[if_num] = devfs_register(devfs_handle, name, DEVFS_FL_NONE,
+					 ipmi_major, if_num,
+					 S_IFCHR | S_IRUSR | S_IWUSR,
+					 &ipmi_fops, NULL);
+}
+
+static void ipmi_smi_gone(int if_num)
+{
+	if (if_num > MAX_DEVICES)
+		return;
+
+	devfs_unregister(handles[if_num]);
+}
+
+static struct ipmi_smi_watcher smi_watcher =
+{
+	new_smi  : ipmi_new_smi,
+	smi_gone : ipmi_smi_gone
+};
+
+static __init int init_ipmi_devintf(void)
+{
+	int rv;
+
+	if (ipmi_major < 0)
+		return -EINVAL;
+
+	rv = register_chrdev(ipmi_major, DEVICE_NAME, &ipmi_fops);
+	if (rv < 0) {
+		printk(KERN_ERR "ipmi: can't get major %d\n", ipmi_major);
+		return rv;
+	}
+
+	if (ipmi_major == 0) {
+		ipmi_major = rv;
+	}
+
+	devfs_handle = devfs_mk_dir(NULL, DEVICE_NAME, NULL);
+
+	rv = ipmi_smi_watcher_register(&smi_watcher);
+	if (rv) {
+		unregister_chrdev(ipmi_major, DEVICE_NAME);
+		printk(KERN_WARNING "ipmi: can't register smi watcher");
+		return rv;
+	}
+
+	printk(KERN_INFO "ipmi: device interface at char major %d\n",
+	       ipmi_major);
+
+	return 0;
+}
+module_init(init_ipmi_devintf);
+
+static __exit void cleanup_ipmi(void)
+{
+	ipmi_smi_watcher_unregister(&smi_watcher);
+	devfs_unregister(devfs_handle);
+	unregister_chrdev(ipmi_major, DEVICE_NAME);
+}
+module_exit(cleanup_ipmi);
+#ifndef MODULE
+static __init int ipmi_setup (char *str)
+{
+	int x;
+
+	if (get_option (&str, &x)) {
+		/* ipmi=x sets the major number to x. */
+		ipmi_major = x;
+	} else if (!strcmp(str, "off")) {
+		ipmi_major = -1;
+	}
+
+	return 1;
+}
+#endif
+
+__setup("ipmi=", ipmi_setup);
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.21-pre3/drivers/char/ipmi/ipmi_kcs_intf.c linux-2.4.21-pre4/drivers/char/ipmi/ipmi_kcs_intf.c
--- linux-2.4.21-pre3/drivers/char/ipmi/ipmi_kcs_intf.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/drivers/char/ipmi/ipmi_kcs_intf.c	Tue Jan 28 19:44:29 2003
@@ -0,0 +1,1235 @@
+/*
+ * ipmi_kcs_intf.c
+ *
+ * The interface to the IPMI driver for the KCS.
+ *
+ * Author: MontaVista Software, Inc.
+ *         Corey Minyard <minyard@mvista.com>
+ *         source@mvista.com
+ *
+ * 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.
+ *
+ *
+ *  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 holds the "policy" for the interface to the KCS state
+ * machine.  It does the configuration, handles timers and interrupts,
+ * and drives the real KCS state machine.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <asm/system.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/ioport.h>
+#ifdef CONFIG_HIGH_RES_TIMERS
+#include <linux/hrtime.h>
+#endif
+#include <linux/interrupt.h>
+#include <linux/ipmi_smi.h>
+#include <asm/io.h>
+#include "ipmi_kcs_sm.h"
+#include <linux/init.h>
+
+/* Measure times between events in the driver. */
+#undef DEBUG_TIMING
+
+#ifdef CONFIG_IPMI_KCS
+/* This forces a dependency to the config file for this option. */
+#endif
+
+enum kcs_intf_state {
+	KCS_NORMAL,
+	KCS_GETTING_FLAGS,
+	KCS_GETTING_EVENTS,
+	KCS_CLEARING_FLAGS,
+	KCS_CLEARING_FLAGS_THEN_SET_IRQ,
+	KCS_GETTING_MESSAGES,
+	KCS_ENABLE_INTERRUPTS1,
+	KCS_ENABLE_INTERRUPTS2
+	/* FIXME - add watchdog stuff. */
+};
+
+struct kcs_info
+{
+	ipmi_smi_t          intf;
+	struct kcs_data     *kcs_sm;
+	spinlock_t          kcs_lock;
+	spinlock_t          msg_lock;
+	struct list_head    xmit_msgs;
+	struct list_head    hp_xmit_msgs;
+	struct ipmi_smi_msg *curr_msg;
+	enum kcs_intf_state kcs_state;
+
+	/* Flags from the last GET_MSG_FLAGS command, used when an ATTN
+	   is set to hold the flags until we are done handling everything
+	   from the flags. */
+#define RECEIVE_MSG_AVAIL	0x01
+#define EVENT_MSG_BUFFER_FULL	0x02
+#define WDT_PRE_TIMEOUT_INT	0x08
+	unsigned char       msg_flags;
+
+	/* If set to true, this will request events the next time the
+	   state machine is idle. */
+	atomic_t            req_events;
+
+	/* If true, run the state machine to completion on every send
+	   call.  Generally used after a panic to make sure stuff goes
+	   out. */
+	int                 run_to_completion;
+
+	/* The I/O port of a KCS interface. */
+	int                 port;
+
+	/* zero if no irq; */
+	int                 irq;
+
+	/* The physical and remapped memory addresses of a KCS interface. */
+	unsigned long	    physaddr;
+	unsigned char	    *addr;
+
+	/* The timer for this kcs. */
+	struct timer_list   kcs_timer;
+
+	/* The time (in jiffies) the last timeout occurred at. */
+	unsigned long       last_timeout_jiffies;
+
+	/* Used to gracefully stop the timer without race conditions. */
+	volatile int        stop_operation;
+	volatile int        timer_stopped;
+
+	/* The driver will disable interrupts when it gets into a
+	   situation where it cannot handle messages due to lack of
+	   memory.  Once that situation clears up, it will re-enable
+	   interupts. */
+	int                 interrupt_disabled;
+};
+
+static void deliver_recv_msg(struct kcs_info *kcs_info, struct ipmi_smi_msg *msg)
+{
+	/* Deliver the message to the upper layer with the lock
+           released. */
+	spin_unlock(&(kcs_info->kcs_lock));
+	ipmi_smi_msg_received(kcs_info->intf, msg);
+	spin_lock(&(kcs_info->kcs_lock));
+}
+
+static void return_hosed_msg(struct kcs_info *kcs_info)
+{
+	struct ipmi_smi_msg *msg = kcs_info->curr_msg;
+
+	/* Make it a reponse */
+	msg->rsp[0] = msg->data[0] | 4;
+	msg->rsp[1] = msg->data[1];
+	msg->rsp[2] = 0xFF; /* Unknown error. */
+	msg->rsp_size = 3;
+			
+	kcs_info->curr_msg = NULL;
+	deliver_recv_msg(kcs_info, msg);
+}
+
+static enum kcs_result start_next_msg(struct kcs_info *kcs_info)
+{
+	int              rv;
+	struct list_head *entry = NULL;
+#ifdef DEBUG_TIMING
+	struct timeval t;
+#endif
+
+	/* No need to save flags, we aleady have interrupts off and we
+	   already hold the KCS lock. */
+	spin_lock(&(kcs_info->msg_lock));
+	
+	/* Pick the high priority queue first. */
+	if (! list_empty(&(kcs_info->hp_xmit_msgs))) {
+		entry = kcs_info->hp_xmit_msgs.next;
+	} else if (! list_empty(&(kcs_info->xmit_msgs))) {
+		entry = kcs_info->xmit_msgs.next;
+	}
+
+	if (!entry) {
+		kcs_info->curr_msg = NULL;
+		rv = KCS_SM_IDLE;
+	} else {
+		int err;
+
+		list_del(entry);
+		kcs_info->curr_msg = list_entry(entry,
+						struct ipmi_smi_msg,
+						link);
+#ifdef DEBUG_TIMING
+		do_gettimeofday(&t);
+		printk("**Start2: %d.%9.9d\n", t.tv_sec, t.tv_usec);
+#endif
+		err = start_kcs_transaction(kcs_info->kcs_sm,
+					   kcs_info->curr_msg->data,
+					   kcs_info->curr_msg->data_size);
+		if (err) {
+			return_hosed_msg(kcs_info);
+		}
+
+		rv = KCS_CALL_WITHOUT_DELAY;
+	}
+	spin_unlock(&(kcs_info->msg_lock));
+
+	return rv;
+}
+
+static void start_enable_irq(struct kcs_info *kcs_info)
+{
+	unsigned char msg[2];
+
+	/* If we are enabling interrupts, we have to tell the
+	   BMC to use them. */
+	msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
+	msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD;
+
+	start_kcs_transaction(kcs_info->kcs_sm, msg, 2);
+	kcs_info->kcs_state = KCS_ENABLE_INTERRUPTS1;
+}
+
+static void start_clear_flags(struct kcs_info *kcs_info)
+{
+	unsigned char msg[3];
+
+	/* Make sure the watchdog pre-timeout flag is not set at startup. */
+	msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
+	msg[1] = IPMI_CLEAR_MSG_FLAGS_CMD;
+	msg[2] = WDT_PRE_TIMEOUT_INT;
+
+	start_kcs_transaction(kcs_info->kcs_sm, msg, 3);
+	kcs_info->kcs_state = KCS_CLEARING_FLAGS;
+}
+
+/* When we have a situtaion where we run out of memory and cannot
+   allocate messages, we just leave them in the BMC and run the system
+   polled until we can allocate some memory.  Once we have some
+   memory, we will re-enable the interrupt. */
+static inline void disable_kcs_irq(struct kcs_info *kcs_info)
+{
+	if ((kcs_info->irq) && (!kcs_info->interrupt_disabled)) {
+		disable_irq_nosync(kcs_info->irq);
+		kcs_info->interrupt_disabled = 1;
+	}
+}
+
+static inline void enable_kcs_irq(struct kcs_info *kcs_info)
+{
+	if ((kcs_info->irq) && (kcs_info->interrupt_disabled)) {
+		enable_irq(kcs_info->irq);
+		kcs_info->interrupt_disabled = 0;
+	}
+}
+
+static void handle_flags(struct kcs_info *kcs_info)
+{
+	if (kcs_info->msg_flags & WDT_PRE_TIMEOUT_INT) {
+		/* Watchdog pre-timeout */
+		start_clear_flags(kcs_info);
+		spin_unlock(&(kcs_info->kcs_lock));
+		ipmi_smi_watchdog_pretimeout(kcs_info->intf);
+		spin_lock(&(kcs_info->kcs_lock));
+	} else if (kcs_info->msg_flags & RECEIVE_MSG_AVAIL) {
+		/* Messages available. */
+		kcs_info->curr_msg = ipmi_alloc_smi_msg();
+		if (!kcs_info->curr_msg) {
+			disable_kcs_irq(kcs_info);
+			kcs_info->kcs_state = KCS_NORMAL;
+			return;
+		}
+		enable_kcs_irq(kcs_info);
+
+		kcs_info->curr_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
+		kcs_info->curr_msg->data[1] = IPMI_GET_MSG_CMD;
+		kcs_info->curr_msg->data_size = 2;
+
+		start_kcs_transaction(kcs_info->kcs_sm,
+				      kcs_info->curr_msg->data,
+				      kcs_info->curr_msg->data_size);
+		kcs_info->kcs_state = KCS_GETTING_MESSAGES;
+	} else if (kcs_info->msg_flags & EVENT_MSG_BUFFER_FULL) {
+		/* Events available. */
+		kcs_info->curr_msg = ipmi_alloc_smi_msg();
+		if (!kcs_info->curr_msg) {
+			disable_kcs_irq(kcs_info);
+			kcs_info->kcs_state = KCS_NORMAL;
+			return;
+		}
+		enable_kcs_irq(kcs_info);
+
+		kcs_info->curr_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
+		kcs_info->curr_msg->data[1] = IPMI_READ_EVENT_MSG_BUFFER_CMD;
+		kcs_info->curr_msg->data_size = 2;
+
+		start_kcs_transaction(kcs_info->kcs_sm,
+				      kcs_info->curr_msg->data,
+				      kcs_info->curr_msg->data_size);
+		kcs_info->kcs_state = KCS_GETTING_EVENTS;
+	} else {
+		kcs_info->kcs_state = KCS_NORMAL;
+	}
+}
+
+static void handle_transaction_done(struct kcs_info *kcs_info)
+{
+	struct ipmi_smi_msg *msg;
+#ifdef DEBUG_TIMING
+	struct timeval t;
+
+	do_gettimeofday(&t);
+	printk("**Done: %d.%9.9d\n", t.tv_sec, t.tv_usec);
+#endif
+	switch (kcs_info->kcs_state) {
+	case KCS_NORMAL:
+		kcs_info->curr_msg->rsp_size
+			= kcs_get_result(kcs_info->kcs_sm,
+					 kcs_info->curr_msg->rsp,
+					 IPMI_MAX_MSG_LENGTH);
+		
+		/* Do this here becase deliver_recv_msg() releases the
+		   lock, and a new message can be put in during the
+		   time the lock is released. */
+		msg = kcs_info->curr_msg;
+		kcs_info->curr_msg = NULL;
+		deliver_recv_msg(kcs_info, msg);
+		break;
+		
+	case KCS_GETTING_FLAGS:
+	{
+		unsigned char msg[4];
+
+		/* We got the flags from the KCS, now handle them. */
+		kcs_get_result(kcs_info->kcs_sm, msg, 4);
+		if (msg[2] != 0) {
+			/* Error fetching flags, just give up for
+			   now. */
+			kcs_info->kcs_state = KCS_NORMAL;
+		} else {
+			kcs_info->msg_flags = msg[3];
+			handle_flags(kcs_info);
+		}
+		break;
+	}
+
+	case KCS_CLEARING_FLAGS:
+	case KCS_CLEARING_FLAGS_THEN_SET_IRQ:
+	{
+		unsigned char msg[3];
+
+		/* We cleared the flags. */
+		kcs_get_result(kcs_info->kcs_sm, msg, 3);
+		if (msg[2] != 0) {
+			/* Error clearing flags */
+			printk(KERN_WARNING
+			       "ipmi_kcs: Error clearing flags: %2.2x\n",
+			       msg[2]);
+		}
+		if (kcs_info->kcs_state == KCS_CLEARING_FLAGS_THEN_SET_IRQ)
+			start_enable_irq(kcs_info);
+		else
+			kcs_info->kcs_state = KCS_NORMAL;
+		break;
+	}
+
+	case KCS_GETTING_EVENTS:
+	{
+		kcs_info->curr_msg->rsp_size
+			= kcs_get_result(kcs_info->kcs_sm,
+					 kcs_info->curr_msg->rsp,
+					 IPMI_MAX_MSG_LENGTH);
+
+		/* Do this here becase deliver_recv_msg() releases the
+		   lock, and a new message can be put in during the
+		   time the lock is released. */
+		msg = kcs_info->curr_msg;
+		kcs_info->curr_msg = NULL;
+		if (msg->rsp[2] != 0) {
+			/* Error getting event, probably done. */
+			msg->done(msg);
+
+			/* Take off the event flag. */
+			kcs_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
+		} else {
+			deliver_recv_msg(kcs_info, msg);
+		}
+		handle_flags(kcs_info);
+		break;
+	}
+
+	case KCS_GETTING_MESSAGES:
+	{
+		kcs_info->curr_msg->rsp_size
+			= kcs_get_result(kcs_info->kcs_sm,
+					 kcs_info->curr_msg->rsp,
+					 IPMI_MAX_MSG_LENGTH);
+
+		/* Do this here becase deliver_recv_msg() releases the
+		   lock, and a new message can be put in during the
+		   time the lock is released. */
+		msg = kcs_info->curr_msg;
+		kcs_info->curr_msg = NULL;
+		if (msg->rsp[2] != 0) {
+			/* Error getting event, probably done. */
+			msg->done(msg);
+
+			/* Take off the msg flag. */
+			kcs_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
+		} else {
+			deliver_recv_msg(kcs_info, msg);
+		}
+		handle_flags(kcs_info);
+		break;
+	}
+
+	case KCS_ENABLE_INTERRUPTS1:
+	{
+		unsigned char msg[4];
+
+		/* We got the flags from the KCS, now handle them. */
+		kcs_get_result(kcs_info->kcs_sm, msg, 4);
+		if (msg[2] != 0) {
+			printk(KERN_WARNING
+			       "ipmi_kcs: Could not enable interrupts"
+			       ", failed get, using polled mode.\n");
+			kcs_info->kcs_state = KCS_NORMAL;
+		} else {
+			msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
+			msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD;
+			msg[2] = msg[3] | 1; /* enable msg queue int */
+			start_kcs_transaction(kcs_info->kcs_sm, msg,3);
+			kcs_info->kcs_state = KCS_ENABLE_INTERRUPTS2;
+		}
+		break;
+	}
+
+	case KCS_ENABLE_INTERRUPTS2:
+	{
+		unsigned char msg[4];
+
+		/* We got the flags from the KCS, now handle them. */
+		kcs_get_result(kcs_info->kcs_sm, msg, 4);
+		if (msg[2] != 0) {
+			printk(KERN_WARNING
+			       "ipmi_kcs: Could not enable interrupts"
+			       ", failed set, using polled mode.\n");
+		}
+		kcs_info->kcs_state = KCS_NORMAL;
+		break;
+	}
+	}
+}
+
+/* Called on timeouts and events.  Timeouts should pass the elapsed
+   time, interrupts should pass in zero. */
+static enum kcs_result kcs_event_handler(struct kcs_info *kcs_info, int time)
+{
+	enum kcs_result kcs_result;
+
+ restart:
+	/* There used to be a loop here that waited a little while
+	   (around 25us) before giving up.  That turned out to be
+	   pointless, the minimum delays I was seeing were in the 300us
+	   range, which is far too long to wait in an interrupt.  So
+	   we just run until the state machine tells us something
+	   happened or it needs a delay. */
+	kcs_result = kcs_event(kcs_info->kcs_sm, time);
+	time = 0;
+	while (kcs_result == KCS_CALL_WITHOUT_DELAY)
+	{
+		kcs_result = kcs_event(kcs_info->kcs_sm, 0);
+	}
+
+	if (kcs_result == KCS_TRANSACTION_COMPLETE)
+	{
+		handle_transaction_done(kcs_info);
+		kcs_result = kcs_event(kcs_info->kcs_sm, 0);
+	}
+	else if (kcs_result == KCS_SM_HOSED)
+	{
+		if (kcs_info->curr_msg != NULL) {
+			/* If we were handling a user message, format
+                           a response to send to the upper layer to
+                           tell it about the error. */
+			return_hosed_msg(kcs_info);
+		}
+		kcs_result = kcs_event(kcs_info->kcs_sm, 0);
+		kcs_info->kcs_state = KCS_NORMAL;
+	}
+
+	/* We prefer handling attn over new messages. */
+	if (kcs_result == KCS_ATTN)
+	{
+		unsigned char msg[2];
+
+		/* Got a attn, send down a get message flags to see
+                   what's causing it.  It would be better to handle
+                   this in the upper layer, but due to the way
+                   interrupts work with the KCS, that's not really
+                   possible. */
+		msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
+		msg[1] = IPMI_GET_MSG_FLAGS_CMD;
+
+		start_kcs_transaction(kcs_info->kcs_sm, msg, 2);
+		kcs_info->kcs_state = KCS_GETTING_FLAGS;
+		goto restart;
+	}
+
+	/* If we are currently idle, try to start the next message. */
+	if (kcs_result == KCS_SM_IDLE) {
+		kcs_result = start_next_msg(kcs_info);
+		if (kcs_result != KCS_SM_IDLE)
+			goto restart;
+        }
+
+	if ((kcs_result == KCS_SM_IDLE)
+	    && (atomic_read(&kcs_info->req_events)))
+	{
+		/* We are idle and the upper layer requested that I fetch
+		   events, so do so. */
+		unsigned char msg[2];
+
+		atomic_set(&kcs_info->req_events, 0);
+		msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
+		msg[1] = IPMI_GET_MSG_FLAGS_CMD;
+
+		start_kcs_transaction(kcs_info->kcs_sm, msg, 2);
+		kcs_info->kcs_state = KCS_GETTING_FLAGS;
+		goto restart;
+	}
+
+	return kcs_result;
+}
+
+static void sender(void                *send_info,
+		   struct ipmi_smi_msg *msg,
+		   int                 priority)
+{
+	struct kcs_info *kcs_info = (struct kcs_info *) send_info;
+	enum kcs_result result;
+	unsigned long   flags;
+#ifdef DEBUG_TIMING
+	struct timeval t;
+#endif
+
+	spin_lock_irqsave(&(kcs_info->msg_lock), flags);
+#ifdef DEBUG_TIMING
+	do_gettimeofday(&t);
+	printk("**Enqueue: %d.%9.9d\n", t.tv_sec, t.tv_usec);
+#endif
+
+	if (kcs_info->run_to_completion) {
+		/* If we are running to completion, then throw it in
+		   the list and run transactions until everything is
+		   clear.  Priority doesn't matter here. */
+		list_add_tail(&(msg->link), &(kcs_info->xmit_msgs));
+
+		/* We have to release the msg lock and claim the kcs
+		   lock in this case, because of race conditions. */
+		spin_unlock_irqrestore(&(kcs_info->msg_lock), flags);
+
+		spin_lock_irqsave(&(kcs_info->kcs_lock), flags);
+		result = kcs_event_handler(kcs_info, 0);
+		while (result != KCS_SM_IDLE) {
+			udelay(500);
+			result = kcs_event_handler(kcs_info, 500);
+		}
+		spin_unlock_irqrestore(&(kcs_info->kcs_lock), flags);
+		return;
+	} else {
+		if (priority > 0) {
+			list_add_tail(&(msg->link), &(kcs_info->hp_xmit_msgs));
+		} else {
+			list_add_tail(&(msg->link), &(kcs_info->xmit_msgs));
+		}
+	}
+	spin_unlock_irqrestore(&(kcs_info->msg_lock), flags);
+
+	spin_lock_irqsave(&(kcs_info->kcs_lock), flags);
+	if ((kcs_info->kcs_state == KCS_NORMAL)
+	    && (kcs_info->curr_msg == NULL))
+	{
+		start_next_msg(kcs_info);
+	}
+	spin_unlock_irqrestore(&(kcs_info->kcs_lock), flags);
+}
+
+static void set_run_to_completion(void *send_info, int i_run_to_completion)
+{
+	struct kcs_info *kcs_info = (struct kcs_info *) send_info;
+	enum kcs_result result;
+	unsigned long   flags;
+
+	spin_lock_irqsave(&(kcs_info->kcs_lock), flags);
+
+	kcs_info->run_to_completion = i_run_to_completion;
+	if (i_run_to_completion) {
+		result = kcs_event_handler(kcs_info, 0);
+		while (result != KCS_SM_IDLE) {
+			udelay(500);
+			result = kcs_event_handler(kcs_info, 500);
+		}
+	}
+
+	spin_unlock_irqrestore(&(kcs_info->kcs_lock), flags);
+}
+
+static void request_events(void *send_info)
+{
+	struct kcs_info *kcs_info = (struct kcs_info *) send_info;
+
+	atomic_set(&kcs_info->req_events, 1);
+}
+
+static int new_user(void *send_info)
+{
+	if (!try_inc_mod_count(THIS_MODULE))
+		return -EBUSY;
+	return 0;
+}
+
+static void user_left(void *send_info)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+/* Call every 10 ms. */
+#define KCS_TIMEOUT_TIME_USEC	10000
+#define KCS_USEC_PER_JIFFY	(1000000/HZ)
+#define KCS_TIMEOUT_JIFFIES	(KCS_TIMEOUT_TIME_USEC/KCS_USEC_PER_JIFFY)
+#define KCS_SHORT_TIMEOUT_USEC  500 /* .5ms when the SM request a
+                                       short timeout */
+static int initialized = 0;
+
+static void kcs_timeout(unsigned long data)
+{
+	struct kcs_info *kcs_info = (struct kcs_info *) data;
+	enum kcs_result kcs_result;
+	unsigned long   flags;
+	unsigned long   jiffies_now;
+	unsigned long   time_diff;
+#ifdef DEBUG_TIMING
+	struct timeval t;
+#endif
+
+	if (kcs_info->stop_operation) {
+		kcs_info->timer_stopped = 1;
+		return;
+	}
+
+	spin_lock_irqsave(&(kcs_info->kcs_lock), flags);
+#ifdef DEBUG_TIMING
+	do_gettimeofday(&t);
+	printk("**Timer: %d.%9.9d\n", t.tv_sec, t.tv_usec);
+#endif
+	jiffies_now = jiffies;
+	time_diff = ((jiffies_now - kcs_info->last_timeout_jiffies)
+		     * KCS_USEC_PER_JIFFY);
+	kcs_result = kcs_event_handler(kcs_info, time_diff);
+
+	spin_unlock_irqrestore(&(kcs_info->kcs_lock), flags);
+
+	kcs_info->last_timeout_jiffies = jiffies_now;
+
+	if ((kcs_info->irq) && (! kcs_info->interrupt_disabled)) {
+		/* Running with interrupts, only do long timeouts. */
+		kcs_info->kcs_timer.expires = jiffies + KCS_TIMEOUT_JIFFIES;
+		goto do_add_timer;
+	}
+
+	/* If the state machine asks for a short delay, then shorten
+           the timer timeout. */
+#ifdef CONFIG_HIGH_RES_TIMERS
+	if (kcs_result == KCS_CALL_WITH_DELAY) {
+		kcs_info->kcs_timer.sub_expires
+			+= usec_to_arch_cycles(KCS_SHORT_TIMEOUT_USEC);
+		while (kcs_info->kcs_timer.sub_expires >= cycles_per_jiffies) {
+			kcs_info->kcs_timer.expires++;
+			kcs_info->kcs_timer.sub_expires -= cycles_per_jiffies;
+		}
+	} else {
+		kcs_info->kcs_timer.expires = jiffies + KCS_TIMEOUT_JIFFIES;
+	}
+#else
+	/* If requested, take the shortest delay possible */
+	if (kcs_result == KCS_CALL_WITH_DELAY) {
+		kcs_info->kcs_timer.expires = jiffies + 1;
+	} else {
+		kcs_info->kcs_timer.expires = jiffies + KCS_TIMEOUT_JIFFIES;
+	}
+#endif
+
+ do_add_timer:
+	add_timer(&(kcs_info->kcs_timer));
+}
+
+static void kcs_irq_handler(int irq, void *data, struct pt_regs *regs)
+{
+	struct kcs_info *kcs_info = (struct kcs_info *) data;
+	unsigned long   flags;
+#ifdef DEBUG_TIMING
+	struct timeval t;
+#endif
+
+	spin_lock_irqsave(&(kcs_info->kcs_lock), flags);
+	if (kcs_info->stop_operation)
+		goto out;
+
+#ifdef DEBUG_TIMING
+	do_gettimeofday(&t);
+	printk("**Interrupt: %d.%9.9d\n", t.tv_sec, t.tv_usec);
+#endif
+	kcs_event_handler(kcs_info, 0);
+ out:
+	spin_unlock_irqrestore(&(kcs_info->kcs_lock), flags);
+}
+
+static struct ipmi_smi_handlers handlers =
+{
+	sender:		       sender,
+	request_events:        request_events,
+	new_user:	       new_user,
+	user_left:	       user_left,
+	set_run_to_completion: set_run_to_completion
+};
+
+static unsigned char ipmi_kcs_dev_rev;
+static unsigned char ipmi_kcs_fw_rev_major;
+static unsigned char ipmi_kcs_fw_rev_minor;
+static unsigned char ipmi_version_major;
+static unsigned char ipmi_version_minor;
+
+extern int kcs_dbg;
+static int ipmi_kcs_detect_hardware(unsigned int port,
+				    unsigned char *addr,
+				    struct kcs_data *data)
+{
+	unsigned char   msg[2];
+	unsigned char   resp[IPMI_MAX_MSG_LENGTH];
+	unsigned long   resp_len;
+	enum kcs_result kcs_result;
+
+	/* It's impossible for the KCS status register to be all 1's,
+	   (assuming a properly functioning, self-initialized BMC)
+	   but that's what you get from reading a bogus address, so we
+	   test that first. */
+
+	if (port) {
+		if (inb(port+1) == 0xff) return -ENODEV; 
+	} else { 
+		if (readb(addr+1) == 0xff) return -ENODEV; 
+	}
+
+	/* Do a Get Device ID command, since it comes back with some
+	   useful info. */
+	msg[0] = IPMI_NETFN_APP_REQUEST << 2;
+	msg[1] = IPMI_GET_DEVICE_ID_CMD;
+	start_kcs_transaction(data, msg, 2);
+	
+	kcs_result = kcs_event(data, 0);
+	for (;;)
+	{
+		if (kcs_result == KCS_CALL_WITH_DELAY) {
+			udelay(100);
+			kcs_result = kcs_event(data, 100);
+		}
+		else if (kcs_result == KCS_CALL_WITHOUT_DELAY)
+		{
+			kcs_result = kcs_event(data, 0);
+		}
+		else
+			break;
+	}
+	if (kcs_result == KCS_SM_HOSED) {
+		/* We couldn't get the state machine to run, so whatever's at
+		   the port is probably not an IPMI KCS interface. */
+		return -ENODEV;
+	}
+	/* Otherwise, we got some data. */
+	resp_len = kcs_get_result(data, resp, IPMI_MAX_MSG_LENGTH);
+	if (resp_len < 6)
+		/* That's odd, it should be longer. */
+		return -EINVAL;
+	
+	if ((resp[1] != IPMI_GET_DEVICE_ID_CMD) || (resp[2] != 0))
+		/* That's odd, it shouldn't be able to fail. */
+		return -EINVAL;
+	
+	ipmi_kcs_dev_rev = resp[4] & 0xf;
+	ipmi_kcs_fw_rev_major = resp[5] & 0x7f;
+	ipmi_kcs_fw_rev_minor = resp[6];
+	ipmi_version_major = resp[7] & 0xf;
+	ipmi_version_minor = resp[7] >> 4;
+
+	return 0;
+}
+
+/* There can be 4 IO ports passed in (with or without IRQs), 4 addresses,
+   a default IO port, and 1 ACPI/SPMI address.  That sets KCS_MAX_DRIVERS */
+
+#define KCS_MAX_PARMS 4
+#define KCS_MAX_DRIVERS ((KCS_MAX_PARMS * 2) + 2)
+static struct kcs_info *kcs_infos[KCS_MAX_DRIVERS] =
+{ NULL, NULL, NULL, NULL };
+
+#define DEVICE_NAME "ipmi_kcs"
+
+#define DEFAULT_IO_PORT 0xca2
+
+static int kcs_trydefaults = 1;
+static unsigned long kcs_addrs[KCS_MAX_PARMS] = { 0, 0, 0, 0 };
+static int kcs_ports[KCS_MAX_PARMS] = { 0, 0, 0, 0 };
+static int kcs_irqs[KCS_MAX_PARMS] = { 0, 0, 0, 0 };
+
+MODULE_PARM(kcs_trydefaults, "i");
+MODULE_PARM(kcs_addrs, "1-4l");
+MODULE_PARM(kcs_irqs, "1-4i");
+MODULE_PARM(kcs_ports, "1-4i");
+
+/* Returns 0 if initialized, or negative on an error. */
+static int init_one_kcs(int kcs_port, 
+			int irq, 
+			unsigned long kcs_physaddr,
+			struct kcs_info **kcs)
+{
+	int		rv;
+	struct kcs_info *new_kcs;
+
+	/* Did anything get passed in at all?  Both == zero disables the
+	   driver. */
+
+	if (!(kcs_port || kcs_physaddr)) 
+		return -ENODEV;
+	
+	/* Only initialize a port OR a physical address on this call.
+	   Also, IRQs can go with either ports or addresses. */
+
+	if (kcs_port && kcs_physaddr)
+		return -EINVAL;
+
+	new_kcs = kmalloc(kcs_size(), GFP_KERNEL);
+	if (!new_kcs) {
+		printk(KERN_ERR "ipmi_kcs: out of memory\n");
+		return -ENOMEM;
+	}
+
+	/* So we know not to free it unless we have allocated one. */
+	new_kcs->kcs_sm = NULL;
+
+	new_kcs->addr = NULL;
+	new_kcs->physaddr = kcs_physaddr;
+	new_kcs->port = kcs_port;
+
+	if (kcs_port) {
+		if (request_region(kcs_port, 2, DEVICE_NAME) == NULL) {
+			kfree(new_kcs);
+			printk(KERN_ERR 
+			       "ipmi_kcs: can't reserve port @ 0x%4.4x\n",
+		       	       kcs_port);
+			return -EIO;
+		}
+	} else {
+		if (request_mem_region(kcs_physaddr, 2, DEVICE_NAME) == NULL) {
+			kfree(new_kcs);
+			printk(KERN_ERR 
+			       "ipmi_kcs: can't reserve memory @ 0x%lx\n",
+		       	       kcs_physaddr);
+			return -EIO;
+		}
+		if ((new_kcs->addr = ioremap(kcs_physaddr, 2)) == NULL) {
+			kfree(new_kcs);
+			printk(KERN_ERR 
+			       "ipmi_kcs: can't remap memory at 0x%lx\n",
+		       	       kcs_physaddr);
+			return -EIO;
+		}
+	}
+
+	new_kcs->kcs_sm = kmalloc(kcs_size(), GFP_KERNEL);
+	if (!new_kcs->kcs_sm) {
+		printk(KERN_ERR "ipmi_kcs: out of memory\n");
+		rv = -ENOMEM;
+		goto out_err;
+	}
+	init_kcs_data(new_kcs->kcs_sm, kcs_port, new_kcs->addr);
+	spin_lock_init(&(new_kcs->kcs_lock));
+	spin_lock_init(&(new_kcs->msg_lock));
+
+	rv = ipmi_kcs_detect_hardware(kcs_port, new_kcs->addr, new_kcs->kcs_sm);
+	if (rv) {
+		if (kcs_port) 
+			printk(KERN_ERR 
+			       "ipmi_kcs: No KCS @ port 0x%4.4x\n", 
+			       kcs_port);
+		else
+			printk(KERN_ERR 
+			       "ipmi_kcs: No KCS @ addr 0x%lx\n", 
+			       kcs_physaddr);
+		goto out_err;
+	}
+
+	if (irq != 0) {
+		rv = request_irq(irq,
+				 kcs_irq_handler,
+				 SA_INTERRUPT,
+				 DEVICE_NAME,
+				 new_kcs);
+		if (rv) {
+			printk(KERN_WARNING
+			       "ipmi_kcs: %s unable to claim interrupt %d,"
+			       " running polled\n",
+			       DEVICE_NAME, irq);
+			irq = 0;
+		}
+	}
+	new_kcs->irq = irq;
+
+	INIT_LIST_HEAD(&(new_kcs->xmit_msgs));
+	INIT_LIST_HEAD(&(new_kcs->hp_xmit_msgs));
+	new_kcs->curr_msg = NULL;
+	atomic_set(&new_kcs->req_events, 0);
+	new_kcs->run_to_completion = 0;
+
+	start_clear_flags(new_kcs);
+
+	if (irq) {
+		new_kcs->kcs_state = KCS_CLEARING_FLAGS_THEN_SET_IRQ;
+
+		printk(KERN_INFO 
+		       "ipmi_kcs: Acquiring BMC @ port=0x%x irq=%d\n",
+		       kcs_port, irq);
+
+	} else {
+		if (kcs_port)
+			printk(KERN_INFO 
+			       "ipmi_kcs: Acquiring BMC @ port=0x%x\n",
+		       	       kcs_port);
+		else
+			printk(KERN_INFO 
+			       "ipmi_kcs: Acquiring BMC @ addr=0x%lx\n",
+		       	       kcs_physaddr);
+	}
+
+	rv = ipmi_register_smi(&handlers,
+			       new_kcs,
+			       ipmi_version_major,
+			       ipmi_version_minor,
+			       &(new_kcs->intf));
+	if (rv) {
+		free_irq(irq, new_kcs);
+		printk(KERN_ERR 
+		       "ipmi_kcs: Unable to register device: error %d\n",
+		       rv);
+		goto out_err;
+	}
+
+	new_kcs->interrupt_disabled = 0;
+	new_kcs->timer_stopped = 0;
+	new_kcs->stop_operation = 0;
+
+	init_timer(&(new_kcs->kcs_timer));
+	new_kcs->kcs_timer.data = (long) new_kcs;
+	new_kcs->kcs_timer.function = kcs_timeout;
+	new_kcs->last_timeout_jiffies = jiffies;
+	new_kcs->kcs_timer.expires = jiffies + KCS_TIMEOUT_JIFFIES;
+	add_timer(&(new_kcs->kcs_timer));
+
+	*kcs = new_kcs;
+
+	return 0;
+
+ out_err:
+	if (kcs_port) 
+		release_region (kcs_port, 2);
+	if (new_kcs->addr) 
+		iounmap(new_kcs->addr);
+	if (kcs_physaddr) 
+		release_mem_region(kcs_physaddr, 2);
+	if (new_kcs->kcs_sm)
+		kfree(new_kcs->kcs_sm);
+	kfree(new_kcs);
+	return rv;
+}
+
+#ifdef CONFIG_ACPI
+
+/* Retrieve the base physical address from ACPI tables.  Originally
+   from Hewlett-Packard simple bmc.c, a GPL KCS driver. */
+
+#include <linux/acpi.h>
+/* A real hack, but everything's not there yet in 2.4. */
+#define COMPILER_DEPENDENT_UINT64 unsigned long
+#include <../drivers/acpi/include/acpi.h>
+#include <../drivers/acpi/include/actypes.h>
+
+struct SPMITable {
+	s8	Signature[4];
+	u32	Length;
+	u8	Revision;
+	u8	Checksum;
+	s8	OEMID[6];
+	s8	OEMTableID[8];
+	s8	OEMRevision[4];
+	s8	CreatorID[4];
+	s8	CreatorRevision[4];
+	s16	InterfaceType;
+	s16	SpecificationRevision;
+	u8	InterruptType;
+	u8	GPE;
+	s16	Reserved;
+	u64	GlobalSystemInterrupt;
+	u8	BaseAddress[12];
+	u8	UID[4];
+} __attribute__ ((packed));
+
+static unsigned long acpi_find_bmc(void)
+{
+	acpi_status       status;
+	acpi_table_header *spmi;
+	static unsigned long io_base = 0;
+
+	if (io_base != 0)
+		return io_base;
+
+	status = acpi_get_firmware_table("SPMI", 1,
+			ACPI_LOGICAL_ADDRESSING, &spmi);
+
+	if (status != AE_OK) {
+		printk(KERN_ERR "ipmi_kcs: SPMI table not found.\n");
+		return 0;
+	}
+
+	memcpy(&io_base, ((struct SPMITable *)spmi)->BaseAddress,
+			sizeof(io_base));
+	
+	return io_base;
+}
+#endif
+
+static __init int init_ipmi_kcs(void)
+{
+	int		rv = 0;
+	int		pos = 0;
+	int		i = 0;
+	unsigned long	physaddr = 0;
+
+	if (initialized)
+		return 0;
+	initialized = 1;
+
+	/* First do the "command-line" parameters */
+
+	for (i=0; i < KCS_MAX_PARMS; i++) {
+		rv = init_one_kcs(kcs_ports[i], 
+				  kcs_irqs[i], 
+				  0, 
+				  &(kcs_infos[pos]));
+		if (rv == 0)
+			pos++;
+
+		rv = init_one_kcs(0, 
+				  kcs_irqs[i], 
+				  kcs_addrs[i], 
+				  &(kcs_infos[pos]));
+		if (rv == 0)
+			pos++;
+	}
+
+	/* Only try the defaults if enabled and resources are available
+	   (because they weren't already specified above). */
+
+	if (kcs_trydefaults) {
+#ifdef CONFIG_ACPI
+		if ((physaddr = acpi_find_bmc())) {
+			if (!check_mem_region(physaddr, 2)) {
+				rv = init_one_kcs(0, 
+						  0, 
+						  physaddr, 
+						  &(kcs_infos[pos]));
+				if (rv == 0)
+					pos++;
+			}
+		}
+#endif
+		if (!check_region(DEFAULT_IO_PORT, 2)) {
+			rv = init_one_kcs(DEFAULT_IO_PORT, 
+					  0, 
+					  0, 
+					  &(kcs_infos[pos]));
+			if (rv == 0)
+				pos++;
+		}
+	}
+
+	if (kcs_infos[0] == NULL) {
+		printk("ipmi_kcs: Unable to find any KCS interfaces\n");
+		return -ENODEV;
+	} 
+
+	return 0;
+}
+module_init(init_ipmi_kcs);
+
+#ifdef MODULE
+void __exit cleanup_one_kcs(struct kcs_info *to_clean)
+{
+	int           rv;
+	unsigned long flags;
+
+	if (! to_clean)
+		return;
+
+	/* Tell the timer and interrupt handlers that we are shutting
+	   down. */
+	spin_lock_irqsave(&(to_clean->kcs_lock), flags);
+	spin_lock(&(to_clean->msg_lock));
+
+	to_clean->stop_operation = 1;
+
+	if (to_clean->irq != 0)
+		free_irq(to_clean->irq, to_clean);
+	if (to_clean->port) {
+		printk(KERN_INFO 
+		       "ipmi_kcs: Releasing BMC @ port=0x%x\n",
+		       to_clean->port);
+		release_region (to_clean->port, 2);
+	}
+	if (to_clean->addr) {
+		printk(KERN_INFO 
+		       "ipmi_kcs: Releasing BMC @ addr=0x%lx\n",
+		       to_clean->physaddr);
+		iounmap(to_clean->addr);
+		release_mem_region(to_clean->physaddr, 2);
+	}
+
+	spin_unlock(&(to_clean->msg_lock));
+	spin_unlock_irqrestore(&(to_clean->kcs_lock), flags);
+
+	/* Wait for the timer to stop.  This avoids problems with race
+	   conditions removing the timer here.  Hopefully this will be
+	   long enough to avoid problems with interrupts still
+	   running. */
+	schedule_timeout(2);
+	while (!to_clean->timer_stopped) {
+		schedule_timeout(1);
+	}
+
+	rv = ipmi_unregister_smi(to_clean->intf);
+	if (rv) {
+		printk(KERN_ERR 
+		       "ipmi_kcs: Unable to unregister device: errno=%d\n",
+		       rv);
+	}
+
+	initialized = 0;
+
+	kfree(to_clean->kcs_sm);
+	kfree(to_clean);
+}
+
+static __exit void cleanup_ipmi_kcs(void)
+{
+	int i;
+
+	if (!initialized)
+		return;
+
+	for (i=0; i<KCS_MAX_DRIVERS; i++) {
+		cleanup_one_kcs(kcs_infos[i]);
+	}
+}
+module_exit(cleanup_ipmi_kcs);
+#else
+
+/* Unfortunately, cmdline::get_options() only returns integers, not
+   longs.  Since we need ulongs (64-bit physical addresses) parse the 
+   comma-separated list manually.  Arguments can be one of these forms:
+   m0xaabbccddeeff	A physical memory address without an IRQ
+   m0xaabbccddeeff:cc	A physical memory address with an IRQ
+   p0xaabb		An IO port without an IRQ
+   p0xaabb:cc		An IO port with an IRQ
+   nodefaults		Suppress trying the default IO port or ACPI address 
+
+   For example, to pass one IO port with an IRQ, one address, and 
+   suppress the use of the default IO port and ACPI address,
+   use this option string: ipmi_kcs=p0xCA2:5,m0xFF5B0022,nodefaults
+
+   Remember, ipmi_kcs_setup() is passed the string after the equal sign. */
+
+static int __init ipmi_kcs_setup(char *str)
+{
+	unsigned long val;
+	char *cur, *colon;
+	int pos;
+
+	pos = 0;
+	
+	cur = strsep(&str, ",");
+	while ((cur) && (*cur) && (pos < KCS_MAX_PARMS)) {
+		switch (*cur) {
+		case 'n':
+			if (strcmp(cur, "nodefaults") == 0)
+				kcs_trydefaults = 0;
+			else
+				printk(KERN_INFO 
+				       "ipmi_kcs: bad parameter value %s\n",
+				       cur);
+			break;
+		
+		case 'm':
+		case 'p':
+			val = simple_strtoul(cur + 1,
+					     &colon,
+					     0);
+			if (*cur == 'p')
+				kcs_ports[pos] = val;
+			else
+				kcs_addrs[pos] = val;
+			if (*colon == ':') {
+				val = simple_strtoul(colon + 1,
+						     &colon,
+						     0);
+				kcs_irqs[pos] = val;
+			}
+			pos++;
+			break;
+
+		default:
+			printk(KERN_INFO 
+			       "ipmi_kcs: bad parameter value %s\n",
+			       cur);
+		}
+		cur = strsep(&str, ",");
+	}
+
+	return 1;
+}
+__setup("ipmi_kcs=", ipmi_kcs_setup);
+#endif
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.21-pre3/drivers/char/ipmi/ipmi_kcs_sm.c linux-2.4.21-pre4/drivers/char/ipmi/ipmi_kcs_sm.c
--- linux-2.4.21-pre3/drivers/char/ipmi/ipmi_kcs_sm.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/drivers/char/ipmi/ipmi_kcs_sm.c	Tue Jan 28 19:44:29 2003
@@ -0,0 +1,467 @@
+/*
+ * ipmi_kcs_sm.c
+ *
+ * State machine for handling IPMI KCS interfaces.
+ *
+ * Author: MontaVista Software, Inc.
+ *         Corey Minyard <minyard@mvista.com>
+ *         source@mvista.com
+ *
+ * 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.
+ *
+ *
+ *  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 state machine is taken from the state machine in the IPMI spec,
+ * pretty much verbatim.  If you have questions about the states, see
+ * that document.
+ */
+
+#include <asm/io.h>
+#include <asm/string.h>		/* Gets rid of memcpy warning */
+
+#include "ipmi_kcs_sm.h"
+
+/* Set this if you want a printout of why the state machine was hosed
+   when it gets hosed. */
+#define DEBUG_HOSED_REASON
+
+/* Print the state machine state on entry every time. */
+#undef DEBUG_STATE
+
+/* The states the KCS driver may be in. */
+enum kcs_states {
+	KCS_IDLE,		/* The KCS interface is currently
+                                   doing nothing. */
+	KCS_START_OP,		/* We are starting an operation.  The
+				   data is in the output buffer, but
+				   nothing has been done to the
+				   interface yet.  This was added to
+				   the state machine in the spec to
+				   wait for the initial IBF. */
+	KCS_WAIT_WRITE_START,	/* We have written a write cmd to the
+				   interface. */
+	KCS_WAIT_WRITE,		/* We are writing bytes to the
+                                   interface. */
+	KCS_WAIT_WRITE_END,	/* We have written the write end cmd
+                                   to the interface, and still need to
+                                   write the last byte. */
+	KCS_WAIT_READ,		/* We are waiting to read data from
+				   the interface. */
+	KCS_ERROR0,		/* State to transition to the error
+				   handler, this was added to the
+				   state machine in the spec to be
+				   sure IBF was there. */
+	KCS_ERROR1,		/* First stage error handler, wait for
+                                   the interface to respond. */
+	KCS_ERROR2,		/* The abort cmd has been written,
+				   wait for the interface to
+				   respond. */
+	KCS_ERROR3,		/* We wrote some data to the
+				   interface, wait for it to switch to
+				   read mode. */
+	KCS_HOSED		/* The hardware failed to follow the
+				   state machine. */
+};
+
+#define MAX_KCS_READ_SIZE 80
+#define MAX_KCS_WRITE_SIZE 80
+
+/* Timeouts in microseconds. */
+#define IBF_RETRY_TIMEOUT 1000000
+#define OBF_RETRY_TIMEOUT 1000000
+#define MAX_ERROR_RETRIES 10
+
+#define IPMI_ERR_MSG_TRUNCATED	0xc6
+
+struct kcs_data
+{
+	enum kcs_states state;
+	unsigned int    port;
+	unsigned char	*addr;
+	unsigned char   write_data[MAX_KCS_WRITE_SIZE];
+	int             write_pos;
+	int             write_count;
+	int             orig_write_count;
+	unsigned char   read_data[MAX_KCS_READ_SIZE];
+	int             read_pos;
+	int	        truncated;
+
+	unsigned int  error_retries;
+	long          ibf_timeout;
+	long          obf_timeout;
+};
+
+void init_kcs_data(struct kcs_data *kcs, unsigned int port, unsigned char *addr)
+{
+	kcs->state = KCS_IDLE;
+	kcs->port = port;
+	kcs->addr = addr;
+	kcs->write_pos = 0;
+	kcs->write_count = 0;
+	kcs->orig_write_count = 0;
+	kcs->read_pos = 0;
+	kcs->error_retries = 0;
+	kcs->truncated = 0;
+	kcs->ibf_timeout = IBF_RETRY_TIMEOUT;
+	kcs->obf_timeout = OBF_RETRY_TIMEOUT;
+}
+
+/* Remember, init_one_kcs() insured port and addr can't both be set */
+
+static inline unsigned char read_status(struct kcs_data *kcs)
+{
+        if (kcs->port)
+		return inb(kcs->port + 1);
+        else
+		return readb(kcs->addr + 1);
+}
+
+static inline unsigned char read_data(struct kcs_data *kcs)
+{
+        if (kcs->port)
+		return inb(kcs->port + 0);
+        else
+		return readb(kcs->addr + 0);
+}
+
+static inline void write_cmd(struct kcs_data *kcs, unsigned char data)
+{
+        if (kcs->port)
+		outb(data, kcs->port + 1);
+        else
+		writeb(data, kcs->addr + 1);
+}
+
+static inline void write_data(struct kcs_data *kcs, unsigned char data)
+{
+        if (kcs->port)
+		outb(data, kcs->port + 0);
+        else
+		writeb(data, kcs->addr + 0);
+}
+
+/* Control codes. */
+#define KCS_GET_STATUS_ABORT	0x60
+#define KCS_WRITE_START		0x61
+#define KCS_WRITE_END		0x62
+#define KCS_READ_BYTE		0x68
+
+/* Status bits. */
+#define GET_STATUS_STATE(status) (((status) >> 6) & 0x03)
+#define KCS_IDLE_STATE	0
+#define KCS_READ_STATE	1
+#define KCS_WRITE_STATE	2
+#define KCS_ERROR_STATE	3
+#define GET_STATUS_ATN(status) ((status) & 0x04)
+#define GET_STATUS_IBF(status) ((status) & 0x02)
+#define GET_STATUS_OBF(status) ((status) & 0x01)
+
+
+static inline void write_next_byte(struct kcs_data *kcs)
+{
+	write_data(kcs, kcs->write_data[kcs->write_pos]);
+	(kcs->write_pos)++;
+	(kcs->write_count)--;
+}
+
+static inline void start_error_recovery(struct kcs_data *kcs, char *reason)
+{
+	(kcs->error_retries)++;
+	if (kcs->error_retries > MAX_ERROR_RETRIES) {
+#ifdef DEBUG_HOSED_REASON
+		printk("ipmi_kcs_sm: kcs hosed: %s\n", reason);
+#endif
+		kcs->state = KCS_HOSED;
+	} else {
+		kcs->state = KCS_ERROR0;
+	}
+}
+
+static inline void read_next_byte(struct kcs_data *kcs)
+{
+	if (kcs->read_pos >= MAX_KCS_READ_SIZE) {
+		/* Throw the data away and mark it truncated. */
+		read_data(kcs);
+		kcs->truncated = 1;
+	} else {
+		kcs->read_data[kcs->read_pos] = read_data(kcs);
+		(kcs->read_pos)++;
+	}
+	write_data(kcs, KCS_READ_BYTE);
+}
+
+static inline int check_ibf(struct kcs_data *kcs,
+			    unsigned char   status,
+			    long            time)
+{
+	if (GET_STATUS_IBF(status)) {
+		kcs->ibf_timeout -= time;
+		if (kcs->ibf_timeout < 0) {
+			start_error_recovery(kcs, "IBF not ready in time");
+			return 1;
+		}
+		return 0;
+	}
+	kcs->ibf_timeout = IBF_RETRY_TIMEOUT;
+	return 1;
+}
+
+static inline int check_obf(struct kcs_data *kcs,
+			    unsigned char   status,
+			    long            time)
+{
+	if (! GET_STATUS_OBF(status)) {
+		kcs->obf_timeout -= time;
+		if (kcs->obf_timeout < 0) {
+		    start_error_recovery(kcs, "OBF not ready in time");
+		    return 1;
+		}
+		return 0;
+	}
+	kcs->obf_timeout = OBF_RETRY_TIMEOUT;
+	return 1;
+}
+
+static void clear_obf(struct kcs_data *kcs, unsigned char status)
+{
+	if (GET_STATUS_OBF(status))
+		read_data(kcs);
+}
+
+static void restart_kcs_transaction(struct kcs_data *kcs)
+{
+	kcs->write_count = kcs->orig_write_count;
+	kcs->write_pos = 0;
+	kcs->read_pos = 0;
+	kcs->state = KCS_WAIT_WRITE_START;
+	kcs->ibf_timeout = IBF_RETRY_TIMEOUT;
+	kcs->obf_timeout = OBF_RETRY_TIMEOUT;
+	write_cmd(kcs, KCS_WRITE_START);
+}
+
+int start_kcs_transaction(struct kcs_data *kcs, char *data, unsigned int size)
+{
+	if ((size < 2) || (size > MAX_KCS_WRITE_SIZE)) {
+		return -1;
+	}
+
+	if ((kcs->state != KCS_IDLE) && (kcs->state != KCS_HOSED)) {
+		return -2;
+	}
+
+	kcs->error_retries = 0;
+	memcpy(kcs->write_data, data, size);
+	kcs->write_count = size;
+	kcs->orig_write_count = size;
+	kcs->write_pos = 0;
+	kcs->read_pos = 0;
+	kcs->state = KCS_START_OP;
+	kcs->ibf_timeout = IBF_RETRY_TIMEOUT;
+	kcs->obf_timeout = OBF_RETRY_TIMEOUT;
+	return 0;
+}
+
+int kcs_get_result(struct kcs_data *kcs, unsigned char *data, int length)
+{
+	if (length < kcs->read_pos) {
+		kcs->read_pos = length;
+		kcs->truncated = 1;
+	}
+
+	memcpy(data, kcs->read_data, kcs->read_pos);
+
+	if (kcs->truncated) {
+		/* Report a truncated error.  We might overwrite
+		   another error, but that's too bad, the user needs
+		   to know it was truncated. */
+		data[2] = IPMI_ERR_MSG_TRUNCATED;
+		kcs->truncated = 0;
+	}
+
+	return kcs->read_pos;
+}
+
+/* This implements the state machine defined in the IPMI manual, see
+   that for details on how this works.  Divide that flowchart into
+   sections delimited by "Wait for IBF" and this will become clear. */
+enum kcs_result kcs_event(struct kcs_data *kcs, long time)
+{
+	unsigned char status;
+	unsigned char state;
+
+	status = read_status(kcs);
+
+#ifdef DEBUG_STATE
+	printk("  State = %d, %x\n", kcs->state, status);
+#endif
+	/* All states wait for ibf, so just do it here. */
+	if (!check_ibf(kcs, status, time))
+		return KCS_CALL_WITH_DELAY;
+
+	/* Just about everything looks at the KCS state, so grab that, too. */
+	state = GET_STATUS_STATE(status);
+
+	switch (kcs->state) {
+	case KCS_IDLE:
+		if (GET_STATUS_ATN(status))
+			return KCS_ATTN;
+		else
+			return KCS_SM_IDLE;
+
+	case KCS_START_OP:
+		if (state != KCS_IDLE) {
+			start_error_recovery(kcs,
+					     "State machine not idle at start");
+			break;
+		}
+
+		clear_obf(kcs, status);
+		write_cmd(kcs, KCS_WRITE_START);
+		kcs->state = KCS_WAIT_WRITE_START;
+		break;
+
+	case KCS_WAIT_WRITE_START:
+		if (state != KCS_WRITE_STATE) {
+			start_error_recovery(
+				kcs,
+				"Not in write state at write start");
+			break;
+		}
+		read_data(kcs);
+		if (kcs->write_count == 1) {
+			write_cmd(kcs, KCS_WRITE_END);
+			kcs->state = KCS_WAIT_WRITE_END;
+		} else {
+			write_next_byte(kcs);
+			kcs->state = KCS_WAIT_WRITE;
+		}
+		break;
+
+	case KCS_WAIT_WRITE:
+		if (state != KCS_WRITE_STATE) {
+			start_error_recovery(kcs,
+					     "Not in write state for write");
+			break;
+		}
+		clear_obf(kcs, status);
+		if (kcs->write_count == 1) {
+			write_cmd(kcs, KCS_WRITE_END);
+			kcs->state = KCS_WAIT_WRITE_END;
+		} else {
+			write_next_byte(kcs);
+		}
+		break;
+		
+	case KCS_WAIT_WRITE_END:
+		if (state != KCS_WRITE_STATE) {
+			start_error_recovery(kcs,
+					     "Not in write state for write end");
+			break;
+		}
+		clear_obf(kcs, status);
+		write_next_byte(kcs);
+		kcs->state = KCS_WAIT_READ;
+		break;
+
+	case KCS_WAIT_READ:
+		if ((state != KCS_READ_STATE) && (state != KCS_IDLE_STATE)) {
+			start_error_recovery(
+				kcs,
+				"Not in read or idle in read state");
+			break;
+		}
+		if (! check_obf(kcs, status, time))
+			return KCS_CALL_WITH_DELAY;
+
+		if (state == KCS_READ_STATE) {
+			read_next_byte(kcs);
+		} else {
+			read_data(kcs);
+			kcs->orig_write_count = 0;
+			kcs->state = KCS_IDLE;
+			return KCS_TRANSACTION_COMPLETE;
+		}
+		break;
+
+	case KCS_ERROR0:
+		clear_obf(kcs, status);
+		write_cmd(kcs, KCS_GET_STATUS_ABORT);
+		kcs->state = KCS_ERROR1;
+		break;
+
+	case KCS_ERROR1:
+		clear_obf(kcs, status);
+		write_data(kcs, 0);
+		kcs->state = KCS_ERROR2;
+		break;
+		
+	case KCS_ERROR2:
+		if (state != KCS_READ_STATE) {
+			start_error_recovery(kcs,
+					     "Not in read state for error2");
+			break;
+		}
+		if (! check_obf(kcs, status, time))
+			return KCS_CALL_WITH_DELAY;
+
+		clear_obf(kcs, status);
+		write_data(kcs, KCS_READ_BYTE);
+		kcs->state = KCS_ERROR3;
+		break;
+		
+	case KCS_ERROR3:
+		if (state != KCS_IDLE_STATE) {
+			start_error_recovery(kcs,
+					     "Not in idle state for error3");
+			break;
+		}
+
+		if (! check_obf(kcs, status, time))
+			return KCS_CALL_WITH_DELAY;
+
+		clear_obf(kcs, status);
+		if (kcs->orig_write_count) {
+			restart_kcs_transaction(kcs);
+		} else {
+			kcs->state = KCS_IDLE;
+			return KCS_TRANSACTION_COMPLETE;
+		}
+		break;
+			
+	case KCS_HOSED:
+		return KCS_SM_HOSED;
+	}
+
+	if (kcs->state == KCS_HOSED) {
+		init_kcs_data(kcs, kcs->port, kcs->addr);
+		return KCS_SM_HOSED;
+	}
+
+	return KCS_CALL_WITHOUT_DELAY;
+}
+
+int kcs_size(void)
+{
+	return sizeof(struct kcs_data);
+}
diff -urN linux-2.4.21-pre3/drivers/char/ipmi/ipmi_kcs_sm.h linux-2.4.21-pre4/drivers/char/ipmi/ipmi_kcs_sm.h
--- linux-2.4.21-pre3/drivers/char/ipmi/ipmi_kcs_sm.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/drivers/char/ipmi/ipmi_kcs_sm.h	Tue Jan 28 19:44:29 2003
@@ -0,0 +1,70 @@
+/*
+ * ipmi_kcs_sm.h
+ *
+ * State machine for handling IPMI KCS interfaces.
+ *
+ * Author: MontaVista Software, Inc.
+ *         Corey Minyard <minyard@mvista.com>
+ *         source@mvista.com
+ *
+ * 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.
+ *
+ *
+ *  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.
+ */
+
+struct kcs_data;
+
+void init_kcs_data(struct kcs_data *kcs,
+		   unsigned int    port,
+		   unsigned char   *addr);
+
+/* Start a new transaction in the state machine.  This will return -2
+   if the state machine is not idle, -1 if the size is invalid (to
+   large or too small), or 0 if the transaction is successfully
+   completed. */
+int start_kcs_transaction(struct kcs_data *kcs, char *data, unsigned int size);
+
+/* Return the results after the transaction.  This will return -1 if
+   the buffer is too small, zero if no transaction is present, or the
+   actual length of the result data. */
+int kcs_get_result(struct kcs_data *kcs, unsigned char *data, int length);
+
+enum kcs_result
+{
+	KCS_CALL_WITHOUT_DELAY, /* Call the driver again immediately */
+	KCS_CALL_WITH_DELAY,	/* Delay some before calling again. */
+	KCS_TRANSACTION_COMPLETE, /* A transaction is finished. */
+	KCS_SM_IDLE,		/* The SM is in idle state. */
+	KCS_SM_HOSED,		/* The hardware violated the state machine. */
+	KCS_ATTN		/* The hardware is asserting attn and the
+				   state machine is idle. */
+};
+
+/* Call this periodically (for a polled interface) or upon receiving
+   an interrupt (for a interrupt-driven interface).  If interrupt
+   driven, you should probably poll this periodically when not in idle
+   state.  This should be called with the time that passed since the
+   last call, if it is significant.  Time is in microseconds. */
+enum kcs_result kcs_event(struct kcs_data *kcs, long time);
+
+/* Return the size of the KCS structure in bytes. */
+int kcs_size(void);
diff -urN linux-2.4.21-pre3/drivers/char/ipmi/ipmi_msghandler.c linux-2.4.21-pre4/drivers/char/ipmi/ipmi_msghandler.c
--- linux-2.4.21-pre3/drivers/char/ipmi/ipmi_msghandler.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/drivers/char/ipmi/ipmi_msghandler.c	Tue Jan 28 19:44:29 2003
@@ -0,0 +1,1811 @@
+/*
+ * ipmi_msghandler.c
+ *
+ * Incoming and outgoing message routing for an IPMI interface.
+ *
+ * Author: MontaVista Software, Inc.
+ *         Corey Minyard <minyard@mvista.com>
+ *         source@mvista.com
+ *
+ * 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.
+ *
+ *
+ *  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/module.h>
+#include <linux/errno.h>
+#include <asm/system.h>
+#include <linux/sched.h>
+#include <linux/poll.h>
+#include <linux/spinlock.h>
+#include <linux/rwsem.h>
+#include <linux/slab.h>
+#include <linux/ipmi.h>
+#include <linux/ipmi_smi.h>
+#include <linux/notifier.h>
+#include <linux/init.h>
+
+struct ipmi_recv_msg *ipmi_alloc_recv_msg(void);
+static int ipmi_init_msghandler(void);
+
+static int initialized = 0;
+
+#define MAX_EVENTS_IN_QUEUE	25
+
+struct ipmi_user
+{
+	struct list_head link;
+
+	/* The upper layer that handles receive messages. */
+	struct ipmi_user_hndl *handler;
+	void             *handler_data;
+
+	/* The interface this user is bound to. */
+	ipmi_smi_t intf;
+
+	/* Does this interface receive IPMI events? */
+	int gets_events;
+};
+
+struct cmd_rcvr
+{
+	struct list_head link;
+
+	ipmi_user_t   user;
+	unsigned char netfn;
+	unsigned char cmd;
+};
+
+#define IPMI_IPMB_NUM_SEQ	64
+struct ipmi_smi
+{
+	/* The list of upper layers that are using me.  We read-lock
+           this when delivering messages to the upper layer to keep
+           the user from going away while we are processing the
+           message.  This means that you cannot add or delete a user
+           from the receive callback. */
+	rwlock_t                users_lock;
+	struct list_head        users;
+
+	/* The IPMI version of the BMC on the other end. */
+	unsigned char       version_major;
+	unsigned char       version_minor;
+
+	/* This is the lower-layer's sender routine. */
+	struct ipmi_smi_handlers *handlers;
+	void                     *send_info;
+
+	/* A table of sequence numbers for this interface.  We use the
+           sequence numbers for IPMB messages that go out of the
+           interface to match them up with their responses.  A routine
+           is called periodically to time the items in this list. */
+	spinlock_t              seq_lock;
+	struct {
+		unsigned long   timeout;
+		int             inuse;
+		struct ipmi_recv_msg *recv_msg;
+	} seq_table[IPMI_IPMB_NUM_SEQ];
+	int curr_seq;
+
+	/* Messages that were delayed for some reason (out of memory,
+           for instance), will go in here to be processed later in a
+           periodic timer interrupt. */
+	spinlock_t       waiting_msgs_lock;
+	struct list_head waiting_msgs;
+
+	/* The list of command receivers that are registered for commands
+	   on this interface. */
+	rwlock_t	 cmd_rcvr_lock;
+	struct list_head cmd_rcvrs;
+
+	/* Events that were queues because no one was there to receive
+           them. */
+	spinlock_t       events_lock; /* For dealing with event stuff. */
+	struct list_head waiting_events;
+	unsigned int     waiting_events_count; /* How many events in queue? */
+
+	/* This will be non-null if someone registers to receive all
+	   IPMI commands (this is for interface emulation).  There
+	   may not be any things in the cmd_rcvrs list above when
+	   this is registered. */
+	ipmi_user_t all_cmd_rcvr;
+
+	/* My slave address.  This is initialized to IPMI_BMC_SLAVE_ADDR,
+	   but may be changed by the user. */
+	unsigned char my_address;
+
+	/* My LUN.  This should generally stay the SMS LUN, but just in
+	   case... */
+	unsigned char my_lun;
+};
+
+int
+ipmi_register_all_cmd_rcvr(ipmi_user_t user)
+{
+	int flags;
+	int rv = -EBUSY;
+
+	write_lock_irqsave(&(user->intf->users_lock), flags);
+	write_lock(&(user->intf->cmd_rcvr_lock));
+	if ((user->intf->all_cmd_rcvr == NULL)
+	    && (list_empty(&(user->intf->cmd_rcvrs))))
+	{
+		user->intf->all_cmd_rcvr = user;
+		rv = 0;
+	}
+	write_unlock(&(user->intf->cmd_rcvr_lock));
+	write_unlock_irqrestore(&(user->intf->users_lock), flags);
+	return rv;
+}
+
+int
+ipmi_unregister_all_cmd_rcvr(ipmi_user_t user)
+{
+	int flags;
+	int rv = -EINVAL;
+
+	write_lock_irqsave(&(user->intf->users_lock), flags);
+	write_lock(&(user->intf->cmd_rcvr_lock));
+	if (user->intf->all_cmd_rcvr == user)
+	{
+		user->intf->all_cmd_rcvr = NULL;
+		rv = 0;
+	}
+	write_unlock(&(user->intf->cmd_rcvr_lock));
+	write_unlock_irqrestore(&(user->intf->users_lock), flags);
+	return rv;
+}
+
+
+#define MAX_IPMI_INTERFACES 4
+static ipmi_smi_t ipmi_interfaces[MAX_IPMI_INTERFACES];
+
+/* Used to keep interfaces from going away while operations are
+   operating on interfaces.  Grab read if you are not modifying the
+   interfaces, write if you are. */
+static DECLARE_RWSEM(interfaces_sem);
+
+/* Directly protects the ipmi_interfaces data structure.  This is
+   claimed in the timer interrupt. */
+static spinlock_t interfaces_lock = SPIN_LOCK_UNLOCKED;
+
+/* List of watchers that want to know when smi's are added and
+   deleted. */
+static struct list_head smi_watchers = LIST_HEAD_INIT(smi_watchers);
+static DECLARE_RWSEM(smi_watchers_sem);
+
+int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher)
+{
+	int i;
+
+	down_read(&interfaces_sem);
+	down_write(&smi_watchers_sem);
+	list_add(&(watcher->link), &smi_watchers);
+	for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+		if (ipmi_interfaces[i] != NULL) {
+			watcher->new_smi(i);
+		}
+	}
+	up_write(&smi_watchers_sem);
+	up_read(&interfaces_sem);
+	return 0;
+}
+
+int ipmi_smi_watcher_unregister(struct ipmi_smi_watcher *watcher)
+{
+	down_write(&smi_watchers_sem);
+	list_del(&(watcher->link));
+	up_write(&smi_watchers_sem);
+	return 0;
+}
+
+int
+ipmi_addr_equal(struct ipmi_addr *addr1, struct ipmi_addr *addr2)
+{
+	if (addr1->addr_type != addr2->addr_type)
+		return 0;
+
+	if (addr1->channel != addr2->channel)
+		return 0;
+
+	if (addr1->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
+		struct ipmi_system_interface_addr *smi_addr1
+		    = (struct ipmi_system_interface_addr *) addr1;
+		struct ipmi_system_interface_addr *smi_addr2
+		    = (struct ipmi_system_interface_addr *) addr2;
+		return (smi_addr1->lun == smi_addr2->lun);
+	}
+
+	if ((addr1->addr_type == IPMI_IPMB_ADDR_TYPE)
+	    || (addr1->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
+	{
+		struct ipmi_ipmb_addr *ipmb_addr1
+		    = (struct ipmi_ipmb_addr *) addr1;
+		struct ipmi_ipmb_addr *ipmb_addr2
+		    = (struct ipmi_ipmb_addr *) addr2;
+
+		return ((ipmb_addr1->slave_addr == ipmb_addr2->slave_addr)
+			&& (ipmb_addr1->lun == ipmb_addr2->lun));
+	}
+
+	return 1;
+}
+
+int ipmi_validate_addr(struct ipmi_addr *addr, int len)
+{
+	if (len < sizeof(struct ipmi_system_interface_addr)) {
+		return -EINVAL;
+	}
+
+	if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
+		if (addr->channel != IPMI_BMC_CHANNEL)
+			return -EINVAL;
+		return 0;
+	}
+
+	if ((addr->channel == IPMI_BMC_CHANNEL)
+	    || (addr->channel >= IPMI_NUM_CHANNELS)
+	    || (addr->channel < 0))
+		return -EINVAL;
+
+	if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE)
+	    || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
+	{
+		if (len < sizeof(struct ipmi_ipmb_addr)) {
+			return -EINVAL;
+		}
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+unsigned int ipmi_addr_length(int addr_type)
+{
+	if (addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
+		return sizeof(struct ipmi_system_interface_addr);
+
+	if ((addr_type == IPMI_IPMB_ADDR_TYPE)
+	    || (addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
+	{
+		return sizeof(struct ipmi_ipmb_addr);
+	}
+
+	return 0;
+}
+
+static void deliver_response(struct ipmi_recv_msg *msg)
+{
+    msg->user->handler->ipmi_recv_hndl(msg, msg->user->handler_data);
+}
+
+/* Find the next sequence number not being used and add the given
+   message with the given timeout to the sequence table. */
+static int intf_next_seq(ipmi_smi_t           intf,
+			 struct ipmi_recv_msg *recv_msg,
+			 unsigned long        timeout,
+			 unsigned char        *seq)
+{
+	int           rv = 0;
+	unsigned long flags;
+	unsigned int  i;
+
+	spin_lock_irqsave(&(intf->seq_lock), flags);
+	for (i=intf->curr_seq;
+	     i!=(intf->curr_seq-1);
+	     i=(i+1)%IPMI_IPMB_NUM_SEQ)
+	{
+		if (! intf->seq_table[i].inuse)
+			break;
+	}
+
+	if (! intf->seq_table[i].inuse) {
+		intf->seq_table[i].recv_msg = recv_msg;
+		intf->seq_table[i].timeout = timeout;
+		intf->seq_table[i].inuse = 1;
+		*seq = i;
+		intf->curr_seq = (i+1)%IPMI_IPMB_NUM_SEQ;
+	} else {
+		rv = -EAGAIN;
+	}
+	
+	spin_unlock_irqrestore(&(intf->seq_lock), flags);
+
+	return rv;
+}
+
+/* Return the receive message for the given sequence number and
+   release the sequence number so it can be reused.  Some other data
+   is passed in to be sure the message matches up correctly (to help
+   guard against message coming in after their timeout and the
+   sequence number being reused). */
+static int intf_find_seq(ipmi_smi_t           intf,
+			 unsigned char        seq,
+			 short                channel,
+			 unsigned char        cmd,
+			 unsigned char        netfn,
+			 struct ipmi_addr     *addr,
+			 struct ipmi_recv_msg **recv_msg)
+{
+	int           rv = -ENODEV;
+	unsigned long flags;
+
+	if (seq >= IPMI_IPMB_NUM_SEQ)
+		return -EINVAL;
+
+	spin_lock_irqsave(&(intf->seq_lock), flags);
+	if (intf->seq_table[seq].inuse) {
+		struct ipmi_recv_msg *msg = intf->seq_table[seq].recv_msg;
+
+		if ((msg->addr.channel == channel)
+		    && (msg->msg.cmd == cmd)
+		    && (msg->msg.netfn == netfn)
+		    && (ipmi_addr_equal(addr, &(msg->addr))))
+		{
+			*recv_msg = msg;
+			intf->seq_table[seq].inuse = 0;
+			rv = 0;
+		}
+	}
+	spin_unlock_irqrestore(&(intf->seq_lock), flags);
+
+	return rv;
+}
+
+
+int ipmi_create_user(unsigned int          if_num,
+		     struct ipmi_user_hndl *handler,
+		     void                  *handler_data,
+		     ipmi_user_t           *user)
+{
+	unsigned long flags;
+	ipmi_user_t   new_user;
+	int           rv = 0;
+
+	/* There is no module usecount here, because it's not
+           required.  Since this can only be used by and called from
+           other modules, they will implicitly use this module, and
+           thus this can't be removed unless the other modules are
+           removed. */
+
+	if (handler == NULL)
+		return -EINVAL;
+
+	/* Make sure the driver is actually initialized, this handles
+	   problems with initialization order. */
+	if (!initialized) {
+		rv = ipmi_init_msghandler();
+		if (rv)
+			return rv;
+
+		/* The init code doesn't return an error if it was turned
+		   off, but it won't initialize.  Check that. */
+		if (!initialized)
+			return -ENODEV;
+	}
+
+	new_user = kmalloc(sizeof(*new_user), GFP_KERNEL);
+	if (! new_user)
+		return -ENOMEM;
+
+	down_read(&interfaces_sem);
+	if ((if_num > MAX_IPMI_INTERFACES) || ipmi_interfaces[if_num] == NULL)
+	{
+		rv = -EINVAL;
+		goto out_unlock;
+	}
+
+	new_user->handler = handler;
+	new_user->handler_data = handler_data;
+	new_user->intf = ipmi_interfaces[if_num];
+	new_user->gets_events = 0;
+
+	rv = new_user->intf->handlers->new_user(new_user->intf->send_info);
+	if (rv)
+		goto out_unlock;
+
+	write_lock_irqsave(&(new_user->intf->users_lock), flags);
+	list_add_tail(&(new_user->link), &(new_user->intf->users));
+	write_unlock_irqrestore(&(new_user->intf->users_lock), flags);
+
+ out_unlock:	
+	if (rv) {
+		kfree(new_user);
+	} else {
+		*user = new_user;
+	}
+
+	up_read(&interfaces_sem);
+	return rv;
+}
+
+static int ipmi_destroy_user_nolock(ipmi_user_t user)
+{
+	int              rv = -ENODEV;
+	ipmi_user_t      t_user;
+	struct list_head *entry, *entry2;
+	int              i;
+	unsigned long    flags;
+
+	/* Find the user and delete them from the list. */
+	list_for_each(entry, &(user->intf->users)) {
+		t_user = list_entry(entry, struct ipmi_user, link);
+		if (t_user == user) {
+			list_del(entry);
+			rv = 0;
+			break;
+		}
+	}
+
+	if (rv) {
+		goto out_unlock;
+	}
+
+	/* Remove the user from the interfaces sequence table. */
+	spin_lock_irqsave(&(user->intf->seq_lock), flags);
+	for (i=0; i<IPMI_IPMB_NUM_SEQ; i++) {
+		if (user->intf->seq_table[i].inuse
+		    && (user->intf->seq_table[i].recv_msg->user == user))
+		{
+			user->intf->seq_table[i].inuse = 0;
+		}
+	}
+	spin_unlock_irqrestore(&(user->intf->seq_lock), flags);
+
+	/* Remove the user from the command receiver's table. */
+	write_lock_irqsave(&(user->intf->cmd_rcvr_lock), flags);
+	list_for_each_safe(entry, entry2, &(user->intf->cmd_rcvrs)) {
+		struct cmd_rcvr *rcvr;
+		rcvr = list_entry(entry, struct cmd_rcvr, link);
+		if (rcvr->user == user) {
+			list_del(entry);
+			kfree(rcvr);
+		}
+	}
+	write_unlock_irqrestore(&(user->intf->cmd_rcvr_lock), flags);
+
+	kfree(user);
+
+ out_unlock:
+
+	return rv;
+}
+
+int ipmi_destroy_user(ipmi_user_t user)
+{
+	int           rv;
+	ipmi_smi_t    intf = user->intf;
+	unsigned long flags;
+
+	down_read(&interfaces_sem);
+	write_lock_irqsave(&(intf->users_lock), flags);
+	rv = ipmi_destroy_user_nolock(user);
+	if (!rv)
+		intf->handlers->user_left(intf->send_info);
+		
+	write_unlock_irqrestore(&(intf->users_lock), flags);
+	up_read(&interfaces_sem);
+	return rv;
+}
+
+void ipmi_get_version(ipmi_user_t   user,
+		      unsigned char *major,
+		      unsigned char *minor)
+{
+	*major = user->intf->version_major;
+	*minor = user->intf->version_minor;
+}
+
+void ipmi_set_my_address(ipmi_user_t   user,
+			 unsigned char address)
+{
+	user->intf->my_address = address;
+}
+
+unsigned char ipmi_get_my_address(ipmi_user_t user)
+{
+	return user->intf->my_address;
+}
+
+void ipmi_set_my_LUN(ipmi_user_t   user,
+		     unsigned char LUN)
+{
+	user->intf->my_lun = LUN & 0x3;
+}
+
+unsigned char ipmi_get_my_LUN(ipmi_user_t user)
+{
+	return user->intf->my_lun;
+}
+
+int ipmi_set_gets_events(ipmi_user_t user, int val)
+{
+	unsigned long         flags;
+	struct list_head      *e, *e2;
+	struct ipmi_recv_msg  *msg;
+
+	read_lock(&(user->intf->users_lock));
+	spin_lock_irqsave(&(user->intf->events_lock), flags);
+	user->gets_events = val;
+
+	if (val) {
+		/* Deliver any queued events. */
+		list_for_each_safe(e, e2, &(user->intf->waiting_events)) {
+			msg = list_entry(e, struct ipmi_recv_msg, link);
+			list_del(e);
+			msg->user = user;
+			deliver_response(msg);
+		}
+	}
+	
+	spin_unlock_irqrestore(&(user->intf->events_lock), flags);
+	read_unlock(&(user->intf->users_lock));
+
+	return 0;
+}
+
+int ipmi_register_for_cmd(ipmi_user_t   user,
+			  unsigned char netfn,
+			  unsigned char cmd)
+{
+	struct list_head *entry;
+	unsigned long    flags;
+	struct cmd_rcvr  *rcvr;
+	int              rv = 0;
+
+
+	rcvr = kmalloc(sizeof(*rcvr), GFP_KERNEL);
+	if (! rcvr)
+		return -ENOMEM;
+
+	read_lock(&(user->intf->users_lock));
+	write_lock_irqsave(&(user->intf->cmd_rcvr_lock), flags);
+	if (user->intf->all_cmd_rcvr != NULL) {
+		rv = -EBUSY;
+		goto out_unlock;
+	}
+
+	/* Make sure the command/netfn is not already registered. */
+	list_for_each(entry, &(user->intf->cmd_rcvrs)) {
+		struct cmd_rcvr *cmp;
+		cmp = list_entry(entry, struct cmd_rcvr, link);
+		if ((cmp->netfn == netfn) && (cmp->cmd == cmd)) {
+			rv = -EBUSY;
+			break;
+		}
+	}
+
+	if (! rv) {
+		rcvr->cmd = cmd;
+		rcvr->netfn = netfn;
+		rcvr->user = user;
+		list_add_tail(&(rcvr->link), &(user->intf->cmd_rcvrs));
+	}
+ out_unlock:
+	write_unlock_irqrestore(&(user->intf->cmd_rcvr_lock), flags);
+	read_unlock(&(user->intf->users_lock));
+
+	if (rv)
+		kfree(rcvr);
+
+	return rv;
+}
+
+int ipmi_unregister_for_cmd(ipmi_user_t   user,
+			    unsigned char netfn,
+			    unsigned char cmd)
+{
+	struct list_head *entry;
+	unsigned long    flags;
+	struct cmd_rcvr  *rcvr;
+	int              rv = -ENOENT;
+
+	read_lock(&(user->intf->users_lock));
+	write_lock_irqsave(&(user->intf->cmd_rcvr_lock), flags);
+	/* Make sure the command/netfn is not already registered. */
+	list_for_each(entry, &(user->intf->cmd_rcvrs)) {
+		rcvr = list_entry(entry, struct cmd_rcvr, link);
+		if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) {
+			rv = 0;
+			list_del(entry);
+			kfree(rcvr);
+			break;
+		}
+	}
+	write_unlock_irqrestore(&(user->intf->cmd_rcvr_lock), flags);
+	read_unlock(&(user->intf->users_lock));
+
+	return rv;
+}
+
+static unsigned char
+ipmb_checksum(unsigned char *data, int size)
+{
+	unsigned char csum = 0;
+	
+	for (; size > 0; size--, data++)
+		csum += *data;
+
+	return -csum;
+}
+
+/* Separate from ipmi_request so that the user does not have to be
+   supplied in certain circumstances (mainly at panic time).  If
+   messages are supplied, they will be freed, even if an error
+   occurs. */
+static inline int i_ipmi_request(ipmi_user_t          user,
+				 ipmi_smi_t           intf,
+				 struct ipmi_addr     *addr,
+				 long                 msgid,
+				 struct ipmi_msg      *msg,
+				 void                 *supplied_smi,
+				 struct ipmi_recv_msg *supplied_recv,
+				 int                  priority,
+				 unsigned char        source_address,
+				 unsigned char        source_lun)
+{
+	int                  rv = 0;
+	struct ipmi_smi_msg  *smi_msg;
+	struct ipmi_recv_msg *recv_msg;
+
+
+	if (supplied_recv) {
+		recv_msg = supplied_recv;
+	} else {
+		recv_msg = ipmi_alloc_recv_msg();
+		if (recv_msg == NULL) {
+			return -ENOMEM;
+		}
+	}
+
+	if (supplied_smi) {
+		smi_msg = (struct ipmi_smi_msg *) supplied_smi;
+	} else {
+		smi_msg = ipmi_alloc_smi_msg();
+		if (smi_msg == NULL) {
+			ipmi_free_recv_msg(recv_msg);
+			return -ENOMEM;
+		}
+	}
+
+	if (addr->channel > IPMI_NUM_CHANNELS) {
+	    rv = -EINVAL;
+	    goto out_err;
+	}
+
+	if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
+		struct ipmi_system_interface_addr *smi_addr;
+
+		smi_addr = (struct ipmi_system_interface_addr *) addr;
+		if (smi_addr->lun > 3)
+			return -EINVAL;
+
+		if ((msg->netfn == IPMI_NETFN_APP_REQUEST)
+		    && ((msg->cmd == IPMI_SEND_MSG_CMD)
+			|| (msg->cmd == IPMI_GET_MSG_CMD)
+			|| (msg->cmd == IPMI_READ_EVENT_MSG_BUFFER_CMD)))
+		{
+			/* We don't let the user do these, since we manage
+			   the sequence numbers. */
+			rv = -EINVAL;
+			goto out_err;
+		}
+
+		if ((msg->data_len + 2) > IPMI_MAX_MSG_LENGTH) {
+			rv = -EMSGSIZE;
+			goto out_err;
+		}
+
+		recv_msg->user = user;
+		recv_msg->addr = *addr;
+		recv_msg->msgid = msgid;
+		recv_msg->msg = *msg;
+
+		smi_msg->data[0] = (msg->netfn << 2) | (smi_addr->lun & 0x3);
+		smi_msg->data[1] = msg->cmd;
+		smi_msg->msgid = msgid;
+		smi_msg->user_data = recv_msg;
+		if (msg->data_len > 0)
+			memcpy(&(smi_msg->data[2]), msg->data, msg->data_len);
+		smi_msg->data_size = msg->data_len + 2;
+	} else if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE)
+		   || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
+	{
+		struct ipmi_ipmb_addr *ipmb_addr;
+		unsigned char         ipmb_seq;
+		int                   i;
+
+		if (addr == NULL) {
+			rv = -EINVAL;
+			goto out_err;
+		}
+
+		if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE) {
+		    /* Broadcasts add a zero at the beginning of the
+		       message, but otherwise is the same as an IPMB
+		       address. */
+		    smi_msg->data[3] = 0;
+		    addr->addr_type = IPMI_IPMB_ADDR_TYPE;
+		    i = 1;
+		} else {
+		    i = 0;
+		}
+
+		/* 9 for the header and 1 for the checksum, plus
+                   possibly one for the broadcast. */
+		if ((msg->data_len + 10 + i) > IPMI_MAX_MSG_LENGTH) {
+			rv = -EMSGSIZE;
+			goto out_err;
+		}
+
+		ipmb_addr = (struct ipmi_ipmb_addr *) addr;
+		if (ipmb_addr->lun > 3)
+			return -EINVAL;
+
+		memcpy(&(recv_msg->addr), ipmb_addr, sizeof(*ipmb_addr));
+
+		recv_msg->user = user;
+		recv_msg->msgid = msgid;
+		recv_msg->msg = *msg;
+
+		if (recv_msg->msg.netfn & 0x1) {
+			/* It's a response, so use the user's sequence. */
+			ipmb_seq = msgid;
+		} else {
+			/* It's a command, so get a sequence for it. */
+			/* Create a sequence number with a 5 second timeout. */
+			/* FIXME - magic number for the timeout. */
+			rv = intf_next_seq(intf,
+					   recv_msg,
+					   5000,
+					   &ipmb_seq);
+			if (rv) {
+				/* We have used up all the sequence numbers,
+				   probably, so abort. */
+				ipmi_free_recv_msg(recv_msg);
+				smi_msg->done(smi_msg);
+				goto out_err;
+			}
+		}
+
+		/* Format the IPMB header data. */
+		smi_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
+		smi_msg->data[1] = IPMI_SEND_MSG_CMD;
+		smi_msg->data[2] = addr->channel;
+		smi_msg->data[i+3] = ipmb_addr->slave_addr;
+		smi_msg->data[i+4] = (msg->netfn << 2) | (ipmb_addr->lun & 0x3);
+		smi_msg->data[i+5] = ipmb_checksum(&(smi_msg->data[i+3]), 2);
+		smi_msg->data[i+6] = source_address;
+		smi_msg->data[i+7] = (ipmb_seq << 2) | source_lun;
+		smi_msg->data[i+8] = msg->cmd;
+
+		/* Now tack on the data to the message. */
+		if (msg->data_len > 0)
+			memcpy(&(smi_msg->data[i+9]), msg->data, msg->data_len);
+		smi_msg->data_size = msg->data_len + 9;
+
+		/* Now calculate the checksum and tack it on. */
+		smi_msg->data[i+smi_msg->data_size]
+		    = ipmb_checksum(&(smi_msg->data[i+6]), smi_msg->data_size-6);
+
+		/* Add on the checksum size and the offset from the
+                   broadcast. */
+		smi_msg->data_size += 1 + i;
+		
+		smi_msg->msgid = msgid;
+	} else {
+	    /* Unknown address type. */
+	    rv = -EINVAL;
+	    goto out_err;
+	}
+
+#if DEBUG_MSGING
+	{
+	    int m;
+	    for (m=0; m<smi_msg->data_size; m++)
+		printk(" %2.2x", smi_msg->data[m]);
+	    printk("\n");
+	}
+#endif
+	intf->handlers->sender(intf->send_info, smi_msg, priority);
+
+	return 0;
+
+ out_err:
+	smi_msg->done(smi_msg);
+	recv_msg->done(recv_msg);
+	return rv;
+}
+
+int ipmi_request(ipmi_user_t      user,
+		 struct ipmi_addr *addr,
+		 long             msgid,
+		 struct ipmi_msg  *msg,
+		 int              priority)
+{
+	return i_ipmi_request(user,
+			      user->intf,
+			      addr,
+			      msgid,
+			      msg,
+			      NULL, NULL,
+			      priority,
+			      user->intf->my_address,
+			      user->intf->my_lun);
+}
+
+int ipmi_request_supply_msgs(ipmi_user_t          user,
+			     struct ipmi_addr     *addr,
+			     long                 msgid,
+			     struct ipmi_msg      *msg,
+			     void                 *supplied_smi,
+			     struct ipmi_recv_msg *supplied_recv,
+			     int                  priority)
+{
+	return i_ipmi_request(user,
+			      user->intf,
+			      addr,
+			      msgid,
+			      msg,
+			      supplied_smi,
+			      supplied_recv,
+			      priority,
+			      user->intf->my_address,
+			      user->intf->my_lun);
+}
+
+int ipmi_request_with_source(ipmi_user_t      user,
+			     struct ipmi_addr *addr,
+			     long             msgid,
+			     struct ipmi_msg  *msg,
+			     int              priority,
+			     unsigned char    source_address,
+			     unsigned char    source_lun)
+{
+	return i_ipmi_request(user,
+			      user->intf,
+			      addr,
+			      msgid,
+			      msg,
+			      NULL, NULL,
+			      priority,
+			      source_address,
+			      source_lun);
+}
+
+int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
+		      void		       *send_info,
+		      unsigned char            version_major,
+		      unsigned char            version_minor,
+		      ipmi_smi_t               *intf)
+{
+	int              i, j;
+	int              rv;
+	ipmi_smi_t       new_intf;
+	struct list_head *entry;
+	unsigned int     flags;
+
+
+	/* Make sure the driver is actually initialized, this handles
+	   problems with initialization order. */
+	if (!initialized) {
+		rv = ipmi_init_msghandler();
+		if (rv)
+			return rv;
+		/* The init code doesn't return an error if it was turned
+		   off, but it won't initialize.  Check that. */
+		if (!initialized)
+			return -ENODEV;
+	}
+
+	new_intf = kmalloc(sizeof(*new_intf), GFP_KERNEL);
+	if (!new_intf)
+		return -ENOMEM;
+
+	rv = -ENOMEM;
+
+	down_write(&interfaces_sem);
+	for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+		if (ipmi_interfaces[i] == NULL) {
+			new_intf->version_major = version_major;
+			new_intf->version_minor = version_minor;
+			new_intf->my_address = IPMI_BMC_SLAVE_ADDR;
+			new_intf->my_lun = 2;  /* the SMS LUN. */
+			rwlock_init(&(new_intf->users_lock));
+			INIT_LIST_HEAD(&(new_intf->users));
+			new_intf->handlers = handlers;
+			new_intf->send_info = send_info;
+			spin_lock_init(&(new_intf->seq_lock));
+			for (j=0; j<IPMI_IPMB_NUM_SEQ; j++)
+			    new_intf->seq_table[j].inuse = 0;
+			new_intf->curr_seq = 0;
+			spin_lock_init(&(new_intf->waiting_msgs_lock));
+			INIT_LIST_HEAD(&(new_intf->waiting_msgs));
+			spin_lock_init(&(new_intf->events_lock));
+			INIT_LIST_HEAD(&(new_intf->waiting_events));
+			new_intf->waiting_events_count = 0;
+			rwlock_init(&(new_intf->cmd_rcvr_lock));
+			INIT_LIST_HEAD(&(new_intf->cmd_rcvrs));
+			new_intf->all_cmd_rcvr = NULL;
+
+			spin_lock_irqsave(&interfaces_lock, flags);
+			ipmi_interfaces[i] = new_intf;
+			spin_unlock_irqrestore(&interfaces_lock, flags);
+
+			rv = 0;
+			*intf = new_intf;
+			break;
+		}
+	}
+
+	/* We convert to a read semaphore here.  It's possible the
+	   interface was removed between the calls, we have to recheck
+	   afterwards. */
+	up_write(&interfaces_sem);
+	down_read(&interfaces_sem);
+
+	if (ipmi_interfaces[i] != new_intf)
+		/* Well, it went away.  Just return. */
+		goto out;
+
+	if (rv == 0) {
+		/* Call all the watcher interfaces to tell them that a
+		   new interface is available. */
+		down_read(&smi_watchers_sem);
+		list_for_each(entry, &smi_watchers) {
+			struct ipmi_smi_watcher *w;
+			w = list_entry(entry, struct ipmi_smi_watcher, link);
+			w->new_smi(i);
+		}
+		up_read(&smi_watchers_sem);
+	}
+
+ out:
+	up_read(&interfaces_sem);
+
+	if (rv)
+		kfree(new_intf);
+
+	return rv;
+}
+
+static void free_recv_msg_list(struct list_head *q)
+{
+	struct list_head     *entry, *entry2;
+	struct ipmi_recv_msg *msg;
+
+	list_for_each_safe(entry, entry2, q) {
+		msg = list_entry(entry, struct ipmi_recv_msg, link);
+		list_del(entry);
+		ipmi_free_recv_msg(msg);
+	}
+}
+
+static void free_cmd_rcvr_list(struct list_head *q)
+{
+	struct list_head *entry, *entry2;
+	struct cmd_rcvr  *rcvr;
+
+	list_for_each_safe(entry, entry2, q) {
+		rcvr = list_entry(entry, struct cmd_rcvr, link);
+		list_del(entry);
+		kfree(rcvr);
+	}
+}
+
+static void clean_up_interface_data(ipmi_smi_t intf)
+{
+	int i;
+
+	free_recv_msg_list(&(intf->waiting_msgs));
+	free_recv_msg_list(&(intf->waiting_events));
+	free_cmd_rcvr_list(&(intf->cmd_rcvrs));
+
+	for (i=0; i<IPMI_IPMB_NUM_SEQ; i++) {
+		if ((intf->seq_table[i].inuse)
+		    && (intf->seq_table[i].recv_msg))
+		{
+			ipmi_free_recv_msg(intf->seq_table[i].recv_msg);
+		}	
+	}
+}
+
+int ipmi_unregister_smi(ipmi_smi_t intf)
+{
+	int              rv = -ENODEV;
+	int              i;
+	struct list_head *entry;
+	unsigned int     flags;
+
+	down_write(&interfaces_sem);
+	if (list_empty(&(intf->users)))
+	{
+		for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+			if (ipmi_interfaces[i] == intf) {
+				spin_lock_irqsave(&interfaces_lock, flags);
+				ipmi_interfaces[i] = NULL;
+				clean_up_interface_data(intf);
+				spin_unlock_irqrestore(&interfaces_lock,flags);
+				kfree(intf);
+				rv = 0;
+				goto out_call_watcher;
+			}
+		}
+	} else {
+		rv = -EBUSY;
+	}
+	up_write(&interfaces_sem);
+
+	return rv;
+
+ out_call_watcher:
+	/* Convert to a read semaphore so callbacks don't bite us. */
+	up_write(&interfaces_sem);
+	down_read(&interfaces_sem);
+
+	/* Call all the watcher interfaces to tell them that
+	   an interface is gone. */
+	down_read(&smi_watchers_sem);
+	list_for_each(entry, &smi_watchers) {
+		struct ipmi_smi_watcher *w;
+		w = list_entry(entry,
+			       struct ipmi_smi_watcher,
+			       link);
+		w->smi_gone(i);
+	}
+	up_read(&smi_watchers_sem);
+	up_read(&interfaces_sem);
+	return 0;
+}
+
+static int handle_get_msg_rsp(ipmi_smi_t          intf,
+			      struct ipmi_smi_msg *msg)
+{
+	struct ipmi_ipmb_addr ipmb_addr;
+	struct ipmi_recv_msg  *recv_msg;
+
+	
+	if (msg->rsp_size < 11)
+		/* Message not big enough, just ignore it. */
+		return 0;
+
+	if (msg->rsp[2] != 0)
+		/* An error getting the response, just ignore it. */
+		return 0;
+
+	ipmb_addr.addr_type = IPMI_IPMB_ADDR_TYPE;
+	ipmb_addr.slave_addr = msg->rsp[6];
+	ipmb_addr.channel = msg->rsp[3] & 0x0f;
+	ipmb_addr.lun = msg->rsp[7] & 3;
+
+	/* It's a response from a remote entity.  Look up the sequence
+	   number and handle the response. */
+	if (intf_find_seq(intf,
+			  msg->rsp[7] >> 2,
+			  msg->rsp[3] & 0x0f,
+			  msg->rsp[8],
+			  (msg->rsp[4] >> 2) & (~1),
+			  (struct ipmi_addr *) &(ipmb_addr),
+			  &recv_msg))
+	{
+		/* We were unable to find the sequence number,
+		   so just nuke the message. */
+		return 0;
+	}
+
+	memcpy(recv_msg->msg_data,
+	       &(msg->rsp[9]),
+	       msg->rsp_size - 9);
+	/* THe other fields matched, so no need to set them, except
+           for netfn, which needs to be the response that was
+           returned, not the request value. */
+	recv_msg->msg.netfn = msg->rsp[4] >> 2;
+	recv_msg->msg.data = recv_msg->msg_data;
+	recv_msg->msg.data_len = msg->rsp_size - 10;
+	recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
+	deliver_response(recv_msg);
+
+	return 0;
+}
+
+static int handle_get_msg_cmd(ipmi_smi_t          intf,
+			      struct ipmi_smi_msg *msg)
+{
+	struct list_head *entry;
+	struct cmd_rcvr       *rcvr;
+	int              rv = 0;
+	unsigned char    netfn;
+	unsigned char    cmd;
+	ipmi_user_t      user = NULL;
+	struct ipmi_ipmb_addr *ipmb_addr;
+	struct ipmi_recv_msg  *recv_msg;
+
+	if (msg->rsp_size < 10)
+		/* Message not big enough, just ignore it. */
+		return 0;
+
+	if (msg->rsp[2] != 0) {
+		/* An error getting the response, just ignore it. */
+		return 0;
+	}
+
+	netfn = msg->rsp[4] >> 2;
+	cmd = msg->rsp[8];
+
+	read_lock(&(intf->cmd_rcvr_lock));
+	
+	if (intf->all_cmd_rcvr) {
+		user = intf->all_cmd_rcvr;
+	} else {
+		/* Find the command/netfn. */
+		list_for_each(entry, &(intf->cmd_rcvrs)) {
+			rcvr = list_entry(entry, struct cmd_rcvr, link);
+			if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) {
+				user = rcvr->user;
+				break;
+			}
+		}
+	}
+	read_unlock(&(intf->cmd_rcvr_lock));
+
+	if (user == NULL) {
+		/* We didn't find a user, deliver an error response. */
+		msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
+		msg->data[1] = IPMI_SEND_MSG_CMD;
+		msg->data[2] = msg->rsp[3];
+		msg->data[3] = msg->rsp[6];
+                msg->data[4] = ((netfn + 1) << 2) | (msg->rsp[7] & 0x3);
+		msg->data[5] = ipmb_checksum(&(msg->data[3]), 2);
+		msg->data[6] = intf->my_address;
+                /* rqseq/lun */
+                msg->data[7] = (msg->rsp[7] & 0xfc) | (msg->rsp[4] & 0x3);
+		msg->data[8] = msg->rsp[8]; /* cmd */
+		msg->data[9] = IPMI_INVALID_CMD_COMPLETION_CODE;
+		msg->data[10] = ipmb_checksum(&(msg->data[6]), 4);
+		msg->data_size = 11;
+
+		intf->handlers->sender(intf->send_info, msg, 0);
+
+		rv = -1; /* We used the message, so return the value that
+			    causes it to not be freed or queued. */
+	} else {
+		/* Deliver the message to the user. */
+		recv_msg = ipmi_alloc_recv_msg();
+		if (! recv_msg) {
+			/* We couldn't allocate memory for the
+                           message, so requeue it for handling
+                           later. */
+			rv = 1;
+		} else {
+			ipmb_addr = (struct ipmi_ipmb_addr *) &recv_msg->addr;
+			ipmb_addr->addr_type = IPMI_IPMB_ADDR_TYPE;
+			ipmb_addr->slave_addr = msg->rsp[6];
+			ipmb_addr->lun = msg->rsp[7] & 3;
+			ipmb_addr->channel = msg->rsp[3];
+
+			recv_msg->user = user;
+			recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
+			recv_msg->msgid = msg->rsp[7] >> 2;
+			recv_msg->msg.netfn = msg->rsp[4] >> 2;
+			recv_msg->msg.cmd = msg->rsp[8];
+			recv_msg->msg.data = recv_msg->msg_data;
+			recv_msg->msg.data_len = msg->rsp_size - 10;
+			memcpy(recv_msg->msg_data,
+			       &(msg->rsp[9]),
+			       msg->rsp_size - 10);
+			deliver_response(recv_msg);
+		}
+	}
+
+	return rv;
+}
+
+static void copy_event_into_recv_msg(struct ipmi_recv_msg *recv_msg,
+				     struct ipmi_smi_msg  *msg)
+{
+	struct ipmi_system_interface_addr *smi_addr;
+	
+	recv_msg->msgid = 0;
+	smi_addr = (struct ipmi_system_interface_addr *) &(recv_msg->addr);
+	smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+	smi_addr->channel = IPMI_BMC_CHANNEL;
+	smi_addr->lun = msg->rsp[0] & 3;
+	recv_msg->recv_type = IPMI_ASYNC_EVENT_RECV_TYPE;
+	recv_msg->msg.netfn = msg->rsp[0] >> 2;
+	recv_msg->msg.cmd = msg->rsp[1];
+	memcpy(recv_msg->msg_data, &(msg->rsp[3]), msg->rsp_size - 3);
+	recv_msg->msg.data = recv_msg->msg_data;
+	recv_msg->msg.data_len = msg->rsp_size - 3;
+}
+
+/* This will be called with the intf->users_lock read-locked, so no need
+   to do that here. */
+static int handle_read_event_rsp(ipmi_smi_t          intf,
+				 struct ipmi_smi_msg *msg)
+{
+	struct ipmi_recv_msg *recv_msg;
+	struct list_head     msgs;
+	struct list_head     *entry, *entry2;
+	ipmi_user_t          user;
+	int                  rv = 0;
+	int                  deliver_count = 0;
+	unsigned long        flags;
+
+	if (msg->rsp_size < 19) {
+		/* Message is too small to be an IPMB event. */
+		return 0;
+	}
+
+	if (msg->rsp[2] != 0) {
+		/* An error getting the event, just ignore it. */
+		return 0;
+	}
+
+	INIT_LIST_HEAD(&msgs);
+
+	spin_lock_irqsave(&(intf->events_lock), flags);
+
+	/* Allocate and fill in one message for every user that is getting
+	   events. */
+	list_for_each(entry, &(intf->users)) {
+		user = list_entry(entry, struct ipmi_user, link);
+
+		if (! user->gets_events)
+			continue;
+
+		recv_msg = ipmi_alloc_recv_msg();
+		if (! recv_msg) {
+			list_for_each_safe(entry, entry2, &msgs) {
+				recv_msg = list_entry(entry,
+						      struct ipmi_recv_msg,
+						      link);
+				list_del(entry);
+				ipmi_free_recv_msg(recv_msg);
+			}
+			/* We couldn't allocate memory for the
+                           message, so requeue it for handling
+                           later. */
+			rv = 1;
+			goto out;
+		}
+
+		deliver_count++;
+
+		copy_event_into_recv_msg(recv_msg, msg);
+		recv_msg->user = user;
+		list_add_tail(&(recv_msg->link), &msgs);
+	}
+
+	if (deliver_count) {
+		/* Now deliver all the messages. */
+		list_for_each_safe(entry, entry2, &msgs) {
+			recv_msg = list_entry(entry,
+					      struct ipmi_recv_msg,
+					      link);
+			list_del(entry);
+			deliver_response(recv_msg);
+		}
+	} else if (intf->waiting_events_count < MAX_EVENTS_IN_QUEUE) {
+		/* No one to receive the message, put it in queue if there's
+		   not already too many things in the queue. */
+		recv_msg = ipmi_alloc_recv_msg();
+		if (! recv_msg) {
+			/* We couldn't allocate memory for the
+                           message, so requeue it for handling
+                           later. */
+			rv = 1;
+			goto out;
+		}
+
+		copy_event_into_recv_msg(recv_msg, msg);
+		list_add_tail(&(recv_msg->link), &(intf->waiting_events));
+	} else {
+		/* There's too many things in the queue, discard this
+		   message. */
+		printk(KERN_WARNING "ipmi: Event queue full, discarding an"
+		       " incoming event\n");
+	}
+
+ out:
+	spin_unlock_irqrestore(&(intf->events_lock), flags);
+
+	return rv;
+}
+
+static int handle_bmc_rsp(ipmi_smi_t          intf,
+			  struct ipmi_smi_msg *msg)
+{
+	struct ipmi_recv_msg *recv_msg;
+	int                  found = 0;
+	struct list_head     *entry;
+
+	recv_msg = (struct ipmi_recv_msg *) msg->user_data;
+
+	/* Make sure the user still exists. */
+	list_for_each(entry, &(intf->users)) {
+		if (list_entry(entry, struct ipmi_user, link)
+		    == recv_msg->user)
+		{
+			/* Found it, so we can deliver it */
+			found = 1;
+			break;
+		}
+	}
+
+	if (!found) {
+		/* The user for the message went away, so give up. */
+		ipmi_free_recv_msg(recv_msg);
+	} else {
+		struct ipmi_system_interface_addr *smi_addr;
+
+		recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
+		recv_msg->msgid = msg->msgid;
+		smi_addr = ((struct ipmi_system_interface_addr *)
+			    &(recv_msg->addr));
+		smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+		smi_addr->channel = IPMI_BMC_CHANNEL;
+		smi_addr->lun = msg->rsp[0] & 3;
+		recv_msg->msg.netfn = msg->rsp[0] >> 2;
+		recv_msg->msg.cmd = msg->rsp[1];
+		memcpy(recv_msg->msg_data,
+		       &(msg->rsp[2]),
+		       msg->rsp_size - 2);
+		recv_msg->msg.data = recv_msg->msg_data;
+		recv_msg->msg.data_len = msg->rsp_size - 2;
+		deliver_response(recv_msg);
+	}
+
+	return 0;
+}
+
+/* Handle a new message.  Return 1 if the message should be requeued,
+   0 if the message should be freed, or -1 if the message should not
+   be freed or requeued. */
+static int handle_new_recv_msg(ipmi_smi_t          intf,
+			       struct ipmi_smi_msg *msg)
+{
+	int requeue;
+
+	if (msg->rsp_size < 2) {
+		/* Message is too small to be correct. */
+		requeue = 0;
+	} else if (msg->rsp[1] == IPMI_GET_MSG_CMD) {
+#if DEBUG_MSGING
+		int m;
+		printk("Response:");
+		for (m=0; m<msg->rsp_size; m++)
+			printk(" %2.2x", msg->rsp[m]);
+		printk("\n");
+#endif
+		/* It's from the receive queue. */
+		if (msg->rsp[4] & 0x04) {
+			/* It's a response, so find the
+			   requesting message and send it up. */
+			requeue = handle_get_msg_rsp(intf, msg);
+		} else {
+			/* It's a command to the SMS from some other
+			   entity.  Handle that. */
+			requeue = handle_get_msg_cmd(intf, msg);
+		}
+	} else if (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD) {
+		/* It's an asyncronous event. */
+		requeue = handle_read_event_rsp(intf, msg);
+	} else {
+		/* It's a response from the local BMC. */
+		requeue = handle_bmc_rsp(intf, msg);
+	}
+
+	return requeue;
+}
+
+/* Handle a new message from the lower layer. */
+void ipmi_smi_msg_received(ipmi_smi_t          intf,
+			   struct ipmi_smi_msg *msg)
+{
+	unsigned long flags;
+	int           rv;
+
+
+	if ((msg->data_size >= 2) && (msg->data[1] == IPMI_SEND_MSG_CMD)) {
+		/* This is the local response to a send, we just
+                   ignore these. */
+		msg->done(msg);
+		return;
+	}
+
+	/* Lock the user lock so the user can't go away while we are
+	   working on it. */
+	read_lock(&(intf->users_lock));
+
+	/* To preserve message order, if the list is not empty, we
+           tack this message onto the end of the list. */
+	spin_lock_irqsave(&(intf->waiting_msgs_lock), flags);
+	if (!list_empty(&(intf->waiting_msgs))) {
+		list_add_tail(&(msg->link), &(intf->waiting_msgs));
+		spin_unlock(&(intf->waiting_msgs_lock));
+		return;
+	}
+	spin_unlock_irqrestore(&(intf->waiting_msgs_lock), flags);
+		
+	rv = handle_new_recv_msg(intf, msg);
+	if (rv > 0) {
+		/* Could not handle the message now, just add it to a
+                   list to handle later. */
+		spin_lock(&(intf->waiting_msgs_lock));
+		list_add_tail(&(msg->link), &(intf->waiting_msgs));
+		spin_unlock(&(intf->waiting_msgs_lock));
+	} else if (rv == 0) {
+		msg->done(msg);
+	}
+
+	read_unlock(&(intf->users_lock));
+}
+
+void ipmi_smi_watchdog_pretimeout(ipmi_smi_t intf)
+{
+	struct list_head *entry;
+	ipmi_user_t      user;
+
+	read_lock(&(intf->users_lock));
+	list_for_each(entry, &(intf->users)) {
+		user = list_entry(entry, struct ipmi_user, link);
+
+		if (! user->handler->ipmi_watchdog_pretimeout)
+			continue;
+
+		user->handler->ipmi_watchdog_pretimeout(user->handler_data);
+	}
+	read_unlock(&(intf->users_lock));
+}
+
+static void
+handle_msg_timeout(struct ipmi_recv_msg *msg)
+{
+	msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
+	msg->msg_data[0] = IPMI_TIMEOUT_COMPLETION_CODE;
+	msg->msg.netfn |= 1; /* Convert to a response. */
+	msg->msg.data_len = 1;
+	msg->msg.data = msg->msg_data;
+	deliver_response(msg);
+}
+
+static void
+ipmi_timeout_handler(long timeout_period)
+{
+	ipmi_smi_t           intf;
+	struct list_head     timeouts;
+	struct ipmi_recv_msg *msg;
+	struct ipmi_smi_msg  *smi_msg;
+	unsigned long        flags;
+	struct list_head     *entry, *entry2;
+	int                  i, j;
+
+	INIT_LIST_HEAD(&timeouts);
+
+	spin_lock(&interfaces_lock);
+	for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+		intf = ipmi_interfaces[i];
+		if (intf == NULL)
+			continue;
+
+		read_lock(&(intf->users_lock));
+
+		/* See if any waiting messages need to be processed. */
+		spin_lock_irqsave(&(intf->waiting_msgs_lock), flags);
+		list_for_each_safe(entry, entry2, &(intf->waiting_msgs)) {
+			smi_msg = list_entry(entry, struct ipmi_smi_msg, link);
+			if (! handle_new_recv_msg(intf, smi_msg)) {
+				list_del(entry);
+				smi_msg->done(smi_msg);
+			} else {
+				/* To preserve message order, quit if we
+				   can't handle a message. */
+				break;
+			}
+		}
+		spin_unlock_irqrestore(&(intf->waiting_msgs_lock), flags);
+
+		/* Go through the seq table and find any messages that
+		   have timed out, putting them in the timeouts
+		   list. */
+		spin_lock_irqsave(&(intf->seq_lock), flags);
+		for (j=0; j<IPMI_IPMB_NUM_SEQ; j++) {
+			if (intf->seq_table[j].inuse) {
+				intf->seq_table[j].timeout -= timeout_period;
+				if (intf->seq_table[j].timeout <= 0) {
+					intf->seq_table[j].inuse = 0;
+					msg = intf->seq_table[j].recv_msg;
+					list_add_tail(&(msg->link), &timeouts);
+				}
+			}
+		}
+		spin_unlock_irqrestore(&(intf->seq_lock), flags);
+
+		list_for_each_safe(entry, entry2, &timeouts) {
+			msg = list_entry(entry, struct ipmi_recv_msg, link);
+			handle_msg_timeout(msg);
+		}
+
+		read_unlock(&(intf->users_lock));
+	}
+	spin_unlock(&interfaces_lock);
+}
+
+static void ipmi_request_event(void)
+{
+	ipmi_smi_t intf;
+	int        i;
+
+	spin_lock(&interfaces_lock);
+	for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+		intf = ipmi_interfaces[i];
+		if (intf == NULL)
+			continue;
+
+		intf->handlers->request_events(intf->send_info);
+	}
+	spin_unlock(&interfaces_lock);
+}
+
+static struct timer_list ipmi_timer;
+
+/* Call every 100 ms. */
+#define IPMI_TIMEOUT_TIME	100
+#define IPMI_TIMEOUT_JIFFIES	(IPMI_TIMEOUT_TIME/(1000/HZ))
+
+/* Request events from the queue every second.  Hopefully, in the
+   future, IPMI will add a way to know immediately if an event is
+   in the queue. */
+#define IPMI_REQUEST_EV_TIME	(1000 / (IPMI_TIMEOUT_TIME))
+
+static volatile int stop_operation = 0;
+static volatile int timer_stopped = 0;
+static unsigned int ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
+
+static void ipmi_timeout(unsigned long data)
+{
+	if (stop_operation) {
+		timer_stopped = 1;
+		return;
+	}
+
+	ticks_to_req_ev--;
+	if (ticks_to_req_ev == 0) {
+		ipmi_request_event();
+		ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
+	}
+
+	ipmi_timeout_handler(IPMI_TIMEOUT_TIME);
+
+	ipmi_timer.expires += IPMI_TIMEOUT_JIFFIES;
+	add_timer(&ipmi_timer);
+}
+
+
+/* FIXME - convert these to slabs. */
+static void free_smi_msg(struct ipmi_smi_msg *msg)
+{
+	kfree(msg);
+}
+
+struct ipmi_smi_msg *ipmi_alloc_smi_msg(void)
+{
+	struct ipmi_smi_msg *rv;
+	rv = kmalloc(sizeof(struct ipmi_smi_msg), GFP_ATOMIC);
+	if (rv)
+		rv->done = free_smi_msg;
+	return rv;
+}
+
+static void free_recv_msg(struct ipmi_recv_msg *msg)
+{
+	kfree(msg);
+}
+
+struct ipmi_recv_msg *ipmi_alloc_recv_msg(void)
+{
+	struct ipmi_recv_msg *rv;
+
+	rv = kmalloc(sizeof(struct ipmi_recv_msg), GFP_ATOMIC);
+	if (rv)
+		rv->done = free_recv_msg;
+	return rv;
+}
+
+#ifdef CONFIG_IPMI_PANIC_EVENT
+
+static void dummy_smi_done_handler(struct ipmi_smi_msg *msg)
+{
+}
+
+static void dummy_recv_done_handler(struct ipmi_recv_msg *msg)
+{
+}
+
+static void send_panic_events(void)
+{
+	struct ipmi_msg                   msg;
+	ipmi_smi_t                        intf;
+	unsigned char                     data[8];
+	int                               i;
+	struct ipmi_system_interface_addr addr;
+	struct ipmi_smi_msg               smi_msg;
+	struct ipmi_recv_msg              recv_msg;
+
+	addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+	addr.channel = IPMI_BMC_CHANNEL;
+
+	/* Fill in an event telling that we have failed. */
+	msg.netfn = 0x04; /* Sensor or Event. */
+	msg.cmd = 2; /* Platform event command. */
+	msg.data = data;
+	msg.data_len = 8;
+	data[0] = 0x21; /* Kernel generator ID, IPMI table 5-4 */
+	data[1] = 0x03; /* This is for IPMI 1.0. */
+	data[2] = 0x20; /* OS Critical Stop, IPMI table 36-3 */
+	data[4] = 0x6f; /* Sensor specific, IPMI table 36-1 */
+	data[5] = 0xa1; /* Runtime stop OEM bytes 2 & 3. */
+
+	/* These used to have the first three bytes of the panic string,
+	   but not only is that not terribly useful, it's not available
+	   any more. */
+	data[3] = 0;
+	data[6] = 0;
+	data[7] = 0;
+
+	smi_msg.done = dummy_smi_done_handler;
+	recv_msg.done = dummy_recv_done_handler;
+
+	/* For every registered interface, send the event. */
+	for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+		intf = ipmi_interfaces[i];
+		if (intf == NULL)
+			continue;
+
+		intf->handlers->set_run_to_completion(intf->send_info, 1);
+		i_ipmi_request(NULL,
+			       intf,
+			       (struct ipmi_addr *) &addr,
+			       0,
+			       &msg,
+			       &smi_msg,
+			       &recv_msg,
+			       0,
+			       intf->my_address,
+			       intf->my_lun);
+	}
+}
+#endif /* CONFIG_IPMI_PANIC_EVENT */
+
+static int has_paniced = 0;
+
+static int panic_event(struct notifier_block *this,
+		       unsigned long         event,
+                       void                  *ptr)
+{
+	int        i;
+	ipmi_smi_t intf;
+
+	if (has_paniced)
+		return NOTIFY_DONE;
+	has_paniced = 1;
+
+	/* For every registered interface, set it to run to completion. */
+	for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+		intf = ipmi_interfaces[i];
+		if (intf == NULL)
+			continue;
+
+		intf->handlers->set_run_to_completion(intf->send_info, 1);
+	}
+
+#ifdef CONFIG_IPMI_PANIC_EVENT
+	send_panic_events();
+#endif
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block panic_block = {
+	panic_event,
+	NULL,
+	200   /* priority: INT_MAX >= x >= 0 */
+};
+
+
+static __init int ipmi_init_msghandler(void)
+{
+	int i;
+
+	if (initialized)
+		return 0;
+
+	for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+		ipmi_interfaces[i] = NULL;
+	}
+
+	init_timer(&ipmi_timer);
+	ipmi_timer.data = 0;
+	ipmi_timer.function = ipmi_timeout;
+	ipmi_timer.expires = jiffies + IPMI_TIMEOUT_JIFFIES;
+	add_timer(&ipmi_timer);
+
+	notifier_chain_register(&panic_notifier_list, &panic_block);
+
+	initialized = 1;
+
+	printk(KERN_INFO "ipmi: message handler initialized\n");
+
+	return 0;
+}
+
+static __exit void cleanup_ipmi(void)
+{
+	if (!initialized)
+		return;
+
+	notifier_chain_unregister(&panic_notifier_list, &panic_block);
+
+	/* This can't be called if any interfaces exist, so no worry about
+	   shutting down the interfaces. */
+
+	/* Tell the timer to stop, then wait for it to stop.  This avoids
+	   problems with race conditions removing the timer here. */
+	stop_operation = 1;
+	while (!timer_stopped) {
+		schedule_timeout(1);
+	}
+
+	initialized = 0;
+}
+module_exit(cleanup_ipmi);
+
+module_init(ipmi_init_msghandler);
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(ipmi_alloc_recv_msg);
+EXPORT_SYMBOL(ipmi_create_user);
+EXPORT_SYMBOL(ipmi_destroy_user);
+EXPORT_SYMBOL(ipmi_get_version);
+EXPORT_SYMBOL(ipmi_request);
+EXPORT_SYMBOL(ipmi_request_supply_msgs);
+EXPORT_SYMBOL(ipmi_request_with_source);
+EXPORT_SYMBOL(ipmi_register_smi);
+EXPORT_SYMBOL(ipmi_unregister_smi);
+EXPORT_SYMBOL(ipmi_register_for_cmd);
+EXPORT_SYMBOL(ipmi_unregister_for_cmd);
+EXPORT_SYMBOL(ipmi_smi_msg_received);
+EXPORT_SYMBOL(ipmi_smi_watchdog_pretimeout);
+EXPORT_SYMBOL(ipmi_alloc_smi_msg);
+EXPORT_SYMBOL(ipmi_register_all_cmd_rcvr);
+EXPORT_SYMBOL(ipmi_unregister_all_cmd_rcvr);
+EXPORT_SYMBOL(ipmi_addr_length);
+EXPORT_SYMBOL(ipmi_validate_addr);
+EXPORT_SYMBOL(ipmi_set_gets_events);
+EXPORT_SYMBOL(ipmi_addr_equal);
+EXPORT_SYMBOL(ipmi_smi_watcher_register);
+EXPORT_SYMBOL(ipmi_smi_watcher_unregister);
+EXPORT_SYMBOL(ipmi_set_my_address);
+EXPORT_SYMBOL(ipmi_get_my_address);
+EXPORT_SYMBOL(ipmi_set_my_LUN);
+EXPORT_SYMBOL(ipmi_get_my_LUN);
diff -urN linux-2.4.21-pre3/drivers/char/ipmi/ipmi_watchdog.c linux-2.4.21-pre4/drivers/char/ipmi/ipmi_watchdog.c
--- linux-2.4.21-pre3/drivers/char/ipmi/ipmi_watchdog.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/drivers/char/ipmi/ipmi_watchdog.c	Tue Jan 28 19:44:29 2003
@@ -0,0 +1,971 @@
+/*
+ * ipmi_watchdog.c
+ *
+ * A watchdog timer based upon the IPMI interface.
+ *
+ * Author: MontaVista Software, Inc.
+ *         Corey Minyard <minyard@mvista.com>
+ *         source@mvista.com
+ *
+ * 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.
+ *
+ *
+ *  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/module.h>
+#include <linux/ipmi.h>
+#include <linux/ipmi_smi.h>
+#include <linux/watchdog.h>
+#include <linux/miscdevice.h>
+#include <linux/init.h>
+#include <linux/rwsem.h>
+#include <linux/errno.h>
+#include <asm/uaccess.h>
+#include <linux/notifier.h>
+#include <linux/nmi.h>
+#include <linux/reboot.h>
+#ifdef CONFIG_X86_LOCAL_APIC
+#include <asm/apic.h>
+#endif
+
+/*
+ * The IPMI command/response information for the watchdog timer.
+ */
+
+/* values for byte 1 of the set command, byte 2 of the get response. */
+#define WDOG_DONT_LOG		(1 << 7)
+#define WDOG_DONT_STOP_ON_SET	(1 << 6)
+#define WDOG_SET_TIMER_USE(byte, use) \
+	byte = ((byte) & 0xf8) | ((use) & 0x7)
+#define WDOG_GET_TIMER_USE(byte) ((byte) & 0x7)
+#define WDOG_TIMER_USE_BIOS_FRB2	1
+#define WDOG_TIMER_USE_BIOS_POST	2
+#define WDOG_TIMER_USE_OS_LOAD		3
+#define WDOG_TIMER_USE_SMS_OS		4
+#define WDOG_TIMER_USE_OEM		5
+
+/* values for byte 2 of the set command, byte 3 of the get response. */
+#define WDOG_SET_PRETIMEOUT_ACT(byte, use) \
+	byte = ((byte) & 0x8f) | (((use) & 0x7) << 4)
+#define WDOG_GET_PRETIMEOUT_ACT(byte) (((byte) >> 4) & 0x7)
+#define WDOG_PRETIMEOUT_NONE		0
+#define WDOG_PRETIMEOUT_SMI		1
+#define WDOG_PRETIMEOUT_NMI		2
+#define WDOG_PRETIMEOUT_MSG_INT		3
+
+#define WDOG_SET_TIMEOUT_ACT(byte, use) \
+	byte = ((byte) & 0xf8) | ((use) & 0x7)
+#define WDOG_GET_TIMEOUT_ACT(byte) ((byte) & 0x7)
+#define WDOG_TIMEOUT_NONE		0
+#define WDOG_TIMEOUT_RESET		1
+#define WDOG_TIMEOUT_POWER_DOWN		2
+#define WDOG_TIMEOUT_POWER_CYCLE	3
+
+/* Byte 3 of the get command, byte 4 of the get response is the
+   pre-timeout in seconds. */
+
+/* Bits for setting byte 4 of the set command, byte 5 of the get response. */
+#define WDOG_EXPIRE_CLEAR_BIOS_FRB2	(1 << 1)
+#define WDOG_EXPIRE_CLEAR_BIOS_POST	(1 << 2)
+#define WDOG_EXPIRE_CLEAR_OS_LOAD	(1 << 3)
+#define WDOG_EXPIRE_CLEAR_SMS_OS	(1 << 4)
+#define WDOG_EXPIRE_CLEAR_OEM		(1 << 5)
+
+/* Setting/getting the watchdog timer value.  This is for bytes 5 and
+   6 (the timeout time) of the set command, and bytes 6 and 7 (the
+   timeout time) and 8 and 9 (the current countdown value) of the
+   response.  The timeout value is given in seconds (in the command it
+   is 100ms intervals). */
+#define WDOG_SET_TIMEOUT(byte1, byte2, val) \
+	(byte1) = (((val) * 10) & 0xff), (byte2) = (((val) * 10) >> 8)
+#define WDOG_GET_TIMEOUT(byte1, byte2) \
+	(((byte1) | ((byte2) << 8)) / 10)
+
+#define IPMI_WDOG_RESET_TIMER		0x22
+#define IPMI_WDOG_SET_TIMER		0x24
+#define IPMI_WDOG_GET_TIMER		0x25
+
+/* These are here until the real ones get into the watchdog.h interface. */
+#ifndef WDIOC_GETTIMEOUT
+#define	WDIOC_GETTIMEOUT        _IOW(WATCHDOG_IOCTL_BASE, 20, int)
+#endif
+#ifndef WDIOC_SET_PRETIMEOUT
+#define	WDIOC_SET_PRETIMEOUT     _IOW(WATCHDOG_IOCTL_BASE, 21, int)
+#endif
+#ifndef WDIOC_GET_PRETIMEOUT
+#define	WDIOC_GET_PRETIMEOUT     _IOW(WATCHDOG_IOCTL_BASE, 22, int)
+#endif
+
+static ipmi_user_t watchdog_user = NULL;
+
+/* Default the timeout to 10 seconds. */
+static int timeout = 10;
+
+/* The pre-timeout is disabled by default. */
+static int pretimeout = 0;
+
+/* Default action is to reset the board on a timeout. */
+static unsigned char action_val = WDOG_TIMEOUT_RESET;
+
+static char *action = "reset";
+
+static unsigned char preaction_val = WDOG_PRETIMEOUT_NONE;
+
+static char *preaction = "pre_none";
+
+MODULE_PARM(timeout, "i");
+MODULE_PARM(pretimeout, "i");
+MODULE_PARM(action, "s");
+MODULE_PARM(preaction, "s");
+
+/* Default state of the timer. */
+static unsigned char ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
+
+/* If shutting down via IPMI, we ignore the heartbeat. */
+static int ipmi_ignore_heartbeat = 0;
+
+/* Is someone using the watchdog?  Only one user is allowed. */
+static int ipmi_wdog_open = 0;
+
+/* If true, the driver will start running as soon as it is configured
+   and ready. */
+static int start_now = 0;
+
+/* If set to 1, the heartbeat command will set the state to reset and
+   start the timer.  The timer doesn't normally run when the driver is
+   first opened until the heartbeat is set the first time, this
+   variable is used to accomplish this. */
+static int ipmi_start_timer_on_heartbeat = 0;
+
+/* IPMI version of the BMC. */
+static unsigned char ipmi_version_major;
+static unsigned char ipmi_version_minor;
+
+
+static int ipmi_heartbeat(void);
+static void panic_halt_ipmi_heartbeat(void);
+
+
+/* We use a semaphore to make sure that only one thing can send a set
+   timeout at one time, because we only have one copy of the data.
+   The semaphore is claimed when the set_timeout is sent and freed
+   when both messages are free. */
+static atomic_t set_timeout_tofree = ATOMIC_INIT(0);
+static DECLARE_MUTEX(set_timeout_lock);
+static void set_timeout_free_smi(struct ipmi_smi_msg *msg)
+{
+    if (atomic_dec_and_test(&set_timeout_tofree))
+	    up(&set_timeout_lock);
+}
+static void set_timeout_free_recv(struct ipmi_recv_msg *msg)
+{
+    if (atomic_dec_and_test(&set_timeout_tofree))
+	    up(&set_timeout_lock);
+}
+static struct ipmi_smi_msg set_timeout_smi_msg =
+{
+	.done = set_timeout_free_smi
+};
+static struct ipmi_recv_msg set_timeout_recv_msg =
+{
+	.done = set_timeout_free_recv
+};
+ 
+static int i_ipmi_set_timeout(struct ipmi_smi_msg  *smi_msg,
+			      struct ipmi_recv_msg *recv_msg,
+			      int                  *send_heartbeat_now)
+{
+	struct ipmi_msg    msg;
+	unsigned char      data[6];
+	int                rv;
+	struct ipmi_system_interface_addr addr;
+
+
+	*send_heartbeat_now = 0;
+	data[0] = 0;
+	WDOG_SET_TIMER_USE(data[0], WDOG_TIMER_USE_SMS_OS);
+
+	if ((ipmi_version_major > 1)
+	    || ((ipmi_version_major == 1) && (ipmi_version_minor >= 5)))
+	{
+		/* This is an IPMI 1.5-only feature. */
+		data[0] |= WDOG_DONT_STOP_ON_SET;
+	} else if (ipmi_watchdog_state != WDOG_TIMEOUT_NONE) {
+		/* In ipmi 1.0, setting the timer stops the watchdog, we
+		   need to start it back up again. */
+		*send_heartbeat_now = 1;
+	}
+
+	data[1] = 0;
+	WDOG_SET_TIMEOUT_ACT(data[1], ipmi_watchdog_state);
+	if (pretimeout > 0) {
+	    WDOG_SET_PRETIMEOUT_ACT(data[1], preaction_val);
+	    data[2] = pretimeout;
+	} else {
+	    WDOG_SET_PRETIMEOUT_ACT(data[1], WDOG_PRETIMEOUT_NONE);
+	    data[2] = 0; /* No pretimeout. */
+	}
+	data[3] = 0;
+	WDOG_SET_TIMEOUT(data[4], data[5], timeout);
+
+	addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+	addr.channel = IPMI_BMC_CHANNEL;
+	addr.lun = 0;
+
+	msg.netfn = 0x06;
+	msg.cmd = IPMI_WDOG_SET_TIMER;
+	msg.data = data;
+	msg.data_len = sizeof(data);
+	rv = ipmi_request_supply_msgs(watchdog_user,
+				      (struct ipmi_addr *) &addr,
+				      0,
+				      &msg,
+				      smi_msg,
+				      recv_msg,
+				      1);
+	if (rv) {
+		printk(KERN_WARNING "IPMI Watchdog, set timeout error: %d\n",
+		       rv);
+	}
+
+	return rv;
+}
+
+static int ipmi_set_timeout(void)
+{
+	int send_heartbeat_now;
+	int rv;
+
+
+	/* We can only send one of these at a time. */
+	down(&set_timeout_lock);
+
+	atomic_set(&set_timeout_tofree, 2);
+
+	rv = i_ipmi_set_timeout(&set_timeout_smi_msg,
+				&set_timeout_recv_msg,
+				&send_heartbeat_now);
+	if (rv) {
+		up(&set_timeout_lock);
+	} else {
+		if (send_heartbeat_now)
+			rv = ipmi_heartbeat();
+	}
+
+	return rv;
+}
+
+static void dummy_smi_free(struct ipmi_smi_msg *msg)
+{
+}
+static void dummy_recv_free(struct ipmi_recv_msg *msg)
+{
+}
+static struct ipmi_smi_msg panic_halt_smi_msg =
+{
+	.done = dummy_smi_free
+};
+static struct ipmi_recv_msg panic_halt_recv_msg =
+{
+	.done = dummy_recv_free
+};
+
+/* Special call, doesn't claim any locks.  This is only to be called
+   at panic or halt time, in run-to-completion mode, when the caller
+   is the only CPU and the only thing that will be going IPMI
+   calls. */
+static void panic_halt_ipmi_set_timeout(void)
+{
+	int send_heartbeat_now;
+	int rv;
+
+	rv = i_ipmi_set_timeout(&panic_halt_smi_msg,
+				&panic_halt_recv_msg,
+				&send_heartbeat_now);
+	if (!rv) {
+		if (send_heartbeat_now)
+			panic_halt_ipmi_heartbeat();
+	}
+}
+
+/* Do a delayed shutdown, with the delay in milliseconds.  If power_off is
+   false, do a reset.  If power_off is true, do a power down.  This is
+   primarily for the IMB code's shutdown. */
+void ipmi_delayed_shutdown(long delay, int power_off)
+{
+	ipmi_ignore_heartbeat = 1;
+	if (power_off) 
+		ipmi_watchdog_state = WDOG_TIMEOUT_POWER_DOWN;
+	else
+		ipmi_watchdog_state = WDOG_TIMEOUT_RESET;
+	timeout = delay;
+	ipmi_set_timeout();
+}
+
+/* We use a semaphore to make sure that only one thing can send a
+   heartbeat at one time, because we only have one copy of the data.
+   The semaphore is claimed when the set_timeout is sent and freed
+   when both messages are free. */
+static atomic_t heartbeat_tofree = ATOMIC_INIT(0);
+static DECLARE_MUTEX(heartbeat_lock);
+static DECLARE_MUTEX_LOCKED(heartbeat_wait_lock);
+static void heartbeat_free_smi(struct ipmi_smi_msg *msg)
+{
+    if (atomic_dec_and_test(&heartbeat_tofree))
+	    up(&heartbeat_wait_lock);
+}
+static void heartbeat_free_recv(struct ipmi_recv_msg *msg)
+{
+    if (atomic_dec_and_test(&heartbeat_tofree))
+	    up(&heartbeat_wait_lock);
+}
+static struct ipmi_smi_msg heartbeat_smi_msg =
+{
+	.done = heartbeat_free_smi
+};
+static struct ipmi_recv_msg heartbeat_recv_msg =
+{
+	.done = heartbeat_free_recv
+};
+ 
+static struct ipmi_smi_msg panic_halt_heartbeat_smi_msg =
+{
+	.done = dummy_smi_free
+};
+static struct ipmi_recv_msg panic_halt_heartbeat_recv_msg =
+{
+	.done = dummy_recv_free
+};
+ 
+static int ipmi_heartbeat(void)
+{
+	struct ipmi_msg                   msg;
+	int                               rv;
+	struct ipmi_system_interface_addr addr;
+
+	if (ipmi_ignore_heartbeat) {
+		return 0;
+	}
+
+	if (ipmi_start_timer_on_heartbeat) {
+		ipmi_start_timer_on_heartbeat = 0;
+		ipmi_watchdog_state = action_val;
+		return ipmi_set_timeout();
+	}
+
+	down(&heartbeat_lock);
+
+	atomic_set(&heartbeat_tofree, 2);
+
+	/* Don't reset the timer if we have the timer turned off, that
+           re-enables the watchdog. */
+	if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE) {
+		up(&heartbeat_lock);
+		return 0;
+	}
+
+	addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+	addr.channel = IPMI_BMC_CHANNEL;
+	addr.lun = 0;
+
+	msg.netfn = 0x06;
+	msg.cmd = IPMI_WDOG_RESET_TIMER;
+	msg.data = NULL;
+	msg.data_len = 0;
+	rv = ipmi_request_supply_msgs(watchdog_user,
+				      (struct ipmi_addr *) &addr,
+				      0,
+				      &msg,
+				      &heartbeat_smi_msg,
+				      &heartbeat_recv_msg,
+				      1);
+	if (rv) {
+		up(&heartbeat_lock);
+		printk(KERN_WARNING "IPMI Watchdog, heartbeat failure: %d\n",
+		       rv);
+		return rv;
+	}
+
+	/* Wait for the heartbeat to be sent. */
+	down(&heartbeat_wait_lock);
+
+	if (heartbeat_recv_msg.msg.data[0] != 0) {
+	    /* Got an error in the heartbeat response.  It was already
+	       reported in ipmi_wdog_msg_handler, but we should return
+	       an error here. */
+	    rv = -EINVAL;
+	}
+
+	up(&heartbeat_lock);
+
+	return rv;
+}
+
+static void panic_halt_ipmi_heartbeat(void)
+{
+	struct ipmi_msg                   msg;
+	struct ipmi_system_interface_addr addr;
+
+
+	/* Don't reset the timer if we have the timer turned off, that
+           re-enables the watchdog. */
+	if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE)
+		return;
+
+	addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+	addr.channel = IPMI_BMC_CHANNEL;
+	addr.lun = 0;
+
+	msg.netfn = 0x06;
+	msg.cmd = IPMI_WDOG_RESET_TIMER;
+	msg.data = NULL;
+	msg.data_len = 0;
+	ipmi_request_supply_msgs(watchdog_user,
+				 (struct ipmi_addr *) &addr,
+				 0,
+				 &msg,
+				 &panic_halt_heartbeat_smi_msg,
+				 &panic_halt_heartbeat_recv_msg,
+				 1);
+}
+
+static struct watchdog_info ident=
+{
+	0, /* WDIOF_SETTIMEOUT, */
+	1,
+	"IPMI"
+};
+
+static int ipmi_ioctl(struct inode *inode, struct file *file,
+		      unsigned int cmd, unsigned long arg)
+{
+	int i;
+	int val;
+
+	switch(cmd) {
+	case WDIOC_GETSUPPORT:
+		i = copy_to_user((void*)arg, &ident, sizeof(ident));
+		return i ? -EFAULT : 0;
+
+	case WDIOC_SETTIMEOUT:
+		i = copy_from_user(&val, (void *) arg, sizeof(int));
+		if (i)
+			return -EFAULT;
+		timeout = val;
+		return ipmi_set_timeout();
+
+	case WDIOC_GETTIMEOUT:
+		i = copy_to_user((void *) arg,
+				 &timeout,
+				 sizeof(timeout));
+		if (i)
+			return -EFAULT;
+		return 0;
+
+	case WDIOC_SET_PRETIMEOUT:
+		i = copy_from_user(&val, (void *) arg, sizeof(int));
+		if (i)
+			return -EFAULT;
+		pretimeout = val;
+		return ipmi_set_timeout();
+
+	case WDIOC_GET_PRETIMEOUT:
+		i = copy_to_user((void *) arg,
+				 &pretimeout,
+				 sizeof(pretimeout));
+		if (i)
+			return -EFAULT;
+		return 0;
+
+	case WDIOC_KEEPALIVE:
+		return ipmi_heartbeat();
+
+	case WDIOC_SETOPTIONS:
+		i = copy_from_user(&val, (void *) arg, sizeof(int));
+		if (i)
+			return -EFAULT;
+		if (val & WDIOS_DISABLECARD)
+		{
+			ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
+			ipmi_set_timeout();
+			ipmi_start_timer_on_heartbeat = 0;
+		}
+
+		if (val & WDIOS_ENABLECARD)
+		{
+			ipmi_watchdog_state = action_val;
+			ipmi_set_timeout();
+		}
+		return 0;
+
+	case WDIOC_GETSTATUS:
+		val = 0;
+		return copy_to_user((void *) arg, &val, sizeof(val));
+
+	default:
+		return -ENOIOCTLCMD;
+	}
+}
+
+static ssize_t ipmi_write(struct file *file,
+			  const char  *buf,
+			  size_t      len,
+			  loff_t      *ppos)
+{
+	int rv;
+
+	/*  Can't seek (pwrite) on this device  */
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	if (len) {
+		rv = ipmi_heartbeat();
+		if (rv)
+			return rv;
+		return 1;
+	}
+	return 0;
+}
+
+static ssize_t ipmi_read(struct file *file,
+			 char        *buf,
+			 size_t      count,
+			 loff_t      *ppos)
+{
+	/*  Can't seek (pread) on this device  */
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	/* Also can't read it. */
+	return -EINVAL;
+}
+
+static int ipmi_open(struct inode *ino, struct file *filep)
+{
+        switch (minor(ino->i_rdev))
+        {
+                case WATCHDOG_MINOR:
+                    if (ipmi_wdog_open)
+                        return -EBUSY;
+
+                    ipmi_wdog_open = 1;
+
+		    /* Don't start the timer now, let it start on the
+		       first heartbeat. */
+		    ipmi_start_timer_on_heartbeat = 1;
+                    return(0);
+
+                default:
+                    return (-ENODEV);
+        }
+}
+
+static int ipmi_close(struct inode *ino, struct file *filep)
+{
+	if (minor(ino->i_rdev)==WATCHDOG_MINOR)
+	{
+#ifndef CONFIG_WATCHDOG_NOWAYOUT	
+		ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
+		ipmi_set_timeout();
+#endif		
+	        ipmi_wdog_open = 0;
+	}
+	return 0;
+}
+
+static struct file_operations ipmi_wdog_fops = {
+	.owner   = THIS_MODULE,
+	.read    = ipmi_read,
+	.write   = ipmi_write,
+	.ioctl   = ipmi_ioctl,
+	.open    = ipmi_open,
+	.release = ipmi_close,
+};
+
+static struct miscdevice ipmi_wdog_miscdev = {
+	WATCHDOG_MINOR,
+	"watchdog",
+	&ipmi_wdog_fops
+};
+
+static DECLARE_RWSEM(register_sem);
+
+static void ipmi_wdog_msg_handler(struct ipmi_recv_msg *msg,
+				  void            *handler_data)
+{
+	if (msg->msg.data[0] != 0) {
+		printk(KERN_ERR "IPMI Watchdog response: Error %x on cmd %x\n",
+		       msg->msg.data[0],
+		       msg->msg.cmd);
+	}
+	
+	ipmi_free_recv_msg(msg);
+}
+
+static void ipmi_wdog_pretimeout_handler(void *handler_data)
+{
+	panic("Watchdog pre-timeout");
+}
+
+static struct ipmi_user_hndl ipmi_hndlrs =
+{
+	.ipmi_recv_hndl           = ipmi_wdog_msg_handler,
+	.ipmi_watchdog_pretimeout = ipmi_wdog_pretimeout_handler
+};
+
+static void ipmi_register_watchdog(int ipmi_intf)
+{
+	int rv = -EBUSY;
+
+	down_read(&register_sem);
+	if (watchdog_user)
+		goto out;
+
+	rv = ipmi_create_user(ipmi_intf, &ipmi_hndlrs, NULL, &watchdog_user);
+	if (rv < 0) {
+		printk("IPMI watchdog: Unable to register with ipmi\n");
+		goto out;
+	}
+
+	ipmi_get_version(watchdog_user,
+			 &ipmi_version_major,
+			 &ipmi_version_minor);
+
+	rv = misc_register(&ipmi_wdog_miscdev);
+	if (rv < 0) {
+		ipmi_destroy_user(watchdog_user);
+		watchdog_user = NULL;
+		printk("IPMI watchdog: Unable to register misc device\n");
+	}
+
+ out:
+	up_write(&register_sem);
+
+	if ((start_now) && (rv == 0)) {
+		/* Run from startup, so start the timer now. */
+		start_now = 0; /* Disable this function after first startup. */
+		ipmi_watchdog_state = action_val;
+		ipmi_set_timeout();
+		printk("Starting IPMI Watchdog now!\n");
+	}
+}
+
+#ifdef HAVE_NMI_HANDLER
+static int
+ipmi_nmi(void *dev_id, struct pt_regs *regs, int cpu, int handled)
+{
+	/* If no one else handled the NMI, we assume it was the IPMI
+           watchdog. */
+	if (!handled)
+		panic("IPMI watchdog pre-timeout");
+	return NOTIFY_DONE;
+}
+
+static struct nmi_handler ipmi_nmi_handler =
+{
+	.dev_name = "ipmi_watchdog",
+	.dev_id   = NULL,
+	.handler  = ipmi_nmi,
+	.priority = 0, /* Call us last. */
+};
+#endif
+
+static int wdog_reboot_handler(struct notifier_block *this,
+			       unsigned long         code,
+			       void                  *unused)
+{
+	static int reboot_event_handled = 0;
+
+	if ((watchdog_user) && (!reboot_event_handled)) {
+		/* Make sure we only do this once. */
+		reboot_event_handled = 1;
+
+		if (code == SYS_DOWN || code == SYS_HALT) {
+			/* Disable the WDT if we are shutting down. */
+			ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
+			panic_halt_ipmi_set_timeout();
+		} else {
+			/* Set a long timer to let the reboot happens, but
+			   reboot if it hangs. */
+			timeout = 120;
+			pretimeout = 0;
+			ipmi_watchdog_state = WDOG_TIMEOUT_RESET;
+			panic_halt_ipmi_set_timeout();
+		}
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block wdog_reboot_notifier = {
+	wdog_reboot_handler,
+	NULL,
+	0
+};
+
+extern int panic_timeout; /* Why isn't this defined anywhere? */
+
+static int wdog_panic_handler(struct notifier_block *this,
+			      unsigned long         event,
+			      void                  *unused)
+{
+	static int panic_event_handled = 0;
+
+	/* On a panic, if we have a panic timeout, make sure that the thing
+	   reboots, even if it hangs during that panic. */
+	if (watchdog_user && !panic_event_handled && (panic_timeout > 0)) {
+		/* Make sure the panic doesn't hang, and make sure we
+		   do this only once. */
+		panic_event_handled = 1;
+	    
+		timeout = panic_timeout + 120;
+		if (timeout > 255)
+			timeout = 255;
+		pretimeout = 0;
+		ipmi_watchdog_state = WDOG_TIMEOUT_RESET;
+		panic_halt_ipmi_set_timeout();
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block wdog_panic_notifier = {
+	wdog_panic_handler,
+	NULL,
+	150   /* priority: INT_MAX >= x >= 0 */
+};
+
+
+static void ipmi_new_smi(int if_num)
+{
+	ipmi_register_watchdog(if_num);
+}
+
+static void ipmi_smi_gone(int if_num)
+{
+	/* This can never be called, because once the watchdog is
+	   registered, the interface can't go away until the watchdog
+	   is unregistered. */
+}
+
+static struct ipmi_smi_watcher smi_watcher =
+{
+	.new_smi  = ipmi_new_smi,
+	.smi_gone = ipmi_smi_gone
+};
+
+static int __init ipmi_wdog_init(void)
+{
+	int rv;
+
+	if (strcmp(action, "reset") == 0) {
+		action_val = WDOG_TIMEOUT_RESET;
+	} else if (strcmp(action, "none") == 0) {
+		action_val = WDOG_TIMEOUT_NONE;
+	} else if (strcmp(action, "power_cycle") == 0) {
+		action_val = WDOG_TIMEOUT_POWER_CYCLE;
+	} else if (strcmp(action, "power_off") == 0) {
+		action_val = WDOG_TIMEOUT_POWER_DOWN;
+	} else {
+		action_val = WDOG_TIMEOUT_RESET;
+		printk("ipmi_watchdog: Unknown action '%s', defaulting to"
+		       " reset\n", action);
+	}
+
+	if (strcmp(preaction, "pre_none") == 0) {
+		preaction_val = WDOG_PRETIMEOUT_NONE;
+	} else if (strcmp(preaction, "pre_smi") == 0) {
+		preaction_val = WDOG_PRETIMEOUT_SMI;
+#ifdef HAVE_NMI_HANDLER
+	} else if (strcmp(preaction, "pre_nmi") == 0) {
+		preaction_val = WDOG_PRETIMEOUT_NMI;
+#endif
+	} else if (strcmp(preaction, "pre_int") == 0) {
+		preaction_val = WDOG_PRETIMEOUT_MSG_INT;
+	} else {
+		action_val = WDOG_PRETIMEOUT_NONE;
+		printk("ipmi_watchdog: Unknown preaction '%s', defaulting to"
+		       " none\n", preaction);
+	}
+
+#ifdef HAVE_NMI_HANDLER
+	if (preaction_val == WDOG_PRETIMEOUT_NMI) {
+#ifdef CONFIG_X86_LOCAL_APIC
+		if (nmi_watchdog == NMI_IO_APIC) {
+			printk(KERN_WARNING
+			       "ipmi_watchdog: nmi_watchdog is set to IO APIC"
+			       " mode (value is %d), that is incompatible"
+			       " with using NMI in the IPMI watchdog."
+			       " Disabling IPMI nmi pretimeout.\n",
+			       nmi_watchdog);
+			preaction_val = WDOG_PRETIMEOUT_NONE;
+		} else {
+#endif
+		rv = request_nmi(&ipmi_nmi_handler);
+		if (rv) {
+			printk(KERN_WARNING
+			       "ipmi_watchdog: Can't register nmi handler\n");
+			return rv;
+		}
+#ifdef CONFIG_X86_LOCAL_APIC
+		}
+#endif
+	}
+#endif
+
+	rv = ipmi_smi_watcher_register(&smi_watcher);
+	if (rv) {
+#ifdef HAVE_NMI_HANDLER
+		if (preaction_val == WDOG_PRETIMEOUT_NMI)
+			release_nmi(&ipmi_nmi_handler);
+#endif
+		printk(KERN_WARNING
+		       "ipmi_watchdog: can't register smi watcher\n");
+		return rv;
+	}
+
+	register_reboot_notifier(&wdog_reboot_notifier);
+	notifier_chain_register(&panic_notifier_list, &wdog_panic_notifier);
+
+	printk(KERN_INFO "IPMI watchdog by "
+	       "Corey Minyard (minyard@mvista.com)\n");
+
+	return 0;
+}
+
+#ifdef MODULE
+static void ipmi_unregister_watchdog(void)
+{
+	int rv;
+
+	down_write(&register_sem);
+
+#ifdef HAVE_NMI_HANDLER
+	if (preaction_val == WDOG_PRETIMEOUT_NMI)
+		release_nmi(&ipmi_nmi_handler);
+#endif
+
+	if (! watchdog_user)
+		goto out;
+
+	/* Make sure no one can call us any more. */
+	misc_deregister(&ipmi_wdog_miscdev);
+
+	notifier_chain_unregister(&panic_notifier_list, &wdog_panic_notifier);
+	unregister_reboot_notifier(&wdog_reboot_notifier);
+
+	/*  Disable the timer. */
+	ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
+	ipmi_set_timeout();
+
+	/* Wait to make sure the message makes it out.  The lower layer has
+	   pointers to our buffers, we want to make sure they are done before
+	   we release our memory. */
+	while (atomic_read(&set_timeout_tofree)) {
+		schedule_timeout(1);
+	}
+
+	/* Disconnect from IPMI. */
+	rv = ipmi_destroy_user(watchdog_user);
+	if (rv) {
+		printk(KERN_WARNING
+		       "IPMI Watchdog, error unlinking from IPMI: %d\n",
+		       rv);
+	}
+	watchdog_user = NULL;
+
+ out:
+	up_write(&register_sem);
+}
+
+static void __exit ipmi_wdog_exit(void)
+{
+	ipmi_smi_watcher_unregister(&smi_watcher);
+	ipmi_unregister_watchdog();
+}
+module_exit(ipmi_wdog_exit);
+#else
+static int __init ipmi_wdog_setup(char *str)
+{
+	int  val;
+	int  rv;
+	char *option;
+
+	rv = get_option(&str, &val);
+	if (rv == 0)
+		return 1;
+	if (val > 0)
+		timeout = val;
+	if (rv == 1)
+		return 1;
+
+	rv = get_option(&str, &val);
+	if (rv == 0)
+		return 1;
+	if (val >= 0)
+		pretimeout = val;
+	if (rv == 1)
+		return 1;
+
+	while ((option = strsep(&str, ",")) != NULL) {
+		if (strcmp(option, "reset") == 0) {
+			action = "reset";
+		}
+		else if (strcmp(option, "none") == 0) {
+			action = "none";
+		}
+		else if (strcmp(option, "power_cycle") == 0) {
+			action = "power_cycle";
+		}
+		else if (strcmp(option, "power_off") == 0) {
+			action = "power_off";
+		}
+		else if (strcmp(option, "pre_none") == 0) {
+			preaction = "pre_none";
+		}
+		else if (strcmp(option, "pre_smi") == 0) {
+			preaction = "pre_smi";
+		}
+#ifdef HAVE_NMI_HANDLER
+		else if (strcmp(option, "pre_nmi") == 0) {
+			preaction = "pre_nmi";
+		}
+#endif
+		else if (strcmp(option, "pre_int") == 0) {
+			preaction = "pre_int";
+		}
+		else if (strcmp(option, "start_now") == 0) {
+			start_now = 1;
+		} else {
+		    printk("Unknown IPMI watchdog option: '%s'\n", option);
+		}
+	}
+
+	return 1;
+}
+__setup("ipmi_wdog=", ipmi_wdog_setup);
+#endif
+
+EXPORT_SYMBOL(ipmi_delayed_shutdown);
+
+module_init(ipmi_wdog_init);
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.21-pre3/drivers/char/joystick/iforce.c linux-2.4.21-pre4/drivers/char/joystick/iforce.c
--- linux-2.4.21-pre3/drivers/char/joystick/iforce.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/drivers/char/joystick/iforce.c	Tue Jan 28 19:44:29 2003
@@ -93,6 +93,7 @@
 	BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_A, BTN_B, BTN_C, BTN_DEAD, -1 };
 static signed short btn_wheel[] =    { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE,
 	BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_A, BTN_B, BTN_C, -1 };
+static signed short btn_avb_tw[] =   { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, -1 };
 static signed short abs_joystick[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 };
 static signed short abs_wheel[] =    { ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, -1 };
 static signed short ff_iforce[] =    { FF_PERIODIC, FF_CONSTANT, FF_SPRING, FF_FRICTION,
@@ -106,11 +107,15 @@
 	signed short *abs;
 	signed short *ff;
 } iforce_device[] = {
+	{ 0x044f, 0xa01c, "Thrustmaster Motor Sport GT",		btn_wheel, abs_wheel, ff_iforce },
 	{ 0x046d, 0xc281, "Logitech WingMan Force",			btn_joystick, abs_joystick, ff_iforce },
 	{ 0x046d, 0xc291, "Logitech WingMan Formula Force",		btn_wheel, abs_wheel, ff_iforce },
 	{ 0x05ef, 0x020a, "AVB Top Shot Pegasus",			btn_joystick, abs_joystick, ff_iforce },
 	{ 0x05ef, 0x8884, "AVB Mag Turbo Force",			btn_wheel, abs_wheel, ff_iforce },
+	{ 0x05ef, 0x8888, "AVB Top Shot Force Feedback Racing Wheel",	btn_avb_tw, abs_wheel, ff_iforce },
+	{ 0x061c, 0xc084, "ACT LABS Force RS",                          btn_wheel, abs_wheel, ff_iforce },
 	{ 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback",	btn_wheel, abs_wheel, ff_iforce },
+	{ 0x06f8, 0x0004, "Guillemot Force Feedback Racing Wheel",	btn_wheel, abs_wheel, ff_iforce },
 	{ 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]",		btn_joystick, abs_joystick, ff_iforce }
 };
 
@@ -1061,11 +1066,15 @@
 }
 
 static struct usb_device_id iforce_usb_ids [] = {
+	{ USB_DEVICE(0x044f, 0xa01c) },		/* Thrustmaster Motor Sport GT */
 	{ USB_DEVICE(0x046d, 0xc281) },		/* Logitech WingMan Force */
 	{ USB_DEVICE(0x046d, 0xc291) },		/* Logitech WingMan Formula Force */
 	{ USB_DEVICE(0x05ef, 0x020a) },		/* AVB Top Shot Pegasus */
 	{ USB_DEVICE(0x05ef, 0x8884) },		/* AVB Mag Turbo Force */
+	{ USB_DEVICE(0x05ef, 0x8888) },		/* AVB Top Shot FFB Racing Wheel */
+	{ USB_DEVICE(0x061c, 0xc084) },         /* ACT LABS Force RS */
 	{ USB_DEVICE(0x06f8, 0x0001) },		/* Guillemot Race Leader Force Feedback */
+	{ USB_DEVICE(0x06f8, 0x0004) },		/* Guillemot Force Feedback Racing Wheel */
 	{ }					/* Terminating entry */
 };
 
diff -urN linux-2.4.21-pre3/drivers/char/mux.c linux-2.4.21-pre4/drivers/char/mux.c
--- linux-2.4.21-pre3/drivers/char/mux.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/drivers/char/mux.c	Tue Jan 28 19:44:29 2003
@@ -0,0 +1,638 @@
+/*
+** mux.c:
+**      MUX console for the NOVA and K-Class systems.
+**
+**	(c) Copyright 2002 Ryan Bradetich
+**	(c) Copyright 2002 Hewlett-Packard Company
+**
+** 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 Driver used Christoph Plattner's pdc_console.c as a driver
+** template.
+**
+** This Driver currently only supports the console (port 0) on the MUX.
+** Additional work will be needed on this driver to enable the full
+** functionality of the MUX.
+**
+*/
+
+static char *mux_drv_version = "0.1";
+
+#include <linux/config.h>
+#include <linux/version.h>
+
+#undef SERIAL_PARANOIA_CHECK
+#define CONFIG_SERIAL_NOPAUSE_IO
+#define SERIAL_DO_RESTART
+
+#include <linux/module.h>
+#include <linux/serial.h>
+#include <linux/serialP.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+
+#ifdef CONFIG_MAGIC_SYSRQ
+#include <linux/sysrq.h>
+static unsigned long break_pressed;
+#endif
+
+#ifdef CONFIG_GSC
+#include <asm/gsc.h>
+#endif
+
+static unsigned long hpa;
+
+#define MUX_OFFSET 0x800
+#define MUX_LINE_OFFSET 0x80
+
+#define MUX_FIFO_SIZE 255
+#define MUX_MIN_FREE_SIZE 32
+
+#define MUX_FIFO_DRAIN_DELAY 1
+#define MUX_POLL_DELAY (30 * HZ / 1000)
+
+#define IO_COMMAND_REG_OFFSET 0x30
+#define IO_STATUS_REG_OFFSET 0x34
+#define IO_DATA_REG_OFFSET 0x3c
+#define IO_DCOUNT_REG_OFFSET 0x40
+#define IO_UCOUNT_REG_OFFSET 0x44
+#define IO_FIFOS_REG_OFFSET 0x48
+
+#define MUX_EOFIFO(status) ((status & 0xF000) == 0xF000)
+#define MUX_STATUS(status) ((status & 0xF000) == 0x8000)
+#define MUX_BREAK(status) ((status & 0xF000) == 0x2000)
+
+static int mux_drv_refcount; /* = 0 */
+static struct tty_driver mux_drv_driver;
+static struct async_struct *mux_drv_info;
+static struct timer_list mux_drv_timer;
+
+#define NR_PORTS 1
+static struct tty_struct *mux_drv_table[NR_PORTS];
+static struct termios *mux_drv_termios[NR_PORTS];
+static struct termios *mux_drv_termios_locked[NR_PORTS];
+
+/**
+ * mux_read_fifo - Read chars from the mux fifo.
+ * @info: Ptr to the async structure.
+ *
+ * This reads all available data from the mux's fifo and pushes
+ * the data to the tty layer.
+ */
+static void
+mux_read_fifo(struct async_struct *info)
+{
+	int data;
+	struct tty_struct *tty = info->tty;
+
+	while(1) {
+		data = __raw_readl((unsigned long)info->iomem_base 
+				   + IO_DATA_REG_OFFSET);
+
+		if (MUX_STATUS(data))
+			continue;
+
+		if (MUX_EOFIFO(data))
+			break;
+
+		if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+			continue;
+
+		*tty->flip.char_buf_ptr = data & 0xffu;
+		*tty->flip.flag_buf_ptr = 0;
+
+#ifdef CONFIG_MAGIC_SYSRQ
+		if (MUX_BREAK(data) && !break_pressed) {
+ 			break_pressed = jiffies;
+			continue;
+		}
+
+		if(MUX_BREAK(data)) {
+			*tty->flip.flag_buf_ptr = TTY_BREAK;
+		}
+
+		if(break_pressed) {
+			if(time_before(jiffies, break_pressed + HZ * 5)) {
+				handle_sysrq(data & 0xffu, NULL, NULL, NULL);
+				break_pressed = 0;
+				continue; 
+			}
+			break_pressed = 0;
+		}
+#endif
+
+		tty->flip.flag_buf_ptr++;
+		tty->flip.char_buf_ptr++;
+		tty->flip.count++;
+	}
+
+	tty_flip_buffer_push(tty);
+}
+
+
+/**
+ * mux_drv_poll - Mux poll function.
+ * @unused: Unused variable
+ *
+ * This function periodically polls the Mux to check for new data.
+ */
+static void
+mux_drv_poll(unsigned long unused)
+{
+	struct async_struct *info = mux_drv_info;
+
+	if(info && info->tty && mux_drv_refcount) {
+		mux_read_fifo(info);
+		info->last_active = jiffies;
+	}
+
+	mod_timer(&mux_drv_timer, jiffies + MUX_POLL_DELAY);
+}
+
+/**
+ * mux_chars_in_buffer - Returns the number of chars present in the outbound fifo.
+ * @tty: Ptr to the tty structure.
+ *
+ * This function returns the number of chars sitting in the outbound fifo.
+ * [Note: This function is required for the normal_poll function in 
+ *  drivers/char/n_tty.c].
+ */
+static int
+mux_chars_in_buffer(struct tty_struct *tty)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	return __raw_readl((unsigned long)info->iomem_base 
+			   + IO_DCOUNT_REG_OFFSET);
+}
+
+/**
+ * mux_flush_buffer - Pause until the fifo is empty.
+ * @tty: Ptr to the tty structure.
+ *
+ * Since the mux fifo is self draining, this function just
+ * waits until the fifo has completely drained.
+ */
+static void
+mux_flush_buffer(struct tty_struct *tty)
+{
+	while(mux_chars_in_buffer(tty))
+		mdelay(MUX_FIFO_DRAIN_DELAY);
+}
+
+/**
+ * mux_write_room - How much room is left in the fifo.
+ * @tty: Ptr to the tty structure.
+ *
+ * This function returns how much room is in the fifo for
+ * writing.
+ */
+static int
+mux_write_room(struct tty_struct *tty)
+{
+	int room = mux_chars_in_buffer(tty);
+	if(room > MUX_FIFO_SIZE)
+		return 0;
+
+	return MUX_FIFO_SIZE - room;
+}
+
+/**
+ * mux_write - Write chars to the mux fifo.
+ * @tty: Ptr to the tty structure.
+ * @from_user: Is the buffer from user space?
+ * @buf: The buffer to write to the mux fifo.
+ * @count: The number of chars to write to the mux fifo.
+ *
+ * This function writes the data from buf to the mux fifo.
+ * [Note: we need the mux_flush_buffer() at the end of the 
+ * function, otherwise the system will wait for LONG_MAX
+ * if the fifo is not empty when the TCSETSW ioctl is called.]
+ */
+static int
+mux_write(struct tty_struct *tty, int from_user,
+	  const unsigned char *buf, int count)
+{
+	int size, len, ret = count;
+	char buffer[MUX_FIFO_SIZE], *buf_p;
+	unsigned long iomem_base = 
+		(unsigned long)((struct async_struct *)tty->driver_data)->iomem_base;
+
+	while (count) {
+		size = mux_write_room(tty);
+		len = (size < count) ? size : count;
+
+		if (from_user) {
+			copy_from_user(buffer, buf, len);
+			buf_p = buffer;
+		} else {
+			buf_p = (char *)buf;
+		}
+
+		count -= len;
+		buf += len;
+
+		if(size < MUX_MIN_FREE_SIZE)
+			mux_flush_buffer(tty);
+
+		while(len--) {
+			__raw_writel(*buf_p++, iomem_base + IO_DATA_REG_OFFSET);
+		}
+	}
+
+	mux_flush_buffer(tty);
+	return ret;
+}
+
+/**
+ * mux_break - Turn break handling on or off.
+ * @tty: Ptr to the tty structure.
+ * @break_state: break value.
+ *
+ * This function must be defined because the send_break() in
+ * drivers/char/tty_io.c requires it.  Currently the Serial Mux
+ * does nothing when this function is called.
+ */
+static void
+mux_break(struct tty_struct *tty, int break_state)
+{
+}
+
+/**
+ * get_serial_info - Return the serial structure to userspace.
+ * @info: Ptr to the async structure.
+ * @retinfo: Ptr to the users space buffer.
+ *
+ * Fill in this serial structure and return it to userspace.
+ */
+static int
+get_serial_info(struct async_struct *info,
+		struct serial_struct *retinfo)
+{
+	struct serial_struct tmp;
+
+	if (!retinfo)
+		return -EFAULT;
+
+	memset(&tmp, 0, sizeof(tmp));
+	tmp.line = info->line;
+	tmp.port = info->line;
+	tmp.flags = info->flags;
+	tmp.close_delay = info->close_delay;
+	return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
+}
+
+/**
+ * get_modem_info - Return the modem control and status signals to userspace.
+ * @info: Ptr to the async structure.
+ * @value: The return buffer.
+ *
+ * The Serial MUX driver always returns these values to userspace:
+ *      Data Terminal Ready, Carrier Detect, Clear To Send,
+ *      Request To Send.
+ *
+ */
+static int 
+get_modem_info(struct async_struct *info, unsigned int *value)
+{
+	unsigned int result = TIOCM_DTR|TIOCM_CAR|TIOCM_CTS|TIOCM_RTS;
+	return copy_to_user(value, &result, sizeof(int)) ? -EFAULT : 0;
+}
+
+/**
+ * get_lsr_info - Return line status register info to userspace.
+ * @info: Ptr to the async structure.
+ * @value: The return buffer.
+ *
+ * The Serial MUX driver always returns empty transmitter to userspace.
+ */
+static int 
+get_lsr_info(struct async_struct *info, unsigned int *value)
+{
+	unsigned int result = TIOCSER_TEMT;
+	return copy_to_user(value, &result, sizeof(int)) ? -EFAULT : 0;
+}
+
+/**
+ * mux_ioctl - Handle driver specific ioctl commands.
+ * @tty: Ptr to the tty structure.
+ * @file: Unused.
+ * @cmd: The ioctl number.
+ * @arg: The ioctl argument.
+ *
+ * This function handles ioctls specific to the Serial MUX driver,
+ * or ioctls that need driver specific information.
+ *
+ */
+static int
+mux_ioctl(struct tty_struct *tty, struct file *file,
+	  unsigned int cmd, unsigned long arg)
+{
+	struct async_struct *info = (struct async_struct *) tty->driver_data;
+
+	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+	    (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
+	    (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 0;
+
+	case TIOCGSERIAL:
+		return get_serial_info(info, (struct serial_struct *) arg);
+
+	case TIOCSSERIAL:
+		return 0;
+
+	case TIOCSERCONFIG:
+		return 0;
+
+	case TIOCSERGETLSR:
+		return get_lsr_info(info, (unsigned int *) arg);
+
+	case TIOCSERGSTRUCT:
+		if (copy_to_user((struct async_struct *) arg,
+				 info, sizeof (struct async_struct)))
+			return -EFAULT;
+		return 0;
+
+	case TIOCMIWAIT:
+		return 0;
+
+	case TIOCGICOUNT:
+		return 0;
+
+	case TIOCSERGWILD:
+	case TIOCSERSWILD:
+		/* "setserial -W" is called in Debian boot */
+		printk("TIOCSER?WILD ioctl obsolete, ignored.\n");
+		return 0;
+
+	default:
+		return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+/**
+ * mux_close - Close the serial mux driver.
+ * @tty: Ptr to the tty structure.
+ * @filp: Unused.
+ * 
+ * This routine is called when the serial port gets closed.  First, we
+ * wait for the last remaining data to be sent.  Then, we unlink its
+ * async structure from the interrupt chain if necessary, and we free
+ * that IRQ if nothing is left in the chain.
+ */
+static void
+mux_close(struct tty_struct *tty, struct file *filp)
+{
+	struct async_struct *info = (struct async_struct *) tty->driver_data;
+
+	mux_drv_refcount--;
+	if (mux_drv_refcount > 0)
+		return;
+
+	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->state->normal_termios = *tty->termios;
+	if (info->flags & ASYNC_CALLOUT_ACTIVE)
+		info->state->callout_termios = *tty->termios;
+
+	/*
+	 * At this point we stop accepting input.  To do this, we
+	 * disable the receive line status interrupts, and tell the
+	 * interrupt driver to stop checking the data ready bit in the
+	 * line status register.
+	 */
+
+	/* XXX CP: make mask for receive !!! */
+
+	if (tty->driver.flush_buffer)
+		tty->driver.flush_buffer(tty);
+	if (tty->ldisc.flush_buffer)
+		tty->ldisc.flush_buffer(tty);
+	tty->closing = 0;
+	info->event = 0;
+	info->tty = 0;
+	mux_drv_info = NULL;
+	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);
+	MOD_DEC_USE_COUNT;
+}
+
+/**
+ * get_async_struct - Get the async structure.
+ * @line: Minor number of the tty device.
+ * @ret_info: Ptr to the newly allocated async structure.
+ *
+ * Allocate and return an async structure for the specified
+ * tty device line.
+ */
+static int
+get_async_struct(int line, struct async_struct **ret_info)
+{
+	struct async_struct *info;
+
+	info = kmalloc(sizeof (struct async_struct), GFP_KERNEL);
+	if (!info) {
+		return -ENOMEM;
+	}
+	memset(info, 0, sizeof (struct async_struct));
+	init_waitqueue_head(&info->open_wait);
+	init_waitqueue_head(&info->close_wait);
+	init_waitqueue_head(&info->delta_msr_wait);
+	info->magic = SERIAL_MAGIC;
+	info->port = 0;
+	info->flags = 0;
+	info->io_type = 0;
+	info->iomem_base = (void *)(hpa + MUX_OFFSET);
+	info->iomem_reg_shift = 0;
+	info->xmit_fifo_size = MUX_FIFO_SIZE;
+	info->line = line;
+	info->tqueue.routine = NULL;
+	info->tqueue.data = info;
+	info->state = NULL;
+	*ret_info = info;
+	return 0;
+}
+
+/**
+ * mux_open - Open the serial mux driver.
+ * @tty: Ptr to the tty structure.
+ * @filp: Unused.
+ *
+ * This routine is called whenever a serial port is opened.  It
+ * enables interrupts for a serial port, linking in its async structure 
+ * into the IRQ chain.   It also performs the serial-specific
+ * initialization for the tty structure.
+ */
+static int
+mux_open(struct tty_struct *tty, struct file *filp)
+{
+	struct async_struct *info;
+	int retval, line;
+
+	MOD_INC_USE_COUNT;
+	line = MINOR(tty->device) - tty->driver.minor_start;
+	if ((line < 0) || (line >= NR_PORTS)) {
+		MOD_DEC_USE_COUNT;
+		return -ENODEV;
+	}
+	retval = get_async_struct(line, &info);
+	if (retval) {
+		MOD_DEC_USE_COUNT;
+		return retval;
+	}
+
+	tty->driver_data = info;
+	info->tty = tty;
+	mux_drv_info = info;
+	info->tty->low_latency = 0;
+	info->session = current->session;
+	info->pgrp = current->pgrp;
+	mux_drv_refcount++;
+	return 0;
+}
+
+/**
+ * mux_probe - Determine if the Serial Mux should claim this device.
+ * @dev: The parisc device.
+ *
+ * Deterimine if the Sserial Mux should claim this chip (return 0)
+ * or not (return 1).
+ */
+static int __init 
+mux_probe(struct parisc_device *dev)
+{
+	if(hpa) {
+		printk(KERN_INFO "Serial MUX driver already registered, skipping additonal MUXes for now.\n");
+		return 1;
+	}
+
+	init_timer(&mux_drv_timer);
+	mux_drv_timer.function = mux_drv_poll;
+	mod_timer(&mux_drv_timer, jiffies + MUX_POLL_DELAY);
+
+	hpa = dev->hpa;
+	printk(KERN_INFO "Serial MUX driver version %s at 0x%lx\n",
+	       mux_drv_version, hpa);
+
+	/* Initialize the tty_driver structure */
+
+	memset(&mux_drv_driver, 0, sizeof (struct tty_driver));
+	mux_drv_driver.magic = TTY_DRIVER_MAGIC;
+	mux_drv_driver.driver_name = "Serial MUX driver";
+#ifdef CONFIG_DEVFS_FS
+	mux_drv_driver.name = "ttb/%d";
+#else
+	mux_drv_driver.name = "ttyB";
+#endif
+	mux_drv_driver.major = MUX_MAJOR;
+	mux_drv_driver.minor_start = 0;
+	mux_drv_driver.num = NR_PORTS;
+	mux_drv_driver.type = TTY_DRIVER_TYPE_SERIAL;
+	mux_drv_driver.subtype = SERIAL_TYPE_NORMAL;
+	mux_drv_driver.init_termios = tty_std_termios;
+	mux_drv_driver.init_termios.c_cflag =
+	    B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	mux_drv_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+	mux_drv_driver.refcount = &mux_drv_refcount;
+	mux_drv_driver.table = mux_drv_table;
+	mux_drv_driver.termios = mux_drv_termios;
+	mux_drv_driver.termios_locked = mux_drv_termios_locked;
+
+	mux_drv_driver.open = mux_open;
+	mux_drv_driver.close = mux_close;
+	mux_drv_driver.write = mux_write;
+	mux_drv_driver.put_char = NULL;
+	mux_drv_driver.flush_chars = NULL;
+	mux_drv_driver.write_room = mux_write_room;
+	mux_drv_driver.chars_in_buffer = mux_chars_in_buffer;
+	mux_drv_driver.flush_buffer = mux_flush_buffer;
+	mux_drv_driver.ioctl = mux_ioctl;
+	mux_drv_driver.throttle = NULL;
+	mux_drv_driver.unthrottle = NULL;
+	mux_drv_driver.set_termios = NULL;
+	mux_drv_driver.stop = NULL;
+	mux_drv_driver.start = NULL;
+	mux_drv_driver.hangup = NULL;
+	mux_drv_driver.break_ctl = mux_break;
+	mux_drv_driver.send_xchar = NULL;
+	mux_drv_driver.wait_until_sent = NULL;
+	mux_drv_driver.read_proc = NULL;
+
+	if (tty_register_driver(&mux_drv_driver))
+		panic("Could not register the serial MUX driver\n");
+
+	return 0;
+}
+
+static struct parisc_device_id mux_tbl[] = {
+	{ HPHW_A_DIRECT, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0000D },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(parisc, mux_tbl);
+
+static struct parisc_driver mux_driver = {
+	name:		"Serial MUX driver",
+	id_table:	mux_tbl,
+	probe:		mux_probe,
+};
+
+/**
+ * mux_init - Serial MUX initalization procedure.
+ *
+ * Register the Serial MUX driver.
+ */
+static int __init mux_init(void) 
+{
+	return register_parisc_driver(&mux_driver);
+}
+
+/**
+ * mux_exit - Serial MUX cleanup procedure.
+ *
+ * Unregister the Serial MUX driver from the tty layer.
+ */
+static void __exit mux_exit(void)
+{
+	int status = tty_unregister_driver(&mux_drv_driver);
+	if(status) {
+		printk("MUX: failed to unregister the Serial MUX driver (%d)\n", status);
+	}
+}
+
+module_init(mux_init);
+module_exit(mux_exit);
+MODULE_DESCRIPTION("Serial MUX driver");
+MODULE_AUTHOR("Ryan Bradetich");
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.21-pre3/drivers/char/nvram.c linux-2.4.21-pre4/drivers/char/nvram.c
--- linux-2.4.21-pre3/drivers/char/nvram.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre4/drivers/char/nvram.c	Tue Jan 28 19:44:29 2003
@@ -98,6 +98,8 @@
 #define RTC_PORT(x)		(TT_RTC_BAS + 2*(x))
 #define CHECK_DRIVER_INIT()	(MACH_IS_ATARI && ATARIHW_PRESENT(TT_CLK))
 
+#define NVRAM_BYTES		50
+
 /* On Ataris, the checksum is over all bytes except the checksum bytes
  * themselves; these are at the very end */
 #define ATARI_CKS_RANGE_START	0
diff -urN linux-2.4.21-pre3/drivers/char/rtc.c linux-2.4.21-pre4/drivers/char/rtc.c
--- linux-2.4.21-pre3/drivers/char/rtc.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.21-pre4/drivers/char/rtc.c	Tue Jan 28 19:44:29 2003
@@ -383,22 +383,18 @@
 		min = alm_tm.tm_min;
 		sec = alm_tm.tm_sec;
 
-		if (hrs >= 24)
-			hrs = 0xff;
-
-		if (min >= 60)
-			min = 0xff;
-
-		if (sec >= 60)
-			sec = 0xff;
-
 		spin_lock_irq(&rtc_lock);
 		if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) ||
 		    RTC_ALWAYS_BCD)
 		{
-			BIN_TO_BCD(sec);
-			BIN_TO_BCD(min);
-			BIN_TO_BCD(hrs);
+			if (sec < 60) BIN_TO_BCD(sec);
+			else sec = 0xff;
+
+			if (min < 60) BIN_TO_BCD(min);
+			else min = 0xff;
+
+			if (hrs < 24) BIN_TO_BCD(hrs);
+			else hrs = 0xff;
 		}
 		CMOS_WRITE(hrs, RTC_HOURS_ALARM);
 		CMOS_WRITE(min, RTC_MINUTES_ALARM);
diff -urN linux-2.4.21-pre3/drivers/char/sonypi.c linux-2.4.21-pre4/drivers/char/sonypi.c
--- linux-2.4.21-pre3/drivers/char/sonypi.c	Tue Jan 28 19:44:25 2003
+++ linux-2.4.21-pre4/drivers/char/sonypi.c	Tue Jan 28 19:44:29 2003
@@ -714,11 +714,11 @@
 	       SONYPI_DRIVER_MAJORVERSION,
 	       SONYPI_DRIVER_MINORVERSION);
 	printk(KERN_INFO "sonypi: detected %s model, "
-	       "verbose = %s, fnkeyinit = %s, camera = %s, "
+	       "verbose = %d, fnkeyinit = %s, camera = %s, "
 	       "compat = %s, mask = 0x%08lx\n",
 	       (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE1) ?
 			"type1" : "type2",
-	       verbose ? "on" : "off",
+	       verbose,
 	       fnkeyinit ? "on" : "off",
 	       camera ? "on" : "off",
 	       compat ? "on" : "off",
diff -urN linux-2.4.21-pre3/drivers/char/sonypi.h linux-2.4.21-pre4/drivers/char/sonypi.h
--- linux-2.4.21-pre3/drivers/char/sonypi.h	Tue Jan 28 19:44:25 2003
+++ linux-2.4.21-pre4/drivers/char/sonypi.h	Tue Jan 28 19:44:29 2003
@@ -37,7 +37,7 @@
 #ifdef __KERNEL__
 
 #define SONYPI_DRIVER_MAJORVERSION	 1
-#define SONYPI_DRIVER_MINORVERSION	16
+#define SONYPI_DRIVER_MINORVERSION	17
 
 #define SONYPI_DEVICE_MODEL_TYPE1	1
 #define SONYPI_DEVICE_MODEL_TYPE2	2
@@ -171,6 +171,13 @@
 	u8	data;
 	u8	event;
 };
+
+/* The set of possible button release events */
+static struct sonypi_event sonypi_releaseev[] = {
+	{ 0x00, SONYPI_EVENT_ANYBUTTON_RELEASED },
+	{ 0, 0 }
+};
+
 /* The set of possible jogger events  */
 static struct sonypi_event sonypi_joggerev[] = {
 	{ 0x1f, SONYPI_EVENT_JOGDIAL_UP },
@@ -186,7 +193,6 @@
 	{ 0x5d, SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED },
 	{ 0x43, SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED },
 	{ 0x40, SONYPI_EVENT_JOGDIAL_PRESSED },
-	{ 0x00, SONYPI_EVENT_JOGDIAL_RELEASED },
 	{ 0, 0 }
 };
 
@@ -195,7 +201,6 @@
 	{ 0x05, SONYPI_EVENT_CAPTURE_PARTIALPRESSED },
 	{ 0x07, SONYPI_EVENT_CAPTURE_PRESSED },
 	{ 0x01, SONYPI_EVENT_CAPTURE_PARTIALRELEASED },
-	{ 0x00, SONYPI_EVENT_CAPTURE_RELEASED },
 	{ 0, 0 }
 };
 
@@ -293,6 +298,7 @@
 	unsigned long		mask;
 	struct sonypi_event *	events;
 } sonypi_eventtypes[] = {
+	{ SONYPI_DEVICE_MODEL_TYPE1, 0, 0xffffffff, sonypi_releaseev },
 	{ SONYPI_DEVICE_MODEL_TYPE1, 0x70, SONYPI_MEYE_MASK, sonypi_meyeev },
 	{ SONYPI_DEVICE_MODEL_TYPE1, 0x30, SONYPI_LID_MASK, sonypi_lidev },
 	{ SONYPI_DEVICE_MODEL_TYPE1, 0x60, SONYPI_CAPTURE_MASK, sonypi_captureev },
@@ -301,6 +307,7 @@
 	{ SONYPI_DEVICE_MODEL_TYPE1, 0x30, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
 	{ SONYPI_DEVICE_MODEL_TYPE1, 0x40, SONYPI_PKEY_MASK, sonypi_pkeyev },
 
+	{ SONYPI_DEVICE_MODEL_TYPE2, 0, 0xffffffff, sonypi_releaseev },
 	{ SONYPI_DEVICE_MODEL_TYPE2, 0x38, SONYPI_LID_MASK, sonypi_lidev },
 	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_JOGGER_MASK, sonypi_joggerev },
 	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_CAPTURE_MASK, sonypi_captureev },
@@ -356,6 +363,14 @@
 		printk(KERN_WARNING "sonypi command failed at %s : %s (line %d)\n", __FILE__, __FUNCTION__, __LINE__); \
 }
 
+#ifdef CONFIG_ACPI
+#include <linux/acpi.h>
+#if (ACPI_CA_VERSION > 0x20021121)
+#define USE_ACPI
+#endif
+#endif /* CONFIG_ACPI */
+
+#ifndef USE_ACPI
 extern int verbose;
 
 static inline int ec_write(u8 addr, u8 value) {
@@ -378,6 +393,7 @@
 	*value = inb_p(SONYPI_DATA_IOPORT);
 	return 0;
 }
+#endif /* ! USE_ACPI */
 
 #endif /* __KERNEL__ */
 
diff -urN linux-2.4.21-pre3/drivers/ide/Config.in linux-2.4.21-pre4/drivers/ide/Config.in
--- linux-2.4.21-pre3/drivers/ide/Config.in	Tue Jan 28 19:44:25 2003
+++ linux-2.4.21-pre4/drivers/ide/Config.in	Tue Jan 28 19:44:29 2003
@@ -23,7 +23,7 @@
    dep_tristate '  SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE $CONFIG_SCSI
 
    bool '  IDE Taskfile Access' CONFIG_IDE_TASK_IOCTL
-   bool '  IDE Taskfile IO' CONFIG_IDE_TASKFILE_IO
+#   bool '  IDE Taskfile IO' CONFIG_IDE_TASKFILE_IO
 
    comment 'IDE chipset support/bugfixes'
    if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then
@@ -219,5 +219,6 @@
 dep_tristate 'Support for IDE Raid controllers (EXPERIMENTAL)' CONFIG_BLK_DEV_ATARAID $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL
 dep_tristate '   Support Promise software RAID (Fasttrak(tm)) (EXPERIMENTAL)' CONFIG_BLK_DEV_ATARAID_PDC $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL $CONFIG_BLK_DEV_ATARAID
 dep_tristate '   Highpoint 370 software RAID (EXPERIMENTAL)' CONFIG_BLK_DEV_ATARAID_HPT $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL $CONFIG_BLK_DEV_ATARAID
+dep_tristate '   Silicon Image Medley software RAID (EXPERIMENTAL)' CONFIG_BLK_DEV_ATARAID_SII $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL $CONFIG_BLK_DEV_ATARAID
 
 endmenu
diff -urN linux-2.4.21-pre3/drivers/ide/ide-cd.c linux-2.4.21-pre4/drivers/ide/ide-cd.c
--- linux-2.4.21-pre3/drivers/ide/ide-cd.c	Tue Jan 28 19:44:25 2003
+++ linux-2.4.21-pre4/drivers/ide/ide-cd.c	Tue Jan 28 19:44:29 2003
@@ -3137,11 +3137,7 @@
 	version:		IDECD_VERSION,
 	media:			ide_cdrom,
 	busy:			0,
-#ifdef CONFIG_IDEDMA_ONLYDISK
-	supports_dma:		0,
-#else
 	supports_dma:		1,
-#endif
 	supports_dsc_overlap:	1,
 	cleanup:		ide_cdrom_cleanup,
 	standby:		NULL,
diff -urN linux-2.4.21-pre3/drivers/ide/ide-dma.c linux-2.4.21-pre4/drivers/ide/ide-dma.c
--- linux-2.4.21-pre3/drivers/ide/ide-dma.c	Tue Jan 28 19:44:25 2003
+++ linux-2.4.21-pre4/drivers/ide/ide-dma.c	Tue Jan 28 19:44:29 2003
@@ -249,6 +249,7 @@
 {
 	struct buffer_head *bh;
 	struct scatterlist *sg = hwif->sg_table;
+	unsigned long lastdataend = ~0UL;
 	int nents = 0;
 
 	if (hwif->sg_dma_active)
@@ -256,24 +257,42 @@
 
 	bh = rq->bh;
 	do {
-		unsigned char *virt_addr = bh->b_data;
-		unsigned int size = bh->b_size;
+		int contig = 0;
+
+		if (bh->b_page) {
+			if (bh_phys(bh) == lastdataend)
+				contig = 1;
+		} else {
+			if ((unsigned long) bh->b_data == lastdataend)
+				contig = 1;
+		}
+
+		if (contig) {
+			sg[nents - 1].length += bh->b_size;
+			lastdataend += bh->b_size;
+			continue;
+		}
 
 		if (nents >= PRD_ENTRIES)
 			return 0;
 
-		while ((bh = bh->b_reqnext) != NULL) {
-			if ((virt_addr + size) != (unsigned char *) bh->b_data)
-				break;
-			size += bh->b_size;
-		}
 		memset(&sg[nents], 0, sizeof(*sg));
-		sg[nents].address = virt_addr;
-		sg[nents].length = size;
-		if(size == 0)
-			BUG();
+
+		if (bh->b_page) {
+			sg[nents].page = bh->b_page;
+			sg[nents].offset = bh_offset(bh);
+			lastdataend = bh_phys(bh) + bh->b_size;
+		} else {
+			if ((unsigned long) bh->b_data < PAGE_SIZE)
+				BUG();
+
+			sg[nents].address = bh->b_data;
+			lastdataend = (unsigned long) bh->b_data + bh->b_size;
+		}
+
+		sg[nents].length = bh->b_size;
 		nents++;
-	} while (bh != NULL);
+	} while ((bh = bh->b_reqnext) != NULL);
 
 	if(nents == 0)
 		BUG();
diff -urN linux-2.4.21-pre3/drivers/ide/ide-floppy.c linux-2.4.21-pre4/drivers/ide/ide-floppy.c
--- linux-2.4.21-pre3/drivers/ide/ide-floppy.c	Tue Jan 28 19:44:25 2003
+++ linux-2.4.21-pre4/drivers/ide/ide-floppy.c	Tue Jan 28 19:44:29 2003
@@ -2093,11 +2093,7 @@
 	version:		IDEFLOPPY_VERSION,
 	media:			ide_floppy,
 	busy:			0,
-#ifdef CONFIG_IDEDMA_ONLYDISK
-	supports_dma:		0,
-#else
 	supports_dma:		1,
-#endif
 	supports_dsc_overlap:	0,
 	cleanup:		idefloppy_cleanup,
 	standby:		NULL,
diff -urN linux-2.4.21-pre3/drivers/ide/ide-probe.c linux-2.4.21-pre4/drivers/ide/ide-probe.c
--- linux-2.4.21-pre3/drivers/ide/ide-probe.c	Tue Jan 28 19:44:25 2003
+++ linux-2.4.21-pre4/drivers/ide/ide-probe.c	Tue Jan 28 19:44:29 2003
@@ -608,7 +608,6 @@
 		probe_cmos_for_drives(hwif);
 	}
 #endif
-
 	if ((hwif->chipset != ide_4drives || !hwif->mate || !hwif->mate->present) &&
 #if CONFIG_BLK_DEV_PDC4030
 	    (hwif->chipset != ide_pdc4030 || hwif->channel == 0) &&
@@ -681,11 +680,18 @@
 
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
 		ide_drive_t *drive = &hwif->drives[unit];
+		int enable_dma = 1;
+
 		if (drive->present) {
 			if (hwif->tuneproc != NULL && 
 				drive->autotune == IDE_TUNE_AUTO)
 				/* auto-tune PIO mode */
 				hwif->tuneproc(drive, 255);
+
+#ifdef CONFIG_IDEDMA_ONLYDISK
+			if (drive->media != ide_disk)
+				enable_dma = 0;
+#endif
 			/*
 			 * MAJOR HACK BARF :-/
 			 *
@@ -705,7 +711,8 @@
 				 *   PARANOIA!!!
 				 */
 				hwif->ide_dma_off_quietly(drive);
-				hwif->ide_dma_check(drive);
+				if (enable_dma)
+					hwif->ide_dma_check(drive);
 			}
 		}
 	}
diff -urN linux-2.4.21-pre3/drivers/ide/ide-tape.c linux-2.4.21-pre4/drivers/ide/ide-tape.c
--- linux-2.4.21-pre3/drivers/ide/ide-tape.c	Tue Jan 28 19:44:25 2003
+++ linux-2.4.21-pre4/drivers/ide/ide-tape.c	Tue Jan 28 19:44:29 2003
@@ -450,8 +450,6 @@
 #include <asm/bitops.h>
 
 
-#define NO_LONGER_REQUIRED	(1)
-
 /*
  *	OnStream support
  */
@@ -2165,11 +2163,6 @@
 			status.b.check = 0;
 		if (status.b.check || test_bit(PC_DMA_ERROR, &pc->flags)) {
 			/* Error detected */
-#if IDETAPE_DEBUG_LOG
-			if (tape->debug_level >= 1)
-				printk(KERN_INFO "ide-tape: %s: I/O error\n",
-					tape->name);
-#endif /* IDETAPE_DEBUG_LOG */
 			if (pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
 				printk(KERN_ERR "ide-tape: I/O error in "
 					"request sense command\n");
@@ -2270,8 +2263,8 @@
 	pc->current_position += bcount.all;
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 2)
-		printk(KERN_INFO "ide-tape: [cmd %x] transferred %d bytes "
-			"on that interrupt\n", pc->c[0], bcount.all);
+		printk(KERN_INFO "ide-tape: [cmd %x] done %d\n"
+			pc->c[0], bcount.all);
 #endif
 	if (HWGROUP(drive)->handler != NULL)
 		BUG();
@@ -2614,8 +2607,11 @@
 	if (status.b.dsc) {
 		if (status.b.check) {
 			/* Error detected */
-			printk(KERN_ERR "ide-tape: %s: I/O error, ",
-					tape->name);
+			printk(KERN_ERR "ide-tape: %s: I/O error: "
+			    "pc = %2x, key = %2x, asc = %2x, ascq = %2x\n",
+			    tape->name, pc->c[0],
+			    tape->sense_key, tape->asc, tape->ascq);
+
 			/* Retry operation */
 			return idetape_retry_pc(drive);
 		}
@@ -3486,29 +3482,10 @@
 		printk (KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 
-#ifdef NO_LONGER_REQUIRED
-	idetape_flush_tape_buffers(drive);
-#endif
 	idetape_create_read_position_cmd(&pc);
 	if (idetape_queue_pc_tail(drive, &pc))
 		return -1;
 	position = tape->first_frame_position;
-#ifdef NO_LONGER_REQUIRED
-	if (tape->onstream) {
-		if ((position != tape->last_frame_position - tape->blocks_in_buffer) &&
-		    (position != tape->last_frame_position + tape->blocks_in_buffer)) {
-			if (tape->blocks_in_buffer == 0) {
-				printk("ide-tape: %s: correcting read "
-					"position %d, %d, %d\n",
-					tape->name, position,
-					tape->last_frame_position,
-					tape->blocks_in_buffer);
-				position = tape->last_frame_position;
-				tape->first_frame_position = position;
-			}
-		}
-	}
-#endif
 	return position;
 }
 
@@ -6195,6 +6172,10 @@
 		printk(KERN_INFO "ide-tape: %s: overriding capabilities->max_speed (assuming 650KB/sec)\n", drive->name);
 		capabilities->max_speed = 650;
 	}
+	if (!capabilities->ctl) {
+		printk(KERN_INFO "ide-tape: %s: overriding capabilities->ctl (assuming 26KB)\n", drive->name);
+		capabilities->ctl = 52;
+	}
 
 	tape->capabilities = *capabilities;		/* Save us a copy */
 	if (capabilities->blk512)
@@ -6250,10 +6231,6 @@
 	idetape_create_mode_sense_cmd(&pc, IDETAPE_BLOCK_DESCRIPTOR);
 	if (idetape_queue_pc_tail(drive, &pc)) {
 		printk(KERN_ERR "ide-tape: Can't get block descriptor\n");
-		if (tape->tape_block_size == 0) {
-			printk(KERN_WARNING "ide-tape: Cannot deal with zero block size, assume 32k\n");
-			tape->tape_block_size =  32768;
-		}
 		return;
 	}
 	header = (idetape_mode_parameter_header_t *) pc.buffer;
@@ -6350,6 +6327,10 @@
 	idetape_get_inquiry_results(drive);
 	idetape_get_mode_sense_results(drive);
 	idetape_get_blocksize_from_block_descriptor(drive);
+	if (tape->tape_block_size == 0) {
+		printk(KERN_WARNING "ide-tape: Zero block size, using 512\n");
+		tape->tape_block_size = 512;
+	}
 	if (tape->onstream) {
 		idetape_onstream_mode_sense_tape_parameter_page(drive, 1);
 		idetape_configure_onstream(drive);
@@ -6480,11 +6461,7 @@
 	version:		IDETAPE_VERSION,
 	media:			ide_tape,
 	busy:			1,
-#ifdef CONFIG_IDEDMA_ONLYDISK
-	supports_dma:		0,
-#else
 	supports_dma:		1,
-#endif
 	supports_dsc_overlap: 	1,
 	cleanup:		idetape_cleanup,
 	standby:		NULL,
diff -urN linux-2.4.21-pre3/drivers/ide/pci/alim15x3.c linux-2.4.21-pre4/drivers/ide/pci/alim15x3.c
--- linux-2.4.21-pre3/drivers/ide/pci/alim15x3.c	Tue Jan 28 19:44:25 2003
+++ linux-2.4.21-pre4/drivers/ide/pci/alim15x3.c	Tue Jan 28 19:44:29 2003
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/ide/alim15x3.c		Version 0.15	2002/08/19
+ * linux/drivers/ide/alim15x3.c		Version 0.16	2003/01/02
  *
  *  Copyright (C) 1998-2000 Michel Aubry, Maintainer
  *  Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer
@@ -854,10 +854,8 @@
 	ide_pci_device_t *d = &ali15x3_chipsets[id->driver_data];
 	
 	if(pci_find_device(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_IGP, NULL))
-	{
-		printk(KERN_ERR "Warning: ATI Radeon IGP Northbridge is not supported by Linux\n");
-		return 1;
-	}
+		printk(KERN_ERR "Warning: ATI Radeon IGP Northbridge is not yet fully tested.\n");
+
 #if defined(CONFIG_SPARC64)
 	d->init_hwif = init_hwif_common_ali15x3;
 #endif /* CONFIG_SPARC64 */
diff -urN linux-2.4.21-pre3/drivers/ide/pci/generic.c linux-2.4.21-pre4/drivers/ide/pci/generic.c
--- linux-2.4.21-pre3/drivers/ide/pci/generic.c	Tue Jan 28 19:44:25 2003
+++ linux-2.4.21-pre4/drivers/ide/pci/generic.c	Tue Jan 28 19:44:29 2003
@@ -1,10 +1,26 @@
 /*
- *  linux/drivers/ide/generic.c		Version 0.10	Sept 11, 2002
+ *  linux/drivers/ide/generic.c		Version 0.11	December 30, 2002
  *
  *  Copyright (C) 2001-2002	Andre Hedrick <andre@linux-ide.org>
+ *  Portions (C) Copyright 2002  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 as published by the
+ * Free Software Foundation; either version 2, 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.
+ *
+ * For the avoidance of doubt the "preferred form" of this code is one which
+ * is in an open non patent encumbered format. Where cryptographic key signing
+ * forms part of the process of creating an executable the information
+ * including keys needed to generate an equivalently functional executable
+ * are deemed to be part of the source code.
  */
 
-
 #undef REALLY_SLOW_IO		/* most systems can safely undef this */
 
 #include <linux/config.h> /* for CONFIG_BLK_DEV_IDEPCI */
@@ -89,6 +105,7 @@
 static int __devinit generic_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
 	ide_pci_device_t *d = &generic_chipsets[id->driver_data];
+	u16 command;
 
 	if (dev->device != d->device)
 		BUG();
@@ -102,6 +119,12 @@
 	    (!(PCI_FUNC(dev->devfn) & 1)))
 		return 1;
 
+	pci_read_config_word(dev, PCI_COMMAND, &command);
+	if(!(command & PCI_COMMAND_IO))
+	{
+		printk(KERN_INFO "Skipping disabled %s IDE controller.\n", d->name);
+		return 1; 
+	}
 	ide_setup_pci_device(dev, d);
 	MOD_INC_USE_COUNT;
 	return 0;
diff -urN linux-2.4.21-pre3/drivers/ide/pci/nvidia.c linux-2.4.21-pre4/drivers/ide/pci/nvidia.c
--- linux-2.4.21-pre3/drivers/ide/pci/nvidia.c	Tue Jan 28 19:44:25 2003
+++ linux-2.4.21-pre4/drivers/ide/pci/nvidia.c	Tue Jan 28 19:44:29 2003
@@ -77,6 +77,7 @@
 
         switch(HWIF(drive)->pci_dev->device) {
 		case PCI_DEVICE_ID_NVIDIA_NFORCE_IDE:
+		case PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE:
 			mode = 3;
 			break;
 		default:
@@ -286,6 +287,7 @@
 
 	switch(dev->device) {
 		case PCI_DEVICE_ID_NVIDIA_NFORCE_IDE:
+		case PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE:
 			ata66 = (hwif->channel) ?
 				cable_80_pin[1] :
 				cable_80_pin[0];
@@ -341,6 +343,7 @@
 
 static struct pci_device_id nforce_pci_tbl[] __devinitdata = {
 	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
 	{ 0, },
 };
 
diff -urN linux-2.4.21-pre3/drivers/ide/pci/nvidia.h linux-2.4.21-pre4/drivers/ide/pci/nvidia.h
--- linux-2.4.21-pre3/drivers/ide/pci/nvidia.h	Tue Jan 28 19:44:25 2003
+++ linux-2.4.21-pre4/drivers/ide/pci/nvidia.h	Tue Jan 28 19:44:29 2003
@@ -43,6 +43,21 @@
 		enablebits:	{{0x50,0x01,0x01}, {0x50,0x02,0x02}},
 		bootable:	ON_BOARD,
 		extra:		0,
+	},
+
+	{
+		vendor:		PCI_VENDOR_ID_NVIDIA,
+		device:		PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE,
+		name:		"NFORCE2",
+		init_chipset:	init_chipset_nforce,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_nforce,
+		init_dma:	init_dma_nforce,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x50,0x01,0x01}, {0x50,0x02,0x02}},
+		bootable:	ON_BOARD,
+		extra:		0,
 	}
 };
 
diff -urN linux-2.4.21-pre3/drivers/ide/raid/Makefile linux-2.4.21-pre4/drivers/ide/raid/Makefile
--- linux-2.4.21-pre3/drivers/ide/raid/Makefile	Tue Jan 28 19:44:25 2003
+++ linux-2.4.21-pre4/drivers/ide/raid/Makefile	Tue Jan 28 19:44:29 2003
@@ -12,6 +12,7 @@
 obj-$(CONFIG_BLK_DEV_ATARAID)		+= ataraid.o
 obj-$(CONFIG_BLK_DEV_ATARAID_PDC)	+= pdcraid.o
 obj-$(CONFIG_BLK_DEV_ATARAID_HPT)	+= hptraid.o
+obj-$(CONFIG_BLK_DEV_ATARAID_SII)	+= silraid.o
 
 EXTRA_CFLAGS	:= -I../
 
diff -urN linux-2.4.21-pre3/drivers/ide/raid/silraid.c linux-2.4.21-pre4/drivers/ide/raid/silraid.c
--- linux-2.4.21-pre3/drivers/ide/raid/silraid.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/drivers/ide/raid/silraid.c	Tue Jan 28 19:44:29 2003
@@ -0,0 +1,487 @@
+/*
+   silraid.c  Copyright (C) 2002 Red Hat, Inc. All rights reserved.
+
+   The contents of this file are subject to the Open Software License version 1.1
+   that can be found at http://www.opensource.org/licenses/osl-1.1.txt and is 
+   included herein by reference. 
+   
+   Alternatively, the contents of this file may be used under the
+   terms of the GNU General Public License version 2 (the "GPL") as 
+   distributed in the kernel source COPYING file, in which
+   case the provisions of the GPL are applicable instead of the
+   above.  If you wish to allow the use of your version of this file
+   only under the terms of the GPL and not to allow others to use
+   your version of this file under the OSL, indicate your decision
+   by deleting the provisions above and replace them with the notice
+   and other provisions required by the GPL.  If you do not delete
+   the provisions above, a recipient may use your version of this
+   file under either the OSL or the GPL.
+   
+   Authors: 	Arjan van de Ven <arjanv@redhat.com>
+   		
+
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/blkdev.h>
+#include <linux/blkpg.h>
+#include <linux/genhd.h>
+#include <linux/ioctl.h>
+
+#include <linux/ide.h>
+#include <asm/uaccess.h>
+
+#include "ataraid.h"
+
+static int silraid_open(struct inode * inode, struct file * filp);
+static int silraid_release(struct inode * inode, struct file * filp);
+static int silraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+static int silraid0_make_request (request_queue_t *q, int rw, struct buffer_head * bh);
+
+struct disk_dev {
+	int major;
+	int minor;
+	int device;
+};
+
+static struct disk_dev devlist[]= {
+	{IDE0_MAJOR,  0,  -1 },
+	{IDE0_MAJOR, 64,  -1 },
+	{IDE1_MAJOR,  0,  -1 },
+	{IDE1_MAJOR, 64,  -1 },
+	{IDE2_MAJOR,  0,  -1 },
+	{IDE2_MAJOR, 64,  -1 },
+	{IDE3_MAJOR,  0,  -1 },
+	{IDE3_MAJOR, 64,  -1 },
+	{IDE4_MAJOR,  0,  -1 },
+	{IDE4_MAJOR, 64,  -1 },
+	{IDE5_MAJOR,  0,  -1 },
+	{IDE5_MAJOR, 64,  -1 },
+	{IDE6_MAJOR,  0,  -1 },
+	{IDE6_MAJOR, 64,  -1 },
+};
+
+
+struct sildisk {
+	kdev_t	device;
+	unsigned long sectors;
+	struct block_device *bdev;
+	unsigned long last_pos;
+};
+
+struct silraid {
+	unsigned int stride;
+	unsigned int disks;
+	unsigned long sectors;
+	struct geom geom;
+	
+	struct sildisk disk[8];
+	
+	unsigned long cutoff[8];
+	unsigned int cutoff_disks[8];
+};
+
+static struct raid_device_operations silraid0_ops = {
+        open:                   silraid_open,
+	release:                silraid_release,
+	ioctl:			silraid_ioctl,
+	make_request:		silraid0_make_request
+};
+
+static struct silraid raid[16];
+
+
+static int silraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	unsigned int minor;
+   	unsigned long sectors;
+
+	if (!inode || !inode->i_rdev) 
+		return -EINVAL;
+
+	minor = MINOR(inode->i_rdev)>>SHIFT;
+	
+	switch (cmd) {
+
+         	case BLKGETSIZE:   /* Return device size */
+ 			if (!arg)  return -EINVAL;
+			sectors = ataraid_gendisk.part[MINOR(inode->i_rdev)].nr_sects;
+			if (MINOR(inode->i_rdev)&15)
+				return put_user(sectors, (unsigned long *) arg);
+			return put_user(raid[minor].sectors , (unsigned long *) arg);
+			break;
+			
+
+		case HDIO_GETGEO:
+		{
+			struct hd_geometry *loc = (struct hd_geometry *) arg;
+			unsigned short bios_cyl = raid[minor].geom.cylinders; /* truncate */
+			
+			if (!loc) return -EINVAL;
+			if (put_user(raid[minor].geom.heads, (byte *) &loc->heads)) return -EFAULT;
+			if (put_user(raid[minor].geom.sectors, (byte *) &loc->sectors)) return -EFAULT;
+			if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT;
+			if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
+				(unsigned long *) &loc->start)) return -EFAULT;
+			return 0;
+		}
+
+		case HDIO_GETGEO_BIG:
+		{
+			struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
+			if (!loc) return -EINVAL;
+			if (put_user(raid[minor].geom.heads, (byte *) &loc->heads)) return -EFAULT;
+			if (put_user(raid[minor].geom.sectors, (byte *) &loc->sectors)) return -EFAULT;
+			if (put_user(raid[minor].geom.cylinders, (unsigned int *) &loc->cylinders)) return -EFAULT;
+			if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
+				(unsigned long *) &loc->start)) return -EFAULT;
+			return 0;
+		}
+
+			
+		case BLKROSET:
+		case BLKROGET:
+		case BLKSSZGET:
+			return blk_ioctl(inode->i_rdev, cmd, arg);
+
+		default:
+			printk("Invalid ioctl \n");
+			return -EINVAL;
+	};
+
+	return 0;
+}
+
+
+unsigned long partition_map_normal(unsigned long block, unsigned long partition_off, unsigned long partition_size, int stride)
+{
+	return block + partition_off;
+}
+
+static int silraid0_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
+{
+	unsigned long rsect;
+	unsigned long rsect_left,rsect_accum = 0;
+	unsigned long block;
+	unsigned int disk=0,real_disk=0;
+	int i;
+	int device;
+	struct silraid *thisraid;
+
+	rsect = bh->b_rsector;
+	
+	/* Ok. We need to modify this sector number to a new disk + new sector number. 
+	 * If there are disks of different sizes, this gets tricky. 
+	 * Example with 3 disks (1Gb, 4Gb and 5 GB):
+	 * The first 3 Gb of the "RAID" are evenly spread over the 3 disks.
+	 * Then things get interesting. The next 2Gb (RAID view) are spread across disk 2 and 3
+	 * and the last 1Gb is disk 3 only.
+	 *
+	 * the way this is solved is like this: We have a list of "cutoff" points where everytime
+	 * a disk falls out of the "higher" count, we mark the max sector. So once we pass a cutoff
+	 * point, we have to divide by one less.
+	 */
+	
+	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
+	thisraid = &raid[device];
+	if (thisraid->stride==0)
+		thisraid->stride=1;
+
+	/* Partitions need adding of the start sector of the partition to the requested sector */
+	
+	rsect = partition_map_normal(rsect, ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect, ataraid_gendisk.part[MINOR(bh->b_rdev)].nr_sects, thisraid->stride);
+
+	/* Woops we need to split the request to avoid crossing a stride barrier */
+	if ((rsect/thisraid->stride) != ((rsect+(bh->b_size/512)-1)/thisraid->stride)) {
+		return -1;  
+	}
+	
+	rsect_left = rsect;
+	
+	for (i=0;i<8;i++) {
+		if (thisraid->cutoff_disks[i]==0)
+			break;
+		if (rsect > thisraid->cutoff[i]) {
+			/* we're in the wrong area so far */
+			rsect_left -= thisraid->cutoff[i];
+			rsect_accum += thisraid->cutoff[i]/thisraid->cutoff_disks[i];
+		} else {
+			block = rsect_left / thisraid->stride;
+			disk = block % thisraid->cutoff_disks[i];
+			block = (block / thisraid->cutoff_disks[i]) * thisraid->stride;
+			rsect = rsect_accum + (rsect_left % thisraid->stride) + block;
+			break;
+		}
+	}
+	
+	for (i=0;i<8;i++) {
+		if ((disk==0) && (thisraid->disk[i].sectors > rsect_accum)) {
+			real_disk = i;
+			break;
+		}
+		if ((disk>0) && (thisraid->disk[i].sectors >= rsect_accum)) {
+			disk--;
+		}
+		
+	}
+	disk = real_disk;
+		
+	
+	/*
+	 * The new BH_Lock semantics in ll_rw_blk.c guarantee that this
+	 * is the only IO operation happening on this bh.
+	 */
+	bh->b_rdev = thisraid->disk[disk].device;
+	bh->b_rsector = rsect;
+
+	/*
+	 * Let the main block layer submit the IO and resolve recursion:
+	 */
+	return 1;
+}
+
+#include "silraid.h"
+
+static unsigned long calc_silblock_offset (int major,int minor)
+{
+	unsigned long lba = 0, cylinders;
+	kdev_t dev;
+	ide_drive_t *ideinfo;
+	
+	dev = MKDEV(major,minor);
+	ideinfo = get_info_ptr (dev);
+	if (ideinfo==NULL)
+		return 0;
+	
+	
+	/* last sector second to last cylinder */
+	if (ideinfo->head==0) 
+		return 0;
+	if (ideinfo->sect==0)
+		return 0;
+	cylinders = (ideinfo->capacity / (ideinfo->head*ideinfo->sect));
+	lba = (cylinders - 1) * (ideinfo->head*ideinfo->sect);
+	lba = lba - ideinfo->head -1;
+	
+//	return 80417215;  
+	printk("Guestimating sector %li for superblock\n",lba);
+	return lba;
+
+}
+
+
+
+static int read_disk_sb (int major, int minor, unsigned char *buffer,int bufsize)
+{
+	int ret = -EINVAL;
+	struct buffer_head *bh = NULL;
+	kdev_t dev = MKDEV(major,minor);
+	unsigned long sb_offset;
+	
+	if (blksize_size[major]==NULL)   /* device doesn't exist */
+		return -EINVAL;
+                       
+
+	/*
+	 * Calculate the position of the superblock,
+	 * it's at first sector of the last cylinder
+	 */
+	sb_offset = calc_silblock_offset(major,minor)/8;
+	/* The /8 transforms sectors into 4Kb blocks */
+
+	if (sb_offset==0)
+		return -1;	
+	
+	set_blocksize (dev, 4096);
+
+	bh = bread (dev, sb_offset, 4096);
+	
+	if (bh) {
+		memcpy (buffer, bh->b_data, bufsize);
+	} else {
+		printk(KERN_ERR "silraid: Error reading superblock.\n");
+		goto abort;
+	}
+	ret = 0;
+abort:
+	if (bh)
+		brelse (bh); return ret;
+}
+
+static unsigned short checksum1(unsigned short *buffer)
+{
+	int i;
+	int sum = 0;
+	for (i=0; i<0x13f/2; i++)
+		sum += buffer[i];	
+	return (-sum)&0xFFFF;
+}
+
+static int cookie = 0;
+
+static void __init probedisk(int devindex,int device, int raidlevel)
+{
+	int i;
+	int major, minor;
+        struct signature *superblock;
+	static unsigned char block[4096];
+	struct block_device *bdev;
+
+	if (devlist[devindex].device!=-1) /* already assigned to another array */
+		return;
+	
+	major = devlist[devindex].major;
+	minor = devlist[devindex].minor; 
+
+        if (read_disk_sb(major,minor,(unsigned char*)&block,sizeof(block)))
+        	return;
+                                                                                                                 
+        superblock = (struct signature*)&block[4096-512];
+        
+        if (superblock->unknown[0] != 'Z') /* Need better check here */
+        	return;
+        	
+        if (superblock->checksum1 != checksum1((unsigned short*)superblock))
+        	return;  
+        
+        
+
+	if (superblock->raidlevel!=raidlevel) /* different raidlevel */
+		return;
+
+	/* This looks evil. But basically, we have to search for our adapternumber
+	   in the arraydefinition, both of which are in the superblock */	
+	 i = superblock->disk_in_set;
+
+	bdev = bdget(MKDEV(major,minor));
+        if (bdev && blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_RAW) == 0) {
+		raid[device].disk[i].bdev = bdev;
+	}
+	raid[device].disk[i].device = MKDEV(major,minor);
+	raid[device].disk[i].sectors = superblock->thisdisk_sectors; 
+	raid[device].stride = superblock->raid0_sectors_per_stride;
+	raid[device].disks = superblock->disks_in_set;
+	raid[device].sectors = superblock->array_sectors;
+	raid[device].geom.heads = 255;
+	raid[device].geom.sectors = 63;
+	raid[device].geom.cylinders =  raid[device].sectors / raid[device].geom.heads / raid[device].geom.sectors; 
+	
+	devlist[devindex].device=device;
+	               
+}
+
+static void __init fill_cutoff(int device)
+{
+	int i,j;
+	unsigned long smallest;
+	unsigned long bar;
+	int count;
+	
+	bar = 0;
+	for (i=0;i<8;i++) {
+		smallest = ~0;
+		for (j=0;j<8;j++) 
+			if ((raid[device].disk[j].sectors < smallest) && (raid[device].disk[j].sectors>bar))
+				smallest = raid[device].disk[j].sectors;
+		count = 0;
+		for (j=0;j<8;j++) 
+			if (raid[device].disk[j].sectors >= smallest)
+				count++;
+				
+		smallest = smallest * count;
+		bar = smallest;
+		raid[device].cutoff[i] = smallest;
+		raid[device].cutoff_disks[i] = count;
+	}
+}
+			   
+static __init int silraid_init_one(int device,int raidlevel)
+{
+	int i, count;
+
+	for (i=0; i<14; i++) 
+		probedisk(i, device, raidlevel);
+	
+	if (raidlevel==0)
+		fill_cutoff(device);
+	
+	/* Initialize the gendisk structure */
+	
+	ataraid_register_disk(device,raid[device].sectors);        
+		
+	count=0;
+	
+	for (i=0;i<8;i++) {
+		if (raid[device].disk[i].device!=0) {
+			printk(KERN_INFO "Drive %i is %li Mb (%i / %i) \n",
+				i,raid[device].disk[i].sectors/2048,MAJOR(raid[device].disk[i].device),MINOR(raid[device].disk[i].device));
+			count++;
+		}
+	}
+	if (count) {
+		printk(KERN_INFO "Raid%i array consists of %i drives. \n",raidlevel,count);
+		return 0;
+	} else {
+		return -ENODEV;
+	}
+}
+
+static __init int silraid_init(void)
+{
+	int retval, device, count = 0;
+
+	do {
+		cookie = 0;
+		device=ataraid_get_device(&silraid0_ops);
+		if (device<0)
+			break;
+		retval = silraid_init_one(device,0);
+		if (retval) {
+			ataraid_release_device(device);
+			break;
+		} else {
+			count++;
+		}
+	} while (1);
+
+	if (count) {
+		printk(KERN_INFO "driver for Silicon Image(tm) Medley(tm) hardware version 0.0.1\n");
+		return 0;
+	}
+	printk(KERN_DEBUG "driver for Silicon Image(tm) Medley(tm) hardware version 0.0.1: No raid array found\n");
+	return -ENODEV;
+}
+
+static void __exit silraid_exit (void)
+{
+	int i,device;
+	for (device = 0; device<16; device++) {
+		for (i=0;i<8;i++) {
+			struct block_device *bdev = raid[device].disk[i].bdev;
+			raid[device].disk[i].bdev = NULL;
+			if (bdev)
+				blkdev_put(bdev, BDEV_RAW);
+		}	
+		if (raid[device].sectors)
+			ataraid_release_device(device);
+	}
+}
+
+static int silraid_open(struct inode * inode, struct file * filp) 
+{
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+static int silraid_release(struct inode * inode, struct file * filp)
+{	
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+module_init(silraid_init);
+module_exit(silraid_exit);
+MODULE_LICENSE("GPL and additional rights");
diff -urN linux-2.4.21-pre3/drivers/ide/raid/silraid.h linux-2.4.21-pre4/drivers/ide/raid/silraid.h
--- linux-2.4.21-pre3/drivers/ide/raid/silraid.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/drivers/ide/raid/silraid.h	Tue Jan 28 19:44:29 2003
@@ -0,0 +1,30 @@
+struct signature {
+	char unknown[0x36];  		/* 0x00 to 0x35 */
+	char diskname[32];	     	/* 0x36 to 0x56 */
+	char unknown2[0x6c-86];		/* 0x57 to 0x6B */	
+	unsigned int array_sectors;	/* 0x6C to 0x6F */
+	char unknown2b[8];		/* 0x70 to 0x77 */
+	unsigned int thisdisk_sectors;	/* 0x78 to 0x7B */
+	char unknown2c[0xFF-0x7B];	/* 0x7C to 0xFF */
+	char unknown3[4];		/* 0x100 to 0x103 */
+	unsigned short PCI_DEV_ID;	/* 0x104 and 0x105 */
+	unsigned short PCI_VEND_ID;	/* 0x106 and 0x107 */
+	char unknown4[4];		/* 0x108 to 0x10B */
+	unsigned char seconds;		/* 0x10C */
+	unsigned char minutes;		/* 0x10D */
+	unsigned char hour;		/* 0x10E */
+	unsigned char day;		/* 0x10F */
+	unsigned char month;		/* 0x110 */
+	unsigned char year;		/* 0x111 */
+	unsigned short raid0_sectors_per_stride; /* 0x112 */
+	char unknown6[2];		/* 0x113 - 0x115 */
+	unsigned char disk_in_set;	/* 0x116 */
+	unsigned char raidlevel;	/* 0x117 */
+	unsigned char disks_in_set;	/* 0x118 */
+	char unknown7[0x12a - 0x118];   /* 0x118 - 0x12a */
+	unsigned char idechannel;	/* 0x12b */
+	char unknown8[0x13D-0x12B];	/* 0x12c - 0x13d */
+	unsigned short checksum1;	/* 0x13e and 0x13f */	
+	char assumed_zeros[509-0x13f];
+	unsigned short checksum2;	/* 0x1FE and 0x1FF */
+} __attribute__((packed));
diff -urN linux-2.4.21-pre3/drivers/input/evdev.c linux-2.4.21-pre4/drivers/input/evdev.c
--- linux-2.4.21-pre3/drivers/input/evdev.c	Mon Feb 25 11:37:58 2002
+++ linux-2.4.21-pre4/drivers/input/evdev.c	Tue Jan 28 19:44:30 2003
@@ -223,6 +223,9 @@
 	struct input_dev *dev = evdev->handle.dev;
 	int retval;
 
+	if (!evdev->exist)
+		return -ENODEV;
+
 	switch (cmd) {
 
 		case EVIOCGVERSION:
diff -urN linux-2.4.21-pre3/drivers/input/joydev.c linux-2.4.21-pre4/drivers/input/joydev.c
--- linux-2.4.21-pre3/drivers/input/joydev.c	Tue Jan 28 19:44:25 2003
+++ linux-2.4.21-pre4/drivers/input/joydev.c	Tue Jan 28 19:44:30 2003
@@ -231,6 +231,9 @@
 
 	if (count < sizeof(struct js_event))
 		return -EINVAL;
+	
+	if (!joydev->exist)
+		return -ENODEV;
 
 	if (count == sizeof(struct JS_DATA_TYPE)) {
 
@@ -258,6 +261,10 @@
 
 		while (list->head == list->tail) {
 
+			if (!joydev->exist) {
+                                retval = -ENODEV;
+                                break;
+                        }
 			if (file->f_flags & O_NONBLOCK) {
 				retval = -EAGAIN;
 				break;
@@ -329,6 +336,9 @@
 	struct input_dev *dev = joydev->handle.dev;
 	int i;
 
+	if (!joydev->exist)
+		return -ENODEV;
+
 	switch (cmd) {
 
 		case JS_SET_CAL:
@@ -367,7 +377,7 @@
 		case JSIOCSAXMAP:
 			if (copy_from_user(joydev->abspam, (__u8 *) arg, sizeof(__u8) * ABS_MAX))
 				return -EFAULT;
-			for (i = 0; i < ABS_MAX; i++) {
+			for (i = 0; i < joydev->nabs; i++) {
 				if (joydev->abspam[i] > ABS_MAX) return -EINVAL;
 				joydev->absmap[joydev->abspam[i]] = i;
 			}
@@ -376,11 +386,11 @@
 			return copy_to_user((__u8 *) arg, joydev->abspam,
 						sizeof(__u8) * ABS_MAX) ? -EFAULT : 0;
 		case JSIOCSBTNMAP:
-			if (copy_from_user(joydev->absmap, (__u16 *) arg, sizeof(__u16) * (KEY_MAX - BTN_MISC)))
+			if (copy_from_user(joydev->keypam, (__u16 *) arg, sizeof(__u16) * (KEY_MAX - BTN_MISC)))
 				return -EFAULT;
-			for (i = 0; i < KEY_MAX - BTN_MISC; i++); {
+			for (i = 0; i < joydev->nkey; i++); {
 				if (joydev->keypam[i] > KEY_MAX || joydev->keypam[i] < BTN_MISC) return -EINVAL;
-				joydev->keymap[joydev->abspam[i - BTN_MISC]] = i;
+				joydev->keymap[joydev->keypam[i] - BTN_MISC] = i;
 			}
 			return 0;
 		case JSIOCGBTNMAP:
diff -urN linux-2.4.21-pre3/drivers/isdn/Config.in linux-2.4.21-pre4/drivers/isdn/Config.in
--- linux-2.4.21-pre3/drivers/isdn/Config.in	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre4/drivers/isdn/Config.in	Tue Jan 28 19:44:30 2003
@@ -87,8 +87,9 @@
    dep_tristate 'Sedlbauer PCMCIA cards'                              CONFIG_HISAX_SEDLBAUER_CS  $CONFIG_ISDN_DRV_HISAX $CONFIG_PCMCIA
    dep_tristate 'ELSA PCMCIA MicroLink cards'                         CONFIG_HISAX_ELSA_CS       $CONFIG_ISDN_DRV_HISAX $CONFIG_PCMCIA
    dep_tristate 'AVM A1 PCMCIA cards'                                 CONFIG_HISAX_AVM_A1_CS     $CONFIG_ISDN_DRV_HISAX $CONFIG_PCMCIA $CONFIG_HISAX_AVM_A1_PCMCIA
-   dep_tristate 'ST5481 USB ISDN modem (EXPERIMENTAL)'                CONFIG_HISAX_ST5481        $CONFIG_ISDN_DRV_HISAX $CONFIG_USB    $CONFIG_EXPERIMENTAL
+   dep_tristate 'ST5481 USB ISDN modem (EXPERIMENTAL)'                CONFIG_HISAX_ST5481        $CONFIG_ISDN_DRV_HISAX    $CONFIG_EXPERIMENTAL
    dep_tristate 'AVM Fritz!Card PCI/PCIv2/PnP support (EXPERIMENTAL)' CONFIG_HISAX_FRITZ_PCIPNP  $CONFIG_ISDN_DRV_HISAX                $CONFIG_EXPERIMENTAL
+   dep_tristate 'Auerswald devices ISDN support'                      CONFIG_USB_AUERISDN        $CONFIG_ISDN_DRV_HISAX
 
 fi
 endmenu
diff -urN linux-2.4.21-pre3/drivers/isdn/avmb1/capidrv.c linux-2.4.21-pre4/drivers/isdn/avmb1/capidrv.c
--- linux-2.4.21-pre3/drivers/isdn/avmb1/capidrv.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.21-pre4/drivers/isdn/avmb1/capidrv.c	Tue Jan 28 19:44:30 2003
@@ -105,6 +105,7 @@
 				int oldstate;
 				/* */
 				__u16 datahandle;
+                                spinlock_t lock;
 				struct ncci_datahandle_queue {
 				    struct ncci_datahandle_queue *next;
 				    __u16                         datahandle;
@@ -422,6 +423,7 @@
 	nccip->plcip = plcip;
 	nccip->chan = plcip->chan;
 	nccip->datahandle = 0;
+        nccip->lock = SPIN_LOCK_UNLOCKED;
 
 	nccip->next = plcip->ncci_list;
 	plcip->ncci_list = nccip;
@@ -478,6 +480,7 @@
 		           __u16 datahandle, int len)
 {
 	struct ncci_datahandle_queue *n, **pp;
+	unsigned long flags;
 
 	n = (struct ncci_datahandle_queue *)
 		kmalloc(sizeof(struct ncci_datahandle_queue), GFP_ATOMIC);
@@ -488,25 +491,31 @@
 	n->next = 0;
 	n->datahandle = datahandle;
 	n->len = len;
+	spin_lock_irqsave(&nccip->lock, flags);
 	for (pp = &nccip->ackqueue; *pp; pp = &(*pp)->next) ;
 	*pp = n;
+	spin_unlock_irqrestore(&nccip->lock, flags);
 	return 0;
 }
 
 static int capidrv_del_ack(struct capidrv_ncci *nccip, __u16 datahandle)
 {
 	struct ncci_datahandle_queue **pp, *p;
+	unsigned long flags;
 	int len;
 
+	spin_lock_irqsave(&nccip->lock, flags);
 	for (pp = &nccip->ackqueue; *pp; pp = &(*pp)->next) {
  		if ((*pp)->datahandle == datahandle) {
 			p = *pp;
 			len = p->len;
 			*pp = (*pp)->next;
+	                spin_unlock_irqrestore(&nccip->lock, flags);
 		        kfree(p);
 			return len;
 		}
 	}
+        spin_unlock_irqrestore(&nccip->lock, flags);
 	return -1;
 }
 
diff -urN linux-2.4.21-pre3/drivers/isdn/avmb1/kcapi.c linux-2.4.21-pre4/drivers/isdn/avmb1/kcapi.c
--- linux-2.4.21-pre3/drivers/isdn/avmb1/kcapi.c	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre4/drivers/isdn/avmb1/kcapi.c	Tue Jan 28 19:44:30 2003
@@ -64,6 +64,7 @@
 	__u32 ncci;
 	__u32 winsize;
 	int   nmsg;
+        spinlock_t lock;
 	struct msgidqueue *msgidqueue;
 	struct msgidqueue *msgidlast;
 	struct msgidqueue *msgidfree;
@@ -640,6 +641,7 @@
 static inline void mq_init(struct capi_ncci * np)
 {
 	int i;
+        np->lock = SPIN_LOCK_UNLOCKED;
 	np->msgidqueue = 0;
 	np->msgidlast = 0;
 	np->nmsg = 0;
@@ -654,8 +656,11 @@
 static inline int mq_enqueue(struct capi_ncci * np, __u16 msgid)
 {
 	struct msgidqueue *mq;
-	if ((mq = np->msgidfree) == 0)
+	spin_lock_bh(&np->lock);
+	if ((mq = np->msgidfree) == 0) {
+	        spin_unlock_bh(&np->lock);
 		return 0;
+	}
 	np->msgidfree = mq->next;
 	mq->msgid = msgid;
 	mq->next = 0;
@@ -665,12 +670,14 @@
 	if (!np->msgidqueue)
 		np->msgidqueue = mq;
 	np->nmsg++;
+	spin_unlock_bh(&np->lock);
 	return 1;
 }
 
 static inline int mq_dequeue(struct capi_ncci * np, __u16 msgid)
 {
 	struct msgidqueue **pp;
+	spin_lock_bh(&np->lock);
 	for (pp = &np->msgidqueue; *pp; pp = &(*pp)->next) {
 		if ((*pp)->msgid == msgid) {
 			struct msgidqueue *mq = *pp;
@@ -680,9 +687,11 @@
 			mq->next = np->msgidfree;
 			np->msgidfree = mq;
 			np->nmsg--;
+	                spin_unlock_bh(&np->lock);
 			return 1;
 		}
 	}
+	spin_unlock_bh(&np->lock);
 	return 0;
 }
 
diff -urN linux-2.4.21-pre3/drivers/isdn/hisax/Makefile linux-2.4.21-pre4/drivers/isdn/hisax/Makefile
--- linux-2.4.21-pre3/drivers/isdn/hisax/Makefile	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre4/drivers/isdn/hisax/Makefile	Tue Jan 28 19:44:30 2003
@@ -10,15 +10,14 @@
 
 # Objects that export symbols.
 
-export-objs	  := config.o hisax_isac.o
+export-objs	  := config.o hisax_isac.o isdnhdlc.o
 
 # Multipart objects.
 
 list-multi	  := hisax.o hisax_st5481.o
 hisax-objs	  := config.o isdnl1.o tei.o isdnl2.o isdnl3.o \
 		     lmgr.o q931.o callc.o fsm.o cert.o
-hisax_st5481-objs := st5481_init.o st5481_usb.o st5481_d.o st5481_b.o \
-		     st5481_hdlc.o
+hisax_st5481-objs := st5481_init.o st5481_usb.o st5481_d.o st5481_b.o
 
 # Optional parts of multipart objects.
 hisax-objs-$(CONFIG_HISAX_EURO) += l3dss1.o
@@ -63,8 +62,9 @@
 obj-$(CONFIG_HISAX_SEDLBAUER_CS)	+= sedlbauer_cs.o
 obj-$(CONFIG_HISAX_ELSA_CS)		+= elsa_cs.o
 obj-$(CONFIG_HISAX_AVM_A1_CS)		+= avma1_cs.o
-obj-$(CONFIG_HISAX_ST5481)		+= hisax_st5481.o
+obj-$(CONFIG_HISAX_ST5481)		+= hisax_st5481.o isdnhdlc.o
 obj-$(CONFIG_HISAX_FRITZ_PCIPNP)        += hisax_isac.o hisax_fcpcipnp.o
+obj-$(CONFIG_USB_AUERISDN)	        += isdnhdlc.o
 
 CERT := $(shell md5sum -c md5sums.asc >> /dev/null;echo $$?)
 CFLAGS_cert.o := -DCERTIFICATION=$(CERT)
diff -urN linux-2.4.21-pre3/drivers/isdn/hisax/amd7930.c linux-2.4.21-pre4/drivers/isdn/hisax/amd7930.c
--- linux-2.4.21-pre3/drivers/isdn/hisax/amd7930.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.21-pre4/drivers/isdn/hisax/amd7930.c	Wed Dec 31 16:00:00 1969
@@ -1,755 +0,0 @@
-/* $Id: amd7930.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
- *
- * HiSax ISDN driver - chip specific routines for AMD 7930
- *
- * Author       Brent Baccala
- * Copyright    by Brent Baccala <baccala@FreeSoft.org>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- *    - Existing ISDN HiSax driver provides all the smarts
- *    - it compiles, runs, talks to an isolated phone switch, connects
- *      to a Cisco, pings go through
- *    - AMD 7930 support only (no DBRI yet)
- *    - no US NI-1 support (may not work on US phone system - untested)
- *    - periodic packet loss, apparently due to lost interrupts
- *    - ISDN sometimes freezes, requiring reboot before it will work again
- *
- * The code is unreliable enough to be consider alpha
- *
- * This file is (c) under GNU General Public License
- *
- * Advanced Micro Devices' Am79C30A is an ISDN/audio chip used in the
- * SparcStation 1+.  The chip provides microphone and speaker interfaces
- * which provide mono-channel audio at 8K samples per second via either
- * 8-bit A-law or 8-bit mu-law encoding.  Also, the chip features an
- * ISDN BRI Line Interface Unit (LIU), I.430 S/T physical interface,
- * which performs basic D channel LAPD processing and provides raw
- * B channel data.  The digital audio channel, the two ISDN B channels,
- * and two 64 Kbps channels to the microprocessor are all interconnected
- * via a multiplexer.
- *
- * This driver interfaces to the Linux HiSax ISDN driver, which performs
- * all high-level Q.921 and Q.931 ISDN functions.  The file is not
- * itself a hardware driver; rather it uses functions exported by
- * the AMD7930 driver in the sparcaudio subsystem (drivers/sbus/audio),
- * allowing the chip to be simultaneously used for both audio and ISDN data.
- * The hardware driver does _no_ buffering, but provides several callbacks
- * which are called during interrupt service and should therefore run quickly.
- *
- * D channel transmission is performed by passing the hardware driver the
- * address and size of an skb's data area, then waiting for a callback
- * to signal successful transmission of the packet.  A task is then
- * queued to notify the HiSax driver that another packet may be transmitted.
- *
- * D channel reception is quite simple, mainly because of:
- *   1) the slow speed of the D channel - 16 kbps, and
- *   2) the presence of an 8- or 32-byte (depending on chip version) FIFO
- *      to buffer the D channel data on the chip
- * Worst case scenario of back-to-back packets with the 8 byte buffer
- * at 16 kbps yields an service time of 4 ms - long enough to preclude
- * the need for fancy buffering.  We queue a background task that copies
- * data out of the receive buffer into an skb, and the hardware driver
- * simply does nothing until we're done with the receive buffer and
- * reset it for a new packet.
- *
- * B channel processing is more complex, because of:
- *   1) the faster speed - 64 kbps,
- *   2) the lack of any on-chip buffering (it interrupts for every byte), and
- *   3) the lack of any chip support for HDLC encapsulation
- *
- * The HiSax driver can put each B channel into one of three modes -
- * L1_MODE_NULL (channel disabled), L1_MODE_TRANS (transparent data relay),
- * and L1_MODE_HDLC (HDLC encapsulation by low-level driver).
- * L1_MODE_HDLC is the most common, used for almost all "pure" digital
- * data sessions.  L1_MODE_TRANS is used for ISDN audio.
- *
- * HDLC B channel transmission is performed via a large buffer into
- * which the skb is copied while performing HDLC bit-stuffing.  A CRC
- * is computed and attached to the end of the buffer, which is then
- * passed to the low-level routines for raw transmission.  Once
- * transmission is complete, the hardware driver is set to enter HDLC
- * idle by successive transmission of mark (all 1) bytes, waiting for
- * the ISDN driver to prepare another packet for transmission and
- * deliver it.
- *
- * HDLC B channel reception is performed via an X-byte ring buffer
- * divided into N sections of X/N bytes each.  Defaults: X=256 bytes, N=4.
- * As the hardware driver notifies us that each section is full, we
- * hand it the next section and schedule a background task to peruse
- * the received section, bit-by-bit, with an HDLC decoder.  As
- * packets are detected, they are copied into a large buffer while
- * decoding HDLC bit-stuffing.  The ending CRC is verified, and if
- * it is correct, we alloc a new skb of the correct length (which we
- * now know), copy the packet into it, and hand it to the upper layers.
- * Optimization: for large packets, we hand the buffer (which also
- * happens to be an skb) directly to the upper layer after an skb_trim,
- * and alloc a new large buffer for future packets, thus avoiding a copy.
- * Then we return to HDLC processing; state is saved between calls.
- * 
- */
-
-#define __NO_VERSION__
-#include "hisax.h"
-#include "../../sbus/audio/amd7930.h"
-#include "isac.h"
-#include "isdnl1.h"
-#include "rawhdlc.h"
-#include <linux/interrupt.h>
-
-static const char *amd7930_revision = "$Revision: 1.1.4.1 $";
-
-#define RCV_BUFSIZE	1024	/* Size of raw receive buffer in bytes */
-#define RCV_BUFBLKS	4	/* Number of blocks to divide buffer into
-				 * (must divide RCV_BUFSIZE) */
-
-static void Bchan_fill_fifo(struct BCState *, struct sk_buff *);
-
-static void
-Bchan_xmt_bh(struct BCState *bcs)
-{
-	struct sk_buff *skb;
-
-	if (bcs->hw.amd7930.tx_skb != NULL) {
-		dev_kfree_skb(bcs->hw.amd7930.tx_skb);
-		bcs->hw.amd7930.tx_skb = NULL;
-	}
-
-	if ((skb = skb_dequeue(&bcs->squeue))) {
-		Bchan_fill_fifo(bcs, skb);
-	} else {
-		clear_bit(BC_FLG_BUSY, &bcs->Flag);
-		bcs->event |= 1 << B_XMTBUFREADY;
-		queue_task(&bcs->tqueue, &tq_immediate);
-		mark_bh(IMMEDIATE_BH);
-	}
-}
-
-static void
-Bchan_xmit_callback(struct BCState *bcs)
-{
-	queue_task(&bcs->hw.amd7930.tq_xmt, &tq_immediate);
-	mark_bh(IMMEDIATE_BH);
-}
-
-/* B channel transmission: two modes (three, if you count L1_MODE_NULL)
- *
- * L1_MODE_HDLC - We need to do HDLC encapsulation before transmiting
- * the packet (i.e. make_raw_hdlc_data).  Since this can be a
- * time-consuming operation, our completion callback just schedules
- * a bottom half to do encapsulation for the next packet.  In between,
- * the link will just idle
- *
- * L1_MODE_TRANS - Data goes through, well, transparent.  No HDLC encap,
- * and we can't just let the link idle, so the "bottom half" actually
- * gets called during the top half (it's our callback routine in this case),
- * but it's a lot faster now since we don't call make_raw_hdlc_data
- */
-
-static void
-Bchan_fill_fifo(struct BCState *bcs, struct sk_buff *skb)
-{
-	struct IsdnCardState *cs = bcs->cs;
-	int len;
-
-	if ((cs->debug & L1_DEB_HSCX) || (cs->debug & L1_DEB_HSCX_FIFO)) {
-		char tmp[1024];
-		char *t = tmp;
-
-		t += sprintf(t, "amd7930_fill_fifo %c cnt %d",
-			     bcs->channel ? 'B' : 'A', skb->len);
-		if (cs->debug & L1_DEB_HSCX_FIFO)
-			QuickHex(t, skb->data, skb->len);
-		debugl1(cs, tmp);
-	}
-
-	if (bcs->mode == L1_MODE_HDLC) {
-		len = make_raw_hdlc_data(skb->data, skb->len,
-					 bcs->hw.amd7930.tx_buff, RAW_BUFMAX);
-		if (len > 0)
-			amd7930_bxmit(0, bcs->channel,
-				      bcs->hw.amd7930.tx_buff, len,
-				      (void *) &Bchan_xmit_callback,
-				      (void *) bcs);
-		dev_kfree_skb(skb);
-	} else if (bcs->mode == L1_MODE_TRANS) {
-		amd7930_bxmit(0, bcs->channel,
-			      bcs->hw.amd7930.tx_buff, skb->len,
-			      (void *) &Bchan_xmt_bh,
-			      (void *) bcs);
-		bcs->hw.amd7930.tx_skb = skb;
-	} else {
-		dev_kfree_skb(skb);
-	}
-}
-
-static void
-Bchan_mode(struct BCState *bcs, int mode, int bc)
-{
-	struct IsdnCardState *cs = bcs->cs;
-
-	if (cs->debug & L1_DEB_HSCX) {
-		char tmp[40];
-		sprintf(tmp, "AMD 7930 mode %d bchan %d/%d",
-			mode, bc, bcs->channel);
-		debugl1(cs, tmp);
-	}
-	bcs->mode = mode;
-}
-
-/* Bchan_l2l1 is the entry point for upper layer routines that want to
- * transmit on the B channel.  PH_DATA_REQ is a normal packet that
- * we either start transmitting (if idle) or queue (if busy).
- * PH_PULL_REQ can be called to request a callback message (PH_PULL_CNF)
- * once the link is idle.  After a "pull" callback, the upper layer
- * routines can use PH_PULL_IND to send data.
- */
-
-static void
-Bchan_l2l1(struct PStack *st, int pr, void *arg)
-{
-	struct sk_buff *skb = arg;
-
-	switch (pr) {
-		case (PH_DATA_REQ):
-			if (test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag)) {
-				skb_queue_tail(&st->l1.bcs->squeue, skb);
-			} else {
-				test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
-				Bchan_fill_fifo(st->l1.bcs, skb);
-			}
-			break;
-		case (PH_PULL_IND):
-			if (test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag)) {
-				printk(KERN_WARNING "amd7930: this shouldn't happen\n");
-				break;
-			}
-			test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
-			Bchan_fill_fifo(st->l1.bcs, skb);
-			break;
-		case (PH_PULL_REQ):
-			if (!test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag)) {
-				clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
-				st->l1.l1l2(st, PH_PULL_CNF, NULL);
-			} else
-				set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
-			break;
-	}
-}
-
-/* Receiver callback and bottom half - decodes HDLC at leisure (if
- * L1_MODE_HDLC) and passes newly received skb on via bcs->rqueue.  If
- * a large packet is received, stick rv_skb (the buffer that the
- * packet has been decoded into) on the receive queue and alloc a new
- * (large) skb to act as buffer for future receives.  If a small
- * packet is received, leave rv_skb alone, alloc a new skb of the
- * correct size, and copy the packet into it
- */
-
-static void
-Bchan_recv_callback(struct BCState *bcs)
-{
-	struct amd7930_hw *hw = &bcs->hw.amd7930;
-
-	hw->rv_buff_in += RCV_BUFSIZE/RCV_BUFBLKS;
-	hw->rv_buff_in %= RCV_BUFSIZE;
-
-	if (hw->rv_buff_in != hw->rv_buff_out) {
-		amd7930_brecv(0, bcs->channel,
-			      hw->rv_buff + hw->rv_buff_in,
-			      RCV_BUFSIZE/RCV_BUFBLKS,
-			      (void *) &Bchan_recv_callback, (void *) bcs);
-	}
-
-	queue_task(&hw->tq_rcv, &tq_immediate);
-	mark_bh(IMMEDIATE_BH);
-}
-
-static void
-Bchan_rcv_bh(struct BCState *bcs)
-{
-	struct IsdnCardState *cs = bcs->cs;
-	struct amd7930_hw *hw = &bcs->hw.amd7930;
-	struct sk_buff *skb;
-	int len;
-
-	if (cs->debug & L1_DEB_HSCX) {
-		char tmp[1024];
-
-		sprintf(tmp, "amd7930_Bchan_rcv (%d/%d)",
-			hw->rv_buff_in, hw->rv_buff_out);
-		debugl1(cs, tmp);
-		QuickHex(tmp, hw->rv_buff + hw->rv_buff_out,
-			 RCV_BUFSIZE/RCV_BUFBLKS);
-		debugl1(cs, tmp);
-	}
-
-	do {
-		if (bcs->mode == L1_MODE_HDLC) {
-			while ((len = read_raw_hdlc_data(hw->hdlc_state,
-							 hw->rv_buff + hw->rv_buff_out, RCV_BUFSIZE/RCV_BUFBLKS,
-							 hw->rv_skb->tail, HSCX_BUFMAX))) {
-				if (len > 0 && (cs->debug & L1_DEB_HSCX_FIFO)) {
-					char tmp[1024];
-					char *t = tmp;
-
-					t += sprintf(t, "amd7930_Bchan_rcv %c cnt %d", bcs->channel ? 'B' : 'A', len);
-					QuickHex(t, hw->rv_skb->tail, len);
-					debugl1(cs, tmp);
-				}
-
-				if (len > HSCX_BUFMAX/2) {
-					/* Large packet received */
-
-					if (!(skb = dev_alloc_skb(HSCX_BUFMAX))) {
-						printk(KERN_WARNING "amd7930: receive out of memory");
-					} else {
-						skb_put(hw->rv_skb, len);
-						skb_queue_tail(&bcs->rqueue, hw->rv_skb);
-						hw->rv_skb = skb;
-						bcs->event |= 1 << B_RCVBUFREADY;
-						queue_task(&bcs->tqueue, &tq_immediate);
-					}
-				} else if (len > 0) {
-					/* Small packet received */
-
-					if (!(skb = dev_alloc_skb(len))) {
-						printk(KERN_WARNING "amd7930: receive out of memory\n");
-					} else {
-						memcpy(skb_put(skb, len), hw->rv_skb->tail, len);
-						skb_queue_tail(&bcs->rqueue, skb);
-						bcs->event |= 1 << B_RCVBUFREADY;
-						queue_task(&bcs->tqueue, &tq_immediate);
-						mark_bh(IMMEDIATE_BH);
-					}
-				} else {
-					/* Reception Error */
-					/* printk("amd7930: B channel receive error\n"); */
-				}
-			}
-		} else if (bcs->mode == L1_MODE_TRANS) {
-			if (!(skb = dev_alloc_skb(RCV_BUFSIZE/RCV_BUFBLKS))) {
-				printk(KERN_WARNING "amd7930: receive out of memory\n");
-			} else {
-				memcpy(skb_put(skb, RCV_BUFSIZE/RCV_BUFBLKS),
-				       hw->rv_buff + hw->rv_buff_out,
-				       RCV_BUFSIZE/RCV_BUFBLKS);
-				skb_queue_tail(&bcs->rqueue, skb);
-				bcs->event |= 1 << B_RCVBUFREADY;
-				queue_task(&bcs->tqueue, &tq_immediate);
-				mark_bh(IMMEDIATE_BH);
-			}
-		}
-
-		if (hw->rv_buff_in == hw->rv_buff_out) {
-			/* Buffer was filled up - need to restart receiver */
-			amd7930_brecv(0, bcs->channel,
-				      hw->rv_buff + hw->rv_buff_in,
-				      RCV_BUFSIZE/RCV_BUFBLKS,
-				      (void *) &Bchan_recv_callback,
-				      (void *) bcs);
-		}
-
-		hw->rv_buff_out += RCV_BUFSIZE/RCV_BUFBLKS;
-		hw->rv_buff_out %= RCV_BUFSIZE;
-
-	} while (hw->rv_buff_in != hw->rv_buff_out);
-}
-
-static void
-Bchan_close(struct BCState *bcs)
-{
-	struct sk_buff *skb;
-
-	Bchan_mode(bcs, 0, 0);
-	amd7930_bclose(0, bcs->channel);
-
-	if (test_bit(BC_FLG_INIT, &bcs->Flag)) {
-		skb_queue_purge(&bcs->rqueue);
-		skb_queue_purge(&bcs->squeue);
-	}
-	test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
-}
-
-static int
-Bchan_open(struct BCState *bcs)
-{
-	struct amd7930_hw *hw = &bcs->hw.amd7930;
-
-	if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
-		skb_queue_head_init(&bcs->rqueue);
-		skb_queue_head_init(&bcs->squeue);
-	}
-	test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
-
-	amd7930_bopen(0, bcs->channel, 0xff);
-	hw->rv_buff_in = 0;
-	hw->rv_buff_out = 0;
-	hw->tx_skb = NULL;
-	init_hdlc_state(hw->hdlc_state, 0);
-	amd7930_brecv(0, bcs->channel,
-		      hw->rv_buff + hw->rv_buff_in, RCV_BUFSIZE/RCV_BUFBLKS,
-		      (void *) &Bchan_recv_callback, (void *) bcs);
-
-	bcs->event = 0;
-	bcs->tx_cnt = 0;
-	return (0);
-}
-
-static void
-Bchan_init(struct BCState *bcs)
-{
-	if (!(bcs->hw.amd7930.tx_buff = kmalloc(RAW_BUFMAX, GFP_ATOMIC))) {
-		printk(KERN_WARNING
-		       "HiSax: No memory for amd7930.tx_buff\n");
-		return;
-	}
-	if (!(bcs->hw.amd7930.rv_buff = kmalloc(RCV_BUFSIZE, GFP_ATOMIC))) {
-		printk(KERN_WARNING
-		       "HiSax: No memory for amd7930.rv_buff\n");
-		return;
-	}
-	if (!(bcs->hw.amd7930.rv_skb = dev_alloc_skb(HSCX_BUFMAX))) {
-		printk(KERN_WARNING
-		       "HiSax: No memory for amd7930.rv_skb\n");
-		return;
-	}
-	if (!(bcs->hw.amd7930.hdlc_state = kmalloc(sizeof(struct hdlc_state),
-						   GFP_ATOMIC))) {
-		printk(KERN_WARNING
-		       "HiSax: No memory for amd7930.hdlc_state\n");
-		return;
-	}
-
-	bcs->hw.amd7930.tq_rcv.sync = 0;
-	bcs->hw.amd7930.tq_rcv.routine = (void (*)(void *)) &Bchan_rcv_bh;
-	bcs->hw.amd7930.tq_rcv.data = (void *) bcs;
-
-	bcs->hw.amd7930.tq_xmt.sync = 0;
-	bcs->hw.amd7930.tq_xmt.routine = (void (*)(void *)) &Bchan_xmt_bh;
-	bcs->hw.amd7930.tq_xmt.data = (void *) bcs;
-}
-
-static void
-Bchan_manl1(struct PStack *st, int pr,
-	  void *arg)
-{
-	switch (pr) {
-		case (PH_ACTIVATE_REQ):
-			test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
-			Bchan_mode(st->l1.bcs, st->l1.mode, st->l1.bc);
-			st->l1.l1man(st, PH_ACTIVATE_CNF, NULL);
-			break;
-		case (PH_DEACTIVATE_REQ):
-			if (!test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag))
-				Bchan_mode(st->l1.bcs, 0, 0);
-			test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
-			break;
-	}
-}
-
-int
-setstack_amd7930(struct PStack *st, struct BCState *bcs)
-{
-	if (Bchan_open(bcs))
-		return (-1);
-	st->l1.bcs = bcs;
-	st->l2.l2l1 = Bchan_l2l1;
-	st->ma.manl1 = Bchan_manl1;
-	setstack_manager(st);
-	bcs->st = st;
-	return (0);
-}
-
-
-static void
-amd7930_drecv_callback(void *arg, int error, unsigned int count)
-{
-	struct IsdnCardState *cs = (struct IsdnCardState *) arg;
-	static struct tq_struct task;
-	struct sk_buff *skb;
-
-        /* NOTE: This function is called directly from an interrupt handler */
-
-	if (1) {
-		if (!(skb = alloc_skb(count, GFP_ATOMIC)))
-			printk(KERN_WARNING "HiSax: D receive out of memory\n");
-		else {
-			memcpy(skb_put(skb, count), cs->rcvbuf, count);
-			skb_queue_tail(&cs->rq, skb);
-		}
-
-		task.routine = (void *) DChannel_proc_rcv;
-		task.data = (void *) cs;
-		queue_task(&task, &tq_immediate);
-		mark_bh(IMMEDIATE_BH);
-	}
-
-	if (cs->debug & L1_DEB_ISAC_FIFO) {
-		char tmp[128];
-		char *t = tmp;
-
-		t += sprintf(t, "amd7930 Drecv cnt %d", count);
-		if (error) t += sprintf(t, " ERR %x", error);
-		QuickHex(t, cs->rcvbuf, count);
-		debugl1(cs, tmp);
-	}
-
-	amd7930_drecv(0, cs->rcvbuf, MAX_DFRAME_LEN,
-		      &amd7930_drecv_callback, cs);
-}
-
-static void
-amd7930_dxmit_callback(void *arg, int error)
-{
-	struct IsdnCardState *cs = (struct IsdnCardState *) arg;
-	static struct tq_struct task;
-
-        /* NOTE: This function is called directly from an interrupt handler */
-
-	/* may wish to do retransmission here, if error indicates collision */
-
-	if (cs->debug & L1_DEB_ISAC_FIFO) {
-		char tmp[128];
-		char *t = tmp;
-
-		t += sprintf(t, "amd7930 Dxmit cnt %d", cs->tx_skb->len);
-		if (error) t += sprintf(t, " ERR %x", error);
-		QuickHex(t, cs->tx_skb->data, cs->tx_skb->len);
-		debugl1(cs, tmp);
-	}
-
-	cs->tx_skb = NULL;
-
-	task.routine = (void *) DChannel_proc_xmt;
-	task.data = (void *) cs;
-	queue_task(&task, &tq_immediate);
-	mark_bh(IMMEDIATE_BH);
-}
-
-static void
-amd7930_Dchan_l2l1(struct PStack *st, int pr, void *arg)
-{
-	struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
-	struct sk_buff *skb = arg;
-	char str[64];
-
-	switch (pr) {
-		case (PH_DATA_REQ):
-			if (cs->tx_skb) {
-				skb_queue_tail(&cs->sq, skb);
-#ifdef L2FRAME_DEBUG		/* psa */
-				if (cs->debug & L1_DEB_LAPD)
-					Logl2Frame(cs, skb, "PH_DATA Queued", 0);
-#endif
-			} else {
-				if ((cs->dlogflag) && (!(skb->data[2] & 1))) {
-					/* I-FRAME */
-					LogFrame(cs, skb->data, skb->len);
-					sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei);
-					dlogframe(cs, skb->data+4, skb->len-4,
-						  str);
-				}
-				cs->tx_skb = skb;
-				cs->tx_cnt = 0;
-#ifdef L2FRAME_DEBUG		/* psa */
-				if (cs->debug & L1_DEB_LAPD)
-					Logl2Frame(cs, skb, "PH_DATA", 0);
-#endif
-				amd7930_dxmit(0, skb->data, skb->len,
-					      &amd7930_dxmit_callback, cs);
-			}
-			break;
-		case (PH_PULL_IND):
-			if (cs->tx_skb) {
-				if (cs->debug & L1_DEB_WARN)
-					debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
-				skb_queue_tail(&cs->sq, skb);
-				break;
-			}
-			if ((cs->dlogflag) && (!(skb->data[2] & 1))) {	/* I-FRAME */
-				LogFrame(cs, skb->data, skb->len);
-				sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei);
-				dlogframe(cs, skb->data + 4, skb->len - 4,
-					  str);
-			}
-			cs->tx_skb = skb;
-			cs->tx_cnt = 0;
-#ifdef L2FRAME_DEBUG		/* psa */
-			if (cs->debug & L1_DEB_LAPD)
-				Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
-#endif
-			amd7930_dxmit(0, cs->tx_skb->data, cs->tx_skb->len,
-				      &amd7930_dxmit_callback, cs);
-			break;
-		case (PH_PULL_REQ):
-#ifdef L2FRAME_DEBUG		/* psa */
-			if (cs->debug & L1_DEB_LAPD)
-				debugl1(cs, "-> PH_REQUEST_PULL");
-#endif
-			if (!cs->tx_skb) {
-				test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
-				st->l1.l1l2(st, PH_PULL_CNF, NULL);
-			} else
-				test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
-			break;
-	}
-}
-
-int
-setDstack_amd7930(struct PStack *st, struct IsdnCardState *cs)
-{
-	st->l2.l2l1 = amd7930_Dchan_l2l1;
-	if (! cs->rcvbuf) {
-		printk("setDstack_amd7930: No cs->rcvbuf!\n");
-	} else {
-		amd7930_drecv(0, cs->rcvbuf, MAX_DFRAME_LEN,
-			      &amd7930_drecv_callback, cs);
-	}
-	return (0);
-}
-
-static void
-manl1_msg(struct IsdnCardState *cs, int msg, void *arg) {
-	struct PStack *st;
-
-	st = cs->stlist;
-	while (st) {
-		st->ma.manl1(st, msg, arg);
-		st = st->next;
-	}
-}
-
-static void
-amd7930_new_ph(struct IsdnCardState *cs)
-{
-	switch (amd7930_get_liu_state(0)) {
-	        case 3:
-			manl1_msg(cs, PH_POWERUP_CNF, NULL);
-                        break;
-
-	        case 7:
-			manl1_msg(cs, PH_I4_P8_IND, NULL);
-			break;
-
-	        case 8:
-			manl1_msg(cs, PH_RSYNC_IND, NULL);
-			break;
-	}
-}
-
-/* amd7930 LIU state change callback */
-
-static void
-amd7930_liu_callback(struct IsdnCardState *cs)
-{
-	static struct tq_struct task;
-
-	if (!cs)
-		return;
-
-	if (cs->debug & L1_DEB_ISAC) {
-		char tmp[32];
-		sprintf(tmp, "amd7930_liu state %d", amd7930_get_liu_state(0));
-		debugl1(cs, tmp);
-	}
-
-	task.sync = 0;
-	task.routine = (void *) &amd7930_new_ph;
-	task.data = (void *) cs;
-	queue_task(&task, &tq_immediate);
-	mark_bh(IMMEDIATE_BH);
-}
-
-void
-amd7930_l1cmd(struct IsdnCardState *cs, int msg, void *arg)
-{
-	u_char val;
-	char tmp[32];
-	
-	if (cs->debug & L1_DEB_ISAC) {
-		char tmp[32];
-		sprintf(tmp, "amd7930_l1cmd msg %x", msg);
-		debugl1(cs, tmp);
-	}
-
-	switch(msg) {
-		case PH_RESET_REQ:
-			if (amd7930_get_liu_state(0) <= 3)
-				amd7930_liu_activate(0,0);
-			else
-				amd7930_liu_deactivate(0);
-			break;
-		case PH_ENABLE_REQ:
-			break;
-		case PH_INFO3_REQ:
-			amd7930_liu_activate(0,0);
-			break;
-		case PH_TESTLOOP_REQ:
-			break;
-		default:
-			if (cs->debug & L1_DEB_WARN) {
-				sprintf(tmp, "amd7930_l1cmd unknown %4x", msg);
-				debugl1(cs, tmp);
-			}
-			break;
-	}
-}
-
-static void init_amd7930(struct IsdnCardState *cs)
-{
-	Bchan_init(&cs->bcs[0]);
-	Bchan_init(&cs->bcs[1]);
-	cs->bcs[0].BC_SetStack = setstack_amd7930;
-	cs->bcs[1].BC_SetStack = setstack_amd7930;
-	cs->bcs[0].BC_Close = Bchan_close;
-	cs->bcs[1].BC_Close = Bchan_close;
-	Bchan_mode(cs->bcs, 0, 0);
-	Bchan_mode(cs->bcs + 1, 0, 0);
-}
-
-void
-release_amd7930(struct IsdnCardState *cs)
-{
-}
-
-static int
-amd7930_card_msg(struct IsdnCardState *cs, int mt, void *arg)
-{
-	switch (mt) {
-		case CARD_RESET:
-			return(0);
-		case CARD_RELEASE:
-			release_amd7930(cs);
-			return(0);
-		case CARD_INIT:
-			cs->l1cmd = amd7930_l1cmd;
-			amd7930_liu_init(0, &amd7930_liu_callback, (void *)cs);
-			init_amd7930(cs);
-			return(0);
-		case CARD_TEST:
-			return(0);
-	}
-	return(0);
-}
-
-int __init
-setup_amd7930(struct IsdnCard *card)
-{
-	struct IsdnCardState *cs = card->cs;
-	char tmp[64];
-
-	strcpy(tmp, amd7930_revision);
-	printk(KERN_INFO "HiSax: AMD7930 driver Rev. %s\n", HiSax_getrev(tmp));
-	if (cs->typ != ISDN_CTYPE_AMD7930)
-		return (0);
-
-        cs->irq = amd7930_get_irqnum(0);
-        if (cs->irq == 0)
-		return (0);
-
-	cs->cardmsg = &amd7930_card_msg;
-
-	return (1);
-}
diff -urN linux-2.4.21-pre3/drivers/isdn/hisax/hisax.h linux-2.4.21-pre4/drivers/isdn/hisax/hisax.h
--- linux-2.4.21-pre3/drivers/isdn/hisax/hisax.h	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre4/drivers/isdn/hisax/hisax.h	Tue Jan 28 19:44:30 2003
@@ -472,6 +472,8 @@
 #define BC_FLG_FTI_RUN	13
 #define BC_FLG_LL_OK	14
 #define BC_FLG_LL_CONN	15
+#define BC_FLG_FTI_FTS	16
+#define BC_FLG_FRH_WAIT	17
 
 #define L1_MODE_NULL	0
 #define L1_MODE_TRANS	1
diff -urN linux-2.4.21-pre3/drivers/isdn/hisax/isar.c linux-2.4.21-pre4/drivers/isdn/hisax/isar.c
--- linux-2.4.21-pre3/drivers/isdn/hisax/isar.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.21-pre4/drivers/isdn/hisax/isar.c	Tue Jan 28 19:44:30 2003
@@ -21,10 +21,12 @@
 #define DLE	0x10
 #define ETX	0x03
 
-
-const u_char faxmodulation_s[] = "3,24,48,72,73,74,96,97,98,121,122,145,146"; 
-const u_char faxmodulation[] = {3,24,48,72,73,74,96,97,98,121,122,145,146}; 
-#define FAXMODCNT 13
+#define FAXMODCNT	13
+const	u_char	faxmodulation[] = {3,24,48,72,73,74,96,97,98,121,122,145,146};
+static	u_int	modmask = 0x1fff;
+static	int	frm_extra_delay = 2;
+static	int	para_TOA = 6;
+const   u_char  *FC1_CMD[] = {"FAE", "FTS", "FRS", "FTM", "FRM", "FTH", "FRH", "CTRL" };
 
 void isar_setup(struct IsdnCardState *cs);
 static void isar_pump_cmd(struct BCState *bcs, u_char cmd, u_char para);
@@ -125,7 +127,7 @@
 	ireg->clsb = cs->BC_Read_Reg(cs, 1, ISAR_CTRL_L);
 #if DUMP_MBOXFRAME
 	if (cs->debug & L1_DEB_HSCX)
-		debugl1(cs, "rcv_mbox(%02x,%02x,%d)", ireg->iis, ireg->cmsb,
+		debugl1(cs, "irq_stat(%02x,%02x,%d)", ireg->iis, ireg->cmsb,
 			ireg->clsb);
 #endif
 }
@@ -412,6 +414,7 @@
 	}
 	cs->debug = debug;
 	isar_setup(cs);
+
 	ret = 0;
 reterrflg:
 	restore_flags(flags);
@@ -581,7 +584,6 @@
 				if (ireg->cmsb & SART_NMD) { /* ABORT */
 					if (cs->debug & L1_DEB_WARN)
 						debugl1(cs, "isar_rcv_frame: no more data");
-					cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
 					bcs->hw.isar.rcvidx = 0;
 					send_DLE_ETX(bcs);
 					sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) |
@@ -592,7 +594,6 @@
 				}
 			} else {
 				printk(KERN_WARNING "HiSax: skb out of memory\n");
-				cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
 			}
 			break;
 		}
@@ -617,8 +618,9 @@
 			bcs->hw.isar.rcvidx = 0;
 			cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
 		} else {
-			if (ireg->cmsb & HDLC_FSD)
+			if (ireg->cmsb & HDLC_FSD) {
 				bcs->hw.isar.rcvidx = 0;
+			}
 			ptr = bcs->hw.isar.rcvbuf + bcs->hw.isar.rcvidx;
 			bcs->hw.isar.rcvidx += ireg->clsb;
 			rcv_mbox(cs, ireg, ptr);
@@ -629,6 +631,8 @@
 					if (cs->debug & L1_DEB_WARN)
 						debugl1(cs, "isar frame to short %d",
 							bcs->hw.isar.rcvidx);
+					printk(KERN_WARNING "ISAR: frame to short %d\n",
+						bcs->hw.isar.rcvidx);
 				} else if (!(skb = dev_alloc_skb(bcs->hw.isar.rcvidx))) {
 					printk(KERN_WARNING "ISAR: receive out of memory\n");
 				} else {
@@ -639,6 +643,7 @@
 					isar_sched_event(bcs, B_RCVBUFREADY);
 					send_DLE_ETX(bcs);
 					isar_sched_event(bcs, B_LL_OK);
+					test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag);
 				}
 				bcs->hw.isar.rcvidx = 0;
 			}
@@ -646,13 +651,14 @@
 		if (ireg->cmsb & SART_NMD) { /* ABORT */
 			if (cs->debug & L1_DEB_WARN)
 				debugl1(cs, "isar_rcv_frame: no more data");
-			cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
 			bcs->hw.isar.rcvidx = 0;
-			send_DLE_ETX(bcs);
 			sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) |
 				ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 0, NULL);
 			bcs->hw.isar.state = STFAX_ESCAPE;
-			isar_sched_event(bcs, B_LL_NOCARRIER);
+			if (test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag)) {
+				send_DLE_ETX(bcs);
+				isar_sched_event(bcs, B_LL_NOCARRIER);
+			}
 		}
 		break;
 	default:
@@ -1075,19 +1081,22 @@
 			if (cs->debug & L1_DEB_HSCX)
 				debugl1(cs, "pump stev RSP_DISC");
 			if (bcs->hw.isar.state == STFAX_ESCAPE) {
+				p1 = 5;
 				switch(bcs->hw.isar.newcmd) {
 					case 0:
 						bcs->hw.isar.state = STFAX_READY;
 						break;
-					case PCTRL_CMD_FTH:
 					case PCTRL_CMD_FTM:
-						p1 = 10;
+						p1 = 2;
+					case PCTRL_CMD_FTH:
 						sendmsg(cs, dps | ISAR_HIS_PUMPCTRL,
 							PCTRL_CMD_SILON, 1, &p1);
 						bcs->hw.isar.state = STFAX_SILDET;
 						break;
-					case PCTRL_CMD_FRH:
 					case PCTRL_CMD_FRM:
+						if (frm_extra_delay)
+							mdelay(frm_extra_delay);
+					case PCTRL_CMD_FRH:
 						p1 = bcs->hw.isar.mod = bcs->hw.isar.newmod;
 						bcs->hw.isar.newmod = 0;
 						bcs->hw.isar.cmd = bcs->hw.isar.newcmd;
@@ -1206,6 +1215,9 @@
 					isar_pump_statev_modem(bcs, ireg->cmsb);
 				} else if (bcs->mode == L1_MODE_FAX) {
 					isar_pump_statev_fax(bcs, ireg->cmsb);
+				} else if (ireg->cmsb == PSEV_10MS_TIMER) {
+					if (cs->debug & L1_DEB_HSCX)
+						debugl1(cs, "pump stev TIMER");
 				} else {
 					if (cs->debug & L1_DEB_WARN)
 						debugl1(cs, "isar IIS_PSTEV pmode %d stat %x",
@@ -1266,6 +1278,9 @@
 	if (test_and_clear_bit(BC_FLG_LL_CONN, &bcs->Flag)) {
 		isar_sched_event(bcs, B_LL_CONNECT);
 	}
+	if (test_and_clear_bit(BC_FLG_FTI_FTS, &bcs->Flag)) {
+		isar_sched_event(bcs, B_LL_OK);
+	}
 }
 
 static void
@@ -1288,7 +1303,7 @@
 			} else {
 				param[5] = PV32P6_ATN;
 			}
-			param[0] = 6; /* 6 db */
+			param[0] = para_TOA; /* 6 db */
 			param[1] = PV32P2_V23R | PV32P2_V22A | PV32P2_V22B |
 				   PV32P2_V22C | PV32P2_V21 | PV32P2_BEL; 
 			param[2] = PV32P3_AMOD | PV32P3_V32B | PV32P3_V23B;
@@ -1304,7 +1319,7 @@
 			} else {
 				param[1] = PFAXP2_ATN;
 			}
-			param[0] = 6; /* 6 db */
+			param[0] = para_TOA; /* 6 db */
 			sendmsg(cs, dps | ISAR_HIS_PUMPCFG, ctrl, 2, param);
 			bcs->hw.isar.state = STFAX_NULL;
 			bcs->hw.isar.newcmd = 0;
@@ -1333,7 +1348,6 @@
 				"\0\0");
 			break;
 		case L1_MODE_HDLC:
-		case L1_MODE_FAX:
 			param[0] = 0;
 			sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_HDLC, 1,
 				param);
@@ -1345,6 +1359,9 @@
 			sendmsg(cs, dps | ISAR_HIS_SARTCFG, ctrl, 2,
 				param);
 			break;
+		case L1_MODE_FAX:
+			/* SART must not configured with FAX */
+			break;
 	}
 	udelay(1000);
 	sendmsg(cs, dps | ISAR_HIS_BSTREQ, 0, 0, NULL);
@@ -1448,6 +1465,7 @@
 
 	switch(cmd) {
 		case ISDN_FAX_CLASS1_FTM:
+			test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag);
 			if (bcs->hw.isar.state == STFAX_READY) {
 				p1 = para;
 				ctrl = PCTRL_CMD_FTM;
@@ -1471,6 +1489,7 @@
 			}
 			break;
 		case ISDN_FAX_CLASS1_FTH:
+			test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag);
 			if (bcs->hw.isar.state == STFAX_READY) {
 				p1 = para;
 				ctrl = PCTRL_CMD_FTH;
@@ -1494,6 +1513,7 @@
 			}
 			break;
 		case ISDN_FAX_CLASS1_FRM:
+			test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag);
 			if (bcs->hw.isar.state == STFAX_READY) {
 				p1 = para;
 				ctrl = PCTRL_CMD_FRM;
@@ -1517,6 +1537,7 @@
 			}
 			break;
 		case ISDN_FAX_CLASS1_FRH:
+			test_and_set_bit(BC_FLG_FRH_WAIT, &bcs->Flag);
 			if (bcs->hw.isar.state == STFAX_READY) {
 				p1 = para;
 				ctrl = PCTRL_CMD_FRH;
@@ -1539,6 +1560,11 @@
 				bcs->hw.isar.state = STFAX_ESCAPE; 
 			}
 			break;
+		case ISDN_FAXPUMP_HALT:
+			bcs->hw.isar.state = STFAX_NULL;
+			nom = 0;
+			ctrl = PCTRL_CMD_HALT;
+			break;
 	}
 	if (ctrl)
 		sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, ctrl, nom, &p1);
@@ -1632,6 +1658,15 @@
 			l1_msg_b(st, pr, arg);
 			break;
 		case (PH_DEACTIVATE | CONFIRM):
+			switch(st->l1.mode) {
+				case L1_MODE_TRANS:
+				case L1_MODE_HDLC:
+				case L1_MODE_V32:
+					break;
+				case L1_MODE_FAX:
+					isar_pump_cmd(st->l1.bcs, ISDN_FAXPUMP_HALT, 0);
+					break;
+			}
 			test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
 			test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
 			if (st->l1.bcs->cs->debug & L1_DEB_HSCX)
@@ -1723,6 +1758,51 @@
 						test_and_set_bit(BC_FLG_DLEETX,
 							&bcs->Flag);
 					break;
+				case ISDN_FAX_CLASS1_FTS:
+					if (ic->parm.aux.subcmd == AT_QUERY) {
+						ic->command = ISDN_STAT_FAXIND;
+						ic->parm.aux.cmd = ISDN_FAX_CLASS1_OK;
+						cs->iif.statcallb(ic);
+						return(0);
+					} else if (ic->parm.aux.subcmd == AT_EQ_QUERY) {
+						strcpy(ic->parm.aux.para, "0-255");
+						ic->command = ISDN_STAT_FAXIND;
+						ic->parm.aux.cmd = ISDN_FAX_CLASS1_QUERY;
+						cs->iif.statcallb(ic);
+						return(0);
+					} else if (ic->parm.aux.subcmd == AT_EQ_VALUE) {
+						if (cs->debug & L1_DEB_HSCX)
+							debugl1(cs, "isar_auxcmd %s=%d",
+								FC1_CMD[ic->parm.aux.cmd], ic->parm.aux.para[0]);
+						if (bcs->hw.isar.state == STFAX_READY) {
+							if (! ic->parm.aux.para[0]) {
+								ic->command = ISDN_STAT_FAXIND;
+								ic->parm.aux.cmd = ISDN_FAX_CLASS1_OK;
+								cs->iif.statcallb(ic);
+								return(0);
+							}
+							if (! test_and_set_bit(BC_FLG_FTI_RUN, &bcs->Flag)) {
+								/* n*10 ms */
+								bcs->hw.isar.ftimer.expires =
+									jiffies + ((ic->parm.aux.para[0] * 10 * HZ)/1000);
+								test_and_set_bit(BC_FLG_FTI_FTS, &bcs->Flag);
+								add_timer(&bcs->hw.isar.ftimer);
+								return(0);
+							} else {
+								if (cs->debug)
+									debugl1(cs, "isar FTS=%d and FTI busy",
+										ic->parm.aux.para[0]);
+							}
+						} else {
+							if (cs->debug)
+								debugl1(cs, "isar FTS=%d and isar.state not ready(%x)",
+									ic->parm.aux.para[0],bcs->hw.isar.state);
+						}
+						ic->command = ISDN_STAT_FAXIND;
+						ic->parm.aux.cmd = ISDN_FAX_CLASS1_ERROR;
+						cs->iif.statcallb(ic);
+					}
+					break;
 				case ISDN_FAX_CLASS1_FRM:
 				case ISDN_FAX_CLASS1_FRH:
 				case ISDN_FAX_CLASS1_FTM:
@@ -1735,16 +1815,24 @@
 						cs->iif.statcallb(ic);
 						return(0);
 					} else if (ic->parm.aux.subcmd == AT_EQ_QUERY) {
-						strcpy(ic->parm.aux.para, faxmodulation_s);
+						char *p = ic->parm.aux.para;
+						for(i=0;i<FAXMODCNT;i++)
+							if ((1<<i) & modmask)
+								p += sprintf(p, "%d,", faxmodulation[i]);
+						p--;
+						*p=0;
 						ic->command = ISDN_STAT_FAXIND;
 						ic->parm.aux.cmd = ISDN_FAX_CLASS1_QUERY;
 						cs->iif.statcallb(ic);
 						return(0);
 					} else if (ic->parm.aux.subcmd == AT_EQ_VALUE) {
+						if (cs->debug & L1_DEB_HSCX)
+							debugl1(cs, "isar_auxcmd %s=%d",
+								FC1_CMD[ic->parm.aux.cmd], ic->parm.aux.para[0]);
 						for(i=0;i<FAXMODCNT;i++)
 							if (faxmodulation[i]==ic->parm.aux.para[0])
 								break;
-						if ((FAXMODCNT > i) && 
+						if ((i < FAXMODCNT) && ((1<<i) & modmask) && 
 							test_bit(BC_FLG_INIT, &bcs->Flag)) {
 							isar_pump_cmd(bcs,
 								ic->parm.aux.cmd,
@@ -1762,7 +1850,7 @@
 			break;
 		case (ISDN_CMD_IOCTL):
 			switch (ic->arg) {
-				case (9): /* load firmware */
+				case 9: /* load firmware */
 					features = ISDN_FEATURE_L2_MODEM |
 						ISDN_FEATURE_L2_FAX |
 						ISDN_FEATURE_L3_FCLASS1;
@@ -1772,6 +1860,26 @@
 					else 
 						ll_run(cs, features);
 					break;
+				case 20:
+					features = *(unsigned int *) ic->parm.num;
+					printk(KERN_DEBUG "HiSax: max modulation old(%04x) new(%04x)\n",
+						modmask, features);
+					modmask = features;
+					break;
+				case 21:
+					features = *(unsigned int *) ic->parm.num;
+					printk(KERN_DEBUG "HiSax: FRM extra delay old(%d) new(%d) ms\n",
+						frm_extra_delay, features);
+					if (features >= 0)
+						frm_extra_delay = features;
+					break;
+				case 22:
+					features = *(unsigned int *) ic->parm.num;
+					printk(KERN_DEBUG "HiSax: TOA old(%d) new(%d) db\n",
+						para_TOA, features);
+					if (features >= 0 && features < 32)
+						para_TOA = features;
+					break;
 				default:
 					printk(KERN_DEBUG "HiSax: invalid ioctl %d\n",
 					       (int) ic->arg);
diff -urN linux-2.4.21-pre3/drivers/isdn/hisax/isar.h linux-2.4.21-pre4/drivers/isdn/hisax/isar.h
--- linux-2.4.21-pre3/drivers/isdn/hisax/isar.h	Fri Dec 21 09:41:54 2001
+++ linux-2.4.21-pre4/drivers/isdn/hisax/isar.h	Tue Jan 28 19:44:30 2003
@@ -28,6 +28,8 @@
 #define ISAR_HIS_FIRM		0x1e
 #define ISAR_HIS_STDSP		0x08
 #define ISAR_HIS_DIAG		0x05
+#define ISAR_HIS_WAITSTATE	0x27
+#define ISAR_HIS_TIMERIRQ	0x25
 #define ISAR_HIS_P0CFG		0x3c
 #define ISAR_HIS_P12CFG		0x24
 #define ISAR_HIS_SARTCFG	0x25	
@@ -43,6 +45,10 @@
 #define ISAR_HIS_DPS2		0x80
 #define SET_DPS(x)		((x<<6) & 0xc0)
 
+#define ISAR_CMD_TIMERIRQ_OFF	0x20
+#define ISAR_CMD_TIMERIRQ_ON	0x21
+
+
 #define ISAR_IIS_MSCMSD		0x3f
 #define ISAR_IIS_VNR		0x15
 #define ISAR_IIS_DKEY		0x03
@@ -207,6 +213,8 @@
 #define STFAX_ESCAPE	5
 #define STFAX_SILDET	6
 
+#define ISDN_FAXPUMP_HALT	100
+
 extern int ISARVersion(struct IsdnCardState *cs, char *s);
 extern void isar_int_main(struct IsdnCardState *cs);
 extern void initisar(struct IsdnCardState *cs);
diff -urN linux-2.4.21-pre3/drivers/isdn/hisax/isdnhdlc.c linux-2.4.21-pre4/drivers/isdn/hisax/isdnhdlc.c
--- linux-2.4.21-pre3/drivers/isdn/hisax/isdnhdlc.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/drivers/isdn/hisax/isdnhdlc.c	Tue Jan 28 19:44:30 2003
@@ -0,0 +1,669 @@
+/*
+ * isdnhdlc.c  --  General purpose ISDN HDLC decoder.
+ *
+ *Copyright (C) 2002	Wolfgang Mües      <wolfgang@iksw-muees.de>
+ *		2001 	Frode Isaksen      <fisaksen@bewan.com>
+ *              2001 	Kai Germaschewski  <kai.germaschewski@gmx.de>
+ *
+ *      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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include "isdnhdlc.h"
+
+/*-------------------------------------------------------------------*/
+
+MODULE_AUTHOR("Wolfgang Mües <wolfgang@iksw-muees.de>, "
+	      "Frode Isaksen <fisaksen@bewan.com>, "
+	      "Kai Germaschewski <kai.germaschewski@gmx.de>");
+MODULE_DESCRIPTION("General purpose ISDN HDLC decoder");
+MODULE_LICENSE("GPL");
+
+/*-------------------------------------------------------------------*/
+
+/* bit swap table.
+ * Very handy for devices with different bit order,
+ * and neccessary for each transparent B-channel access for all
+ * devices which works with this HDLC decoder without bit reversal.
+ */
+const unsigned char isdnhdlc_bit_rev_tab[256] = {
+	0x00,0x80,0x40,0xC0,0x20,0xA0,0x60,0xE0,0x10,0x90,0x50,0xD0,0x30,0xB0,0x70,0xF0,
+	0x08,0x88,0x48,0xC8,0x28,0xA8,0x68,0xE8,0x18,0x98,0x58,0xD8,0x38,0xB8,0x78,0xF8,
+	0x04,0x84,0x44,0xC4,0x24,0xA4,0x64,0xE4,0x14,0x94,0x54,0xD4,0x34,0xB4,0x74,0xF4,
+	0x0C,0x8C,0x4C,0xCC,0x2C,0xAC,0x6C,0xEC,0x1C,0x9C,0x5C,0xDC,0x3C,0xBC,0x7C,0xFC,
+	0x02,0x82,0x42,0xC2,0x22,0xA2,0x62,0xE2,0x12,0x92,0x52,0xD2,0x32,0xB2,0x72,0xF2,
+	0x0A,0x8A,0x4A,0xCA,0x2A,0xAA,0x6A,0xEA,0x1A,0x9A,0x5A,0xDA,0x3A,0xBA,0x7A,0xFA,
+	0x06,0x86,0x46,0xC6,0x26,0xA6,0x66,0xE6,0x16,0x96,0x56,0xD6,0x36,0xB6,0x76,0xF6,
+	0x0E,0x8E,0x4E,0xCE,0x2E,0xAE,0x6E,0xEE,0x1E,0x9E,0x5E,0xDE,0x3E,0xBE,0x7E,0xFE,
+	0x01,0x81,0x41,0xC1,0x21,0xA1,0x61,0xE1,0x11,0x91,0x51,0xD1,0x31,0xB1,0x71,0xF1,
+	0x09,0x89,0x49,0xC9,0x29,0xA9,0x69,0xE9,0x19,0x99,0x59,0xD9,0x39,0xB9,0x79,0xF9,
+	0x05,0x85,0x45,0xC5,0x25,0xA5,0x65,0xE5,0x15,0x95,0x55,0xD5,0x35,0xB5,0x75,0xF5,
+	0x0D,0x8D,0x4D,0xCD,0x2D,0xAD,0x6D,0xED,0x1D,0x9D,0x5D,0xDD,0x3D,0xBD,0x7D,0xFD,
+	0x03,0x83,0x43,0xC3,0x23,0xA3,0x63,0xE3,0x13,0x93,0x53,0xD3,0x33,0xB3,0x73,0xF3,
+	0x0B,0x8B,0x4B,0xCB,0x2B,0xAB,0x6B,0xEB,0x1B,0x9B,0x5B,0xDB,0x3B,0xBB,0x7B,0xFB,
+	0x07,0x87,0x47,0xC7,0x27,0xA7,0x67,0xE7,0x17,0x97,0x57,0xD7,0x37,0xB7,0x77,0xF7,
+	0x0F,0x8F,0x4F,0xCF,0x2F,0xAF,0x6F,0xEF,0x1F,0x9F,0x5F,0xDF,0x3F,0xBF,0x7F,0xFF
+};
+
+/* Table for CRC16. Internal used only. */
+static const unsigned short int crc16_tab[] = {
+	0x0000,0x1189,0x2312,0x329b,0x4624,0x57ad,0x6536,0x74bf,
+	0x8c48,0x9dc1,0xaf5a,0xbed3,0xca6c,0xdbe5,0xe97e,0xf8f7,
+	0x1081,0x0108,0x3393,0x221a,0x56a5,0x472c,0x75b7,0x643e,
+	0x9cc9,0x8d40,0xbfdb,0xae52,0xdaed,0xcb64,0xf9ff,0xe876,
+	0x2102,0x308b,0x0210,0x1399,0x6726,0x76af,0x4434,0x55bd,
+	0xad4a,0xbcc3,0x8e58,0x9fd1,0xeb6e,0xfae7,0xc87c,0xd9f5,
+	0x3183,0x200a,0x1291,0x0318,0x77a7,0x662e,0x54b5,0x453c,
+	0xbdcb,0xac42,0x9ed9,0x8f50,0xfbef,0xea66,0xd8fd,0xc974,
+	0x4204,0x538d,0x6116,0x709f,0x0420,0x15a9,0x2732,0x36bb,
+	0xce4c,0xdfc5,0xed5e,0xfcd7,0x8868,0x99e1,0xab7a,0xbaf3,
+	0x5285,0x430c,0x7197,0x601e,0x14a1,0x0528,0x37b3,0x263a,
+	0xdecd,0xcf44,0xfddf,0xec56,0x98e9,0x8960,0xbbfb,0xaa72,
+	0x6306,0x728f,0x4014,0x519d,0x2522,0x34ab,0x0630,0x17b9,
+	0xef4e,0xfec7,0xcc5c,0xddd5,0xa96a,0xb8e3,0x8a78,0x9bf1,
+	0x7387,0x620e,0x5095,0x411c,0x35a3,0x242a,0x16b1,0x0738,
+	0xffcf,0xee46,0xdcdd,0xcd54,0xb9eb,0xa862,0x9af9,0x8b70,
+	0x8408,0x9581,0xa71a,0xb693,0xc22c,0xd3a5,0xe13e,0xf0b7,
+	0x0840,0x19c9,0x2b52,0x3adb,0x4e64,0x5fed,0x6d76,0x7cff,
+	0x9489,0x8500,0xb79b,0xa612,0xd2ad,0xc324,0xf1bf,0xe036,
+	0x18c1,0x0948,0x3bd3,0x2a5a,0x5ee5,0x4f6c,0x7df7,0x6c7e,
+	0xa50a,0xb483,0x8618,0x9791,0xe32e,0xf2a7,0xc03c,0xd1b5,
+	0x2942,0x38cb,0x0a50,0x1bd9,0x6f66,0x7eef,0x4c74,0x5dfd,
+	0xb58b,0xa402,0x9699,0x8710,0xf3af,0xe226,0xd0bd,0xc134,
+	0x39c3,0x284a,0x1ad1,0x0b58,0x7fe7,0x6e6e,0x5cf5,0x4d7c,
+	0xc60c,0xd785,0xe51e,0xf497,0x8028,0x91a1,0xa33a,0xb2b3,
+	0x4a44,0x5bcd,0x6956,0x78df,0x0c60,0x1de9,0x2f72,0x3efb,
+	0xd68d,0xc704,0xf59f,0xe416,0x90a9,0x8120,0xb3bb,0xa232,
+	0x5ac5,0x4b4c,0x79d7,0x685e,0x1ce1,0x0d68,0x3ff3,0x2e7a,
+	0xe70e,0xf687,0xc41c,0xd595,0xa12a,0xb0a3,0x8238,0x93b1,
+	0x6b46,0x7acf,0x4854,0x59dd,0x2d62,0x3ceb,0x0e70,0x1ff9,
+	0xf78f,0xe606,0xd49d,0xc514,0xb1ab,0xa022,0x92b9,0x8330,
+	0x7bc7,0x6a4e,0x58d5,0x495c,0x3de3,0x2c6a,0x1ef1,0x0f78
+};
+
+
+enum {
+	HDLC_FAST_IDLE,HDLC_GET_FLAG_B0,HDLC_GETFLAG_B1A6,HDLC_GETFLAG_B7,
+	HDLC_GET_DATA,HDLC_FAST_FLAG
+};
+
+enum {
+	HDLC_SEND_DATA,HDLC_SEND_CRC1,HDLC_SEND_FAST_FLAG,
+	HDLC_SEND_FIRST_FLAG,HDLC_SEND_CRC2,HDLC_SEND_CLOSING_FLAG,
+	HDLC_SEND_IDLE1,HDLC_SEND_FAST_IDLE,HDLC_SENDFLAG_B0,
+	HDLC_SENDFLAG_B1A6,HDLC_SENDFLAG_B7,STOPPED
+};
+
+void isdnhdlc_rcv_init (struct isdnhdlc_vars *hdlc, int do_adapt56)
+{
+   	hdlc->bit_shift = 0;
+	hdlc->hdlc_bits1 = 0;
+	hdlc->data_bits = 0;
+	hdlc->ffbit_shift = 0;
+	hdlc->data_received = 0;
+	hdlc->state = HDLC_GET_DATA;
+	hdlc->do_adapt56 = do_adapt56;
+	hdlc->dchannel = 0;
+	hdlc->crc = 0;
+	hdlc->cbin = 0;
+	hdlc->shift_reg = 0;
+	hdlc->ffvalue = 0;
+	hdlc->dstpos = 0;
+}
+
+void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc, int is_d_channel, int do_adapt56)
+{
+   	hdlc->bit_shift = 0;
+	hdlc->hdlc_bits1 = 0;
+	hdlc->data_bits = 0;
+	hdlc->ffbit_shift = 0;
+	hdlc->data_received = 0;
+	hdlc->do_closing = 0;
+	hdlc->ffvalue = 0;
+	if (is_d_channel) {
+		hdlc->dchannel = 1;
+		hdlc->state = HDLC_SEND_FIRST_FLAG;
+	} else {
+		hdlc->dchannel = 0;
+		hdlc->state = HDLC_SEND_FAST_FLAG;
+		hdlc->ffvalue = 0x7e;
+	}
+	hdlc->cbin = 0x7e;
+	hdlc->bit_shift = 0;
+	if(do_adapt56){
+		hdlc->do_adapt56 = 1;
+		hdlc->data_bits = 0;
+		hdlc->state = HDLC_SENDFLAG_B0;
+	} else {
+		hdlc->do_adapt56 = 0;
+		hdlc->data_bits = 8;
+	}
+	hdlc->shift_reg = 0;
+}
+
+/*
+  isdnhdlc_decode - decodes HDLC frames from a transparent bit stream.
+
+  The source buffer is scanned for valid HDLC frames looking for
+  flags (01111110) to indicate the start of a frame. If the start of
+  the frame is found, the bit stuffing is removed (0 after 5 1's).
+  When a new flag is found, the complete frame has been received
+  and the CRC is checked.
+  If a valid frame is found, the function returns the frame length
+  excluding the CRC with the bit HDLC_END_OF_FRAME set.
+  If the beginning of a valid frame is found, the function returns
+  the length.
+  If a framing error is found (too many 1s and not a flag) the function
+  returns the length with the bit HDLC_FRAMING_ERROR set.
+  If a CRC error is found the function returns the length with the
+  bit HDLC_CRC_ERROR set.
+  If the frame length exceeds the destination buffer size, the function
+  returns the length with the bit HDLC_LENGTH_ERROR set.
+
+  src - source buffer
+  slen - source buffer length
+  count - number of bytes removed (decoded) from the source buffer
+  dst _ destination buffer
+  dsize - destination buffer size
+  returns - number of decoded bytes in the destination buffer and status
+  flag.
+ */
+int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src,
+		     int slen, int *count, unsigned char *dst, int dsize)
+{
+	int status=0;
+
+	static const unsigned char fast_flag[]={
+		0x00,0x00,0x00,0x20,0x30,0x38,0x3c,0x3e,0x3f
+	};
+
+	static const unsigned char fast_flag_value[]={
+		0x00,0x7e,0xfc,0xf9,0xf3,0xe7,0xcf,0x9f,0x3f
+	};
+
+	static const unsigned char fast_abort[]={
+		0x00,0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff
+	};
+
+	*count = slen;
+
+	while(slen > 0){
+		if(hdlc->bit_shift==0){
+			hdlc->cbin = *src++;
+			slen--;
+			hdlc->bit_shift = 8;
+			if(hdlc->do_adapt56){
+				hdlc->bit_shift --;
+			}
+		}
+
+		switch(hdlc->state){
+		case STOPPED:
+			return 0;
+		case HDLC_FAST_IDLE:
+			if(hdlc->cbin == 0xff){
+				hdlc->bit_shift = 0;
+				break;
+			}
+			hdlc->state = HDLC_GET_FLAG_B0;
+			hdlc->hdlc_bits1 = 0;
+			hdlc->bit_shift = 8;
+			break;
+		case HDLC_GET_FLAG_B0:
+			if(!(hdlc->cbin & 0x80)) {
+				hdlc->state = HDLC_GETFLAG_B1A6;
+				hdlc->hdlc_bits1 = 0;
+			} else {
+				if(!hdlc->do_adapt56){
+					if(++hdlc->hdlc_bits1 >=8 ) if(hdlc->bit_shift==1)
+						hdlc->state = HDLC_FAST_IDLE;
+				}
+			}
+			hdlc->cbin<<=1;
+			hdlc->bit_shift --;
+			break;
+		case HDLC_GETFLAG_B1A6:
+			if(hdlc->cbin & 0x80){
+				hdlc->hdlc_bits1++;
+				if(hdlc->hdlc_bits1==6){
+					hdlc->state = HDLC_GETFLAG_B7;
+				}
+			} else {
+				hdlc->hdlc_bits1 = 0;
+			}
+			hdlc->cbin<<=1;
+			hdlc->bit_shift --;
+			break;
+		case HDLC_GETFLAG_B7:
+			if(hdlc->cbin & 0x80) {
+				hdlc->state = HDLC_GET_FLAG_B0;
+			} else {
+				hdlc->state = HDLC_GET_DATA;
+				hdlc->crc = 0xffff;
+				hdlc->shift_reg = 0;
+				hdlc->hdlc_bits1 = 0;
+				hdlc->data_bits = 0;
+				hdlc->data_received = 0;
+			}
+			hdlc->cbin<<=1;
+			hdlc->bit_shift --;
+			break;
+		case HDLC_GET_DATA:
+			if(hdlc->cbin & 0x80){
+				hdlc->hdlc_bits1++;
+				switch(hdlc->hdlc_bits1){
+				case 6:
+					break;
+				case 7:
+					if(hdlc->data_received) {
+						// bad frame
+						status = -HDLC_FRAMING_ERROR;
+					}
+					if(!hdlc->do_adapt56){
+						if(hdlc->cbin==fast_abort[hdlc->bit_shift+1]){
+							hdlc->state = HDLC_FAST_IDLE;
+							hdlc->bit_shift=1;
+							break;
+						}
+					} else {
+						hdlc->state = HDLC_GET_FLAG_B0;
+					}
+					break;
+				default:
+					hdlc->shift_reg>>=1;
+					hdlc->shift_reg |= 0x80;
+					hdlc->data_bits++;
+					break;
+				}
+			} else {
+				switch(hdlc->hdlc_bits1){
+				case 5:
+					break;
+				case 6:
+					if(hdlc->data_received){
+						if (hdlc->dstpos < 2) {
+							status = -HDLC_FRAMING_ERROR;
+						} else if (hdlc->crc != 0xf0b8){
+							// crc error
+							status = -HDLC_CRC_ERROR;
+						} else {
+							// remove CRC
+							hdlc->dstpos -= 2;
+							// good frame
+							status = hdlc->dstpos;
+						}
+					}
+					hdlc->crc = 0xffff;
+					hdlc->shift_reg = 0;
+					hdlc->data_bits = 0;
+					if(!hdlc->do_adapt56){
+						if(hdlc->cbin==fast_flag[hdlc->bit_shift]){
+							hdlc->ffvalue = fast_flag_value[hdlc->bit_shift];
+							hdlc->state = HDLC_FAST_FLAG;
+							hdlc->ffbit_shift = hdlc->bit_shift;
+							hdlc->bit_shift = 1;
+						} else {
+							hdlc->state = HDLC_GET_DATA;
+							hdlc->data_received = 0;
+						}
+					} else {
+						hdlc->state = HDLC_GET_DATA;
+						hdlc->data_received = 0;
+					}
+					break;
+				default:
+					hdlc->shift_reg>>=1;
+					hdlc->data_bits++;
+					break;
+				}
+				hdlc->hdlc_bits1 = 0;
+			}
+			if (status) {
+				hdlc->dstpos = 0;
+				*count -= slen;
+				hdlc->cbin <<= 1;
+				hdlc->bit_shift--;
+				return status;
+			}
+			if(hdlc->data_bits==8){
+				unsigned cval;
+
+				hdlc->data_bits = 0;
+				hdlc->data_received = 1;
+				cval = (hdlc->crc^hdlc->shift_reg) & 0xff;
+				hdlc->crc = (hdlc->crc>>8)^crc16_tab[cval];
+				// good byte received
+				if (dsize--) {
+					dst[hdlc->dstpos++] = hdlc->shift_reg;
+				} else {
+					// frame too long
+					status = -HDLC_LENGTH_ERROR;
+					hdlc->dstpos = 0;
+				}
+			}
+			hdlc->cbin <<= 1;
+			hdlc->bit_shift--;
+			break;
+		case HDLC_FAST_FLAG:
+			if(hdlc->cbin==hdlc->ffvalue){
+				hdlc->bit_shift = 0;
+				break;
+			} else {
+				if(hdlc->cbin == 0xff){
+					hdlc->state = HDLC_FAST_IDLE;
+					hdlc->bit_shift=0;
+				} else if(hdlc->ffbit_shift==8){
+					hdlc->state = HDLC_GETFLAG_B7;
+					break;
+				} else {
+					hdlc->shift_reg = fast_abort[hdlc->ffbit_shift-1];
+					hdlc->hdlc_bits1 = hdlc->ffbit_shift-2;
+					if(hdlc->hdlc_bits1<0)hdlc->hdlc_bits1 = 0;
+					hdlc->data_bits = hdlc->ffbit_shift-1;
+					hdlc->state = HDLC_GET_DATA;
+					hdlc->data_received = 0;
+				}
+			}
+			break;
+		default:
+			break;
+		}
+	}
+	*count -= slen;
+	return 0;
+}
+
+/*
+  isdnhdlc_encode - encodes HDLC frames to a transparent bit stream.
+
+  The bit stream starts with a beginning flag (01111110). After
+  that each byte is added to the bit stream with bit stuffing added
+  (0 after 5 1's).
+  When the last byte has been removed from the source buffer, the
+  CRC (2 bytes is added) and the frame terminates with the ending flag.
+  For the dchannel, the idle character (all 1's) is also added at the end.
+  If this function is called with empty source buffer (slen=0), flags or
+  idle character will be generated.
+
+  src - source buffer
+  slen - source buffer length
+  count - number of bytes removed (encoded) from source buffer
+  dst _ destination buffer
+  dsize - destination buffer size
+  returns - number of encoded bytes in the destination buffer
+*/
+int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src,
+		unsigned short slen, int *count,
+		unsigned char *dst, int dsize)
+{
+	static const unsigned char xfast_flag_value[] = {
+		0x7e,0x3f,0x9f,0xcf,0xe7,0xf3,0xf9,0xfc,0x7e
+	};
+
+	int len = 0;
+
+	*count = slen;
+
+	while (dsize > 0) {
+		if(hdlc->bit_shift==0){
+			if(slen && !hdlc->do_closing){
+				hdlc->shift_reg = *src++;
+				slen--;
+				if (slen == 0)
+					hdlc->do_closing = 1;  /* closing sequence, CRC + flag(s) */
+				hdlc->bit_shift = 8;
+			} else {
+				if(hdlc->state == HDLC_SEND_DATA){
+					if(hdlc->data_received){
+						hdlc->state = HDLC_SEND_CRC1;
+						hdlc->crc ^= 0xffff;
+						hdlc->bit_shift = 8;
+						hdlc->shift_reg = hdlc->crc & 0xff;
+					} else if(!hdlc->do_adapt56){
+						hdlc->state = HDLC_SEND_FAST_FLAG;
+					} else {
+						hdlc->state = HDLC_SENDFLAG_B0;
+					}
+				}
+
+			}
+		}
+
+		switch(hdlc->state){
+		case STOPPED:
+			while (dsize--)
+				*dst++ = 0xff;
+
+			return dsize;
+		case HDLC_SEND_FAST_FLAG:
+			hdlc->do_closing = 0;
+			if(slen == 0){
+				*dst++ = hdlc->ffvalue;
+				len++;
+				dsize--;
+				break;
+			}
+			if(hdlc->bit_shift==8){
+				hdlc->cbin = hdlc->ffvalue>>(8-hdlc->data_bits);
+				hdlc->state = HDLC_SEND_DATA;
+				hdlc->crc = 0xffff;
+				hdlc->hdlc_bits1 = 0;
+				hdlc->data_received = 1;
+			}
+			break;
+		case HDLC_SENDFLAG_B0:
+			hdlc->do_closing = 0;
+			hdlc->cbin <<= 1;
+			hdlc->data_bits++;
+			hdlc->hdlc_bits1 = 0;
+			hdlc->state = HDLC_SENDFLAG_B1A6;
+			break;
+		case HDLC_SENDFLAG_B1A6:
+			hdlc->cbin <<= 1;
+			hdlc->data_bits++;
+			hdlc->cbin++;
+			if(++hdlc->hdlc_bits1 == 6)
+				hdlc->state = HDLC_SENDFLAG_B7;
+			break;
+		case HDLC_SENDFLAG_B7:
+			hdlc->cbin <<= 1;
+			hdlc->data_bits++;
+			if(slen == 0){
+				hdlc->state = HDLC_SENDFLAG_B0;
+				break;
+			}
+			if(hdlc->bit_shift==8){
+				hdlc->state = HDLC_SEND_DATA;
+				hdlc->crc = 0xffff;
+				hdlc->hdlc_bits1 = 0;
+				hdlc->data_received = 1;
+			}
+			break;
+		case HDLC_SEND_FIRST_FLAG:
+			hdlc->data_received = 1;
+			if(hdlc->data_bits==8){
+				hdlc->state = HDLC_SEND_DATA;
+				hdlc->crc = 0xffff;
+				hdlc->hdlc_bits1 = 0;
+				break;
+			}
+			hdlc->cbin <<= 1;
+			hdlc->data_bits++;
+			if(hdlc->shift_reg & 0x01)
+				hdlc->cbin++;
+			hdlc->shift_reg >>= 1;
+			hdlc->bit_shift--;
+			if(hdlc->bit_shift==0){
+				hdlc->state = HDLC_SEND_DATA;
+				hdlc->crc = 0xffff;
+				hdlc->hdlc_bits1 = 0;
+			}
+			break;
+		case HDLC_SEND_DATA:
+			hdlc->cbin <<= 1;
+			hdlc->data_bits++;
+			if(hdlc->hdlc_bits1 == 5){
+				hdlc->hdlc_bits1 = 0;
+				break;
+			}
+			if(hdlc->bit_shift==8){
+				unsigned cval;
+
+				cval = (hdlc->crc^hdlc->shift_reg) & 0xff;
+				hdlc->crc = (hdlc->crc>>8)^crc16_tab[cval];
+			}
+			if(hdlc->shift_reg & 0x01){
+				hdlc->hdlc_bits1++;
+				hdlc->cbin++;
+				hdlc->shift_reg >>= 1;
+				hdlc->bit_shift--;
+			} else {
+				hdlc->hdlc_bits1 = 0;
+				hdlc->shift_reg >>= 1;
+				hdlc->bit_shift--;
+			}
+			break;
+		case HDLC_SEND_CRC1:
+			hdlc->cbin <<= 1;
+			hdlc->data_bits++;
+			if(hdlc->hdlc_bits1 == 5){
+				hdlc->hdlc_bits1 = 0;
+				break;
+			}
+			if(hdlc->shift_reg & 0x01){
+				hdlc->hdlc_bits1++;
+				hdlc->cbin++;
+				hdlc->shift_reg >>= 1;
+				hdlc->bit_shift--;
+			} else {
+				hdlc->hdlc_bits1 = 0;
+				hdlc->shift_reg >>= 1;
+				hdlc->bit_shift--;
+			}
+			if(hdlc->bit_shift==0){
+				hdlc->shift_reg = (hdlc->crc >> 8);
+				hdlc->state = HDLC_SEND_CRC2;
+				hdlc->bit_shift = 8;
+			}
+			break;
+		case HDLC_SEND_CRC2:
+			hdlc->cbin <<= 1;
+			hdlc->data_bits++;
+			if(hdlc->hdlc_bits1 == 5){
+				hdlc->hdlc_bits1 = 0;
+				break;
+			}
+			if(hdlc->shift_reg & 0x01){
+				hdlc->hdlc_bits1++;
+				hdlc->cbin++;
+				hdlc->shift_reg >>= 1;
+				hdlc->bit_shift--;
+			} else {
+				hdlc->hdlc_bits1 = 0;
+				hdlc->shift_reg >>= 1;
+				hdlc->bit_shift--;
+			}
+			if(hdlc->bit_shift==0){
+				hdlc->shift_reg = 0x7e;
+				hdlc->state = HDLC_SEND_CLOSING_FLAG;
+				hdlc->bit_shift = 8;
+			}
+			break;
+		case HDLC_SEND_CLOSING_FLAG:
+			hdlc->cbin <<= 1;
+			hdlc->data_bits++;
+			if(hdlc->hdlc_bits1 == 5){
+				hdlc->hdlc_bits1 = 0;
+				break;
+			}
+			if(hdlc->shift_reg & 0x01){
+				hdlc->cbin++;
+			}
+			hdlc->shift_reg >>= 1;
+			hdlc->bit_shift--;
+			if(hdlc->bit_shift==0){
+				hdlc->ffvalue = xfast_flag_value[hdlc->data_bits];
+				if(hdlc->dchannel){
+					hdlc->ffvalue = 0x7e;
+					hdlc->state = HDLC_SEND_IDLE1;
+					hdlc->bit_shift = 8-hdlc->data_bits;
+					if(hdlc->bit_shift==0)
+						hdlc->state = HDLC_SEND_FAST_IDLE;
+				} else {
+					if(!hdlc->do_adapt56){
+						hdlc->state = HDLC_SEND_FAST_FLAG;
+						hdlc->data_received = 0;
+					} else {
+						hdlc->state = HDLC_SENDFLAG_B0;
+						hdlc->data_received = 0;
+					}
+					// Finished with this frame, send flags
+					if (dsize > 1) dsize = 1;
+				}
+			}
+			break;
+		case HDLC_SEND_IDLE1:
+			hdlc->do_closing = 0;
+			hdlc->cbin <<= 1;
+			hdlc->cbin++;
+			hdlc->data_bits++;
+			hdlc->bit_shift--;
+			if(hdlc->bit_shift==0){
+				hdlc->state = HDLC_SEND_FAST_IDLE;
+				hdlc->bit_shift = 0;
+			}
+			break;
+		case HDLC_SEND_FAST_IDLE:
+			hdlc->do_closing = 0;
+			hdlc->cbin = 0xff;
+			hdlc->data_bits = 8;
+			if(hdlc->bit_shift == 8){
+				hdlc->cbin = 0x7e;
+				hdlc->state = HDLC_SEND_FIRST_FLAG;
+			} else {
+				*dst++ = hdlc->cbin;
+				hdlc->bit_shift = hdlc->data_bits = 0;
+				len++;
+				dsize = 0;
+			}
+			break;
+		default:
+			break;
+		}
+		if(hdlc->do_adapt56){
+			if(hdlc->data_bits==7){
+				hdlc->cbin <<= 1;
+				hdlc->cbin++;
+				hdlc->data_bits++;
+			}
+		}
+		if(hdlc->data_bits==8){
+			*dst++ = hdlc->cbin;
+			hdlc->data_bits = 0;
+			len++;
+			dsize--;
+		}
+	}
+	*count -= slen;
+
+	return len;
+}
+
+EXPORT_SYMBOL(isdnhdlc_bit_rev_tab);
+EXPORT_SYMBOL(isdnhdlc_rcv_init);
+EXPORT_SYMBOL(isdnhdlc_decode);
+EXPORT_SYMBOL(isdnhdlc_out_init);
+EXPORT_SYMBOL(isdnhdlc_encode);
diff -urN linux-2.4.21-pre3/drivers/isdn/hisax/isdnhdlc.h linux-2.4.21-pre4/drivers/isdn/hisax/isdnhdlc.h
--- linux-2.4.21-pre3/drivers/isdn/hisax/isdnhdlc.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/drivers/isdn/hisax/isdnhdlc.h	Tue Jan 28 19:44:30 2003
@@ -0,0 +1,72 @@
+/*
+ * isdnhdlc.h  --  General purpose ISDN HDLC decoder.
+ *
+ * Implementation of a HDLC decoder/encoder in software.
+ * Neccessary because some ISDN devices don't have HDLC
+ * controllers. Also included: a bit reversal table.
+ *
+ *Copyright (C) 2002    Wolfgang Mües      <wolfgang@iksw-muees.de>
+ *		2001 	Frode Isaksen      <fisaksen@bewan.com>
+ *              2001 	Kai Germaschewski  <kai.germaschewski@gmx.de>
+ *
+ *      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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __ISDNHDLC_H__
+#define __ISDNHDLC_H__
+
+struct isdnhdlc_vars {
+	int bit_shift;
+	int hdlc_bits1;
+	int data_bits;
+	int ffbit_shift; 	// encoding only
+	int state;
+	int dstpos;
+
+	unsigned short crc;
+
+	unsigned char cbin;
+	unsigned char shift_reg;
+	unsigned char ffvalue;
+
+	int data_received:1; 	// set if transferring data
+	int dchannel:1; 	// set if D channel (send idle instead of flags)
+	int do_adapt56:1; 	// set if 56K adaptation
+        int do_closing:1; 	// set if in closing phase (need to send CRC + flag
+};
+
+
+/*
+  The return value from isdnhdlc_decode is
+  the frame length, 0 if no complete frame was decoded,
+  or a negative error number
+*/
+#define HDLC_FRAMING_ERROR     1
+#define HDLC_CRC_ERROR         2
+#define HDLC_LENGTH_ERROR      3
+
+extern const unsigned char isdnhdlc_bit_rev_tab[256];
+
+extern void isdnhdlc_rcv_init (struct isdnhdlc_vars *hdlc, int do_adapt56);
+
+extern int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, int slen,int *count,
+	                    unsigned char *dst, int dsize);
+
+extern void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc,int is_d_channel,int do_adapt56);
+
+extern int isdnhdlc_encode (struct isdnhdlc_vars *hdlc,const unsigned char *src,unsigned short slen,int *count,
+	                    unsigned char *dst,int dsize);
+
+#endif /* __ISDNHDLC_H__ */
diff -urN linux-2.4.21-pre3/drivers/isdn/hisax/rawhdlc.c linux-2.4.21-pre4/drivers/isdn/hisax/rawhdlc.c
--- linux-2.4.21-pre3/drivers/isdn/hisax/rawhdlc.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.21-pre4/drivers/isdn/hisax/rawhdlc.c	Wed Dec 31 16:00:00 1969
@@ -1,543 +0,0 @@
-/* $Id: rawhdlc.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
- *
- * support routines for cards that don't support HDLC
- *
- * Author     Brent Baccala
- * Copyright  by Karsten Keil <keil@isdn4linux.de>
- *            by Brent Baccala <baccala@FreeSoft.org>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- *
- * Some passive ISDN cards, such as the Traverse NETJet and the AMD 7930,
- * don't perform HDLC encapsulation over the B channel.  Drivers for
- * such cards use support routines in this file to perform B channel HDLC.
- *
- * Bit-synchronous HDLC encapsulation is a means of encapsulating packets
- * over a continuously transmitting serial communications link.
- * It looks like this:
- *
- *      11111111101111110...........0111111011111111111
- *      iiiiiiiiiffffffffdddddddddddffffffffiiiiiiiiiii
- *
- *      i = idle     f = flag     d = data
- *
- * When idle, the channel sends a continuous string of ones (mark
- * idle; illustrated), or a continuous string of flag characters (flag
- * idle).  The beginning of a data frame is marked by a flag character
- * (01111110), then comes the actual data, followed by another flag
- * character, after which another frame may be sent immediately (a
- * single flag may serve as both the end of one frame and the start of
- * the next), or the link may return to idle.  Obviously, the flag
- * character can not appear anywhere in the data (or a false
- * end-of-frame would occur), so the transmitter performs
- * "bit-stuffing" - inserting a zero bit after every five one bits,
- * irregardless of the original bit after the five ones.  Byte
- * ordering is irrelevent at this point - the data is treated as a
- * string of bits, not bytes.  Since no more than 5 ones may now occur
- * in a row, the flag sequence, with its 6 ones, is unique.
- *
- * Upon reception, a zero bit that occur after 5 one bits is simply
- * discarded.  A series of 6 one bits is end-of-frame, and a series of
- * 7 one bits is an abort.  Once bit-stuffing has been corrected for,
- * an integer number of bytes should now be present.  The last two
- * of these bytes form the Frame Check Sequence, a CRC that is verified
- * and then discarded.  Note that bit-stuffing is performed on the FCS
- * just as if it were regular data.
- *
- *
- *
- * int make_raw_hdlc_data(u_char *src, u_int slen,
- *                        u_char *dst, u_int dsize)
- *
- *   Used for transmission.  Copies slen bytes from src to dst, performing
- *   HDLC encapsulation (flag bytes, bit-stuffing, CRC) in the process.
- *   dsize is size of destination buffer, and should be at least
- *   ((6*slen)/5)+5 bytes to ensure adequate space will be available.
- *   Function returns length (in bytes) of valid destination buffer, or
- *   0 upon destination overflow.
- *
- * void init_hdlc_state(struct hdlc_state *stateptr, int mode)
- *
- *   Initializes hdlc_state structure before first call to read_raw_hdlc_data
- *
- *   mode = 0: Sane mode
- *   mode = 1/2: 
- *             Insane mode; NETJet use a shared unsigned int memory block (
- * 	       with busmaster DMA), the bit pattern of every word is 
- *  	       <8 B1> <8 B2> <8 Mon> <2 D> <4 C/I> <MX> <MR>
- *	       according to Siemens IOM-2 interface, so we have to handle
- *             the src buffer as unsigned int and have to shift/mask the
- *             B-channel bytes.
- *             mode 1 -> B1  mode 2  -> B2 data is used
- *
- * int read_raw_hdlc_data(struct hdlc_state *saved_state,
- *                        u_char *src, u_int slen,
- *                        u_char *dst, u_int dsize)
- *
- *   Used for reception.  Scans source buffer bit-by-bit looking for
- *   valid HDLC frames, which are copied to destination buffer.  HDLC
- *   state information is stored in a structure, which allows this
- *   function to process frames spread across several blocks of raw
- *   HDLC data.  Part of the state information is bit offsets into
- *   the source and destination buffers.
- *
- *   A return value >0 indicates the length of a valid frame, now
- *   stored in the destination buffer.  In this case, the source
- *   buffer might not be completely processed, so this function should
- *   be called again with the same source buffer, possibly with a
- *   different destination buffer.
- *
- *   A return value of zero indicates that the source buffer was
- *   completely processed without finding a valid end-of-packet;
- *   however, we might be in the middle of packet reception, so
- *   the function should be called again with the next block of
- *   raw HDLC data and the same destination buffer.  It is NOT
- *   permitted to change the destination buffer in this case,
- *   since data may already have begun to be stored there.
- *
- *   A return value of -1 indicates some kind of error - destination
- *   buffer overflow, CRC check failed, frame not a multiple of 8
- *   bits.  Destination buffer probably contains invalid data, which
- *   should be discarded.  Call function again with same source buffer
- *   and a new (or same) destination buffer.
- *
- *   Suggested calling sequence:
- *
- *      init_hdlc_state(...);
- *      for (EACH_RAW_DATA_BLOCK) {
- *         while (len = read_raw_hdlc_data(...)) {
- *             if (len == -1) DISCARD_FRAME;
- *             else PROCESS_FRAME;
- *         }
- *      }
- *
- *
- * Test the code in this file as follows:
- *    gcc -DDEBUGME -o rawhdlctest rawhdlc.c
- *    ./rawhdlctest < rawdata
- *
- * The file "rawdata" can be easily generated from a HISAX B-channel
- * hex dump (CF CF CF 02 ...) using the following perl script:
- *
- * while(<>) {
- *     @hexlist = split ' ';
- *     while ($hexstr = shift(@hexlist)) {
- *         printf "%c", hex($hexstr);
- *     }
- * }
- *
- */
-
-#ifdef DEBUGME
-#include <stdio.h>
-#endif
-
-#include <linux/types.h>
-#include <linux/ppp_defs.h>
-#include "rawhdlc.h"
-
-/* There's actually an identical copy of this table in the PPP code
- * (ppp_crc16_table), but I don't want this code dependent on PPP
- */
-
-// static 
-__u16 fcstab[256] =
-{
-	0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
-	0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
-	0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
-	0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
-	0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
-	0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
-	0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
-	0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
-	0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
-	0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
-	0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
-	0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
-	0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
-	0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
-	0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
-	0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
-	0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
-	0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
-	0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
-	0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
-	0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
-	0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
-	0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
-	0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
-	0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
-	0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
-	0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
-	0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
-	0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
-	0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
-	0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
-	0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
-};
-
-#define HDLC_ZERO_SEARCH 0
-#define HDLC_FLAG_SEARCH 1
-#define HDLC_FLAG_FOUND  2
-#define HDLC_FRAME_FOUND 3
-#define HDLC_NULL 4
-#define HDLC_PART 5
-#define HDLC_FULL 6
-
-#define HDLC_FLAG_VALUE	0x7e
-
-
-#define MAKE_RAW_BYTE for (j=0; j<8; j++) { \
-			bitcnt++;\
-			out_val >>= 1;\
-			if (val & 1) {\
-				s_one++;\
-				out_val |= 0x80;\
-			} else {\
-				s_one = 0;\
-				out_val &= 0x7f;\
-			}\
-			if (bitcnt==8) {\
-				if (d_cnt == dsize) return 0;\
-				dst[d_cnt++] = out_val;\
-				bitcnt = 0;\
-			}\
-			if (s_one == 5) {\
-				out_val >>= 1;\
-				out_val &= 0x7f;\
-				bitcnt++;\
-				s_one = 0;\
-			}\
-			if (bitcnt==8) {\
-				if (d_cnt == dsize) return 0;\
-				dst[d_cnt++] = out_val;\
-				bitcnt = 0;\
-			}\
-			val >>= 1;\
-		}
-
-/* Optimization suggestion: If needed, this function could be
- * dramatically sped up using a state machine.  Each state would
- * correspond to having seen N one bits, and being offset M bits into
- * the current output byte.  N ranges from 0 to 4, M from 0 to 7, so
- * we need 5*8 = 35 states.  Each state would have a table with 256
- * entries, one for each input character.  Each entry would contain
- * three output characters, an output state, an a byte increment
- * that's either 1 or 2.  All this could fit in four bytes; so we need
- * 4 bytes * 256 characters = 1 KB for each state (35 KB total).  Zero
- * the output buffer before you start.  For each character in your
- * input, you look it up in the current state's table and get three
- * bytes to be or'ed into the output at the current byte offset, and
- * an byte increment to move your pointer forward.  A simple Perl
- * script could generate the tables.  Given HDLC semantics, probably
- * would be better to set output to all 1s, then use ands instead of ors.
- * A smaller state machine could operate on nibbles instead of bytes.
- * A state machine for 32-bit architectures could use word offsets
- * instead of byte offsets, requiring 5*32 = 160 states; probably
- * best to work on nibbles in such a case.
- */
-
-
-int make_raw_hdlc_data(u_char *src, u_int slen, u_char *dst, u_int dsize)
-{
-	register u_int i,d_cnt=0;
-	register u_char j;
-	register u_char val;
-	register u_char s_one = 0;
-	register u_char out_val = 0;
-	register u_char bitcnt = 0;
-	u_int fcs;
-	
-	
-	dst[d_cnt++] = HDLC_FLAG_VALUE;
-	fcs = PPP_INITFCS;
-	for (i=0; i<slen; i++) {
-		val = src[i];
-		fcs = PPP_FCS (fcs, val);
-		MAKE_RAW_BYTE;
-	}
-	fcs ^= 0xffff;
-	val = fcs & 0xff;
-	MAKE_RAW_BYTE;
-	val = (fcs>>8) & 0xff;
-	MAKE_RAW_BYTE;
-	val = HDLC_FLAG_VALUE;
-	for (j=0; j<8; j++) { 
-		bitcnt++;
-		out_val >>= 1;
-		if (val & 1)
-			out_val |= 0x80;
-		else
-			out_val &= 0x7f;
-		if (bitcnt==8) {
-			if (d_cnt == dsize) return 0;
-			dst[d_cnt++] = out_val;
-			bitcnt = 0;
-		}
-		val >>= 1;
-	}
-	if (bitcnt) {
-		while (8>bitcnt++) {
-			out_val >>= 1;
-			out_val |= 0x80;
-		}
-		if (d_cnt == dsize) return 0;
-		dst[d_cnt++] = out_val;
-	}
-
-	return d_cnt;
-}
-
-void init_hdlc_state(struct hdlc_state *stateptr, int mode)
-{
-	stateptr->state = HDLC_ZERO_SEARCH;
-	stateptr->r_one = 0;
-	stateptr->r_val = 0;
-	stateptr->o_bitcnt = 0;
-	stateptr->i_bitcnt = 0;
-	stateptr->insane_mode = mode;
-}
-
-/* Optimization suggestion: A similar state machine could surely
- * be developed for this function as well.
- */
-
-int read_raw_hdlc_data(struct hdlc_state *saved_state,
-                       u_char *src, u_int slen, u_char *dst, u_int dsize)
-{
-	int retval=0;
-	register u_char val;
-	register u_char state = saved_state->state;
-	register u_char r_one = saved_state->r_one;
-	register u_char r_val = saved_state->r_val;
-	register u_int o_bitcnt = saved_state->o_bitcnt;
-	register u_int i_bitcnt = saved_state->i_bitcnt;
-	register u_int fcs    = saved_state->fcs;
-	register u_int *isrc = (u_int *) src;
-        
-	/* Use i_bitcnt (bit offset into source buffer) to reload "val"
-	 * in case we're starting up again partway through a source buffer
-	 */
-
-	if ((i_bitcnt >> 3) < slen) {
-		if (saved_state->insane_mode==1) {
-			val = isrc[(i_bitcnt >> 3)] & 0xff;
-		} else if (saved_state->insane_mode==2) {
-			val = (isrc[i_bitcnt >> 3] >>8) & 0xff;
-		} else {
-			val = src[i_bitcnt >> 3];
-		}
-		val >>= i_bitcnt & 7;
-	}
-
-	/* One bit per loop.  Keep going until we've got something to
-	 * report (retval != 0), or we exhaust the source buffer
-	 */
-
-	while ((retval == 0) && ((i_bitcnt >> 3) < slen)) {
-		if ((i_bitcnt & 7) == 0) {
-			if (saved_state->insane_mode==1) {
-				val = isrc[(i_bitcnt >> 3)] & 0xff;
-			} else if (saved_state->insane_mode==2) {
-				val = (isrc[i_bitcnt >> 3] >>8) & 0xff;
-			} else {
-				val = src[i_bitcnt >> 3];
-			}
-#ifdef DEBUGME
-			printf("Input byte %d: 0x%2x\n", i_bitcnt>>3, val);
-#endif
-			if (val == 0xff) {
-				state = HDLC_ZERO_SEARCH;
-				o_bitcnt = 0;
-				r_one = 0;
-				i_bitcnt += 8;
-				continue;
-			}
-		}
-
-#ifdef DEBUGME
-		/* printf("Data bit=%d (%d/%d)\n", val&1, i_bitcnt>>3, i_bitcnt&7);*/
-#endif
-
-		if (state == HDLC_ZERO_SEARCH) {
-			if (val & 1) {
-				r_one++;
-			} else {
-				r_one=0;
-				state= HDLC_FLAG_SEARCH;
-			}
-		} else if (state == HDLC_FLAG_SEARCH) { 
-			if (val & 1) {
-				r_one++;
-				if (r_one>6) {
-					state=HDLC_ZERO_SEARCH;
-				}
-			} else {
-				if (r_one==6) {
-					o_bitcnt=0;
-					r_val=0;
-					state=HDLC_FLAG_FOUND;
-				}
-				r_one=0;
-			}
-		} else if (state ==  HDLC_FLAG_FOUND) {
-			if (val & 1) {
-				r_one++;
-				if (r_one>6) {
-					state=HDLC_ZERO_SEARCH;
-				} else {
-					r_val >>= 1;
-					r_val |= 0x80;
-					o_bitcnt++;
-				}
-			} else {
-				if (r_one==6) {
-					o_bitcnt=0;
-					r_val=0;
-					r_one=0;
-					i_bitcnt++;
-					val >>= 1;
-					continue;
-				} else if (r_one!=5) {
-					r_val >>= 1;
-					r_val &= 0x7f;
-					o_bitcnt++;
-				}
-				r_one=0;	
-			}
-			if ((state != HDLC_ZERO_SEARCH) &&
-				!(o_bitcnt & 7)) {
-#ifdef DEBUGME
-				printf("HDLC_FRAME_FOUND at i_bitcnt:%d\n",i_bitcnt);
-#endif
-				state=HDLC_FRAME_FOUND;
-				fcs = PPP_INITFCS;
-				dst[0] = r_val;
-				fcs = PPP_FCS (fcs, r_val);
-			}
-		} else if (state ==  HDLC_FRAME_FOUND) {
-			if (val & 1) {
-				r_one++;
-				if (r_one>6) {
-					state=HDLC_ZERO_SEARCH;
-					o_bitcnt=0;
-				} else {
-					r_val >>= 1;
-					r_val |= 0x80;
-					o_bitcnt++;
-				}
-			} else {
-				if (r_one==6) {
-					r_val=0; 
-					r_one=0;
-					o_bitcnt++;
-					if (o_bitcnt & 7) {
-						/* Alignment error */
-#ifdef DEBUGME
-						printf("Alignment error\n");
-#endif
-						state=HDLC_FLAG_SEARCH;
-						retval = -1;
-					} else if (fcs==PPP_GOODFCS) {
-						/* Valid frame */
-						state=HDLC_FLAG_FOUND;
-						retval = (o_bitcnt>>3)-3;
-					} else {
-						/* CRC error */
-#ifdef DEBUGME
-						printf("CRC error; fcs was 0x%x, should have been 0x%x\n", fcs, PPP_GOODFCS);
-#endif
-						state=HDLC_FLAG_FOUND;
-						retval = -1;
-					}
-				} else if (r_one==5) {
-					r_one=0;
-					i_bitcnt++;
-					val >>= 1;
-					continue;
-				} else {
-					r_val >>= 1;
-					r_val &= 0x7f;
-					o_bitcnt++;
-				}
-				r_one=0;	
-			}
-			if ((state == HDLC_FRAME_FOUND) &&
-				!(o_bitcnt & 7)) {
-				if ((o_bitcnt>>3)>=dsize) {
-					/* Buffer overflow error */
-#ifdef DEBUGME
-					printf("Buffer overflow error\n");
-#endif
-					r_val=0; 
-					state=HDLC_FLAG_SEARCH;
-					retval = -1;
-				} else {
-					dst[(o_bitcnt>>3)-1] = r_val;
-					fcs = PPP_FCS (fcs, r_val);
-#ifdef DEBUGME
-					printf("Output byte %d: 0x%02x; FCS 0x%04x\n", (o_bitcnt>>3)-1, r_val, fcs);
-#endif
-				}
-			}
-		}
-		i_bitcnt ++;
-		val >>= 1;
-	}
-
-	/* We exhausted the source buffer before anything else happened
-	 * (retval==0).  Reset i_bitcnt in expectation of a new source
-	 * buffer.  Other, we either had an error or a valid frame, so
-	 * reset o_bitcnt in expectation of a new destination buffer.
-	 */
-
-	if (retval == 0) {
-		i_bitcnt = 0;
-	} else {
-		o_bitcnt = 0;
-	}
-
-	saved_state->state = state;
-	saved_state->r_one = r_one;
-	saved_state->r_val = r_val;
-	saved_state->fcs = fcs;
-	saved_state->o_bitcnt = o_bitcnt;
-	saved_state->i_bitcnt = i_bitcnt;
-
-	return (retval);
-}
-
-
-
-#ifdef DEBUGME
-
-char buffer[1024];
-char obuffer[1024];
-
-main()
-{
-  int buflen=0;
-  int len;
-  struct hdlc_state hdlc_state;
-
-  while((buffer[buflen] = getc(stdin)) != EOF && buflen<1024) buflen++;
-
-  printf("buflen = %d\n", buflen);
-
-  init_hdlc_state(&hdlc_state, 0);
-
-  while (len = read_raw_hdlc_data(&hdlc_state,buffer,buflen,obuffer,1024)) {
-    if (len == -1) printf("Error @ byte %d/bit %d\n",
-			  hdlc_state.i_bitcnt>>3, hdlc_state.i_bitcnt & 7);
-    else {
-      printf("Frame received: len %d\n", len);
-    }
-  }
-
-  printf("Done\n");
-}
-
-#endif
diff -urN linux-2.4.21-pre3/drivers/isdn/hisax/rawhdlc.h linux-2.4.21-pre4/drivers/isdn/hisax/rawhdlc.h
--- linux-2.4.21-pre3/drivers/isdn/hisax/rawhdlc.h	Fri Dec 21 09:41:54 2001
+++ linux-2.4.21-pre4/drivers/isdn/hisax/rawhdlc.h	Wed Dec 31 16:00:00 1969
@@ -1,28 +0,0 @@
-/* $Id: rawhdlc.h,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
- *
- * Author     Brent Baccala
- * Copyright  by Brent Baccala <baccala@FreeSoft.org>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#ifndef RAWHDLC_H
-struct hdlc_state {
-	char insane_mode;
-	u_char state;
-	u_char r_one;
-	u_char r_val;
-	u_int o_bitcnt;
-	u_int i_bitcnt;
-	u_int fcs;
-};
-
-
-int make_raw_hdlc_data(u_char *src, u_int slen, u_char *dst, u_int dsize);
-void init_hdlc_state(struct hdlc_state *stateptr, int mode);
-int read_raw_hdlc_data(struct hdlc_state *saved_state,
-                       u_char *src, u_int slen, u_char *dst, u_int dsize);
-#define RAWHDLC_H
-#endif
diff -urN linux-2.4.21-pre3/drivers/isdn/hisax/st5481.h linux-2.4.21-pre4/drivers/isdn/hisax/st5481.h
--- linux-2.4.21-pre3/drivers/isdn/hisax/st5481.h	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre4/drivers/isdn/hisax/st5481.h	Tue Jan 28 19:44:30 2003
@@ -227,7 +227,7 @@
 #define INFO(format, arg...) \
 printk(KERN_INFO __FILE__ ": " __FUNCTION__ ": " format "\n" , ## arg)
 
-#include "st5481_hdlc.h"
+#include "isdnhdlc.h"
 #include "fsm.h"
 #include "hisax_if.h"
 #include <linux/skbuff.h>
@@ -236,7 +236,7 @@
  * FIFO handling
  */
 
-/* Generic FIFO structure */ 
+/* Generic FIFO structure */
 struct fifo {
 	u_char r,w,count,size;
 	spinlock_t lock;
@@ -270,7 +270,7 @@
 		index = -1;
 	} else {
 		// Return index where to get the next data to add to the FIFO
-		index = fifo->w++ & (fifo->size-1); 
+		index = fifo->w++ & (fifo->size-1);
 		fifo->count++;
 	}
 	spin_unlock_irqrestore(&fifo->lock, flags);
@@ -289,13 +289,13 @@
 		return -1;
 	}
 
-	spin_lock_irqsave(&fifo->lock, flags);		
+	spin_lock_irqsave(&fifo->lock, flags);
 	if (!fifo->count) {
 		// FIFO empty
 		index = -1;
 	} else {
 		// Return index where to get the next data from the FIFO
-		index = fifo->r++ & (fifo->size-1); 
+		index = fifo->r++ & (fifo->size-1);
 		fifo->count--;
 	}
 	spin_unlock_irqrestore(&fifo->lock, flags);
@@ -336,7 +336,7 @@
 };
 
 struct st5481_d_out {
-	struct hdlc_vars hdlc_state;
+	struct isdnhdlc_vars hdlc_state;
 	struct urb *urb[2]; /* double buffering */
 	unsigned long busy;
 	struct sk_buff *tx_skb;
@@ -344,7 +344,7 @@
 };
 
 struct st5481_b_out {
-	struct hdlc_vars hdlc_state;
+	struct isdnhdlc_vars hdlc_state;
 	struct urb *urb[2]; /* double buffering */
 	u_char flow_event;
 	u_long busy;
@@ -352,7 +352,7 @@
 };
 
 struct st5481_in {
-	struct hdlc_vars hdlc_state;
+	struct isdnhdlc_vars hdlc_state;
 	struct urb *urb[2]; /* double buffering */
 	int mode;
 	int bufsize;
diff -urN linux-2.4.21-pre3/drivers/isdn/hisax/st5481_b.c linux-2.4.21-pre4/drivers/isdn/hisax/st5481_b.c
--- linux-2.4.21-pre3/drivers/isdn/hisax/st5481_b.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.21-pre4/drivers/isdn/hisax/st5481_b.c	Tue Jan 28 19:44:30 2003
@@ -67,24 +67,28 @@
 				bytes_sent = buf_size - len;
 				if (skb->len < bytes_sent)
 					bytes_sent = skb->len;
-
-				memcpy(urb->transfer_buffer+len, skb->data, bytes_sent);
-				
+				{	/* swap tx bytes to get hearable audio data */
+					register unsigned char *src  = skb->data;
+					register unsigned char *dest = urb->transfer_buffer+len;
+					register unsigned int count;
+					for (count = 0; count < bytes_sent; count++)
+						*dest++ = isdnhdlc_bit_rev_tab[*src++];
+				}
 				len += bytes_sent;
 			} else {
-				len += hdlc_encode(&b_out->hdlc_state, 
-						   skb->data, skb->len, &bytes_sent,
-						   urb->transfer_buffer+len, buf_size-len);
+				len += isdnhdlc_encode(&b_out->hdlc_state,
+						       skb->data, skb->len, &bytes_sent,
+						       urb->transfer_buffer+len, buf_size-len);
 			}
 
 			skb_pull(skb, bytes_sent);
-			
+
 			if (!skb->len) {
 				// Frame sent
 				b_out->tx_skb = NULL;
 				B_L1L2(bcs, PH_DATA | CONFIRM, (void *) skb->truesize);
 				dev_kfree_skb_any(skb);
-				
+
 /* 				if (!(bcs->tx_skb = skb_dequeue(&bcs->sq))) { */
 /* 					st5481B_sched_event(bcs, B_XMTBUFREADY); */
 /* 				} */
@@ -95,9 +99,9 @@
 				len = buf_size;
 			} else {
 				// Send flags
-				len += hdlc_encode(&b_out->hdlc_state, 
-						   NULL, 0, &bytes_sent,
-						   urb->transfer_buffer+len, buf_size-len);
+				len += isdnhdlc_encode(&b_out->hdlc_state,
+						       NULL, 0, &bytes_sent,
+						       urb->transfer_buffer+len, buf_size-len);
 			}
 		}	
 	}
@@ -209,7 +213,7 @@
 	if (bcs->mode != L1_MODE_NULL) {
 		// Open the B channel
 		if (bcs->mode != L1_MODE_TRANS) {
-			hdlc_out_init(&b_out->hdlc_state, 0, bcs->mode == L1_MODE_HDLC_56K);
+			isdnhdlc_out_init(&b_out->hdlc_state, 0, bcs->mode == L1_MODE_HDLC_56K);
 		}
 		st5481_usb_pipe_reset(adapter, (bcs->channel+1)*2, NULL, NULL);
 	
diff -urN linux-2.4.21-pre3/drivers/isdn/hisax/st5481_d.c linux-2.4.21-pre4/drivers/isdn/hisax/st5481_d.c
--- linux-2.4.21-pre3/drivers/isdn/hisax/st5481_d.c	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre4/drivers/isdn/hisax/st5481_d.c	Tue Jan 28 19:44:30 2003
@@ -313,15 +313,15 @@
 	buf_size = NUM_ISO_PACKETS_D * SIZE_ISO_PACKETS_D_OUT;
 	
 	if (skb) {
-		len = hdlc_encode(&d_out->hdlc_state, 
-				  skb->data, skb->len, &bytes_sent,
-				  urb->transfer_buffer, buf_size);
+		len = isdnhdlc_encode(&d_out->hdlc_state,
+				      skb->data, skb->len, &bytes_sent,
+				      urb->transfer_buffer, buf_size);
 		skb_pull(skb,bytes_sent);
 	} else {
 		// Send flags or idle
-		len = hdlc_encode(&d_out->hdlc_state, 
-				  NULL, 0, &bytes_sent,
-				  urb->transfer_buffer, buf_size);
+		len = isdnhdlc_encode(&d_out->hdlc_state,
+				      NULL, 0, &bytes_sent,
+				      urb->transfer_buffer, buf_size);
 	}
 	
 	if (len < buf_size) {
@@ -413,7 +413,7 @@
 
 	DBG(2,"len=%d",skb->len);
 
-	hdlc_out_init(&d_out->hdlc_state, 1, 0);
+	isdnhdlc_out_init(&d_out->hdlc_state, 1, 0);
 
 	if (test_and_set_bit(buf_nr, &d_out->busy)) {
 		WARN("ep %d urb %d busy %#lx", EP_D_OUT, buf_nr, d_out->busy);
@@ -422,9 +422,9 @@
 	urb = d_out->urb[buf_nr];
 
 	DBG_SKB(0x10, skb);
-	len = hdlc_encode(&d_out->hdlc_state, 
-			  skb->data, skb->len, &bytes_sent,
-			  urb->transfer_buffer, 16);
+	len = isdnhdlc_encode(&d_out->hdlc_state,
+			      skb->data, skb->len, &bytes_sent,
+			      urb->transfer_buffer, 16);
 	skb_pull(skb, bytes_sent);
 
 	if(len < 16)
diff -urN linux-2.4.21-pre3/drivers/isdn/hisax/st5481_init.c linux-2.4.21-pre4/drivers/isdn/hisax/st5481_init.c
--- linux-2.4.21-pre3/drivers/isdn/hisax/st5481_init.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.21-pre4/drivers/isdn/hisax/st5481_init.c	Tue Jan 28 19:44:30 2003
@@ -14,7 +14,6 @@
  * TODO:
  *
  * b layer1 delay?
- * hdlc as module
  * hotplug / unregister issues
  * mod_inc/dec_use_count
  * unify parts of d/b channel usb handling
diff -urN linux-2.4.21-pre3/drivers/isdn/hisax/st5481_usb.c linux-2.4.21-pre4/drivers/isdn/hisax/st5481_usb.c
--- linux-2.4.21-pre3/drivers/isdn/hisax/st5481_usb.c	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre4/drivers/isdn/hisax/st5481_usb.c	Tue Jan 28 19:44:30 2003
@@ -484,16 +484,18 @@
 	ptr = urb->transfer_buffer;
 	while (len > 0) {
 		if (in->mode == L1_MODE_TRANS) {
-			memcpy(in->rcvbuf, ptr, len);
+			/* swap rx bytes to get hearable audio */
+			register unsigned char *dest = in->rcvbuf;
 			status = len;
-			len = 0;
+			for (; len; len--)
+				*dest++ = isdnhdlc_bit_rev_tab[*ptr++];
 		} else {
-			status = hdlc_decode(&in->hdlc_state, ptr, len, &count,
-					     in->rcvbuf, in->bufsize);
+			status = isdnhdlc_decode(&in->hdlc_state, ptr, len, &count,
+					         in->rcvbuf, in->bufsize);
 			ptr += count;
 			len -= count;
 		}
-		
+
 		if (status > 0) {
 			// Good frame received
 			DBG(4,"count=%d",status);
@@ -622,8 +624,8 @@
 
 	if (in->mode != L1_MODE_NULL) {
 		if (in->mode != L1_MODE_TRANS)
-			hdlc_rcv_init(&in->hdlc_state,
-				      in->mode == L1_MODE_HDLC_56K);
+			isdnhdlc_rcv_init(&in->hdlc_state,
+				          in->mode == L1_MODE_HDLC_56K);
 		
 		st5481_usb_pipe_reset(in->adapter, in->ep, NULL, NULL);
 		st5481_usb_device_ctrl_msg(in->adapter, in->counter,
diff -urN linux-2.4.21-pre3/drivers/isdn/isdn_audio.c linux-2.4.21-pre4/drivers/isdn/isdn_audio.c
--- linux-2.4.21-pre3/drivers/isdn/isdn_audio.c	Mon Feb 25 11:37:58 2002
+++ linux-2.4.21-pre4/drivers/isdn/isdn_audio.c	Tue Jan 28 19:44:30 2003
@@ -169,39 +169,19 @@
 	0x8a, 0x8a, 0x6a, 0x6a, 0xea, 0xea, 0x2a, 0x2a
 };
 
-#define NCOEFF           16     /* number of frequencies to be analyzed       */
-#define DTMF_TRESH    25000     /* above this is dtmf                         */
+#define NCOEFF            8     /* number of frequencies to be analyzed       */
+#define DTMF_TRESH     4000     /* above this is dtmf                         */
 #define SILENCE_TRESH   200     /* below this is silence                      */
-#define H2_TRESH      20000     /* 2nd harmonic                               */
 #define AMP_BITS          9     /* bits per sample, reduced to avoid overflow */
 #define LOGRP             0
 #define HIGRP             1
 
-typedef struct {
-	int grp;                /* low/high group     */
-	int k;                  /* k                  */
-	int k2;                 /* k fuer 2. harmonic */
-} dtmf_t;
-
 /* For DTMF recognition:
  * 2 * cos(2 * PI * k / N) precalculated for all k
  */
 static int cos2pik[NCOEFF] =
 {
-	55812, 29528, 53603, 24032, 51193, 14443, 48590, 6517,
-	38113, -21204, 33057, -32186, 25889, -45081, 18332, -55279
-};
-
-static dtmf_t dtmf_tones[8] =
-{
-	{LOGRP, 0, 1},          /*  697 Hz */
-	{LOGRP, 2, 3},          /*  770 Hz */
-	{LOGRP, 4, 5},          /*  852 Hz */
-	{LOGRP, 6, 7},          /*  941 Hz */
-	{HIGRP, 8, 9},          /* 1209 Hz */
-	{HIGRP, 10, 11},        /* 1336 Hz */
-	{HIGRP, 12, 13},        /* 1477 Hz */
-	{HIGRP, 14, 15}         /* 1633 Hz */
+	55813, 53604, 51193, 48591, 38114, 33057, 25889, 18332
 };
 
 static char dtmf_matrix[4][4] =
@@ -499,6 +479,18 @@
 			sk2 = sk1;
 			sk1 = sk;
 		}
+		/* Avoid overflows */
+		sk >>= 1;
+		sk2 >>= 1;
+		/* compute |X(k)|**2 */
+		/* report overflows. This should not happen. */
+		/* Comment this out if desired */
+		if (sk < -32768 || sk > 32767)
+			printk(KERN_DEBUG
+			       "isdn_audio: dtmf goertzel overflow, sk=%d\n", sk);
+		if (sk2 < -32768 || sk2 > 32767)
+			printk(KERN_DEBUG
+			       "isdn_audio: dtmf goertzel overflow, sk2=%d\n", sk2);
 		result[k] =
 		    ((sk * sk) >> AMP_BITS) -
 		    ((((cos2pik[k] * sk) >> 15) * sk2) >> AMP_BITS) +
@@ -522,28 +514,58 @@
 	int grp[2];
 	char what;
 	char *p;
+	int thresh;
 
 	while ((skb = skb_dequeue(&info->dtmf_queue))) {
 		result = (int *) skb->data;
 		s = info->dtmf_state;
-		grp[LOGRP] = grp[HIGRP] = -2;
+		grp[LOGRP] = grp[HIGRP] = -1;
 		silence = 0;
-		for (i = 0; i < 8; i++) {
-			if ((result[dtmf_tones[i].k] > DTMF_TRESH) &&
-			    (result[dtmf_tones[i].k2] < H2_TRESH))
-				grp[dtmf_tones[i].grp] = (grp[dtmf_tones[i].grp] == -2) ? i : -1;
-			else if ((result[dtmf_tones[i].k] < SILENCE_TRESH) &&
-			      (result[dtmf_tones[i].k2] < SILENCE_TRESH))
+		thresh = 0;
+		for (i = 0; i < NCOEFF; i++) {
+			if (result[i] > DTMF_TRESH) {
+				if (result[i] > thresh)
+					thresh = result[i];
+			}
+			else if (result[i] < SILENCE_TRESH)
 				silence++;
 		}
-		if (silence == 8)
+		if (silence == NCOEFF)
 			what = ' ';
 		else {
-			if ((grp[LOGRP] >= 0) && (grp[HIGRP] >= 0)) {
-				what = dtmf_matrix[grp[LOGRP]][grp[HIGRP] - 4];
-				if (s->last != ' ' && s->last != '.')
-					s->last = what;	/* min. 1 non-DTMF between DTMF */
-			} else
+			if (thresh > 0)	{
+				thresh = thresh >> 4;  /* touchtones must match within 12 dB */
+				for (i = 0; i < NCOEFF; i++) {
+					if (result[i] < thresh)
+						continue;  /* ignore */
+					/* good level found. This is allowed only one time per group */
+					if (i < NCOEFF / 2) {
+						/* lowgroup*/
+						if (grp[LOGRP] >= 0) {
+							// Bad. Another tone found. */
+							grp[LOGRP] = -1;
+							break;
+						}
+						else
+							grp[LOGRP] = i;
+					}
+					else { /* higroup */
+						if (grp[HIGRP] >= 0) { // Bad. Another tone found. */
+							grp[HIGRP] = -1;
+							break;
+						}
+						else
+							grp[HIGRP] = i - NCOEFF/2;
+					}
+				}
+				if ((grp[LOGRP] >= 0) && (grp[HIGRP] >= 0)) {
+					what = dtmf_matrix[grp[LOGRP]][grp[HIGRP]];
+					if (s->last != ' ' && s->last != '.')
+						s->last = what;	/* min. 1 non-DTMF between DTMF */
+				} else
+					what = '.';
+			}
+			else
 				what = '.';
 		}
 		if ((what != s->last) && (what != ' ') && (what != '.')) {
diff -urN linux-2.4.21-pre3/drivers/isdn/isdn_audio.h linux-2.4.21-pre4/drivers/isdn/isdn_audio.h
--- linux-2.4.21-pre3/drivers/isdn/isdn_audio.h	Fri Dec 21 09:41:54 2001
+++ linux-2.4.21-pre4/drivers/isdn/isdn_audio.h	Tue Jan 28 19:44:30 2003
@@ -20,6 +20,7 @@
 
 typedef struct dtmf_state {
 	char last;
+	char llast;
 	int idx;
 	int buf[DTMF_NPOINTS];
 } dtmf_state;
diff -urN linux-2.4.21-pre3/drivers/md/md.c linux-2.4.21-pre4/drivers/md/md.c
--- linux-2.4.21-pre3/drivers/md/md.c	Tue Jan 28 19:44:25 2003
+++ linux-2.4.21-pre4/drivers/md/md.c	Tue Jan 28 19:44:30 2003
@@ -2617,21 +2617,8 @@
 			goto done;
 #endif
 
-		case BLKGETSIZE:	/* Return device size */
-			if (!arg) {
-				err = -EINVAL;
-				MD_BUG();
-				goto abort;
-			}
-			err = md_put_user(md_hd_struct[minor].nr_sects,
-						(unsigned long *) arg);
-			goto done;
-
-		case BLKGETSIZE64:	/* Return device size */
-			err = md_put_user((u64)md_hd_struct[minor].nr_sects << 9,
-						(u64 *) arg);
-			goto done;
-
+		case BLKGETSIZE:
+		case BLKGETSIZE64:
 		case BLKRAGET:
 		case BLKRASET:
 		case BLKFLSBUF:
diff -urN linux-2.4.21-pre3/drivers/media/video/Makefile linux-2.4.21-pre4/drivers/media/video/Makefile
--- linux-2.4.21-pre3/drivers/media/video/Makefile	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre4/drivers/media/video/Makefile	Tue Jan 28 19:44:30 2003
@@ -35,7 +35,7 @@
 
 obj-$(CONFIG_BUS_I2C) += i2c-old.o
 obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tvaudio.o \
-	tda7432.o tda9875.o tuner.o
+	tda7432.o tda9875.o tda9887.o tuner.o
 obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o
 
 obj-$(CONFIG_VIDEO_ZR36120) += zoran.o
diff -urN linux-2.4.21-pre3/drivers/media/video/audiochip.h linux-2.4.21-pre4/drivers/media/video/audiochip.h
--- linux-2.4.21-pre3/drivers/media/video/audiochip.h	Sun Nov 12 20:47:19 2000
+++ linux-2.4.21-pre4/drivers/media/video/audiochip.h	Tue Jan 28 19:44:30 2003
@@ -30,41 +30,7 @@
  * make sense in v4l context only.  So I think that's acceptable...
  */
 
-#if 0
-
-/* TODO (if it is ever [to be] accessible in the V4L[2] spec):
- *   maybe fade? (back/front)
- * notes:
- * NEWCHANNEL and SWITCH_MUTE are here because the MSP3400 has a special
- * routine to go through when it tunes in to a new channel before turning
- * back on the sound.
- * Either SET_RADIO, NEWCHANNEL, and SWITCH_MUTE or SET_INPUT need to be
- * implemented (MSP3400 uses SET_RADIO to select inputs, and SWITCH_MUTE for
- * channel-change mute -- TEA6300 et al use SET_AUDIO to select input [TV, 
- * radio, external, or MUTE]).  If both methods are implemented, you get a
- * cookie for doing such a good job! :)
- */
-
-#define AUDC_SET_TVNORM       _IOW('m',1,int)  /* TV mode + PAL/SECAM/NTSC  */
-#define AUDC_NEWCHANNEL       _IO('m',3)       /* indicate new chan - off mute */
-
-#define AUDC_GET_VOLUME_LEFT  _IOR('m',4,__u16)
-#define AUDC_GET_VOLUME_RIGHT _IOR('m',5,__u16)
-#define AUDC_SET_VOLUME_LEFT  _IOW('m',6,__u16)
-#define AUDC_SET_VOLUME_RIGHT _IOW('m',7,__u16)
-
-#define AUDC_GET_STEREO       _IOR('m',8,__u16)
-#define AUDC_SET_STEREO       _IOW('m',9,__u16)
-
-#define AUDC_GET_DC           _IOR('m',10,__u16)/* ??? */
-
-#define AUDC_GET_BASS         _IOR('m',11,__u16)
-#define AUDC_SET_BASS         _IOW('m',12,__u16)
-#define AUDC_GET_TREBLE       _IOR('m',13,__u16)
-#define AUDC_SET_TREBLE       _IOW('m',14,__u16)
-
-#define AUDC_GET_UNIT         _IOR('m',15,int) /* ??? - unimplemented in MSP3400 */
-#define AUDC_SWITCH_MUTE      _IO('m',16)      /* turn on mute */
-#endif
+/* misc stuff to pass around config info to i2c chips */
+#define AUDC_CONFIG_PINNACLE  _IOW('m',32,int)
 
 #endif /* AUDIOCHIP_H */
diff -urN linux-2.4.21-pre3/drivers/media/video/bt832.c linux-2.4.21-pre4/drivers/media/video/bt832.c
--- linux-2.4.21-pre3/drivers/media/video/bt832.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/drivers/media/video/bt832.c	Tue Jan 28 19:44:30 2003
@@ -0,0 +1,288 @@
+/* Driver for Bt832 CMOS Camera Video Processor
+    i2c-adresses: 0x88 or 0x8a
+
+  The BT832 interfaces to a Quartzsight Digital Camera (352x288, 25 or 30 fps)
+  via a 9 pin connector ( 4-wire SDATA, 2-wire i2c, SCLK, VCC, GND).
+  It outputs an 8-bit 4:2:2 YUV or YCrCb video signal which can be directly
+  connected to bt848/bt878 GPIO pins on this purpose.
+  (see: VLSI Vision Ltd. www.vvl.co.uk for camera datasheets)
+  
+  Supported Cards:
+  -  Pixelview Rev.4E: 0x8a
+		GPIO 0x400000 toggles Bt832 RESET, and the chip changes to i2c 0x88 !
+
+  (c) Gunther Mayer, 2002
+
+  STATUS:
+  - detect chip and hexdump
+  - reset chip and leave low power mode
+  - detect camera present
+
+  TODO:
+  - make it work (find correct setup for Bt832 and Bt878)
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/types.h>
+#include <linux/videodev.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+
+#include "id.h"
+#include "audiochip.h"
+#include "bttv.h"
+#include "bt832.h"
+
+MODULE_LICENSE("GPL");
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = {I2C_CLIENT_END};
+static unsigned short normal_i2c_range[] = {I2C_BT832_ALT1>>1,I2C_BT832_ALT2>>1,I2C_CLIENT_END};
+I2C_CLIENT_INSMOD;
+
+/* ---------------------------------------------------------------------- */
+
+#define dprintk     if (debug) printk
+
+static int bt832_detach(struct i2c_client *client);
+
+
+static struct i2c_driver driver;
+static struct i2c_client client_template;
+
+struct bt832 {
+        struct i2c_client client;
+};
+
+int bt832_hexdump(struct i2c_client *i2c_client_s, unsigned char *buf)
+{
+	int i,rc;
+	buf[0]=0x80; // start at register 0 with auto-increment
+        if (1 != (rc = i2c_master_send(i2c_client_s,buf,1)))
+                printk("bt832: i2c i/o error: rc == %d (should be 1)\n",rc);
+
+        for(i=0;i<65;i++)
+                buf[i]=0;
+        if (65 != (rc=i2c_master_recv(i2c_client_s,buf,65)))
+                printk("bt832: i2c i/o error: rc == %d (should be 65)\n",rc);
+
+        // Note: On READ the first byte is the current index
+        //  (e.g. 0x80, what we just wrote)
+
+        if(1) {
+                int i;
+                printk("BT832 hexdump:\n");
+                for(i=1;i<65;i++) {
+			if(i!=1) {
+			  if(((i-1)%8)==0) printk(" ");
+                          if(((i-1)%16)==0) printk("\n");
+			}
+                        printk(" %02x",buf[i]);
+                }
+                printk("\n");
+        }
+	return 0;
+}
+
+// Return: 1 (is a bt832), 0 (No bt832 here)
+int bt832_init(struct i2c_client *i2c_client_s)
+{
+	unsigned char *buf;
+	int rc;
+
+	buf=kmalloc(65,GFP_KERNEL);
+	bt832_hexdump(i2c_client_s,buf);
+	
+	if(buf[0x40] != 0x31) {
+		printk("bt832: this i2c chip is no bt832 (id=%02x). Detaching.\n",buf[0x40]);
+		kfree(buf);
+		return 0;
+	}
+
+        printk("Write 0 tp VPSTATUS\n");
+        buf[0]=BT832_VP_STATUS; // Reg.52
+        buf[1]= 0x00;
+        if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
+                printk("bt832: i2c i/o error VPS: rc == %d (should be 2)\n",rc);
+
+        bt832_hexdump(i2c_client_s,buf);
+
+
+	// Leave low power mode:
+	printk("Bt832: leave low power mode.\n");
+	buf[0]=BT832_CAM_SETUP0; //0x39 57
+	buf[1]=0x08;
+	if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
+                printk("bt832: i2c i/o error LLPM: rc == %d (should be 2)\n",rc);
+
+        bt832_hexdump(i2c_client_s,buf);
+
+	printk("Write 0 tp VPSTATUS\n");
+        buf[0]=BT832_VP_STATUS; // Reg.52
+        buf[1]= 0x00;
+        if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
+                printk("bt832: i2c i/o error VPS: rc == %d (should be 2)\n",rc);
+
+        bt832_hexdump(i2c_client_s,buf);
+
+
+	// Enable Output
+	printk("Enable Output\n");
+	buf[0]=BT832_VP_CONTROL1; // Reg.40
+	buf[1]= 0x27 & (~0x01); // Default | !skip
+	if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
+                printk("bt832: i2c i/o error EO: rc == %d (should be 2)\n",rc);
+	
+        bt832_hexdump(i2c_client_s,buf);
+
+#if 0
+	// Full 30/25 Frame rate
+	printk("Full 30/25 Frame rate\n");
+	buf[0]=BT832_VP_CONTROL0; // Reg.39
+        buf[1]= 0x00;
+        if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
+                printk("bt832: i2c i/o error FFR: rc == %d (should be 2)\n",rc);
+
+        bt832_hexdump(i2c_client_s,buf);
+#endif
+
+#if 1
+	// for testing (even works when no camera attached)
+	printk("bt832: *** Generate NTSC M Bars *****\n");
+	buf[0]=BT832_VP_TESTCONTROL0; // Reg. 42
+	buf[1]=3; // Generate NTSC System M bars, Generate Frame timing internally
+        if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
+                printk("bt832: i2c i/o error MBAR: rc == %d (should be 2)\n",rc);
+#endif
+
+	printk("Bt832: Camera Present: %s\n",
+		(buf[1+BT832_CAM_STATUS] & BT832_56_CAMERA_PRESENT) ? "yes":"no");
+
+        bt832_hexdump(i2c_client_s,buf);
+	kfree(buf);
+	return 1;
+}
+
+
+
+static int bt832_attach(struct i2c_adapter *adap, int addr,
+			  unsigned short flags, int kind)
+{
+	struct bt832 *t;
+
+	printk("bt832_attach\n");
+
+        client_template.adapter = adap;
+        client_template.addr    = addr;
+
+        printk("bt832: chip found @ 0x%x\n", addr<<1);
+
+        if (NULL == (t = kmalloc(sizeof(*t), GFP_KERNEL)))
+                return -ENOMEM;
+	memset(t,0,sizeof(*t));
+	t->client = client_template;
+        t->client.data = t;
+        i2c_attach_client(&t->client);
+
+	MOD_INC_USE_COUNT;
+	if(! bt832_init(&t->client)) {
+		bt832_detach(&t->client);
+		return -1;
+	}
+        
+	return 0;
+}
+
+static int bt832_probe(struct i2c_adapter *adap)
+{
+	int rc;
+
+	printk("bt832_probe\n");
+
+	switch (adap->id) {
+	case I2C_ALGO_BIT | I2C_HW_B_BT848:
+	case I2C_ALGO_BIT | I2C_HW_B_RIVA:
+	case I2C_ALGO_SAA7134:
+		printk("bt832: probing %s i2c adapter [id=0x%x]\n",
+		       adap->name,adap->id);
+		rc = i2c_probe(adap, &addr_data, bt832_attach);
+		break;
+	default:
+		printk("bt832: ignoring %s i2c adapter [id=0x%x]\n",
+		       adap->name,adap->id);
+		rc = 0;
+		/* nothing */
+	}
+	return rc;
+}
+
+static int bt832_detach(struct i2c_client *client)
+{
+	struct bt832 *t = (struct bt832*)client->data;
+
+	printk("bt832: detach.\n");
+	i2c_detach_client(client);
+	kfree(t);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int
+bt832_command(struct i2c_client *client, unsigned int cmd, void *arg)
+{
+	struct bt832 *t = (struct bt832*)client->data;
+
+	printk("bt832: command %x\n",cmd);
+
+        switch (cmd) {
+		case BT832_HEXDUMP: {
+			unsigned char *buf;
+			buf=kmalloc(65,GFP_KERNEL);
+			bt832_hexdump(&t->client,buf);
+			kfree(buf);
+		}
+		break;
+		case BT832_REATTACH:
+			printk("bt832: re-attach\n");
+			i2c_del_driver(&driver);
+			i2c_add_driver(&driver);
+		break;
+	}
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_driver driver = {
+        .name           = "i2c bt832 driver",
+        .id             = -1, /* FIXME */
+        .flags          = I2C_DF_NOTIFY,
+        .attach_adapter = bt832_probe,
+        .detach_client  = bt832_detach,
+        .command        = bt832_command,
+};
+static struct i2c_client client_template =
+{
+        .name   = "bt832",
+	.flags  = I2C_CLIENT_ALLOW_USE,
+        .driver = &driver,
+};
+
+
+int bt832_init_module(void)
+{
+	i2c_add_driver(&driver);
+	return 0;
+}
+
+static void bt832_cleanup_module(void)
+{
+	i2c_del_driver(&driver);
+}
+
+module_init(bt832_init_module);
+module_exit(bt832_cleanup_module);
+
diff -urN linux-2.4.21-pre3/drivers/media/video/bt832.h linux-2.4.21-pre4/drivers/media/video/bt832.h
--- linux-2.4.21-pre3/drivers/media/video/bt832.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/drivers/media/video/bt832.h	Tue Jan 28 19:44:30 2003
@@ -0,0 +1,305 @@
+/* Bt832 CMOS Camera Video Processor (VP)
+
+ The Bt832 CMOS Camera Video Processor chip connects a Quartsight CMOS 
+  color digital camera directly to video capture devices via an 8-bit,
+  4:2:2 YUV or YCrCb video interface.
+
+ i2c adresses: 0x88 or 0x8a
+ */
+
+/* The 64 registers: */
+
+// Input Processor
+#define BT832_OFFSET 0
+#define BT832_RCOMP	1
+#define BT832_G1COMP	2
+#define BT832_G2COMP	3
+#define BT832_BCOMP	4
+// Exposures:
+#define BT832_FINEH	5
+#define BT832_FINEL	6
+#define BT832_COARSEH	7
+#define BT832_COARSEL   8
+#define BT832_CAMGAIN	9
+// Main Processor:
+#define BT832_M00	10
+#define BT832_M01	11
+#define BT832_M02	12
+#define BT832_M10	13
+#define BT832_M11	14
+#define BT832_M12	15
+#define BT832_M20	16
+#define BT832_M21	17
+#define BT832_M22	18
+#define BT832_APCOR	19
+#define BT832_GAMCOR	20
+// Level Accumulator Inputs
+#define BT832_VPCONTROL2	21
+#define BT832_ZONECODE0	22
+#define BT832_ZONECODE1	23
+#define BT832_ZONECODE2	24
+#define BT832_ZONECODE3	25
+// Level Accumulator Outputs:
+#define BT832_RACC	26
+#define BT832_GACC	27
+#define BT832_BACC	28
+#define BT832_BLACKACC	29
+#define BT832_EXP_AGC	30
+#define BT832_LACC0	31
+#define BT832_LACC1	32
+#define BT832_LACC2	33
+#define BT832_LACC3	34
+#define BT832_LACC4	35
+#define BT832_LACC5	36
+#define BT832_LACC6	37
+#define BT832_LACC7	38
+// System:
+#define BT832_VP_CONTROL0	39
+#define BT832_VP_CONTROL1	40
+#define BT832_THRESH	41
+#define BT832_VP_TESTCONTROL0	42
+#define BT832_VP_DMCODE	43
+#define BT832_ACB_CONFIG	44
+#define BT832_ACB_GNBASE	45
+#define BT832_ACB_MU	46
+#define BT832_CAM_TEST0	47
+#define BT832_AEC_CONFIG	48
+#define BT832_AEC_TL	49
+#define BT832_AEC_TC	50
+#define BT832_AEC_TH	51
+// Status:
+#define BT832_VP_STATUS	52
+#define BT832_VP_LINECOUNT	53
+#define BT832_CAM_DEVICEL	54 // e.g. 0x19
+#define BT832_CAM_DEVICEH	55 // e.g. 0x40  == 0x194 Mask0, 0x194 = 404 decimal (VVL-404 camera)
+#define BT832_CAM_STATUS		56
+ #define BT832_56_CAMERA_PRESENT 0x20
+//Camera Setups:
+#define BT832_CAM_SETUP0	57
+#define BT832_CAM_SETUP1	58
+#define BT832_CAM_SETUP2	59
+#define BT832_CAM_SETUP3	60
+// System:
+#define BT832_DEFCOR		61
+#define BT832_VP_TESTCONTROL1	62
+#define BT832_DEVICE_ID		63
+# define BT832_DEVICE_ID__31		0x31 // Bt832 has ID 0x31
+
+/* STMicroelectronivcs VV5404 camera module 
+   i2c: 0x20: sensor address
+   i2c: 0xa0: eeprom for ccd defect map
+ */
+#define VV5404_device_h		0x00  // 0x19
+#define VV5404_device_l		0x01  // 0x40
+#define VV5404_status0		0x02
+#define VV5404_linecountc	0x03 // current line counter
+#define VV5404_linecountl	0x04
+#define VV5404_setup0		0x10
+#define VV5404_setup1		0x11
+#define VV5404_setup2		0x12
+#define VV5404_setup4		0x14
+#define VV5404_setup5		0x15
+#define VV5404_fine_h		0x20  // fine exposure
+#define VV5404_fine_l		0x21
+#define VV5404_coarse_h		0x22  //coarse exposure
+#define VV5404_coarse_l		0x23
+#define VV5404_gain		0x24 // ADC pre-amp gain setting
+#define VV5404_clk_div		0x25
+#define VV5404_cr		0x76 // control register
+#define VV5404_as0		0x77 // ADC setup register
+
+
+// IOCTL
+#define BT832_HEXDUMP   _IOR('b',1,int)
+#define BT832_REATTACH	_IOR('b',2,int)
+
+/* from BT8x8VXD/capdrv/dialogs.cpp */
+
+/*
+typedef enum { SVI, Logitech, Rockwell } CAMERA;
+
+static COMBOBOX_ENTRY gwCameraOptions[] =
+{
+   { SVI,      "Silicon Vision 512N" },
+   { Logitech, "Logitech VideoMan 1.3"  },
+   { Rockwell, "Rockwell QuartzSight PCI 1.0"   }
+};
+
+// SRAM table values
+//===========================================================================
+typedef enum { TGB_NTSC624, TGB_NTSC780, TGB_NTSC858, TGB_NTSC392 } TimeGenByte;
+
+BYTE SRAMTable[][ 60 ] =
+{
+   // TGB_NTSC624
+   {
+      0x33, // size of table = 51
+      0x0E, 0xC0, 0x00, 0x00, 0x90, 0x02, 0x03, 0x10, 0x03, 0x06,
+      0x10, 0x04, 0x12, 0x12, 0x05, 0x02, 0x13, 0x04, 0x19, 0x00,
+      0x04, 0x39, 0x00, 0x06, 0x59, 0x08, 0x03, 0x85, 0x08, 0x07,
+      0x03, 0x50, 0x00, 0x91, 0x40, 0x00, 0x11, 0x01, 0x01, 0x4D,
+      0x0D, 0x02, 0x03, 0x11, 0x01, 0x05, 0x37, 0x00, 0x37, 0x21, 0x00
+   },
+   // TGB_NTSC780
+   {
+      0x33, // size of table = 51
+      0x0e, 0xc0, 0x00, 0x00, 0x90, 0xe2, 0x03, 0x10, 0x03, 0x06,
+      0x10, 0x34, 0x12, 0x12, 0x65, 0x02, 0x13, 0x24, 0x19, 0x00,
+      0x24, 0x39, 0x00, 0x96, 0x59, 0x08, 0x93, 0x85, 0x08, 0x97,
+      0x03, 0x50, 0x50, 0xaf, 0x40, 0x30, 0x5f, 0x01, 0xf1, 0x7f,
+      0x0d, 0xf2, 0x03, 0x11, 0xf1, 0x05, 0x37, 0x30, 0x85, 0x21, 0x50
+   },
+   // TGB_NTSC858
+   {
+      0x33, // size of table = 51
+      0x0c, 0xc0, 0x00, 0x00, 0x90, 0xc2, 0x03, 0x10, 0x03, 0x06,
+      0x10, 0x34, 0x12, 0x12, 0x65, 0x02, 0x13, 0x24, 0x19, 0x00,
+      0x24, 0x39, 0x00, 0x96, 0x59, 0x08, 0x93, 0x83, 0x08, 0x97,
+      0x03, 0x50, 0x30, 0xc0, 0x40, 0x30, 0x86, 0x01, 0x01, 0xa6,
+      0x0d, 0x62, 0x03, 0x11, 0x61, 0x05, 0x37, 0x30, 0xac, 0x21, 0x50
+   },
+   // TGB_NTSC392
+   // This table has been modified to be used for Fusion Rev D
+   {
+      0x2A, // size of table = 42
+      0x06, 0x08, 0x04, 0x0a, 0xc0, 0x00, 0x18, 0x08, 0x03, 0x24,
+      0x08, 0x07, 0x02, 0x90, 0x02, 0x08, 0x10, 0x04, 0x0c, 0x10,
+      0x05, 0x2c, 0x11, 0x04, 0x55, 0x48, 0x00, 0x05, 0x50, 0x00,
+      0xbf, 0x0c, 0x02, 0x2f, 0x3d, 0x00, 0x2f, 0x3f, 0x00, 0xc3,
+      0x20, 0x00
+   }
+};
+
+//===========================================================================
+// This is the structure of the camera specifications
+//===========================================================================
+typedef struct tag_cameraSpec
+{
+   SignalFormat signal;       // which digital signal format the camera has
+   VideoFormat  vidFormat;    // video standard
+   SyncVideoRef syncRef;      // which sync video reference is used
+   State        syncOutput;   // enable sync output for sync video input?
+   DecInputClk  iClk;         // which input clock is used
+   TimeGenByte  tgb;          // which timing generator byte does the camera use
+   int          HReset;       // select 64, 48, 32, or 16 CLKx1 for HReset
+   PLLFreq      pllFreq;      // what synthesized frequency to set PLL to
+   VSIZEPARMS   vSize;        // video size the camera produces
+   int          lineCount;    // expected total number of half-line per frame - 1
+   BOOL         interlace;    // interlace signal?
+} CameraSpec;
+
+//===========================================================================
+// <UPDATE REQUIRED>
+// Camera specifications database. Update this table whenever camera spec
+// has been changed or added/deleted supported camera models
+//===========================================================================
+static CameraSpec dbCameraSpec[ N_CAMERAOPTIONS ] =
+{  // Silicon Vision 512N
+   { Signal_CCIR656, VFormat_NTSC, VRef_alignedCb, Off, DecClk_GPCLK, TGB_NTSC624, 64, KHz19636,
+      // Clkx1_HACTIVE, Clkx1_HDELAY, VActive, VDelay, linesPerField; lineCount, Interlace
+   {         512,           0x64,       480,    0x13,      240 },         0,       TRUE
+   },
+   // Logitech VideoMan 1.3
+   { Signal_CCIR656, VFormat_NTSC, VRef_alignedCb, Off, DecClk_GPCLK, TGB_NTSC780, 64, KHz24545,
+      // Clkx1_HACTIVE, Clkx1_HDELAY, VActive, VDelay, linesPerField; lineCount, Interlace
+      {      640,           0x80,       480,    0x1A,      240 },         0,       TRUE
+   },
+   // Rockwell QuartzSight
+   // Note: Fusion Rev D (rev ID 0x02) and later supports 16 pixels for HReset which is preferable.
+   //       Use 32 for earlier version of hardware. Clkx1_HDELAY also changed from 0x27 to 0x20.
+   { Signal_CCIR656, VFormat_NTSC, VRef_alignedCb, Off, DecClk_GPCLK, TGB_NTSC392, 16, KHz28636,
+      // Clkx1_HACTIVE, Clkx1_HDELAY, VActive, VDelay, linesPerField; lineCount, Interlace
+      {      352,           0x20,       576,    0x08,      288 },       607,       FALSE
+   }
+};
+*/
+
+/*
+The corresponding APIs required to be invoked are:
+SetConnector( ConCamera, TRUE/FALSE );
+SetSignalFormat( spec.signal );
+SetVideoFormat( spec.vidFormat );
+SetSyncVideoRef( spec.syncRef );
+SetEnableSyncOutput( spec.syncOutput );
+SetTimGenByte( SRAMTable[ spec.tgb ], SRAMTableSize[ spec.tgb ] );
+SetHReset( spec.HReset );
+SetPLL( spec.pllFreq );
+SetDecInputClock( spec.iClk );
+SetVideoInfo( spec.vSize );
+SetTotalLineCount( spec.lineCount );
+SetInterlaceMode( spec.interlace );
+*/
+
+/* from web:
+ Video Sampling
+Digital video is a sampled form of analog video. The most common sampling schemes in use today are:
+                  Pixel Clock   Horiz    Horiz    Vert
+                   Rate         Total    Active
+NTSC square pixel  12.27 MHz    780      640      525
+NTSC CCIR-601      13.5  MHz    858      720      525
+NTSC 4FSc          14.32 MHz    910      768      525
+PAL  square pixel  14.75 MHz    944      768      625
+PAL  CCIR-601      13.5  MHz    864      720      625
+PAL  4FSc          17.72 MHz   1135      948      625
+
+For the CCIR-601 standards, the sampling is based on a static orthogonal sampling grid. The luminance component (Y) is sampled at 13.5 MHz, while the two color difference signals, Cr and Cb are sampled at half that, or 6.75 MHz. The Cr and Cb samples are colocated with alternate Y samples, and they are taken at the same position on each line, such that one sample is coincident with the 50% point of the falling edge of analog sync. The samples are coded to either 8 or 10 bits per component.
+*/
+
+/* from DScaler:*/
+/*
+//===========================================================================
+// CCIR656 Digital Input Support: The tables were taken from DScaler proyect
+//
+// 13 Dec 2000 - Michael Eskin, Conexant Systems - Initial version
+//
+
+//===========================================================================
+// Timing generator SRAM table values for CCIR601 720x480 NTSC
+//===========================================================================
+// For NTSC CCIR656 
+BYTE BtCard::SRAMTable_NTSC[] =
+{
+    // SRAM Timing Table for NTSC
+    0x0c, 0xc0, 0x00, 
+    0x00, 0x90, 0xc2, 
+    0x03, 0x10, 0x03, 
+    0x06, 0x10, 0x34, 
+    0x12, 0x12, 0x65, 
+    0x02, 0x13, 0x24, 
+    0x19, 0x00, 0x24, 
+    0x39, 0x00, 0x96, 
+    0x59, 0x08, 0x93, 
+    0x83, 0x08, 0x97,
+    0x03, 0x50, 0x30, 
+    0xc0, 0x40, 0x30, 
+    0x86, 0x01, 0x01, 
+    0xa6, 0x0d, 0x62, 
+    0x03, 0x11, 0x61, 
+    0x05, 0x37, 0x30, 
+    0xac, 0x21, 0x50
+};
+
+//===========================================================================
+// Timing generator SRAM table values for CCIR601 720x576 NTSC
+//===========================================================================
+// For PAL CCIR656
+BYTE BtCard::SRAMTable_PAL[] =
+{
+    // SRAM Timing Table for PAL
+    0x36, 0x11, 0x01,
+    0x00, 0x90, 0x02,
+    0x05, 0x10, 0x04,
+    0x16, 0x14, 0x05,
+    0x11, 0x00, 0x04,
+    0x12, 0xc0, 0x00,
+    0x31, 0x00, 0x06,
+    0x51, 0x08, 0x03,
+    0x89, 0x08, 0x07,
+    0xc0, 0x44, 0x00,
+    0x81, 0x01, 0x01,
+    0xa9, 0x0d, 0x02,
+    0x02, 0x50, 0x03,
+    0x37, 0x3d, 0x00,
+    0xaf, 0x21, 0x00,
+};
+*/
diff -urN linux-2.4.21-pre3/drivers/media/video/msp3400.c linux-2.4.21-pre4/drivers/media/video/msp3400.c
--- linux-2.4.21-pre3/drivers/media/video/msp3400.c	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre4/drivers/media/video/msp3400.c	Tue Jan 28 19:44:30 2003
@@ -62,17 +62,7 @@
 /* Addresses to scan */
 static unsigned short normal_i2c[] = {I2C_CLIENT_END};
 static unsigned short normal_i2c_range[] = {0x40,0x40,I2C_CLIENT_END};
-static unsigned short probe[2]        = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short probe_range[2]  = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore[2]       = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short force[2]        = { I2C_CLIENT_END, I2C_CLIENT_END };
-static struct i2c_client_address_data addr_data = {
-	normal_i2c, normal_i2c_range, 
-	probe, probe_range, 
-	ignore, ignore_range, 
-	force
-};
+I2C_CLIENT_INSMOD;
 
 /* insmod parameters */
 static int debug   = 0;    /* debug output */
@@ -145,17 +135,33 @@
 /* ----------------------------------------------------------------------- */
 /* functions for talking to the MSP3400C Sound processor                   */
 
+#ifndef I2C_M_IGNORE_NAK
+# define I2C_M_IGNORE_NAK 0x1000
+#endif
+
 static int msp3400c_reset(struct i2c_client *client)
 {
-        static char reset_off[3] = { 0x00, 0x80, 0x00 };
-        static char reset_on[3]  = { 0x00, 0x00, 0x00 };
-
-        i2c_master_send(client,reset_off,3);  /* XXX ignore errors here */
-        if (3 != i2c_master_send(client,reset_on, 3)) {
-		printk(KERN_ERR "msp3400: chip reset failed, penguin on i2c bus?\n");
-                return -1;
-	}
-        return 0;
+	/* reset and read revision code */
+	static char reset_off[3] = { 0x00, 0x80, 0x00 };
+	static char reset_on[3]  = { 0x00, 0x00, 0x00 };
+	static char write[3]     = { I2C_MSP3400C_DFP + 1, 0x00, 0x1e };
+	char read[2];
+	struct i2c_msg reset[2] = {
+		{ client->addr, I2C_M_IGNORE_NAK, 3, reset_off },
+		{ client->addr, I2C_M_IGNORE_NAK, 3, reset_on  },
+	};
+	struct i2c_msg test[2] = {
+		{ client->addr, 0,        3, write },
+		{ client->addr, I2C_M_RD, 2, read  },
+	};
+	
+	if ( (1 != i2c_transfer(client->adapter,&reset[0],1)) ||
+	     (1 != i2c_transfer(client->adapter,&reset[1],1)) ||
+	     (2 != i2c_transfer(client->adapter,test,2)) ) {
+		printk(KERN_ERR "msp3400: chip reset failed\n");
+		return -1;
+        }
+	return 0; 
 }
 
 static int
@@ -1213,19 +1219,19 @@
 static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg);
 
 static struct i2c_driver driver = {
-        name:           "i2c msp3400 driver",
-        id:             I2C_DRIVERID_MSP3400,
-        flags:          I2C_DF_NOTIFY,
-        attach_adapter: msp_probe,
-        detach_client:  msp_detach,
-        command:        msp_command,
+        .name           = "i2c msp3400 driver",
+        .id             = I2C_DRIVERID_MSP3400,
+        .flags          = I2C_DF_NOTIFY,
+        .attach_adapter = msp_probe,
+        .detach_client  = msp_detach,
+        .command        = msp_command,
 };
 
 static struct i2c_client client_template = 
 {
-	name:   "(unset)",
-	flags:  I2C_CLIENT_ALLOW_USE,
-        driver: &driver,
+	.name   = "(unset)",
+	.flags  = I2C_CLIENT_ALLOW_USE,
+        .driver = &driver,
 };
 
 static int msp_attach(struct i2c_adapter *adap, int addr,
@@ -1258,6 +1264,7 @@
 	msp->bass   = 32768;
 	msp->treble = 32768;
 	msp->input  = -1;
+	msp->muted  = 1;
 	for (i = 0; i < DFP_COUNT; i++)
 		msp->dfp_regs[i] = -1;
 
@@ -1283,8 +1290,9 @@
 
 #if 0
 	/* this will turn on a 1kHz beep - might be useful for debugging... */
-	msp3400c_write(client,I2C_MSP3400C_DFP, 0x0014, 0x1040);
+	msp3400c_write(c,I2C_MSP3400C_DFP, 0x0014, 0x1040);
 #endif
+	msp3400c_setvolume(c,msp->muted,msp->left,msp->right);
 
 	sprintf(c->name,"MSP34%02d%c-%c%d",
 		(rev2>>8)&0xff, (rev1&0xff)+'@', ((rev1>>8)&0xff)+'@', rev2&0x1f);
@@ -1300,6 +1308,7 @@
 	}
 
 	/* timer for stereo checking */
+	init_timer(&msp->wake_stereo);
 	msp->wake_stereo.function = msp3400c_stereo_wake;
 	msp->wake_stereo.data     = (unsigned long)msp;
 
diff -urN linux-2.4.21-pre3/drivers/media/video/tda7432.c linux-2.4.21-pre4/drivers/media/video/tda7432.c
--- linux-2.4.21-pre3/drivers/media/video/tda7432.c	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre4/drivers/media/video/tda7432.c	Tue Jan 28 19:44:30 2003
@@ -52,6 +52,10 @@
 #include "audiochip.h"
 #include "id.h"
 
+#ifndef VIDEO_AUDIO_BALANCE
+# define VIDEO_AUDIO_BALANCE 32
+#endif
+
 MODULE_AUTHOR("Eric Sandeen <eric_sandeen@bigfoot.com>");
 MODULE_DESCRIPTION("bttv driver for the tda7432 audio processor chip");
 MODULE_LICENSE("GPL");
@@ -68,19 +72,10 @@
 /* Address to scan (I2C address of this chip) */
 static unsigned short normal_i2c[] = {
 	I2C_TDA7432 >> 1,
-	I2C_CLIENT_END};
-static unsigned short normal_i2c_range[] = {I2C_CLIENT_END};
-static unsigned short probe[2]        = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short probe_range[2]  = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore[2]       = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short force[2]        = { I2C_CLIENT_END, I2C_CLIENT_END };
-static struct i2c_client_address_data addr_data = {
-	normal_i2c, normal_i2c_range, 
-	probe, probe_range, 
-	ignore, ignore_range, 
-	force
+	I2C_CLIENT_END,
 };
+static unsigned short normal_i2c_range[] = { I2C_CLIENT_END, I2C_CLIENT_END };
+I2C_CLIENT_INSMOD;
 
 /* Structure of address and subaddresses for the tda7432 */
 
@@ -395,10 +390,10 @@
 		 * Max (0dB) is 0x20 (829)
 		 * (Mask out bit 7 of vol - it's for the loudness setting)
 		 */
-		if(!maxvol){  /* max +20db */
+		if (!maxvol){  /* max +20db */
 			va->volume = ( 0x6f - (t->volume & 0x7F) ) * 630;
-		} else {     /* max 0db   */
-			va->volume = (int )(( 0x6f - (t->volume & 0x7F) ) * 829.557);
+		} else {       /* max 0db   */
+			va->volume = ( 0x6f - (t->volume & 0x7F) ) * 829;
 		}
 		
 		/* Balance depends on L,R attenuation
@@ -436,11 +431,10 @@
 		dprintk("tda7432: VIDEOCSAUDIO\n");
 
 		if(va->flags & VIDEO_AUDIO_VOLUME){
-				
 			if(!maxvol){ /* max +20db */
-				t->volume = 0x6f - ( (va->volume)/630 );
+				t->volume = 0x6f - ((va->volume)/630);
 			} else {    /* max 0db   */
-				t->volume = 0x6f - ((int) (va->volume)/829.557 );
+				t->volume = 0x6f - ((va->volume)/829);
 			}
 		
 		if (loudness)		/* Turn on the loudness bit */
@@ -520,35 +514,28 @@
 	return 0;
 }
 
-
 static struct i2c_driver driver = {
-        "i2c tda7432 driver",
-	I2C_DRIVERID_TDA7432,
-        I2C_DF_NOTIFY,
-	tda7432_probe,
-        tda7432_detach,
-        tda7432_command,
+        .name            = "i2c tda7432 driver",
+	.id              = I2C_DRIVERID_TDA7432,
+        .flags           = I2C_DF_NOTIFY,
+	.attach_adapter  = tda7432_probe,
+        .detach_client   = tda7432_detach,
+        .command         = tda7432_command,
 };
 
 static struct i2c_client client_template =
 {
-        "(unset)",		/* name */
-        -1,
-        0,
-        0,
-        NULL,
-        &driver
+        .name   = "tda7432",
+        .id     = -1,
+	.driver = &driver, 
 };
 
 static int tda7432_init(void)
 {
-
-	if ( (loudness < 0) || (loudness > 15) )
-	{
+	if ( (loudness < 0) || (loudness > 15) ) {
 		printk(KERN_ERR "tda7432: loudness parameter must be between 0 and 15\n");
 		return -EINVAL;
 	}
-
 	i2c_add_driver(&driver);
 	return 0;
 }
diff -urN linux-2.4.21-pre3/drivers/media/video/tda9875.c linux-2.4.21-pre4/drivers/media/video/tda9875.c
--- linux-2.4.21-pre3/drivers/media/video/tda9875.c	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre4/drivers/media/video/tda9875.c	Tue Jan 28 19:44:30 2003
@@ -42,19 +42,10 @@
 /* Addresses to scan */
 static unsigned short normal_i2c[] =  {
     I2C_TDA9875 >> 1,
-    I2C_CLIENT_END};
-static unsigned short normal_i2c_range[] = {I2C_CLIENT_END};
-static unsigned short probe[2]        = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short probe_range[2]  = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore[2]       = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short force[2]        = { I2C_CLIENT_END, I2C_CLIENT_END };
-static struct i2c_client_address_data addr_data = {
-	normal_i2c, normal_i2c_range, 
-	probe, probe_range, 
-	ignore, ignore_range, 
-	force
+    I2C_CLIENT_END
 };
+static unsigned short normal_i2c_range[] = {I2C_CLIENT_END};
+I2C_CLIENT_INSMOD;
 
 /* This is a superset of the TDA9875 */
 struct tda9875 {
@@ -64,7 +55,6 @@
 	struct i2c_client c;
 };
 
-
 static struct i2c_driver driver;
 static struct i2c_client client_template;
 
@@ -397,22 +387,19 @@
 
 
 static struct i2c_driver driver = {
-        "i2c tda9875 driver",
-        I2C_DRIVERID_TDA9875, /* Get new one for TDA9875 */
-        I2C_DF_NOTIFY,
-	tda9875_probe,
-        tda9875_detach,
-        tda9875_command,
+        .name           = "i2c tda9875 driver",
+        .id             = I2C_DRIVERID_TDA9875,
+        .flags          = I2C_DF_NOTIFY,
+	.attach_adapter = tda9875_probe,
+        .detach_client  = tda9875_detach,
+        .command        = tda9875_command,
 };
 
 static struct i2c_client client_template =
 {
-        "(unset)",		/* name */
-        -1,
-        0,
-        0,
-        NULL,
-        &driver
+        .name    = "tda9875",
+        .id      = -1,
+        .driver  = &driver,
 };
 
 static int tda9875_init(void)
diff -urN linux-2.4.21-pre3/drivers/media/video/tda9887.c linux-2.4.21-pre4/drivers/media/video/tda9887.c
--- linux-2.4.21-pre3/drivers/media/video/tda9887.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/drivers/media/video/tda9887.c	Tue Jan 28 19:44:30 2003
@@ -0,0 +1,483 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/types.h>
+#include <linux/videodev.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+
+#include "id.h"
+#include "audiochip.h"
+
+/* Chips:
+   TDA9885 (PAL, NTSC)
+   TDA9886 (PAL, SECAM, NTSC)
+   TDA9887 (PAL, SECAM, NTSC, FM Radio)
+
+   found on:
+   - Pinnacle PCTV (Jul.2002 Version with MT2032, bttv)
+      TDA9887 (world), TDA9885 (USA)
+      Note: OP2 of tda988x must be set to 1, else MT2032 is disabled!
+   - KNC One TV-Station RDS (saa7134)
+*/
+    
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = {I2C_CLIENT_END};
+static unsigned short normal_i2c_range[] = {0x86>>1,0x86>>1,I2C_CLIENT_END};
+I2C_CLIENT_INSMOD;
+
+/* insmod options */
+static int debug =  0;
+static char *pal =  "b";
+static char *secam =  "l";
+MODULE_PARM(debug,"i");
+MODULE_PARM(pal,"s");
+MODULE_PARM(secam,"s");
+MODULE_LICENSE("GPL");
+
+/* ---------------------------------------------------------------------- */
+
+#define dprintk     if (debug) printk
+
+struct tda9887 {
+	struct i2c_client client;
+	int radio,tvnorm;
+	int pinnacle_id;
+};
+
+static struct i2c_driver driver;
+static struct i2c_client client_template;
+
+/* ---------------------------------------------------------------------- */
+
+//
+// TDA defines
+//
+
+//// first reg
+#define cVideoTrapBypassOFF     0x00    // bit b0
+#define cVideoTrapBypassON      0x01    // bit b0
+
+#define cAutoMuteFmInactive     0x00    // bit b1
+#define cAutoMuteFmActive       0x02    // bit b1
+
+#define cIntercarrier           0x00    // bit b2
+#define cQSS                    0x04    // bit b2
+
+#define cPositiveAmTV           0x00    // bit b3:4
+#define cFmRadio                0x08    // bit b3:4
+#define cNegativeFmTV           0x10    // bit b3:4
+
+
+#define cForcedMuteAudioON      0x20    // bit b5
+#define cForcedMuteAudioOFF     0x00    // bit b5
+
+#define cOutputPort1Active      0x00    // bit b6
+#define cOutputPort1Inactive    0x40    // bit b6
+
+#define cOutputPort2Active      0x00    // bit b7
+#define cOutputPort2Inactive    0x80    // bit b7
+
+
+//// second reg
+#define cDeemphasisOFF          0x00    // bit c5
+#define cDeemphasisON           0x20    // bit c5
+
+#define cDeemphasis75           0x00    // bit c6
+#define cDeemphasis50           0x40    // bit c6
+
+#define cAudioGain0             0x00    // bit c7
+#define cAudioGain6             0x80    // bit c7
+
+
+//// third reg
+#define cAudioIF_4_5             0x00    // bit e0:1
+#define cAudioIF_5_5             0x01    // bit e0:1
+#define cAudioIF_6_0             0x02    // bit e0:1
+#define cAudioIF_6_5             0x03    // bit e0:1
+
+
+#define cVideoIF_58_75           0x00    // bit e2:4
+#define cVideoIF_45_75           0x04    // bit e2:4
+#define cVideoIF_38_90           0x08    // bit e2:4
+#define cVideoIF_38_00           0x0C    // bit e2:4
+#define cVideoIF_33_90           0x10    // bit e2:4
+#define cVideoIF_33_40           0x14    // bit e2:4
+#define cRadioIF_45_75           0x18    // bit e2:4
+#define cRadioIF_38_90           0x1C    // bit e2:4
+
+
+#define cTunerGainNormal         0x00    // bit e5
+#define cTunerGainLow            0x20    // bit e5
+
+#define cGating_18               0x00    // bit e6
+#define cGating_36               0x40    // bit e6
+
+#define cAgcOutON                0x80    // bit e7
+#define cAgcOutOFF               0x00    // bit e7
+
+static int tda9887_miro(struct tda9887 *t)
+{
+	int rc;
+	u8   bData[4]     = { 0 };
+	u8   bVideoIF     = 0;
+	u8   bAudioIF     = 0;
+	u8   bDeEmphasis  = 0;
+	u8   bDeEmphVal   = 0;
+	u8   bModulation  = 0;
+	u8   bCarrierMode = 0;
+	u8   bOutPort1    = cOutputPort1Inactive;
+#if 0
+	u8   bOutPort2    = cOutputPort2Inactive & mbTADState; // store i2c tuner state
+#else
+	u8   bOutPort2    = cOutputPort2Inactive;
+#endif
+	u8   bVideoTrap   = cVideoTrapBypassOFF;
+#if 1
+	u8   bTopAdjust   = 0x0e /* -2dB */;
+#else
+	u8   bTopAdjust   = 0;
+#endif
+
+#if 0
+	if (mParams.fVideoTrap)
+		bVideoTrap   = cVideoTrapBypassON;
+#endif
+
+	if (t->radio) {
+		bVideoTrap   = cVideoTrapBypassOFF;
+		bCarrierMode = cQSS;
+		bModulation  = cFmRadio;
+		bOutPort1    = cOutputPort1Inactive;
+		bDeEmphasis  = cDeemphasisON;
+		if (3 == t->pinnacle_id) {
+			/* ntsc */
+			bDeEmphVal   = cDeemphasis75;
+			bAudioIF     = cAudioIF_4_5;
+			bVideoIF     = cRadioIF_45_75;
+		} else {
+			/* pal */
+			bAudioIF     = cAudioIF_5_5;
+			bVideoIF     = cRadioIF_38_90;
+			bDeEmphVal   = cDeemphasis50;
+		}
+
+	} else if (t->tvnorm == VIDEO_MODE_PAL) {
+		bDeEmphasis  = cDeemphasisON;
+		bDeEmphVal   = cDeemphasis50;
+		bModulation  = cNegativeFmTV;
+		bOutPort1    = cOutputPort1Inactive;
+		if (1 == t->pinnacle_id) {
+			bCarrierMode = cIntercarrier;
+		} else {
+			// stereo boards
+			bCarrierMode = cQSS;
+		}
+		switch (pal[0]) {
+		case 'b':
+		case 'g':
+		case 'h':
+			bVideoIF     = cVideoIF_38_90;
+			bAudioIF     = cAudioIF_5_5;
+			break;
+		case 'd':
+			bVideoIF     = cVideoIF_38_00;
+			bAudioIF     = cAudioIF_6_5;
+			break;
+		case 'i':
+			bVideoIF     = cVideoIF_38_90;
+			bAudioIF     = cAudioIF_6_0;
+			break;
+		case 'm':
+		case 'n':
+			bVideoIF     = cVideoIF_45_75;
+			bAudioIF     = cAudioIF_4_5;
+			bDeEmphVal   = cDeemphasis75;
+			if ((5 == t->pinnacle_id) || (6 == t->pinnacle_id)) {
+				bCarrierMode = cIntercarrier;
+			} else {
+				bCarrierMode = cQSS;
+			}
+			break;
+		}
+
+	} else if (t->tvnorm == VIDEO_MODE_SECAM) {
+		bAudioIF     = cAudioIF_6_5;
+		bDeEmphasis  = cDeemphasisON;
+		bDeEmphVal   = cDeemphasis50;
+		bModulation  = cNegativeFmTV;
+		bCarrierMode = cQSS;
+		bOutPort1    = cOutputPort1Inactive;                
+		switch (secam[0]) {
+		case 'd':
+			bVideoIF     = cVideoIF_38_00;
+			break;
+		case 'k':
+			bVideoIF     = cVideoIF_38_90;
+			break;
+		case 'l':
+			bVideoIF     = cVideoIF_38_90;
+			bDeEmphasis  = cDeemphasisOFF;
+			bDeEmphVal   = cDeemphasis75;
+			bModulation  = cPositiveAmTV;
+			break;
+		case 'L' /* L1 */:
+			bVideoIF     = cVideoIF_33_90;
+			bDeEmphasis  = cDeemphasisOFF;
+			bDeEmphVal   = cDeemphasis75;
+			bModulation  = cPositiveAmTV;
+			break;
+		}
+
+	} else if (t->tvnorm == VIDEO_MODE_NTSC) {
+                bVideoIF     = cVideoIF_45_75;
+                bAudioIF     = cAudioIF_4_5;
+                bDeEmphasis  = cDeemphasisON;
+                bDeEmphVal   = cDeemphasis75;
+                bModulation  = cNegativeFmTV;                
+                bOutPort1    = cOutputPort1Inactive;
+                if ((5 == t->pinnacle_id) || (6 == t->pinnacle_id)) {
+			bCarrierMode = cIntercarrier;
+		} else {
+			bCarrierMode = cQSS;
+                }
+	}
+
+	bData[1] = bVideoTrap        |  // B0: video trap bypass
+		cAutoMuteFmInactive  |  // B1: auto mute
+		bCarrierMode         |  // B2: InterCarrier for PAL else QSS 
+		bModulation          |  // B3 - B4: positive AM TV for SECAM only
+		cForcedMuteAudioOFF  |  // B5: forced Audio Mute (off)
+		bOutPort1            |  // B6: Out Port 1 
+		bOutPort2;              // B7: Out Port 2 
+	bData[2] = bTopAdjust |   // C0 - C4: Top Adjust 0 == -16dB  31 == 15dB
+		bDeEmphasis   |   // C5: De-emphasis on/off
+		bDeEmphVal    |   // C6: De-emphasis 50/75 microsec
+		cAudioGain0;      // C7: normal audio gain
+	bData[3] = bAudioIF      |  // E0 - E1: Sound IF
+		bVideoIF         |  // E2 - E4: Video IF
+		cTunerGainNormal |  // E5: Tuner gain (normal)
+		cGating_18       |  // E6: Gating (18%)
+		cAgcOutOFF;         // E7: VAGC  (off)
+	
+	dprintk("tda9885/6/7: 0x%02x 0x%02x 0x%02x [pinnacle_id=%d]\n",
+		bData[1],bData[2],bData[3],t->pinnacle_id);
+	if (4 != (rc = i2c_master_send(&t->client,bData,4)))
+		printk("tda9885/6/7: i2c i/o error: rc == %d (should be 4)\n",rc);
+	return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+#if 0
+/* just for reference: old knc-one saa7134 stuff */
+static unsigned char buf_pal_bg[]    = { 0x00, 0x16, 0x70, 0x49 };
+static unsigned char buf_pal_i[]     = { 0x00, 0x16, 0x70, 0x4a };
+static unsigned char buf_pal_dk[]    = { 0x00, 0x16, 0x70, 0x4b };
+static unsigned char buf_pal_l[]     = { 0x00, 0x06, 0x50, 0x4b };
+static unsigned char buf_fm_stereo[] = { 0x00, 0x0e, 0x0d, 0x77 };
+#endif
+
+static unsigned char buf_pal_bg[]    = { 0x00, 0x96, 0x70, 0x49 };
+static unsigned char buf_pal_i[]     = { 0x00, 0x96, 0x70, 0x4a };
+static unsigned char buf_pal_dk[]    = { 0x00, 0x96, 0x70, 0x4b };
+static unsigned char buf_pal_l[]     = { 0x00, 0x86, 0x50, 0x4b };
+static unsigned char buf_fm_stereo[] = { 0x00, 0x8e, 0x0d, 0x77 };
+static unsigned char buf_ntsc[]	     = { 0x00, 0x96, 0x70, 0x44 };
+static unsigned char buf_ntsc_jp[]   = { 0x00, 0x96, 0x70, 0x40 };
+
+static int tda9887_configure(struct tda9887 *t)
+{
+	unsigned char *buf = NULL;
+	int rc;
+
+	printk("tda9887_configure\n");
+
+	if (t->radio) {
+		dprintk("tda9885/6/7: FM Radio mode\n");
+		buf = buf_fm_stereo;
+
+	} else if (t->tvnorm == VIDEO_MODE_PAL) {
+		dprintk("tda9885/6/7: PAL-%c mode\n",pal[0]);
+		switch (pal[0]) {
+		case 'b':
+		case 'g':
+			buf = buf_pal_bg;
+			break;
+		case 'i':
+			buf = buf_pal_i;
+			break;
+		case 'd':
+		case 'k':
+			buf = buf_pal_dk;
+			break;
+		case 'l':
+			buf = buf_pal_l;
+			break;
+		}
+
+	} else if (t->tvnorm == VIDEO_MODE_NTSC) {
+		dprintk("tda9885/6/7: NTSC mode\n");
+		buf = buf_ntsc;
+
+	} else if (t->tvnorm == VIDEO_MODE_SECAM) {
+		dprintk("tda9885/6/7: SECAM mode\n");
+                buf = buf_pal_l;
+
+        } else if (t->tvnorm == 6 /* BTTV hack */) {
+		dprintk("tda9885/6/7: NTSC-Japan mode\n");
+                buf = buf_ntsc_jp;
+        }
+
+	if (NULL == buf) {
+		printk("tda9885/6/7 unknown norm=%d\n",t->tvnorm);
+		return 0;
+	}
+
+	dprintk("tda9885/6/7: 0x%02x 0x%02x 0x%02x\n",
+		buf[1],buf[2],buf[3]);
+        if (4 != (rc = i2c_master_send(&t->client,buf,4)))
+                printk("tda9885/6/7: i2c i/o error: rc == %d (should be 4)\n",rc);
+	return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int tda9887_attach(struct i2c_adapter *adap, int addr,
+			  unsigned short flags, int kind)
+{
+	struct tda9887 *t;
+
+        client_template.adapter = adap;
+        client_template.addr    = addr;
+
+        printk("tda9887: chip found @ 0x%x\n", addr<<1);
+
+        if (NULL == (t = kmalloc(sizeof(*t), GFP_KERNEL)))
+                return -ENOMEM;
+	memset(t,0,sizeof(*t));
+	t->client = client_template;
+        t->client.data = t;
+	t->pinnacle_id = -1;
+        i2c_attach_client(&t->client);
+        
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int tda9887_probe(struct i2c_adapter *adap)
+{
+	int rc;
+
+	switch (adap->id) {
+	case I2C_ALGO_BIT | I2C_HW_B_BT848:
+	case I2C_ALGO_BIT | I2C_HW_B_RIVA:
+	case I2C_ALGO_SAA7134:
+		printk("tda9887: probing %s i2c adapter [id=0x%x]\n",
+		       adap->name,adap->id);
+		rc = i2c_probe(adap, &addr_data, tda9887_attach);
+		break;
+	default:
+		printk("tda9887: ignoring %s i2c adapter [id=0x%x]\n",
+		       adap->name,adap->id);
+		rc = 0;
+		/* nothing */
+	}
+	return rc;
+}
+
+static int tda9887_detach(struct i2c_client *client)
+{
+	struct tda9887 *t = (struct tda9887*)client->data;
+
+	i2c_detach_client(client);
+	kfree(t);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int
+tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg)
+{
+	struct tda9887 *t = (struct tda9887*)client->data;
+
+        switch (cmd) {
+
+	/* --- configuration --- */
+	case AUDC_SET_RADIO:
+		t->radio = 1;
+		if (-1 != t->pinnacle_id)
+			tda9887_miro(t);
+		else
+			tda9887_configure(t);
+		break;
+		
+	case AUDC_CONFIG_PINNACLE:
+	{
+		int *i = arg;
+
+		t->pinnacle_id = *i;
+		break;
+	}
+	/* --- v4l ioctls --- */
+	/* take care: bttv does userspace copying, we'll get a
+	   kernel pointer here... */
+	case VIDIOCSCHAN:
+	{
+		struct video_channel *vc = arg;
+
+		t->radio  = 0;
+		t->tvnorm = vc->norm;
+		if (-1 != t->pinnacle_id)
+			tda9887_miro(t);
+		else
+			tda9887_configure(t);
+		break;
+	}
+	default:
+		/* nothing */
+		break;
+	}
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_driver driver = {
+        .name           = "i2c tda9887 driver",
+        .id             = -1, /* FIXME */
+        .flags          = I2C_DF_NOTIFY,
+        .attach_adapter = tda9887_probe,
+        .detach_client  = tda9887_detach,
+        .command        = tda9887_command,
+};
+static struct i2c_client client_template =
+{
+        .name   = "tda9887",
+	.flags  = I2C_CLIENT_ALLOW_USE,
+        .driver = &driver,
+};
+
+static int tda9887_init_module(void)
+{
+	i2c_add_driver(&driver);
+	return 0;
+}
+
+static void tda9887_cleanup_module(void)
+{
+	i2c_del_driver(&driver);
+}
+
+module_init(tda9887_init_module);
+module_exit(tda9887_cleanup_module);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff -urN linux-2.4.21-pre3/drivers/media/video/tuner.c linux-2.4.21-pre4/drivers/media/video/tuner.c
--- linux-2.4.21-pre3/drivers/media/video/tuner.c	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre4/drivers/media/video/tuner.c	Tue Jan 28 19:44:30 2003
@@ -18,17 +18,7 @@
 /* Addresses to scan */
 static unsigned short normal_i2c[] = {I2C_CLIENT_END};
 static unsigned short normal_i2c_range[] = {0x60,0x6f,I2C_CLIENT_END};
-static unsigned short probe[2]        = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short probe_range[2]  = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore[2]       = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short force[2]        = { I2C_CLIENT_END, I2C_CLIENT_END };
-static struct i2c_client_address_data addr_data = {
-	normal_i2c, normal_i2c_range, 
-	probe, probe_range, 
-	ignore, ignore_range, 
-	force
-};
+I2C_CLIENT_INSMOD;
 
 /* insmod options */
 static int debug =  0;
@@ -127,7 +117,9 @@
 	unsigned char VHF_H;
 	unsigned char UHF;
 	unsigned char config; 
-	unsigned short IFPCoff; /* 622.4=16*38.90 MHz PAL, 732=16*45.75 NTSC */
+	unsigned short IFPCoff; /* 622.4=16*38.90 MHz PAL, 
+				   732  =16*45.75 NTSCi, 
+				   940  =58.75 NTSC-Japan */
 };
 
 /*
@@ -140,7 +132,7 @@
 	  16*140.25,16*463.25,0x02,0x04,0x01,0x8e,623},
 	{ "Philips PAL_I (FI1246 and compatibles)", Philips, PAL_I,
 	  16*140.25,16*463.25,0xa0,0x90,0x30,0x8e,623},
-	{ "Philips NTSC (FI1236 and compatibles)", Philips, NTSC,
+	{ "Philips NTSC (FI1236,FM1236 and compatibles)", Philips, NTSC,
 	  16*157.25,16*451.25,0xA0,0x90,0x30,0x8e,732},
 	{ "Philips (SECAM+PAL_BG) (FI1216MF, FM1216MF, FR1216MF)", Philips, SECAM,
 	  16*168.25,16*447.25,0xA7,0x97,0x37,0x8e,623},
@@ -303,6 +295,13 @@
                 }
                 printk("\n ");
         }
+	// Look for MT2032 id:
+	// part= 0x04(MT2032), 0x06(MT2030), 0x07(MT2040)
+        if((buf[0x11] != 0x4d) || (buf[0x12] != 0x54) || (buf[0x13] != 0x04)) {
+                printk("not a MT2032.\n");
+                return 0;
+        }
+
 
         // Initialize Registers per spec.
         buf[1]=2; // Index to register 2
@@ -727,6 +726,7 @@
 
         if2=10700*1000; //  10.7MHz FM intermediate frequency
 
+	// per Manual for FM tuning: first if center freq. 1085 MHz
         mt2032_set_if_freq(c,freq* 1000*1000/16, 1085*1000*1000,if2,if2,if2);
 }
 
@@ -802,6 +802,7 @@
         memset(t,0,sizeof(struct tuner));
 	if (type >= 0 && type < TUNERS) {
 		t->type = type;
+		printk("tuner(bttv): type forced to %d (%s) [insmod]\n",t->type,tuners[t->type].name);
 		strncpy(client->name, tuners[t->type].name, sizeof(client->name));
 	} else {
 		t->type = -1;
@@ -811,7 +812,6 @@
                  mt2032_init(client);
 
 	MOD_INC_USE_COUNT;
-
 	return 0;
 }
 
@@ -828,6 +828,7 @@
 	case I2C_ALGO_BIT | I2C_HW_B_BT848:
 	case I2C_ALGO_BIT | I2C_HW_B_RIVA:
 	case I2C_ALGO_SAA7134:
+	case I2C_ALGO_SAA7146:
 		printk("tuner: probing %s i2c adapter [id=0x%x]\n",
 		       adap->name,adap->id);
 		rc = i2c_probe(adap, &addr_data, tuner_attach);
@@ -865,12 +866,14 @@
 
 	/* --- configuration --- */
 	case TUNER_SET_TYPE:
-		if (t->type != -1)
+		if (t->type != -1) {
+			printk("tuner: type already set (%d)\n",t->type);
 			return 0;
+		}
 		if (*iarg < 0 || *iarg >= TUNERS)
 			return 0;
 		t->type = *iarg;
-		dprintk("tuner: type set to %d (%s)\n",
+		printk("tuner: type set to %d (%s)\n",
                         t->type,tuners[t->type].name);
 		strncpy(client->name, tuners[t->type].name, sizeof(client->name));
 		if (t->type == TUNER_MT2032)
@@ -964,18 +967,18 @@
 /* ----------------------------------------------------------------------- */
 
 static struct i2c_driver driver = {
-        name:           "i2c TV tuner driver",
-        id:             I2C_DRIVERID_TUNER,
-        flags:          I2C_DF_NOTIFY,
-        attach_adapter: tuner_probe,
-        detach_client:  tuner_detach,
-        command:        tuner_command,
+        .name           = "i2c TV tuner driver",
+        .id             = I2C_DRIVERID_TUNER,
+        .flags          = I2C_DF_NOTIFY,
+        .attach_adapter = tuner_probe,
+        .detach_client  = tuner_detach,
+        .command        = tuner_command,
 };
 static struct i2c_client client_template =
 {
-        name:   "(unset)",
-	flags:  I2C_CLIENT_ALLOW_USE,
-        driver: &driver,
+        .name   = "(tuner unset)",
+	.flags  = I2C_CLIENT_ALLOW_USE,
+        .driver = &driver,
 };
 
 static int tuner_init_module(void)
diff -urN linux-2.4.21-pre3/drivers/media/video/tuner.h linux-2.4.21-pre4/drivers/media/video/tuner.h
--- linux-2.4.21-pre3/drivers/media/video/tuner.h	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre4/drivers/media/video/tuner.h	Tue Jan 28 19:44:30 2003
@@ -86,7 +86,9 @@
 
 #define TUNER_SET_TYPE               _IOW('t',1,int)    /* set tuner type */
 #define TUNER_SET_TVFREQ             _IOW('t',2,int)    /* set tv freq */
-#define TUNER_SET_RADIOFREQ          _IOW('t',3,int)    /* set radio freq */
-#define TUNER_SET_MODE               _IOW('t',4,int)    /* set tuner mode */
+#if 0 /* obsolete */
+# define TUNER_SET_RADIOFREQ         _IOW('t',3,int)    /* set radio freq */
+# define TUNER_SET_MODE              _IOW('t',4,int)    /* set tuner mode */
+#endif
 
 #endif
diff -urN linux-2.4.21-pre3/drivers/media/video/tvaudio.c linux-2.4.21-pre4/drivers/media/video/tvaudio.c
--- linux-2.4.21-pre3/drivers/media/video/tvaudio.c	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre4/drivers/media/video/tvaudio.c	Tue Jan 28 19:44:30 2003
@@ -146,17 +146,7 @@
 	I2C_PIC16C54  >> 1,
 	I2C_CLIENT_END };
 static unsigned short normal_i2c_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short probe[2]            = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short probe_range[2]      = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore[2]           = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore_range[2]     = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short force[2]            = { I2C_CLIENT_END, I2C_CLIENT_END };
-static struct i2c_client_address_data addr_data = {
-	normal_i2c, normal_i2c_range, 
-	probe, probe_range, 
-	ignore, ignore_range, 
-	force
-};
+I2C_CLIENT_INSMOD;
 
 static struct i2c_driver driver;
 static struct i2c_client client_template;
@@ -1088,6 +1078,19 @@
 static int tda8425_shift10(int val) { return (val >> 10) | 0xc0; }
 static int tda8425_shift12(int val) { return (val >> 12) | 0xf0; }
 
+static int tda8425_initialize(struct CHIPSTATE *chip)
+{
+	struct CHIPDESC *desc = chiplist + chip->type;
+	int inputmap[8] = { /* tuner	*/ TDA8425_S1_CH2, /* radio  */ TDA8425_S1_CH1,
+			    /* extern	*/ TDA8425_S1_CH1, /* intern */ TDA8425_S1_OFF,
+			    /* off	*/ TDA8425_S1_OFF, /* on     */ TDA8425_S1_CH2};
+
+	if (chip->c.adapter->id == (I2C_ALGO_BIT | I2C_HW_B_RIVA)) {
+		memcpy (desc->inputmap, inputmap, sizeof (inputmap));
+	}
+	return 0;
+}
+
 static void tda8425_setmode(struct CHIPSTATE *chip, int mode)
 {
 	int s1 = chip->shadow.bytes[TDA8425_S1+1] & 0xe1;
@@ -1156,165 +1159,166 @@
 
 static struct CHIPDESC chiplist[] = {
 	{
-		name:       "tda9840",
-		id:         I2C_DRIVERID_TDA9840,
-		insmodopt:  &tda9840,
-		addr_lo:    I2C_TDA9840 >> 1,
-		addr_hi:    I2C_TDA9840 >> 1,
-		registers:  5,
-
-		getmode:    tda9840_getmode,
-		setmode:    tda9840_setmode,
-		checkmode:  generic_checkmode,
+		.name       = "tda9840",
+		.id         = I2C_DRIVERID_TDA9840,
+		.insmodopt  = &tda9840,
+		.addr_lo    = I2C_TDA9840 >> 1,
+		.addr_hi    = I2C_TDA9840 >> 1,
+		.registers  = 5,
+
+		.getmode    = tda9840_getmode,
+		.setmode    = tda9840_setmode,
+		.checkmode  = generic_checkmode,
 
-	        init:       { 2, { TDA9840_TEST, TDA9840_TEST_INT1SN
+	        .init       = { 2, { TDA9840_TEST, TDA9840_TEST_INT1SN
 				/* ,TDA9840_SW, TDA9840_MONO */} }
 	},
 	{
-		name:       "tda9873h",
-		id:         I2C_DRIVERID_TDA9873,
-		checkit:    tda9873_checkit,
-		insmodopt:  &tda9873,
-		addr_lo:    I2C_TDA985x_L >> 1,
-		addr_hi:    I2C_TDA985x_H >> 1,
-		registers:  3,
-		flags:      CHIP_HAS_INPUTSEL,
-
-		getmode:    tda9873_getmode,
-		setmode:    tda9873_setmode,
-		checkmode:  generic_checkmode,
-
-		init:       { 4, { TDA9873_SW, 0xa4, 0x06, 0x03 } },
-		inputreg:   TDA9873_SW,
-		inputmute:  TDA9873_MUTE | TDA9873_AUTOMUTE,
-		inputmap:   {0xa0, 0xa2, 0xa0, 0xa0, 0xc0},
-		inputmask:  TDA9873_INP_MASK | TDA9873_MUTE | TDA9873_AUTOMUTE
+		.name       = "tda9873h",
+		.id         = I2C_DRIVERID_TDA9873,
+		.checkit    = tda9873_checkit,
+		.insmodopt  = &tda9873,
+		.addr_lo    = I2C_TDA985x_L >> 1,
+		.addr_hi    = I2C_TDA985x_H >> 1,
+		.registers  = 3,
+		.flags      = CHIP_HAS_INPUTSEL,
+
+		.getmode    = tda9873_getmode,
+		.setmode    = tda9873_setmode,
+		.checkmode  = generic_checkmode,
+
+		.init       = { 4, { TDA9873_SW, 0xa4, 0x06, 0x03 } },
+		.inputreg   = TDA9873_SW,
+		.inputmute  = TDA9873_MUTE | TDA9873_AUTOMUTE,
+		.inputmap   = {0xa0, 0xa2, 0xa0, 0xa0, 0xc0},
+		.inputmask  = TDA9873_INP_MASK|TDA9873_MUTE|TDA9873_AUTOMUTE,
 		
 	},
 	{
-		name:       "tda9874h/a",
-		id:         I2C_DRIVERID_TDA9874,
-		checkit:    tda9874a_checkit,
-		initialize: tda9874a_initialize,
-		insmodopt:  &tda9874a,
-		addr_lo:    I2C_TDA9874 >> 1,
-		addr_hi:    I2C_TDA9874 >> 1,
-
-		getmode:    tda9874a_getmode,
-		setmode:    tda9874a_setmode,
-		checkmode:  generic_checkmode,
+		.name       = "tda9874h/a",
+		.id         = I2C_DRIVERID_TDA9874,
+		.checkit    = tda9874a_checkit,
+		.initialize = tda9874a_initialize,
+		.insmodopt  = &tda9874a,
+		.addr_lo    = I2C_TDA9874 >> 1,
+		.addr_hi    = I2C_TDA9874 >> 1,
+
+		.getmode    = tda9874a_getmode,
+		.setmode    = tda9874a_setmode,
+		.checkmode  = generic_checkmode,
 	},
 	{
-		name:       "tda9850",
-		id:         I2C_DRIVERID_TDA9850,
-		insmodopt:  &tda9850,
-		addr_lo:    I2C_TDA985x_L >> 1,
-		addr_hi:    I2C_TDA985x_H >> 1,
-		registers:  11,
+		.name       = "tda9850",
+		.id         = I2C_DRIVERID_TDA9850,
+		.insmodopt  = &tda9850,
+		.addr_lo    = I2C_TDA985x_L >> 1,
+		.addr_hi    = I2C_TDA985x_H >> 1,
+		.registers  = 11,
 
-		getmode:    tda985x_getmode,
-		setmode:    tda985x_setmode,
+		.getmode    = tda985x_getmode,
+		.setmode    = tda985x_setmode,
 
-		init:       { 8, { TDA9850_C4, 0x08, 0x08, TDA985x_STEREO, 0x07, 0x10, 0x10, 0x03 } }
+		.init       = { 8, { TDA9850_C4, 0x08, 0x08, TDA985x_STEREO, 0x07, 0x10, 0x10, 0x03 } }
 	},
 	{
-		name:       "tda9855",
-		id:         I2C_DRIVERID_TDA9855,
-		insmodopt:  &tda9855,
-		addr_lo:    I2C_TDA985x_L >> 1,
-		addr_hi:    I2C_TDA985x_H >> 1,
-		registers:  11,
-		flags:      CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE,
-
-		leftreg:    TDA9855_VL,
-		rightreg:   TDA9855_VR,
-		bassreg:    TDA9855_BA,
-		treblereg:  TDA9855_TR,
-		volfunc:    tda9855_volume,
-		bassfunc:   tda9855_bass,
-		treblefunc: tda9855_treble,
+		.name       = "tda9855",
+		.id         = I2C_DRIVERID_TDA9855,
+		.insmodopt  = &tda9855,
+		.addr_lo    = I2C_TDA985x_L >> 1,
+		.addr_hi    = I2C_TDA985x_H >> 1,
+		.registers  = 11,
+		.flags      = CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE,
+
+		.leftreg    = TDA9855_VL,
+		.rightreg   = TDA9855_VR,
+		.bassreg    = TDA9855_BA,
+		.treblereg  = TDA9855_TR,
+		.volfunc    = tda9855_volume,
+		.bassfunc   = tda9855_bass,
+		.treblefunc = tda9855_treble,
 
-		getmode:    tda985x_getmode,
-		setmode:    tda985x_setmode,
+		.getmode    = tda985x_getmode,
+		.setmode    = tda985x_setmode,
 
-		init:       { 12, { 0, 0x6f, 0x6f, 0x0e, 0x07<<1, 0x8<<2,
+		.init       = { 12, { 0, 0x6f, 0x6f, 0x0e, 0x07<<1, 0x8<<2,
 				    TDA9855_MUTE | TDA9855_AVL | TDA9855_LOUD | TDA9855_INT,
 				    TDA985x_STEREO | TDA9855_LINEAR | TDA9855_TZCM | TDA9855_VZCM,
 				    0x07, 0x10, 0x10, 0x03 }}
 	},
 	{
-		name:       "tea6300",
-		id:         I2C_DRIVERID_TEA6300,
-		insmodopt:  &tea6300,
-		addr_lo:    I2C_TEA6300 >> 1,
-		addr_hi:    I2C_TEA6300 >> 1,
-		registers:  6,
-		flags:      CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE | CHIP_HAS_INPUTSEL,
-
-		leftreg:    TEA6300_VR,
-		rightreg:   TEA6300_VL,
-		bassreg:    TEA6300_BA,
-		treblereg:  TEA6300_TR,
-		volfunc:    tea6300_shift10,
-		bassfunc:   tea6300_shift12,
-		treblefunc: tea6300_shift12,
-
-		inputreg:   TEA6300_S,
-		inputmap:   { TEA6300_S_SA, TEA6300_S_SB, TEA6300_S_SC },
-		inputmute:  TEA6300_S_GMU,
+		.name       = "tea6300",
+		.id         = I2C_DRIVERID_TEA6300,
+		.insmodopt  = &tea6300,
+		.addr_lo    = I2C_TEA6300 >> 1,
+		.addr_hi    = I2C_TEA6300 >> 1,
+		.registers  = 6,
+		.flags      = CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE | CHIP_HAS_INPUTSEL,
+
+		.leftreg    = TEA6300_VR,
+		.rightreg   = TEA6300_VL,
+		.bassreg    = TEA6300_BA,
+		.treblereg  = TEA6300_TR,
+		.volfunc    = tea6300_shift10,
+		.bassfunc   = tea6300_shift12,
+		.treblefunc = tea6300_shift12,
+
+		.inputreg   = TEA6300_S,
+		.inputmap   = { TEA6300_S_SA, TEA6300_S_SB, TEA6300_S_SC },
+		.inputmute  = TEA6300_S_GMU,
 	},
 	{
-		name:       "tea6420",
-		id:         I2C_DRIVERID_TEA6420,
-		insmodopt:  &tea6420,
-		addr_lo:    I2C_TEA6420 >> 1,
-		addr_hi:    I2C_TEA6420 >> 1,
-		registers:  1,
-		flags:      CHIP_HAS_INPUTSEL,
-
-		inputreg:   -1,
-		inputmap:   { TEA6420_S_SA, TEA6420_S_SB, TEA6420_S_SC },
-		inputmute:  TEA6300_S_GMU,
+		.name       = "tea6420",
+		.id         = I2C_DRIVERID_TEA6420,
+		.insmodopt  = &tea6420,
+		.addr_lo    = I2C_TEA6420 >> 1,
+		.addr_hi    = I2C_TEA6420 >> 1,
+		.registers  = 1,
+		.flags      = CHIP_HAS_INPUTSEL,
+
+		.inputreg   = -1,
+		.inputmap   = { TEA6420_S_SA, TEA6420_S_SB, TEA6420_S_SC },
+		.inputmute  = TEA6300_S_GMU,
 	},
 	{
-		name:       "tda8425",
-		id:         I2C_DRIVERID_TDA8425,
-		insmodopt:  &tda8425,
-		addr_lo:    I2C_TDA8425 >> 1,
-		addr_hi:    I2C_TDA8425 >> 1,
-		registers:  9,
-		flags:      CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE | CHIP_HAS_INPUTSEL,
-
-		leftreg:    TDA8425_VR,
-		rightreg:   TDA8425_VL,
-		bassreg:    TDA8425_BA,
-		treblereg:  TDA8425_TR,
-		volfunc:    tda8425_shift10,
-		bassfunc:   tda8425_shift12,
-		treblefunc: tda8425_shift12,
-
-		inputreg:   TDA8425_S1,
-		inputmap:   { TDA8425_S1_CH1, TDA8425_S1_CH1, TDA8425_S1_CH1 },
-		inputmute:  TDA8425_S1_OFF,
+		.name       = "tda8425",
+		.id         = I2C_DRIVERID_TDA8425,
+		.insmodopt  = &tda8425,
+		.addr_lo    = I2C_TDA8425 >> 1,
+		.addr_hi    = I2C_TDA8425 >> 1,
+		.registers  = 9,
+		.flags      = CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE | CHIP_HAS_INPUTSEL,
+
+		.leftreg    = TDA8425_VL,
+		.rightreg   = TDA8425_VR,
+		.bassreg    = TDA8425_BA,
+		.treblereg  = TDA8425_TR,
+		.volfunc    = tda8425_shift10,
+		.bassfunc   = tda8425_shift12,
+		.treblefunc = tda8425_shift12,
+
+		.inputreg   = TDA8425_S1,
+		.inputmap   = { TDA8425_S1_CH1, TDA8425_S1_CH1, TDA8425_S1_CH1 },
+		.inputmute  = TDA8425_S1_OFF,
 
-		setmode:    tda8425_setmode,
+		.setmode    = tda8425_setmode,
+		.initialize = tda8425_initialize,
 	},
 	{
-		name:       "pic16c54 (PV951)",
-		id:         I2C_DRIVERID_PIC16C54_PV951,
-		insmodopt:  &pic16c54,
-		addr_lo:    I2C_PIC16C54 >> 1,
-		addr_hi:    I2C_PIC16C54>> 1,
-		registers:  2,
-		flags:      CHIP_HAS_INPUTSEL,
+		.name       = "pic16c54 (PV951)",
+		.id         = I2C_DRIVERID_PIC16C54_PV951,
+		.insmodopt  = &pic16c54,
+		.addr_lo    = I2C_PIC16C54 >> 1,
+		.addr_hi    = I2C_PIC16C54>> 1,
+		.registers  = 2,
+		.flags      = CHIP_HAS_INPUTSEL,
 
-		inputreg:   PIC16C54_REG_MISC,
-		inputmap:   {PIC16C54_MISC_SND_NOTMUTE|PIC16C54_MISC_SWITCH_TUNER,
+		.inputreg   = PIC16C54_REG_MISC,
+		.inputmap   = {PIC16C54_MISC_SND_NOTMUTE|PIC16C54_MISC_SWITCH_TUNER,
 			     PIC16C54_MISC_SND_NOTMUTE|PIC16C54_MISC_SWITCH_LINE,
 			     PIC16C54_MISC_SND_NOTMUTE|PIC16C54_MISC_SWITCH_LINE,
 			     PIC16C54_MISC_SND_MUTE,PIC16C54_MISC_SND_MUTE,
 			     PIC16C54_MISC_SND_NOTMUTE},
-		inputmute:  PIC16C54_MISC_SND_MUTE,
+		.inputmute  = PIC16C54_MISC_SND_MUTE,
 	},
 	{ name: NULL } /* EOF */
 };
@@ -1392,6 +1396,7 @@
 		/* start async thread */
 		DECLARE_MUTEX_LOCKED(sem);
 		chip->notify = &sem;
+		init_timer(&chip->wt);
 		chip->wt.function = chip_thread_wake;
 		chip->wt.data     = (unsigned long)chip;
 		init_waitqueue_head(&chip->wq);
@@ -1543,19 +1548,19 @@
 
 
 static struct i2c_driver driver = {
-        name:            "generic i2c audio driver",
-        id:              I2C_DRIVERID_TVAUDIO,
-        flags:           I2C_DF_NOTIFY,
-        attach_adapter:  chip_probe,
-        detach_client:   chip_detach,
-        command:         chip_command,
+        .name            = "generic i2c audio driver",
+        .id              = I2C_DRIVERID_TVAUDIO,
+        .flags           = I2C_DF_NOTIFY,
+        .attach_adapter  = chip_probe,
+        .detach_client   = chip_detach,
+        .command         = chip_command,
 };
 
 static struct i2c_client client_template =
 {
-        name:   "(unset)",
-	flags:  I2C_CLIENT_ALLOW_USE,
-        driver: &driver,
+        .name   = "(unset)",
+	.flags  = I2C_CLIENT_ALLOW_USE,
+        .driver = &driver,
 };
 
 static int audiochip_init_module(void)
diff -urN linux-2.4.21-pre3/drivers/media/video/tvmixer.c linux-2.4.21-pre4/drivers/media/video/tvmixer.c
--- linux-2.4.21-pre3/drivers/media/video/tvmixer.c	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre4/drivers/media/video/tvmixer.c	Tue Jan 28 19:44:30 2003
@@ -216,19 +216,19 @@
 }
 
 static struct i2c_driver driver = {
-	name:            "tv card mixer driver",
-        id:              I2C_DRIVERID_TVMIXER,
-	flags:           I2C_DF_DUMMY,
-        attach_adapter:  tvmixer_adapters,
-        detach_client:   tvmixer_clients,
+	.name            = "tv card mixer driver",
+        .id              = I2C_DRIVERID_TVMIXER,
+	.flags           = I2C_DF_DUMMY,
+        .attach_adapter  = tvmixer_adapters,
+        .detach_client   = tvmixer_clients,
 };
 
 static struct file_operations tvmixer_fops = {
-	owner:		THIS_MODULE,
-	llseek:         no_llseek,
-	ioctl:          tvmixer_ioctl,
-	open:           tvmixer_open,
-	release:        tvmixer_release,
+	.owner		= THIS_MODULE,
+	.llseek         = no_llseek,
+	.ioctl          = tvmixer_ioctl,
+	.open           = tvmixer_open,
+	.release        = tvmixer_release,
 };
 
 /* ----------------------------------------------------------------------- */
diff -urN linux-2.4.21-pre3/drivers/media/video/videodev.c linux-2.4.21-pre4/drivers/media/video/videodev.c
--- linux-2.4.21-pre3/drivers/media/video/videodev.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.21-pre4/drivers/media/video/videodev.c	Tue Jan 28 19:44:30 2003
@@ -186,14 +186,21 @@
 static int video_release(struct inode *inode, struct file *file)
 {
 	struct video_device *vfl;
+	struct module *owner;
 
-	down(&videodev_lock);
 	vfl = video_devdata(file);
-	if(vfl->close)
+	owner = vfl->owner;
+	if (vfl->close)
 		vfl->close(vfl);
-	vfl->users--;
-	if(vfl->owner)
-		__MOD_DEC_USE_COUNT(vfl->owner);
+
+	down(&videodev_lock);
+	/* ->close() might have called video_device_unregister()
+           in case of a hot unplug, thus we have to get vfl again */
+	vfl = video_devdata(file);
+	if (NULL != vfl)
+		vfl->users--;
+	if (owner)
+		__MOD_DEC_USE_COUNT(owner);
 	up(&videodev_lock);
 	return 0;
 }
diff -urN linux-2.4.21-pre3/drivers/mtd/Config.in linux-2.4.21-pre4/drivers/mtd/Config.in
--- linux-2.4.21-pre3/drivers/mtd/Config.in	Fri Aug  2 17:39:44 2002
+++ linux-2.4.21-pre4/drivers/mtd/Config.in	Tue Jan 28 19:44:30 2003
@@ -1,5 +1,5 @@
 
-# $Id: Config.in,v 1.73 2002/03/08 16:34:35 rkaiser Exp $
+# $Id: Config.in,v 1.74 2002/04/23 13:52:14 mag Exp $
 
 mainmenu_option next_comment
 comment 'Memory Technology Devices (MTD)'
@@ -14,8 +14,8 @@
    dep_tristate '  MTD partitioning support' CONFIG_MTD_PARTITIONS $CONFIG_MTD
    dep_tristate '  MTD concatenating support' CONFIG_MTD_CONCAT $CONFIG_MTD
    dep_tristate '  RedBoot partition table parsing' CONFIG_MTD_REDBOOT_PARTS $CONFIG_MTD_PARTITIONS
+   dep_tristate '  Command line partition table parsing' CONFIG_MTD_CMDLINE_PARTS $CONFIG_MTD_PARTITIONS
    if [ "$CONFIG_ARM" = "y" ]; then
-      dep_tristate '  Compaq bootldr partition table parsing' CONFIG_MTD_BOOTLDR_PARTS $CONFIG_MTD_PARTITIONS
       dep_tristate '  ARM Firmware Suite partition parsing' CONFIG_MTD_AFS_PARTS $CONFIG_MTD_PARTITIONS
    fi
 
diff -urN linux-2.4.21-pre3/drivers/mtd/Makefile linux-2.4.21-pre4/drivers/mtd/Makefile
--- linux-2.4.21-pre3/drivers/mtd/Makefile	Fri Aug  2 17:39:44 2002
+++ linux-2.4.21-pre4/drivers/mtd/Makefile	Tue Jan 28 19:44:30 2003
@@ -19,7 +19,7 @@
 
 O_TARGET	:= mtdlink.o
 
-export-objs	:= mtdcore.o mtdpart.o redboot.o bootldr.o afs.o mtdconcat.o
+export-objs	:= mtdcore.o mtdpart.o redboot.o cmdlinepart.o afs.o mtdconcat.o
 list-multi	:= nftl.o
 
 mod-subdirs	:= 
@@ -44,10 +44,10 @@
 
 # Core functionality.
 obj-$(CONFIG_MTD)		+= mtdcore.o
-obj-$(CONFIG_MTD_CONCAT)		+= mtdconcat.o
+obj-$(CONFIG_MTD_CONCAT)	+= mtdconcat.o
 obj-$(CONFIG_MTD_PARTITIONS)	+= mtdpart.o
 obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
-obj-$(CONFIG_MTD_BOOTLDR_PARTS) += bootldr.o
+obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o
 obj-$(CONFIG_MTD_AFS_PARTS)	+= afs.o
 
 # 'Users' - code which presents functionality to userspace.
diff -urN linux-2.4.21-pre3/drivers/mtd/afs.c linux-2.4.21-pre4/drivers/mtd/afs.c
--- linux-2.4.21-pre3/drivers/mtd/afs.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.21-pre4/drivers/mtd/afs.c	Tue Jan 28 19:44:30 2003
@@ -21,7 +21,7 @@
    This is access code for flashes using ARM's flash partitioning 
    standards.
 
-   $Id: afs.c,v 1.7 2001/11/01 20:04:54 rmk Exp $
+   $Id: afs.c,v 1.8 2002/05/04 08:49:09 rmk Exp $
 
 ======================================================================*/
 
@@ -169,6 +169,7 @@
 	if (!parts)
 		return -ENOMEM;
 
+	memset(parts, 0, sz);
 	str = (char *)(parts + idx);
 
 	/*
diff -urN linux-2.4.21-pre3/drivers/mtd/bootldr.c linux-2.4.21-pre4/drivers/mtd/bootldr.c
--- linux-2.4.21-pre3/drivers/mtd/bootldr.c	Thu Oct  4 15:14:44 2001
+++ linux-2.4.21-pre4/drivers/mtd/bootldr.c	Wed Dec 31 16:00:00 1969
@@ -1,214 +0,0 @@
-/*
- * Read flash partition table from Compaq Bootloader
- *
- * Copyright 2001 Compaq Computer Corporation.
- *
- * $Id: bootldr.c,v 1.6 2001/10/02 15:05:11 dwmw2 Exp $
- *
- * Use consistent with the GNU GPL is permitted,
- * provided that this copyright notice is
- * preserved in its entirety in all copies and derived works.
- *
- * COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
- * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
- * FITNESS FOR ANY PARTICULAR PURPOSE.
- *
- */
-
-/*
- * Maintainer: Jamey Hicks (jamey.hicks@compaq.com)
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/partitions.h>
-#include <asm/setup.h>
-#include <linux/bootmem.h>
-
-#define FLASH_PARTITION_NAMELEN 32
-enum LFR_FLAGS {
-   LFR_SIZE_PREFIX = 1,		/* prefix data with 4-byte size */
-   LFR_PATCH_BOOTLDR = 2,	/* patch bootloader's 0th instruction */
-   LFR_KERNEL = 4,		/* add BOOTIMG_MAGIC, imgsize and VKERNEL_BASE to head of programmed region (see bootldr.c) */
-   LFR_EXPAND = 8               /* expand partition size to fit rest of flash */
-};
-
-// the tags are parsed too early to malloc or alloc_bootmem so we'll fix it
-// for now
-#define MAX_NUM_PARTITIONS 8
-typedef struct FlashRegion {
-   char name[FLASH_PARTITION_NAMELEN];
-   unsigned long base;
-   unsigned long size;
-   enum LFR_FLAGS flags;
-} FlashRegion;
-
-typedef struct BootldrFlashPartitionTable {
-  int magic; /* should be filled with 0x646c7470 (btlp) BOOTLDR_PARTITION_MAGIC */
-  int npartitions;
-  struct FlashRegion partition[8];
-} BootldrFlashPartitionTable;
-
-#define BOOTLDR_MAGIC      0x646c7462        /* btld: marks a valid bootldr image */
-#define BOOTLDR_PARTITION_MAGIC  0x646c7470  /* btlp: marks a valid bootldr partition table in params sector */
-
-#define BOOTLDR_MAGIC_OFFSET 0x20 /* offset 0x20 into the bootldr */
-#define BOOTCAP_OFFSET 0X30 /* offset 0x30 into the bootldr */
-
-#define BOOTCAP_WAKEUP	(1<<0)
-#define BOOTCAP_PARTITIONS (1<<1) /* partition table stored in params sector */
-#define BOOTCAP_PARAMS_AFTER_BOOTLDR (1<<2) /* params sector right after bootldr sector(s), else in last sector */
-
-static struct BootldrFlashPartitionTable Table;
-static struct BootldrFlashPartitionTable *partition_table = NULL;
-
-
-int parse_bootldr_partitions(struct mtd_info *master, struct mtd_partition **pparts)
-{
-	struct mtd_partition *parts;
-	int ret, retlen, i;
-	int npartitions = 0;
-	long partition_table_offset;
-	long bootmagic = 0;
-	long bootcap = 0;
-	int namelen = 0;
-
-	char *names; 
-
-#if 0
-	/* verify bootldr magic */
-	ret = master->read(master, BOOTLDR_MAGIC_OFFSET, sizeof(long), &retlen, (void *)&bootmagic);
-	if (ret) 
-		goto out;
-        if (bootmagic != BOOTLDR_MAGIC)
-                goto out;
-	/* see if bootldr supports partition tables and where to find the partition table */
-	ret = master->read(master, BOOTCAP_OFFSET, sizeof(long), &retlen, (void *)&bootcap);
-	if (ret) 
-		goto out;
-
-	if (!(bootcap & BOOTCAP_PARTITIONS))
-		goto out;
-	if (bootcap & BOOTCAP_PARAMS_AFTER_BOOTLDR)
-		partition_table_offset = master->erasesize;
-	else
-		partition_table_offset = master->size - master->erasesize;
-
-	printk(__FUNCTION__ ": partition_table_offset=%#lx\n", partition_table_offset);
-	printk(__FUNCTION__ ": ptable_addr=%#lx\n", ptable_addr);
-
-
-	/* Read the partition table */
-	partition_table = (struct BootldrFlashPartitionTable *)kmalloc(PAGE_SIZE, GFP_KERNEL);
-	if (!partition_table)
-		return -ENOMEM;
-
-	ret = master->read(master, partition_table_offset,
-			   PAGE_SIZE, &retlen, (void *)partition_table);
-	if (ret)
-	    goto out;
-
-#endif
-	if (!partition_table)
-	    return -ENOMEM;
-
-	
-	printk(__FUNCTION__ ": magic=%#x\n", partition_table->magic);
-	printk(__FUNCTION__ ": numPartitions=%#x\n", partition_table->npartitions);
-
-
-	/* check for partition table magic number */
-	if (partition_table->magic != BOOTLDR_PARTITION_MAGIC) 
-		goto out;
-	npartitions = (partition_table->npartitions > MAX_NUM_PARTITIONS)?
-	    MAX_NUM_PARTITIONS:partition_table->npartitions;	
-
-	printk(__FUNCTION__ ": npartitions=%#x\n", npartitions);
-
-	for (i = 0; i < npartitions; i++) {
-		namelen += strlen(partition_table->partition[i].name) + 1;
-	}
-
-	parts = kmalloc(sizeof(*parts)*npartitions + namelen, GFP_KERNEL);
-	if (!parts) {
-		ret = -ENOMEM;
-		goto out;
-	}
-	names = (char *)&parts[npartitions];
-	memset(parts, 0, sizeof(*parts)*npartitions + namelen);
-
-
-
-	// from here we use the partition table
-	for (i = 0; i < npartitions; i++) {
-                struct FlashRegion *partition = &partition_table->partition[i];
-		const char *name = partition->name;
-		parts[i].name = names;
-		names += strlen(name) + 1;
-		strcpy(parts[i].name, name);
-
-                if (partition->flags & LFR_EXPAND)
-                        parts[i].size = MTDPART_SIZ_FULL;
-                else
-                        parts[i].size = partition->size;
-		parts[i].offset = partition->base;
-		parts[i].mask_flags = 0;
-		
-		printk("        partition %s o=%x s=%x\n", 
-		       parts[i].name, parts[i].offset, parts[i].size);
-
-	}
-
-	ret = npartitions;
-	*pparts = parts;
-
- out:
-#if 0
-	if (partition_table)
-		kfree(partition_table);
-#endif
-	
-	return ret;
-}
-
-
-static int __init parse_tag_ptable(const struct tag *tag)
-{
-    char buf[128];
-    int i;
-    int j;
-    
-    partition_table = &Table;
-
-#ifdef CONFIG_DEBUG_LL    
-    sprintf(buf,"ptable: magic = = 0x%lx  npartitions= %d \n",
-	    tag->u.ptable.magic,tag->u.ptable.npartitions);
-    printascii(buf);
-    
-    for (i=0; i<tag->u.ptable.npartitions; i++){
-	sprintf(buf,"ptable: partition name = %s base= 0x%lx  size= 0x%lx flags= 0x%lx\n",
-	    (char *) (&tag->u.ptable.partition[i].name[0]),
-		tag->u.ptable.partition[i].base,
-		tag->u.ptable.partition[i].size,
-		tag->u.ptable.partition[i].flags);
-	printascii(buf);
-    }
-#endif
-
-    memcpy((void *)partition_table,(void *) (&(tag->u.ptable)),sizeof(partition_table) +
-	sizeof(struct FlashRegion)*tag->u.ptable.npartitions);
-
-    
-    return 0;
-}
-
-__tagtable(ATAG_PTABLE, parse_tag_ptable);
-
-EXPORT_SYMBOL(parse_bootldr_partitions);
-
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Compaq Computer Corporation");
-MODULE_DESCRIPTION("Parsing code for Compaq bootldr partitions");
diff -urN linux-2.4.21-pre3/drivers/mtd/chips/Config.in linux-2.4.21-pre4/drivers/mtd/chips/Config.in
--- linux-2.4.21-pre3/drivers/mtd/chips/Config.in	Thu Oct  4 15:13:18 2001
+++ linux-2.4.21-pre4/drivers/mtd/chips/Config.in	Tue Jan 28 19:44:30 2003
@@ -1,19 +1,18 @@
 # drivers/mtd/chips/Config.in
 
-# $Id: Config.in,v 1.12 2001/09/23 15:35:21 dwmw2 Exp $
+# $Id: Config.in,v 1.16 2002/09/03 13:30:43 joern Exp $
 
 mainmenu_option next_comment
 
 comment 'RAM/ROM/Flash chip drivers'
 
 dep_tristate '  Detect flash chips by Common Flash Interface (CFI) probe' CONFIG_MTD_CFI $CONFIG_MTD
-#dep_tristate '  Detect non-CFI Intel-compatible flash chips' CONFIG_MTD_INTELPROBE $CONFIG_MTD
-dep_tristate '  Detect non-CFI AMD/JEDEC-compatible flash chips' CONFIG_MTD_JEDECPROBE $CONFIG_MTD
+dep_tristate '  Detect JEDEC JESD21c compatible flash chips' CONFIG_MTD_JEDECPROBE $CONFIG_MTD
 
-if [ "$CONFIG_MTD_CFI" = "y" -o "$CONFIG_MTD_INTELPROBE" = "y" -o "$CONFIG_MTD_JEDECPROBE" = "y" ]; then
+if [ "$CONFIG_MTD_CFI" = "y" -o "$CONFIG_MTD_JEDECPROBE" = "y" ]; then
    define_bool CONFIG_MTD_GEN_PROBE y
 else
-   if [ "$CONFIG_MTD_CFI" = "m" -o "$CONFIG_MTD_INTELPROBE" = "m" -o "$CONFIG_MTD_JEDECPROBE" = "m" ]; then
+   if [ "$CONFIG_MTD_CFI" = "m" -o "$CONFIG_MTD_JEDECPROBE" = "m" ]; then
       define_bool CONFIG_MTD_GEN_PROBE m
    else
       define_bool CONFIG_MTD_GEN_PROBE n
@@ -31,6 +30,7 @@
        bool '    Support  8-bit buswidth' CONFIG_MTD_CFI_B1
        bool '    Support 16-bit buswidth' CONFIG_MTD_CFI_B2
        bool '    Support 32-bit buswidth' CONFIG_MTD_CFI_B4
+       bool '    Support 64-bit buswidth' CONFIG_MTD_CFI_B8
 	 if [ "$CONFIG_MTD_CFI_B1" = "y" ]; then
 	   define_bool CONFIG_MTD_CFI_I1 y
          else
@@ -38,11 +38,13 @@
 	 fi
        bool '    Support 2-chip flash interleave' CONFIG_MTD_CFI_I2
        bool '    Support 4-chip flash interleave' CONFIG_MTD_CFI_I4
+       bool '    Support 8-chip flash interleave' CONFIG_MTD_CFI_I8
      fi
   fi
 fi
 dep_tristate '  Support for Intel/Sharp flash chips' CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_GEN_PROBE
 dep_tristate '  Support for AMD/Fujitsu flash chips' CONFIG_MTD_CFI_AMDSTD $CONFIG_MTD_GEN_PROBE
+dep_tristate '  Support for ST (Advanced Architecture) flash chips' CONFIG_MTD_CFI_STAA $CONFIG_MTD_GEN_PROBE
 
 dep_tristate '  Support for RAM chips in bus mapping' CONFIG_MTD_RAM $CONFIG_MTD
 dep_tristate '  Support for ROM chips in bus mapping' CONFIG_MTD_ROM $CONFIG_MTD
diff -urN linux-2.4.21-pre3/drivers/mtd/chips/amd_flash.c linux-2.4.21-pre4/drivers/mtd/chips/amd_flash.c
--- linux-2.4.21-pre3/drivers/mtd/chips/amd_flash.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.21-pre4/drivers/mtd/chips/amd_flash.c	Tue Jan 28 19:44:30 2003
@@ -3,7 +3,7 @@
  *
  * Author: Jonas Holmberg <jonas.holmberg@axis.com>
  *
- * $Id: amd_flash.c,v 1.17 2002/03/05 17:00:37 jonashg Exp $
+ * $Id: amd_flash.c,v 1.19 2003/01/24 13:30:11 dwmw2 Exp $
  *
  * Copyright (c) 2001 Axis Communications AB
  *
@@ -75,6 +75,7 @@
 /* Fujitsu */
 #define MBM29LV160TE	0x22C4
 #define MBM29LV160BE	0x2249
+#define MBM29LV800BB	0x225B
 
 /* ST - www.st.com */
 #define M29W800T	0x00D7
@@ -560,6 +561,18 @@
 			{ offset: 0x0FC000, erasesize: 0x04000, numblocks:  1 }
 		}
 	}, {
+		mfr_id: MANUFACTURER_FUJITSU,
+		dev_id: MBM29LV800BB,
+		name: "Fujitsu MBM29LV800BB",
+		size: 0x00100000,
+		numeraseregions: 4,
+		regions: {
+			{ offset: 0x000000, erasesize: 0x04000, numblocks:  1 },
+			{ offset: 0x004000, erasesize: 0x02000, numblocks:  2 },
+			{ offset: 0x008000, erasesize: 0x08000, numblocks:  1 },
+			{ offset: 0x010000, erasesize: 0x10000, numblocks: 15 }
+		}
+	}, {
 		mfr_id: MANUFACTURER_ST,
 		dev_id: M29W800T,
 		name: "ST M29W800T",
@@ -913,7 +926,7 @@
 
 	times_left = 500000;
 	while (times_left-- && flash_is_busy(map, adr, private->interleave)) { 
-		if (current->need_resched) {
+		if (need_resched()) {
 			spin_unlock_bh(chip->mutex);
 			schedule();
 			spin_lock_bh(chip->mutex);
@@ -1150,7 +1163,7 @@
 		/* Latency issues. Drop the lock, wait a while and retry */
 		spin_unlock_bh(chip->mutex);
 
-		if (current->need_resched)
+		if (need_resched())
 			schedule();
 		else
 			udelay(1);
diff -urN linux-2.4.21-pre3/drivers/mtd/chips/cfi_cmdset_0001.c linux-2.4.21-pre4/drivers/mtd/chips/cfi_cmdset_0001.c
--- linux-2.4.21-pre3/drivers/mtd/chips/cfi_cmdset_0001.c	Thu Oct  4 15:14:59 2001
+++ linux-2.4.21-pre4/drivers/mtd/chips/cfi_cmdset_0001.c	Tue Jan 28 19:44:30 2003
@@ -4,7 +4,7 @@
  *
  * (C) 2000 Red Hat. GPL'd
  *
- * $Id: cfi_cmdset_0001.c,v 1.87 2001/10/02 15:05:11 dwmw2 Exp $
+ * $Id: cfi_cmdset_0001.c,v 1.110 2003/01/09 16:57:28 jocke Exp $
  *
  * 
  * 10/10/2000	Nicolas Pitre <nico@cam.org>
@@ -13,6 +13,8 @@
  * 	- scalability vs code size is completely set at compile-time
  * 	  (see include/linux/mtd/cfi.h for selection)
  *	- optimized write buffer method
+ * 02/05/2002	Christopher Hoover <ch@hpl.hp.com>/<ch@murgatroid.com>
+ *	- reworked lock/unlock/erase support for var size flash
  */
 
 #include <linux/module.h>
@@ -30,7 +32,11 @@
 #include <linux/mtd/cfi.h>
 #include <linux/mtd/compatmac.h>
 
+// debugging, turns off buffer write mode #define FORCE_WORD_WRITE
+
 static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
+static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
+static int cfi_intelext_read_fact_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
 static int cfi_intelext_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
 static int cfi_intelext_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
 static int cfi_intelext_erase_varsize(struct mtd_info *, struct erase_info *);
@@ -46,6 +52,11 @@
 
 static struct mtd_info *cfi_intelext_setup (struct map_info *);
 
+static int do_point (struct mtd_info *mtd, loff_t from, size_t len,
+		     size_t *retlen, u_char **mtdbuf);
+static void do_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from,
+			size_t len);
+
 static struct mtd_chip_driver cfi_intelext_chipdrv = {
 	probe: NULL, /* Not usable directly */
 	destroy: cfi_intelext_destroy,
@@ -59,6 +70,7 @@
 #ifdef DEBUG_CFI_FEATURES
 static void cfi_tell_features(struct cfi_pri_intelext *extp)
 {
+	int i;
 	printk("  Feature/Command Support: %4.4X\n", extp->FeatureSupport);
 	printk("     - Chip Erase:         %s\n", extp->FeatureSupport&1?"supported":"unsupported");
 	printk("     - Suspend Erase:      %s\n", extp->FeatureSupport&2?"supported":"unsupported");
@@ -110,7 +122,7 @@
 	int i;
 	__u32 base = cfi->chips[0].start;
 
-	if (cfi->cfi_mode) {
+	if (cfi->cfi_mode == CFI_MODE_CFI) {
 		/* 
 		 * It's a real CFI chip, not one for which the probe
 		 * routine faked a CFI structure. So we read the feature
@@ -149,26 +161,34 @@
 		}
 		
 		/* Do some byteswapping if necessary */
-		extp->FeatureSupport = cfi32_to_cpu(extp->FeatureSupport);
-		extp->BlkStatusRegMask = cfi32_to_cpu(extp->BlkStatusRegMask);
-		
+		extp->FeatureSupport = le32_to_cpu(extp->FeatureSupport);
+		extp->BlkStatusRegMask = le16_to_cpu(extp->BlkStatusRegMask);
+		extp->ProtRegAddr = le16_to_cpu(extp->ProtRegAddr);
+			
 #ifdef DEBUG_CFI_FEATURES
 		/* Tell the user about it in lots of lovely detail */
 		cfi_tell_features(extp);
 #endif	
 
+#ifdef DISABLE_ERASE_SUSPEND_ON_WRITE
+/* Enable this if you suspect buggy suspend support */ 
+		if(extp->SuspendCmdSupport & 1)
+			printk(KERN_WARNING "cfi_cmdset_0001: Suspend "
+			       "erase on write disabled.\n");
+		extp->SuspendCmdSupport &= ~1;
+#endif
 		/* Install our own private info structure */
-		cfi->cmdset_priv = extp;
-	}	
+		cfi->cmdset_priv = extp;	
+	}
 
 	for (i=0; i< cfi->numchips; i++) {
-		cfi->chips[i].word_write_time = 128;
-		cfi->chips[i].buffer_write_time = 128;
-		cfi->chips[i].erase_time = 1024;
+		cfi->chips[i].word_write_time = 1<<cfi->cfiq->WordWriteTimeoutTyp;
+		cfi->chips[i].buffer_write_time = 1<<cfi->cfiq->BufWriteTimeoutTyp;
+		cfi->chips[i].erase_time = 1<<cfi->cfiq->BlockEraseTimeoutTyp;
+		cfi->chips[i].ref_point_counter = 0;
 	}		
 
 	map->fldrv = &cfi_intelext_chipdrv;
-	MOD_INC_USE_COUNT;
 	
 	/* Make sure it's in read mode */
 	cfi_send_gen_cmd(0xff, 0x55, base, map, cfi, cfi->device_type, NULL);
@@ -188,8 +208,7 @@
 
 	if (!mtd) {
 		printk(KERN_ERR "Failed to allocate memory for MTD device\n");
-		kfree(cfi->cmdset_priv);
-		return NULL;
+		goto setup_err;
 	}
 
 	memset(mtd, 0, sizeof(*mtd));
@@ -202,8 +221,7 @@
 			* mtd->numeraseregions, GFP_KERNEL);
 	if (!mtd->eraseregions) { 
 		printk(KERN_ERR "Failed to allocate memory for MTD erase region info\n");
-		kfree(cfi->cmdset_priv);
-		return NULL;
+		goto setup_err;
 	}
 	
 	for (i=0; i<cfi->cfiq->NumEraseRegions; i++) {
@@ -220,33 +238,43 @@
 			mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].numblocks = ernum;
 		}
 		offset += (ersize * ernum);
-		}
+	}
 
-		if (offset != devsize) {
-			/* Argh */
-			printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize);
-			kfree(mtd->eraseregions);
-			kfree(cfi->cmdset_priv);
-			return NULL;
-		}
+	if (offset != devsize) {
+		/* Argh */
+		printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize);
+		goto setup_err;
+	}
 
-		for (i=0; i<mtd->numeraseregions;i++){
-			printk(KERN_DEBUG "%d: offset=0x%x,size=0x%x,blocks=%d\n",
-			       i,mtd->eraseregions[i].offset,
-			       mtd->eraseregions[i].erasesize,
-			       mtd->eraseregions[i].numblocks);
-		}
+	for (i=0; i<mtd->numeraseregions;i++){
+		printk(KERN_DEBUG "%d: offset=0x%x,size=0x%x,blocks=%d\n",
+		       i,mtd->eraseregions[i].offset,
+		       mtd->eraseregions[i].erasesize,
+		       mtd->eraseregions[i].numblocks);
+	}
 
 	/* Also select the correct geometry setup too */ 
-		mtd->erase = cfi_intelext_erase_varsize;
+	mtd->erase = cfi_intelext_erase_varsize;
 	mtd->read = cfi_intelext_read;
+
+	if(map->point && map->unpoint){
+		mtd->point = do_point;
+		mtd->unpoint = do_unpoint;
+	}
+
+#ifndef FORCE_WORD_WRITE
 	if ( cfi->cfiq->BufWriteTimeoutTyp ) {
-		//printk(KERN_INFO "Using buffer write method\n" );
+		printk("Using buffer write method\n" );
 		mtd->write = cfi_intelext_write_buffers;
 	} else {
-		//printk(KERN_INFO "Using word write method\n" );
+#else
+	{
+#endif
+		printk("Using word write method\n" );
 		mtd->write = cfi_intelext_write_words;
 	}
+	mtd->read_user_prot_reg = cfi_intelext_read_user_prot_reg;
+	mtd->read_fact_prot_reg = cfi_intelext_read_fact_prot_reg;
 	mtd->sync = cfi_intelext_sync;
 	mtd->lock = cfi_intelext_lock;
 	mtd->unlock = cfi_intelext_unlock;
@@ -257,12 +285,181 @@
 	MOD_INC_USE_COUNT;
 	mtd->name = map->name;
 	return mtd;
+
+ setup_err:
+	if(mtd) {
+		if(mtd->eraseregions)
+			kfree(mtd->eraseregions);
+		kfree(mtd);
+	}
+	kfree(cfi->cmdset_priv);
+	kfree(cfi->cfiq);
+	return NULL;
+}
+
+static int do_point_onechip (struct map_info *map,  struct flchip *chip, loff_t adr, size_t len)
+{
+	cfi_word status, status_OK;
+	unsigned long timeo;
+	DECLARE_WAITQUEUE(wait, current);
+	unsigned long cmd_addr;
+	struct cfi_private *cfi = map->fldrv_priv;
+
+	adr += chip->start;
+
+	/* Ensure cmd read/writes are aligned. */ 
+	cmd_addr = adr & ~(CFIDEV_BUSWIDTH-1); 
+
+	/* Let's determine this according to the interleave only once */
+	status_OK = CMD(0x80);
+
+	timeo = jiffies + HZ;
+ retry:
+	spin_lock(chip->mutex);
+
+	/* Check that the chip's ready to talk to us.
+	 * If it's in FL_ERASING state, suspend it and make it talk now.
+	 */
+	switch (chip->state) {
+
+	case FL_READY:
+	case FL_POINT:
+		break;
+
+	case FL_CFI_QUERY:
+	case FL_JEDEC_QUERY:
+		cfi_write(map, CMD(0x70), cmd_addr);
+		chip->state = FL_STATUS;
+
+	case FL_STATUS:
+		status = cfi_read(map, cmd_addr);
+		if ((status & status_OK) == status_OK) {
+			cfi_write(map, CMD(0xff), cmd_addr);
+			chip->state = FL_READY;
+			break;
+		}
+		
+		/* Urgh. Chip not yet ready to talk to us. */
+		if (time_after(jiffies, timeo)) {
+			spin_unlock(chip->mutex);
+			printk(KERN_ERR "waiting for chip to be ready timed out in read. WSM status = %llx\n", (__u64)status);
+			return -EIO;
+		}
+
+		/* Latency issues. Drop the lock, wait a while and retry */
+		spin_unlock(chip->mutex);
+		cfi_udelay(1);
+		goto retry;
+
+	default:
+		/* Stick ourselves on a wait queue to be woken when
+		   someone changes the status */
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		add_wait_queue(&chip->wq, &wait);
+		spin_unlock(chip->mutex);
+		schedule();
+		remove_wait_queue(&chip->wq, &wait);
+		timeo = jiffies + HZ;
+		goto retry;
+	}
+
+	chip->state = FL_POINT;
+	chip->ref_point_counter++;
+	spin_unlock(chip->mutex);
+	return 0;
+}
+static int do_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	unsigned long ofs;
+	int chipnum;
+	int ret = 0;
+
+	if (from + len > mtd->size)
+		return -EINVAL;
+	
+	*mtdbuf = map->point(map, from, len);
+	if(*mtdbuf == NULL)
+		return -EINVAL; /* can not point this region */
+	*retlen = 0;
+
+	/* Now lock the chip(s) to POINT state */
+
+	/* ofs: offset within the first chip that the first read should start */
+	chipnum = (from >> cfi->chipshift);
+	ofs = from - (chipnum <<  cfi->chipshift);
+
+	while (len) {
+		unsigned long thislen;
+
+		if (chipnum >= cfi->numchips)
+			break;
+
+		if ((len + ofs -1) >> cfi->chipshift)
+			thislen = (1<<cfi->chipshift) - ofs;
+		else
+			thislen = len;
+
+		ret = do_point_onechip(map, &cfi->chips[chipnum], ofs, thislen);
+		if (ret)
+			break;
+
+		*retlen += thislen;
+		len -= thislen;
+		
+		ofs = 0;
+		chipnum++;
+	}
+	return 0;
 }
 
+static void do_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	unsigned long ofs;
+	int chipnum;
+
+	map->unpoint(map, addr, from, len);
+	/* Now unlock the chip(s) POINT state */
+
+	/* ofs: offset within the first chip that the first read should start */
+	chipnum = (from >> cfi->chipshift);
+	ofs = from - (chipnum <<  cfi->chipshift);
+
+	while (len) {
+		unsigned long thislen;
+		struct flchip *chip;
+
+		chip = &cfi->chips[chipnum];
+		if (chipnum >= cfi->numchips)
+			break;
+
+		if ((len + ofs -1) >> cfi->chipshift)
+			thislen = (1<<cfi->chipshift) - ofs;
+		else
+			thislen = len;
+
+		spin_lock(chip->mutex);
+		if(chip->state == FL_POINT){
+			chip->ref_point_counter--;
+			if(chip->ref_point_counter == 0)
+				chip->state = FL_READY;
+		} else
+			printk("Warning: unpoint called on non pointed region\n"); /* Should this give an error? */
+		wake_up(&chip->wq);
+		spin_unlock(chip->mutex);
+
+		len -= thislen;
+		ofs = 0;
+		chipnum++;
+	}
+}
 
 static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
 {
-	__u32 status, status_OK;
+	cfi_word status, status_OK;
 	unsigned long timeo;
 	DECLARE_WAITQUEUE(wait, current);
 	int suspended = 0;
@@ -279,14 +476,15 @@
 
 	timeo = jiffies + HZ;
  retry:
-	spin_lock_bh(chip->mutex);
+	spin_lock(chip->mutex);
 
 	/* Check that the chip's ready to talk to us.
 	 * If it's in FL_ERASING state, suspend it and make it talk now.
 	 */
 	switch (chip->state) {
 	case FL_ERASING:
-		if (!((struct cfi_pri_intelext *)cfi->cmdset_priv)->FeatureSupport & 2)
+		if (!cfi->cmdset_priv ||
+		    !(((struct cfi_pri_intelext *)cfi->cmdset_priv)->FeatureSupport & 2))
 			goto sleep; /* We don't support erase suspend */
 		
 		cfi_write (map, CMD(0xb0), cmd_addr);
@@ -310,15 +508,15 @@
 				/* make sure we're in 'read status' mode */
 				cfi_write(map, CMD(0x70), cmd_addr);
 				chip->state = FL_ERASING;
-				spin_unlock_bh(chip->mutex);
+				spin_unlock(chip->mutex);
 				printk(KERN_ERR "Chip not ready after erase "
-				       "suspended: status = 0x%x\n", status);
+				       "suspended: status = 0x%llx\n", (__u64)status);
 				return -EIO;
 			}
 			
-			spin_unlock_bh(chip->mutex);
+			spin_unlock(chip->mutex);
 			cfi_udelay(1);
-			spin_lock_bh(chip->mutex);
+			spin_lock(chip->mutex);
 		}
 		
 		suspended = 1;
@@ -332,6 +530,7 @@
 #endif
 
 	case FL_READY:
+	case FL_POINT:
 		break;
 
 	case FL_CFI_QUERY:
@@ -349,13 +548,13 @@
 		
 		/* Urgh. Chip not yet ready to talk to us. */
 		if (time_after(jiffies, timeo)) {
-			spin_unlock_bh(chip->mutex);
-			printk(KERN_ERR "waiting for chip to be ready timed out in read. WSM status = %x\n", status);
+			spin_unlock(chip->mutex);
+			printk(KERN_ERR "waiting for chip to be ready timed out in read. WSM status = %llx\n", (__u64)status);
 			return -EIO;
 		}
 
 		/* Latency issues. Drop the lock, wait a while and retry */
-		spin_unlock_bh(chip->mutex);
+		spin_unlock(chip->mutex);
 		cfi_udelay(1);
 		goto retry;
 
@@ -365,7 +564,7 @@
 		   someone changes the status */
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		add_wait_queue(&chip->wq, &wait);
-		spin_unlock_bh(chip->mutex);
+		spin_unlock(chip->mutex);
 		schedule();
 		remove_wait_queue(&chip->wq, &wait);
 		timeo = jiffies + HZ;
@@ -390,7 +589,7 @@
 	}
 
 	wake_up(&chip->wq);
-	spin_unlock_bh(chip->mutex);
+	spin_unlock(chip->mutex);
 	return 0;
 }
 
@@ -433,13 +632,124 @@
 	return ret;
 }
 
-static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, __u32 datum)
+static int cfi_intelext_read_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, int base_offst, int reg_sz)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	struct cfi_pri_intelext *extp=cfi->cmdset_priv;
+	int ofs_factor = cfi->interleave * cfi->device_type;
+	int   count=len;
+	struct flchip *chip;
+	int chip_num,offst;
+	unsigned long timeo;
+	DECLARE_WAITQUEUE(wait, current);
+
+	chip=0;
+	/* Calculate which chip & protection register offset we need */
+	chip_num=((unsigned int)from/reg_sz);
+	offst=from-(reg_sz*chip_num)+base_offst;
+
+	while(count){
+		
+		if(chip_num>=cfi->numchips)
+			goto out;
+
+		/* Make sure that the chip is in the right state */
+
+		timeo = jiffies + HZ;
+		chip=&cfi->chips[chip_num];
+	retry:		
+		spin_lock(chip->mutex);
+	
+		switch (chip->state) {
+		case FL_READY:
+		case FL_STATUS:
+		case FL_CFI_QUERY:
+		case FL_JEDEC_QUERY:
+			break;
+		
+		default:
+				/* Stick ourselves on a wait queue to be woken when
+				   someone changes the status */
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			add_wait_queue(&chip->wq, &wait);
+			spin_unlock(chip->mutex);
+			schedule();
+			remove_wait_queue(&chip->wq, &wait);
+			timeo = jiffies + HZ;
+			goto retry;
+		}
+			
+		/* Now read the data required from this flash */
+       
+		cfi_send_gen_cmd(0x90, 0x55,chip->start, map, cfi, cfi->device_type, NULL);
+		while(count && ((offst-base_offst)<reg_sz)){
+			*buf=map->read8(map,(chip->start+((extp->ProtRegAddr+1)*ofs_factor)+offst));
+			buf++;
+			offst++;
+			count--;
+		}
+	       
+		chip->state=FL_CFI_QUERY;
+		spin_unlock(chip->mutex);
+		/* Move on to the next chip */
+		chip_num++;
+		offst=base_offst;
+	
+	}
+	
+ out:	
+	wake_up(&chip->wq);
+	return len-count;
+}
+	
+static int cfi_intelext_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	struct cfi_pri_intelext *extp=cfi->cmdset_priv;
+	int base_offst,reg_sz;
+	
+	/* Check that we actually have some protection registers */
+	if(!(extp->FeatureSupport&64)){
+		printk(KERN_WARNING "%s: This flash device has no protection data to read!\n",map->name);
+		return 0;
+	}
+
+	base_offst=(1<<extp->FactProtRegSize);
+	reg_sz=(1<<extp->UserProtRegSize);
+
+	return cfi_intelext_read_prot_reg(mtd, from, len, retlen, buf, base_offst, reg_sz);
+}
+
+static int cfi_intelext_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	struct cfi_pri_intelext *extp=cfi->cmdset_priv;
+	int base_offst,reg_sz;
+	
+	/* Check that we actually have some protection registers */
+	if(!(extp->FeatureSupport&64)){
+		printk(KERN_WARNING "%s: This flash device has no protection data to read!\n",map->name);
+		return 0;
+	}
+
+	base_offst=0;
+	reg_sz=(1<<extp->FactProtRegSize);
+
+	return cfi_intelext_read_prot_reg(mtd, from, len, retlen, buf, base_offst, reg_sz);
+}
+
+
+static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, cfi_word datum)
 {
 	struct cfi_private *cfi = map->fldrv_priv;
-	__u32 status, status_OK;
+	struct cfi_pri_intelext *extp = cfi->cmdset_priv;
+	cfi_word status, status_OK;
 	unsigned long timeo;
 	DECLARE_WAITQUEUE(wait, current);
-	int z;
+	int z, suspended=0, ret=0;
 
 	adr += chip->start;
 
@@ -448,7 +758,7 @@
 
 	timeo = jiffies + HZ;
  retry:
-	spin_lock_bh(chip->mutex);
+	spin_lock(chip->mutex);
 
 	/* Check that the chip's ready to talk to us.
 	 * Later, we can actually think about interrupting it
@@ -471,22 +781,63 @@
 		
 		/* Urgh. Chip not yet ready to talk to us. */
 		if (time_after(jiffies, timeo)) {
-			spin_unlock_bh(chip->mutex);
+			spin_unlock(chip->mutex);
 			printk(KERN_ERR "waiting for chip to be ready timed out in read\n");
 			return -EIO;
 		}
 
 		/* Latency issues. Drop the lock, wait a while and retry */
-		spin_unlock_bh(chip->mutex);
+		spin_unlock(chip->mutex);
 		cfi_udelay(1);
 		goto retry;
 
+	case FL_ERASING:
+		if (!extp || 
+		    !((extp->FeatureSupport & 2) && (extp->SuspendCmdSupport & 1)))
+			goto sleep; /* We don't support erase suspend */
+		
+		cfi_write (map, CMD(0xb0), adr);
+
+		/* If the flash has finished erasing, then 'erase suspend'
+		 * appears to make some (28F320) flash devices switch to
+		 * 'read' mode.  Make sure that we switch to 'read status'
+		 * mode so we get the right data. --rmk
+		 */
+		cfi_write(map, CMD(0x70), adr);
+		chip->oldstate = FL_ERASING;
+		chip->state = FL_ERASE_SUSPENDING;
+		for (;;) {
+			status = cfi_read(map, adr);
+			if ((status & status_OK) == status_OK)
+				break;
+			
+			if (time_after(jiffies, timeo)) {
+				/* Urgh */
+				cfi_write(map, CMD(0xd0), adr);
+				/* make sure we're in 'read status' mode */
+				cfi_write(map, CMD(0x70), adr);
+				chip->state = FL_ERASING;
+				spin_unlock(chip->mutex);
+				printk(KERN_ERR "Chip not ready after erase "
+				       "suspended: status = 0x%x\n", status);
+				return -EIO;
+			}
+			
+			spin_unlock(chip->mutex);
+			cfi_udelay(1);
+			spin_lock(chip->mutex);
+		}
+		suspended = 1;
+		chip->state = FL_STATUS;
+		break;
+
 	default:
+	sleep:
 		/* Stick ourselves on a wait queue to be woken when
 		   someone changes the status */
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		add_wait_queue(&chip->wq, &wait);
-		spin_unlock_bh(chip->mutex);
+		spin_unlock(chip->mutex);
 		schedule();
 		remove_wait_queue(&chip->wq, &wait);
 		timeo = jiffies + HZ;
@@ -498,9 +849,9 @@
 	cfi_write(map, datum, adr);
 	chip->state = FL_WRITING;
 
-	spin_unlock_bh(chip->mutex);
+	spin_unlock(chip->mutex);
 	cfi_udelay(chip->word_write_time);
-	spin_lock_bh(chip->mutex);
+	spin_lock(chip->mutex);
 
 	timeo = jiffies + (HZ/2);
 	z = 0;
@@ -509,11 +860,11 @@
 			/* Someone's suspended the write. Sleep */
 			set_current_state(TASK_UNINTERRUPTIBLE);
 			add_wait_queue(&chip->wq, &wait);
-			spin_unlock_bh(chip->mutex);
+			spin_unlock(chip->mutex);
 			schedule();
 			remove_wait_queue(&chip->wq, &wait);
 			timeo = jiffies + (HZ / 2); /* FIXME */
-			spin_lock_bh(chip->mutex);
+			spin_lock(chip->mutex);
 			continue;
 		}
 
@@ -525,16 +876,16 @@
 		if (time_after(jiffies, timeo)) {
 			chip->state = FL_STATUS;
 			DISABLE_VPP(map);
-			spin_unlock_bh(chip->mutex);
 			printk(KERN_ERR "waiting for chip to be ready timed out in word write\n");
-			return -EIO;
+			ret = -EIO;
+			goto out;
 		}
 
 		/* Latency issues. Drop the lock, wait a while and retry */
-		spin_unlock_bh(chip->mutex);
+		spin_unlock(chip->mutex);
 		z++;
 		cfi_udelay(1);
-		spin_lock_bh(chip->mutex);
+		spin_lock(chip->mutex);
 	}
 	if (!z) {
 		chip->word_write_time--;
@@ -553,13 +904,27 @@
 		cfi_write(map, CMD(0x50), adr);
 		/* put back into read status register mode */
 		cfi_write(map, CMD(0x70), adr);
-		wake_up(&chip->wq);
-		spin_unlock_bh(chip->mutex);
-		return -EROFS;
+		ret = -EROFS;
+		goto out;
+	}
+ out:
+	if (suspended) {
+		chip->state = chip->oldstate;
+		/* What if one interleaved chip has finished and the 
+		   other hasn't? The old code would leave the finished
+		   one in READY mode. That's bad, and caused -EROFS 
+		   errors to be returned from do_erase_oneblock because
+		   that's the only bit it checked for at the time.
+		   As the state machine appears to explicitly allow 
+		   sending the 0x70 (Read Status) command to an erasing
+		   chip and expecting it to be ignored, that's what we 
+		   do. */
+		cfi_write(map, CMD(0xd0), adr);
+		cfi_write(map, CMD(0x70), adr);		
 	}
 	wake_up(&chip->wq);
-	spin_unlock_bh(chip->mutex);
-	return 0;
+	spin_unlock(chip->mutex);
+	return ret;
 }
 
 
@@ -583,8 +948,8 @@
 		unsigned long bus_ofs = ofs & ~(CFIDEV_BUSWIDTH-1);
 		int gap = ofs - bus_ofs;
 		int i = 0, n = 0;
-		u_char tmp_buf[4];
-		__u32 datum;
+		u_char tmp_buf[8];
+		cfi_word datum;
 
 		while (gap--)
 			tmp_buf[i++] = 0xff;
@@ -597,6 +962,8 @@
 			datum = *(__u16*)tmp_buf;
 		} else if (cfi_buswidth_is_4()) {
 			datum = *(__u32*)tmp_buf;
+		} else if (cfi_buswidth_is_8()) {
+			datum = *(__u64*)tmp_buf;
 		} else {
 			return -EINVAL;  /* should never happen, but be safe */
 		}
@@ -619,7 +986,7 @@
 	}
 	
 	while(len >= CFIDEV_BUSWIDTH) {
-		__u32 datum;
+		cfi_word datum;
 
 		if (cfi_buswidth_is_1()) {
 			datum = *(__u8*)buf;
@@ -627,6 +994,8 @@
 			datum = *(__u16*)buf;
 		} else if (cfi_buswidth_is_4()) {
 			datum = *(__u32*)buf;
+		} else if (cfi_buswidth_is_8()) {
+			datum = *(__u64*)buf;
 		} else {
 			return -EINVAL;
 		}
@@ -651,8 +1020,8 @@
 
 	if (len & (CFIDEV_BUSWIDTH-1)) {
 		int i = 0, n = 0;
-		u_char tmp_buf[4];
-		__u32 datum;
+		u_char tmp_buf[8];
+		cfi_word datum;
 
 		while (len--)
 			tmp_buf[i++] = buf[n++];
@@ -663,6 +1032,8 @@
 			datum = *(__u16*)tmp_buf;
 		} else if (cfi_buswidth_is_4()) {
 			datum = *(__u32*)tmp_buf;
+		} else if (cfi_buswidth_is_8()) {
+			datum = *(__u64*)tmp_buf;
 		} else {
 			return -EINVAL;  /* should never happen, but be safe */
 		}
@@ -683,10 +1054,11 @@
 				  unsigned long adr, const u_char *buf, int len)
 {
 	struct cfi_private *cfi = map->fldrv_priv;
-	__u32 status, status_OK;
+	struct cfi_pri_intelext *extp = cfi->cmdset_priv;
+	cfi_word status, status_OK;
 	unsigned long cmd_adr, timeo;
 	DECLARE_WAITQUEUE(wait, current);
-	int wbufsize, z;
+	int wbufsize, z, suspended=0, ret=0;
 
 	wbufsize = CFIDEV_INTERLEAVE << cfi->cfiq->MaxBufWriteSize;
 	adr += chip->start;
@@ -697,7 +1069,7 @@
 
 	timeo = jiffies + HZ;
  retry:
-	spin_lock_bh(chip->mutex);
+	spin_lock(chip->mutex);
 
 	/* Check that the chip's ready to talk to us.
 	 * Later, we can actually think about interrupting it
@@ -706,8 +1078,6 @@
 	 */
 	switch (chip->state) {
 	case FL_READY:
-		break;
-		
 	case FL_CFI_QUERY:
 	case FL_JEDEC_QUERY:
 		cfi_write(map, CMD(0x70), cmd_adr);
@@ -719,50 +1089,104 @@
 			break;
 		/* Urgh. Chip not yet ready to talk to us. */
 		if (time_after(jiffies, timeo)) {
-			spin_unlock_bh(chip->mutex);
+			spin_unlock(chip->mutex);
 			printk(KERN_ERR "waiting for chip to be ready timed out in buffer write\n");
 			return -EIO;
 		}
 
 		/* Latency issues. Drop the lock, wait a while and retry */
-		spin_unlock_bh(chip->mutex);
+		spin_unlock(chip->mutex);
 		cfi_udelay(1);
 		goto retry;
 
+	case FL_ERASING:
+		if (!extp || 
+		    !((extp->FeatureSupport & 2) && (extp->SuspendCmdSupport & 1)))
+			goto sleep; /* We don't support erase suspend */
+		
+		cfi_write (map, CMD(0xb0), adr);
+
+		/* If the flash has finished erasing, then 'erase suspend'
+		 * appears to make some (28F320) flash devices switch to
+		 * 'read' mode.  Make sure that we switch to 'read status'
+		 * mode so we get the right data. --rmk
+		 */
+		cfi_write(map, CMD(0x70), adr);
+		chip->oldstate = FL_ERASING;
+		chip->state = FL_ERASE_SUSPENDING;
+		for (;;) {
+			status = cfi_read(map, adr);
+			if ((status & status_OK) == status_OK)
+				break;
+			
+			if (time_after(jiffies, timeo)) {
+				/* Urgh */
+				cfi_write(map, CMD(0xd0), adr);
+				/* make sure we're in 'read status' mode */
+				cfi_write(map, CMD(0x70), adr);
+				chip->state = FL_ERASING;
+				spin_unlock(chip->mutex);
+				printk(KERN_ERR "Chip not ready after erase "
+				       "suspended: status = 0x%x\n", status);
+				return -EIO;
+			}
+			
+			spin_unlock(chip->mutex);
+			cfi_udelay(1);
+			spin_lock(chip->mutex);
+		}
+		suspended = 1;
+		chip->state = FL_STATUS;
+		break;
+
 	default:
+	sleep:
 		/* Stick ourselves on a wait queue to be woken when
 		   someone changes the status */
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		add_wait_queue(&chip->wq, &wait);
-		spin_unlock_bh(chip->mutex);
+		spin_unlock(chip->mutex);
 		schedule();
 		remove_wait_queue(&chip->wq, &wait);
 		timeo = jiffies + HZ;
 		goto retry;
 	}
-
+	/* We know we're now in FL_STATUS mode, and 'status' is current */
+	/* §4.8 of the 28FxxxJ3A datasheet says "Any time SR.4 and/or SR.5 is set
+	   [...], the device will not accept any more Write to Buffer commands". 
+	   So we must check here and reset those bits if they're set. Otherwise
+	   we're just pissing in the wind */
+	if (status & CMD(0x30)) {
+		printk(KERN_WARNING "SR.4 or SR.5 bits set in buffer write (status %x). Clearing.\n", status);
+		cfi_write(map, CMD(0x50), cmd_adr);
+		cfi_write(map, CMD(0x70), cmd_adr);
+	}
 	ENABLE_VPP(map);
-	cfi_write(map, CMD(0xe8), cmd_adr);
 	chip->state = FL_WRITING_TO_BUFFER;
 
 	z = 0;
 	for (;;) {
+		cfi_write(map, CMD(0xe8), cmd_adr);
+
 		status = cfi_read(map, cmd_adr);
 		if ((status & status_OK) == status_OK)
 			break;
 
-		spin_unlock_bh(chip->mutex);
+		spin_unlock(chip->mutex);
 		cfi_udelay(1);
-		spin_lock_bh(chip->mutex);
+		spin_lock(chip->mutex);
 
 		if (++z > 20) {
 			/* Argh. Not ready for write to buffer */
 			cfi_write(map, CMD(0x70), cmd_adr);
 			chip->state = FL_STATUS;
 			DISABLE_VPP(map);
-			spin_unlock_bh(chip->mutex);
-			printk(KERN_ERR "Chip not ready for buffer write. Xstatus = %x, status = %x\n", status, cfi_read(map, cmd_adr));
-			return -EIO;
+			printk(KERN_ERR "Chip not ready for buffer write. Xstatus = %llx, status = %llx\n", (__u64)status, (__u64)cfi_read(map, cmd_adr));
+			/* Odd. Clear status bits */
+			cfi_write(map, CMD(0x50), cmd_adr);
+			cfi_write(map, CMD(0x70), cmd_adr);
+			ret = -EIO;
+			goto out;
 		}
 	}
 
@@ -777,18 +1201,21 @@
 			map->write16 (map, *((__u16*)buf)++, adr+z);
 		} else if (cfi_buswidth_is_4()) {
 			map->write32 (map, *((__u32*)buf)++, adr+z);
+		} else if (cfi_buswidth_is_8()) {
+			map->write64 (map, *((__u64*)buf)++, adr+z);
 		} else {
 			DISABLE_VPP(map);
-			return -EINVAL;
+			ret = -EINVAL;
+			goto out;
 		}
 	}
 	/* GO GO GO */
 	cfi_write(map, CMD(0xd0), cmd_adr);
 	chip->state = FL_WRITING;
 
-	spin_unlock_bh(chip->mutex);
+	spin_unlock(chip->mutex);
 	cfi_udelay(chip->buffer_write_time);
-	spin_lock_bh(chip->mutex);
+	spin_lock(chip->mutex);
 
 	timeo = jiffies + (HZ/2);
 	z = 0;
@@ -797,11 +1224,11 @@
 			/* Someone's suspended the write. Sleep */
 			set_current_state(TASK_UNINTERRUPTIBLE);
 			add_wait_queue(&chip->wq, &wait);
-			spin_unlock_bh(chip->mutex);
+			spin_unlock(chip->mutex);
 			schedule();
 			remove_wait_queue(&chip->wq, &wait);
 			timeo = jiffies + (HZ / 2); /* FIXME */
-			spin_lock_bh(chip->mutex);
+			spin_lock(chip->mutex);
 			continue;
 		}
 
@@ -813,16 +1240,16 @@
 		if (time_after(jiffies, timeo)) {
 			chip->state = FL_STATUS;
 			DISABLE_VPP(map);
-			spin_unlock_bh(chip->mutex);
 			printk(KERN_ERR "waiting for chip to be ready timed out in bufwrite\n");
-			return -EIO;
+			ret = -EIO;
+			goto out;
 		}
 		
 		/* Latency issues. Drop the lock, wait a while and retry */
-		spin_unlock_bh(chip->mutex);
+		spin_unlock(chip->mutex);
 		cfi_udelay(1);
 		z++;
-		spin_lock_bh(chip->mutex);
+		spin_lock(chip->mutex);
 	}
 	if (!z) {
 		chip->buffer_write_time--;
@@ -841,13 +1268,27 @@
 		cfi_write(map, CMD(0x50), cmd_adr);
 		/* put back into read status register mode */
 		cfi_write(map, CMD(0x70), adr);
-		wake_up(&chip->wq);
-		spin_unlock_bh(chip->mutex);
-		return -EROFS;
+		ret = -EROFS;
+		goto out;
+	}
+ out:
+	if (suspended) {
+		chip->state = chip->oldstate;
+		/* What if one interleaved chip has finished and the 
+		   other hasn't? The old code would leave the finished
+		   one in READY mode. That's bad, and caused -EROFS 
+		   errors to be returned from do_erase_oneblock because
+		   that's the only bit it checked for at the time.
+		   As the state machine appears to explicitly allow 
+		   sending the 0x70 (Read Status) command to an erasing
+		   chip and expecting it to be ignored, that's what we 
+		   do. */
+		cfi_write(map, CMD(0xd0), adr);
+		cfi_write(map, CMD(0x70), adr);		
 	}
 	wake_up(&chip->wq);
-	spin_unlock_bh(chip->mutex);
-	return 0;
+	spin_unlock(chip->mutex);
+	return ret;
 }
 
 static int cfi_intelext_write_buffers (struct mtd_info *mtd, loff_t to, 
@@ -926,11 +1367,102 @@
 	return 0;
 }
 
+typedef int (*varsize_frob_t)(struct map_info *map, struct flchip *chip,
+			      unsigned long adr, void *thunk);
 
-static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr)
+static int cfi_intelext_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob,
+				     loff_t ofs, size_t len, void *thunk)
 {
+	struct map_info *map = mtd->priv;
 	struct cfi_private *cfi = map->fldrv_priv;
-	__u32 status, status_OK;
+	unsigned long adr;
+	int chipnum, ret = 0;
+	int i, first;
+	struct mtd_erase_region_info *regions = mtd->eraseregions;
+
+	if (ofs > mtd->size)
+		return -EINVAL;
+
+	if ((len + ofs) > mtd->size)
+		return -EINVAL;
+
+	/* Check that both start and end of the requested erase are
+	 * aligned with the erasesize at the appropriate addresses.
+	 */
+
+	i = 0;
+
+	/* Skip all erase regions which are ended before the start of 
+	   the requested erase. Actually, to save on the calculations,
+	   we skip to the first erase region which starts after the
+	   start of the requested erase, and then go back one.
+	*/
+	
+	while (i < mtd->numeraseregions && ofs >= regions[i].offset)
+	       i++;
+	i--;
+
+	/* OK, now i is pointing at the erase region in which this 
+	   erase request starts. Check the start of the requested
+	   erase range is aligned with the erase size which is in
+	   effect here.
+	*/
+
+	if (ofs & (regions[i].erasesize-1))
+		return -EINVAL;
+
+	/* Remember the erase region we start on */
+	first = i;
+
+	/* Next, check that the end of the requested erase is aligned
+	 * with the erase region at that address.
+	 */
+
+	while (i<mtd->numeraseregions && (ofs + len) >= regions[i].offset)
+		i++;
+
+	/* As before, drop back one to point at the region in which
+	   the address actually falls
+	*/
+	i--;
+	
+	if ((ofs + len) & (regions[i].erasesize-1))
+		return -EINVAL;
+
+	chipnum = ofs >> cfi->chipshift;
+	adr = ofs - (chipnum << cfi->chipshift);
+
+	i=first;
+
+	while(len) {
+		ret = (*frob)(map, &cfi->chips[chipnum], adr, thunk);
+		
+		if (ret)
+			return ret;
+
+		adr += regions[i].erasesize;
+		len -= regions[i].erasesize;
+
+		if (adr % (1<< cfi->chipshift) == ((regions[i].offset + (regions[i].erasesize * regions[i].numblocks)) %( 1<< cfi->chipshift)))
+			i++;
+
+		if (adr >> cfi->chipshift) {
+			adr = 0;
+			chipnum++;
+			
+			if (chipnum >= cfi->numchips)
+			break;
+		}
+	}
+
+	return 0;
+}
+
+
+static int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, void *thunk)
+{
+	struct cfi_private *cfi = map->fldrv_priv;
+	cfi_word status, status_OK;
 	unsigned long timeo;
 	int retries = 3;
 	DECLARE_WAITQUEUE(wait, current);
@@ -943,7 +1475,7 @@
 
 	timeo = jiffies + HZ;
 retry:
-	spin_lock_bh(chip->mutex);
+	spin_lock(chip->mutex);
 
 	/* Check that the chip's ready to talk to us. */
 	switch (chip->state) {
@@ -960,13 +1492,13 @@
 		
 		/* Urgh. Chip not yet ready to talk to us. */
 		if (time_after(jiffies, timeo)) {
-			spin_unlock_bh(chip->mutex);
+			spin_unlock(chip->mutex);
 			printk(KERN_ERR "waiting for chip to be ready timed out in erase\n");
 			return -EIO;
 		}
 
 		/* Latency issues. Drop the lock, wait a while and retry */
-		spin_unlock_bh(chip->mutex);
+		spin_unlock(chip->mutex);
 		cfi_udelay(1);
 		goto retry;
 
@@ -975,7 +1507,7 @@
 		   someone changes the status */
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		add_wait_queue(&chip->wq, &wait);
-		spin_unlock_bh(chip->mutex);
+		spin_unlock(chip->mutex);
 		schedule();
 		remove_wait_queue(&chip->wq, &wait);
 		timeo = jiffies + HZ;
@@ -990,10 +1522,12 @@
 	cfi_write(map, CMD(0x20), adr);
 	cfi_write(map, CMD(0xD0), adr);
 	chip->state = FL_ERASING;
-	
-	spin_unlock_bh(chip->mutex);
-	schedule_timeout(HZ);
-	spin_lock_bh(chip->mutex);
+	chip->oldstate = 0;
+
+	spin_unlock(chip->mutex);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout((chip->erase_time*HZ)/(2*1000));
+	spin_lock(chip->mutex);
 
 	/* FIXME. Use a timer to check this, and return immediately. */
 	/* Once the state machine's known to be working I'll do that */
@@ -1004,13 +1538,18 @@
 			/* Someone's suspended the erase. Sleep */
 			set_current_state(TASK_UNINTERRUPTIBLE);
 			add_wait_queue(&chip->wq, &wait);
-			spin_unlock_bh(chip->mutex);
+			spin_unlock(chip->mutex);
 			schedule();
 			remove_wait_queue(&chip->wq, &wait);
-			timeo = jiffies + (HZ*20); /* FIXME */
-			spin_lock_bh(chip->mutex);
+			spin_lock(chip->mutex);
 			continue;
 		}
+		if (chip->oldstate) {
+			/* This erase was suspended and resumed.
+			   Adjust the timeout */
+			timeo = jiffies + (HZ*20); /* FIXME */
+			chip->oldstate = 0;
+		}
 
 		status = cfi_read(map, adr);
 		if ((status & status_OK) == status_OK)
@@ -1020,16 +1559,21 @@
 		if (time_after(jiffies, timeo)) {
 			cfi_write(map, CMD(0x70), adr);
 			chip->state = FL_STATUS;
-			printk(KERN_ERR "waiting for erase to complete timed out. Xstatus = %x, status = %x.\n", status, cfi_read(map, adr));
+			printk(KERN_ERR "waiting for erase at %08lx to complete timed out. Xstatus = %llx, status = %llx.\n",
+			       adr, (__u64)status, (__u64)cfi_read(map, adr));
+			/* Clear status bits */
+			cfi_write(map, CMD(0x50), adr);
+			cfi_write(map, CMD(0x70), adr);
 			DISABLE_VPP(map);
-			spin_unlock_bh(chip->mutex);
+			spin_unlock(chip->mutex);
 			return -EIO;
 		}
 		
 		/* Latency issues. Drop the lock, wait a while and retry */
-		spin_unlock_bh(chip->mutex);
-		cfi_udelay(1);
-		spin_lock_bh(chip->mutex);
+		spin_unlock(chip->mutex);
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+		spin_lock(chip->mutex);
 	}
 	
 	DISABLE_VPP(map);
@@ -1048,124 +1592,52 @@
 			for (i = 1; i<CFIDEV_INTERLEAVE; i++) {
 				      chipstatus |= status >> (cfi->device_type * 8);
 			}
-			printk(KERN_WARNING "Status is not identical for all chips: 0x%x. Merging to give 0x%02x\n", status, chipstatus);
+			printk(KERN_WARNING "Status is not identical for all chips: 0x%llx. Merging to give 0x%02x\n", (__u64)status, chipstatus);
 		}
 		/* Reset the error bits */
 		cfi_write(map, CMD(0x50), adr);
 		cfi_write(map, CMD(0x70), adr);
 		
 		if ((chipstatus & 0x30) == 0x30) {
-			printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%x\n", status);
+			printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%llx\n", (__u64)status);
 			ret = -EIO;
 		} else if (chipstatus & 0x02) {
 			/* Protection bit set */
 			ret = -EROFS;
 		} else if (chipstatus & 0x8) {
 			/* Voltage */
-			printk(KERN_WARNING "Chip reports voltage low on erase: status 0x%x\n", status);
+			printk(KERN_WARNING "Chip reports voltage low on erase: status 0x%llx\n", (__u64)status);
 			ret = -EIO;
 		} else if (chipstatus & 0x20) {
 			if (retries--) {
-				printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x. Retrying...\n", adr, status);
+				printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%llx. Retrying...\n", adr, (__u64)status);
 				timeo = jiffies + HZ;
 				chip->state = FL_STATUS;
-				spin_unlock_bh(chip->mutex);
+				spin_unlock(chip->mutex);
 				goto retry;
 			}
-			printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x\n", adr, status);
+			printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%llx\n", adr, (__u64)status);
 			ret = -EIO;
 		}
 	}
 
 	wake_up(&chip->wq);
-	spin_unlock_bh(chip->mutex);
+	spin_unlock(chip->mutex);
 	return ret;
 }
 
 int cfi_intelext_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
-{	struct map_info *map = mtd->priv;
-	struct cfi_private *cfi = map->fldrv_priv;
-	unsigned long adr, len;
-	int chipnum, ret = 0;
-	int i, first;
-	struct mtd_erase_region_info *regions = mtd->eraseregions;
-
-	if (instr->addr > mtd->size)
-		return -EINVAL;
-
-	if ((instr->len + instr->addr) > mtd->size)
-		return -EINVAL;
-
-	/* Check that both start and end of the requested erase are
-	 * aligned with the erasesize at the appropriate addresses.
-	 */
-
-	i = 0;
-
-	/* Skip all erase regions which are ended before the start of 
-	   the requested erase. Actually, to save on the calculations,
-	   we skip to the first erase region which starts after the
-	   start of the requested erase, and then go back one.
-	*/
-	
-	while (i < mtd->numeraseregions && instr->addr >= regions[i].offset)
-	       i++;
-	i--;
-
-	/* OK, now i is pointing at the erase region in which this 
-	   erase request starts. Check the start of the requested
-	   erase range is aligned with the erase size which is in
-	   effect here.
-	*/
-
-	if (instr->addr & (regions[i].erasesize-1))
-		return -EINVAL;
-
-	/* Remember the erase region we start on */
-	first = i;
-
-	/* Next, check that the end of the requested erase is aligned
-	 * with the erase region at that address.
-	 */
-
-	while (i<mtd->numeraseregions && (instr->addr + instr->len) >= regions[i].offset)
-		i++;
-
-	/* As before, drop back one to point at the region in which
-	   the address actually falls
-	*/
-	i--;
-	
-	if ((instr->addr + instr->len) & (regions[i].erasesize-1))
-		return -EINVAL;
+{
+	unsigned long ofs, len;
+	int ret;
 
-	chipnum = instr->addr >> cfi->chipshift;
-	adr = instr->addr - (chipnum << cfi->chipshift);
+	ofs = instr->addr;
 	len = instr->len;
 
-	i=first;
-
-	while(len) {
-		ret = do_erase_oneblock(map, &cfi->chips[chipnum], adr);
-		
-		if (ret)
-			return ret;
-
-		adr += regions[i].erasesize;
-		len -= regions[i].erasesize;
-
-		if (adr % (1<< cfi->chipshift) == ((regions[i].offset + (regions[i].erasesize * regions[i].numblocks)) %( 1<< cfi->chipshift)))
-			i++;
+	ret = cfi_intelext_varsize_frob(mtd, do_erase_oneblock, ofs, len, 0);
+	if (ret)
+		return ret;
 
-		if (adr >> cfi->chipshift) {
-			adr = 0;
-			chipnum++;
-			
-			if (chipnum >= cfi->numchips)
-			break;
-		}
-	}
-		
 	instr->state = MTD_ERASE_DONE;
 	if (instr->callback)
 		instr->callback(instr);
@@ -1186,7 +1658,7 @@
 		chip = &cfi->chips[i];
 
 	retry:
-		spin_lock_bh(chip->mutex);
+		spin_lock(chip->mutex);
 
 		switch(chip->state) {
 		case FL_READY:
@@ -1200,14 +1672,14 @@
 			 * with the chip now anyway.
 			 */
 		case FL_SYNCING:
-			spin_unlock_bh(chip->mutex);
+			spin_unlock(chip->mutex);
 			break;
 
 		default:
 			/* Not an idle state */
 			add_wait_queue(&chip->wq, &wait);
 			
-			spin_unlock_bh(chip->mutex);
+			spin_unlock(chip->mutex);
 			schedule();
 		        remove_wait_queue(&chip->wq, &wait);
 			
@@ -1220,169 +1692,38 @@
 	for (i--; i >=0; i--) {
 		chip = &cfi->chips[i];
 
-		spin_lock_bh(chip->mutex);
+		spin_lock(chip->mutex);
 		
 		if (chip->state == FL_SYNCING) {
 			chip->state = chip->oldstate;
 			wake_up(&chip->wq);
 		}
-		spin_unlock_bh(chip->mutex);
+		spin_unlock(chip->mutex);
 	}
 }
 
-static inline int do_lock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr)
+#ifdef DEBUG_LOCK_BITS
+static int do_printlockstatus_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, void *thunk)
 {
 	struct cfi_private *cfi = map->fldrv_priv;
-	__u32 status, status_OK;
-	unsigned long timeo = jiffies + HZ;
-	DECLARE_WAITQUEUE(wait, current);
-
-	adr += chip->start;
-
-	/* Let's determine this according to the interleave only once */
-	status_OK = CMD(0x80);
-
-	timeo = jiffies + HZ;
-retry:
-	spin_lock_bh(chip->mutex);
-
-	/* Check that the chip's ready to talk to us. */
-	switch (chip->state) {
-	case FL_CFI_QUERY:
-	case FL_JEDEC_QUERY:
-	case FL_READY:
-		cfi_write(map, CMD(0x70), adr);
-		chip->state = FL_STATUS;
-
-	case FL_STATUS:
-		status = cfi_read(map, adr);
-		if ((status & status_OK) == status_OK) 
-			break;
-		
-		/* Urgh. Chip not yet ready to talk to us. */
-		if (time_after(jiffies, timeo)) {
-			spin_unlock_bh(chip->mutex);
-			printk(KERN_ERR "waiting for chip to be ready timed out in lock\n");
-			return -EIO;
-		}
-
-		/* Latency issues. Drop the lock, wait a while and retry */
-		spin_unlock_bh(chip->mutex);
-		cfi_udelay(1);
-		goto retry;
-
-	default:
-		/* Stick ourselves on a wait queue to be woken when
-		   someone changes the status */
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		add_wait_queue(&chip->wq, &wait);
-		spin_unlock_bh(chip->mutex);
-		schedule();
-		remove_wait_queue(&chip->wq, &wait);
-		timeo = jiffies + HZ;
-		goto retry;
-	}
-
-	ENABLE_VPP(map);
-	cfi_write(map, CMD(0x60), adr);
-	cfi_write(map, CMD(0x01), adr);
-	chip->state = FL_LOCKING;
-	
-	spin_unlock_bh(chip->mutex);
-	schedule_timeout(HZ);
-	spin_lock_bh(chip->mutex);
-
-	/* FIXME. Use a timer to check this, and return immediately. */
-	/* Once the state machine's known to be working I'll do that */
-
-	timeo = jiffies + (HZ*2);
-	for (;;) {
+	int ofs_factor = cfi->interleave * cfi->device_type;
 
-		status = cfi_read(map, adr);
-		if ((status & status_OK) == status_OK)
-			break;
-		
-		/* OK Still waiting */
-		if (time_after(jiffies, timeo)) {
-			cfi_write(map, CMD(0x70), adr);
-			chip->state = FL_STATUS;
-			printk(KERN_ERR "waiting for lock to complete timed out. Xstatus = %x, status = %x.\n", status, cfi_read(map, adr));
-			DISABLE_VPP(map);
-			spin_unlock_bh(chip->mutex);
-			return -EIO;
-		}
-		
-		/* Latency issues. Drop the lock, wait a while and retry */
-		spin_unlock_bh(chip->mutex);
-		cfi_udelay(1);
-		spin_lock_bh(chip->mutex);
-	}
+	cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
+	printk(KERN_DEBUG "block status register for 0x%08lx is %x\n",
+	       adr, cfi_read_query(map, adr+(2*ofs_factor)));
+	cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);
 	
-	/* Done and happy. */
-	chip->state = FL_STATUS;
-	DISABLE_VPP(map);
-	wake_up(&chip->wq);
-	spin_unlock_bh(chip->mutex);
 	return 0;
 }
-static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
-{
-	struct map_info *map = mtd->priv;
-	struct cfi_private *cfi = map->fldrv_priv;
-	unsigned long adr;
-	int chipnum, ret = 0;
-#ifdef DEBUG_LOCK_BITS
-	int ofs_factor = cfi->interleave * cfi->device_type;
 #endif
 
-	if (ofs & (mtd->erasesize - 1))
-		return -EINVAL;
-
-	if (len & (mtd->erasesize -1))
-		return -EINVAL;
-
-	if ((len + ofs) > mtd->size)
-		return -EINVAL;
-
-	chipnum = ofs >> cfi->chipshift;
-	adr = ofs - (chipnum << cfi->chipshift);
-
-	while(len) {
-
-#ifdef DEBUG_LOCK_BITS
-		cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
-		printk("before lock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor)));
-		cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);
-#endif
-
-		ret = do_lock_oneblock(map, &cfi->chips[chipnum], adr);
-
-#ifdef DEBUG_LOCK_BITS
-		cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
-		printk("after lock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor)));
-		cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);
-#endif	
-		
-		if (ret)
-			return ret;
-
-		adr += mtd->erasesize;
-		len -= mtd->erasesize;
+#define DO_XXLOCK_ONEBLOCK_LOCK		((void *) 1)
+#define DO_XXLOCK_ONEBLOCK_UNLOCK	((void *) 2)
 
-		if (adr >> cfi->chipshift) {
-			adr = 0;
-			chipnum++;
-			
-			if (chipnum >= cfi->numchips)
-			break;
-		}
-	}
-	return 0;
-}
-static inline int do_unlock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr)
+static int do_xxlock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, void *thunk)
 {
 	struct cfi_private *cfi = map->fldrv_priv;
-	__u32 status, status_OK;
+	cfi_word status, status_OK;
 	unsigned long timeo = jiffies + HZ;
 	DECLARE_WAITQUEUE(wait, current);
 
@@ -1393,7 +1734,7 @@
 
 	timeo = jiffies + HZ;
 retry:
-	spin_lock_bh(chip->mutex);
+	spin_lock(chip->mutex);
 
 	/* Check that the chip's ready to talk to us. */
 	switch (chip->state) {
@@ -1410,13 +1751,13 @@
 		
 		/* Urgh. Chip not yet ready to talk to us. */
 		if (time_after(jiffies, timeo)) {
-			spin_unlock_bh(chip->mutex);
-			printk(KERN_ERR "waiting for chip to be ready timed out in unlock\n");
+			spin_unlock(chip->mutex);
+			printk(KERN_ERR "%s: waiting for chip to be ready timed out\n", __FUNCTION__);
 			return -EIO;
 		}
 
 		/* Latency issues. Drop the lock, wait a while and retry */
-		spin_unlock_bh(chip->mutex);
+		spin_unlock(chip->mutex);
 		cfi_udelay(1);
 		goto retry;
 
@@ -1425,7 +1766,7 @@
 		   someone changes the status */
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		add_wait_queue(&chip->wq, &wait);
-		spin_unlock_bh(chip->mutex);
+		spin_unlock(chip->mutex);
 		schedule();
 		remove_wait_queue(&chip->wq, &wait);
 		timeo = jiffies + HZ;
@@ -1434,17 +1775,24 @@
 
 	ENABLE_VPP(map);
 	cfi_write(map, CMD(0x60), adr);
-	cfi_write(map, CMD(0xD0), adr);
-	chip->state = FL_UNLOCKING;
-	
-	spin_unlock_bh(chip->mutex);
+
+	if (thunk == DO_XXLOCK_ONEBLOCK_LOCK) {
+		cfi_write(map, CMD(0x01), adr);
+		chip->state = FL_LOCKING;
+	} else if (thunk == DO_XXLOCK_ONEBLOCK_UNLOCK) {
+		cfi_write(map, CMD(0xD0), adr);
+		chip->state = FL_UNLOCKING;
+	} else
+		BUG();
+
+	spin_unlock(chip->mutex);
 	schedule_timeout(HZ);
-	spin_lock_bh(chip->mutex);
+	spin_lock(chip->mutex);
 
 	/* FIXME. Use a timer to check this, and return immediately. */
 	/* Once the state machine's known to be working I'll do that */
 
-	timeo = jiffies + (HZ*2);
+	timeo = jiffies + (HZ*20);
 	for (;;) {
 
 		status = cfi_read(map, adr);
@@ -1455,59 +1803,68 @@
 		if (time_after(jiffies, timeo)) {
 			cfi_write(map, CMD(0x70), adr);
 			chip->state = FL_STATUS;
-			printk(KERN_ERR "waiting for unlock to complete timed out. Xstatus = %x, status = %x.\n", status, cfi_read(map, adr));
+			printk(KERN_ERR "waiting for unlock to complete timed out. Xstatus = %llx, status = %llx.\n", (__u64)status, (__u64)cfi_read(map, adr));
 			DISABLE_VPP(map);
-			spin_unlock_bh(chip->mutex);
+			spin_unlock(chip->mutex);
 			return -EIO;
 		}
 		
-		/* Latency issues. Drop the unlock, wait a while and retry */
-		spin_unlock_bh(chip->mutex);
+		/* Latency issues. Drop the lock, wait a while and retry */
+		spin_unlock(chip->mutex);
 		cfi_udelay(1);
-		spin_lock_bh(chip->mutex);
+		spin_lock(chip->mutex);
 	}
 	
 	/* Done and happy. */
 	chip->state = FL_STATUS;
 	DISABLE_VPP(map);
 	wake_up(&chip->wq);
-	spin_unlock_bh(chip->mutex);
+	spin_unlock(chip->mutex);
 	return 0;
 }
-static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
+
+static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
 {
-	struct map_info *map = mtd->priv;
-	struct cfi_private *cfi = map->fldrv_priv;
-	unsigned long adr;
-	int chipnum, ret = 0;
+	int ret;
+
 #ifdef DEBUG_LOCK_BITS
-	int ofs_factor = cfi->interleave * cfi->device_type;
+	printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n",
+	       __FUNCTION__, ofs, len);
+	cfi_intelext_varsize_frob(mtd, do_printlockstatus_oneblock,
+				  ofs, len, 0);
 #endif
 
-	chipnum = ofs >> cfi->chipshift;
-	adr = ofs - (chipnum << cfi->chipshift);
-
+	ret = cfi_intelext_varsize_frob(mtd, do_xxlock_oneblock, 
+					ofs, len, DO_XXLOCK_ONEBLOCK_LOCK);
+	
 #ifdef DEBUG_LOCK_BITS
-	{
-		unsigned long temp_adr = adr;
-		unsigned long temp_len = len;
-                 
-		cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
-                while (temp_len) {
-			printk("before unlock %x: block status register is %x\n",temp_adr,cfi_read_query(map, temp_adr+(2*ofs_factor)));
-			temp_adr += mtd->erasesize;
-			temp_len -= mtd->erasesize;
-		}
-		cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);
-	}
+	printk(KERN_DEBUG __FUNCTION__
+	       "%s: lock status after, ret=%d\n", __FUNCTION__, ret);
+	cfi_intelext_varsize_frob(mtd, do_printlockstatus_oneblock,
+				  ofs, len, 0);
 #endif
 
-	ret = do_unlock_oneblock(map, &cfi->chips[chipnum], adr);
+	return ret;
+}
+
+static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+	int ret;
 
 #ifdef DEBUG_LOCK_BITS
-	cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
-	printk("after unlock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor)));
-	cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);
+	printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n",
+	       __FUNCTION__, ofs, len);
+	cfi_intelext_varsize_frob(mtd, do_printlockstatus_oneblock,
+				  ofs, len, 0);
+#endif
+
+	ret = cfi_intelext_varsize_frob(mtd, do_xxlock_oneblock,
+					ofs, len, DO_XXLOCK_ONEBLOCK_UNLOCK);
+	
+#ifdef DEBUG_LOCK_BITS
+	printk(KERN_DEBUG "%s: lock status after, ret=%d\n", __FUNCTION__, ret);
+	cfi_intelext_varsize_frob(mtd, do_printlockstatus_oneblock, 
+				  ofs, len, 0);
 #endif
 	
 	return ret;
@@ -1524,7 +1881,7 @@
 	for (i=0; !ret && i<cfi->numchips; i++) {
 		chip = &cfi->chips[i];
 
-		spin_lock_bh(chip->mutex);
+		spin_lock(chip->mutex);
 
 		switch(chip->state) {
 		case FL_READY:
@@ -1544,7 +1901,7 @@
 			ret = -EAGAIN;
 			break;
 		}
-		spin_unlock_bh(chip->mutex);
+		spin_unlock(chip->mutex);
 	}
 
 	/* Unlock the chips again */
@@ -1553,7 +1910,7 @@
 		for (i--; i >=0; i--) {
 			chip = &cfi->chips[i];
 			
-			spin_lock_bh(chip->mutex);
+			spin_lock(chip->mutex);
 			
 			if (chip->state == FL_PM_SUSPENDED) {
 				/* No need to force it into a known state here,
@@ -1562,7 +1919,7 @@
 				chip->state = chip->oldstate;
 				wake_up(&chip->wq);
 			}
-			spin_unlock_bh(chip->mutex);
+			spin_unlock(chip->mutex);
 		}
 	} 
 	
@@ -1580,7 +1937,7 @@
 	
 		chip = &cfi->chips[i];
 
-		spin_lock_bh(chip->mutex);
+		spin_lock(chip->mutex);
 		
 		/* Go to known state. Chip may have been power cycled */
 		if (chip->state == FL_PM_SUSPENDED) {
@@ -1589,7 +1946,7 @@
 			wake_up(&chip->wq);
 		}
 
-		spin_unlock_bh(chip->mutex);
+		spin_unlock(chip->mutex);
 	}
 }
 
@@ -1598,7 +1955,9 @@
 	struct map_info *map = mtd->priv;
 	struct cfi_private *cfi = map->fldrv_priv;
 	kfree(cfi->cmdset_priv);
+	kfree(cfi->cfiq);
 	kfree(cfi);
+	kfree(mtd->eraseregions);
 }
 
 static char im_name_1[]="cfi_cmdset_0001";
diff -urN linux-2.4.21-pre3/drivers/mtd/chips/cfi_cmdset_0002.c linux-2.4.21-pre4/drivers/mtd/chips/cfi_cmdset_0002.c
--- linux-2.4.21-pre3/drivers/mtd/chips/cfi_cmdset_0002.c	Thu Oct 25 00:07:09 2001
+++ linux-2.4.21-pre4/drivers/mtd/chips/cfi_cmdset_0002.c	Tue Jan 28 19:44:30 2003
@@ -8,7 +8,7 @@
  *
  * This code is GPL
  *
- * $Id: cfi_cmdset_0002.c,v 1.52 2001/10/24 09:37:30 dwmw2 Exp $
+ * $Id: cfi_cmdset_0002.c,v 1.62 2003/01/24 23:30:13 dwmw2 Exp $
  *
  */
 
@@ -30,11 +30,13 @@
 
 static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
 static int cfi_amdstd_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
+static int cfi_amdstd_erase_chip(struct mtd_info *, struct erase_info *);
 static int cfi_amdstd_erase_onesize(struct mtd_info *, struct erase_info *);
 static int cfi_amdstd_erase_varsize(struct mtd_info *, struct erase_info *);
 static void cfi_amdstd_sync (struct mtd_info *);
 static int cfi_amdstd_suspend (struct mtd_info *);
 static void cfi_amdstd_resume (struct mtd_info *);
+static int cfi_amdstd_secsi_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
 
 static void cfi_amdstd_destroy(struct mtd_info *);
 
@@ -58,7 +60,7 @@
 	__u8 major, minor;
 	__u32 base = cfi->chips[0].start;
 
-	if (cfi->cfi_mode==1){
+	if (cfi->cfi_mode==CFI_MODE_CFI){
 		__u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR;
 
 		cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
@@ -74,7 +76,7 @@
 		cfi_send_gen_cmd(0x55, 0x2aa, base, map, cfi, cfi->device_type, NULL);
 		cfi_send_gen_cmd(0x90, 0x555, base, map, cfi, cfi->device_type, NULL);
 		cfi->mfr = cfi_read_query(map, base);
-		cfi->id = cfi_read_query(map, base + ofs_factor);
+		cfi->id = cfi_read_query(map, base + ofs_factor);    
 
 		/* Wheee. Bring me the head of someone at AMD. */
 #ifdef AMD_BOOTLOC_BUG
@@ -135,7 +137,6 @@
 	}		
 	
 	map->fldrv = &cfi_amdstd_chipdrv;
-	MOD_INC_USE_COUNT;
 
 	cfi_send_gen_cmd(0xf0, 0x55, base, map, cfi, cfi->device_type, NULL);
 	return cfi_amdstd_setup(map);
@@ -148,12 +149,12 @@
 	unsigned long devsize = (1<<cfi->cfiq->DevSize) * cfi->interleave;
 
 	mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
-	printk(KERN_NOTICE "number of %s chips: %d\n", (cfi->cfi_mode)?"CFI":"JEDEC",cfi->numchips);
+	printk(KERN_NOTICE "number of %s chips: %d\n", 
+		(cfi->cfi_mode == CFI_MODE_CFI)?"CFI":"JEDEC",cfi->numchips);
 
 	if (!mtd) {
 	  printk(KERN_WARNING "Failed to allocate memory for MTD device\n");
-	  kfree(cfi->cmdset_priv);
-	  return NULL;
+	  goto setup_err;
 	}
 
 	memset(mtd, 0, sizeof(*mtd));
@@ -173,8 +174,7 @@
 		mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) * mtd->numeraseregions, GFP_KERNEL);
 		if (!mtd->eraseregions) { 
 			printk(KERN_WARNING "Failed to allocate memory for MTD erase region info\n");
-			kfree(cfi->cmdset_priv);
-			return NULL;
+			goto setup_err;
 		}
 			
 		for (i=0; i<cfi->cfiq->NumEraseRegions; i++) {
@@ -195,9 +195,7 @@
 		if (offset != devsize) {
 			/* Argh */
 			printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize);
-			kfree(mtd->eraseregions);
-			kfree(cfi->cmdset_priv);
-			return NULL;
+			goto setup_err;
 		}
 #if 0
 		// debug
@@ -220,6 +218,9 @@
 			mtd->erase = cfi_amdstd_erase_varsize;
 		else
 #endif
+		if (((cfi->cfiq->EraseRegionInfo[0] & 0xffff) + 1) == 1)
+			mtd->erase = cfi_amdstd_erase_chip;
+		else
 			mtd->erase = cfi_amdstd_erase_onesize;
 		mtd->read = cfi_amdstd_read;
 		mtd->write = cfi_amdstd_write;
@@ -227,11 +228,38 @@
 
 	default:
 	        printk(KERN_WARNING "Unsupported buswidth\n");
-		kfree(mtd);
-		kfree(cfi->cmdset_priv);
-		return NULL;
+		goto setup_err;
 		break;
 	}
+	if (cfi->fast_prog) {
+		/* In cfi_amdstd_write() we frob the protection stuff
+		   without paying any attention to the state machine.
+		   This upsets in-progress erases. So we turn this flag
+		   off for now till the code gets fixed. */
+		printk(KERN_NOTICE "cfi_cmdset_0002: Disabling fast programming due to code brokenness.\n");
+		cfi->fast_prog = 0;
+	}
+
+
+        /* does this chip have a secsi area? */
+	if(cfi->mfr==1){
+		
+		switch(cfi->id){
+		case 0x50:
+		case 0x53:
+		case 0x55:
+		case 0x56:
+		case 0x5C:
+		case 0x5F:
+			/* Yes */
+			mtd->read_user_prot_reg = cfi_amdstd_secsi_read;
+			mtd->read_fact_prot_reg = cfi_amdstd_secsi_read;
+		default:		       
+			;
+		}
+	}
+	
+		
 	mtd->sync = cfi_amdstd_sync;
 	mtd->suspend = cfi_amdstd_suspend;
 	mtd->resume = cfi_amdstd_resume;
@@ -240,6 +268,16 @@
 	mtd->name = map->name;
 	MOD_INC_USE_COUNT;
 	return mtd;
+
+ setup_err:
+	if(mtd) {
+		if(mtd->eraseregions)
+			kfree(mtd->eraseregions);
+		kfree(mtd);
+	}
+	kfree(cfi->cmdset_priv);
+	kfree(cfi->cfiq);
+	return NULL;
 }
 
 static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
@@ -323,11 +361,104 @@
 	return ret;
 }
 
+static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	unsigned long timeo = jiffies + HZ;
+	struct cfi_private *cfi = map->fldrv_priv;
+
+ retry:
+	cfi_spin_lock(chip->mutex);
+
+	if (chip->state != FL_READY){
+#if 0
+	        printk(KERN_DEBUG "Waiting for chip to read, status = %d\n", chip->state);
+#endif
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		add_wait_queue(&chip->wq, &wait);
+                
+		cfi_spin_unlock(chip->mutex);
+
+		schedule();
+		remove_wait_queue(&chip->wq, &wait);
+#if 0
+		if(signal_pending(current))
+			return -EINTR;
+#endif
+		timeo = jiffies + HZ;
+
+		goto retry;
+	}	
+
+	adr += chip->start;
+
+	chip->state = FL_READY;
+	
+	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
+	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
+	cfi_send_gen_cmd(0x88, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
+	
+	map->copy_from(map, buf, adr, len);
+
+	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
+	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
+	cfi_send_gen_cmd(0x90, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
+	cfi_send_gen_cmd(0x00, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
+	
+	wake_up(&chip->wq);
+	cfi_spin_unlock(chip->mutex);
+
+	return 0;
+}
+
+static int cfi_amdstd_secsi_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	unsigned long ofs;
+	int chipnum;
+	int ret = 0;
+
+
+	/* ofs: offset within the first chip that the first read should start */
+
+	/* 8 secsi bytes per chip */
+	chipnum=from>>3;
+	ofs=from & 7;
+
+
+	*retlen = 0;
+
+	while (len) {
+		unsigned long thislen;
+
+		if (chipnum >= cfi->numchips)
+			break;
+
+		if ((len + ofs -1) >> 3)
+			thislen = (1<<3) - ofs;
+		else
+			thislen = len;
+
+		ret = do_read_secsi_onechip(map, &cfi->chips[chipnum], ofs, thislen, buf);
+		if (ret)
+			break;
+
+		*retlen += thislen;
+		len -= thislen;
+		buf += thislen;
+
+		ofs = 0;
+		chipnum++;
+	}
+	return ret;
+}
+
 static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, __u32 datum, int fast)
 {
 	unsigned long timeo = jiffies + HZ;
-	unsigned int Last[4];
-	unsigned long Count = 0;
+	unsigned int oldstatus, status;
+	unsigned int dq6, dq5;	
 	struct cfi_private *cfi = map->fldrv_priv;
 	DECLARE_WAITQUEUE(wait, current);
 	int ret = 0;
@@ -335,7 +466,7 @@
  retry:
 	cfi_spin_lock(chip->mutex);
 
-	if (chip->state != FL_READY){
+	if (chip->state != FL_READY) {
 #if 0
 	        printk(KERN_DEBUG "Waiting for chip to write, status = %d\n", chip->state);
 #endif
@@ -375,33 +506,63 @@
 	cfi_udelay(chip->word_write_time);
 	cfi_spin_lock(chip->mutex);
 
-	Last[0] = cfi_read(map, adr);
-	//	printk("Last[0] is %x\n", Last[0]);
-	Last[1] = cfi_read(map, adr);
-	//	printk("Last[1] is %x\n", Last[1]);
-	Last[2] = cfi_read(map, adr);
-	//	printk("Last[2] is %x\n", Last[2]);
-
-	for (Count = 3; Last[(Count - 1) % 4] != Last[(Count - 2) % 4] && Count < 10000; Count++){
-		cfi_spin_unlock(chip->mutex);
-		cfi_udelay(10);
-		cfi_spin_lock(chip->mutex);
+	/* Polling toggle bits instead of reading back many times
+	   This ensures that write operation is really completed,
+	   or tells us why it failed. */        
+	dq6 = CMD(1<<6);
+	dq5 = CMD(1<<5);
+	timeo = jiffies + (HZ/1000); /* setting timeout to 1ms for now */
 		
-	        Last[Count % 4] = cfi_read(map, adr);
-		//		printk("Last[%d%%4] is %x\n", Count, Last[Count%4]);
+	oldstatus = cfi_read(map, adr);
+	status = cfi_read(map, adr);
+
+	while( (status & dq6) != (oldstatus & dq6) && 
+	       (status & dq5) != dq5 &&
+	       !time_after(jiffies, timeo) ) {
+
+		if (need_resched()) {
+			cfi_spin_unlock(chip->mutex);
+			yield();
+			cfi_spin_lock(chip->mutex);
+		} else 
+			udelay(1);
+
+		oldstatus = cfi_read( map, adr );
+		status = cfi_read( map, adr );
 	}
 	
-	if (Last[(Count - 1) % 4] != datum){
-		printk(KERN_WARNING "Last[%ld] is %x, datum is %x\n",(Count - 1) % 4,Last[(Count - 1) % 4],datum);
-	        cfi_send_gen_cmd(0xF0, 0, chip->start, map, cfi, cfi->device_type, NULL);
-		DISABLE_VPP(map);
-		ret = -EIO;
-	}       
+	if( (status & dq6) != (oldstatus & dq6) ) {
+		/* The erasing didn't stop?? */
+		if( (status & dq5) == dq5 ) {
+			/* When DQ5 raises, we must check once again
+			   if DQ6 is toggling.  If not, the erase has been
+			   completed OK.  If not, reset chip. */
+			oldstatus = cfi_read(map, adr);
+			status = cfi_read(map, adr);
+		    
+			if ( (oldstatus & 0x00FF) == (status & 0x00FF) ) {
+				printk(KERN_WARNING "Warning: DQ5 raised while program operation was in progress, however operation completed OK\n" );
+			} else { 
+				/* DQ5 is active so we can do a reset and stop the erase */
+				cfi_write(map, CMD(0xF0), chip->start);
+				printk(KERN_WARNING "Internal flash device timeout occurred or write operation was performed while flash was programming.\n" );
+			}
+		} else {
+			printk(KERN_WARNING "Waiting for write to complete timed out in do_write_oneword.");        
+			
+			chip->state = FL_READY;
+			wake_up(&chip->wq);
+			cfi_spin_unlock(chip->mutex);
+			DISABLE_VPP(map);
+			ret = -EIO;
+		}
+	}
+
 	DISABLE_VPP(map);
 	chip->state = FL_READY;
 	wake_up(&chip->wq);
 	cfi_spin_unlock(chip->mutex);
-	
+
 	return ret;
 }
 
@@ -458,10 +619,12 @@
 		}
 	}
 	
-	/* Go into unlock bypass mode */
-	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);
-	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);
-	cfi_send_gen_cmd(0x20, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);
+	if (cfi->fast_prog) {
+		/* Go into unlock bypass mode */
+		cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);
+		cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);
+		cfi_send_gen_cmd(0x20, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);
+	}
 
 	/* We are now aligned, write as much as possible */
 	while(len >= CFIDEV_BUSWIDTH) {
@@ -519,6 +682,7 @@
 		cfi_send_gen_cmd(0x00, 0, chipstart, map, cfi, cfi->device_type, NULL);
 	}
 
+	/* Write the trailing bytes if any */
 	if (len & (CFIDEV_BUSWIDTH-1)) {
 		int i = 0, n = 0;
 		u_char tmp_buf[4];
@@ -547,12 +711,139 @@
 	return 0;
 }
 
+static inline int do_erase_chip(struct map_info *map, struct flchip *chip)
+{
+	unsigned int oldstatus, status;
+	unsigned int dq6, dq5;
+	unsigned long timeo = jiffies + HZ;
+	unsigned int adr;
+	struct cfi_private *cfi = map->fldrv_priv;
+	DECLARE_WAITQUEUE(wait, current);
+
+ retry:
+	cfi_spin_lock(chip->mutex);
+
+	if (chip->state != FL_READY){
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		add_wait_queue(&chip->wq, &wait);
+                
+		cfi_spin_unlock(chip->mutex);
+
+		schedule();
+		remove_wait_queue(&chip->wq, &wait);
+#if 0
+		if(signal_pending(current))
+			return -EINTR;
+#endif
+		timeo = jiffies + HZ;
+
+		goto retry;
+	}	
+
+	chip->state = FL_ERASING;
+	
+	/* Handle devices with one erase region, that only implement
+	 * the chip erase command.
+	 */
+	ENABLE_VPP(map);
+	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
+	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
+	cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
+	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
+	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
+	cfi_send_gen_cmd(0x10, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
+	timeo = jiffies + (HZ*20);
+	adr = cfi->addr_unlock1;
+
+	/* Wait for the end of programing/erasure by using the toggle method.
+	 * As long as there is a programming procedure going on, bit 6 of the last
+	 * written byte is toggling it's state with each consectuve read.
+	 * The toggling stops as soon as the procedure is completed.
+	 *
+	 * If the process has gone on for too long on the chip bit 5 gets.
+	 * After bit5 is set you can kill the operation by sending a reset
+	 * command to the chip.
+	 */
+	dq6 = CMD(1<<6);
+	dq5 = CMD(1<<5);
+
+	oldstatus = cfi_read(map, adr);
+	status = cfi_read(map, adr);
+	while( ((status & dq6) != (oldstatus & dq6)) && 
+		((status & dq5) != dq5) &&
+		!time_after(jiffies, timeo)) {
+		int wait_reps;
+
+		/* an initial short sleep */
+		cfi_spin_unlock(chip->mutex);
+		schedule_timeout(HZ/100);
+		cfi_spin_lock(chip->mutex);
+		
+		if (chip->state != FL_ERASING) {
+			/* Someone's suspended the erase. Sleep */
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			add_wait_queue(&chip->wq, &wait);
+			
+			cfi_spin_unlock(chip->mutex);
+			printk("erase suspended. Sleeping\n");
+			
+			schedule();
+			remove_wait_queue(&chip->wq, &wait);
+#if 0			
+			if (signal_pending(current))
+				return -EINTR;
+#endif			
+			timeo = jiffies + (HZ*2); /* FIXME */
+			cfi_spin_lock(chip->mutex);
+			continue;
+		}
+
+		/* Busy wait for 1/10 of a milisecond */
+		for(wait_reps = 0;
+		    	(wait_reps < 100) &&
+			((status & dq6) != (oldstatus & dq6)) && 
+			((status & dq5) != dq5);
+			wait_reps++) {
+			
+			/* Latency issues. Drop the lock, wait a while and retry */
+			cfi_spin_unlock(chip->mutex);
+			
+			cfi_udelay(1);
+		
+			cfi_spin_lock(chip->mutex);
+			oldstatus = cfi_read(map, adr);
+			status = cfi_read(map, adr);
+		}
+		oldstatus = cfi_read(map, adr);
+		status = cfi_read(map, adr);
+	}
+	if ((status & dq6) != (oldstatus & dq6)) {
+		/* The erasing didn't stop?? */
+		if ((status & dq5) == dq5) {
+			/* dq5 is active so we can do a reset and stop the erase */
+			cfi_write(map, CMD(0xF0), chip->start);
+		}
+		chip->state = FL_READY;
+		wake_up(&chip->wq);
+		cfi_spin_unlock(chip->mutex);
+		printk("waiting for erase to complete timed out.");
+		DISABLE_VPP(map);
+		return -EIO;
+	}
+	DISABLE_VPP(map);
+	chip->state = FL_READY;
+	wake_up(&chip->wq);
+	cfi_spin_unlock(chip->mutex);
+
+	return 0;
+}
+
 static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr)
 {
-	unsigned int status;
+	unsigned int oldstatus, status;
+	unsigned int dq6, dq5;
 	unsigned long timeo = jiffies + HZ;
 	struct cfi_private *cfi = map->fldrv_priv;
-	unsigned int rdy_mask;
 	DECLARE_WAITQUEUE(wait, current);
 
  retry:
@@ -588,18 +879,30 @@
 	
 	timeo = jiffies + (HZ*20);
 
-	cfi_spin_unlock(chip->mutex);
-	schedule_timeout(HZ);
-	cfi_spin_lock(chip->mutex);
-	
-	rdy_mask = CMD(0x80);
-
-	/* FIXME. Use a timer to check this, and return immediately. */
-	/* Once the state machine's known to be working I'll do that */
+	/* Wait for the end of programing/erasure by using the toggle method.
+	 * As long as there is a programming procedure going on, bit 6 of the last
+	 * written byte is toggling it's state with each consectuve read.
+	 * The toggling stops as soon as the procedure is completed.
+	 *
+	 * If the process has gone on for too long on the chip bit 5 gets.
+	 * After bit5 is set you can kill the operation by sending a reset
+	 * command to the chip.
+	 */
+	dq6 = CMD(1<<6);
+	dq5 = CMD(1<<5);
 
-	while ( ( (status = cfi_read(map,adr)) & rdy_mask ) != rdy_mask ) {
-		static int z=0;
+	oldstatus = cfi_read(map, adr);
+	status = cfi_read(map, adr);
+	while( ((status & dq6) != (oldstatus & dq6)) && 
+		((status & dq5) != dq5) &&
+		!time_after(jiffies, timeo)) {
+		int wait_reps;
 
+		/* an initial short sleep */
+		cfi_spin_unlock(chip->mutex);
+		schedule_timeout(HZ/100);
+		cfi_spin_lock(chip->mutex);
+		
 		if (chip->state != FL_ERASING) {
 			/* Someone's suspended the erase. Sleep */
 			set_current_state(TASK_UNINTERRUPTIBLE);
@@ -619,29 +922,58 @@
 			continue;
 		}
 
-		/* OK Still waiting */
-		if (time_after(jiffies, timeo)) {
-			chip->state = FL_READY;
+		/* Busy wait for 1/10 of a milisecond */
+		for(wait_reps = 0;
+		    	(wait_reps < 100) &&
+			((status & dq6) != (oldstatus & dq6)) && 
+			((status & dq5) != dq5);
+			wait_reps++) {
+			
+			/* Latency issues. Drop the lock, wait a while and retry */
 			cfi_spin_unlock(chip->mutex);
-			printk(KERN_WARNING "waiting for erase to complete timed out.");
-			DISABLE_VPP(map);
-			return -EIO;
-		}
+			
+			cfi_udelay(1);
 		
-		/* Latency issues. Drop the lock, wait a while and retry */
+			cfi_spin_lock(chip->mutex);
+			oldstatus = cfi_read(map, adr);
+			status = cfi_read(map, adr);
+		}
+		oldstatus = cfi_read(map, adr);
+		status = cfi_read(map, adr);
+	}
+	if( (status & dq6) != (oldstatus & dq6) ) 
+	{                                       
+		/* The erasing didn't stop?? */
+		if( ( status & dq5 ) == dq5 ) 
+		{   			
+			/* When DQ5 raises, we must check once again if DQ6 is toggling.
+               If not, the erase has been completed OK.  If not, reset chip. */
+		    oldstatus   = cfi_read( map, adr );
+		    status      = cfi_read( map, adr );
+		    
+		    if( ( oldstatus & 0x00FF ) == ( status & 0x00FF ) )
+		    {
+                printk( "Warning: DQ5 raised while erase operation was in progress, but erase completed OK\n" ); 		    
+		    } 			
+			else
+            {
+			    /* DQ5 is active so we can do a reset and stop the erase */
+				cfi_write(map, CMD(0xF0), chip->start);
+                printk( KERN_WARNING "Internal flash device timeout occured or write operation was performed while flash was erasing\n" );
+			}
+		}
+        else
+        {
+		    printk( "Waiting for erase to complete timed out in do_erase_oneblock.");        
+		    
+		chip->state = FL_READY;
+		wake_up(&chip->wq);
 		cfi_spin_unlock(chip->mutex);
-
-		z++;
-		if ( 0 && !(z % 100 )) 
-			printk(KERN_WARNING "chip not ready yet after erase. looping\n");
-
-		cfi_udelay(1);
-		
-		cfi_spin_lock(chip->mutex);
-		continue;
+		DISABLE_VPP(map);
+		return -EIO;
 	}
-	
-	/* Done and happy. */
+	}
+
 	DISABLE_VPP(map);
 	chip->state = FL_READY;
 	wake_up(&chip->wq);
@@ -786,6 +1118,29 @@
 	return 0;
 }
 
+static int cfi_amdstd_erase_chip(struct mtd_info *mtd, struct erase_info *instr)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	int ret = 0;
+
+	if (instr->addr != 0)
+		return -EINVAL;
+
+	if (instr->len != mtd->size)
+		return -EINVAL;
+
+	ret = do_erase_chip(map, &cfi->chips[0]);
+	if (ret)
+		return ret;
+
+	instr->state = MTD_ERASE_DONE;
+	if (instr->callback)
+		instr->callback(instr);
+	
+	return 0;
+}
+
 static void cfi_amdstd_sync (struct mtd_info *mtd)
 {
 	struct map_info *map = mtd->priv;
@@ -853,7 +1208,6 @@
 	int i;
 	struct flchip *chip;
 	int ret = 0;
-//printk("suspend\n");
 
 	for (i=0; !ret && i<cfi->numchips; i++) {
 		chip = &cfi->chips[i];
@@ -906,7 +1260,6 @@
 	struct cfi_private *cfi = map->fldrv_priv;
 	int i;
 	struct flchip *chip;
-//printk("resume\n");
 
 	for (i=0; i<cfi->numchips; i++) {
 	
@@ -931,7 +1284,9 @@
 	struct map_info *map = mtd->priv;
 	struct cfi_private *cfi = map->fldrv_priv;
 	kfree(cfi->cmdset_priv);
+	kfree(cfi->cfiq);
 	kfree(cfi);
+	kfree(mtd->eraseregions);
 }
 
 static char im_name[]="cfi_cmdset_0002";
@@ -953,3 +1308,4 @@
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Crossnet Co. <info@crossnet.co.jp> et al.");
 MODULE_DESCRIPTION("MTD chip driver for AMD/Fujitsu flash chips");
+
diff -urN linux-2.4.21-pre3/drivers/mtd/chips/cfi_cmdset_0020.c linux-2.4.21-pre4/drivers/mtd/chips/cfi_cmdset_0020.c
--- linux-2.4.21-pre3/drivers/mtd/chips/cfi_cmdset_0020.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/drivers/mtd/chips/cfi_cmdset_0020.c	Tue Jan 28 19:44:30 2003
@@ -0,0 +1,1451 @@
+/*
+ * Common Flash Interface support:
+ *   ST Advanced Architecture Command Set (ID 0x0020)
+ *
+ * (C) 2000 Red Hat. GPL'd
+ *
+ * 
+ * 10/10/2000	Nicolas Pitre <nico@cam.org>
+ * 	- completely revamped method functions so they are aware and
+ * 	  independent of the flash geometry (buswidth, interleave, etc.)
+ * 	- scalability vs code size is completely set at compile-time
+ * 	  (see include/linux/mtd/cfi.h for selection)
+ *	- optimized write buffer method
+ * 06/21/2002	Joern Engel <joern@wh.fh-wedel.de> and others
+ *	- modified Intel Command Set 0x0001 to support ST Advanced Architecture
+ *	  (command set 0x0020)
+ *	- added a writev function
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <asm/io.h>
+#include <asm/byteorder.h>
+
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/cfi.h>
+#include <linux/mtd/compatmac.h>
+
+
+static int cfi_staa_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *);
+static int cfi_staa_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
+static int cfi_staa_writev(struct mtd_info *mtd, const struct iovec *vecs,
+		unsigned long count, loff_t to, size_t *retlen);
+static int cfi_staa_erase_varsize(struct mtd_info *, struct erase_info *);
+static void cfi_staa_sync (struct mtd_info *);
+static int cfi_staa_lock(struct mtd_info *mtd, loff_t ofs, size_t len);
+static int cfi_staa_unlock(struct mtd_info *mtd, loff_t ofs, size_t len);
+static int cfi_staa_suspend (struct mtd_info *);
+static void cfi_staa_resume (struct mtd_info *);
+
+static void cfi_staa_destroy(struct mtd_info *);
+
+struct mtd_info *cfi_cmdset_0020(struct map_info *, int);
+
+static struct mtd_info *cfi_staa_setup (struct map_info *);
+
+static struct mtd_chip_driver cfi_staa_chipdrv = {
+	probe: NULL, /* Not usable directly */
+	destroy: cfi_staa_destroy,
+	name: "cfi_cmdset_0020",
+	module: THIS_MODULE
+};
+
+/* #define DEBUG_LOCK_BITS */
+//#define DEBUG_CFI_FEATURES
+
+#ifdef DEBUG_CFI_FEATURES
+static void cfi_tell_features(struct cfi_pri_intelext *extp)
+{
+        int i;
+        printk("  Feature/Command Support: %4.4X\n", extp->FeatureSupport);
+	printk("     - Chip Erase:         %s\n", extp->FeatureSupport&1?"supported":"unsupported");
+	printk("     - Suspend Erase:      %s\n", extp->FeatureSupport&2?"supported":"unsupported");
+	printk("     - Suspend Program:    %s\n", extp->FeatureSupport&4?"supported":"unsupported");
+	printk("     - Legacy Lock/Unlock: %s\n", extp->FeatureSupport&8?"supported":"unsupported");
+	printk("     - Queued Erase:       %s\n", extp->FeatureSupport&16?"supported":"unsupported");
+	printk("     - Instant block lock: %s\n", extp->FeatureSupport&32?"supported":"unsupported");
+	printk("     - Protection Bits:    %s\n", extp->FeatureSupport&64?"supported":"unsupported");
+	printk("     - Page-mode read:     %s\n", extp->FeatureSupport&128?"supported":"unsupported");
+	printk("     - Synchronous read:   %s\n", extp->FeatureSupport&256?"supported":"unsupported");
+	for (i=9; i<32; i++) {
+		if (extp->FeatureSupport & (1<<i)) 
+			printk("     - Unknown Bit %X:      supported\n", i);
+	}
+	
+	printk("  Supported functions after Suspend: %2.2X\n", extp->SuspendCmdSupport);
+	printk("     - Program after Erase Suspend: %s\n", extp->SuspendCmdSupport&1?"supported":"unsupported");
+	for (i=1; i<8; i++) {
+		if (extp->SuspendCmdSupport & (1<<i))
+			printk("     - Unknown Bit %X:               supported\n", i);
+	}
+	
+	printk("  Block Status Register Mask: %4.4X\n", extp->BlkStatusRegMask);
+	printk("     - Lock Bit Active:      %s\n", extp->BlkStatusRegMask&1?"yes":"no");
+	printk("     - Valid Bit Active:     %s\n", extp->BlkStatusRegMask&2?"yes":"no");
+	for (i=2; i<16; i++) {
+		if (extp->BlkStatusRegMask & (1<<i))
+			printk("     - Unknown Bit %X Active: yes\n",i);
+	}
+	
+	printk("  Vcc Logic Supply Optimum Program/Erase Voltage: %d.%d V\n", 
+	       extp->VccOptimal >> 8, extp->VccOptimal & 0xf);
+	if (extp->VppOptimal)
+		printk("  Vpp Programming Supply Optimum Program/Erase Voltage: %d.%d V\n", 
+		       extp->VppOptimal >> 8, extp->VppOptimal & 0xf);
+}
+#endif
+
+/* This routine is made available to other mtd code via
+ * inter_module_register.  It must only be accessed through
+ * inter_module_get which will bump the use count of this module.  The
+ * addresses passed back in cfi are valid as long as the use count of
+ * this module is non-zero, i.e. between inter_module_get and
+ * inter_module_put.  Keith Owens <kaos@ocs.com.au> 29 Oct 2000.
+ */
+struct mtd_info *cfi_cmdset_0020(struct map_info *map, int primary)
+{
+	struct cfi_private *cfi = map->fldrv_priv;
+	int i;
+	__u32 base = cfi->chips[0].start;
+
+	if (cfi->cfi_mode) {
+		/* 
+		 * It's a real CFI chip, not one for which the probe
+		 * routine faked a CFI structure. So we read the feature
+		 * table from it.
+		 */
+		__u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR;
+		struct cfi_pri_intelext *extp;
+		int ofs_factor = cfi->interleave * cfi->device_type;
+
+                printk(" ST Microelectronics Extended Query Table at 0x%4.4X\n", adr);
+		if (!adr)
+			return NULL;
+
+		/* Switch it into Query Mode */
+		cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
+
+		extp = kmalloc(sizeof(*extp), GFP_KERNEL);
+		if (!extp) {
+			printk(KERN_ERR "Failed to allocate memory\n");
+			return NULL;
+		}
+		
+		/* Read in the Extended Query Table */
+		for (i=0; i<sizeof(*extp); i++) {
+			((unsigned char *)extp)[i] = 
+				cfi_read_query(map, (base+((adr+i)*ofs_factor)));
+		}
+		
+		if (extp->MajorVersion != '1' || 
+                    (extp->MinorVersion < '0' || extp->MinorVersion > '2')) {
+                    printk(KERN_WARNING "  Unknown staa Extended Query "
+                           "version %c.%c.\n",  extp->MajorVersion,
+                           extp->MinorVersion);
+                    kfree(extp);
+                    return NULL;
+		}
+		
+		/* Do some byteswapping if necessary */
+		extp->FeatureSupport = cfi32_to_cpu(extp->FeatureSupport);
+		extp->BlkStatusRegMask = cfi32_to_cpu(extp->BlkStatusRegMask);
+		
+#ifdef DEBUG_CFI_FEATURES
+		/* Tell the user about it in lots of lovely detail */
+		cfi_tell_features(extp);
+#endif	
+
+		/* Install our own private info structure */
+		cfi->cmdset_priv = extp;
+	}	
+
+	for (i=0; i< cfi->numchips; i++) {
+		cfi->chips[i].word_write_time = 128;
+		cfi->chips[i].buffer_write_time = 128;
+		cfi->chips[i].erase_time = 1024;
+	}		
+
+	map->fldrv = &cfi_staa_chipdrv;
+	MOD_INC_USE_COUNT;
+	
+	/* Make sure it's in read mode */
+	cfi_send_gen_cmd(0xff, 0x55, base, map, cfi, cfi->device_type, NULL);
+	return cfi_staa_setup(map);
+}
+
+static struct mtd_info *cfi_staa_setup(struct map_info *map)
+{
+	struct cfi_private *cfi = map->fldrv_priv;
+	struct mtd_info *mtd;
+	unsigned long offset = 0;
+	int i,j;
+	unsigned long devsize = (1<<cfi->cfiq->DevSize) * cfi->interleave;
+
+	mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
+	//printk(KERN_DEBUG "number of CFI chips: %d\n", cfi->numchips);
+
+	if (!mtd) {
+		printk(KERN_ERR "Failed to allocate memory for MTD device\n");
+		kfree(cfi->cmdset_priv);
+		return NULL;
+	}
+
+	memset(mtd, 0, sizeof(*mtd));
+	mtd->priv = map;
+	mtd->type = MTD_NORFLASH;
+	mtd->size = devsize * cfi->numchips;
+
+	mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips;
+	mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) 
+			* mtd->numeraseregions, GFP_KERNEL);
+	if (!mtd->eraseregions) { 
+		printk(KERN_ERR "Failed to allocate memory for MTD erase region info\n");
+		kfree(cfi->cmdset_priv);
+		return NULL;
+	}
+	
+	for (i=0; i<cfi->cfiq->NumEraseRegions; i++) {
+		unsigned long ernum, ersize;
+		ersize = ((cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff) * cfi->interleave;
+		ernum = (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1;
+
+		if (mtd->erasesize < ersize) {
+			mtd->erasesize = ersize;
+		}
+		for (j=0; j<cfi->numchips; j++) {
+			mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].offset = (j*devsize)+offset;
+			mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].erasesize = ersize;
+			mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].numblocks = ernum;
+		}
+		offset += (ersize * ernum);
+		}
+
+		if (offset != devsize) {
+			/* Argh */
+			printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize);
+			kfree(mtd->eraseregions);
+			kfree(cfi->cmdset_priv);
+			return NULL;
+		}
+
+		for (i=0; i<mtd->numeraseregions;i++){
+			printk(KERN_DEBUG "%d: offset=0x%x,size=0x%x,blocks=%d\n",
+			       i,mtd->eraseregions[i].offset,
+			       mtd->eraseregions[i].erasesize,
+			       mtd->eraseregions[i].numblocks);
+		}
+
+	/* Also select the correct geometry setup too */ 
+	mtd->erase = cfi_staa_erase_varsize;
+	mtd->read = cfi_staa_read;
+        mtd->write = cfi_staa_write_buffers;
+	mtd->writev = cfi_staa_writev;
+	mtd->sync = cfi_staa_sync;
+	mtd->lock = cfi_staa_lock;
+	mtd->unlock = cfi_staa_unlock;
+	mtd->suspend = cfi_staa_suspend;
+	mtd->resume = cfi_staa_resume;
+	mtd->flags = MTD_CAP_NORFLASH;
+	mtd->flags |= MTD_ECC; /* FIXME: Not all STMicro flashes have this */
+	mtd->eccsize = 8; /* FIXME: Should be 0 for STMicro flashes w/out ECC */
+	map->fldrv = &cfi_staa_chipdrv;
+	MOD_INC_USE_COUNT;
+	mtd->name = map->name;
+	return mtd;
+}
+
+
+static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
+{
+	__u32 status, status_OK;
+	unsigned long timeo;
+	DECLARE_WAITQUEUE(wait, current);
+	int suspended = 0;
+	unsigned long cmd_addr;
+	struct cfi_private *cfi = map->fldrv_priv;
+
+	adr += chip->start;
+
+	/* Ensure cmd read/writes are aligned. */ 
+	cmd_addr = adr & ~(CFIDEV_BUSWIDTH-1); 
+
+	/* Let's determine this according to the interleave only once */
+	status_OK = CMD(0x80);
+
+	timeo = jiffies + HZ;
+ retry:
+	spin_lock_bh(chip->mutex);
+
+	/* Check that the chip's ready to talk to us.
+	 * If it's in FL_ERASING state, suspend it and make it talk now.
+	 */
+	switch (chip->state) {
+	case FL_ERASING:
+		if (!((struct cfi_pri_intelext *)cfi->cmdset_priv)->FeatureSupport & 2)
+			goto sleep; /* We don't support erase suspend */
+		
+		cfi_write (map, CMD(0xb0), cmd_addr);
+		/* If the flash has finished erasing, then 'erase suspend'
+		 * appears to make some (28F320) flash devices switch to
+		 * 'read' mode.  Make sure that we switch to 'read status'
+		 * mode so we get the right data. --rmk
+		 */
+		cfi_write(map, CMD(0x70), cmd_addr);
+		chip->oldstate = FL_ERASING;
+		chip->state = FL_ERASE_SUSPENDING;
+		//		printk("Erase suspending at 0x%lx\n", cmd_addr);
+		for (;;) {
+			status = cfi_read(map, cmd_addr);
+			if ((status & status_OK) == status_OK)
+				break;
+			
+			if (time_after(jiffies, timeo)) {
+				/* Urgh */
+				cfi_write(map, CMD(0xd0), cmd_addr);
+				/* make sure we're in 'read status' mode */
+				cfi_write(map, CMD(0x70), cmd_addr);
+				chip->state = FL_ERASING;
+				spin_unlock_bh(chip->mutex);
+				printk(KERN_ERR "Chip not ready after erase "
+				       "suspended: status = 0x%x\n", status);
+				return -EIO;
+			}
+			
+			spin_unlock_bh(chip->mutex);
+			cfi_udelay(1);
+			spin_lock_bh(chip->mutex);
+		}
+		
+		suspended = 1;
+		cfi_write(map, CMD(0xff), cmd_addr);
+		chip->state = FL_READY;
+		break;
+	
+#if 0
+	case FL_WRITING:
+		/* Not quite yet */
+#endif
+
+	case FL_READY:
+		break;
+
+	case FL_CFI_QUERY:
+	case FL_JEDEC_QUERY:
+		cfi_write(map, CMD(0x70), cmd_addr);
+		chip->state = FL_STATUS;
+
+	case FL_STATUS:
+		status = cfi_read(map, cmd_addr);
+		if ((status & status_OK) == status_OK) {
+			cfi_write(map, CMD(0xff), cmd_addr);
+			chip->state = FL_READY;
+			break;
+		}
+		
+		/* Urgh. Chip not yet ready to talk to us. */
+		if (time_after(jiffies, timeo)) {
+			spin_unlock_bh(chip->mutex);
+			printk(KERN_ERR "waiting for chip to be ready timed out in read. WSM status = %x\n", status);
+			return -EIO;
+		}
+
+		/* Latency issues. Drop the lock, wait a while and retry */
+		spin_unlock_bh(chip->mutex);
+		cfi_udelay(1);
+		goto retry;
+
+	default:
+	sleep:
+		/* Stick ourselves on a wait queue to be woken when
+		   someone changes the status */
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		add_wait_queue(&chip->wq, &wait);
+		spin_unlock_bh(chip->mutex);
+		schedule();
+		remove_wait_queue(&chip->wq, &wait);
+		timeo = jiffies + HZ;
+		goto retry;
+	}
+
+	map->copy_from(map, buf, adr, len);
+
+	if (suspended) {
+		chip->state = chip->oldstate;
+		/* What if one interleaved chip has finished and the 
+		   other hasn't? The old code would leave the finished
+		   one in READY mode. That's bad, and caused -EROFS 
+		   errors to be returned from do_erase_oneblock because
+		   that's the only bit it checked for at the time.
+		   As the state machine appears to explicitly allow 
+		   sending the 0x70 (Read Status) command to an erasing
+		   chip and expecting it to be ignored, that's what we 
+		   do. */
+		cfi_write(map, CMD(0xd0), cmd_addr);
+		cfi_write(map, CMD(0x70), cmd_addr);		
+	}
+
+	wake_up(&chip->wq);
+	spin_unlock_bh(chip->mutex);
+	return 0;
+}
+
+static int cfi_staa_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	unsigned long ofs;
+	int chipnum;
+	int ret = 0;
+
+	/* ofs: offset within the first chip that the first read should start */
+	chipnum = (from >> cfi->chipshift);
+	ofs = from - (chipnum <<  cfi->chipshift);
+
+	*retlen = 0;
+
+	while (len) {
+		unsigned long thislen;
+
+		if (chipnum >= cfi->numchips)
+			break;
+
+		if ((len + ofs -1) >> cfi->chipshift)
+			thislen = (1<<cfi->chipshift) - ofs;
+		else
+			thislen = len;
+
+		ret = do_read_onechip(map, &cfi->chips[chipnum], ofs, thislen, buf);
+		if (ret)
+			break;
+
+		*retlen += thislen;
+		len -= thislen;
+		buf += thislen;
+		
+		ofs = 0;
+		chipnum++;
+	}
+	return ret;
+}
+
+static inline int do_write_buffer(struct map_info *map, struct flchip *chip, 
+				  unsigned long adr, const u_char *buf, int len)
+{
+	struct cfi_private *cfi = map->fldrv_priv;
+	__u32 status, status_OK;
+	unsigned long cmd_adr, timeo;
+	DECLARE_WAITQUEUE(wait, current);
+	int wbufsize, z;
+        
+        /* M58LW064A requires bus alignment for buffer wriets -- saw */
+        if (adr & (CFIDEV_BUSWIDTH-1))
+            return -EINVAL;
+
+        wbufsize = CFIDEV_INTERLEAVE << cfi->cfiq->MaxBufWriteSize;
+        adr += chip->start;
+	cmd_adr = adr & ~(wbufsize-1);
+	
+	/* Let's determine this according to the interleave only once */
+        status_OK = CMD(0x80);
+        
+	timeo = jiffies + HZ;
+ retry:
+
+#ifdef DEBUG_CFI_FEATURES
+       printk("%s: chip->state[%d]\n", __FUNCTION__, chip->state);
+#endif
+	spin_lock_bh(chip->mutex);
+ 
+	/* Check that the chip's ready to talk to us.
+	 * Later, we can actually think about interrupting it
+	 * if it's in FL_ERASING state.
+	 * Not just yet, though.
+	 */
+	switch (chip->state) {
+	case FL_READY:
+		break;
+		
+	case FL_CFI_QUERY:
+	case FL_JEDEC_QUERY:
+		cfi_write(map, CMD(0x70), cmd_adr);
+                chip->state = FL_STATUS;
+#ifdef DEBUG_CFI_FEATURES
+        printk("%s: 1 status[%x]\n", __FUNCTION__, cfi_read(map, cmd_adr));
+#endif
+
+	case FL_STATUS:
+		status = cfi_read(map, cmd_adr);
+		if ((status & status_OK) == status_OK)
+			break;
+		/* Urgh. Chip not yet ready to talk to us. */
+		if (time_after(jiffies, timeo)) {
+			spin_unlock_bh(chip->mutex);
+                        printk(KERN_ERR "waiting for chip to be ready timed out in buffer write Xstatus = %x, status = %x\n",
+                               status, cfi_read(map, cmd_adr));
+			return -EIO;
+		}
+
+		/* Latency issues. Drop the lock, wait a while and retry */
+		spin_unlock_bh(chip->mutex);
+		cfi_udelay(1);
+		goto retry;
+
+	default:
+		/* Stick ourselves on a wait queue to be woken when
+		   someone changes the status */
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		add_wait_queue(&chip->wq, &wait);
+		spin_unlock_bh(chip->mutex);
+		schedule();
+		remove_wait_queue(&chip->wq, &wait);
+		timeo = jiffies + HZ;
+		goto retry;
+	}
+
+	ENABLE_VPP(map);
+	cfi_write(map, CMD(0xe8), cmd_adr);
+	chip->state = FL_WRITING_TO_BUFFER;
+
+	z = 0;
+	for (;;) {
+		status = cfi_read(map, cmd_adr);
+		if ((status & status_OK) == status_OK)
+			break;
+
+		spin_unlock_bh(chip->mutex);
+		cfi_udelay(1);
+		spin_lock_bh(chip->mutex);
+
+		if (++z > 100) {
+			/* Argh. Not ready for write to buffer */
+			DISABLE_VPP(map);
+                        cfi_write(map, CMD(0x70), cmd_adr);
+			chip->state = FL_STATUS;
+			spin_unlock_bh(chip->mutex);
+			printk(KERN_ERR "Chip not ready for buffer write. Xstatus = %x\n", status);
+			return -EIO;
+		}
+	}
+
+	/* Write length of data to come */
+	cfi_write(map, CMD(len/CFIDEV_BUSWIDTH-1), cmd_adr );
+        
+	/* Write data */
+	for (z = 0; z < len; z += CFIDEV_BUSWIDTH) {
+		if (cfi_buswidth_is_1()) {
+			map->write8 (map, *((__u8*)buf)++, adr+z);
+		} else if (cfi_buswidth_is_2()) {
+			map->write16 (map, *((__u16*)buf)++, adr+z);
+		} else if (cfi_buswidth_is_4()) {
+			map->write32 (map, *((__u32*)buf)++, adr+z);
+		} else {
+			DISABLE_VPP(map);
+			return -EINVAL;
+		}
+	}
+	/* GO GO GO */
+	cfi_write(map, CMD(0xd0), cmd_adr);
+	chip->state = FL_WRITING;
+
+	spin_unlock_bh(chip->mutex);
+	cfi_udelay(chip->buffer_write_time);
+	spin_lock_bh(chip->mutex);
+
+	timeo = jiffies + (HZ/2);
+	z = 0;
+	for (;;) {
+		if (chip->state != FL_WRITING) {
+			/* Someone's suspended the write. Sleep */
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			add_wait_queue(&chip->wq, &wait);
+			spin_unlock_bh(chip->mutex);
+			schedule();
+			remove_wait_queue(&chip->wq, &wait);
+			timeo = jiffies + (HZ / 2); /* FIXME */
+			spin_lock_bh(chip->mutex);
+			continue;
+		}
+
+		status = cfi_read(map, cmd_adr);
+		if ((status & status_OK) == status_OK)
+			break;
+
+		/* OK Still waiting */
+		if (time_after(jiffies, timeo)) {
+                        /* clear status */
+                        cfi_write(map, CMD(0x50), cmd_adr);
+                        /* put back into read status register mode */
+                        cfi_write(map, CMD(0x70), adr);
+			chip->state = FL_STATUS;
+			DISABLE_VPP(map);
+			spin_unlock_bh(chip->mutex);
+			printk(KERN_ERR "waiting for chip to be ready timed out in bufwrite\n");
+			return -EIO;
+		}
+		
+		/* Latency issues. Drop the lock, wait a while and retry */
+		spin_unlock_bh(chip->mutex);
+		cfi_udelay(1);
+		z++;
+		spin_lock_bh(chip->mutex);
+	}
+	if (!z) {
+		chip->buffer_write_time--;
+		if (!chip->buffer_write_time)
+			chip->buffer_write_time++;
+	}
+	if (z > 1) 
+		chip->buffer_write_time++;
+        
+	/* Done and happy. */
+	DISABLE_VPP(map);
+	chip->state = FL_STATUS;
+
+        /* check for errors: 'lock bit', 'VPP', 'dead cell'/'unerased cell' or 'incorrect cmd' -- saw */
+        if ((status & CMD(0x02)) || (status & CMD(0x08)) ||
+            (status & CMD(0x10)) || (status & CMD(0x20))) {
+#ifdef DEBUG_CFI_FEATURES
+            printk("%s: 2 status[%x]\n", __FUNCTION__, status);
+#endif
+            /* clear status */
+            cfi_write(map, CMD(0x50), cmd_adr);
+            /* put back into read status register mode */
+            cfi_write(map, CMD(0x70), adr);
+            wake_up(&chip->wq);
+            spin_unlock_bh(chip->mutex);
+            return (status & CMD(0x02)) ? -EROFS : -EIO;
+        }
+	wake_up(&chip->wq);
+	spin_unlock_bh(chip->mutex);
+
+        return 0;
+}
+
+static int cfi_staa_write_buffers (struct mtd_info *mtd, loff_t to, 
+				       size_t len, size_t *retlen, const u_char *buf)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	int wbufsize = CFIDEV_INTERLEAVE << cfi->cfiq->MaxBufWriteSize;
+	int ret = 0;
+	int chipnum;
+	unsigned long ofs;
+
+	*retlen = 0;
+	if (!len)
+		return 0;
+
+	chipnum = to >> cfi->chipshift;
+	ofs = to  - (chipnum << cfi->chipshift);
+
+#ifdef DEBUG_CFI_FEATURES
+        printk("%s: CFIDEV_BUSWIDTH[%x]\n", __FUNCTION__, CFIDEV_BUSWIDTH);
+        printk("%s: chipnum[%x] wbufsize[%x]\n", __FUNCTION__, chipnum, wbufsize);
+        printk("%s: ofs[%x] len[%x]\n", __FUNCTION__, ofs, len);
+#endif
+        
+        /* Write buffer is worth it only if more than one word to write... */
+        while (len > 0) {
+		/* We must not cross write block boundaries */
+		int size = wbufsize - (ofs & (wbufsize-1));
+
+                if (size > len)
+                    size = len;
+
+                ret = do_write_buffer(map, &cfi->chips[chipnum], 
+				      ofs, buf, size);
+		if (ret)
+			return ret;
+
+		ofs += size;
+		buf += size;
+		(*retlen) += size;
+		len -= size;
+
+		if (ofs >> cfi->chipshift) {
+			chipnum ++; 
+			ofs = 0;
+			if (chipnum == cfi->numchips)
+				return 0;
+		}
+	}
+        
+	return 0;
+}
+
+/*
+ * Writev for ECC-Flashes is a little more complicated. We need to maintain
+ * a small buffer for this.
+ * XXX: If the buffer size is not a multiple of 2, this will break
+ */
+#define ECCBUF_SIZE (mtd->eccsize)
+#define ECCBUF_DIV(x) ((x) & ~(ECCBUF_SIZE - 1))
+#define ECCBUF_MOD(x) ((x) &  (ECCBUF_SIZE - 1))
+static int
+cfi_staa_writev(struct mtd_info *mtd, const struct iovec *vecs,
+		unsigned long count, loff_t to, size_t *retlen)
+{
+	unsigned long i;
+	size_t	 totlen = 0, thislen;
+	int	 ret = 0;
+	size_t	 buflen = 0;
+	static char *buffer;
+
+	if (!ECCBUF_SIZE) {
+		/* We should fall back to a general writev implementation.
+		 * Until that is written, just break.
+		 */
+		return -EIO;
+	}
+	buffer = kmalloc(ECCBUF_SIZE, GFP_KERNEL);
+	if (!buffer)
+		return -ENOMEM;
+
+	for (i=0; i<count; i++) {
+		size_t elem_len = vecs[i].iov_len;
+		void *elem_base = vecs[i].iov_base;
+		if (!elem_len) /* FIXME: Might be unnecessary. Check that */
+			continue;
+		if (buflen) { /* cut off head */
+			if (buflen + elem_len < ECCBUF_SIZE) { /* just accumulate */
+				memcpy(buffer+buflen, elem_base, elem_len);
+				buflen += elem_len;
+				continue;
+			}
+			memcpy(buffer+buflen, elem_base, ECCBUF_SIZE-buflen);
+			ret = mtd->write(mtd, to, ECCBUF_SIZE, &thislen, buffer);
+			totlen += thislen;
+			if (ret || thislen != ECCBUF_SIZE)
+				goto write_error;
+			elem_len -= thislen-buflen;
+			elem_base += thislen-buflen;
+			to += ECCBUF_SIZE;
+		}
+		if (ECCBUF_DIV(elem_len)) { /* write clean aligned data */
+			ret = mtd->write(mtd, to, ECCBUF_DIV(elem_len), &thislen, elem_base);
+			totlen += thislen;
+			if (ret || thislen != ECCBUF_DIV(elem_len))
+				goto write_error;
+			to += thislen;
+		}
+		buflen = ECCBUF_MOD(elem_len); /* cut off tail */
+		if (buflen) {
+			memset(buffer, 0xff, ECCBUF_SIZE);
+			memcpy(buffer, elem_base + thislen, buflen);
+		}
+	}
+	if (buflen) { /* flush last page, even if not full */
+		/* This is sometimes intended behaviour, really */
+		ret = mtd->write(mtd, to, buflen, &thislen, buffer);
+		totlen += thislen;
+		if (ret || thislen != ECCBUF_SIZE)
+			goto write_error;
+	}
+write_error:
+	if (retlen)
+		*retlen = totlen;
+	return ret;
+}
+
+
+static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr)
+{
+	struct cfi_private *cfi = map->fldrv_priv;
+	__u32 status, status_OK;
+	unsigned long timeo;
+	int retries = 3;
+	DECLARE_WAITQUEUE(wait, current);
+	int ret = 0;
+
+	adr += chip->start;
+
+	/* Let's determine this according to the interleave only once */
+	status_OK = CMD(0x80);
+
+	timeo = jiffies + HZ;
+retry:
+	spin_lock_bh(chip->mutex);
+
+	/* Check that the chip's ready to talk to us. */
+	switch (chip->state) {
+	case FL_CFI_QUERY:
+	case FL_JEDEC_QUERY:
+	case FL_READY:
+		cfi_write(map, CMD(0x70), adr);
+		chip->state = FL_STATUS;
+
+	case FL_STATUS:
+		status = cfi_read(map, adr);
+		if ((status & status_OK) == status_OK)
+			break;
+		
+		/* Urgh. Chip not yet ready to talk to us. */
+		if (time_after(jiffies, timeo)) {
+			spin_unlock_bh(chip->mutex);
+			printk(KERN_ERR "waiting for chip to be ready timed out in erase\n");
+			return -EIO;
+		}
+
+		/* Latency issues. Drop the lock, wait a while and retry */
+		spin_unlock_bh(chip->mutex);
+		cfi_udelay(1);
+		goto retry;
+
+	default:
+		/* Stick ourselves on a wait queue to be woken when
+		   someone changes the status */
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		add_wait_queue(&chip->wq, &wait);
+		spin_unlock_bh(chip->mutex);
+		schedule();
+		remove_wait_queue(&chip->wq, &wait);
+		timeo = jiffies + HZ;
+		goto retry;
+	}
+
+	ENABLE_VPP(map);
+	/* Clear the status register first */
+	cfi_write(map, CMD(0x50), adr);
+
+	/* Now erase */
+	cfi_write(map, CMD(0x20), adr);
+	cfi_write(map, CMD(0xD0), adr);
+	chip->state = FL_ERASING;
+	
+	spin_unlock_bh(chip->mutex);
+	schedule_timeout(HZ);
+	spin_lock_bh(chip->mutex);
+
+	/* FIXME. Use a timer to check this, and return immediately. */
+	/* Once the state machine's known to be working I'll do that */
+
+	timeo = jiffies + (HZ*20);
+	for (;;) {
+		if (chip->state != FL_ERASING) {
+			/* Someone's suspended the erase. Sleep */
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			add_wait_queue(&chip->wq, &wait);
+			spin_unlock_bh(chip->mutex);
+			schedule();
+			remove_wait_queue(&chip->wq, &wait);
+			timeo = jiffies + (HZ*20); /* FIXME */
+			spin_lock_bh(chip->mutex);
+			continue;
+		}
+
+		status = cfi_read(map, adr);
+		if ((status & status_OK) == status_OK)
+			break;
+		
+		/* OK Still waiting */
+		if (time_after(jiffies, timeo)) {
+			cfi_write(map, CMD(0x70), adr);
+			chip->state = FL_STATUS;
+			printk(KERN_ERR "waiting for erase to complete timed out. Xstatus = %x, status = %x.\n", status, cfi_read(map, adr));
+			DISABLE_VPP(map);
+			spin_unlock_bh(chip->mutex);
+			return -EIO;
+		}
+		
+		/* Latency issues. Drop the lock, wait a while and retry */
+		spin_unlock_bh(chip->mutex);
+		cfi_udelay(1);
+		spin_lock_bh(chip->mutex);
+	}
+	
+	DISABLE_VPP(map);
+	ret = 0;
+
+	/* We've broken this before. It doesn't hurt to be safe */
+	cfi_write(map, CMD(0x70), adr);
+	chip->state = FL_STATUS;
+	status = cfi_read(map, adr);
+
+	/* check for lock bit */
+	if (status & CMD(0x3a)) {
+		unsigned char chipstatus = status;
+		if (status != CMD(status & 0xff)) {
+			int i;
+			for (i = 1; i<CFIDEV_INTERLEAVE; i++) {
+				      chipstatus |= status >> (cfi->device_type * 8);
+			}
+			printk(KERN_WARNING "Status is not identical for all chips: 0x%x. Merging to give 0x%02x\n", status, chipstatus);
+		}
+		/* Reset the error bits */
+		cfi_write(map, CMD(0x50), adr);
+		cfi_write(map, CMD(0x70), adr);
+		
+		if ((chipstatus & 0x30) == 0x30) {
+			printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%x\n", status);
+			ret = -EIO;
+		} else if (chipstatus & 0x02) {
+			/* Protection bit set */
+			ret = -EROFS;
+		} else if (chipstatus & 0x8) {
+			/* Voltage */
+			printk(KERN_WARNING "Chip reports voltage low on erase: status 0x%x\n", status);
+			ret = -EIO;
+		} else if (chipstatus & 0x20) {
+			if (retries--) {
+				printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x. Retrying...\n", adr, status);
+				timeo = jiffies + HZ;
+				chip->state = FL_STATUS;
+				spin_unlock_bh(chip->mutex);
+				goto retry;
+			}
+			printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x\n", adr, status);
+			ret = -EIO;
+		}
+	}
+
+	wake_up(&chip->wq);
+	spin_unlock_bh(chip->mutex);
+	return ret;
+}
+
+int cfi_staa_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
+{	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	unsigned long adr, len;
+	int chipnum, ret = 0;
+	int i, first;
+	struct mtd_erase_region_info *regions = mtd->eraseregions;
+
+	if (instr->addr > mtd->size)
+		return -EINVAL;
+
+	if ((instr->len + instr->addr) > mtd->size)
+		return -EINVAL;
+
+	/* Check that both start and end of the requested erase are
+	 * aligned with the erasesize at the appropriate addresses.
+	 */
+
+	i = 0;
+
+	/* Skip all erase regions which are ended before the start of 
+	   the requested erase. Actually, to save on the calculations,
+	   we skip to the first erase region which starts after the
+	   start of the requested erase, and then go back one.
+	*/
+	
+	while (i < mtd->numeraseregions && instr->addr >= regions[i].offset)
+	       i++;
+	i--;
+
+	/* OK, now i is pointing at the erase region in which this 
+	   erase request starts. Check the start of the requested
+	   erase range is aligned with the erase size which is in
+	   effect here.
+	*/
+
+	if (instr->addr & (regions[i].erasesize-1))
+		return -EINVAL;
+
+	/* Remember the erase region we start on */
+	first = i;
+
+	/* Next, check that the end of the requested erase is aligned
+	 * with the erase region at that address.
+	 */
+
+	while (i<mtd->numeraseregions && (instr->addr + instr->len) >= regions[i].offset)
+		i++;
+
+	/* As before, drop back one to point at the region in which
+	   the address actually falls
+	*/
+	i--;
+	
+	if ((instr->addr + instr->len) & (regions[i].erasesize-1))
+		return -EINVAL;
+
+	chipnum = instr->addr >> cfi->chipshift;
+	adr = instr->addr - (chipnum << cfi->chipshift);
+	len = instr->len;
+
+	i=first;
+
+	while(len) {
+		ret = do_erase_oneblock(map, &cfi->chips[chipnum], adr);
+		
+		if (ret)
+			return ret;
+
+		adr += regions[i].erasesize;
+		len -= regions[i].erasesize;
+
+		if (adr % (1<< cfi->chipshift) == ((regions[i].offset + (regions[i].erasesize * regions[i].numblocks)) %( 1<< cfi->chipshift)))
+			i++;
+
+		if (adr >> cfi->chipshift) {
+			adr = 0;
+			chipnum++;
+			
+			if (chipnum >= cfi->numchips)
+			break;
+		}
+	}
+		
+	instr->state = MTD_ERASE_DONE;
+	if (instr->callback)
+		instr->callback(instr);
+	
+	return 0;
+}
+
+static void cfi_staa_sync (struct mtd_info *mtd)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	int i;
+	struct flchip *chip;
+	int ret = 0;
+	DECLARE_WAITQUEUE(wait, current);
+
+	for (i=0; !ret && i<cfi->numchips; i++) {
+		chip = &cfi->chips[i];
+
+	retry:
+		spin_lock_bh(chip->mutex);
+
+		switch(chip->state) {
+		case FL_READY:
+		case FL_STATUS:
+		case FL_CFI_QUERY:
+		case FL_JEDEC_QUERY:
+			chip->oldstate = chip->state;
+			chip->state = FL_SYNCING;
+			/* No need to wake_up() on this state change - 
+			 * as the whole point is that nobody can do anything
+			 * with the chip now anyway.
+			 */
+		case FL_SYNCING:
+			spin_unlock_bh(chip->mutex);
+			break;
+
+		default:
+			/* Not an idle state */
+			add_wait_queue(&chip->wq, &wait);
+			
+			spin_unlock_bh(chip->mutex);
+			schedule();
+		        remove_wait_queue(&chip->wq, &wait);
+			
+			goto retry;
+		}
+	}
+
+	/* Unlock the chips again */
+
+	for (i--; i >=0; i--) {
+		chip = &cfi->chips[i];
+
+		spin_lock_bh(chip->mutex);
+		
+		if (chip->state == FL_SYNCING) {
+			chip->state = chip->oldstate;
+			wake_up(&chip->wq);
+		}
+		spin_unlock_bh(chip->mutex);
+	}
+}
+
+static inline int do_lock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr)
+{
+	struct cfi_private *cfi = map->fldrv_priv;
+	__u32 status, status_OK;
+	unsigned long timeo = jiffies + HZ;
+	DECLARE_WAITQUEUE(wait, current);
+
+	adr += chip->start;
+
+	/* Let's determine this according to the interleave only once */
+	status_OK = CMD(0x80);
+
+	timeo = jiffies + HZ;
+retry:
+	spin_lock_bh(chip->mutex);
+
+	/* Check that the chip's ready to talk to us. */
+	switch (chip->state) {
+	case FL_CFI_QUERY:
+	case FL_JEDEC_QUERY:
+	case FL_READY:
+		cfi_write(map, CMD(0x70), adr);
+		chip->state = FL_STATUS;
+
+	case FL_STATUS:
+		status = cfi_read(map, adr);
+		if ((status & status_OK) == status_OK) 
+			break;
+		
+		/* Urgh. Chip not yet ready to talk to us. */
+		if (time_after(jiffies, timeo)) {
+			spin_unlock_bh(chip->mutex);
+			printk(KERN_ERR "waiting for chip to be ready timed out in lock\n");
+			return -EIO;
+		}
+
+		/* Latency issues. Drop the lock, wait a while and retry */
+		spin_unlock_bh(chip->mutex);
+		cfi_udelay(1);
+		goto retry;
+
+	default:
+		/* Stick ourselves on a wait queue to be woken when
+		   someone changes the status */
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		add_wait_queue(&chip->wq, &wait);
+		spin_unlock_bh(chip->mutex);
+		schedule();
+		remove_wait_queue(&chip->wq, &wait);
+		timeo = jiffies + HZ;
+		goto retry;
+	}
+
+	ENABLE_VPP(map);
+	cfi_write(map, CMD(0x60), adr);
+	cfi_write(map, CMD(0x01), adr);
+	chip->state = FL_LOCKING;
+	
+	spin_unlock_bh(chip->mutex);
+	schedule_timeout(HZ);
+	spin_lock_bh(chip->mutex);
+
+	/* FIXME. Use a timer to check this, and return immediately. */
+	/* Once the state machine's known to be working I'll do that */
+
+	timeo = jiffies + (HZ*2);
+	for (;;) {
+
+		status = cfi_read(map, adr);
+		if ((status & status_OK) == status_OK)
+			break;
+		
+		/* OK Still waiting */
+		if (time_after(jiffies, timeo)) {
+			cfi_write(map, CMD(0x70), adr);
+			chip->state = FL_STATUS;
+			printk(KERN_ERR "waiting for lock to complete timed out. Xstatus = %x, status = %x.\n", status, cfi_read(map, adr));
+			DISABLE_VPP(map);
+			spin_unlock_bh(chip->mutex);
+			return -EIO;
+		}
+		
+		/* Latency issues. Drop the lock, wait a while and retry */
+		spin_unlock_bh(chip->mutex);
+		cfi_udelay(1);
+		spin_lock_bh(chip->mutex);
+	}
+	
+	/* Done and happy. */
+	chip->state = FL_STATUS;
+	DISABLE_VPP(map);
+	wake_up(&chip->wq);
+	spin_unlock_bh(chip->mutex);
+	return 0;
+}
+static int cfi_staa_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	unsigned long adr;
+	int chipnum, ret = 0;
+#ifdef DEBUG_LOCK_BITS
+	int ofs_factor = cfi->interleave * cfi->device_type;
+#endif
+
+	if (ofs & (mtd->erasesize - 1))
+		return -EINVAL;
+
+	if (len & (mtd->erasesize -1))
+		return -EINVAL;
+
+	if ((len + ofs) > mtd->size)
+		return -EINVAL;
+
+	chipnum = ofs >> cfi->chipshift;
+	adr = ofs - (chipnum << cfi->chipshift);
+
+	while(len) {
+
+#ifdef DEBUG_LOCK_BITS
+		cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
+		printk("before lock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor)));
+		cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);
+#endif
+
+		ret = do_lock_oneblock(map, &cfi->chips[chipnum], adr);
+
+#ifdef DEBUG_LOCK_BITS
+		cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
+		printk("after lock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor)));
+		cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);
+#endif	
+		
+		if (ret)
+			return ret;
+
+		adr += mtd->erasesize;
+		len -= mtd->erasesize;
+
+		if (adr >> cfi->chipshift) {
+			adr = 0;
+			chipnum++;
+			
+			if (chipnum >= cfi->numchips)
+			break;
+		}
+	}
+	return 0;
+}
+static inline int do_unlock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr)
+{
+	struct cfi_private *cfi = map->fldrv_priv;
+	__u32 status, status_OK;
+	unsigned long timeo = jiffies + HZ;
+	DECLARE_WAITQUEUE(wait, current);
+
+	adr += chip->start;
+
+	/* Let's determine this according to the interleave only once */
+	status_OK = CMD(0x80);
+
+	timeo = jiffies + HZ;
+retry:
+	spin_lock_bh(chip->mutex);
+
+	/* Check that the chip's ready to talk to us. */
+	switch (chip->state) {
+	case FL_CFI_QUERY:
+	case FL_JEDEC_QUERY:
+	case FL_READY:
+		cfi_write(map, CMD(0x70), adr);
+		chip->state = FL_STATUS;
+
+	case FL_STATUS:
+		status = cfi_read(map, adr);
+		if ((status & status_OK) == status_OK)
+			break;
+		
+		/* Urgh. Chip not yet ready to talk to us. */
+		if (time_after(jiffies, timeo)) {
+			spin_unlock_bh(chip->mutex);
+			printk(KERN_ERR "waiting for chip to be ready timed out in unlock\n");
+			return -EIO;
+		}
+
+		/* Latency issues. Drop the lock, wait a while and retry */
+		spin_unlock_bh(chip->mutex);
+		cfi_udelay(1);
+		goto retry;
+
+	default:
+		/* Stick ourselves on a wait queue to be woken when
+		   someone changes the status */
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		add_wait_queue(&chip->wq, &wait);
+		spin_unlock_bh(chip->mutex);
+		schedule();
+		remove_wait_queue(&chip->wq, &wait);
+		timeo = jiffies + HZ;
+		goto retry;
+	}
+
+	ENABLE_VPP(map);
+	cfi_write(map, CMD(0x60), adr);
+	cfi_write(map, CMD(0xD0), adr);
+	chip->state = FL_UNLOCKING;
+	
+	spin_unlock_bh(chip->mutex);
+	schedule_timeout(HZ);
+	spin_lock_bh(chip->mutex);
+
+	/* FIXME. Use a timer to check this, and return immediately. */
+	/* Once the state machine's known to be working I'll do that */
+
+	timeo = jiffies + (HZ*2);
+	for (;;) {
+
+		status = cfi_read(map, adr);
+		if ((status & status_OK) == status_OK)
+			break;
+		
+		/* OK Still waiting */
+		if (time_after(jiffies, timeo)) {
+			cfi_write(map, CMD(0x70), adr);
+			chip->state = FL_STATUS;
+			printk(KERN_ERR "waiting for unlock to complete timed out. Xstatus = %x, status = %x.\n", status, cfi_read(map, adr));
+			DISABLE_VPP(map);
+			spin_unlock_bh(chip->mutex);
+			return -EIO;
+		}
+		
+		/* Latency issues. Drop the unlock, wait a while and retry */
+		spin_unlock_bh(chip->mutex);
+		cfi_udelay(1);
+		spin_lock_bh(chip->mutex);
+	}
+	
+	/* Done and happy. */
+	chip->state = FL_STATUS;
+	DISABLE_VPP(map);
+	wake_up(&chip->wq);
+	spin_unlock_bh(chip->mutex);
+	return 0;
+}
+static int cfi_staa_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	unsigned long adr;
+	int chipnum, ret = 0;
+#ifdef DEBUG_LOCK_BITS
+	int ofs_factor = cfi->interleave * cfi->device_type;
+#endif
+
+	chipnum = ofs >> cfi->chipshift;
+	adr = ofs - (chipnum << cfi->chipshift);
+
+#ifdef DEBUG_LOCK_BITS
+	{
+		unsigned long temp_adr = adr;
+		unsigned long temp_len = len;
+                 
+		cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
+                while (temp_len) {
+			printk("before unlock %x: block status register is %x\n",temp_adr,cfi_read_query(map, temp_adr+(2*ofs_factor)));
+			temp_adr += mtd->erasesize;
+			temp_len -= mtd->erasesize;
+		}
+		cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);
+	}
+#endif
+
+	ret = do_unlock_oneblock(map, &cfi->chips[chipnum], adr);
+
+#ifdef DEBUG_LOCK_BITS
+	cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
+	printk("after unlock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor)));
+	cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);
+#endif
+	
+	return ret;
+}
+
+static int cfi_staa_suspend(struct mtd_info *mtd)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	int i;
+	struct flchip *chip;
+	int ret = 0;
+
+	for (i=0; !ret && i<cfi->numchips; i++) {
+		chip = &cfi->chips[i];
+
+		spin_lock_bh(chip->mutex);
+
+		switch(chip->state) {
+		case FL_READY:
+		case FL_STATUS:
+		case FL_CFI_QUERY:
+		case FL_JEDEC_QUERY:
+			chip->oldstate = chip->state;
+			chip->state = FL_PM_SUSPENDED;
+			/* No need to wake_up() on this state change - 
+			 * as the whole point is that nobody can do anything
+			 * with the chip now anyway.
+			 */
+		case FL_PM_SUSPENDED:
+			break;
+
+		default:
+			ret = -EAGAIN;
+			break;
+		}
+		spin_unlock_bh(chip->mutex);
+	}
+
+	/* Unlock the chips again */
+
+	if (ret) {
+		for (i--; i >=0; i--) {
+			chip = &cfi->chips[i];
+			
+			spin_lock_bh(chip->mutex);
+			
+			if (chip->state == FL_PM_SUSPENDED) {
+				/* No need to force it into a known state here,
+				   because we're returning failure, and it didn't
+				   get power cycled */
+				chip->state = chip->oldstate;
+				wake_up(&chip->wq);
+			}
+			spin_unlock_bh(chip->mutex);
+		}
+	} 
+	
+	return ret;
+}
+
+static void cfi_staa_resume(struct mtd_info *mtd)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	int i;
+	struct flchip *chip;
+
+	for (i=0; i<cfi->numchips; i++) {
+	
+		chip = &cfi->chips[i];
+
+		spin_lock_bh(chip->mutex);
+		
+		/* Go to known state. Chip may have been power cycled */
+		if (chip->state == FL_PM_SUSPENDED) {
+			cfi_write(map, CMD(0xFF), 0);
+			chip->state = FL_READY;
+			wake_up(&chip->wq);
+		}
+
+		spin_unlock_bh(chip->mutex);
+	}
+}
+
+static void cfi_staa_destroy(struct mtd_info *mtd)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	kfree(cfi->cmdset_priv);
+	kfree(cfi);
+}
+
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
+#define cfi_staa_init init_module
+#define cfi_staa_exit cleanup_module
+#endif
+
+static char im_name[]="cfi_cmdset_0020";
+
+mod_init_t cfi_staa_init(void)
+{
+	inter_module_register(im_name, THIS_MODULE, &cfi_cmdset_0020);
+	return 0;
+}
+
+mod_exit_t cfi_staa_exit(void)
+{
+	inter_module_unregister(im_name);
+}
+
+module_init(cfi_staa_init);
+module_exit(cfi_staa_exit);
diff -urN linux-2.4.21-pre3/drivers/mtd/chips/cfi_probe.c linux-2.4.21-pre4/drivers/mtd/chips/cfi_probe.c
--- linux-2.4.21-pre3/drivers/mtd/chips/cfi_probe.c	Thu Oct  4 15:14:59 2001
+++ linux-2.4.21-pre4/drivers/mtd/chips/cfi_probe.c	Tue Jan 28 19:44:30 2003
@@ -1,7 +1,7 @@
 /* 
    Common Flash Interface probe code.
    (C) 2000 Red Hat. GPL'd.
-   $Id: cfi_probe.c,v 1.66 2001/10/02 15:05:12 dwmw2 Exp $
+   $Id: cfi_probe.c,v 1.69 2002/05/11 22:13:03 dwmw2 Exp $
 */
 
 #include <linux/config.h>
@@ -24,16 +24,13 @@
 static void print_cfi_ident(struct cfi_ident *);
 #endif
 
-int cfi_jedec_setup(struct cfi_private *p_cfi, int index);
-int cfi_jedec_lookup(int index, int mfr_id, int dev_id);
-
 static int cfi_probe_chip(struct map_info *map, __u32 base,
 			  struct flchip *chips, struct cfi_private *cfi);
 static int cfi_chip_setup(struct map_info *map, struct cfi_private *cfi);
 
 struct mtd_info *cfi_probe(struct map_info *map);
 
-/* check for QRY, or search for jedec id.
+/* check for QRY.
    in: interleave,type,mode
    ret: table index, <0 for error
  */
@@ -55,6 +52,18 @@
 {
 	int i;
 	
+	if ((base + 0) >= map->size) {
+		printk(KERN_NOTICE
+			"Probe at base[0x00](0x%08lx) past the end of the map(0x%08lx)\n",
+			(unsigned long)base, map->size -1);
+		return 0;
+	}
+	if ((base + 0xff) >= map->size) {
+		printk(KERN_NOTICE
+			"Probe at base[0x55](0x%08lx) past the end of the map(0x%08lx)\n",
+			(unsigned long)base + 0x55, map->size -1);
+		return 0;
+	}
 	cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
 	cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
 
@@ -139,7 +148,7 @@
 	
 	memset(cfi->cfiq,0,sizeof(struct cfi_ident));	
 	
-	cfi->cfi_mode = 1;
+	cfi->cfi_mode = CFI_MODE_CFI;
 	cfi->fast_prog=1;		/* CFI supports fast programming */
 	
 	/* Read the CFI info structure */
@@ -250,11 +259,11 @@
 	else
 		printk("Full buffer write not supported\n");
 	
-	printk("Typical block erase timeout: %d µs\n", 1<<cfip->BlockEraseTimeoutTyp);
-	printk("Maximum block erase timeout: %d µs\n", (1<<cfip->BlockEraseTimeoutMax) * (1<<cfip->BlockEraseTimeoutTyp));
+	printk("Typical block erase timeout: %d ms\n", 1<<cfip->BlockEraseTimeoutTyp);
+	printk("Maximum block erase timeout: %d ms\n", (1<<cfip->BlockEraseTimeoutMax) * (1<<cfip->BlockEraseTimeoutTyp));
 	if (cfip->ChipEraseTimeoutTyp || cfip->ChipEraseTimeoutMax) {
-		printk("Typical chip erase timeout: %d µs\n", 1<<cfip->ChipEraseTimeoutTyp); 
-		printk("Maximum chip erase timeout: %d µs\n", (1<<cfip->ChipEraseTimeoutMax) * (1<<cfip->ChipEraseTimeoutTyp));
+		printk("Typical chip erase timeout: %d ms\n", 1<<cfip->ChipEraseTimeoutTyp); 
+		printk("Maximum chip erase timeout: %d ms\n", (1<<cfip->ChipEraseTimeoutMax) * (1<<cfip->ChipEraseTimeoutTyp));
 	}
 	else
 		printk("Chip erase not supported\n");
diff -urN linux-2.4.21-pre3/drivers/mtd/chips/chipreg.c linux-2.4.21-pre4/drivers/mtd/chips/chipreg.c
--- linux-2.4.21-pre3/drivers/mtd/chips/chipreg.c	Thu Oct  4 15:14:59 2001
+++ linux-2.4.21-pre4/drivers/mtd/chips/chipreg.c	Tue Jan 28 19:44:30 2003
@@ -1,5 +1,5 @@
 /*
- * $Id: chipreg.c,v 1.12 2001/10/02 15:29:53 dwmw2 Exp $
+ * $Id: chipreg.c,v 1.13 2002/02/21 08:26:58 dwmw2 Exp $
  *
  * Registration for chip drivers
  *
@@ -29,7 +29,7 @@
 	spin_unlock(&chip_drvs_lock);
 }
 
-static struct mtd_chip_driver *get_mtd_chip_driver (char *name)
+static struct mtd_chip_driver *get_mtd_chip_driver (const char *name)
 {
 	struct list_head *pos;
 	struct mtd_chip_driver *ret = NULL, *this;
@@ -57,7 +57,7 @@
 	/* Hide all the horrid details, like some silly person taking
 	   get_module_symbol() away from us, from the caller. */
 
-struct mtd_info *do_map_probe(char *name, struct map_info *map)
+struct mtd_info *do_map_probe(const char *name, struct map_info *map)
 {
 	struct mtd_chip_driver *drv;
 	struct mtd_info *ret;
diff -urN linux-2.4.21-pre3/drivers/mtd/chips/gen_probe.c linux-2.4.21-pre4/drivers/mtd/chips/gen_probe.c
--- linux-2.4.21-pre3/drivers/mtd/chips/gen_probe.c	Thu Oct  4 15:14:59 2001
+++ linux-2.4.21-pre4/drivers/mtd/chips/gen_probe.c	Tue Jan 28 19:44:30 2003
@@ -2,7 +2,7 @@
  * Routines common to all CFI-type probes.
  * (C) 2001, 2001 Red Hat, Inc.
  * GPL'd
- * $Id: gen_probe.c,v 1.5 2001/10/02 15:05:12 dwmw2 Exp $
+ * $Id: gen_probe.c,v 1.9 2002/09/05 05:15:32 acurtis Exp $
  */
 
 #include <linux/kernel.h>
@@ -38,7 +38,7 @@
 	if (mtd)
 		return mtd;
 
-	printk(KERN_WARNING"cfi_probe: No supported Vendor Command Set found\n");
+	printk(KERN_WARNING"gen_probe: No supported Vendor Command Set found\n");
 	
 	kfree(cfi->cfiq);
 	kfree(cfi);
@@ -106,6 +106,12 @@
 	 * Now probe for other chips, checking sensibly for aliases while
 	 * we're at it. The new_chip probe above should have let the first
 	 * chip in read mode.
+	 *
+	 * NOTE: Here, we're checking if there is room for another chip
+	 *       the same size within the mapping. Therefore, 
+	 *       base + chipsize <= map->size is the correct thing to do, 
+	 *       because, base + chipsize would be the  _first_ byte of the
+	 *       next chip, not the one we're currently pondering.
 	 */
 
 	for (base = (1<<cfi.chipshift); base + (1<<cfi.chipshift) <= map->size;
@@ -224,6 +230,41 @@
 		break;
 #endif /* CFIDEV_BUSWIDTH_4 */
 
+#ifdef CFIDEV_BUSWIDTH_8
+	case CFIDEV_BUSWIDTH_8:
+#if defined(CFIDEV_INTERLEAVE_2) && defined(SOMEONE_ACTUALLY_MAKES_THESE)
+                cfi->interleave = CFIDEV_INTERLEAVE_2;
+
+                cfi->device_type = CFI_DEVICETYPE_X32;
+		if (cp->probe_chip(map, 0, NULL, cfi))
+			return 1;
+#endif /* CFIDEV_INTERLEAVE_2 */
+#ifdef CFIDEV_INTERLEAVE_4
+		cfi->interleave = CFIDEV_INTERLEAVE_4;
+
+#ifdef SOMEONE_ACTUALLY_MAKES_THESE
+		cfi->device_type = CFI_DEVICETYPE_X32;
+		if (cp->probe_chip(map, 0, NULL, cfi))
+			return 1;
+#endif
+		cfi->device_type = CFI_DEVICETYPE_X16;
+		if (cp->probe_chip(map, 0, NULL, cfi))
+			return 1;
+#endif /* CFIDEV_INTERLEAVE_4 */
+#ifdef CFIDEV_INTERLEAVE_8
+		cfi->interleave = CFIDEV_INTERLEAVE_8;
+
+		cfi->device_type = CFI_DEVICETYPE_X16;
+		if (cp->probe_chip(map, 0, NULL, cfi))
+			return 1;
+
+		cfi->device_type = CFI_DEVICETYPE_X8;
+		if (cp->probe_chip(map, 0, NULL, cfi))
+			return 1;
+#endif /* CFIDEV_INTERLEAVE_8 */
+		break;
+#endif /* CFIDEV_BUSWIDTH_8 */
+
 	default:
 		printk(KERN_WARNING "genprobe_new_chip called with unsupported buswidth %d\n", map->buswidth);
 		return 0;
@@ -289,6 +330,10 @@
 	case 0x0002:
 		return cfi_cmdset_0002(map, primary);
 #endif
+#ifdef CONFIG_MTD_CFI_STAA
+        case 0x0020:
+		return cfi_cmdset_0020(map, primary);
+#endif
 	}
 
 	return cfi_cmdset_unknown(map, primary);
diff -urN linux-2.4.21-pre3/drivers/mtd/chips/jedec.c linux-2.4.21-pre4/drivers/mtd/chips/jedec.c
--- linux-2.4.21-pre3/drivers/mtd/chips/jedec.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.21-pre4/drivers/mtd/chips/jedec.c	Tue Jan 28 19:44:30 2003
@@ -11,7 +11,7 @@
  * not going to guess how to send commands to them, plus I expect they will
  * all speak CFI..
  *
- * $Id: jedec.c,v 1.13 2002/02/08 15:57:21 rkaiser Exp $
+ * $Id: jedec.c,v 1.14 2002/06/27 02:19:12 dwmw2 Exp $
  */
 
 #include <linux/mtd/jedec.h>
@@ -465,8 +465,8 @@
       we call this routine with the JEDEC return still enabled, if two or
       more flashes have a truncated address space the probe test will still
       work */
-   if (base + Size+0x555 < map->size &&
-       base + Size+0x555 < (base & (~(my_bank_size-1))) + my_bank_size)
+   if (base + (Size<<2)+0x555 < map->size &&
+       base + (Size<<2)+0x555 < (base & (~(my_bank_size-1))) + my_bank_size)
    {
       if (flread(base+Size) != flread(base+Size + 0x100) ||
 	  flread(base+Size + 1) != flread(base+Size + 0x101))
diff -urN linux-2.4.21-pre3/drivers/mtd/chips/jedec_probe.c linux-2.4.21-pre4/drivers/mtd/chips/jedec_probe.c
--- linux-2.4.21-pre3/drivers/mtd/chips/jedec_probe.c	Fri Nov  9 14:29:40 2001
+++ linux-2.4.21-pre4/drivers/mtd/chips/jedec_probe.c	Tue Jan 28 19:44:30 2003
@@ -1,7 +1,9 @@
 /* 
    Common Flash Interface probe code.
    (C) 2000 Red Hat. GPL'd.
-   $Id: jedec_probe.c,v 1.3 2001/10/02 15:05:12 dwmw2 Exp $
+   $Id: jedec_probe.c,v 1.19 2002/11/12 13:12:10 dwmw2 Exp $
+   See JEDEC (http://www.jedec.org/) standard JESD21C (section 3.5)
+   for the standard this probe goes back to.
 */
 
 #include <linux/config.h>
@@ -18,15 +20,17 @@
 #include <linux/mtd/cfi.h>
 #include <linux/mtd/gen_probe.h>
 
-
 /* Manufacturers */
 #define MANUFACTURER_AMD	0x0001
-#define MANUFACTURER_FUJITSU	0x0004
 #define MANUFACTURER_ATMEL	0x001f
+#define MANUFACTURER_FUJITSU	0x0004
+#define MANUFACTURER_INTEL	0x0089
+#define MANUFACTURER_MACRONIX	0x00C2
 #define MANUFACTURER_ST		0x0020
 #define MANUFACTURER_SST	0x00BF
 #define MANUFACTURER_TOSHIBA	0x0098
 
+
 /* AMD */
 #define AM29F800BB	0x2258
 #define AM29F800BT	0x22D6
@@ -34,27 +38,89 @@
 #define AM29LV800BT	0x22DA
 #define AM29LV160DT	0x22C4
 #define AM29LV160DB	0x2249
+#define AM29F017D	0x003D
+#define AM29F016	0x00AD
+#define AM29F080	0x00D5
+#define AM29F040	0x00A4
+#define AM29LV040B	0x004F
+#define AM29F032B	0x0041
 
 /* Atmel */
-#define AT49BV16X4	0x00c0
-#define AT49BV16X4T	0x00c2
+#define AT49BV512	0x0003
+#define AT29LV512	0x003d
+#define AT49BV16X	0x00C0
+#define AT49BV16XT	0x00C2
+#define AT49BV32X	0x00C8
+#define AT49BV32XT	0x00C9
 
 /* Fujitsu */
+#define MBM29LV650UE	0x22D7
+#define MBM29LV320TE	0x22F6
+#define MBM29LV320BE	0x22F9
 #define MBM29LV160TE	0x22C4
 #define MBM29LV160BE	0x2249
+#define MBM29LV800BA	0x225B
+#define MBM29LV800TA	0x22DA
+
+/* Intel */
+#define I28F004B3T	0x00d4
+#define I28F004B3B	0x00d5
+#define I28F400B3T	0x8894
+#define I28F400B3B	0x8895
+#define I28F008S5	0x00a6
+#define I28F016S5	0x00a0
+#define I28F008SA	0x00a2
+#define I28F008B3T	0x00d2
+#define I28F008B3B	0x00d3
+#define I28F800B3T	0x8892
+#define I28F800B3B	0x8893
+#define I28F016S3	0x00aa
+#define I28F016B3T	0x00d0
+#define I28F016B3B	0x00d1
+#define I28F160B3T	0x8890
+#define I28F160B3B	0x8891
+#define I28F320B3T	0x8896
+#define I28F320B3B	0x8897
+#define I28F640B3T	0x8898
+#define I28F640B3B	0x8899
+#define I82802AB	0x00ad
+#define I82802AC	0x00ac
+
+/* Macronix */
+#define MX29LV160T	0x22C4
+#define MX29LV160B	0x2249
+#define MX29F016	0x00AD
+#define MX29F004T	0x0045
+#define MX29F004B	0x0046
 
 /* ST - www.st.com */
 #define M29W800T	0x00D7
 #define M29W160DT	0x22C4
 #define M29W160DB	0x2249
+#define M29W040B	0x00E3
 
 /* SST */
+#define SST29EE512	0x005d
+#define SST29LE512	0x003d
 #define SST39LF800	0x2781
 #define SST39LF160	0x2782
+#define SST39LF512	0x00D4
+#define SST39LF010	0x00D5
+#define SST39LF020	0x00D6
+#define SST39LF040	0x00D7
+#define SST39SF010A	0x00B5
+#define SST39SF020A	0x00B6
+#define SST49LF030A	0x001C
+#define SST49LF040A	0x0051
+#define SST49LF080A	0x005B
 
 /* Toshiba */
 #define TC58FVT160	0x00C2
 #define TC58FVB160	0x0043
+#define TC58FVT321	0x009A
+#define TC58FVB321	0x009C
+#define TC58FVT641	0x0093
+#define TC58FVB641	0x0095
 
 
 struct amd_flash_info {
@@ -64,21 +130,37 @@
 	const int DevSize;
 	const int InterfaceDesc;
 	const int NumEraseRegions;
+	const int CmdSet;
 	const ulong regions[4];
 };
 
 #define ERASEINFO(size,blocks) (size<<8)|(blocks-1)
 
-#define SIZE_1MiB 20
-#define SIZE_2MiB 21
-#define SIZE_4MiB 22
+#define SIZE_64KiB  16
+#define SIZE_128KiB 17
+#define SIZE_256KiB 18
+#define SIZE_512KiB 19
+#define SIZE_1MiB   20
+#define SIZE_2MiB   21
+#define SIZE_4MiB   22
+#define SIZE_8MiB   23
 
 static const struct amd_flash_info jedec_table[] = {
 	{
 		mfr_id: MANUFACTURER_AMD,
+		dev_id: AM29F032B,
+		name: "AMD AM29F032B",
+		DevSize: SIZE_4MiB,
+		CmdSet:	P_ID_AMD_STD,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x10000,64)
+		}
+	}, {
+		mfr_id: MANUFACTURER_AMD,
 		dev_id: AM29LV160DT,
 		name: "AMD AM29LV160DT",
 		DevSize: SIZE_2MiB,
+		CmdSet:	P_ID_AMD_STD,
 		NumEraseRegions: 4,
 		regions: {ERASEINFO(0x10000,31),
 			  ERASEINFO(0x08000,1),
@@ -90,6 +172,7 @@
 		dev_id: AM29LV160DB,
 		name: "AMD AM29LV160DB",
 		DevSize: SIZE_2MiB,
+		CmdSet:	P_ID_AMD_STD,
 		NumEraseRegions: 4,
 		regions: {ERASEINFO(0x04000,1),
 			  ERASEINFO(0x02000,2),
@@ -101,6 +184,7 @@
 		dev_id: TC58FVT160,
 		name: "Toshiba TC58FVT160",
 		DevSize: SIZE_2MiB,
+		CmdSet:	P_ID_AMD_STD,
 		NumEraseRegions: 4,
 		regions: {ERASEINFO(0x10000,31),
 			  ERASEINFO(0x08000,1),
@@ -108,10 +192,92 @@
 			  ERASEINFO(0x04000,1)
 		}
 	}, {
+		mfr_id: MANUFACTURER_TOSHIBA,
+		dev_id: TC58FVB160,
+		name: "Toshiba TC58FVB160",
+		DevSize: SIZE_2MiB,
+		CmdSet:	P_ID_AMD_STD,
+		NumEraseRegions: 4,
+		regions: {ERASEINFO(0x04000,1),
+			  ERASEINFO(0x02000,2),
+			  ERASEINFO(0x08000,1),
+			  ERASEINFO(0x10000,31)
+		}
+	}, {
+		mfr_id: MANUFACTURER_TOSHIBA,
+		dev_id: TC58FVB321,
+		name: "Toshiba TC58FVB321",
+		DevSize: SIZE_4MiB,
+		CmdSet:	P_ID_AMD_STD,
+		NumEraseRegions: 2,
+		regions: {ERASEINFO(0x02000,8),
+			  ERASEINFO(0x10000,63)
+		}
+	}, {
+		mfr_id: MANUFACTURER_TOSHIBA,
+		dev_id: TC58FVT321,
+		name: "Toshiba TC58FVT321",
+		DevSize: SIZE_4MiB,
+		CmdSet:	P_ID_AMD_STD,
+		NumEraseRegions: 2,
+		regions: {ERASEINFO(0x10000,63),
+			  ERASEINFO(0x02000,8)
+		}
+	}, {
+		mfr_id: MANUFACTURER_TOSHIBA,
+		dev_id: TC58FVB641,
+		name: "Toshiba TC58FVB641",
+		DevSize: SIZE_8MiB,
+		CmdSet:	P_ID_AMD_STD,
+		NumEraseRegions: 2,
+		regions: {ERASEINFO(0x02000,8),
+			  ERASEINFO(0x10000,127)
+		}
+	}, {
+		mfr_id: MANUFACTURER_TOSHIBA,
+		dev_id: TC58FVT641,
+		name: "Toshiba TC58FVT641",
+		DevSize: SIZE_8MiB,
+		CmdSet:	P_ID_AMD_STD,
+		NumEraseRegions: 2,
+		regions: {ERASEINFO(0x10000,127),
+			  ERASEINFO(0x02000,8)
+		}
+	}, {
+		mfr_id: MANUFACTURER_FUJITSU,
+		dev_id: MBM29LV650UE,
+		name: "Fujitsu MBM29LV650UE",
+		DevSize: SIZE_8MiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x10000,128)
+		}
+	}, {
+		mfr_id: MANUFACTURER_FUJITSU,
+		dev_id: MBM29LV320TE,
+		name: "Fujitsu MBM29LV320TE",
+		DevSize: SIZE_4MiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 2,
+		regions: {ERASEINFO(0x10000,63),
+			  ERASEINFO(0x02000,8)
+		}
+	}, {
+		mfr_id: MANUFACTURER_FUJITSU,
+		dev_id: MBM29LV320BE,
+		name: "Fujitsu MBM29LV320BE",
+		DevSize: SIZE_4MiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 2,
+		regions: {ERASEINFO(0x02000,8),
+			  ERASEINFO(0x10000,63)
+		}
+	}, {
 		mfr_id: MANUFACTURER_FUJITSU,
 		dev_id: MBM29LV160TE,
 		name: "Fujitsu MBM29LV160TE",
 		DevSize: SIZE_2MiB,
+		CmdSet:	P_ID_AMD_STD,
 		NumEraseRegions: 4,
 		regions: {ERASEINFO(0x10000,31),
 			  ERASEINFO(0x08000,1),
@@ -119,10 +285,11 @@
 			  ERASEINFO(0x04000,1)
 		}
 	}, {
-		mfr_id: MANUFACTURER_TOSHIBA,
-		dev_id: TC58FVB160,
-		name: "Toshiba TC58FVB160",
+		mfr_id: MANUFACTURER_FUJITSU,
+		dev_id: MBM29LV160BE,
+		name: "Fujitsu MBM29LV160BE",
 		DevSize: SIZE_2MiB,
+		CmdSet:	P_ID_AMD_STD,
 		NumEraseRegions: 4,
 		regions: {ERASEINFO(0x04000,1),
 			  ERASEINFO(0x02000,2),
@@ -131,20 +298,34 @@
 		}
 	}, {
 		mfr_id: MANUFACTURER_FUJITSU,
-		dev_id: MBM29LV160BE,
-		name: "Fujitsu MBM29LV160BE",
-		DevSize: SIZE_2MiB,
+		dev_id: MBM29LV800BA,
+		name: "Fujitsu MBM29LV800BA",
+		DevSize: SIZE_1MiB,
+		CmdSet:	P_ID_AMD_STD,
 		NumEraseRegions: 4,
 		regions: {ERASEINFO(0x04000,1),
 			  ERASEINFO(0x02000,2),
 			  ERASEINFO(0x08000,1),
-			  ERASEINFO(0x10000,31)
+			  ERASEINFO(0x10000,15)
+		}
+	}, {
+		mfr_id: MANUFACTURER_FUJITSU,
+		dev_id: MBM29LV800TA,
+		name: "Fujitsu MBM29LV800TA",
+		DevSize: SIZE_1MiB,
+		CmdSet:	P_ID_AMD_STD,
+		NumEraseRegions: 4,
+		regions: {ERASEINFO(0x10000,15),
+ 			  ERASEINFO(0x08000,1),
+ 			  ERASEINFO(0x02000,2),
+ 			  ERASEINFO(0x04000,1)
 		}
 	}, {
 		mfr_id: MANUFACTURER_AMD,
 		dev_id: AM29LV800BB,
 		name: "AMD AM29LV800BB",
 		DevSize: SIZE_1MiB,
+		CmdSet:	P_ID_AMD_STD,
 		NumEraseRegions: 4,
 		regions: {ERASEINFO(0x04000,1),
 			  ERASEINFO(0x02000,2),
@@ -156,6 +337,7 @@
 		dev_id: AM29F800BB,
 		name: "AMD AM29F800BB",
 		DevSize: SIZE_1MiB,
+		CmdSet:	P_ID_AMD_STD,
 		NumEraseRegions: 4,
 		regions: {ERASEINFO(0x04000,1),
 			  ERASEINFO(0x02000,2),
@@ -167,6 +349,7 @@
 		dev_id: AM29LV800BT,
 		name: "AMD AM29LV800BT",
 		DevSize: SIZE_1MiB,
+		CmdSet:	P_ID_AMD_STD,
 		NumEraseRegions: 4,
 		regions: {ERASEINFO(0x10000,15),
 			  ERASEINFO(0x08000,1),
@@ -178,6 +361,7 @@
 		dev_id: AM29F800BT,
 		name: "AMD AM29F800BT",
 		DevSize: SIZE_1MiB,
+		CmdSet:	P_ID_AMD_STD,
 		NumEraseRegions: 4,
 		regions: {ERASEINFO(0x10000,15),
 			  ERASEINFO(0x08000,1),
@@ -189,6 +373,7 @@
 		dev_id: AM29LV800BB,
 		name: "AMD AM29LV800BB",
 		DevSize: SIZE_1MiB,
+		CmdSet:	P_ID_AMD_STD,
 		NumEraseRegions: 4,
 		regions: {ERASEINFO(0x10000,15),
 			  ERASEINFO(0x08000,1),
@@ -196,10 +381,243 @@
 			  ERASEINFO(0x04000,1)
 		}
 	}, {
+		mfr_id:			MANUFACTURER_INTEL,
+		dev_id:			I28F004B3B,
+		name:			"Intel 28F004B3B",
+		DevSize:		SIZE_512KiB,
+		CmdSet:			P_ID_INTEL_STD,
+		NumEraseRegions:	2,
+		regions: {
+			ERASEINFO(0x02000, 8),
+			ERASEINFO(0x10000, 7),
+		}
+	}, {
+		mfr_id:			MANUFACTURER_INTEL,
+		dev_id:			I28F004B3T,
+		name:			"Intel 28F004B3T",
+		DevSize:		SIZE_512KiB,
+		CmdSet:			P_ID_INTEL_STD,
+		NumEraseRegions:	2,
+		regions: {
+			ERASEINFO(0x10000, 7),
+			ERASEINFO(0x02000, 8),
+		}
+	}, {
+		mfr_id:			MANUFACTURER_INTEL,
+		dev_id:			I28F400B3B,
+		name:			"Intel 28F400B3B",
+		DevSize:		SIZE_512KiB,
+		CmdSet:			P_ID_INTEL_STD,
+		NumEraseRegions:	2,
+		regions: {
+			ERASEINFO(0x02000, 8),
+			ERASEINFO(0x10000, 7),
+		}
+	}, {
+		mfr_id:			MANUFACTURER_INTEL,
+		dev_id:			I28F400B3T,
+		name:			"Intel 28F400B3T",
+		DevSize:		SIZE_512KiB,
+		CmdSet:			P_ID_INTEL_STD,
+		NumEraseRegions:	2,
+		regions: {
+			ERASEINFO(0x10000, 7),
+			ERASEINFO(0x02000, 8),
+		}
+	}, {
+		mfr_id:			MANUFACTURER_INTEL,
+		dev_id:			I28F008B3B,
+		name:			"Intel 28F008B3B",
+		DevSize:		SIZE_1MiB,
+		CmdSet:			P_ID_INTEL_STD,
+		NumEraseRegions:	2,
+		regions: {
+			ERASEINFO(0x02000, 8),
+			ERASEINFO(0x10000, 15),
+		}
+	}, {
+		mfr_id:			MANUFACTURER_INTEL,
+		dev_id:			I28F008B3T,
+		name:			"Intel 28F008B3T",
+		DevSize:		SIZE_1MiB,
+		CmdSet:			P_ID_INTEL_STD,
+		NumEraseRegions:	2,
+		regions: {
+			ERASEINFO(0x10000, 15),
+			ERASEINFO(0x02000, 8),
+		}
+	}, {
+		mfr_id: MANUFACTURER_INTEL,
+		dev_id: I28F008S5,
+		name: "Intel 28F008S5",
+		DevSize: SIZE_1MiB,
+		CmdSet: P_ID_INTEL_EXT,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x10000,16),
+		}
+	}, {
+		mfr_id: MANUFACTURER_INTEL,
+		dev_id: I28F016S5,
+		name: "Intel 28F016S5",
+		DevSize: SIZE_2MiB,
+		CmdSet: P_ID_INTEL_EXT,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x10000,32),
+		}
+	}, {
+		mfr_id:			MANUFACTURER_INTEL,
+		dev_id:			I28F008SA,
+		name:			"Intel 28F008SA",
+		DevSize:		SIZE_1MiB,
+		CmdSet:			P_ID_INTEL_STD,
+		NumEraseRegions:	1,
+		regions: {
+			ERASEINFO(0x10000, 16),
+		}
+	}, {
+		mfr_id:			MANUFACTURER_INTEL,
+		dev_id:			I28F800B3B,
+		name:			"Intel 28F800B3B",
+		DevSize:		SIZE_1MiB,
+		CmdSet:			P_ID_INTEL_STD,
+		NumEraseRegions:	2,
+		regions: {
+			ERASEINFO(0x02000, 8),
+			ERASEINFO(0x10000, 15),
+		}
+	}, {
+		mfr_id:			MANUFACTURER_INTEL,
+		dev_id:			I28F800B3T,
+		name:			"Intel 28F800B3T",
+		DevSize:		SIZE_1MiB,
+		CmdSet:			P_ID_INTEL_STD,
+		NumEraseRegions:	2,
+		regions: {
+			ERASEINFO(0x10000, 15),
+			ERASEINFO(0x02000, 8),
+		}
+	}, {
+		mfr_id:			MANUFACTURER_INTEL,
+		dev_id:			I28F016B3B,
+		name:			"Intel 28F016B3B",
+		DevSize:		SIZE_2MiB,
+		CmdSet:			P_ID_INTEL_STD,
+		NumEraseRegions:	2,
+		regions: {
+			ERASEINFO(0x02000, 8),
+			ERASEINFO(0x10000, 31),
+		}
+	}, {
+		mfr_id:			MANUFACTURER_INTEL,
+		dev_id:			I28F016S3,
+		name:			"Intel I28F016S3",
+		DevSize:		SIZE_2MiB,
+		CmdSet:			P_ID_INTEL_STD,
+		NumEraseRegions:	1,
+		regions: {
+			ERASEINFO(0x10000, 32),
+		}
+	}, {
+		mfr_id:			MANUFACTURER_INTEL,
+		dev_id:			I28F016B3T,
+		name:			"Intel 28F016B3T",
+		DevSize:		SIZE_2MiB,
+		CmdSet:			P_ID_INTEL_STD,
+		NumEraseRegions:	2,
+		regions: {
+			ERASEINFO(0x10000, 31),
+			ERASEINFO(0x02000, 8),
+		}
+	}, {
+		mfr_id:			MANUFACTURER_INTEL,
+		dev_id:			I28F160B3B,
+		name:			"Intel 28F160B3B",
+		DevSize:		SIZE_2MiB,
+		CmdSet:			P_ID_INTEL_STD,
+		NumEraseRegions:	2,
+		regions: {
+			ERASEINFO(0x02000, 8),
+			ERASEINFO(0x10000, 31),
+		}
+	}, {
+		mfr_id:			MANUFACTURER_INTEL,
+		dev_id:			I28F160B3T,
+		name:			"Intel 28F160B3T",
+		DevSize:		SIZE_2MiB,
+		CmdSet:			P_ID_INTEL_STD,
+		NumEraseRegions:	2,
+		regions: {
+			ERASEINFO(0x10000, 31),
+			ERASEINFO(0x02000, 8),
+		}
+	}, {
+		mfr_id:			MANUFACTURER_INTEL,
+		dev_id:			I28F320B3B,
+		name:			"Intel 28F320B3B",
+		DevSize:		SIZE_4MiB,
+		CmdSet:			P_ID_INTEL_STD,
+		NumEraseRegions:	2,
+		regions: {
+			ERASEINFO(0x02000, 8),
+			ERASEINFO(0x10000, 63),
+		}
+	}, {
+		mfr_id:			MANUFACTURER_INTEL,
+		dev_id:			I28F320B3T,
+		name:			"Intel 28F320B3T",
+		DevSize:		SIZE_4MiB,
+		CmdSet:			P_ID_INTEL_STD,
+		NumEraseRegions:	2,
+		regions: {
+			ERASEINFO(0x10000, 63),
+			ERASEINFO(0x02000, 8),
+		}
+	}, {
+		mfr_id:			MANUFACTURER_INTEL,
+		dev_id:			I28F640B3B,
+		name:			"Intel 28F640B3B",
+		DevSize:		SIZE_8MiB,
+		CmdSet:			P_ID_INTEL_STD,
+		NumEraseRegions:	2,
+		regions: {
+			ERASEINFO(0x02000, 8),
+			ERASEINFO(0x10000, 127),
+		}
+	}, {
+		mfr_id:			MANUFACTURER_INTEL,
+		dev_id:			I28F640B3T,
+		name:			"Intel 28F640B3T",
+		DevSize:		SIZE_8MiB,
+		CmdSet:			P_ID_INTEL_STD,
+		NumEraseRegions:	2,
+		regions: {
+			ERASEINFO(0x10000, 127),
+			ERASEINFO(0x02000, 8),
+		}
+	}, {
+		mfr_id: MANUFACTURER_INTEL,
+		dev_id: I82802AB,
+		name: "Intel 82802AB",
+		DevSize: SIZE_512KiB,
+		CmdSet: P_ID_INTEL_EXT,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x10000,8),
+		}
+	}, {
+		mfr_id: MANUFACTURER_INTEL,
+		dev_id: I82802AC,
+		name: "Intel 82802AC",
+		DevSize: SIZE_1MiB,
+		CmdSet: P_ID_INTEL_EXT,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x10000,16),
+		}
+	}, {
 		mfr_id: MANUFACTURER_ST,
 		dev_id: M29W800T,
 		name: "ST M29W800T",
 		DevSize: SIZE_1MiB,
+		CmdSet:	P_ID_AMD_STD,
 		NumEraseRegions: 4,
 		regions: {ERASEINFO(0x10000,15),
 			  ERASEINFO(0x08000,1),
@@ -211,6 +629,7 @@
 		dev_id: M29W160DT,
 		name: "ST M29W160DT",
 		DevSize: SIZE_2MiB,
+		CmdSet:	P_ID_AMD_STD,
 		NumEraseRegions: 4,
 		regions: {ERASEINFO(0x10000,31),
 			  ERASEINFO(0x08000,1),
@@ -222,6 +641,7 @@
 		dev_id: M29W160DB,
 		name: "ST M29W160DB",
 		DevSize: SIZE_2MiB,
+		CmdSet:	P_ID_AMD_STD,
 		NumEraseRegions: 4,
 		regions: {ERASEINFO(0x04000,1),
 			  ERASEINFO(0x02000,2),
@@ -230,24 +650,256 @@
 		}
 	}, {
 		mfr_id: MANUFACTURER_ATMEL,
-		dev_id: AT49BV16X4,
-		name: "Atmel AT49BV16X4",
+		dev_id: AT49BV512,
+		name: "Atmel AT49BV512",
+		DevSize: SIZE_64KiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x10000,1)
+		}
+	}, {
+		mfr_id: MANUFACTURER_ATMEL,
+		dev_id: AT29LV512,
+		name: "Atmel AT29LV512",
+		DevSize: SIZE_64KiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 1,
+		regions: {
+			ERASEINFO(0x80,256),
+			ERASEINFO(0x80,256)
+		}
+	}, {
+		mfr_id: MANUFACTURER_ATMEL,
+		dev_id: AT49BV16X,
+		name: "Atmel AT49BV16X",
+		DevSize: SIZE_2MiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 2,
+		regions: {ERASEINFO(0x02000,8),
+			  ERASEINFO(0x10000,31)
+		}
+	}, {
+		mfr_id: MANUFACTURER_ATMEL,
+		dev_id: AT49BV16XT,
+		name: "Atmel AT49BV16XT",
 		DevSize: SIZE_2MiB,
-		NumEraseRegions: 3,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 2,
+		regions: {ERASEINFO(0x10000,31),
+			  ERASEINFO(0x02000,8)
+		}
+	}, {
+		mfr_id: MANUFACTURER_ATMEL,
+		dev_id: AT49BV32X,
+		name: "Atmel AT49BV32X",
+		DevSize: SIZE_4MiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 2,
 		regions: {ERASEINFO(0x02000,8),
-			  ERASEINFO(0x08000,2),
-			  ERASEINFO(0x10000,30)
+			  ERASEINFO(0x10000,63)
 		}
 	}, {
-                mfr_id: MANUFACTURER_ATMEL,
-                dev_id: AT49BV16X4T,
-                name: "Atmel AT49BV16X4T",
-                DevSize: SIZE_2MiB,
-                NumEraseRegions: 3,
-                regions: {ERASEINFO(0x10000,30),
-                          ERASEINFO(0x08000,2),
+		mfr_id: MANUFACTURER_ATMEL,
+		dev_id: AT49BV32XT,
+		name: "Atmel AT49BV32XT",
+		DevSize: SIZE_4MiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 2,
+		regions: {ERASEINFO(0x10000,63),
 			  ERASEINFO(0x02000,8)
-                }
+		}
+	}, {
+		mfr_id: MANUFACTURER_AMD,
+		dev_id: AM29F017D,
+		name: "AMD AM29F017D",
+		DevSize: SIZE_2MiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x10000,32),
+		}
+	}, {
+		mfr_id: MANUFACTURER_AMD,
+		dev_id: AM29F016,
+		name: "AMD AM29F016",
+		DevSize: SIZE_2MiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x10000,32),
+		}
+	}, {
+		mfr_id: MANUFACTURER_AMD,
+		dev_id: AM29F080,
+		name: "AMD AM29F080",
+		DevSize: SIZE_1MiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x10000,16),
+		}
+	}, {
+		mfr_id: MANUFACTURER_AMD,
+		dev_id: AM29F040,
+		name: "AMD AM29F040",
+		DevSize: SIZE_512KiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x10000,8),
+		}
+	}, {
+		mfr_id: MANUFACTURER_AMD,
+		dev_id: AM29LV040B,
+		name: "AMD AM29LV040B",
+		DevSize: SIZE_512KiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x10000,8),
+		}
+        }, {
+		mfr_id: MANUFACTURER_ST,
+		dev_id: M29W040B,
+		name: "ST M29W040B",
+		DevSize: SIZE_512KiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x10000,8),
+		}
+	}, {
+		mfr_id: MANUFACTURER_MACRONIX,
+		dev_id: MX29LV160T,
+		name: "MXIC MX29LV160T",
+		DevSize: SIZE_2MiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 4,
+		regions: {ERASEINFO(0x10000,31),
+			  ERASEINFO(0x08000,1),
+			  ERASEINFO(0x02000,2),
+			  ERASEINFO(0x04000,1)
+		}
+	}, {
+		mfr_id: MANUFACTURER_MACRONIX,
+		dev_id: MX29LV160B,
+		name: "MXIC MX29LV160B",
+		DevSize: SIZE_2MiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 4,
+		regions: {ERASEINFO(0x04000,1),
+			  ERASEINFO(0x02000,2),
+			  ERASEINFO(0x08000,1),
+			  ERASEINFO(0x10000,31)
+		}
+	}, {
+		mfr_id: MANUFACTURER_MACRONIX,
+		dev_id: MX29F016,
+		name: "Macronix MX29F016",
+		DevSize: SIZE_2MiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x10000,32),
+		}
+        }, {
+		mfr_id: MANUFACTURER_MACRONIX,
+		dev_id: MX29F004T,
+		name: "Macronix MX29F004T",
+		DevSize: SIZE_512KiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 4,
+		regions: {ERASEINFO(0x10000,7),
+			  ERASEINFO(0x08000,1),
+			  ERASEINFO(0x02000,2),
+			  ERASEINFO(0x04000,1),
+		}
+        }, {
+		mfr_id: MANUFACTURER_MACRONIX,
+		dev_id: MX29F004B,
+		name: "Macronix MX29F004B",
+		DevSize: SIZE_512KiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 4,
+		regions: {ERASEINFO(0x04000,1),
+			  ERASEINFO(0x02000,2),
+			  ERASEINFO(0x08000,1),
+			  ERASEINFO(0x10000,7),
+		}
+        }, {
+		mfr_id: MANUFACTURER_SST,
+		dev_id: SST39LF512,
+		name: "SST 39LF512",
+		DevSize: SIZE_64KiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x01000,16),
+		}
+        }, {
+		mfr_id: MANUFACTURER_SST,
+		dev_id: SST39LF010,
+		name: "SST 39LF010",
+		DevSize: SIZE_128KiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x01000,32),
+		}
+        }, {
+		mfr_id: MANUFACTURER_SST,
+		dev_id: SST39LF020,
+		name: "SST 39LF020",
+		DevSize: SIZE_256KiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x01000,64),
+		}
+        }, {
+		mfr_id: MANUFACTURER_SST,
+		dev_id: SST39LF040,
+		name: "SST 39LF040",
+		DevSize: SIZE_512KiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x01000,128),
+		}
+        }, {
+		mfr_id: MANUFACTURER_SST,
+		dev_id: SST39SF010A,
+		name: "SST 39SF010A",
+		DevSize: SIZE_128KiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x01000,32),
+		}
+        }, {
+		mfr_id: MANUFACTURER_SST,
+		dev_id: SST39SF020A,
+		name: "SST 39SF020A",
+		DevSize: SIZE_256KiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x01000,64),
+		}
+	}, {
+		mfr_id: MANUFACTURER_SST,
+		dev_id: SST49LF030A,
+		name: "SST 49LF030A",
+		DevSize: SIZE_512KiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x01000,96),
+		}
+	}, {
+		mfr_id: MANUFACTURER_SST,
+		dev_id: SST49LF040A,
+		name: "SST 49LF040A",
+		DevSize: SIZE_512KiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x01000,128),
+		}
+	}, {
+		mfr_id: MANUFACTURER_SST,
+		dev_id: SST49LF080A,
+		name: "SST 49LF080A",
+		DevSize: SIZE_1MiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x01000,256),
+		}
 	} 
 };
 
@@ -258,9 +910,42 @@
 			    struct flchip *chips, struct cfi_private *cfi);
 
 struct mtd_info *jedec_probe(struct map_info *map);
-#define jedec_read_mfr(map, base, osf) cfi_read(map, base)
-#define jedec_read_id(map, base, osf) cfi_read(map, (base)+(osf))
 
+static inline u32 jedec_read_mfr(struct map_info *map, __u32 base, 
+	struct cfi_private *cfi)
+{
+	u32 result, mask;
+	mask = (1 << (cfi->device_type * 8)) -1;
+	result = cfi_read(map, base);
+	result &= mask;
+	return result;
+}
+
+static inline u32 jedec_read_id(struct map_info *map, __u32 base, 
+	struct cfi_private *cfi)
+{
+	int osf;
+	u32 result, mask;
+	osf = cfi->interleave *cfi->device_type;
+	mask = (1 << (cfi->device_type * 8)) -1;
+	result = cfi_read(map, base + osf);
+	result &= mask;
+	return result;
+}
+
+static inline void jedec_reset(u32 base, struct map_info *map, 
+	struct cfi_private *cfi)
+{
+	/* Reset */
+	cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
+	/* Some misdesigned intel chips do not respond for 0xF0 for a reset,
+	 * so ensure we're in read mode.  Send both the Intel and the AMD command
+	 * for this.  Intel uses 0xff for this, AMD uses 0xff for NOP, so
+	 * this should be safe.
+	 */ 
+	cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
+
+}
 static int cfi_jedec_setup(struct cfi_private *p_cfi, int index)
 {
 	int i,num_erase_regions;
@@ -276,14 +961,16 @@
 	}
 
 	memset(p_cfi->cfiq,0,sizeof(struct cfi_ident));	
-	
-	p_cfi->cfiq->P_ID = P_ID_AMD_STD;
+
+	p_cfi->cfiq->P_ID = jedec_table[index].CmdSet;
 	p_cfi->cfiq->NumEraseRegions = jedec_table[index].NumEraseRegions;
 	p_cfi->cfiq->DevSize = jedec_table[index].DevSize;
+	p_cfi->cfi_mode = CFI_MODE_JEDEC;
 
 	for (i=0; i<num_erase_regions; i++){
 		p_cfi->cfiq->EraseRegionInfo[i] = jedec_table[index].regions[i];
-	}	
+	}
+	p_cfi->cmdset_priv = 0;
 	return 1; 	/* ok */
 }
 
@@ -291,8 +978,7 @@
 			      struct flchip *chips, struct cfi_private *cfi)
 {
 	int i;
-	int osf = cfi->interleave * cfi->device_type;
-	int retried = 0;
+	int unlockpass = 0;
 
 	if (!cfi->numchips) {
 		switch (cfi->device_type) {
@@ -320,48 +1006,94 @@
 	}
 
  retry:
+	/* Make certain we aren't probing past the end of map */
+	if (base >= map->size) {
+		printk(KERN_NOTICE
+			"Probe at base(0x%08x) past the end of the map(0x%08lx)\n",
+			base, map->size -1);
+		return 0;
+		
+	}
+	if ((base + cfi->addr_unlock1) >= map->size) {
+		printk(KERN_NOTICE
+			"Probe at addr_unlock1(0x%08x + 0x%08x) past the end of the map(0x%08lx)\n",
+			base, cfi->addr_unlock1, map->size -1);
+
+		return 0;
+	}
+	if ((base + cfi->addr_unlock2) >= map->size) {
+		printk(KERN_NOTICE
+			"Probe at addr_unlock2(0x%08x + 0x%08x) past the end of the map(0x%08lx)\n",
+			base, cfi->addr_unlock2, map->size -1);
+		return 0;
+		
+	}
+
 	/* Reset */
-	cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
+	jedec_reset(base, map, cfi);
 
 	/* Autoselect Mode */
-	cfi_send_gen_cmd(0xaa, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL);
-	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, CFI_DEVICETYPE_X8, NULL);
+	if(cfi->addr_unlock1) {
+		cfi_send_gen_cmd(0xaa, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL);
+		cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, CFI_DEVICETYPE_X8, NULL);
+	}
 	cfi_send_gen_cmd(0x90, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL);
 
 	if (!cfi->numchips) {
 		/* This is the first time we're called. Set up the CFI 
 		   stuff accordingly and return */
 		
-		cfi->mfr = jedec_read_mfr(map, base, osf);
-		cfi->id = jedec_read_id(map, base, osf);
-		
+		cfi->mfr = jedec_read_mfr(map, base, cfi);
+		cfi->id = jedec_read_id(map, base, cfi);
+		printk(KERN_INFO "Search for id:(%02x %02x) interleave(%d) type(%d)\n", 
+			cfi->mfr, cfi->id, cfi->interleave, cfi->device_type);
 		for (i=0; i<sizeof(jedec_table)/sizeof(jedec_table[0]); i++) {
 			if (cfi->mfr == jedec_table[i].mfr_id &&
-			    cfi->id == jedec_table[i].dev_id)
-				return cfi_jedec_setup(cfi, i);
+			    cfi->id == jedec_table[i].dev_id) {
+				if (!cfi_jedec_setup(cfi, i))
+					return 0;
+				goto ok_out;
+			}
 		}
-		if (!retried++) {
-			/* Deal with whichever strange chips these were */
-			cfi->addr_unlock1 |= cfi->addr_unlock1 << 8;
-			cfi->addr_unlock2 |= cfi->addr_unlock2 << 8;
+		switch(unlockpass++) {
+		case 0:
+			cfi->addr_unlock1 |= cfi->addr_unlock1 << 4;
+			cfi->addr_unlock2 |= cfi->addr_unlock2 << 4;
+			goto retry;
+		case 1:
+			cfi->addr_unlock1 = cfi->addr_unlock2 = 0;
 			goto retry;
 		}
 		return 0;
+	} else {
+		__u16 mfr;
+		__u16 id;
+
+		/* Make sure it is a chip of the same manufacturer and id */
+		mfr = jedec_read_mfr(map, base, cfi);
+		id = jedec_read_id(map, base, cfi);
+
+		if ((mfr != cfi->mfr) || (id != cfi->id)) {
+			printk(KERN_DEBUG "%s: Found different chip or no chip at all (mfr 0x%x, id 0x%x) at 0x%x\n",
+			       map->name, mfr, id, base);
+			jedec_reset(base, map, cfi);
+			return 0;
+		}
 	}
 	
 	/* Check each previous chip to see if it's an alias */
 	for (i=0; i<cfi->numchips; i++) {
 		/* This chip should be in read mode if it's one
 		   we've already touched. */
-		if (jedec_read_mfr(map, base, osf) == cfi->mfr &&
-		    jedec_read_id(map, base, osf) == cfi->id) {
+		if (jedec_read_mfr(map, chips[i].start, cfi) == cfi->mfr &&
+		    jedec_read_id(map, chips[i].start, cfi) == cfi->id) {
 			/* Eep. This chip also looks like it's in autoselect mode.
 			   Is it an alias for the new one? */
-			
-			cfi_send_gen_cmd(0xF0, 0, chips[i].start, map, cfi, cfi->device_type, NULL);
+			jedec_reset(chips[i].start, map, cfi);
+
 			/* If the device IDs go away, it's an alias */
-			if (jedec_read_mfr(map, base, osf) != cfi->mfr ||
-			    jedec_read_id(map, base, osf) != cfi->id) {
+			if (jedec_read_mfr(map, base, cfi) != cfi->mfr ||
+			    jedec_read_id(map, base, cfi) != cfi->id) {
 				printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n",
 				       map->name, base, chips[i].start);
 				return 0;
@@ -371,9 +1103,9 @@
 			 * unfortunate. Stick the new chip in read mode
 			 * too and if it's the same, assume it's an alias. */
 			/* FIXME: Use other modes to do a proper check */
-			cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
-			if (jedec_read_mfr(map, base, osf) == cfi->mfr &&
-			    jedec_read_id(map, base, osf) == cfi->id) {
+			jedec_reset(base, map, cfi);
+			if (jedec_read_mfr(map, base, cfi) == cfi->mfr &&
+			    jedec_read_id(map, base, cfi) == cfi->id) {
 				printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n",
 				       map->name, base, chips[i].start);
 				return 0;
@@ -392,8 +1124,9 @@
 	chips[cfi->numchips].state = FL_READY;
 	cfi->numchips++;
 		
+ok_out:
 	/* Put it back into Read Mode */
-	cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
+	jedec_reset(base, map, cfi);
 
 	printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit mode\n",
 	       map->name, cfi->interleave, cfi->device_type*8, base, 
diff -urN linux-2.4.21-pre3/drivers/mtd/chips/sharp.c linux-2.4.21-pre4/drivers/mtd/chips/sharp.c
--- linux-2.4.21-pre3/drivers/mtd/chips/sharp.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.21-pre4/drivers/mtd/chips/sharp.c	Tue Jan 28 19:44:30 2003
@@ -4,7 +4,7 @@
  * Copyright 2000,2001 David A. Schleef <ds@schleef.org>
  *           2000,2001 Lineo, Inc.
  *
- * $Id: sharp.c,v 1.7 2002/02/13 15:49:07 dwmw2 Exp $
+ * $Id: sharp.c,v 1.8 2002/05/17 08:59:19 dwmw2 Exp $
  *
  * Devices supported:
  *   LH28F016SCT Symmetrical block flash memory, 2Mx8
@@ -421,6 +421,7 @@
 		}
 	}
 
+	instr->state = MTD_ERASE_DONE;
 	if(instr->callback)
 		instr->callback(instr);
 
diff -urN linux-2.4.21-pre3/drivers/mtd/cmdlinepart.c linux-2.4.21-pre4/drivers/mtd/cmdlinepart.c
--- linux-2.4.21-pre3/drivers/mtd/cmdlinepart.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/drivers/mtd/cmdlinepart.c	Tue Jan 28 19:44:30 2003
@@ -0,0 +1,356 @@
+/*
+ * $Id: cmdlinepart.c,v 1.6 2002/11/16 01:37:39 dneuer Exp $
+ *
+ * Read flash partition table from command line
+ *
+ * Copyright 2002 SYSGO Real-Time Solutions GmbH
+ *
+ * The format for the command line is as follows:
+ * 
+ * mtdparts=<mtddef>[;<mtddef]
+ * <mtddef>  := <mtd-id>:<partdef>[,<partdef>]
+ * <partdef> := <size>[@offset][<name>][ro]
+ * <mtd-id>  := unique id used in mapping driver/device
+ * <size>    := standard linux memsize OR "-" to denote all remaining space
+ * <name>    := '(' NAME ')'
+ * 
+ * Examples:
+ * 
+ * 1 NOR Flash, with 1 single writable partition:
+ * edb7312-nor:-
+ * 
+ * 1 NOR Flash with 2 partitions, 1 NAND with one
+ * edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home)
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <asm/setup.h>
+#include <linux/bootmem.h>
+
+/* error message prefix */
+#define ERRP "mtd: "
+
+/* debug macro */
+#if 0
+#define dbg(x) do { printk("DEBUG-CMDLINE-PART: "); printk x; } while(0)
+#else
+#define dbg(x)
+#endif
+
+
+/* special size referring to all the remaining space in a partition */
+#define SIZE_REMAINING 0xffffffff
+
+struct cmdline_mtd_partition {
+	struct cmdline_mtd_partition *next;
+	char *mtd_id;
+	int num_parts;
+	struct mtd_partition *parts;
+};
+
+/* mtdpart_setup() parses into here */
+static struct cmdline_mtd_partition *partitions;
+
+/* the command line passed to mtdpart_setupd() */
+static char *cmdline;
+static int cmdline_parsed = 0;
+
+/*
+ * Parse one partition definition for an MTD. Since there can be many
+ * comma separated partition definitions, this function calls itself 
+ * recursively until no more partition definitions are found. Nice side
+ * effect: the memory to keep the mtd_partition structs and the names
+ * is allocated upon the last definition being found. At that point the
+ * syntax has been verified ok.
+ */
+static struct mtd_partition * newpart(char *s, 
+                                      char **retptr,
+                                      int *num_parts,
+                                      int this_part, 
+                                      unsigned char **extra_mem_ptr, 
+                                      int extra_mem_size)
+{
+	struct mtd_partition *parts;
+	unsigned long size;
+	unsigned long offset = 0;
+	char *name;
+	int name_len;
+	unsigned char *extra_mem;
+	char delim;
+	unsigned int mask_flags;
+
+	/* fetch the partition size */
+	if (*s == '-')
+	{	/* assign all remaining space to this partition */
+		size = SIZE_REMAINING;
+		s++;
+	}
+	else
+	{
+		size = memparse(s, &s);
+		if (size < PAGE_SIZE)
+		{
+			printk(KERN_ERR ERRP "partition size too small (%lx)\n", size);
+			return 0;
+		}
+	}
+
+	/* fetch partition name and flags */
+	mask_flags = 0; /* this is going to be a regular partition */
+	delim = 0;
+        /* check for offset */
+        if (*s == '@') 
+	{
+                s++;
+                offset = memparse(s, &s);
+        }
+        /* now look for name */
+	if (*s == '(')
+	{
+		delim = ')';
+	}
+		
+	if (delim)
+	{
+		char *p;
+
+	    	name = ++s;
+		if ((p = strchr(name, delim)) == 0)
+		{
+			printk(KERN_ERR ERRP "no closing %c found in partition name\n", delim);
+			return 0;
+		}
+		name_len = p - name;
+		s = p + 1;
+	}
+	else
+	{
+	    	name = NULL;
+		name_len = 13; /* Partition_000 */
+	}
+   
+	/* record name length for memory allocation later */
+	extra_mem_size += name_len + 1;
+
+        /* test for options */
+        if (strncmp(s, "ro", 2) == 0) 
+	{
+		mask_flags |= MTD_WRITEABLE;
+		s += 2;
+        }
+
+	/* test if more partitions are following */
+	if (*s == ',')
+	{
+		if (size == SIZE_REMAINING)
+		{
+			printk(KERN_ERR ERRP "no partitions allowed after a fill-up partition\n");
+			return 0;
+		}
+		/* more partitions follow, parse them */
+		if ((parts = newpart(s + 1, &s, num_parts, 
+		                     this_part + 1, &extra_mem, extra_mem_size)) == 0)
+		  return 0;
+	}
+	else
+	{	/* this is the last partition: allocate space for all */
+		int alloc_size;
+
+		*num_parts = this_part + 1;
+		alloc_size = *num_parts * sizeof(struct mtd_partition) +
+			     extra_mem_size;
+		parts = kmalloc(alloc_size, GFP_KERNEL);
+		if (!parts)
+		{
+			printk(KERN_ERR ERRP "out of memory\n");
+			return 0;
+		}
+		memset(parts, 0, alloc_size);
+		extra_mem = (unsigned char *)(parts + *num_parts);
+	}
+	/* enter this partition (offset will be calculated later if it is zero at this point) */
+	parts[this_part].size = size;
+	parts[this_part].offset = offset;
+	parts[this_part].mask_flags = mask_flags;
+	if (name)
+	{
+		strncpy(extra_mem, name, name_len);
+		extra_mem[name_len] = 0;
+	}
+	else
+	{
+		sprintf(extra_mem, "Partition_%03d", this_part);
+	}
+	parts[this_part].name = extra_mem;
+	extra_mem += name_len + 1;
+
+	dbg(("partition %d: name <%s>, offset %x, size %x, mask flags %x\n",
+	     this_part, 
+	     parts[this_part].name,
+	     parts[this_part].offset,
+	     parts[this_part].size,
+	     parts[this_part].mask_flags));
+
+	/* return (updated) pointer to extra_mem memory */
+	if (extra_mem_ptr)
+	  *extra_mem_ptr = extra_mem;
+
+	/* return (updated) pointer command line string */
+	*retptr = s;
+
+	/* return partition table */
+	return parts;
+}
+
+/* 
+ * Parse the command line. 
+ */
+static int mtdpart_setup_real(char *s)
+{
+	cmdline_parsed = 1;
+
+	for( ; s != NULL; )
+	{
+		struct cmdline_mtd_partition *this_mtd;
+		struct mtd_partition *parts;
+	    	int mtd_id_len;
+		int num_parts;
+		char *p, *mtd_id;
+
+	    	mtd_id = s;
+		/* fetch <mtd-id> */
+		if (!(p = strchr(s, ':')))
+		{
+			printk(KERN_ERR ERRP "no mtd-id\n");
+			return 0;
+		}
+		mtd_id_len = p - mtd_id;
+
+		dbg(("parsing <%s>\n", p+1));
+
+		/* 
+		 * parse one mtd. have it reserve memory for the
+		 * struct cmdline_mtd_partition and the mtd-id string.
+		 */
+		parts = newpart(p + 1,		/* cmdline */
+				&s,		/* out: updated cmdline ptr */
+				&num_parts,	/* out: number of parts */
+				0,		/* first partition */
+				(unsigned char**)&this_mtd, /* out: extra mem */
+				mtd_id_len + 1 + sizeof(*this_mtd));
+		if(!parts)
+		{
+			/*
+			 * An error occurred. We're either:
+			 * a) out of memory, or
+			 * b) in the middle of the partition spec
+			 * Either way, this mtd is hosed and we're
+			 * unlikely to succeed in parsing any more
+			 */
+			 return 0;
+		 }
+
+		/* enter results */	    
+		this_mtd->parts = parts;
+		this_mtd->num_parts = num_parts;
+		this_mtd->mtd_id = (char*)(this_mtd + 1);
+		strncpy(this_mtd->mtd_id, mtd_id, mtd_id_len);
+		this_mtd->mtd_id[mtd_id_len] = 0;
+
+		/* link into chain */
+		this_mtd->next = partitions;	    	
+		partitions = this_mtd;
+
+		dbg(("mtdid=<%s> num_parts=<%d>\n", 
+		     this_mtd->mtd_id, this_mtd->num_parts));
+		
+
+		/* EOS - we're done */
+		if (*s == 0)
+			break;
+
+		/* does another spec follow? */
+		if (*s != ';')
+		{
+			printk(KERN_ERR ERRP "bad character after partition (%c)\n", *s);
+			return 0;
+		}
+		s++;
+	}
+	return 1;
+}
+
+/*
+ * Main function to be called from the MTD mapping driver/device to
+ * obtain the partitioning information. At this point the command line
+ * arguments will actually be parsed and turned to struct mtd_partition
+ * information. It returns partitions for the requested mtd device, or
+ * the first one in the chain if a NULL mtd_id is passed in.
+ */
+int parse_cmdline_partitions(struct mtd_info *master, 
+                             struct mtd_partition **pparts,
+                             const char *mtd_id)
+{
+	unsigned long offset;
+	int i;
+	struct cmdline_mtd_partition *part;
+
+	if(!cmdline)
+		return -EINVAL;
+
+	/* parse command line */
+	if (!cmdline_parsed)
+		mtdpart_setup_real(cmdline);
+
+	for(part = partitions; part; part = part->next)
+	{
+		if ((!mtd_id) || (!strcmp(part->mtd_id, mtd_id)))
+		{
+			for(i = 0, offset = 0; i < part->num_parts; i++)
+			{
+				if (!part->parts[i].offset)
+				  part->parts[i].offset = offset;
+				else
+				  offset = part->parts[i].offset;
+				if (part->parts[i].size == SIZE_REMAINING)
+				  part->parts[i].size = master->size - offset;
+				if (offset + part->parts[i].size > master->size)
+				{
+					printk(KERN_WARNING ERRP 
+					       "%s: partitioning exceeds flash size, truncating\n",
+					       part->mtd_id);
+					part->parts[i].size = master->size - offset;
+					part->num_parts = i;
+				}
+				offset += part->parts[i].size;
+			}
+			*pparts = part->parts;
+			return part->num_parts;
+		}
+	}
+	return -EINVAL;
+}
+
+
+/* 
+ * This is the handler for our kernel parameter, called from 
+ * main.c::checksetup(). Note that we can not yet kmalloc() anything,
+ * so we only save the commandline for later processing.
+ */
+static int __init mtdpart_setup(char *s)
+{
+	cmdline = s;
+	return 1;
+}
+
+__setup("mtdparts=", mtdpart_setup);
+
+EXPORT_SYMBOL(parse_cmdline_partitions);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Marius Groeger <mag@sysgo.de>");
+MODULE_DESCRIPTION("Command line configuration of MTD partitions");
diff -urN linux-2.4.21-pre3/drivers/mtd/devices/Config.in linux-2.4.21-pre4/drivers/mtd/devices/Config.in
--- linux-2.4.21-pre3/drivers/mtd/devices/Config.in	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre4/drivers/mtd/devices/Config.in	Tue Jan 28 19:44:30 2003
@@ -1,6 +1,6 @@
 # drivers/mtd/maps/Config.in
 
-# $Id: Config.in,v 1.5 2001/09/23 15:33:10 dwmw2 Exp $
+# $Id: Config.in,v 1.8 2003/01/24 23:25:14 dwmw2 Exp $
 
 mainmenu_option next_comment
 
@@ -11,11 +11,11 @@
    bool '    PMC551 Debugging' CONFIG_MTD_PMC551_DEBUG
 fi
 if [ "$CONFIG_DECSTATION" = "y" ]; then
-   dep_tristate '  DEC MS02-NV NVRAM module support' CONFIG_MTD_MS02NV $CONFIG_MTD $CONFIG_DECSTATION
+   dep_tristate '  DEC MS02-NV NVRAM module support' CONFIG_MTD_MS02NV $CONFIG_MTD
 fi
 dep_tristate '  Uncached system RAM' CONFIG_MTD_SLRAM $CONFIG_MTD
 if [ "$CONFIG_SA1100_LART" = "y" ]; then
-  dep_tristate '  28F160xx flash driver for LART' CONFIG_MTD_LART $CONFIG_MTD
+   dep_tristate '  28F160xx flash driver for LART' CONFIG_MTD_LART $CONFIG_MTD
 fi
 dep_tristate '  Test driver using RAM' CONFIG_MTD_MTDRAM $CONFIG_MTD
 if [ "$CONFIG_MTD_MTDRAM" = "y" -o "$CONFIG_MTD_MTDRAM" = "m" ]; then
diff -urN linux-2.4.21-pre3/drivers/mtd/devices/blkmtd.c linux-2.4.21-pre4/drivers/mtd/devices/blkmtd.c
--- linux-2.4.21-pre3/drivers/mtd/devices/blkmtd.c	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre4/drivers/mtd/devices/blkmtd.c	Tue Jan 28 19:44:30 2003
@@ -1,57 +1,36 @@
-/* 
- * $Id: blkmtd.c,v 1.7 2001/11/10 17:06:30 spse Exp $
+/*
+ * $Id: blkmtd.c,v 1.17 2003/01/24 13:00:24 dwmw2 Exp $
  *
  * blkmtd.c - use a block device as a fake MTD
  *
  * Author: Simon Evans <spse@secret.org.uk>
  *
- * Copyright (C) 2001 Simon Evans
- * 
+ * Copyright (C) 2001,2002 Simon Evans
+ *
  * Licence: GPL
  *
  * How it works:
- *       The driver uses raw/io to read/write the device and the page
- *       cache to cache access. Writes update the page cache with the
- *       new data but make a copy of the new page(s) and then a kernel
- *       thread writes pages out to the device in the background. This
- *       ensures that writes are order even if a page is updated twice.
- *       Also, since pages in the page cache are never marked as dirty,
- *       we dont have to worry about writepage() being called on some 
- *       random page which may not be in the write order.
- * 
- *       Erases are handled like writes, so the callback is called after
- *       the page cache has been updated. Sync()ing will wait until it is 
- *       all done.
+ *	The driver uses raw/io to read/write the device and the page
+ *	cache to cache access. Writes update the page cache with the
+ *	new data and mark it dirty and add the page into a kiobuf.
+ *	When the kiobuf becomes full or the next extry is to an earlier
+ *	block in the kiobuf then it is flushed to disk. This allows
+ *	writes to remained ordered and gives a small and simple outgoing
+ *	write cache.
  *
- *       It can be loaded Read-Only to prevent erases and writes to the 
- *       medium.
+ *	It can be loaded Read-Only to prevent erases and writes to the
+ *	medium.
  *
- * Todo:
- *       Make the write queue size dynamic so this it is not too big on
- *       small memory systems and too small on large memory systems.
- * 
- *       Page cache usage may still be a bit wrong. Check we are doing
- *       everything properly.
- * 
- *       Somehow allow writes to dirty the page cache so we dont use too
- *       much memory making copies of outgoing pages. Need to handle case
- *       where page x is written to, then page y, then page x again before
- *       any of them have been committed to disk.
- * 
- *       Reading should read multiple pages at once rather than using 
- *       readpage() for each one. This is easy and will be fixed asap.
  */
 
-
 #include <linux/config.h>
 #include <linux/module.h>
-
 #include <linux/fs.h>
-#include <linux/pagemap.h>
+#include <linux/blkdev.h>
 #include <linux/iobuf.h>
 #include <linux/slab.h>
 #include <linux/pagemap.h>
-#include <linux/mtd/compatmac.h>
+#include <linux/list.h>
 #include <linux/mtd/mtd.h>
 
 #ifdef CONFIG_MTD_DEBUG
@@ -63,918 +42,918 @@
 #endif
 
 
-/* Default erase size in K, always make it a multiple of PAGE_SIZE */
-#define CONFIG_MTD_BLKDEV_ERASESIZE 128
-#define VERSION "1.7"
-extern int *blk_size[];
-extern int *blksize_size[];
+#define err(format, arg...) printk(KERN_ERR "blkmtd: " format "\n" , ## arg)
+#define info(format, arg...) printk(KERN_INFO "blkmtd: " format "\n" , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING "blkmtd: " format "\n" , ## arg)
+#define crit(format, arg...) printk(KERN_CRIT "blkmtd: " format "\n" , ## arg)
 
-/* Info for the block device */
-typedef struct mtd_raw_dev_data_s {
-  struct block_device *binding;
-  int sector_size, sector_bits;
-  int partial_last_page;   // 0 if device ends on page boundary, else page no of last page
-  int last_page_sectors;   // Number of sectors in last page if partial_last_page != 0
-  size_t totalsize;
-  int readonly;
-  struct address_space as;
-  struct mtd_info mtd_info;
-} mtd_raw_dev_data_t;
-
-/* Info for each queue item in the write queue */
-typedef struct mtdblkdev_write_queue_s {
-  mtd_raw_dev_data_t *rawdevice;
-  struct page **pages;
-  int pagenr;
-  int pagecnt;
-  int iserase;
-} mtdblkdev_write_queue_t;
 
+/* Default erase size in KiB, always make it a multiple of PAGE_SIZE */
+#define CONFIG_MTD_BLKDEV_ERASESIZE (128 << 10)	/* 128KiB */
+#define VERSION "1.10"
+
+/* Info for the block device */
+struct blkmtd_dev {
+	struct list_head list;
+	struct block_device *binding;
+	struct mtd_info mtd_info;
+	struct kiobuf *rd_buf, *wr_buf;
+	long iobuf_locks;
+	struct semaphore wrbuf_mutex;
+};
 
-/* Our erase page - always remains locked. */
-static struct page *erase_page;
 
 /* Static info about the MTD, used in cleanup_module */
-static mtd_raw_dev_data_t *mtd_rawdevice;
+static LIST_HEAD(blkmtd_device_list);
 
-/* Write queue fixed size */
-#define WRITE_QUEUE_SZ 512
 
-/* Storage for the write queue */
-static mtdblkdev_write_queue_t *write_queue;
-static int write_queue_sz = WRITE_QUEUE_SZ;
-static int volatile write_queue_head;
-static int volatile write_queue_tail;
-static int volatile write_queue_cnt;
-static spinlock_t mbd_writeq_lock = SPIN_LOCK_UNLOCKED;
-
-/* Tell the write thread to finish */
-static volatile int write_task_finish;
-
-/* ipc with the write thread */
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0)
-static DECLARE_MUTEX_LOCKED(thread_sem);
-static DECLARE_WAIT_QUEUE_HEAD(thr_wq);
-static DECLARE_WAIT_QUEUE_HEAD(mtbd_sync_wq);
-#else
-static struct semaphore thread_sem = MUTEX_LOCKED;
-DECLARE_WAIT_QUEUE_HEAD(thr_wq);
-DECLARE_WAIT_QUEUE_HEAD(mtbd_sync_wq);
-#endif
+static void blkmtd_sync(struct mtd_info *mtd);
 
+#define MAX_DEVICES 4
 
 /* Module parameters passed by insmod/modprobe */
-char *device;    /* the block device to use */
-int erasesz;     /* optional default erase size */
-int ro;          /* optional read only flag */
-int bs;          /* optionally force the block size (avoid using) */
-int count;       /* optionally force the block count (avoid using) */
-int wqs;         /* optionally set the write queue size */
+char *device[MAX_DEVICES];    /* the block device to use */
+int erasesz[MAX_DEVICES];     /* optional default erase size */
+int ro[MAX_DEVICES];          /* optional read only flag */
+int sync;
 
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Simon Evans <spse@secret.org.uk>");
 MODULE_DESCRIPTION("Emulate an MTD using a block device");
-MODULE_PARM(device, "s");
+MODULE_PARM(device, "1-4s");
 MODULE_PARM_DESC(device, "block device to use");
-MODULE_PARM(erasesz, "i");
-MODULE_PARM_DESC(erasesz, "optional erase size to use in KB. eg 4=4K.");
-MODULE_PARM(ro, "i");
+MODULE_PARM(erasesz, "1-4i");
+MODULE_PARM_DESC(erasesz, "optional erase size to use in KiB. eg 4=4KiB.");
+MODULE_PARM(ro, "1-4i");
 MODULE_PARM_DESC(ro, "1=Read only, writes and erases cause errors");
-MODULE_PARM(bs, "i");
-MODULE_PARM_DESC(bs, "force the block size in bytes");
-MODULE_PARM(count, "i");
-MODULE_PARM_DESC(count, "force the block count");
-MODULE_PARM(wqs, "i");
-#endif
-
+MODULE_PARM(sync, "i");
+MODULE_PARM_DESC(sync, "1=Synchronous writes");
 
-/* Page cache stuff */
 
-/* writepage() - should never be called - catch it anyway */
-static int blkmtd_writepage(struct page *page)
+/**
+ * read_pages - read in pages via the page cache
+ * @dev: device to read from
+ * @pagenrs: list of page numbers wanted
+ * @pagelst: storage for struce page * pointers
+ * @pages: count of pages wanted
+ *
+ * Read pages, getting them from the page cache if available
+ * else reading them in from disk if not. pagelst must be preallocated
+ * to hold the page count.
+ */
+static int read_pages(struct blkmtd_dev *dev, int pagenrs[], struct page **pagelst, int pages)
 {
-  printk("blkmtd: writepage called!!!\n");
-  return -EIO;
-}
-
-
-/* readpage() - reads one page from the block device */                 
-static int blkmtd_readpage(mtd_raw_dev_data_t *rawdevice, struct page *page)
-{  
-  int err;
-  int sectornr, sectors, i;
-  struct kiobuf *iobuf;
-  kdev_t dev;
-  unsigned long *blocks;
-
-  if(!rawdevice) {
-    printk("blkmtd: readpage: PANIC file->private_data == NULL\n");
-    return -EIO;
-  }
-  dev = to_kdev_t(rawdevice->binding->bd_dev);
-
-  DEBUG(2, "blkmtd: readpage called, dev = `%s' page = %p index = %ld\n",
-	bdevname(dev), page, page->index);
-
-  if(Page_Uptodate(page)) {
-    DEBUG(2, "blkmtd: readpage page %ld is already upto date\n", page->index);
-    UnlockPage(page);
-    return 0;
-  }
-
-  ClearPageUptodate(page);
-  ClearPageError(page);
-
-  /* see if page is in the outgoing write queue */
-  spin_lock(&mbd_writeq_lock);
-  if(write_queue_cnt) {
-    int i = write_queue_tail;
-    while(i != write_queue_head) {
-      mtdblkdev_write_queue_t *item = &write_queue[i];
-      if(page->index >= item->pagenr && page->index < item->pagenr+item->pagecnt) {
-	/* yes it is */
-	int index = page->index - item->pagenr;
-		
-	DEBUG(2, "blkmtd: readpage: found page %ld in outgoing write queue\n",
-	      page->index);
-	if(item->iserase) {
-	  memset(page_address(page), 0xff, PAGE_SIZE);
-	} else {
-	  memcpy(page_address(page), page_address(item->pages[index]), PAGE_SIZE);
+	kdev_t kdev;
+	struct page *page;
+	int cnt = 0;
+	struct kiobuf *iobuf;
+	int err = 0;
+
+	if(!dev) {
+		err("read_pages: PANIC dev == NULL");
+		return -EIO;
 	}
-	SetPageUptodate(page);
-	flush_dcache_page(page);
-	UnlockPage(page);
-	spin_unlock(&mbd_writeq_lock);
-	return 0;
-      }
-      i++;
-      i %= write_queue_sz;
-    }
-  }
-  spin_unlock(&mbd_writeq_lock);
-
-
-  DEBUG(3, "blkmtd: readpage: getting kiovec\n");
-  err = alloc_kiovec(1, &iobuf);
-  if (err) {
-    printk("blkmtd: cant allocate kiobuf\n");
-    SetPageError(page);
-    return err;
-  }
+	kdev = to_kdev_t(dev->binding->bd_dev);
 
-  /* Pre 2.4.4 doesn't have space for the block list in the kiobuf */ 
+	DEBUG(2, "read_pages: reading %d pages\n", pages);
+	if(test_and_set_bit(0, &dev->iobuf_locks)) {
+		err = alloc_kiovec(1, &iobuf);
+		if (err) {
+			crit("cant allocate kiobuf");
+			return -ENOMEM;
+		}
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
-  blocks = kmalloc(KIO_MAX_SECTORS * sizeof(unsigned long));
-  if(blocks == NULL) {
-    printk("blkmtd: cant allocate iobuf blocks\n");
-    free_kiovec(1, &iobuf);
-    SetPageError(page);
-    return -ENOMEM;
-  }
-#else 
-  blocks = iobuf->blocks;
+		iobuf->blocks = kmalloc(KIO_MAX_SECTORS * sizeof(unsigned long), GFP_KERNEL);
+		if(iobuf->blocks == NULL) {
+			crit("cant allocate iobuf blocks");
+			free_kiovec(1, &iobuf);
+			return -ENOMEM;
+		}
 #endif
+	} else {
+		iobuf = dev->rd_buf;
+	}
+
+	iobuf->nr_pages = 0;
+	iobuf->length = 0;
+	iobuf->offset = 0;
+	iobuf->locked = 1;
+	
+	for(cnt = 0; cnt < pages; cnt++) {
+		page = grab_cache_page(dev->binding->bd_inode->i_mapping, pagenrs[cnt]);
+		pagelst[cnt] = page;
+		if(!PageUptodate(page)) {
+				iobuf->blocks[iobuf->nr_pages] = pagenrs[cnt];
+				iobuf->maplist[iobuf->nr_pages++] = page;
+		}
+	}
+
+	if(iobuf->nr_pages) {
+		iobuf->length = iobuf->nr_pages << PAGE_SHIFT;
+		err = brw_kiovec(READ, 1, &iobuf, kdev, iobuf->blocks, PAGE_SIZE);
+		DEBUG(3, "blkmtd: read_pages: finished, err = %d\n", err);
+		if(err < 0) {
+			while(pages--) {
+				ClearPageUptodate(pagelst[pages]);
+				unlock_page(pagelst[pages]);
+				page_cache_release(pagelst[pages]);
+			}
+		} else {
+			while(iobuf->nr_pages--) {
+				SetPageUptodate(iobuf->maplist[iobuf->nr_pages]);
+			}
+			err = 0;
+		}
+	}
 
-  iobuf->offset = 0;
-  iobuf->nr_pages = 1;
-  iobuf->length = PAGE_SIZE;
-  iobuf->locked = 1;
-  iobuf->maplist[0] = page;
-  sectornr = page->index << (PAGE_SHIFT - rawdevice->sector_bits);
-  sectors = 1 << (PAGE_SHIFT - rawdevice->sector_bits);
-  if(rawdevice->partial_last_page && page->index == rawdevice->partial_last_page) {
-    DEBUG(3, "blkmtd: handling partial last page\n");
-    sectors = rawdevice->last_page_sectors;
-  }
-  DEBUG(3, "blkmtd: readpage: sectornr = %d sectors = %d\n", sectornr, sectors);
-  for(i = 0; i < sectors; i++) {
-    blocks[i] = sectornr++;
-  }
-  /* If only a partial page read in, clear the rest of the page */
-  if(rawdevice->partial_last_page && page->index == rawdevice->partial_last_page) {
-    int offset = rawdevice->last_page_sectors << rawdevice->sector_bits;
-    int count = PAGE_SIZE-offset;
-    DEBUG(3, "blkmtd: clear last partial page: offset = %d count = %d\n", offset, count);
-    memset(page_address(page)+offset, 0, count);
-    sectors = rawdevice->last_page_sectors;
-  }
-
-
-  DEBUG(3, "bklmtd: readpage: starting brw_kiovec\n");
-  err = brw_kiovec(READ, 1, &iobuf, dev, blocks, rawdevice->sector_size);
-  DEBUG(3, "blkmtd: readpage: finished, err = %d\n", err);
-  iobuf->locked = 0;
-  free_kiovec(1, &iobuf);
 
+	if(iobuf != dev->rd_buf) {
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
-  kfree(blocks);
+		kfree(iobuf->blocks);
 #endif
-
-  if(err != PAGE_SIZE) {
-    printk("blkmtd: readpage: error reading page %ld\n", page->index);
-    memset(page_address(page), 0, PAGE_SIZE);
-    SetPageError(page);
-    err = -EIO;
-  } else {
-    DEBUG(3, "blkmtd: readpage: setting page upto date\n");
-    SetPageUptodate(page);
-    err = 0;
-  }
-  flush_dcache_page(page);
-  UnlockPage(page);
-  DEBUG(2, "blkmtd: readpage: finished, err = %d\n", err);
-  return 0;
+		free_kiovec(1, &iobuf);
+	} else {
+		clear_bit(0, &dev->iobuf_locks);
+	}
+	DEBUG(2, "read_pages: done, err = %d\n", err);
+	return err;
 }
 
-                    
-static struct address_space_operations blkmtd_aops = {
-  writepage:     blkmtd_writepage,
-  readpage:      NULL,
-}; 
+
+/**
+ * commit_pages - commit pages in the writeout kiobuf to disk
+ * @dev: device to write to
+ *
+ * If the current dev has pages in the dev->wr_buf kiobuf,
+ * they are written to disk using brw_kiovec()
+ */
+static int commit_pages(struct blkmtd_dev *dev)
+{
+	struct kiobuf *iobuf = dev->wr_buf;
+	kdev_t kdev = to_kdev_t(dev->binding->bd_dev);
+	int err = 0;
+
+	iobuf->length = iobuf->nr_pages << PAGE_SHIFT;
+	iobuf->locked = 1;
+	if(iobuf->length) {
+		int i;
+		DEBUG(2, "blkmtd: commit_pages: nrpages = %d\n", iobuf->nr_pages);
+		/* Check all the pages are dirty and lock them */
+		for(i = 0; i < iobuf->nr_pages; i++) {
+			struct page *page = iobuf->maplist[i];
+			BUG_ON(!PageDirty(page));
+			lock_page(page);
+		}
+		err = brw_kiovec(WRITE, 1, &iobuf, kdev, iobuf->blocks, PAGE_SIZE);
+		DEBUG(3, "commit_write: committed %d pages err = %d\n", iobuf->nr_pages, err);
+		while(iobuf->nr_pages) {
+			struct page *page = iobuf->maplist[--iobuf->nr_pages];
+			ClearPageDirty(page);
+			SetPageUptodate(page);
+			unlock_page(page);
+			page_cache_release(page);
+		}
+	}
+
+	DEBUG(2, "blkmtd: sync: end, err = %d\n", err);
+	iobuf->offset = 0;
+	iobuf->nr_pages = 0;
+	iobuf->length = 0;
+	return err;
+}
 
 
-/* This is the kernel thread that empties the write queue to disk */
-static int write_queue_task(void *data)
+/**
+ * write_pages - write block of data to device via the page cache
+ * @dev: device to write to
+ * @buf: data source or NULL if erase (output is set to 0xff)
+ * @to: offset into output device
+ * @len: amount to data to write
+ * @retlen: amount of data written
+ *
+ * Grab pages from the page cache and fill them with the source data.
+ * Non page aligned start and end result in a readin of the page and
+ * part of the page being modified. Pages are added to the wr_buf kiobuf
+ * until this becomes full or the next page written to has a lower pagenr
+ * then the current max pagenr in the kiobuf.
+ */
+static int write_pages(struct blkmtd_dev *dev, const u_char *buf, loff_t to,
+		    size_t len, int *retlen)
 {
-  int err;
-  struct task_struct *tsk = current;
-  struct kiobuf *iobuf;
-  unsigned long *blocks;
-
-  DECLARE_WAITQUEUE(wait, tsk);
-  DEBUG(1, "blkmtd: writetask: starting (pid = %d)\n", tsk->pid);
-  daemonize();
-  strcpy(tsk->comm, "blkmtdd");
-  tsk->tty = NULL;
-  spin_lock_irq(&tsk->sigmask_lock);
-  sigfillset(&tsk->blocked);
-  recalc_sigpending(tsk);
-  spin_unlock_irq(&tsk->sigmask_lock);
-  exit_sighand(tsk);
-
-  if(alloc_kiovec(1, &iobuf)) {
-    printk("blkmtd: write_queue_task cant allocate kiobuf\n");
-    return 0;
-  }
+	int pagenr, offset;
+	size_t start_len = 0, end_len;
+	int pagecnt = 0;
+	struct kiobuf *iobuf = dev->wr_buf;
+	int err = 0;
+	struct page *pagelst[2];
+	int pagenrs[2];
+	int readpages = 0;
+	int ignorepage = -1;
+
+	pagenr = to >> PAGE_SHIFT;
+	offset = to & ~PAGE_MASK;
+
+	DEBUG(2, "blkmtd: write_pages: buf = %p to = %ld len = %d pagenr = %d offset = %d\n",
+	      buf, (long)to, len, pagenr, offset);
+
+	*retlen = 0;
+	/* see if we have to do a partial write at the start */
+	if(offset) {
+		start_len = ((offset + len) > PAGE_SIZE) ? PAGE_SIZE - offset : len;
+		len -= start_len;
+	}
 
-  /* Pre 2.4.4 doesn't have space for the block list in the kiobuf */ 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
-  blocks = kmalloc(KIO_MAX_SECTORS * sizeof(unsigned long));
-  if(blocks == NULL) {
-    printk("blkmtd: write_queue_task cant allocate iobuf blocks\n");
-    free_kiovec(1, &iobuf);
-    return 0;
-  }
-#else 
-  blocks = iobuf->blocks;
-#endif
+	/* calculate the length of the other two regions */
+	end_len = len & ~PAGE_MASK;
+	len -= end_len;
+
+	if(start_len) {
+		pagenrs[0] = pagenr;
+		readpages++;
+		pagecnt++;
+	}
+	if(len)
+		pagecnt += len >> PAGE_SHIFT;
+	if(end_len) {
+		pagenrs[readpages] = pagenr + pagecnt;
+		readpages++;
+		pagecnt++;
+	}
 
-  DEBUG(2, "blkmtd: writetask: entering main loop\n");
-  add_wait_queue(&thr_wq, &wait);
+	DEBUG(3, "blkmtd: write: start_len = %d len = %d end_len = %d pagecnt = %d\n",
+	      start_len, len, end_len, pagecnt);
 
-  while(1) {
-    spin_lock(&mbd_writeq_lock);
+	down(&dev->wrbuf_mutex);
 
-    if(!write_queue_cnt) {
-      /* If nothing in the queue, wake up anyone wanting to know when there
-	 is space in the queue then sleep for 2*HZ */
-      spin_unlock(&mbd_writeq_lock);
-      DEBUG(4, "blkmtd: writetask: queue empty\n");
-      if(waitqueue_active(&mtbd_sync_wq))
-	 wake_up(&mtbd_sync_wq);
-      interruptible_sleep_on_timeout(&thr_wq, 2*HZ);
-      DEBUG(4, "blkmtd: writetask: woken up\n");
-      if(write_task_finish)
-	break;
-    } else {
-      /* we have stuff to write */
-      mtdblkdev_write_queue_t *item = &write_queue[write_queue_tail];
-      struct page **pages = item->pages;
-
-      int i;
-      int sectornr = item->pagenr << (PAGE_SHIFT - item->rawdevice->sector_bits);
-      int sectorcnt = item->pagecnt << (PAGE_SHIFT - item->rawdevice->sector_bits);
-      int max_sectors = KIO_MAX_SECTORS >> (item->rawdevice->sector_bits - 9);
-      kdev_t dev = to_kdev_t(item->rawdevice->binding->bd_dev);
-
-      /* If we are writing to the last page on the device and it doesn't end
-       * on a page boundary, subtract the number of sectors that dont exist.
-       */
-      if(item->rawdevice->partial_last_page && 
-	 (item->pagenr + item->pagecnt -1) == item->rawdevice->partial_last_page) {
-	sectorcnt -= (1 << (PAGE_SHIFT - item->rawdevice->sector_bits));
-	sectorcnt += item->rawdevice->last_page_sectors;
-      }
-
-      DEBUG(3, "blkmtd: writetask: got %d queue items\n", write_queue_cnt);
-      set_current_state(TASK_RUNNING);
-      spin_unlock(&mbd_writeq_lock);
-
-      DEBUG(2, "blkmtd: writetask: writing pagenr = %d pagecnt = %d sectornr = %d sectorcnt = %d\n", 
-	    item->pagenr, item->pagecnt, sectornr, sectorcnt);
-
-      iobuf->offset = 0;
-      iobuf->locked = 1;
-
-      /* Loop through all the pages to be written in the queue item, remembering
-	 we can only write KIO_MAX_SECTORS at a time */
-	 
-      while(sectorcnt) {
-	int cursectors = (sectorcnt < max_sectors) ? sectorcnt : max_sectors;
-	int cpagecnt = (cursectors << item->rawdevice->sector_bits) + PAGE_SIZE-1;
-	cpagecnt >>= PAGE_SHIFT;
-	
-	for(i = 0; i < cpagecnt; i++) {
-	  if(item->iserase) {
-	    iobuf->maplist[i] = erase_page;
-	  } else {
-	    iobuf->maplist[i] = *(pages++);
-	  }
+	if(iobuf->nr_pages && ((pagenr <= iobuf->blocks[iobuf->nr_pages-1])
+			       || (iobuf->nr_pages + pagecnt) >= KIO_STATIC_PAGES)) {
+
+		if((pagenr == iobuf->blocks[iobuf->nr_pages-1])
+		   && ((iobuf->nr_pages + pagecnt) < KIO_STATIC_PAGES)) {
+			iobuf->nr_pages--;
+			ignorepage = pagenr;
+		} else {
+			DEBUG(3, "blkmtd: doing writeout pagenr = %d max_pagenr = %ld pagecnt = %d idx = %d\n",
+			      pagenr, iobuf->blocks[iobuf->nr_pages-1],
+			      pagecnt, iobuf->nr_pages);
+			commit_pages(dev);
+		}
 	}
 	
-	for(i = 0; i < cursectors; i++) {
-	  blocks[i] = sectornr++;
+	if(readpages) {
+		err = read_pages(dev, pagenrs, pagelst, readpages);
+		if(err < 0)
+			goto readin_err;
 	}
-	
-	iobuf->nr_pages = cpagecnt;
-	iobuf->length = cursectors << item->rawdevice->sector_bits;
-	DEBUG(3, "blkmtd: write_task: about to kiovec\n");
-	err = brw_kiovec(WRITE, 1, &iobuf, dev, blocks, item->rawdevice->sector_size);
-	DEBUG(3, "bklmtd: write_task: done, err = %d\n", err);
-	if(err != (cursectors << item->rawdevice->sector_bits)) {
-	  /* if an error occured - set this to exit the loop */
-	  sectorcnt = 0;
-	} else {
-	  sectorcnt -= cursectors;
+
+	if(start_len) {
+		/* do partial start region */
+		struct page *page;
+
+		DEBUG(3, "blkmtd: write: doing partial start, page = %d len = %d offset = %d\n",
+		      pagenr, start_len, offset);
+		page = pagelst[0];
+		BUG_ON(!buf);
+		if(PageDirty(page) && pagenr != ignorepage) {
+			err("to = %lld start_len = %d len = %d end_len = %d pagenr = %d ignorepage = %d\n",
+			    to, start_len, len, end_len, pagenr, ignorepage);
+			BUG();
+		}
+		memcpy(page_address(page)+offset, buf, start_len);
+		SetPageDirty(page);
+		SetPageUptodate(page);
+		unlock_page(page);
+		buf += start_len;
+		*retlen = start_len;
+		err = 0;
+		iobuf->blocks[iobuf->nr_pages] = pagenr++;
+		iobuf->maplist[iobuf->nr_pages] = page;
+		iobuf->nr_pages++;
 	}
-      }
 
-      /* free up the pages used in the write and list of pages used in the write
-	 queue item */
-      iobuf->locked = 0;
-      spin_lock(&mbd_writeq_lock);
-      write_queue_cnt--;
-      write_queue_tail++;
-      write_queue_tail %= write_queue_sz;
-      if(!item->iserase) {
-	for(i = 0 ; i < item->pagecnt; i++) {
-	  UnlockPage(item->pages[i]);
-	  __free_pages(item->pages[i], 0);
-	}
-	kfree(item->pages);
-      }
-      item->pages = NULL;
-      spin_unlock(&mbd_writeq_lock);
-      /* Tell others there is some space in the write queue */
-      if(waitqueue_active(&mtbd_sync_wq))
-	wake_up(&mtbd_sync_wq);
-    }
-  }
-  remove_wait_queue(&thr_wq, &wait);
-  DEBUG(1, "blkmtd: writetask: exiting\n");
-  free_kiovec(1, &iobuf);
+	/* Now do the main loop to a page aligned, n page sized output */
+	if(len) {
+		int pagesc = len >> PAGE_SHIFT;
+		DEBUG(3, "blkmtd: write: whole pages start = %d, count = %d\n",
+		      pagenr, pagesc);
+		while(pagesc) {
+			struct page *page;
+
+			/* see if page is in the page cache */
+			DEBUG(3, "blkmtd: write: grabbing page %d from page cache\n", pagenr);
+			page = grab_cache_page(dev->binding->bd_inode->i_mapping, pagenr);
+			if(PageDirty(page) && pagenr != ignorepage) {
+				BUG();
+			}
+			if(!page) {
+				warn("write: cant grab cache page %d", pagenr);
+				err = -ENOMEM;
+				goto write_err;
+			}
+			if(!buf) {
+				memset(page_address(page), 0xff, PAGE_SIZE);
+			} else {
+				memcpy(page_address(page), buf, PAGE_SIZE);
+				buf += PAGE_SIZE;
+			}
+			iobuf->blocks[iobuf->nr_pages] = pagenr++;
+			iobuf->maplist[iobuf->nr_pages] = page;
+			iobuf->nr_pages++;
+			SetPageDirty(page);
+			SetPageUptodate(page);
+			unlock_page(page);
+			pagesc--;
+			*retlen += PAGE_SIZE;
+		}
+	}
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
-  kfree(blocks);
-#endif
+	if(end_len) {
+		/* do the third region */
+		struct page *page;
+		DEBUG(3, "blkmtd: write: doing partial end, page = %d len = %d\n",
+		      pagenr, end_len);
+		page = pagelst[readpages-1];
+		BUG_ON(!buf);
+		if(PageDirty(page) && pagenr != ignorepage) {
+			err("to = %lld start_len = %d len = %d end_len = %d pagenr = %d ignorepage = %d\n",
+			    to, start_len, len, end_len, pagenr, ignorepage);
+			BUG();
+		}
+		memcpy(page_address(page), buf, end_len);
+		SetPageDirty(page);
+		SetPageUptodate(page);
+		unlock_page(page);
+		DEBUG(3, "blkmtd: write: writing out partial end\n");
+		*retlen += end_len;
+		err = 0;
+		iobuf->blocks[iobuf->nr_pages] = pagenr;
+		iobuf->maplist[iobuf->nr_pages] = page;
+		iobuf->nr_pages++;
+	}
 
-  /* Tell people we have exitd */
-  up(&thread_sem);
-  return 0;
-}
+	DEBUG(2, "blkmtd: write: end, retlen = %d, err = %d\n", *retlen, err);
 
+	if(sync) {
+write_err:
+		commit_pages(dev);
+	}
 
-/* Add a range of pages into the outgoing write queue, making copies of them */
-static int queue_page_write(mtd_raw_dev_data_t *rawdevice, struct page **pages,
-			    int pagenr, int pagecnt, int iserase)
-{
-  struct page *outpage;
-  struct page **new_pages = NULL;
-  mtdblkdev_write_queue_t *item;
-  int i;
-  DECLARE_WAITQUEUE(wait, current);
-  DEBUG(2, "blkmtd: queue_page_write: adding pagenr = %d pagecnt = %d\n", pagenr, pagecnt);
-
-  if(!pagecnt)
-    return 0;
-
-  if(pages == NULL && !iserase)
-    return -EINVAL;
-
-  /* create a array for the list of pages */
-  if(!iserase) {
-    new_pages = kmalloc(pagecnt * sizeof(struct page *), GFP_KERNEL);
-    if(new_pages == NULL)
-      return -ENOMEM;
-
-    /* make copies of the pages in the page cache */
-    for(i = 0; i < pagecnt; i++) {
-      outpage = alloc_pages(GFP_KERNEL, 0);
-      if(!outpage) {
-	while(i--) {
-	  UnlockPage(new_pages[i]);
-	  __free_pages(new_pages[i], 0);
-	}
-	kfree(new_pages);
-	return -ENOMEM;
-      }
-      lock_page(outpage);
-      memcpy(page_address(outpage), page_address(pages[i]), PAGE_SIZE);
-      new_pages[i] = outpage;
-    }
-  }
-
-  /* wait until there is some space in the write queue */
- test_lock:
-  spin_lock(&mbd_writeq_lock);
-  if(write_queue_cnt == write_queue_sz) {
-    spin_unlock(&mbd_writeq_lock);
-    DEBUG(3, "blkmtd: queue_page: Queue full\n");
-    current->state = TASK_UNINTERRUPTIBLE;
-    add_wait_queue(&mtbd_sync_wq, &wait);
-    wake_up_interruptible(&thr_wq);
-    schedule();
-    current->state = TASK_RUNNING;
-    remove_wait_queue(&mtbd_sync_wq, &wait);
-    DEBUG(3, "blkmtd: queue_page_write: Queue has %d items in it\n", write_queue_cnt);
-    goto test_lock;
-  }
-
-  DEBUG(3, "blkmtd: queue_page_write: qhead: %d qtail: %d qcnt: %d\n", 
-	write_queue_head, write_queue_tail, write_queue_cnt);
-
-  /* fix up the queue item */
-  item = &write_queue[write_queue_head];
-  item->pages = new_pages;
-  item->pagenr = pagenr;
-  item->pagecnt = pagecnt;
-  item->rawdevice = rawdevice;
-  item->iserase = iserase;
-
-  write_queue_head++;
-  write_queue_head %= write_queue_sz;
-  write_queue_cnt++;
-  DEBUG(3, "blkmtd: queue_page_write: qhead: %d qtail: %d qcnt: %d\n", 
-	write_queue_head, write_queue_tail, write_queue_cnt);
-  spin_unlock(&mbd_writeq_lock);
-  DEBUG(2, "blkmtd: queue_page_write: finished\n");
-  return 0;
+readin_err:
+	up(&dev->wrbuf_mutex);
+	return err;
 }
 
 
 /* erase a specified part of the device */
 static int blkmtd_erase(struct mtd_info *mtd, struct erase_info *instr)
 {
-  mtd_raw_dev_data_t *rawdevice = mtd->priv;
-  struct mtd_erase_region_info *einfo = mtd->eraseregions;
-  int numregions = mtd->numeraseregions;
-  size_t from;
-  u_long len;
-  int err = 0;
-
-  /* check readonly */
-  if(rawdevice->readonly) {
-    printk("blkmtd: error: trying to erase readonly device %s\n", device);
-    instr->state = MTD_ERASE_FAILED;
-    goto erase_callback;
-  }
-
-  instr->state = MTD_ERASING;
-  from = instr->addr;
-  len = instr->len;
-
-  /* check erase region has valid start and length */
-  DEBUG(2, "blkmtd: erase: dev = `%s' from = 0x%x len = 0x%lx\n",
-	bdevname(rawdevice->binding->bd_dev), from, len);
-  while(numregions) {
-    DEBUG(3, "blkmtd: checking erase region = 0x%08X size = 0x%X num = 0x%x\n",
-	  einfo->offset, einfo->erasesize, einfo->numblocks);
-    if(from >= einfo->offset && from < einfo->offset + (einfo->erasesize * einfo->numblocks)) {
-      if(len == einfo->erasesize && ( (from - einfo->offset) % einfo->erasesize == 0))
-	break;
-    }
-    numregions--;
-    einfo++;
-  }
-
-  if(!numregions) {
-    /* Not a valid erase block */
-    printk("blkmtd: erase: invalid erase request 0x%lX @ 0x%08X\n", len, from);
-    instr->state = MTD_ERASE_FAILED;
-    err = -EIO;
-  }
-  
-  if(instr->state != MTD_ERASE_FAILED) {
-    /* start the erase */
-    int pagenr, pagecnt;
-    struct page *page, **pages;
-    int i = 0;
-
-    /* Handle the last page of the device not being whole */
-    if(len < PAGE_SIZE)
-      len = PAGE_SIZE;
-
-    pagenr = from >> PAGE_SHIFT;
-    pagecnt = len >> PAGE_SHIFT;
-    DEBUG(3, "blkmtd: erase: pagenr = %d pagecnt = %d\n", pagenr, pagecnt);
-
-    pages = kmalloc(pagecnt * sizeof(struct page *), GFP_KERNEL);
-    if(pages == NULL) {
-      err = -ENOMEM;
-      instr->state = MTD_ERASE_FAILED;
-      goto erase_out;
-    }
-
-
-    while(pagecnt) {
-      /* get the page via the page cache */
-      DEBUG(3, "blkmtd: erase: doing grab_cache_page() for page %d\n", pagenr);
-      page = grab_cache_page(&rawdevice->as, pagenr);
-      if(!page) {
-	DEBUG(3, "blkmtd: erase: grab_cache_page() failed for page %d\n", pagenr);
-	kfree(pages);
-	err = -EIO;
-	instr->state = MTD_ERASE_FAILED;
-	goto erase_out;
-      }
-      memset(page_address(page), 0xff, PAGE_SIZE);
-      pages[i] = page;
-      pagecnt--;
-      pagenr++;
-      i++;
-    }
-    DEBUG(3, "blkmtd: erase: queuing page write\n");
-    err = queue_page_write(rawdevice, NULL, from >> PAGE_SHIFT, len >> PAGE_SHIFT, 1);
-    pagecnt = len >> PAGE_SHIFT;
-    if(!err) {
-      while(pagecnt--) {
-	SetPageUptodate(pages[pagecnt]);
-	UnlockPage(pages[pagecnt]);
-	page_cache_release(pages[pagecnt]);
-	flush_dcache_page(pages[pagecnt]);
-      }
-      kfree(pages);
-      instr->state = MTD_ERASE_DONE;
-    } else {
-      while(pagecnt--) {
-	SetPageError(pages[pagecnt]);
-	page_cache_release(pages[pagecnt]);
-      }
-      kfree(pages);
-      instr->state = MTD_ERASE_FAILED;
-    }
-  }
- erase_out:
-  DEBUG(3, "blkmtd: erase: checking callback\n");
+	struct blkmtd_dev *dev = mtd->priv;
+	struct mtd_erase_region_info *einfo = mtd->eraseregions;
+	int numregions = mtd->numeraseregions;
+	size_t from;
+	u_long len;
+	int err = -EIO;
+	int retlen;
+
+	/* check readonly */
+	if(!dev->wr_buf) {
+		err("error: mtd%d trying to erase readonly device %s",
+		    mtd->index, mtd->name);
+		instr->state = MTD_ERASE_FAILED;
+		goto erase_callback;
+	}
+
+	instr->state = MTD_ERASING;
+	from = instr->addr;
+	len = instr->len;
+
+	/* check erase region has valid start and length */
+	DEBUG(2, "blkmtd: erase: dev = `%s' from = 0x%x len = 0x%lx\n",
+	      bdevname(dev->binding->bd_dev), from, len);
+	while(numregions) {
+		DEBUG(3, "blkmtd: checking erase region = 0x%08X size = 0x%X num = 0x%x\n",
+		      einfo->offset, einfo->erasesize, einfo->numblocks);
+		if(from >= einfo->offset
+		   && from < einfo->offset + (einfo->erasesize * einfo->numblocks)) {
+			if(len == einfo->erasesize
+			   && ( (from - einfo->offset) % einfo->erasesize == 0))
+				break;
+		}
+		numregions--;
+		einfo++;
+	}
+
+	if(!numregions) {
+		/* Not a valid erase block */
+		err("erase: invalid erase request 0x%lX @ 0x%08X", len, from);
+		instr->state = MTD_ERASE_FAILED;
+		err = -EIO;
+	}
+
+	if(instr->state != MTD_ERASE_FAILED) {
+		/* do the erase */
+		DEBUG(3, "Doing erase from = %d len = %ld\n", from, len);
+		err = write_pages(dev, NULL, from, len, &retlen);
+		if(err < 0) {
+			err("erase failed err = %d", err);
+			instr->state = MTD_ERASE_FAILED;
+		} else {
+			instr->state = MTD_ERASE_DONE;
+			err = 0;
+		}
+	}
+
+	DEBUG(3, "blkmtd: erase: checking callback\n");
  erase_callback:
-  if (instr->callback) {
-    (*(instr->callback))(instr);
-  }
-  DEBUG(2, "blkmtd: erase: finished (err = %d)\n", err);
-  return err;
+	if (instr->callback) {
+		(*(instr->callback))(instr);
+	}
+	DEBUG(2, "blkmtd: erase: finished (err = %d)\n", err);
+	return err;
 }
 
 
 /* read a range of the data via the page cache */
 static int blkmtd_read(struct mtd_info *mtd, loff_t from, size_t len,
-	     size_t *retlen, u_char *buf)
+		       size_t *retlen, u_char *buf)
 {
-  mtd_raw_dev_data_t *rawdevice = mtd->priv;
-  int err = 0;
-  int offset;
-  int pagenr, pages;
-
-  *retlen = 0;
-
-  DEBUG(2, "blkmtd: read: dev = `%s' from = %ld len = %d buf = %p\n",
-	bdevname(rawdevice->binding->bd_dev), (long int)from, len, buf);
-
-  pagenr = from >> PAGE_SHIFT;
-  offset = from - (pagenr << PAGE_SHIFT);
-  
-  pages = (offset+len+PAGE_SIZE-1) >> PAGE_SHIFT;
-  DEBUG(3, "blkmtd: read: pagenr = %d offset = %d, pages = %d\n", pagenr, offset, pages);
-
-  /* just loop through each page, getting it via readpage() - slow but easy */
-  while(pages) {
-    struct page *page;
-    int cpylen;
-    DEBUG(3, "blkmtd: read: looking for page: %d\n", pagenr);
-    page = read_cache_page(&rawdevice->as, pagenr, (filler_t *)blkmtd_readpage, rawdevice);
-    if(IS_ERR(page)) {
-      return PTR_ERR(page);
-    }
-    wait_on_page(page);
-    if(!Page_Uptodate(page)) {
-      /* error reading page */
-      printk("blkmtd: read: page not uptodate\n");
-      page_cache_release(page);
-      return -EIO;
-    }
-
-    cpylen = (PAGE_SIZE > len) ? len : PAGE_SIZE;
-    if(offset+cpylen > PAGE_SIZE)
-      cpylen = PAGE_SIZE-offset;
-    
-    memcpy(buf + *retlen, page_address(page) + offset, cpylen);
-    offset = 0;
-    len -= cpylen;
-    *retlen += cpylen;
-    pagenr++;
-    pages--;
-    page_cache_release(page);
-  }
-  
-  DEBUG(2, "blkmtd: end read: retlen = %d, err = %d\n", *retlen, err);
-  return err;
+	struct blkmtd_dev *dev = mtd->priv;
+	int err = 0;
+	int offset;
+	int pagenr, pages;
+	struct page **pagelst;
+	int *pagenrs;
+	int i;
+
+	*retlen = 0;
+
+	DEBUG(2, "blkmtd: read: dev = `%s' from = %ld len = %d buf = %p\n",
+	      bdevname(dev->binding->bd_dev), (long int)from, len, buf);
+
+	pagenr = from >> PAGE_SHIFT;
+	offset = from - (pagenr << PAGE_SHIFT);
+
+	pages = (offset+len+PAGE_SIZE-1) >> PAGE_SHIFT;
+	DEBUG(3, "blkmtd: read: pagenr = %d offset = %d, pages = %d\n",
+	      pagenr, offset, pages);
+
+	pagelst = kmalloc(sizeof(struct page *) * pages, GFP_KERNEL);
+	if(!pagelst)
+		return -ENOMEM;
+	pagenrs = kmalloc(sizeof(int) * pages, GFP_KERNEL);
+	if(!pagenrs) {
+		kfree(pagelst);
+		return -ENOMEM;
+	}
+	for(i = 0; i < pages; i++)
+		pagenrs[i] = pagenr+i;
+
+	err = read_pages(dev, pagenrs, pagelst, pages);
+	if(err)
+		goto readerr;
+
+	pagenr = 0;
+	while(pages) {
+		struct page *page;
+		int cpylen;
+
+		DEBUG(3, "blkmtd: read: looking for page: %d\n", pagenr);
+		page = pagelst[pagenr];
+
+		cpylen = (PAGE_SIZE > len) ? len : PAGE_SIZE;
+		if(offset+cpylen > PAGE_SIZE)
+			cpylen = PAGE_SIZE-offset;
+
+		memcpy(buf + *retlen, page_address(page) + offset, cpylen);
+		offset = 0;
+		len -= cpylen;
+		*retlen += cpylen;
+		pagenr++;
+		pages--;
+		unlock_page(page);
+		if(!PageDirty(page))
+			page_cache_release(page);
+	}
+
+ readerr:
+	kfree(pagelst);
+	kfree(pagenrs);
+	DEBUG(2, "blkmtd: end read: retlen = %d, err = %d\n", *retlen, err);
+	return err;
 }
 
-    
-/* write a range of the data via the page cache.
- *
- * Basic operation. break the write into three parts. 
- *
- * 1. From a page unaligned start up until the next page boundary
- * 2. Page sized, page aligned blocks
- * 3. From end of last aligned block to end of range
- *
- * 1,3 are read via the page cache and readpage() since these are partial
- * pages, 2 we just grab pages from the page cache, not caring if they are
- * already in memory or not since they will be completly overwritten.
- *
- */
- 
+
+/* write data to the underlying device */
 static int blkmtd_write(struct mtd_info *mtd, loff_t to, size_t len,
-	      size_t *retlen, const u_char *buf)
+			size_t *retlen, const u_char *buf)
 {
-  mtd_raw_dev_data_t *rawdevice = mtd->priv;
-  int err = 0;
-  int offset;
-  int pagenr;
-  size_t len1 = 0, len2 = 0, len3 = 0;
-  struct page **pages;
-  int pagecnt = 0;
-
-  *retlen = 0;
-  DEBUG(2, "blkmtd: write: dev = `%s' to = %ld len = %d buf = %p\n",
-	bdevname(rawdevice->binding->bd_dev), (long int)to, len, buf);
-
-  /* handle readonly and out of range numbers */
-
-  if(rawdevice->readonly) {
-    printk("blkmtd: error: trying to write to a readonly device %s\n", device);
-    return -EROFS;
-  }
-
-  if(to >= rawdevice->totalsize) {
-    return -ENOSPC;
-  }
-
-  if(to + len > rawdevice->totalsize) {
-    len = (rawdevice->totalsize - to);
-  }
-
-
-  pagenr = to >> PAGE_SHIFT;
-  offset = to - (pagenr << PAGE_SHIFT);
-
-  /* see if we have to do a partial write at the start */
-  if(offset) {
-    if((offset + len) > PAGE_SIZE) {
-      len1 = PAGE_SIZE - offset;
-      len -= len1;
-    } else {
-      len1 = len;
-      len = 0;
-    }
-  }
-
-  /* calculate the length of the other two regions */
-  len3 = len & ~PAGE_MASK;
-  len -= len3;
-  len2 = len;
-
-
-  if(len1)
-    pagecnt++;
-  if(len2)
-    pagecnt += len2 >> PAGE_SHIFT;
-  if(len3)
-    pagecnt++;
-
-  DEBUG(3, "blkmtd: write: len1 = %d len2 = %d len3 = %d pagecnt = %d\n", len1, len2, len3, pagecnt);
-  
-  /* get space for list of pages */
-  pages = kmalloc(pagecnt * sizeof(struct page *), GFP_KERNEL);
-  if(pages == NULL) {
-    return -ENOMEM;
-  }
-  pagecnt = 0;
-
-  if(len1) {
-    /* do partial start region */
-    struct page *page;
-    
-    DEBUG(3, "blkmtd: write: doing partial start, page = %d len = %d offset = %d\n", pagenr, len1, offset);
-    page = read_cache_page(&rawdevice->as, pagenr, (filler_t *)blkmtd_readpage, rawdevice);
-
-    if(IS_ERR(page)) {
-      kfree(pages);
-      return PTR_ERR(page);
-    }
-    memcpy(page_address(page)+offset, buf, len1);
-    pages[pagecnt++] = page;
-    buf += len1;
-    *retlen = len1;
-    err = 0;
-    pagenr++;
-  }
-
-  /* Now do the main loop to a page aligned, n page sized output */
-  if(len2) {
-    int pagesc = len2 >> PAGE_SHIFT;
-    DEBUG(3, "blkmtd: write: whole pages start = %d, count = %d\n", pagenr, pagesc);
-    while(pagesc) {
-      struct page *page;
-
-      /* see if page is in the page cache */
-      DEBUG(3, "blkmtd: write: grabbing page %d from page cache\n", pagenr);
-      page = grab_cache_page(&rawdevice->as, pagenr);
-      DEBUG(3, "blkmtd: write: got page %d from page cache\n", pagenr);
-      if(!page) {
-	printk("blkmtd: write: cant grab cache page %d\n", pagenr);
-	err = -EIO;
-	goto write_err;
-      }
-      memcpy(page_address(page), buf, PAGE_SIZE);
-      pages[pagecnt++] = page;
-      UnlockPage(page);
-      SetPageUptodate(page);
-      pagenr++;
-      pagesc--;
-      buf += PAGE_SIZE;
-      *retlen += PAGE_SIZE;
-    }
-  }
-
-
-  if(len3) {
-    /* do the third region */
-    struct page *page;
-    DEBUG(3, "blkmtd: write: doing partial end, page = %d len = %d\n", pagenr, len3);
-    page = read_cache_page(&rawdevice->as, pagenr, (filler_t *)blkmtd_readpage, rawdevice);
-    if(IS_ERR(page)) {
-      err = PTR_ERR(page);
-      goto write_err;
-    }
-    memcpy(page_address(page), buf, len3);
-    DEBUG(3, "blkmtd: write: writing out partial end\n");
-    pages[pagecnt++] = page;
-    *retlen += len3;
-    err = 0;
-  }
-  DEBUG(2, "blkmtd: write: end, retlen = %d, err = %d\n", *retlen, err);
-  /* submit it to the write task */
-  err = queue_page_write(rawdevice, pages, to >> PAGE_SHIFT, pagecnt, 0);
-  if(!err) {
-    while(pagecnt--) {
-      SetPageUptodate(pages[pagecnt]);
-      flush_dcache_page(pages[pagecnt]);
-      page_cache_release(pages[pagecnt]);
-    }
-    kfree(pages);
-    return 0;
-  }
-
- write_err:
-  while(--pagecnt) {
-    SetPageError(pages[pagecnt]);
-    page_cache_release(pages[pagecnt]);
-  }
-  kfree(pages);
-  return err;
+	struct blkmtd_dev *dev = mtd->priv;
+	int err;
+
+	*retlen = 0;
+	if(!len)
+		return 0;
+
+	DEBUG(2, "blkmtd: write: dev = `%s' to = %ld len = %d buf = %p\n",
+	      bdevname(dev->binding->bd_dev), (long int)to, len, buf);
+
+	/* handle readonly and out of range numbers */
+
+	if(!dev->wr_buf) {
+		err("error: trying to write to a readonly device %s", mtd->name);
+		return -EROFS;
+	}
+
+	if(to >= mtd->size) {
+		return -ENOSPC;
+	}
+
+	if(to + len > mtd->size) {
+		len = (mtd->size - to);
+	}
+
+	err = write_pages(dev, buf, to, len, retlen);
+	if(err < 0)
+		*retlen = 0;
+	else
+		err = 0;
+	DEBUG(2, "blkmtd: write: end, err = %d\n", err);
+	return err;
 }
 
 
 /* sync the device - wait until the write queue is empty */
 static void blkmtd_sync(struct mtd_info *mtd)
 {
-  DECLARE_WAITQUEUE(wait, current);
-  mtd_raw_dev_data_t *rawdevice = mtd->priv;
-  if(rawdevice->readonly)
-    return;
-
-  DEBUG(2, "blkmtd: sync: called\n");
-
- stuff_inq:
-  spin_lock(&mbd_writeq_lock);
-  if(write_queue_cnt) {
-    spin_unlock(&mbd_writeq_lock);
-    current->state = TASK_UNINTERRUPTIBLE;
-    add_wait_queue(&mtbd_sync_wq, &wait);
-    DEBUG(3, "blkmtd: sync: waking up task\n");
-    wake_up_interruptible(&thr_wq);
-    schedule();
-    current->state = TASK_RUNNING;
-    remove_wait_queue(&mtbd_sync_wq, &wait);
-    DEBUG(3, "blkmtd: sync: waking up after write task\n");
-    goto stuff_inq;
-  }
-  spin_unlock(&mbd_writeq_lock);
+	struct blkmtd_dev *dev = mtd->priv;
+	struct kiobuf *iobuf = dev->wr_buf;
 
-  DEBUG(2, "blkmtd: sync: finished\n");
+	DEBUG(2, "blkmtd: sync: called\n");
+	if(iobuf == NULL)
+		return;
+
+	DEBUG(3, "blkmtd: kiovec: length = %d nr_pages = %d\n",
+	      iobuf->length, iobuf->nr_pages);
+	down(&dev->wrbuf_mutex);
+	if(iobuf->nr_pages)
+		commit_pages(dev);
+	up(&dev->wrbuf_mutex);
 }
 
 
 #ifdef BLKMTD_PROC_DEBUG
 /* procfs stuff */
-static int blkmtd_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data)
+static int blkmtd_proc_read(char *page, char **start, off_t off,
+			    int count, int *eof, void *data)
+{
+	int len;
+	struct list_head *temp1, *temp2;
+
+	MOD_INC_USE_COUNT;
+
+	/* Count the size of the page lists */
+
+	len = sprintf(page, "dev\twr_idx\tmax_idx\tnrpages\tclean\tdirty\tlocked\tlru\n");
+	list_for_each_safe(temp1, temp2, &blkmtd_device_list) {
+		struct blkmtd_dev *dev = list_entry(temp1,  struct blkmtd_dev,
+						    list);
+		struct list_head *temp;
+		struct page *pagei;
+
+		int clean = 0, dirty = 0, locked = 0, lru = 0;
+		/* Count the size of the page lists */
+		list_for_each(temp, &dev->binding->bd_inode->i_mapping->clean_pages) {
+			pagei = list_entry(temp, struct page, list);
+			clean++;
+			if(PageLocked(pagei))
+				locked++;
+			if(PageDirty(pagei))
+				dirty++;
+			if(PageLRU(pagei))
+				lru++;
+		}
+		list_for_each(temp, &dev->binding->bd_inode->i_mapping->dirty_pages) {
+			pagei = list_entry(temp, struct page, list);
+			if(PageLocked(pagei))
+				locked++;
+			if(PageDirty(pagei))
+				dirty++;
+			if(PageLRU(pagei))
+				lru++;
+		}
+		list_for_each(temp, &dev->binding->bd_inode->i_mapping->locked_pages) {
+			pagei = list_entry(temp, struct page, list);
+			if(PageLocked(pagei))
+				locked++;
+			if(PageDirty(pagei))
+				dirty++;
+			if(PageLRU(pagei))
+				lru++;
+		}
+
+		len += sprintf(page+len, "mtd%d:\t%ld\t%d\t%ld\t%d\t%d\t%d\t%d\n",
+			       dev->mtd_info.index,
+			       (dev->wr_buf && dev->wr_buf->nr_pages) ?
+			       dev->wr_buf->blocks[dev->wr_buf->nr_pages-1] : 0,
+			       (dev->wr_buf) ? dev->wr_buf->nr_pages : 0,
+			       dev->binding->bd_inode->i_mapping->nrpages,
+			       clean, dirty, locked, lru);
+	}
+
+	if(len <= count)
+		*eof = 1;
+
+	MOD_DEC_USE_COUNT;
+	return len;
+}
+#endif
+
+
+static void free_device(struct blkmtd_dev *dev)
 {
-  int clean = 0, dirty = 0, locked = 0;
-  struct list_head *temp;
-  int i, len, pages = 0, cnt;
-  MOD_INC_USE_COUNT;
-  spin_lock(&mbd_writeq_lock);
-  cnt = write_queue_cnt;
-  i = write_queue_tail;
-  while(cnt) {
-    if(!write_queue[i].iserase)
-      pages += write_queue[i].pagecnt;
-    i++;
-    i %= write_queue_sz;
-    cnt--;
-  }
-
-  /* Count the size of the page lists */
-  list_for_each(temp, &mtd_rawdevice->as.clean_pages) {
-    clean++;
-  }
-  list_for_each(temp, &mtd_rawdevice->as.dirty_pages) {
-    dirty++;
-  }
-  list_for_each(temp, &mtd_rawdevice->as.locked_pages) {
-    locked++;
-  }
-
-  len = sprintf(page, "Write queue head: %d\nWrite queue tail: %d\n"
-		"Write queue count: %d\nPages in queue: %d (%dK)\n"
-		"Clean Pages: %d\nDirty Pages: %d\nLocked Pages: %d\n"
-		"nrpages: %ld\n",
-		write_queue_head, write_queue_tail, write_queue_cnt,
-		pages, pages << (PAGE_SHIFT-10), clean, dirty, locked,
-		mtd_rawdevice->as.nrpages);
-  if(len <= count)
-    *eof = 1;
-  spin_unlock(&mbd_writeq_lock);
-  MOD_DEC_USE_COUNT;
-  return len;
+	DEBUG(2, "blkmtd: free_device() dev = %p\n", dev);
+	if(dev) {
+		del_mtd_device(&dev->mtd_info);
+		info("mtd%d: [%s] removed", dev->mtd_info.index,
+		     dev->mtd_info.name + strlen("blkmtd: "));
+		if(dev->mtd_info.eraseregions)
+			kfree(dev->mtd_info.eraseregions);
+		if(dev->mtd_info.name)
+			kfree(dev->mtd_info.name);
+
+		if(dev->rd_buf) {
+			dev->rd_buf->locked = 0;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
+			if(dev->rd_buf->blocks)
+				kfree(dev->rd_buf->blocks);
+#endif
+			free_kiovec(1, &dev->rd_buf);
+		}
+		if(dev->wr_buf) {
+			dev->wr_buf->locked = 0;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)			
+			if(dev->wr_buf->blocks)
+				kfree(dev->rw_buf->blocks);
+#endif
+			free_kiovec(1, &dev->wr_buf);
+		}
+
+		if(dev->binding) {
+			kdev_t kdev = to_kdev_t(dev->binding->bd_dev);
+			invalidate_inode_pages(dev->binding->bd_inode);
+			set_blocksize(kdev, 1 << 10);
+			blkdev_put(dev->binding, BDEV_RAW);
+		}
+		kfree(dev);
+	}
 }
+
+
+/* For a given size and initial erase size, calculate the number
+ * and size of each erase region. Goes round the loop twice,
+ * once to find out how many regions, then allocates space,
+ * then round the loop again to fill it in.
+ */
+static struct mtd_erase_region_info *calc_erase_regions(
+	size_t erase_size, size_t total_size, int *regions)
+{
+	struct mtd_erase_region_info *info = NULL;
+
+	DEBUG(2, "calc_erase_regions, es = %d size = %d regions = %d\n",
+	      erase_size, total_size, *regions);
+	/* Make any user specified erasesize be a power of 2
+	   and at least PAGE_SIZE */
+	if(erase_size) {
+		int es = erase_size;
+		erase_size = 1;
+		while(es != 1) {
+			es >>= 1;
+			erase_size <<= 1;
+		}
+		if(erase_size < PAGE_SIZE)
+			erase_size = PAGE_SIZE;
+	} else {
+		erase_size = CONFIG_MTD_BLKDEV_ERASESIZE;
+	}
+
+	*regions = 0;
+
+	do {
+		int tot_size = total_size;
+		int er_size = erase_size;
+		int count = 0, offset = 0, regcnt = 0;
+
+		while(tot_size) {
+			count = tot_size / er_size;
+			if(count) {
+				tot_size = tot_size % er_size;
+				if(info) {
+					DEBUG(2, "adding to erase info off=%d er=%d cnt=%d\n",
+					      offset, er_size, count);
+					(info+regcnt)->offset = offset;
+					(info+regcnt)->erasesize = er_size;
+					(info+regcnt)->numblocks = count;
+					(*regions)++;
+				}
+				regcnt++;
+				offset += (count * er_size);
+			}
+			while(er_size > tot_size)
+				er_size >>= 1;
+		}
+		if(info == NULL) {
+			info = kmalloc(regcnt * sizeof(struct mtd_erase_region_info), GFP_KERNEL);
+			if(!info)
+				break;
+		}
+	} while(!(*regions));
+	DEBUG(2, "calc_erase_regions done, es = %d size = %d regions = %d\n",
+	      erase_size, total_size, *regions);
+	return info;
+}
+
+
+extern kdev_t name_to_kdev_t(char *line) __init;
+
+
+static struct blkmtd_dev *add_device(char *devname, int readonly, int erase_size)
+{
+	int maj, min;
+	kdev_t kdev;
+	int mode;
+	struct blkmtd_dev *dev;
+
+#ifdef MODULE
+	struct file *file = NULL;
+	struct inode *inode;
 #endif
 
+	if(!devname)
+		return NULL;
+
+	/* Get a handle on the device */
+	mode = (readonly) ? O_RDONLY : O_RDWR;
+
+#ifdef MODULE
+
+	file = filp_open(devname, mode, 0);
+	if(IS_ERR(file)) {
+		err("error: cant open device %s", devname);
+		DEBUG(2, "blkmtd: filp_open returned %ld\n", PTR_ERR(file));
+		return NULL;
+	}
+
+	/* determine is this is a block device and
+	 * if so get its major and minor numbers
+	 */
+	inode = file->f_dentry->d_inode;
+	if(!S_ISBLK(inode->i_mode)) {
+		err("%s not a block device", devname);
+		filp_close(file, NULL);
+		return NULL;
+	}
+	kdev = inode->i_rdev;
+	filp_close(file, NULL);
+#else
+	kdev = name_to_kdev_t(devname);
+#endif	/* MODULE */
+
+	if(!kdev) {
+		err("bad block device: `%s'", devname);
+		return NULL;
+	}
+
+	maj = MAJOR(kdev);
+	min = MINOR(kdev);
+	DEBUG(1, "blkmtd: found a block device major = %d, minor = %d\n",
+	      maj, min);
+
+	if(maj == MTD_BLOCK_MAJOR) {
+		err("attempting to use an MTD device as a block device");
+		return NULL;
+	}
+
+	DEBUG(1, "blkmtd: devname = %s\n", bdevname(kdev));
+
+	dev = kmalloc(sizeof(struct blkmtd_dev), GFP_KERNEL);
+	if(dev == NULL)
+		return NULL;
+
+	memset(dev, 0, sizeof(struct blkmtd_dev));
+	if(alloc_kiovec(1, &dev->rd_buf)) {
+		err("cant allocate read iobuf");
+		goto devinit_err;
+	}
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
+	dev->rd_buf->blocks = kmalloc(KIO_MAX_SECTORS * sizeof(unsigned long), GFP_KERNEL);
+	if(dev->rd_buf->blocks == NULL) {
+		crit("cant allocate rd_buf blocks");
+		goto devinit_err;
+	}
+#endif
+	
+	if(!readonly) {
+		if(alloc_kiovec(1, &dev->wr_buf)) {
+			err("cant allocate kiobuf - readonly enabled");
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
+		} else {
+			dev->wr_buf->blocks = kmalloc(KIO_MAX_SECTORS * sizeof(unsigned long), GFP_KERNEL);
+			if(dev->wr_buf->blocks == NULL) {
+				crit("cant allocate wr_buf blocks - readonly enabled");
+				free_kiovec(1, &iobuf);
+			}
+#endif
+		}
+		if(dev->wr_buf)
+			init_MUTEX(&dev->wrbuf_mutex);
+	}
+
+	/* get the block device */
+	dev->binding = bdget(kdev_t_to_nr(MKDEV(maj, min)));
+	if(blkdev_get(dev->binding, mode, 0, BDEV_RAW))
+		goto devinit_err;
+
+	if(set_blocksize(kdev, PAGE_SIZE)) {
+		err("cant set block size to PAGE_SIZE on %s", bdevname(kdev));
+		goto devinit_err;
+	}
+
+	dev->mtd_info.size = dev->binding->bd_inode->i_size & PAGE_MASK;
+
+	/* Setup the MTD structure */
+	/* make the name contain the block device in */
+	dev->mtd_info.name = kmalloc(sizeof("blkmtd: ") + strlen(devname), GFP_KERNEL);
+	if(dev->mtd_info.name == NULL)
+		goto devinit_err;
+
+	sprintf(dev->mtd_info.name, "blkmtd: %s", devname);
+	dev->mtd_info.eraseregions = calc_erase_regions(erase_size, dev->mtd_info.size,
+							&dev->mtd_info.numeraseregions);
+	if(dev->mtd_info.eraseregions == NULL)
+		goto devinit_err;
+
+	dev->mtd_info.erasesize = dev->mtd_info.eraseregions->erasesize;
+	DEBUG(1, "blkmtd: init: found %d erase regions\n",
+	      dev->mtd_info.numeraseregions);
+
+	if(readonly) {
+		dev->mtd_info.type = MTD_ROM;
+		dev->mtd_info.flags = MTD_CAP_ROM;
+	} else {
+		dev->mtd_info.type = MTD_RAM;
+		dev->mtd_info.flags = MTD_CAP_RAM;
+	}
+	dev->mtd_info.erase = blkmtd_erase;
+	dev->mtd_info.read = blkmtd_read;
+	dev->mtd_info.write = blkmtd_write;
+	dev->mtd_info.sync = blkmtd_sync;
+	dev->mtd_info.point = 0;
+	dev->mtd_info.unpoint = 0;
+	dev->mtd_info.priv = dev;
+	dev->mtd_info.module = THIS_MODULE;
+
+	list_add(&dev->list, &blkmtd_device_list);
+	if (add_mtd_device(&dev->mtd_info)) {
+		/* Device didnt get added, so free the entry */
+		list_del(&dev->list);
+		free_device(dev);
+		return NULL;
+	} else {
+		info("mtd%d: [%s] erase_size = %dKiB %s",
+		     dev->mtd_info.index, dev->mtd_info.name + strlen("blkmtd: "),
+		     dev->mtd_info.erasesize >> 10,
+		     (dev->wr_buf) ? "" : "(read-only)");
+	}
+	
+	return dev;
+
+ devinit_err:
+	free_device(dev);
+	return NULL;
+}
+
 
 /* Cleanup and exit - sync the device and kill of the kernel thread */
-static void __exit cleanup_blkmtd(void)
+static void __devexit cleanup_blkmtd(void)
 {
+	struct list_head *temp1, *temp2;
 #ifdef BLKMTD_PROC_DEBUG
-  if(blkmtd_proc) {
-    remove_proc_entry("blkmtd_debug", NULL);
-  }
+	if(blkmtd_proc) {
+		remove_proc_entry("blkmtd_debug", NULL);
+	}
 #endif
 
-  if (mtd_rawdevice) {
-    /* sync the device */
-    if (!mtd_rawdevice->readonly) {
-      blkmtd_sync(&mtd_rawdevice->mtd_info);
-      write_task_finish = 1;
-      wake_up_interruptible(&thr_wq);
-      down(&thread_sem);
-    }
-    del_mtd_device(&mtd_rawdevice->mtd_info);
-    if(mtd_rawdevice->binding != NULL)
-      blkdev_put(mtd_rawdevice->binding, BDEV_RAW);
-
-    if(mtd_rawdevice->mtd_info.eraseregions)
-      kfree(mtd_rawdevice->mtd_info.eraseregions);
-    if(mtd_rawdevice->mtd_info.name)
-      kfree(mtd_rawdevice->mtd_info.name);
-
-    kfree(mtd_rawdevice);
-  }
-  if(write_queue)
-    kfree(write_queue);
-
-  if(erase_page) {
-    UnlockPage(erase_page);
-    __free_pages(erase_page, 0);
-  }
-  printk("blkmtd: unloaded for %s\n", device);
+	/* Remove the MTD devices */
+	list_for_each_safe(temp1, temp2, &blkmtd_device_list) {
+		struct blkmtd_dev *dev = list_entry(temp1, struct blkmtd_dev,
+						    list);
+		blkmtd_sync(&dev->mtd_info);
+		free_device(dev);
+	}
 }
 
-extern struct module __this_module;
-
 #ifndef MODULE
 
 /* Handle kernel boot params */
@@ -982,335 +961,97 @@
 
 static int __init param_blkmtd_device(char *str)
 {
-  device = str;
-  return 1;
+	int i;
+
+	for(i = 0; i < MAX_DEVICES; i++) {
+		device[i] = str;
+		DEBUG(2, "blkmtd: device setup: %d = %s\n", i, device[i]);
+		strsep(&str, ",");
+	}
+	return 1;
 }
 
 
 static int __init param_blkmtd_erasesz(char *str)
 {
-  erasesz = simple_strtol(str, NULL, 0);
-  return 1;
+	int i;
+	for(i = 0; i < MAX_DEVICES; i++) {
+		char *val = strsep(&str, ",");
+		if(val)
+			erasesz[i] = simple_strtoul(val, NULL, 0);
+		DEBUG(2, "blkmtd: erasesz setup: %d = %d\n", i, erasesz[i]);
+	}
+
+	return 1;
 }
 
 
 static int __init param_blkmtd_ro(char *str)
 {
-  ro = simple_strtol(str, NULL, 0);
-  return 1;
-}
-
+	int i;
+	for(i = 0; i < MAX_DEVICES; i++) {
+		char *val = strsep(&str, ",");
+		if(val)
+			ro[i] = simple_strtoul(val, NULL, 0);
+		DEBUG(2, "blkmtd: ro setup: %d = %d\n", i, ro[i]);
+	}
 
-static int __init param_blkmtd_bs(char *str)
-{
-  bs = simple_strtol(str, NULL, 0);
-  return 1;
+	return 1;
 }
 
 
-static int __init param_blkmtd_count(char *str)
+static int __init param_blkmtd_sync(char *str)
 {
-  count = simple_strtol(str, NULL, 0);
-  return 1;
+	if(str[0] == '1')
+		sync = 1;
+	return 1;
 }
 
 __setup("blkmtd_device=", param_blkmtd_device);
 __setup("blkmtd_erasesz=", param_blkmtd_erasesz);
 __setup("blkmtd_ro=", param_blkmtd_ro);
-__setup("blkmtd_bs=", param_blkmtd_bs);
-__setup("blkmtd_count=", param_blkmtd_count);
+__setup("blkmtd_sync=", param_blkmtd_sync);
 
 #endif
 
 
-/* for a given size and initial erase size, calculate the number and size of each
-   erase region */
-static int __init calc_erase_regions(struct mtd_erase_region_info *info, size_t erase_size, size_t total_size)
-{
-  int count = 0;
-  int offset = 0;
-  int regions = 0;
-
-   while(total_size) {
-     count = total_size / erase_size;
-     if(count) {
-       total_size = total_size % erase_size;
-       if(info) {
-	 info->offset = offset;
-	 info->erasesize = erase_size;
-	 info->numblocks = count;
-	 info++;
-       }
-       offset += (count * erase_size);
-       regions++;
-     }
-     while(erase_size > total_size)
-       erase_size >>= 1;
-   }
-   return regions;
-}
-
-
-extern kdev_t name_to_kdev_t(char *line) __init;
-
 /* Startup */
 static int __init init_blkmtd(void)
 {
-#ifdef MODULE
-  struct file *file = NULL;
-  struct inode *inode;
-#endif
+	int i;
 
-  int maj, min;
-  int i, blocksize, blocksize_bits;
-  loff_t size = 0;
-  int readonly = 0;
-  int erase_size = CONFIG_MTD_BLKDEV_ERASESIZE;
-  kdev_t rdev;
-  int err;
-  int mode;
-  int regions;
-
-  /* Check args */
-  if(device == 0) {
-    printk("blkmtd: error, missing `device' name\n");
-    return -EINVAL;
-  }
-
-  if(ro)
-    readonly = 1;
-
-  if(erasesz)
-    erase_size = erasesz;
-
-  if(wqs) {
-    if(wqs < 16) 
-      wqs = 16;
-    if(wqs > 4*WRITE_QUEUE_SZ)
-      wqs = 4*WRITE_QUEUE_SZ;
-    write_queue_sz = wqs;
-  }
-
-  DEBUG(1, "blkmtd: device = `%s' erase size = %dK readonly = %s queue size = %d\n",
-	device, erase_size, readonly ? "yes" : "no", write_queue_sz);
-  /* Get a handle on the device */
-  mode = (readonly) ? O_RDONLY : O_RDWR;
-
-#ifdef MODULE
+	/* Check args - device[0] is the bare minimum*/
+	if(!device[0]) {
+		err("error: missing `device' name\n");
+		return -EINVAL;
+	}
 
-  file = filp_open(device, mode, 0);
-  if(IS_ERR(file)) {
-    printk("blkmtd: error, cant open device %s\n", device);
-    DEBUG(2, "blkmtd: filp_open returned %ld\n", PTR_ERR(file));
-    return 1;
-  }
-  
-  /* determine is this is a block device and if so get its major and minor
-     numbers */
-  inode = file->f_dentry->d_inode;
-  if(!S_ISBLK(inode->i_mode)) {
-    printk("blkmtd: %s not a block device\n", device);
-    filp_close(file, NULL);
-    return 1;
-  }
-  rdev = inode->i_rdev;
-  filp_close(file, NULL);
-#else
-  rdev = name_to_kdev_t(device);
-#endif
+	for(i = 0; i < MAX_DEVICES; i++)
+		add_device(device[i], ro[i], erasesz[i] << 10);
 
-  maj = MAJOR(rdev);
-  min = MINOR(rdev);
-  DEBUG(1, "blkmtd: found a block device major = %d, minor = %d\n", maj, min);
-
-  if(!rdev) {
-    printk("blkmtd: bad block device: `%s'\n", device);
-    return 1;
-  }
-
-  if(maj == MTD_BLOCK_MAJOR) {
-    printk("blkmtd: attempting to use an MTD device as a block device\n");
-    return 1;
-  }
-
-  DEBUG(1, "blkmtd: devname = %s\n", bdevname(rdev));
-  blocksize = BLOCK_SIZE;
-
-  if(bs) {
-    blocksize = bs;
-  } else {
-    if (blksize_size[maj] && blksize_size[maj][min]) {
-      DEBUG(2, "blkmtd: blksize_size = %d\n", blksize_size[maj][min]);
-      blocksize = blksize_size[maj][min];
-    }
-  }
-  i = blocksize;
-  blocksize_bits = 0;
-  while(i != 1) {
-    blocksize_bits++;
-    i >>= 1;
-  }
-
-  if(count) {
-    size = count;
-  } else {
-    if (blk_size[maj]) {
-      size = ((loff_t) blk_size[maj][min] << BLOCK_SIZE_BITS) >> blocksize_bits;
-    }
-  }
-  size *= blocksize;
-  DEBUG(1, "blkmtd: size = %ld\n", (long int)size);
-
-  if(size == 0) {
-    printk("blkmtd: cant determine size\n");
-    return 1;
-  }
-
-  mtd_rawdevice = (mtd_raw_dev_data_t *)kmalloc(sizeof(mtd_raw_dev_data_t), GFP_KERNEL);
-  if(mtd_rawdevice == NULL) {
-    err = -ENOMEM;
-    goto init_err;
-  }
-  memset(mtd_rawdevice, 0, sizeof(mtd_raw_dev_data_t));
-  /* get the block device */
-  mtd_rawdevice->binding = bdget(kdev_t_to_nr(MKDEV(maj, min)));
-  err = blkdev_get(mtd_rawdevice->binding, mode, 0, BDEV_RAW);
-  if (err) {
-    goto init_err;
-  }
-  mtd_rawdevice->totalsize = size;
-  mtd_rawdevice->sector_size = blocksize;
-  mtd_rawdevice->sector_bits = blocksize_bits;
-  mtd_rawdevice->readonly = readonly;
-
-  /* See if device ends on page boundary */
-  if(size % PAGE_SIZE) {
-    mtd_rawdevice->partial_last_page = size >> PAGE_SHIFT;
-    mtd_rawdevice->last_page_sectors = (size & (PAGE_SIZE-1)) >> blocksize_bits;
-  }
-
-  DEBUG(2, "sector_size = %d, sector_bits = %d, partial_last_page = %d last_page_sectors = %d\n", 
-	mtd_rawdevice->sector_size, mtd_rawdevice->sector_bits,
-	mtd_rawdevice->partial_last_page, mtd_rawdevice->last_page_sectors);
-
-  /* Setup the MTD structure */
-  /* make the name contain the block device in */
-  mtd_rawdevice->mtd_info.name = kmalloc(9 + strlen(device), GFP_KERNEL);
-  if(mtd_rawdevice->mtd_info.name == NULL)
-    goto init_err;
-
-  sprintf(mtd_rawdevice->mtd_info.name, "blkmtd: %s", device);
-  if(readonly) {
-    mtd_rawdevice->mtd_info.type = MTD_ROM;
-    mtd_rawdevice->mtd_info.flags = MTD_CAP_ROM;
-    mtd_rawdevice->mtd_info.erasesize = erase_size << 10;
-  } else {
-    mtd_rawdevice->mtd_info.type = MTD_RAM;
-    mtd_rawdevice->mtd_info.flags = MTD_CAP_RAM;
-    mtd_rawdevice->mtd_info.erasesize = erase_size << 10;
-  }
-  mtd_rawdevice->mtd_info.size = size;
-  mtd_rawdevice->mtd_info.erase = blkmtd_erase;
-  mtd_rawdevice->mtd_info.read = blkmtd_read;
-  mtd_rawdevice->mtd_info.write = blkmtd_write;
-  mtd_rawdevice->mtd_info.sync = blkmtd_sync;
-  mtd_rawdevice->mtd_info.point = 0;
-  mtd_rawdevice->mtd_info.unpoint = 0;
-
-  mtd_rawdevice->mtd_info.priv = mtd_rawdevice;
-  regions = calc_erase_regions(NULL, erase_size << 10, size);
-  DEBUG(1, "blkmtd: init: found %d erase regions\n", regions);
-  mtd_rawdevice->mtd_info.eraseregions = kmalloc(regions * sizeof(struct mtd_erase_region_info), GFP_KERNEL);
-  if(mtd_rawdevice->mtd_info.eraseregions == NULL) {
-    err = -ENOMEM;
-    goto init_err;
-  }
-  mtd_rawdevice->mtd_info.numeraseregions = regions;
-  calc_erase_regions(mtd_rawdevice->mtd_info.eraseregions, erase_size << 10, size);
-
-  /* setup the page cache info */
-  
-  mtd_rawdevice->as.nrpages = 0;
-  INIT_LIST_HEAD(&mtd_rawdevice->as.clean_pages);
-  INIT_LIST_HEAD(&mtd_rawdevice->as.dirty_pages);
-  INIT_LIST_HEAD(&mtd_rawdevice->as.locked_pages);
-  mtd_rawdevice->as.host = NULL;
-  spin_lock_init(&(mtd_rawdevice->as.i_shared_lock));
-
-  mtd_rawdevice->as.a_ops = &blkmtd_aops;
-  mtd_rawdevice->as.i_mmap = NULL;
-  mtd_rawdevice->as.i_mmap_shared = NULL;
-  mtd_rawdevice->as.gfp_mask = GFP_KERNEL;
+	if(list_empty(&blkmtd_device_list))
+		goto init_err;
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-  mtd_rawdevice->mtd_info.module = THIS_MODULE;			
-#endif
-  if (add_mtd_device(&mtd_rawdevice->mtd_info)) {
-    err = -EIO;
-    goto init_err;
-  }
-
-  if(!mtd_rawdevice->readonly) {
-    /* Allocate the write queue */
-    write_queue = kmalloc(write_queue_sz * sizeof(mtdblkdev_write_queue_t), GFP_KERNEL);
-    if(!write_queue) {
-      err = -ENOMEM;
-      goto init_err;
-    }
-    /* Set up the erase page */
-    erase_page = alloc_pages(GFP_KERNEL, 0);
-    if(erase_page == NULL) {
-      err = -ENOMEM;
-      goto init_err;
-    }
-    memset(page_address(erase_page), 0xff, PAGE_SIZE);
-    lock_page(erase_page);
-
-    init_waitqueue_head(&thr_wq);
-    init_waitqueue_head(&mtbd_sync_wq);
-    DEBUG(3, "blkmtd: init: kernel task @ %p\n", write_queue_task);
-    DEBUG(2, "blkmtd: init: starting kernel task\n");
-    kernel_thread(write_queue_task, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
-    DEBUG(2, "blkmtd: init: started\n");
-    printk("blkmtd loaded: version = %s using %s erase_size = %dK %s\n",
-	   VERSION, device, erase_size, (readonly) ? "(read-only)" : "");
-  }
+	info("version " VERSION);
 
 #ifdef BLKMTD_PROC_DEBUG
-  /* create proc entry */
-  DEBUG(2, "Creating /proc/blkmtd_debug\n");
-  blkmtd_proc = create_proc_read_entry("blkmtd_debug", 0444,
-				       NULL, blkmtd_proc_read, NULL);
-  if(blkmtd_proc == NULL) {
-    printk("Cant create /proc/blkmtd_debug\n");
-  } else {
-    blkmtd_proc->owner = THIS_MODULE;
-  }
+	/* create proc entry */
+	DEBUG(2, "Creating /proc/blkmtd_debug\n");
+	blkmtd_proc = create_proc_read_entry("blkmtd_debug", 0444,
+					     NULL, blkmtd_proc_read, NULL);
+	if(blkmtd_proc == NULL) {
+		err("Cant create /proc/blkmtd_debug");
+	} else {
+		blkmtd_proc->owner = THIS_MODULE;
+	}
 #endif
-  
-  /* Everything is ok if we got here */
-  return 0;
-  
- init_err:
 
-  if(mtd_rawdevice) {
-    if(mtd_rawdevice->mtd_info.eraseregions)
-      kfree(mtd_rawdevice->mtd_info.eraseregions);
-    if(mtd_rawdevice->mtd_info.name)
-      kfree(mtd_rawdevice->mtd_info.name);
-    if(mtd_rawdevice->binding) 
-      blkdev_put(mtd_rawdevice->binding, BDEV_RAW);
-    kfree(mtd_rawdevice);
-  }
-
-  if(write_queue) {
-    kfree(write_queue);
-    write_queue = NULL;
-  }
-
-  if(erase_page) 
-    __free_pages(erase_page, 0);
-  return err;
+	if(!list_empty(&blkmtd_device_list))
+		/* Everything is ok if we got here */
+		return 0;
+
+ init_err:
+	return -EINVAL;
 }
 
 module_init(init_blkmtd);
diff -urN linux-2.4.21-pre3/drivers/mtd/devices/doc1000.c linux-2.4.21-pre4/drivers/mtd/devices/doc1000.c
--- linux-2.4.21-pre3/drivers/mtd/devices/doc1000.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.21-pre4/drivers/mtd/devices/doc1000.c	Tue Jan 28 19:44:30 2003
@@ -1,6 +1,6 @@
 /*======================================================================
 
-  $Id: doc1000.c,v 1.16 2001/12/28 22:45:17 dwmw2 Exp $
+  $Id: doc1000.c,v 1.17 2003/01/24 13:33:20 dwmw2 Exp $
 
 ======================================================================*/
 
@@ -20,8 +20,6 @@
 #include <linux/ioctl.h>
 #include <asm/io.h>
 #include <asm/system.h>
-#include <asm/segment.h>
-#include <stdarg.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 
diff -urN linux-2.4.21-pre3/drivers/mtd/devices/doc2000.c linux-2.4.21-pre4/drivers/mtd/devices/doc2000.c
--- linux-2.4.21-pre3/drivers/mtd/devices/doc2000.c	Thu Oct  4 15:14:59 2001
+++ linux-2.4.21-pre4/drivers/mtd/devices/doc2000.c	Tue Jan 28 19:44:30 2003
@@ -4,7 +4,7 @@
  * (c) 1999 Machine Vision Holdings, Inc.
  * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
  *
- * $Id: doc2000.c,v 1.46 2001/10/02 15:05:13 dwmw2 Exp $
+ * $Id: doc2000.c,v 1.50 2002/12/10 15:05:42 gleixner Exp $
  */
 
 #include <linux/kernel.h>
@@ -22,7 +22,6 @@
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
-#include <linux/mtd/nand_ids.h>
 #include <linux/mtd/doc2000.h>
 
 #define DOC_SUPPORT_2000
@@ -54,9 +53,9 @@
 static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
 		     size_t *retlen, const u_char *buf);
 static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
-			size_t *retlen, u_char *buf, u_char *eccbuf);
+			size_t *retlen, u_char *buf, u_char *eccbuf, int oobsel);
 static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
-			 size_t *retlen, const u_char *buf, u_char *eccbuf);
+			 size_t *retlen, const u_char *buf, u_char *eccbuf, int oobsel);
 static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
 			size_t *retlen, u_char *buf);
 static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
@@ -97,12 +96,8 @@
 			DEBUG(MTD_DEBUG_LEVEL2, "_DoC_WaitReady timed out.\n");
 			return -EIO;
 		}
-		if (current->need_resched) {
-			set_current_state(TASK_UNINTERRUPTIBLE);
-			schedule_timeout(1);
-		}
-		else
-			udelay(1);
+		udelay(1);
+		cond_resched();
 	}
 
 	return 0;
@@ -320,7 +315,7 @@
 
 static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip)
 {
-	int mfr, id, i;
+	int mfr, id, i, j;
 	volatile char dummy;
 
 	/* Page in the required floor/chip */
@@ -378,12 +373,16 @@
 
 	/* Print and store the manufacturer and ID codes. */
 	for (i = 0; nand_flash_ids[i].name != NULL; i++) {
-		if (mfr == nand_flash_ids[i].manufacture_id &&
-		    id == nand_flash_ids[i].model_id) {
+		if (id == nand_flash_ids[i].id) {
+			/* Try to identify manufacturer */
+			for (j = 0; nand_manuf_ids[j].id != 0x0; j++) {
+				if (nand_manuf_ids[j].id == mfr)
+					break;
+			}	
 			printk(KERN_INFO
 			       "Flash chip found: Manufacturer ID: %2.2X, "
-			       "Chip ID: %2.2X (%s)\n", mfr, id,
-			       nand_flash_ids[i].name);
+			       "Chip ID: %2.2X (%s:%s)\n", mfr, id,
+			       nand_manuf_ids[j].name, nand_flash_ids[i].name);
 			if (!doc->mfr) {
 				doc->mfr = mfr;
 				doc->id = id;
@@ -391,7 +390,7 @@
 				    nand_flash_ids[i].chipshift;
 				doc->page256 = nand_flash_ids[i].page256;
 				doc->pageadrlen =
-				    nand_flash_ids[i].pageadrlen;
+				    nand_flash_ids[i].chipshift > 25 ? 3 : 2;
 				doc->erasesize =
 				    nand_flash_ids[i].erasesize;
 				return 1;
@@ -597,11 +596,11 @@
 		    size_t * retlen, u_char * buf)
 {
 	/* Just a special case of doc_read_ecc */
-	return doc_read_ecc(mtd, from, len, retlen, buf, NULL);
+	return doc_read_ecc(mtd, from, len, retlen, buf, NULL, 0);
 }
 
 static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
-			size_t * retlen, u_char * buf, u_char * eccbuf)
+			size_t * retlen, u_char * buf, u_char * eccbuf, int oobsel)
 {
 	struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
 	unsigned long docptr;
@@ -745,12 +744,12 @@
 		     size_t * retlen, const u_char * buf)
 {
 	char eccbuf[6];
-	return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf);
+	return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, 0);
 }
 
 static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
 			 size_t * retlen, const u_char * buf,
-			 u_char * eccbuf)
+			 u_char * eccbuf, int oobsel)
 {
 	struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
 	int di; /* Yes, DI is a hangover from when I was disassembling the binary driver */
diff -urN linux-2.4.21-pre3/drivers/mtd/devices/doc2001.c linux-2.4.21-pre4/drivers/mtd/devices/doc2001.c
--- linux-2.4.21-pre3/drivers/mtd/devices/doc2001.c	Thu Oct  4 15:14:59 2001
+++ linux-2.4.21-pre4/drivers/mtd/devices/doc2001.c	Tue Jan 28 19:44:30 2003
@@ -4,7 +4,7 @@
  * (c) 1999 Machine Vision Holdings, Inc.
  * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
  *
- * $Id: doc2001.c,v 1.35 2001/10/02 15:05:13 dwmw2 Exp $
+ * $Id: doc2001.c,v 1.38 2002/12/10 15:05:42 gleixner Exp $
  */
 
 #include <linux/kernel.h>
@@ -22,7 +22,6 @@
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
-#include <linux/mtd/nand_ids.h>
 #include <linux/mtd/doc2000.h>
 
 /* #define ECC_DEBUG */
@@ -38,9 +37,9 @@
 static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
 		     size_t *retlen, const u_char *buf);
 static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
-			size_t *retlen, u_char *buf, u_char *eccbuf);
+			size_t *retlen, u_char *buf, u_char *eccbuf, int oobsel);
 static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
-			 size_t *retlen, const u_char *buf, u_char *eccbuf);
+			 size_t *retlen, const u_char *buf, u_char *eccbuf, int oobsel);
 static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
 			size_t *retlen, u_char *buf);
 static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
@@ -182,7 +181,7 @@
 /* DoC_IdentChip: Identify a given NAND chip given {floor,chip} */
 static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip)
 {
-	int mfr, id, i;
+	int mfr, id, i, j;
 	volatile char dummy;
 
 	/* Page in the required floor/chip
@@ -216,11 +215,15 @@
 
 	/* FIXME: to deal with multi-flash on multi-Millennium case more carefully */
 	for (i = 0; nand_flash_ids[i].name != NULL; i++) {
-		if (mfr == nand_flash_ids[i].manufacture_id &&
-		    id == nand_flash_ids[i].model_id) {
+		if ( id == nand_flash_ids[i].id) {
+			/* Try to identify manufacturer */
+			for (j = 0; nand_manuf_ids[j].id != 0x0; j++) {
+				if (nand_manuf_ids[j].id == mfr)
+					break;
+			}	
 			printk(KERN_INFO "Flash chip found: Manufacturer ID: %2.2X, "
-			       "Chip ID: %2.2X (%s)\n",
-			       mfr, id, nand_flash_ids[i].name);
+			       "Chip ID: %2.2X (%s:%s)\n",
+			       mfr, id, nand_manuf_ids[j].name, nand_flash_ids[i].name);
 			doc->mfr = mfr;
 			doc->id = id;
 			doc->chipshift = nand_flash_ids[i].chipshift;
@@ -399,11 +402,11 @@
 		     size_t *retlen, u_char *buf)
 {
 	/* Just a special case of doc_read_ecc */
-	return doc_read_ecc(mtd, from, len, retlen, buf, NULL);
+	return doc_read_ecc(mtd, from, len, retlen, buf, NULL, 0);
 }
 
 static int doc_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
-			 size_t *retlen, u_char *buf, u_char *eccbuf)
+			 size_t *retlen, u_char *buf, u_char *eccbuf, int oobsel)
 {
 	int i, ret;
 	volatile char dummy;
@@ -525,11 +528,11 @@
 		      size_t *retlen, const u_char *buf)
 {
 	char eccbuf[6];
-	return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf);
+	return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, 0);
 }
 
 static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
-			  size_t *retlen, const u_char *buf, u_char *eccbuf)
+			  size_t *retlen, const u_char *buf, u_char *eccbuf, int oobsel)
 {
 	int i,ret = 0;
 	volatile char dummy;
diff -urN linux-2.4.21-pre3/drivers/mtd/devices/docprobe.c linux-2.4.21-pre4/drivers/mtd/devices/docprobe.c
--- linux-2.4.21-pre3/drivers/mtd/devices/docprobe.c	Thu Oct  4 15:14:59 2001
+++ linux-2.4.21-pre4/drivers/mtd/devices/docprobe.c	Tue Jan 28 19:44:30 2003
@@ -1,9 +1,10 @@
 
 /* Linux driver for Disk-On-Chip devices			*/
 /* Probe routines common to all DoC devices			*/
-/* (c) 1999 Machine Vision Holdings, Inc.			*/
-/* Author: David Woodhouse <dwmw2@infradead.org>		*/
-/* $Id: docprobe.c,v 1.30 2001/10/02 15:05:13 dwmw2 Exp $	*/
+/* (C) 1999 Machine Vision Holdings, Inc.			*/
+/* (C) 1999-2003 David Woodhouse <dwmw2@infradead.org>		*/
+
+/* $Id: docprobe.c,v 1.33 2003/01/24 14:02:47 dwmw2 Exp $	*/
 
 
 
@@ -67,7 +68,7 @@
 
 static unsigned long doc_config_location = CONFIG_MTD_DOCPROBE_ADDRESS;
 MODULE_PARM(doc_config_location, "l");
-
+MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe for DiskOnChip");
 
 static unsigned long __initdata doc_locations[] = {
 #if defined (__alpha__) || defined(__i386__) || defined(__x86_64__)
@@ -84,11 +85,14 @@
 	0xe0000, 0xe2000, 0xe4000, 0xe6000, 
 	0xe8000, 0xea000, 0xec000, 0xee000,
 #endif /*  CONFIG_MTD_DOCPROBE_HIGH */
-#elif defined(__ppc__)
+#elif defined(__PPC__)
 	0xe4000000,
 #elif defined(CONFIG_MOMENCO_OCELOT)
 	0x2f000000,
-#else
+        0xff000000,
+#elif defined(CONFIG_MOMENCO_OCELOT_G) || defined (CONFIG_MOMENCO_OCELOT_C)
+        0xff000000,
+##else
 #warning Unknown architecture for DiskOnChip. No default probe locations defined
 #endif
 	0 };
diff -urN linux-2.4.21-pre3/drivers/mtd/devices/ms02-nv.c linux-2.4.21-pre4/drivers/mtd/devices/ms02-nv.c
--- linux-2.4.21-pre3/drivers/mtd/devices/ms02-nv.c	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre4/drivers/mtd/devices/ms02-nv.c	Tue Jan 28 19:44:30 2003
@@ -5,6 +5,8 @@
  *      modify it under the terms of the GNU General Public License
  *      as published by the Free Software Foundation; either version
  *      2 of the License, or (at your option) any later version.
+ *
+ *	$Id: ms02-nv.c,v 1.2 2003/01/24 14:05:17 dwmw2 Exp $
  */
 
 #include <linux/init.h>
@@ -296,6 +298,7 @@
 			stride = 2;
 		break;
 	case MACH_DS5000_2X0:
+	case MACH_DS5000:
 		csr = (volatile u32 *)KN03_MCR_BASE;
 		if (*csr & KN03_MCR_BNK32M)
 			stride = 2;
diff -urN linux-2.4.21-pre3/drivers/mtd/devices/mtdram.c linux-2.4.21-pre4/drivers/mtd/devices/mtdram.c
--- linux-2.4.21-pre3/drivers/mtd/devices/mtdram.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.21-pre4/drivers/mtd/devices/mtdram.c	Tue Jan 28 19:44:30 2003
@@ -1,6 +1,6 @@
 /*
  * mtdram - a test mtd device
- * $Id: mtdram.c,v 1.26 2001/12/01 10:24:18 dwmw2 Exp $
+ * $Id: mtdram.c,v 1.29 2002/10/21 13:40:06 jocke Exp $
  * Author: Alexander Larsson <alex@cendio.se>
  *
  * Copyright (c) 1999 Alexander Larsson <alex@cendio.se>
@@ -28,7 +28,9 @@
 static unsigned long total_size = CONFIG_MTDRAM_TOTAL_SIZE;
 static unsigned long erase_size = CONFIG_MTDRAM_ERASE_SIZE;
 MODULE_PARM(total_size,"l");
+MODULE_PARM_DESC(total_size, "Total device size in KiB");
 MODULE_PARM(erase_size,"l");
+MODULE_PARM_DESC(erase_size, "Device erase block size in KiB");
 #define MTDRAM_TOTAL_SIZE (total_size * 1024)
 #define MTDRAM_ERASE_SIZE (erase_size * 1024)
 #else
@@ -69,7 +71,8 @@
   return 0;
 }
 
-static void ram_unpoint (struct mtd_info *mtd, u_char *addr)
+static void ram_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from,
+			 size_t len)
 {
   DEBUG(MTD_DEBUG_LEVEL2, "ram_unpoint\n");
 }
@@ -108,65 +111,119 @@
 {
   if (mtd_info) {
     del_mtd_device(mtd_info);
+#if CONFIG_MTDRAM_TOTAL_SIZE > 0
     if (mtd_info->priv)
 #if CONFIG_MTDRAM_ABS_POS > 0
       iounmap(mtd_info->priv);
 #else
       vfree(mtd_info->priv);
 #endif	
+#endif
     kfree(mtd_info);
   }
 }
 
+int mtdram_init_device(struct mtd_info *mtd, void *mapped_address, 
+                       unsigned long size, char *name)
+{
+   memset(mtd, 0, sizeof(*mtd));
+
+   /* Setup the MTD structure */
+   mtd->name = name;
+   mtd->type = MTD_RAM;
+   mtd->flags = MTD_CAP_RAM;
+   mtd->size = size;
+   mtd->erasesize = MTDRAM_ERASE_SIZE;
+   mtd->priv = mapped_address;
+
+   mtd->module = THIS_MODULE;
+   mtd->erase = ram_erase;
+   mtd->point = ram_point;
+   mtd->unpoint = ram_unpoint;
+   mtd->read = ram_read;
+   mtd->write = ram_write;
+
+   if (add_mtd_device(mtd)) {
+     return -EIO;
+   }
+   
+   return 0;
+}
+
+#if CONFIG_MTDRAM_TOTAL_SIZE > 0
+#if CONFIG_MTDRAM_ABS_POS > 0
 int __init init_mtdram(void)
 {
-   // Allocate some memory
+  void *addr;
+  int err;
+  /* Allocate some memory */
    mtd_info = (struct mtd_info *)kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
    if (!mtd_info)
-      return -ENOMEM;
+     return -ENOMEM;
    
-   memset(mtd_info, 0, sizeof(*mtd_info));
+  addr = ioremap(CONFIG_MTDRAM_ABS_POS, MTDRAM_TOTAL_SIZE);
+  if (!addr) {
+    DEBUG(MTD_DEBUG_LEVEL1, 
+          "Failed to ioremap) memory region of size %ld at ABS_POS:%ld\n", 
+          (long)MTDRAM_TOTAL_SIZE, (long)CONFIG_MTDRAM_ABS_POS);
+    kfree(mtd_info);
+    mtd_info = NULL;
+    return -ENOMEM;
+  }
+  err = mtdram_init_device(mtd_info, addr, 
+                           MTDRAM_TOTAL_SIZE, "mtdram test device");
+  if (err) 
+  {
+    iounmap(addr);
+    kfree(mtd_info);
+    mtd_info = NULL;
+    return err;
+  }
+  memset(mtd_info->priv, 0xff, MTDRAM_TOTAL_SIZE);
+  return err;
+}
 
-   // Setup the MTD structure
-   mtd_info->name = "mtdram test device";
-   mtd_info->type = MTD_RAM;
-   mtd_info->flags = MTD_CAP_RAM;
-   mtd_info->size = MTDRAM_TOTAL_SIZE;
-   mtd_info->erasesize = MTDRAM_ERASE_SIZE;
-#if CONFIG_MTDRAM_ABS_POS > 0
-   mtd_info->priv = ioremap(CONFIG_MTDRAM_ABS_POS, MTDRAM_TOTAL_SIZE);
-#else
-   mtd_info->priv = vmalloc(MTDRAM_TOTAL_SIZE);
-#endif
+#else /* CONFIG_MTDRAM_ABS_POS > 0 */
 
-   if (!mtd_info->priv) {
-     DEBUG(MTD_DEBUG_LEVEL1, "Failed to vmalloc(/ioremap) memory region of size %ld (ABS_POS:%ld)\n", (long)MTDRAM_TOTAL_SIZE, (long)CONFIG_MTDRAM_ABS_POS);
-     kfree(mtd_info);
-     mtd_info = NULL;
+int __init init_mtdram(void)
+{
+  void *addr;
+  int err;
+  /* Allocate some memory */
+   mtd_info = (struct mtd_info *)kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
+   if (!mtd_info)
      return -ENOMEM;
-   }
-   memset(mtd_info->priv, 0xff, MTDRAM_TOTAL_SIZE);
 
-   mtd_info->module = THIS_MODULE;			
-   mtd_info->erase = ram_erase;
-   mtd_info->point = ram_point;
-   mtd_info->unpoint = ram_unpoint;
-   mtd_info->read = ram_read;
-   mtd_info->write = ram_write;
+  addr = vmalloc(MTDRAM_TOTAL_SIZE);
+  if (!addr) {
+    DEBUG(MTD_DEBUG_LEVEL1, 
+          "Failed to vmalloc memory region of size %ld\n", 
+          (long)MTDRAM_TOTAL_SIZE);
+    kfree(mtd_info);
+    mtd_info = NULL;
+    return -ENOMEM;
+  }
+  err = mtdram_init_device(mtd_info, addr, 
+                           MTDRAM_TOTAL_SIZE, "mtdram test device");
+  if (err) 
+  {
+    vfree(addr);
+    kfree(mtd_info);
+    mtd_info = NULL;
+    return err;
+  }
+  memset(mtd_info->priv, 0xff, MTDRAM_TOTAL_SIZE);
+  return err;
+}
+#endif /* !(CONFIG_MTDRAM_ABS_POS > 0) */
 
-   if (add_mtd_device(mtd_info)) {
-#if CONFIG_MTDRAM_ABS_POS > 0
-     iounmap(mtd_info->priv);
-#else
-     vfree(mtd_info->priv);
-#endif	
-     kfree(mtd_info);
-     mtd_info = NULL;
-     return -EIO;
-   }
-   
-   return 0;
+#else /* CONFIG_MTDRAM_TOTAL_SIZE > 0 */
+
+int __init init_mtdram(void)
+{
+  return 0;
 }
+#endif /* !(CONFIG_MTDRAM_TOTAL_SIZE > 0) */
 
 module_init(init_mtdram);
 module_exit(cleanup_mtdram);
diff -urN linux-2.4.21-pre3/drivers/mtd/devices/pmc551.c linux-2.4.21-pre4/drivers/mtd/devices/pmc551.c
--- linux-2.4.21-pre3/drivers/mtd/devices/pmc551.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.21-pre4/drivers/mtd/devices/pmc551.c	Tue Jan 28 19:44:30 2003
@@ -1,5 +1,5 @@
 /*
- * $Id: pmc551.c,v 1.20 2002/03/05 13:47:08 dwmw2 Exp $
+ * $Id: pmc551.c,v 1.22 2003/01/24 13:34:30 dwmw2 Exp $
  *
  * PMC551 PCI Mezzanine Ram Device
  *
@@ -98,8 +98,6 @@
 #include <linux/ioctl.h>
 #include <asm/io.h>
 #include <asm/system.h>
-#include <asm/segment.h>
-#include <stdarg.h>
 #include <linux/pci.h>
 
 #ifndef CONFIG_PCI
@@ -216,7 +214,7 @@
 }
 
 
-static void pmc551_unpoint (struct mtd_info *mtd, u_char *addr)
+static void pmc551_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
 {
 #ifdef CONFIG_MTD_PMC551_DEBUG
 	printk(KERN_DEBUG "pmc551_unpoint()\n");
diff -urN linux-2.4.21-pre3/drivers/mtd/devices/slram.c linux-2.4.21-pre4/drivers/mtd/devices/slram.c
--- linux-2.4.21-pre3/drivers/mtd/devices/slram.c	Thu Oct  4 15:14:59 2001
+++ linux-2.4.21-pre4/drivers/mtd/devices/slram.c	Tue Jan 28 19:44:30 2003
@@ -1,6 +1,32 @@
 /*======================================================================
 
-  $Id: slram.c,v 1.25 2001/10/02 15:05:13 dwmw2 Exp $
+  $Id: slram.c,v 1.28 2003/01/24 13:35:34 dwmw2 Exp $
+
+  This driver provides a method to access memory not used by the kernel
+  itself (i.e. if the kernel commandline mem=xxx is used). To actually
+  use slram at least mtdblock or mtdchar is required (for block or
+  character device access).
+
+  Usage:
+
+  if compiled as loadable module:
+    modprobe slram map=<name>,<start>,<end/offset>
+  if statically linked into the kernel use the following kernel cmd.line
+    slram=<name>,<start>,<end/offset>
+
+  <name>: name of the device that will be listed in /proc/mtd
+  <start>: start of the memory region, decimal or hex (0xabcdef)
+  <end/offset>: end of the memory region. It's possible to use +0x1234
+                to specify the offset instead of the absolute address
+    
+  NOTE:
+  With slram it's only possible to map a contigous memory region. Therfore
+  if there's a device mapped somewhere in the region specified slram will
+  fail to load (see kernel log if modprobe fails).
+
+  -
+  
+  Jochen Schaeuble <psionic@psionic.de>
 
 ======================================================================*/
 
@@ -20,8 +46,6 @@
 #include <linux/init.h>
 #include <asm/io.h>
 #include <asm/system.h>
-#include <asm/segment.h>
-#include <stdarg.h>
 
 #include <linux/mtd/mtd.h>
 
@@ -53,7 +77,7 @@
 
 int slram_erase(struct mtd_info *, struct erase_info *);
 int slram_point(struct mtd_info *, loff_t, size_t, size_t *, u_char **);
-void slram_unpoint(struct mtd_info *, u_char *);
+void slram_unpoint(struct mtd_info *, u_char *, loff_t,	size_t);
 int slram_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *);
 int slram_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
 
@@ -94,7 +118,7 @@
 	return(0);
 }
 
-void slram_unpoint(struct mtd_info *mtd, u_char *addr)
+void slram_unpoint(struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
 {
 }
 
@@ -177,7 +201,7 @@
 	(*curmtd)->mtdinfo->write = slram_write;
 	(*curmtd)->mtdinfo->module = THIS_MODULE;
 	(*curmtd)->mtdinfo->type = MTD_RAM;
-	(*curmtd)->mtdinfo->erasesize = 0x10000;
+	(*curmtd)->mtdinfo->erasesize = 0x0;
 
 	if (add_mtd_device((*curmtd)->mtdinfo))	{
 		E("slram: Failed to register new device\n");
diff -urN linux-2.4.21-pre3/drivers/mtd/ftl.c linux-2.4.21-pre4/drivers/mtd/ftl.c
--- linux-2.4.21-pre3/drivers/mtd/ftl.c	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre4/drivers/mtd/ftl.c	Tue Jan 28 19:44:30 2003
@@ -1,5 +1,5 @@
 /* This version ported to the Linux-MTD system by dwmw2@infradead.org
- * $Id: ftl.c,v 1.43 2002/02/13 15:31:37 dwmw2 Exp $
+ * $Id: ftl.c,v 1.45 2003/01/24 23:31:27 dwmw2 Exp $
  *
  * Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
  * - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups
@@ -70,7 +70,6 @@
 #include <linux/fs.h>
 #include <linux/ioctl.h>
 #include <linux/hdreg.h>
-#include <stdarg.h>
 
 #if (LINUX_VERSION_CODE >= 0x20100)
 #include <linux/vmalloc.h>
@@ -1415,7 +1414,7 @@
 
     memset(myparts, 0, sizeof(myparts));
     
-    DEBUG(0, "$Id: ftl.c,v 1.43 2002/02/13 15:31:37 dwmw2 Exp $\n");
+    DEBUG(0, "$Id: ftl.c,v 1.45 2003/01/24 23:31:27 dwmw2 Exp $\n");
     
     if (register_blkdev(FTL_MAJOR, "ftl", &ftl_blk_fops)) {
 	printk(KERN_NOTICE "ftl_cs: unable to grab major "
@@ -1456,4 +1455,4 @@
 
 MODULE_LICENSE("Dual MPL/GPL");
 MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
-MODULE_DESCRIPTION("Support code for Flash Translation Layer, used on PCMCIA devices and M-Systems DiskOnChip 1000");
+MODULE_DESCRIPTION("Support code for Flash Translation Layer, used on PCMCIA devices");
diff -urN linux-2.4.21-pre3/drivers/mtd/maps/Config.in linux-2.4.21-pre4/drivers/mtd/maps/Config.in
--- linux-2.4.21-pre3/drivers/mtd/maps/Config.in	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/drivers/mtd/maps/Config.in	Tue Jan 28 19:44:30 2003
@@ -1,6 +1,6 @@
 # drivers/mtd/maps/Config.in
 
-# $Id: Config.in,v 1.28 2002/03/08 16:34:35 rkaiser Exp $
+# $Id: Config.in,v 1.43 2003/01/24 14:26:38 dwmw2 Exp $
 
 mainmenu_option next_comment
 
@@ -32,8 +32,10 @@
    dep_tristate '  JEDEC Flash device mapped on Tempustech VMAX SBC301' CONFIG_MTD_VMAX $CONFIG_MTD_JEDEC
    dep_tristate '  Flash device mapped with DOCCS on NatSemi SCx200' CONFIG_MTD_SCx200_DOCFLASH $CONFIG_MTD_CFI
    dep_tristate '  BIOS flash chip on Intel L440GX boards' CONFIG_MTD_L440GX $CONFIG_MTD_JEDECPROBE
-   dep_tristate ' ROM connected to AMD766 southbridge' CONFIG_MTD_AMD766ROM $CONFIG_MTD_GEN_PROBE   
-   dep_tristate ' ROM connected to Intel Hub Controller 2' CONFIG_MTD_ICH2ROM $CONFIG_MTD_JEDECPROBE
+   dep_tristate '  ROM connected to AMD76X southbridge' CONFIG_MTD_AMD76XROM $CONFIG_MTD_GEN_PROBE   
+   dep_tristate '  ROM connected to Intel Hub Controller 2' CONFIG_MTD_ICH2ROM $CONFIG_MTD_JEDECPROBE
+   dep_tristate '  CFI Flash device mapped on SnapGear/SecureEdge' CONFIG_MTD_NETtel $CONFIG_MTD_PARTITIONS
+   dep_tristate '  BIOS flash chip on Intel SCB2 boards' CONFIG_MTD_SCB2_FLASH $CONFIG_MTD_GEN_PROBE
 fi
 
 if [ "$CONFIG_PPC" = "y" ]; then
@@ -42,16 +44,17 @@
    dep_tristate '  System flash on MBX860 board' CONFIG_MTD_MBX860 $CONFIG_MTD_CFI
    dep_tristate '  CFI Flash device mapped on D-Box2' CONFIG_MTD_DBOX2 $CONFIG_MTD_CFI
    dep_tristate '  CFI Flash device mapping on FlagaDM' CONFIG_MTD_CFI_FLAGADM $CONFIG_MTD_CFI
+   dep_tristate '  CFI Flash device mapped on IBM Redwood-4/5' CONFIG_MTD_REDWOOD $CONFIG_MTD_CFI
 fi
 
 if [ "$CONFIG_MIPS" = "y" ]; then
-   dep_tristate '  Pb1000 boot flash device' CONFIG_MTD_PB1000 $CONFIG_MIPS_PB1000
+   dep_tristate '  Pb1000 MTD support' CONFIG_MTD_PB1000 $CONFIG_MIPS_PB1000
    dep_tristate '  Pb1500 MTD support' CONFIG_MTD_PB1500 $CONFIG_MIPS_PB1500
    dep_tristate '  Pb1100 MTD support' CONFIG_MTD_PB1100 $CONFIG_MIPS_PB1100
    if [ "$CONFIG_MTD_PB1500" = "y" -o "$CONFIG_MTD_PB1500" = "m" \
 	-o "$CONFIG_MTD_PB1100" = "y" -o "$CONFIG_MTD_PB1100" = "m" ]; then
-      bool '  Pb1[015]00 boot flash device' CONFIG_MTD_PB1500_BOOT 
-      bool '  Pb1[015]00 user flash device (2nd 32MB bank)' CONFIG_MTD_PB1500_USER
+      bool '  Pb[15]00 boot flash device' CONFIG_MTD_PB1500_BOOT 
+      bool '  Pb[15]00 user flash device (2nd 32MiB bank)' CONFIG_MTD_PB1500_USER
    fi
    dep_tristate '  Flash chip mapping on ITE QED-4N-S01B, Globespan IVR or custom board' CONFIG_MTD_CSTM_MIPS_IXX $CONFIG_MTD_CFI $CONFIG_MTD_JEDEC $CONFIG_MTD_PARTITIONS 
    if [ "$CONFIG_MTD_CSTM_MIPS_IXX" = "y" -o "$CONFIG_MTD_CSTM_MIPS_IXX" = "m" ]; then
@@ -60,6 +63,7 @@
       int '    Bus width in octets' CONFIG_MTD_CSTM_MIPS_IXX_BUSWIDTH 2
    fi
    dep_tristate '  Momenco Ocelot boot flash device' CONFIG_MTD_OCELOT $CONFIG_MOMENCO_OCELOT
+   dep_tristate '  LASAT flash device' CONFIG_MTD_LASAT $CONFIG_MTD_CFI $CONFIG_LASAT
 fi
 
 if [ "$CONFIG_SUPERH" = "y" ]; then
@@ -75,16 +79,25 @@
    dep_tristate '  CFI Flash device mapped on ARM Integrator/P720T' CONFIG_MTD_ARM_INTEGRATOR $CONFIG_MTD_CFI
    dep_tristate '  Cirrus CDB89712 evaluation board mappings' CONFIG_MTD_CDB89712 $CONFIG_MTD_CFI $CONFIG_ARCH_CDB89712
    dep_tristate '  CFI Flash device mapped on StrongARM SA11x0' CONFIG_MTD_SA1100 $CONFIG_MTD_CFI $CONFIG_ARCH_SA1100 $CONFIG_MTD_PARTITIONS
-   dep_tristate '  CFI Flash device mapped on DC21285 Footbridge' CONFIG_MTD_DC21285 $CONFIG_MTD_CFI $CONFIG_ARCH_FOOTBRIDGE $CONFIG_MTD_PARTITIONS
+   dep_tristate '  CFI Flash device mapped on DC21285 Footbridge' CONFIG_MTD_DC21285 $CONFIG_MTD_CFI $CONFIG_ARCH_FOOTBRIDGE
    dep_tristate '  CFI Flash device mapped on the XScale IQ80310 board' CONFIG_MTD_IQ80310 $CONFIG_MTD_CFI $CONFIG_ARCH_IQ80310
    dep_tristate '  CFI Flash device mapped on Epxa10db' CONFIG_MTD_EPXA10DB $CONFIG_MTD_CFI  $CONFIG_MTD_PARTITIONS $CONFIG_ARCH_CAMELOT
+   dep_tristate '  CFI Flash device mapped on the FortuNet board' CONFIG_MTD_FORTUNET $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS $CONFIG_SA1100_FORTUNET
    dep_tristate '  NV-RAM mapping AUTCPU12 board' CONFIG_MTD_AUTCPU12 $CONFIG_ARCH_AUTCPU12
+   dep_tristate '  CFI Flash device mapped on EDB7312' CONFIG_MTD_EDB7312 $CONFIG_MTD_CFI
+   dep_tristate '  JEDEC Flash device mapped on impA7' CONFIG_MTD_IMPA7 $CONFIG_MTD_JEDECPROBE
+   dep_tristate '  JEDEC Flash device mapped on Ceiva/Polaroid PhotoMax Digital Picture Frame' CONFIG_MTD_CEIVA $CONFIG_MTD_JEDECPROBE  $CONFIG_ARCH_CEIVA
 fi
 if [ "$CONFIG_ALPHA" = "y" ]; then
    dep_tristate '  Flash chip mapping on TSUNAMI' CONFIG_MTD_TSUNAMI $CONFIG_MTD_GENPROBE
 fi
 
+if [ "$CONFIG_UCLINUX" = "y" ]; then
+   dep_tristate '  Generic uClinux RAM/ROM filesystem support' CONFIG_MTD_UCLINUX $CONFIG_MTD_PARTITIONS
+fi
+
 # This needs CFI or JEDEC, depending on the cards found.
 dep_tristate '  PCI MTD driver' CONFIG_MTD_PCI $CONFIG_MTD $CONFIG_PCI
+dep_tristate '  PCMCIA MTD driver' CONFIG_MTD_PCMCIA $CONFIG_MTD $CONFIG_PCMCIA
 
 endmenu
diff -urN linux-2.4.21-pre3/drivers/mtd/maps/Makefile linux-2.4.21-pre4/drivers/mtd/maps/Makefile
--- linux-2.4.21-pre3/drivers/mtd/maps/Makefile	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/drivers/mtd/maps/Makefile	Tue Jan 28 19:44:30 2003
@@ -1,45 +1,65 @@
 #
 # linux/drivers/maps/Makefile
 #
-# $Id: Makefile,v 1.21 2002/02/22 09:34:44 gleixner Exp $
+# $Id: Makefile,v 1.37 2003/01/24 14:26:38 dwmw2 Exp $
 
+BELOW25		:= $(shell echo $(PATCHLEVEL) | sed s/[1234]/y/)
+
+ifeq ($(BELOW25),y)
 O_TARGET	:= mapslink.o
+endif
 
 # Chip mappings
-obj-$(CONFIG_MTD_CDB89712)      += cdb89712.o
+obj-$(CONFIG_MTD_CDB89712)	+= cdb89712.o
 obj-$(CONFIG_MTD_ARM_INTEGRATOR)+= integrator-flash.o
 obj-$(CONFIG_MTD_CFI_FLAGADM)	+= cfi_flagadm.o
-obj-$(CONFIG_MTD_CSTM_MIPS_IXX) += cstm_mips_ixx.o
-obj-$(CONFIG_MTD_DC21285)       += dc21285.o
-obj-$(CONFIG_MTD_DILNETPC)      += dilnetpc.o
-obj-$(CONFIG_MTD_ELAN_104NC)    += elan-104nc.o
-obj-$(CONFIG_MTD_EPXA10DB)      += epxa10db-flash.o
+obj-$(CONFIG_MTD_CSTM_MIPS_IXX)	+= cstm_mips_ixx.o
+obj-$(CONFIG_MTD_DC21285)	+= dc21285.o
+obj-$(CONFIG_MTD_DILNETPC)	+= dilnetpc.o
+obj-$(CONFIG_MTD_ELAN_104NC)	+= elan-104nc.o
+obj-$(CONFIG_MTD_EPXA10DB)	+= epxa10db-flash.o
 obj-$(CONFIG_MTD_IQ80310)	+= iq80310.o
 obj-$(CONFIG_MTD_L440GX)	+= l440gx.o
-obj-$(CONFIG_MTD_AMD766ROM)	+= amd766rom.o
+obj-$(CONFIG_MTD_AMD76XROM)	+= amd76xrom.o
 obj-$(CONFIG_MTD_ICH2ROM)	+= ich2rom.o
 obj-$(CONFIG_MTD_TSUNAMI)	+= tsunami_flash.o
 obj-$(CONFIG_MTD_MBX860)	+= mbx860.o
 obj-$(CONFIG_MTD_NORA)		+= nora.o
+obj-$(CONFIG_MTD_CEIVA)		+= ceiva.o
 obj-$(CONFIG_MTD_OCTAGON)	+= octagon-5066.o
-obj-$(CONFIG_MTD_PHYSMAP)	+= physmap.o 
+ifneq ($(CONFIG_MTD_PHYSMAP),n)
+  ifeq ($(CONFIG_MTD_PHYSMAP_BUSWIDTH),8)
+    obj-$(CONFIG_MTD_PHYSMAP)	+= physmap64.o 
+  else
+    obj-$(CONFIG_MTD_PHYSMAP)	+= physmap.o 
+  endif
+endif
 obj-$(CONFIG_MTD_PNC2000)	+= pnc2000.o
+obj-$(CONFIG_MTD_PCMCIA)	+= pcmciamtd.o
 obj-$(CONFIG_MTD_RPXLITE)	+= rpxlite.o
 obj-$(CONFIG_MTD_TQM8XXL)	+= tqm8xxl.o
-obj-$(CONFIG_MTD_SA1100)        += sa1100-flash.o
+obj-$(CONFIG_MTD_SA1100)	+= sa1100-flash.o
 obj-$(CONFIG_MTD_SBC_GXX)	+= sbc_gxx.o
 obj-$(CONFIG_MTD_SC520CDP)	+= sc520cdp.o
 obj-$(CONFIG_MTD_NETSC520)	+= netsc520.o
-obj-$(CONFIG_MTD_SUN_UFLASH)    += sun_uflash.o
+obj-$(CONFIG_MTD_SUN_UFLASH)	+= sun_uflash.o
 obj-$(CONFIG_MTD_VMAX)		+= vmax301.o
 obj-$(CONFIG_MTD_SCx200_DOCFLASH)+= scx200_docflash.o
 obj-$(CONFIG_MTD_DBOX2)		+= dbox2-flash.o
 obj-$(CONFIG_MTD_OCELOT)	+= ocelot.o
 obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o
 obj-$(CONFIG_MTD_PCI)		+= pci.o
-obj-$(CONFIG_MTD_PB1000)        += pb1xxx-flash.o
-obj-$(CONFIG_MTD_PB1100)        += pb1xxx-flash.o
-obj-$(CONFIG_MTD_PB1500)        += pb1xxx-flash.o
+obj-$(CONFIG_MTD_PB1000)	+= pb1xxx-flash.o
+obj-$(CONFIG_MTD_PB1100)	+= pb1xxx-flash.o
+obj-$(CONFIG_MTD_PB1500)	+= pb1xxx-flash.o
+obj-$(CONFIG_MTD_LASAT)		+= lasat.o
 obj-$(CONFIG_MTD_AUTCPU12)	+= autcpu12-nvram.o
+obj-$(CONFIG_MTD_EDB7312)	+= edb7312.o
+obj-$(CONFIG_MTD_IMPA7)		+= impa7.o
+obj-$(CONFIG_MTD_FORTUNET)	+= fortunet.o
+obj-$(CONFIG_MTD_REDWOOD)	+= redwood.o
+obj-$(CONFIG_MTD_UCLINUX)	+= uclinux.o
+obj-$(CONFIG_MTD_NETtel)	+= nettel.o
+obj-$(CONFIG_MTD_SCB2_FLASH)	+= scb2_flash.o
 
 include $(TOPDIR)/Rules.make
diff -urN linux-2.4.21-pre3/drivers/mtd/maps/amd76xrom.c linux-2.4.21-pre4/drivers/mtd/maps/amd76xrom.c
--- linux-2.4.21-pre3/drivers/mtd/maps/amd76xrom.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/drivers/mtd/maps/amd76xrom.c	Tue Jan 28 19:44:30 2003
@@ -0,0 +1,257 @@
+/*
+ * amd76xrom.c
+ *
+ * Normal mappings of chips in physical memory
+ * $Id: amd76xrom.c,v 1.1 2002/10/18 22:45:48 eric Exp $
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+
+
+struct amd76xrom_map_info {
+	struct map_info map;
+	struct mtd_info *mtd;
+	unsigned long window_addr;
+	u32 window_start, window_size;
+	struct pci_dev *pdev;
+};
+
+static __u8 amd76xrom_read8(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readb(map->map_priv_1 + ofs);
+}
+
+static __u16 amd76xrom_read16(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readw(map->map_priv_1 + ofs);
+}
+
+static __u32 amd76xrom_read32(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readl(map->map_priv_1 + ofs);
+}
+
+static void amd76xrom_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	memcpy_fromio(to, map->map_priv_1 + from, len);
+}
+
+static void amd76xrom_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+	__raw_writeb(d, map->map_priv_1 + adr);
+	mb();
+}
+
+static void amd76xrom_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+	__raw_writew(d, map->map_priv_1 + adr);
+	mb();
+}
+
+static void amd76xrom_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+	__raw_writel(d, map->map_priv_1 + adr);
+	mb();
+}
+
+static void amd76xrom_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	memcpy_toio(map->map_priv_1 + to, from, len);
+}
+
+static struct amd76xrom_map_info amd76xrom_map = {
+	map: {
+		name: "AMD76X rom",
+		size: 0,
+		buswidth: 1,
+		read8: amd76xrom_read8,
+		read16: amd76xrom_read16,
+		read32: amd76xrom_read32,
+		copy_from: amd76xrom_copy_from,
+		write8: amd76xrom_write8,
+		write16: amd76xrom_write16,
+		write32: amd76xrom_write32,
+		copy_to: amd76xrom_copy_to,
+		/* The standard rom socket is for single power supply chips
+		 * that don't have an extra vpp.
+		 */
+	},
+	mtd: 0,
+	window_addr: 0,
+};
+
+static int __devinit amd76xrom_init_one (struct pci_dev *pdev,
+	const struct pci_device_id *ent)
+{
+	struct rom_window {
+		u32 start;
+		u32 size;
+		u8 segen_bits;
+	};
+	static struct rom_window rom_window[] = {
+		{ 0xffb00000, 5*1024*1024, (1<<7) | (1<<6), },
+		{ 0xffc00000, 4*1024*1024, (1<<7), },
+		{ 0xffff0000, 64*1024,     0 },
+		{ 0         , 0,           0 },
+	};
+	static const u32 rom_probe_sizes[] = { 
+		5*1024*1024, 4*1024*1024, 2*1024*1024, 1024*1024, 512*1024, 
+		256*1024, 128*1024, 64*1024, 0};
+	static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", 0 };
+	u8 byte;
+	struct amd76xrom_map_info *info = &amd76xrom_map;
+	struct rom_window *window;
+	int i;
+	u32 rom_size;
+
+	window = &rom_window[0];
+#if 0
+	while(window->size) {
+		if (request_mem_region(window->start, window->size, "amd76xrom")) {
+			break;
+		}
+		window++;
+	}
+	if (!window->size) {
+		printk(KERN_ERR "amd76xrom: cannot reserve rom window\n");
+		goto err_out_none;
+	}
+#endif
+
+	/* Enable the selected rom window */
+	pci_read_config_byte(pdev, 0x43, &byte);
+	pci_write_config_byte(pdev, 0x43, byte | window->segen_bits);
+
+	/* Enable writes through the rom window */
+	pci_read_config_byte(pdev, 0x40, &byte);
+	pci_write_config_byte(pdev, 0x40, byte | 1);
+
+	/* FIXME handle registers 0x80 - 0x8C the bios region locks */
+
+	printk(KERN_NOTICE "amd76xrom window : %x at %x\n", 
+		window->size, window->start);
+	/* For write accesses caches are useless */
+	info->window_addr = (unsigned long)ioremap_nocache(window->start, window->size);
+
+	if (!info->window_addr) {
+		printk(KERN_ERR "Failed to ioremap\n");
+		goto err_out_free_mmio_region;
+	}
+	info->mtd = 0;
+	for(i = 0; (rom_size = rom_probe_sizes[i]); i++) {
+		char **chip_type;
+		if (rom_size > window->size) {
+			continue;
+		}
+		info->map.map_priv_1 = 
+			info->window_addr + window->size - rom_size;
+		info->map.size = rom_size;
+		chip_type = rom_probe_types;
+		for(; !info->mtd && *chip_type; chip_type++) {
+			info->mtd = do_map_probe(*chip_type, &amd76xrom_map.map);
+		}
+		if (info->mtd) {
+			break;
+		}
+	}
+	if (!info->mtd) {
+		goto err_out_iounmap;
+	}
+	printk(KERN_NOTICE "amd76xrom chip at offset: %x\n",
+		window->size - rom_size);
+		
+	info->mtd->module = THIS_MODULE;
+	add_mtd_device(info->mtd);
+	info->window_start = window->start;
+	info->window_size = window->size;
+	return 0;
+
+err_out_iounmap:
+	iounmap((void *)(info->window_addr));
+err_out_free_mmio_region:
+	release_mem_region(window->start, window->size);
+err_out_none:
+	return -ENODEV;
+}
+
+
+static void __devexit amd76xrom_remove_one (struct pci_dev *pdev)
+{
+	struct amd76xrom_map_info *info = &amd76xrom_map;
+	u8 byte;
+
+	del_mtd_device(info->mtd);
+	map_destroy(info->mtd);
+	info->mtd = 0;
+	info->map.map_priv_1 = 0;
+
+	iounmap((void *)(info->window_addr));
+	info->window_addr = 0;
+
+	/* Disable writes through the rom window */
+	pci_read_config_byte(pdev, 0x40, &byte);
+	pci_write_config_byte(pdev, 0x40, byte & ~1);
+	
+	release_mem_region(info->window_start, info->window_size);
+}
+
+static struct pci_device_id amd76xrom_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410,  
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7440,  
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, amd76xrom_pci_tbl);
+
+#if 0
+static struct pci_driver amd76xrom_driver = {
+	name:	  "amd76xrom",
+	id_table: amd76xrom_pci_tbl,
+	probe:    amd76xrom_init_one,
+	remove:   amd76xrom_remove_one,
+};
+#endif
+
+int __init init_amd76xrom(void)
+{
+	struct pci_dev *pdev;
+	struct pci_device_id *id;
+	pdev = 0;
+	for(id = amd76xrom_pci_tbl; id->vendor; id++) {
+		pdev = pci_find_device(id->vendor, id->device, 0);
+		if (pdev) {
+			break;
+		}
+	}
+	if (pdev) {
+		amd76xrom_map.pdev = pdev;
+		return amd76xrom_init_one(pdev, &amd76xrom_pci_tbl[0]);
+	}
+	return -ENXIO;
+#if 0
+	return pci_module_init(&amd76xrom_driver);
+#endif
+}
+
+static void __exit cleanup_amd76xrom(void)
+{
+	amd76xrom_remove_one(amd76xrom_map.pdev);
+}
+
+module_init(init_amd76xrom);
+module_exit(cleanup_amd76xrom);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Eric Biederman <ebiederman@lnxi.com>");
+MODULE_DESCRIPTION("MTD map driver for BIOS chips on the AMD76X southbridge");
+
diff -urN linux-2.4.21-pre3/drivers/mtd/maps/ceiva.c linux-2.4.21-pre4/drivers/mtd/maps/ceiva.c
--- linux-2.4.21-pre3/drivers/mtd/maps/ceiva.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/drivers/mtd/maps/ceiva.c	Tue Jan 28 19:44:30 2003
@@ -0,0 +1,408 @@
+/*
+ * Ceiva flash memory driver.
+ * Copyright (C) 2002 Rob Scott <rscott@mtrob.fdns.net>
+ *
+ * Note: this driver supports jedec compatible devices. Modification
+ * for CFI compatible devices should be straight forward: change
+ * jedec_probe to cfi_probe.
+ *
+ * Based on: sa1100-flash.c, which has the following copyright:
+ * Flash memory access on SA11x0 based devices
+ *
+ * (C) 2000 Nicolas Pitre <nico@cam.org>
+ *
+ * $Id: ceiva.c,v 1.2 2002/10/14 12:50:22 rmk Exp $
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/concat.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/io.h>
+#include <asm/sizes.h>
+
+/*
+ * This isnt complete yet, so...
+ */
+#define CONFIG_MTD_CEIVA_STATICMAP
+
+static __u8 clps_read8(struct map_info *map, unsigned long ofs)
+{
+	return readb(map->map_priv_1 + ofs);
+}
+
+static __u16 clps_read16(struct map_info *map, unsigned long ofs)
+{
+	return readw(map->map_priv_1 + ofs);
+}
+
+static __u32 clps_read32(struct map_info *map, unsigned long ofs)
+{
+	return readl(map->map_priv_1 + ofs);
+}
+
+static void clps_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	memcpy(to, (void *)(map->map_priv_1 + from), len);
+}
+
+static void clps_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+	writeb(d, map->map_priv_1 + adr);
+}
+
+static void clps_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+	writew(d, map->map_priv_1 + adr);
+}
+
+static void clps_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+	writel(d, map->map_priv_1 + adr);
+}
+
+static void clps_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	memcpy((void *)(map->map_priv_1 + to), from, len);
+}
+
+static struct map_info clps_map __initdata = {
+	name:		"clps flash",
+	read8:		clps_read8,
+	read16:		clps_read16,
+	read32:		clps_read32,
+	copy_from:	clps_copy_from,
+	write8:		clps_write8,
+	write16:	clps_write16,
+	write32:	clps_write32,
+	copy_to:	clps_copy_to,
+};
+
+#ifdef CONFIG_MTD_CEIVA_STATICMAP
+/*
+ * See include/linux/mtd/partitions.h for definition of the mtd_partition
+ * structure.
+ *
+ * Please note:
+ *  1. The flash size given should be the largest flash size that can
+ *     be accomodated.
+ *
+ *  2. The bus width must defined in clps_setup_flash.
+ *
+ * The MTD layer will detect flash chip aliasing and reduce the size of
+ * the map accordingly.
+ *
+ */
+
+#ifdef CONFIG_ARCH_CEIVA
+/* Flash / Partition sizing */
+/* For the 28F8003, we use the block mapping to calcuate the sizes */
+#define MAX_SIZE_KiB                  (16 + 8 + 8 + 96 + (7*128))
+#define BOOT_PARTITION_SIZE_KiB       (16)
+#define PARAMS_PARTITION_SIZE_KiB     (8)
+#define KERNEL_PARTITION_SIZE_KiB     (4*128)
+/* Use both remaing portion of first flash, and all of second flash */
+#define ROOT_PARTITION_SIZE_KiB       (3*128) + (8*128)
+
+static struct mtd_partition ceiva_partitions[] = {
+	{
+		name: "Ceiva BOOT partition",
+		size:   BOOT_PARTITION_SIZE_KiB*1024,
+		offset: 0,
+
+	},{
+		name: "Ceiva parameters partition",
+		size:   PARAMS_PARTITION_SIZE_KiB*1024,
+		offset: (16 + 8) * 1024,
+	},{
+		name: "Ceiva kernel partition",
+		size: (KERNEL_PARTITION_SIZE_KiB)*1024,
+		offset: 0x20000,
+
+	},{
+		name: "Ceiva root filesystem partition",
+		offset: MTDPART_OFS_APPEND,
+		size: (ROOT_PARTITION_SIZE_KiB)*1024,
+	}
+};
+#endif
+
+static int __init clps_static_partitions(struct mtd_partition **parts)
+{
+	int nb_parts = 0;
+
+#ifdef CONFIG_ARCH_CEIVA
+	if (machine_is_ceiva()) {
+		*parts       = ceiva_partitions;
+		nb_parts     = ARRAY_SIZE(ceiva_partitions);
+	}
+#endif
+	return nb_parts;
+}
+#endif
+
+struct clps_info {
+	unsigned long base;
+	unsigned long size;
+	int width;
+	void *vbase;
+	struct map_info *map;
+	struct mtd_info *mtd;
+	struct resource *res;
+};
+
+#define NR_SUBMTD 4
+
+static struct clps_info info[NR_SUBMTD];
+
+static int __init clps_setup_mtd(struct clps_info *clps, int nr, struct mtd_info **rmtd)
+{
+	struct mtd_info *subdev[nr];
+	struct map_info *maps;
+	int i, found = 0, ret = 0;
+
+	/*
+	 * Allocate the map_info structs in one go.
+	 */
+	maps = kmalloc(sizeof(struct map_info) * nr, GFP_KERNEL);
+	if (!maps)
+		return -ENOMEM;
+
+	/*
+	 * Claim and then map the memory regions.
+	 */
+	for (i = 0; i < nr; i++) {
+		if (clps[i].base == (unsigned long)-1)
+			break;
+
+		clps[i].res = request_mem_region(clps[i].base, clps[i].size, "clps flash");
+		if (!clps[i].res) {
+			ret = -EBUSY;
+			break;
+		}
+
+		clps[i].map = maps + i;
+		memcpy(clps[i].map, &clps_map, sizeof(struct map_info));
+
+		clps[i].vbase = ioremap(clps[i].base, clps[i].size);
+		if (!clps[i].vbase) {
+			ret = -ENOMEM;
+			break;
+		}
+
+		clps[i].map->map_priv_1 = (unsigned long)clps[i].vbase;
+		clps[i].map->buswidth = clps[i].width;
+		clps[i].map->size = clps[i].size;
+
+		clps[i].mtd = do_map_probe("jedec_probe", clps[i].map);
+		if (clps[i].mtd == NULL) {
+			ret = -ENXIO;
+			break;
+		}
+		clps[i].mtd->module = THIS_MODULE;
+		subdev[i] = clps[i].mtd;
+
+		printk(KERN_INFO "clps flash: JEDEC device at 0x%08lx, %dMiB, "
+			"%d-bit\n", clps[i].base, clps[i].mtd->size >> 20,
+			clps[i].width * 8);
+		found += 1;
+	}
+
+	/*
+	 * ENXIO is special.  It means we didn't find a chip when
+	 * we probed.  We need to tear down the mapping, free the
+	 * resource and mark it as such.
+	 */
+	if (ret == -ENXIO) {
+		iounmap(clps[i].vbase);
+		clps[i].vbase = NULL;
+		release_resource(clps[i].res);
+		clps[i].res = NULL;
+	}
+
+	/*
+	 * If we found one device, don't bother with concat support.
+	 * If we found multiple devices, use concat if we have it
+	 * available, otherwise fail.
+	 */
+	if (ret == 0 || ret == -ENXIO) {
+		if (found == 1) {
+			*rmtd = subdev[0];
+			ret = 0;
+		} else if (found > 1) {
+			/*
+			 * We detected multiple devices.  Concatenate
+			 * them together.
+			 */
+#ifdef CONFIG_MTD_CONCAT
+			*rmtd = mtd_concat_create(subdev, found,
+						  "clps flash");
+			if (*rmtd == NULL)
+				ret = -ENXIO;
+#else
+			printk(KERN_ERR "clps flash: multiple devices "
+			       "found but MTD concat support disabled.\n");
+			ret = -ENXIO;
+#endif
+		}
+	}
+
+	/*
+	 * If we failed, clean up.
+	 */
+	if (ret) {
+		do {
+			if (clps[i].mtd)
+				map_destroy(clps[i].mtd);
+			if (clps[i].vbase)
+				iounmap(clps[i].vbase);
+			if (clps[i].res)
+				release_resource(clps[i].res);
+		} while (i--);
+
+		kfree(maps);
+	}
+
+	return ret;
+}
+
+static void __exit clps_destroy_mtd(struct clps_info *clps, struct mtd_info *mtd)
+{
+	int i;
+
+	del_mtd_partitions(mtd);
+
+	if (mtd != clps[0].mtd)
+		mtd_concat_destroy(mtd);
+
+	for (i = NR_SUBMTD; i >= 0; i--) {
+		if (clps[i].mtd)
+			map_destroy(clps[i].mtd);
+		if (clps[i].vbase)
+			iounmap(clps[i].vbase);
+		if (clps[i].res)
+			release_resource(clps[i].res);
+	}
+	kfree(clps[0].map);
+}
+
+/*
+ * We define the memory space, size, and width for the flash memory
+ * space here.
+ */
+
+static int __init clps_setup_flash(void)
+{
+	int nr;
+
+#ifdef CONFIG_ARCH_CEIVA
+	if (machine_is_ceiva()) {
+		info[0].base = CS0_PHYS_BASE;
+		info[0].size = SZ_32M;
+		info[0].width = CEIVA_FLASH_WIDTH;
+		info[1].base = CS1_PHYS_BASE;
+		info[1].size = SZ_32M;
+		info[1].width = CEIVA_FLASH_WIDTH;
+		nr = 2;
+	}
+#endif
+	return nr;
+}
+
+extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts);
+extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partition **pparts, char *);
+
+static struct mtd_partition *parsed_parts;
+
+static void __init clps_locate_partitions(struct mtd_info *mtd)
+{
+	const char *part_type = NULL;
+	int nr_parts = 0;
+	do {
+		/*
+		 * Partition selection stuff.
+		 */
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+		nr_parts = parse_cmdline_partitions(mtd, &parsed_parts, "clps");
+		if (nr_parts > 0) {
+			part_type = "command line";
+			break;
+		}
+#endif
+#ifdef CONFIG_MTD_REDBOOT_PARTS
+		nr_parts = parse_redboot_partitions(mtd, &parsed_parts);
+		if (nr_parts > 0) {
+			part_type = "RedBoot";
+			break;
+		}
+#endif
+#ifdef CONFIG_MTD_CEIVA_STATICMAP
+		nr_parts = clps_static_partitions(&parsed_parts);
+		if (nr_parts > 0) {
+			part_type = "static";
+			break;
+		}
+		printk("found: %d partitions\n", nr_parts);
+#endif
+	} while (0);
+
+	if (nr_parts == 0) {
+		printk(KERN_NOTICE "clps flash: no partition info "
+			"available, registering whole flash\n");
+		add_mtd_device(mtd);
+	} else {
+		printk(KERN_NOTICE "clps flash: using %s partition "
+			"definition\n", part_type);
+		add_mtd_partitions(mtd, parsed_parts, nr_parts);
+	}
+
+	/* Always succeeds. */
+}
+
+static void __exit clps_destroy_partitions(void)
+{
+	if (parsed_parts)
+		kfree(parsed_parts);
+}
+
+static struct mtd_info *mymtd;
+
+static int __init clps_mtd_init(void)
+{
+	int ret;
+	int nr;
+
+	nr = clps_setup_flash();
+	if (nr < 0)
+		return nr;
+
+	ret = clps_setup_mtd(info, nr, &mymtd);
+	if (ret)
+		return ret;
+
+	clps_locate_partitions(mymtd);
+
+	return 0;
+}
+
+static void __exit clps_mtd_cleanup(void)
+{
+	clps_destroy_mtd(info, mymtd);
+	clps_destroy_partitions();
+}
+
+module_init(clps_mtd_init);
+module_exit(clps_mtd_cleanup);
+
+MODULE_AUTHOR("Rob Scott");
+MODULE_DESCRIPTION("Cirrus Logic JEDEC map driver");
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.21-pre3/drivers/mtd/maps/dc21285.c linux-2.4.21-pre4/drivers/mtd/maps/dc21285.c
--- linux-2.4.21-pre3/drivers/mtd/maps/dc21285.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.21-pre4/drivers/mtd/maps/dc21285.c	Tue Jan 28 19:44:30 2003
@@ -5,9 +5,9 @@
  *
  * This code is GPL
  * 
- * $Id: dc21285.c,v 1.7 2001/10/11 16:17:51 nico Exp $
+ * $Id: dc21285.c,v 1.9 2002/10/14 12:22:10 rmk Exp $
  */
-
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -131,7 +131,7 @@
 		dc21285_map.buswidth*8);
 
 	/* Let's map the flash area */
-	dc21285_map.map_priv_1 = (unsigned long)__ioremap(DC21285_FLASH, 16*1024*1024, 0);
+	dc21285_map.map_priv_1 = (unsigned long)ioremap(DC21285_FLASH, 16*1024*1024);
 	if (!dc21285_map.map_priv_1) {
 		printk("Failed to ioremap\n");
 		return -EIO;
@@ -139,21 +139,22 @@
 
 	mymtd = do_map_probe("cfi_probe", &dc21285_map);
 	if (mymtd) {
-		int nrparts;
+		int nrparts = 0;
 
 		mymtd->module = THIS_MODULE;
 			
 		/* partition fixup */
 
+#ifdef CONFIG_MTD_REDBOOT_PARTS
 		nrparts = parse_redboot_partitions(mymtd, &dc21285_parts);
-		if (nrparts <=0) {
+#endif
+		if (nrparts > 0) {
+			add_mtd_partitions(mymtd, dc21285_parts, nrparts);
+		} else if (nrparts == 0) {
 			printk(KERN_NOTICE "RedBoot partition table failed\n");
-			iounmap((void *)dc21285_map.map_priv_1);
-			return -ENXIO;
+			add_mtd_device(mymtd);
 		}
 
-		add_mtd_partitions(mymtd, dc21285_parts, nrparts);
-
 		/* 
 		 * Flash timing is determined with bits 19-16 of the
 		 * CSR_SA110_CNTL.  The value is the number of wait cycles, or
diff -urN linux-2.4.21-pre3/drivers/mtd/maps/edb7312.c linux-2.4.21-pre4/drivers/mtd/maps/edb7312.c
--- linux-2.4.21-pre3/drivers/mtd/maps/edb7312.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/drivers/mtd/maps/edb7312.c	Tue Jan 28 19:44:30 2003
@@ -0,0 +1,202 @@
+/*
+ * $Id: edb7312.c,v 1.2 2002/09/05 05:11:24 acurtis Exp $
+ *
+ * Handle mapping of the NOR flash on Cogent EDB7312 boards
+ *
+ * Copyright 2002 SYSGO Real-Time Solutions GmbH
+ * 
+ * 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/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/config.h>
+
+#ifdef CONFIG_MTD_PARTITIONS
+#include <linux/mtd/partitions.h>
+#endif
+
+#define WINDOW_ADDR 0x00000000      /* physical properties of flash */
+#define WINDOW_SIZE 0x01000000
+#define BUSWIDTH    2
+#define FLASH_BLOCKSIZE_MAIN	0x20000
+#define FLASH_NUMBLOCKS_MAIN	128
+/* can be "cfi_probe", "jedec_probe", "map_rom", 0 }; */
+#define PROBETYPES { "cfi_probe", 0 }
+
+#define MSG_PREFIX "EDB7312-NOR:"   /* prefix for our printk()'s */
+#define MTDID      "edb7312-nor"    /* for mtdparts= partitioning */
+
+static struct mtd_info *mymtd;
+
+__u8 edb7312nor_read8(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readb(map->map_priv_1 + ofs);
+}
+
+__u16 edb7312nor_read16(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readw(map->map_priv_1 + ofs);
+}
+
+__u32 edb7312nor_read32(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readl(map->map_priv_1 + ofs);
+}
+
+void edb7312nor_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	memcpy_fromio(to, map->map_priv_1 + from, len);
+}
+
+void edb7312nor_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+	__raw_writeb(d, map->map_priv_1 + adr);
+	mb();
+}
+
+void edb7312nor_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+	__raw_writew(d, map->map_priv_1 + adr);
+	mb();
+}
+
+void edb7312nor_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+	__raw_writel(d, map->map_priv_1 + adr);
+	mb();
+}
+
+void edb7312nor_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	memcpy_toio(map->map_priv_1 + to, from, len);
+}
+
+struct map_info edb7312nor_map = {
+	name: "NOR flash on EDB7312",
+	size: WINDOW_SIZE,
+	buswidth: BUSWIDTH,
+	read8: edb7312nor_read8,
+	read16: edb7312nor_read16,
+	read32: edb7312nor_read32,
+	copy_from: edb7312nor_copy_from,
+	write8: edb7312nor_write8,
+	write16: edb7312nor_write16,
+	write32: edb7312nor_write32,
+	copy_to: edb7312nor_copy_to
+};
+
+#ifdef CONFIG_MTD_PARTITIONS
+
+/*
+ * MTD partitioning stuff 
+ */
+static struct mtd_partition static_partitions[3] =
+{
+    {
+	name: "ARMboot",
+	  size: 0x40000,
+	  offset: 0
+    },
+    {
+	name: "Kernel",
+	  size: 0x200000,
+	  offset: 0x40000
+    },
+    {
+	name: "RootFS",
+	  size: 0xDC0000,
+	  offset: 0x240000
+    },
+};
+
+#define NB_OF(x) (sizeof (x) / sizeof (x[0]))
+
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+int parse_cmdline_partitions(struct mtd_info *master, 
+			     struct mtd_partition **pparts,
+			     const char *mtd_id);
+#endif
+
+#endif
+
+static int                   mtd_parts_nb = 0;
+static struct mtd_partition *mtd_parts    = 0;
+
+int __init init_edb7312nor(void)
+{
+	static const char *rom_probe_types[] = PROBETYPES;
+	const char **type;
+	const char *part_type = 0;
+
+       	printk(KERN_NOTICE MSG_PREFIX "0x%08x at 0x%08x\n", 
+	       WINDOW_SIZE, WINDOW_ADDR);
+	edb7312nor_map.map_priv_1 = (unsigned long)
+	  ioremap(WINDOW_ADDR, WINDOW_SIZE);
+
+	if (!edb7312nor_map.map_priv_1) {
+		printk(MSG_PREFIX "failed to ioremap\n");
+		return -EIO;
+	}
+
+	mymtd = 0;
+	type = rom_probe_types;
+	for(; !mymtd && *type; type++) {
+		mymtd = do_map_probe(*type, &edb7312nor_map);
+	}
+	if (mymtd) {
+		mymtd->module = THIS_MODULE;
+
+#ifdef CONFIG_MTD_PARTITIONS
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+		mtd_parts_nb = parse_cmdline_partitions(mymtd, &mtd_parts, MTDID);
+		if (mtd_parts_nb > 0)
+		  part_type = "command line";
+#endif
+		if (mtd_parts_nb == 0)
+		{
+			mtd_parts = static_partitions;
+			mtd_parts_nb = NB_OF(static_partitions);
+			part_type = "static";
+		}
+#endif
+		add_mtd_device(mymtd);
+		if (mtd_parts_nb == 0)
+		  printk(KERN_NOTICE MSG_PREFIX "no partition info available\n");
+		else
+		{
+			printk(KERN_NOTICE MSG_PREFIX
+			       "using %s partition definition\n", part_type);
+			add_mtd_partitions(mymtd, mtd_parts, mtd_parts_nb);
+		}
+		return 0;
+	}
+
+	iounmap((void *)edb7312nor_map.map_priv_1);
+	return -ENXIO;
+}
+
+static void __exit cleanup_edb7312nor(void)
+{
+	if (mymtd) {
+		del_mtd_device(mymtd);
+		map_destroy(mymtd);
+	}
+	if (edb7312nor_map.map_priv_1) {
+		iounmap((void *)edb7312nor_map.map_priv_1);
+		edb7312nor_map.map_priv_1 = 0;
+	}
+}
+
+module_init(init_edb7312nor);
+module_exit(cleanup_edb7312nor);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Marius Groeger <mag@sysgo.de>");
+MODULE_DESCRIPTION("Generic configurable MTD map driver");
diff -urN linux-2.4.21-pre3/drivers/mtd/maps/epxa10db-flash.c linux-2.4.21-pre4/drivers/mtd/maps/epxa10db-flash.c
--- linux-2.4.21-pre3/drivers/mtd/maps/epxa10db-flash.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.21-pre4/drivers/mtd/maps/epxa10db-flash.c	Tue Jan 28 19:44:30 2003
@@ -5,7 +5,7 @@
  *  Copyright (C) 2001 Altera Corporation
  *  Copyright (C) 2001 Red Hat, Inc.
  *
- * $Id: epxa10db-flash.c,v 1.2 2001/12/19 13:00:19 jskov Exp $ 
+ * $Id: epxa10db-flash.c,v 1.4 2002/08/22 10:46:19 cdavies Exp $ 
  *
  * 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
@@ -32,6 +32,11 @@
 #include <linux/mtd/partitions.h>
 
 #include <asm/hardware.h>
+#ifdef CONFIG_EPXA10DB
+#define BOARD_NAME "EPXA10DB"
+#else
+#define BOARD_NAME "EPXA1DB"
+#endif
 
 static int nr_parts = 0;
 static struct mtd_partition *parts;
@@ -39,91 +44,94 @@
 static struct mtd_info *mymtd;
 
 extern int parse_redboot_partitions(struct mtd_info *, struct mtd_partition **);
-static int epxa10db_default_partitions(struct mtd_info *master, struct mtd_partition **pparts);
+static int epxa_default_partitions(struct mtd_info *master, struct mtd_partition **pparts);
 
-static __u8 epxa10db_read8(struct map_info *map, unsigned long ofs)
+static __u8 epxa_read8(struct map_info *map, unsigned long ofs)
 {
 	return __raw_readb(map->map_priv_1 + ofs);
 }
 
-static __u16 epxa10db_read16(struct map_info *map, unsigned long ofs)
+static __u16 epxa_read16(struct map_info *map, unsigned long ofs)
 {
 	return __raw_readw(map->map_priv_1 + ofs);
 }
 
-static __u32 epxa10db_read32(struct map_info *map, unsigned long ofs)
+static __u32 epxa_read32(struct map_info *map, unsigned long ofs)
 {
 	return __raw_readl(map->map_priv_1 + ofs);
 }
 
-static void epxa10db_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+static void epxa_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
 {
 	memcpy_fromio(to, (void *)(map->map_priv_1 + from), len);
 }
 
-static void epxa10db_write8(struct map_info *map, __u8 d, unsigned long adr)
+static void epxa_write8(struct map_info *map, __u8 d, unsigned long adr)
 {
 	__raw_writeb(d, map->map_priv_1 + adr);
 	mb();
 }
 
-static void epxa10db_write16(struct map_info *map, __u16 d, unsigned long adr)
+static void epxa_write16(struct map_info *map, __u16 d, unsigned long adr)
 {
 	__raw_writew(d, map->map_priv_1 + adr);
 	mb();
 }
 
-static void epxa10db_write32(struct map_info *map, __u32 d, unsigned long adr)
+static void epxa_write32(struct map_info *map, __u32 d, unsigned long adr)
 {
 	__raw_writel(d, map->map_priv_1 + adr);
 	mb();
 }
 
-static void epxa10db_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+static void epxa_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
 {
 	memcpy_toio((void *)(map->map_priv_1 + to), from, len);
 }
 
 
 
-static struct map_info epxa10db_map = {
-	name:		"EPXA10DB flash",
+static struct map_info epxa_map = {
+	name:		"EPXA flash",
 	size:		FLASH_SIZE,
 	buswidth:	2,
-	read8:		epxa10db_read8,
-	read16:		epxa10db_read16,
-	read32:		epxa10db_read32,
-	copy_from:	epxa10db_copy_from,
-	write8:		epxa10db_write8,
-	write16:	epxa10db_write16,
-	write32:	epxa10db_write32,
-	copy_to:	epxa10db_copy_to
+	read8:		epxa_read8,
+	read16:		epxa_read16,
+	read32:		epxa_read32,
+	copy_from:	epxa_copy_from,
+	write8:		epxa_write8,
+	write16:	epxa_write16,
+	write32:	epxa_write32,
+	copy_to:	epxa_copy_to
 };
 
 
-static int __init epxa10db_mtd_init(void)
+static int __init epxa_mtd_init(void)
 {
 	int i;
-	printk(KERN_NOTICE "Epxa10db flash device: %x at %x\n", FLASH_SIZE, FLASH_START);
-	epxa10db_map.map_priv_1 = (unsigned long)ioremap(FLASH_START, FLASH_SIZE);
-	if (!epxa10db_map.map_priv_1) {
-		printk("Failed to ioremap Epxa10db flash\n");
+	
+	printk(KERN_NOTICE "%s flash device: %x at %x\n", BOARD_NAME, FLASH_SIZE, FLASH_START);
+	epxa_map.map_priv_1 = (unsigned long)ioremap(FLASH_START, FLASH_SIZE);
+	if (!epxa_map.map_priv_1) {
+		printk("Failed to ioremap %s flash\n",BOARD_NAME);
 		return -EIO;
 	}
 
-	mymtd = do_map_probe("cfi_probe", &epxa10db_map);
+	mymtd = do_map_probe("cfi_probe", &epxa_map);
 	if (!mymtd) {
-		iounmap((void *)epxa10db_map.map_priv_1);
+		iounmap((void *)epxa_map.map_priv_1);
 		return -ENXIO;
 	}
 
 	mymtd->module = THIS_MODULE;
 
 	/* Unlock the flash device. */
-	for (i=0; i<mymtd->numeraseregions;i++){
-		int j;
-		for(j=0;j<mymtd->eraseregions[i].numblocks;j++){
-			mymtd->unlock(mymtd,mymtd->eraseregions[i].offset + j * mymtd->eraseregions[i].erasesize,4);
+	if(mymtd->unlock){
+		for (i=0; i<mymtd->numeraseregions;i++){
+			int j;
+			for(j=0;j<mymtd->eraseregions[i].numblocks;j++){
+				mymtd->unlock(mymtd,mymtd->eraseregions[i].offset + j * mymtd->eraseregions[i].erasesize,mymtd->eraseregions[i].erasesize);
+			}
 		}
 	}
 
@@ -145,7 +153,7 @@
 #endif
 
 	/* No recognised partitioning schemes found - use defaults */
-	nr_parts = epxa10db_default_partitions(mymtd, &parts);
+	nr_parts = epxa_default_partitions(mymtd, &parts);
 	if (nr_parts > 0) {
 		add_mtd_partitions(mymtd, parts, nr_parts);
 		return 0;
@@ -156,7 +164,7 @@
 	return 0;
 }
 
-static void __exit epxa10db_mtd_cleanup(void)
+static void __exit epxa_mtd_cleanup(void)
 {
 	if (mymtd) {
 		if (nr_parts)
@@ -165,9 +173,9 @@
 			del_mtd_device(mymtd);
 		map_destroy(mymtd);
 	}
-	if (epxa10db_map.map_priv_1) {
-		iounmap((void *)epxa10db_map.map_priv_1);
-		epxa10db_map.map_priv_1 = 0;
+	if (epxa_map.map_priv_1) {
+		iounmap((void *)epxa_map.map_priv_1);
+		epxa_map.map_priv_1 = 0;
 	}
 }
 
@@ -181,7 +189,7 @@
  * 0x00400000 - 0x00FFFFFF - Flashdisk
  */
 
-static int __init epxa10db_default_partitions(struct mtd_info *master, struct mtd_partition **pparts)
+static int __init epxa_default_partitions(struct mtd_info *master, struct mtd_partition **pparts)
 {
 	struct mtd_partition *parts;
 	int ret, i;
@@ -189,9 +197,10 @@
 	char *names; 
 	const char *name = "jffs";
 
-	printk("Using default partitions for epxa10db\n");
+	printk("Using default partitions for %s\n",BOARD_NAME);
 	npartitions=1;
 	parts = kmalloc(npartitions*sizeof(*parts)+strlen(name), GFP_KERNEL);
+	memzero(parts,npartitions*sizeof(*parts)+strlen(name));
 	if (!parts) {
 		ret = -ENOMEM;
 		goto out;
@@ -202,18 +211,23 @@
 	names += strlen(name) + 1;
 	strcpy(parts[i].name, name);
 
+#ifdef CONFIG_EPXA10DB
 	parts[i].size = FLASH_SIZE-0x00400000;
 	parts[i].offset = 0x00400000;
-	parts[i].mask_flags = 0;
+#else
+	parts[i].size = FLASH_SIZE-0x00180000;
+	parts[i].offset = 0x00180000;
+#endif
 
  out:
 	*pparts = parts;
 	return npartitions;
 }
 
-module_init(epxa10db_mtd_init);
-module_exit(epxa10db_mtd_cleanup);
+
+module_init(epxa_mtd_init);
+module_exit(epxa_mtd_cleanup);
 
 MODULE_AUTHOR("Clive Davies");
-MODULE_DESCRIPTION("Altera epxa10db mtd flash map");
+MODULE_DESCRIPTION("Altera epxa mtd flash map");
 MODULE_LICENSE("GPL");
diff -urN linux-2.4.21-pre3/drivers/mtd/maps/fortunet.c linux-2.4.21-pre4/drivers/mtd/maps/fortunet.c
--- linux-2.4.21-pre3/drivers/mtd/maps/fortunet.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/drivers/mtd/maps/fortunet.c	Tue Jan 28 19:44:30 2003
@@ -0,0 +1,309 @@
+/* fortunet.c memory map
+ *
+ * $Id: fortunet.c,v 1.2 2002/10/14 12:50:22 rmk Exp $
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+#define MAX_NUM_REGIONS		4
+#define MAX_NUM_PARTITIONS	8
+
+#define DEF_WINDOW_ADDR_PHY	0x00000000
+#define DEF_WINDOW_SIZE		0x00800000		// 8 Mega Bytes
+
+#define MTD_FORTUNET_PK		"MTD FortuNet: "
+
+#define MAX_NAME_SIZE		128
+
+struct map_region
+{
+	int			window_addr_phyical;
+	int			altbuswidth;
+	struct map_info		map_info;
+	struct mtd_info		*mymtd;
+	struct mtd_partition	parts[MAX_NUM_PARTITIONS];
+	char			map_name[MAX_NAME_SIZE];
+	char			parts_name[MAX_NUM_PARTITIONS][MAX_NAME_SIZE];
+};
+
+static struct map_region	map_regions[MAX_NUM_REGIONS];
+static int			map_regions_set[MAX_NUM_REGIONS] = {0,0,0,0};
+static int			map_regions_parts[MAX_NUM_REGIONS] = {0,0,0,0};
+
+
+__u8 fortunet_read8(struct map_info *map, unsigned long ofs)
+{
+	return *(__u8 *)(map->map_priv_1 + ofs);
+}
+
+__u16 fortunet_read16(struct map_info *map, unsigned long ofs)
+{
+	return *(__u16 *)(map->map_priv_1 + ofs);
+}
+
+__u32 fortunet_read32(struct map_info *map, unsigned long ofs)
+{
+	return *(__u32 *)(map->map_priv_1 + ofs);
+}
+
+void fortunet_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	memcpy(to, (void *)(map->map_priv_1 + from), len);
+}
+
+void fortunet_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+	*(__u8 *)(map->map_priv_1 + adr) = d;
+}
+
+void fortunet_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+	*(__u16 *)(map->map_priv_1 + adr) = d;
+}
+
+void fortunet_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+	*(__u32 *)(map->map_priv_1 + adr) = d;
+}
+
+void fortunet_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	memcpy((void *)(map->map_priv_1 + to), from, len);
+}
+
+struct map_info default_map = {
+	size: DEF_WINDOW_SIZE,
+	buswidth: 4,
+	read8: fortunet_read8,
+	read16: fortunet_read16,
+	read32: fortunet_read32,
+	copy_from: fortunet_copy_from,
+	write8: fortunet_write8,
+	write16: fortunet_write16,
+	write32: fortunet_write32,
+	copy_to: fortunet_copy_to
+};
+
+static char * __init get_string_option(char *dest,int dest_size,char *sor)
+{
+	if(!dest_size)
+		return sor;
+	dest_size--;
+	while(*sor)
+	{
+		if(*sor==',')
+		{
+			sor++;
+			break;
+		}
+		else if(*sor=='\"')
+		{
+			sor++;
+			while(*sor)
+			{
+				if(*sor=='\"')
+				{
+					sor++;
+					break;
+				}
+				*dest = *sor;
+				dest++;
+				sor++;
+				dest_size--;
+				if(!dest_size)
+				{
+					*dest = 0;
+					return sor;
+				}
+			}
+		}
+		else
+		{
+			*dest = *sor;
+			dest++;
+			sor++;
+			dest_size--;
+			if(!dest_size)
+			{
+				*dest = 0;
+				return sor;
+			}
+		}
+	}
+	*dest = 0;
+	return sor;
+}
+
+static int __init MTD_New_Region(char *line)
+{
+	char	string[MAX_NAME_SIZE];
+	int	params[6];
+	get_options (get_string_option(string,sizeof(string),line),6,params);
+	if(params[0]<1)
+	{
+		printk(MTD_FORTUNET_PK "Bad paramters for MTD Region "
+			" name,region-number[,base,size,buswidth,altbuswidth]\n");
+		return 1;
+	}
+	if((params[1]<0)||(params[1]>=MAX_NUM_REGIONS))
+	{
+		printk(MTD_FORTUNET_PK "Bad region index of %d only have 0..%u regions\n",
+			params[1],MAX_NUM_REGIONS-1);
+		return 1;
+	}
+	memset(&map_regions[params[1]],0,sizeof(map_regions[params[1]]));
+	memcpy(&map_regions[params[1]].map_info,
+		&default_map,sizeof(map_regions[params[1]].map_info));
+        map_regions_set[params[1]] = 1;
+        map_regions[params[1]].window_addr_phyical = DEF_WINDOW_ADDR_PHY;
+        map_regions[params[1]].altbuswidth = 2;
+        map_regions[params[1]].mymtd = NULL;
+	map_regions[params[1]].map_info.name = map_regions[params[1]].map_name;
+	strcpy(map_regions[params[1]].map_info.name,string);
+	if(params[0]>1)
+	{
+		map_regions[params[1]].window_addr_phyical = params[2];
+	}
+	if(params[0]>2)
+	{
+		map_regions[params[1]].map_info.size = params[3];
+	}
+	if(params[0]>3)
+	{
+		map_regions[params[1]].map_info.buswidth = params[4];
+	}
+	if(params[0]>4)
+	{
+		map_regions[params[1]].altbuswidth = params[5];
+	}
+	return 1;
+}
+
+static int __init MTD_New_Partion(char *line)
+{
+	char	string[MAX_NAME_SIZE];
+	int	params[4];
+	get_options (get_string_option(string,sizeof(string),line),4,params);
+	if(params[0]<3)
+	{
+		printk(MTD_FORTUNET_PK "Bad paramters for MTD Partion "
+			" name,region-number,size,offset\n");
+		return 1;
+	}
+	if((params[1]<0)||(params[1]>=MAX_NUM_REGIONS))
+	{
+		printk(MTD_FORTUNET_PK "Bad region index of %d only have 0..%u regions\n",
+			params[1],MAX_NUM_REGIONS-1);
+		return 1;
+	}
+	if(map_regions_parts[params[1]]>=MAX_NUM_PARTITIONS)
+	{
+		printk(MTD_FORTUNET_PK "Out of space for partion in this region\n");
+		return 1;
+	}
+	map_regions[params[1]].parts[map_regions_parts[params[1]]].name =
+		map_regions[params[1]].	parts_name[map_regions_parts[params[1]]];
+	strcpy(map_regions[params[1]].parts[map_regions_parts[params[1]]].name,string);
+	map_regions[params[1]].parts[map_regions_parts[params[1]]].size =
+		params[2];
+	map_regions[params[1]].parts[map_regions_parts[params[1]]].offset =
+		params[3];
+	map_regions[params[1]].parts[map_regions_parts[params[1]]].mask_flags = 0;
+	map_regions_parts[params[1]]++;
+	return 1;
+}
+
+__setup("MTD_Region=", MTD_New_Region);
+__setup("MTD_Partion=", MTD_New_Partion);
+
+int __init init_fortunet(void)
+{
+	int	ix,iy;
+	for(iy=ix=0;ix<MAX_NUM_REGIONS;ix++)
+	{
+		if(map_regions_parts[ix]&&(!map_regions_set[ix]))
+		{
+			printk(MTD_FORTUNET_PK "Region %d is not setup (Seting to default)\n",
+				ix);
+			memset(&map_regions[ix],0,sizeof(map_regions[ix]));
+			memcpy(&map_regions[ix].map_info,&default_map,
+				sizeof(map_regions[ix].map_info));
+			map_regions_set[ix] = 1;
+			map_regions[ix].window_addr_phyical = DEF_WINDOW_ADDR_PHY;
+			map_regions[ix].altbuswidth = 2;
+			map_regions[ix].mymtd = NULL;
+			map_regions[ix].map_info.name = map_regions[ix].map_name;
+			strcpy(map_regions[ix].map_info.name,"FORTUNET");
+		}
+		if(map_regions_set[ix])
+		{
+			iy++;
+			printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash device at phyicaly "
+				" address %x size %x\n",
+				map_regions[ix].map_info.name,
+				map_regions[ix].window_addr_phyical,
+				map_regions[ix].map_info.size);
+			map_regions[ix].map_info.map_priv_1 =
+				(int)ioremap_nocache(
+				map_regions[ix].window_addr_phyical,
+				map_regions[ix].map_info.size);
+			if(!map_regions[ix].map_info.map_priv_1)
+			{
+				printk(MTD_FORTUNET_PK "%s flash failed to ioremap!\n",
+					map_regions[ix].map_info.name);
+				return -ENXIO;
+			}
+			printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash is veritualy at: %x\n",
+				map_regions[ix].map_info.name,
+				map_regions[ix].map_info.map_priv_1);
+			map_regions[ix].mymtd = do_map_probe("cfi_probe",
+				&map_regions[ix].map_info);
+			if((!map_regions[ix].mymtd)&&(
+				map_regions[ix].altbuswidth!=map_regions[ix].map_info.buswidth))
+			{
+				printk(KERN_NOTICE MTD_FORTUNET_PK "Trying alternet buswidth "
+					"for %s flash.\n",
+					map_regions[ix].map_info.name);
+				map_regions[ix].map_info.buswidth =
+					map_regions[ix].altbuswidth;
+				map_regions[ix].mymtd = do_map_probe("cfi_probe",
+					&map_regions[ix].map_info);
+			}
+			map_regions[ix].mymtd->module = THIS_MODULE;
+			add_mtd_partitions(map_regions[ix].mymtd,
+				map_regions[ix].parts,map_regions_parts[ix]);
+		}
+	}
+	if(iy)
+		return 0;
+	return -ENXIO;
+}
+
+static void __exit cleanup_fortunet(void)
+{
+	int	ix;
+	for(ix=0;ix<MAX_NUM_REGIONS;ix++)
+	{
+		if(map_regions_set[ix])
+		{
+			if( map_regions[ix].mymtd )
+			{
+				del_mtd_partitions( map_regions[ix].mymtd );
+				map_destroy( map_regions[ix].mymtd );
+			}
+			iounmap((void *)map_regions[ix].map_info.map_priv_1);
+		}
+	}
+}
+
+module_init(init_fortunet);
+module_exit(cleanup_fortunet);
+
+MODULE_AUTHOR("FortuNet, Inc.");
+MODULE_DESCRIPTION("MTD map driver for FortuNet boards");
diff -urN linux-2.4.21-pre3/drivers/mtd/maps/ich2rom.c linux-2.4.21-pre4/drivers/mtd/maps/ich2rom.c
--- linux-2.4.21-pre3/drivers/mtd/maps/ich2rom.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.21-pre4/drivers/mtd/maps/ich2rom.c	Tue Jan 28 19:44:30 2003
@@ -2,7 +2,7 @@
  * ich2rom.c
  *
  * Normal mappings of chips in physical memory
- * $Id: ich2rom.c,v 1.1 2002/01/10 22:59:13 eric Exp $
+ * $Id: ich2rom.c,v 1.2 2002/10/18 22:45:48 eric Exp $
  */
 
 #include <linux/module.h>
@@ -261,6 +261,9 @@
 static struct pci_device_id ich2rom_pci_tbl[] __devinitdata = {
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, 
 	  PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, 
+	  PCI_ANY_ID, PCI_ANY_ID, },
+	{ 0, },
 };
 
 MODULE_DEVICE_TABLE(pci, ich2rom_pci_tbl);
@@ -278,7 +281,14 @@
 int __init init_ich2rom(void)
 {
 	struct pci_dev *pdev;
-	pdev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, 0);
+	struct pci_device_id *id;
+	pdev = 0;
+	for(id = ich2rom_pci_tbl; id->vendor; id++) {
+		pdev = pci_find_device(id->vendor, id->device, 0);
+		if (pdev) {
+			break;
+		}
+	}
 	if (pdev) {
 		mydev = pdev;
 		return ich2rom_init_one(pdev, &ich2rom_pci_tbl[0]);
diff -urN linux-2.4.21-pre3/drivers/mtd/maps/impa7.c linux-2.4.21-pre4/drivers/mtd/maps/impa7.c
--- linux-2.4.21-pre3/drivers/mtd/maps/impa7.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/drivers/mtd/maps/impa7.c	Tue Jan 28 19:44:30 2003
@@ -0,0 +1,234 @@
+/*
+ * $Id: impa7.c,v 1.2 2002/09/05 05:11:24 acurtis Exp $
+ *
+ * Handle mapping of the NOR flash on implementa A7 boards
+ *
+ * Copyright 2002 SYSGO Real-Time Solutions GmbH
+ * 
+ * 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/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/config.h>
+
+#ifdef CONFIG_MTD_PARTITIONS
+#include <linux/mtd/partitions.h>
+#endif
+
+#define WINDOW_ADDR0 0x00000000      /* physical properties of flash */
+#define WINDOW_SIZE0 0x00800000
+#define WINDOW_ADDR1 0x10000000      /* physical properties of flash */
+#define WINDOW_SIZE1 0x00800000
+#define NUM_FLASHBANKS 2
+#define BUSWIDTH     4
+
+/* can be { "cfi_probe", "jedec_probe", "map_rom", 0 }; */
+#define PROBETYPES { "jedec_probe", 0 }
+
+#define MSG_PREFIX "impA7:"   /* prefix for our printk()'s */
+#define MTDID      "impa7-%d"  /* for mtdparts= partitioning */
+
+static struct mtd_info *impa7_mtd[NUM_FLASHBANKS] = { 0 };
+
+__u8 impa7_read8(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readb(map->map_priv_1 + ofs);
+}
+
+__u16 impa7_read16(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readw(map->map_priv_1 + ofs);
+}
+
+__u32 impa7_read32(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readl(map->map_priv_1 + ofs);
+}
+
+void impa7_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	memcpy_fromio(to, map->map_priv_1 + from, len);
+}
+
+void impa7_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+	__raw_writeb(d, map->map_priv_1 + adr);
+	mb();
+}
+
+void impa7_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+	__raw_writew(d, map->map_priv_1 + adr);
+	mb();
+}
+
+void impa7_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+	__raw_writel(d, map->map_priv_1 + adr);
+	mb();
+}
+
+void impa7_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	memcpy_toio(map->map_priv_1 + to, from, len);
+}
+
+static struct map_info impa7_map[NUM_FLASHBANKS] = {
+	{
+	name: "impA7 NOR Flash Bank #0",
+	size: WINDOW_SIZE0,
+	buswidth: BUSWIDTH,
+	read8: impa7_read8,
+	read16: impa7_read16,
+	read32: impa7_read32,
+	copy_from: impa7_copy_from,
+	write8: impa7_write8,
+	write16: impa7_write16,
+	write32: impa7_write32,
+	copy_to: impa7_copy_to
+	},
+	{
+	name: "impA7 NOR Flash Bank #1",
+	size: WINDOW_SIZE1,
+	buswidth: BUSWIDTH,
+	read8: impa7_read8,
+	read16: impa7_read16,
+	read32: impa7_read32,
+	copy_from: impa7_copy_from,
+	write8: impa7_write8,
+	write16: impa7_write16,
+	write32: impa7_write32,
+	copy_to: impa7_copy_to
+	},
+};
+
+#ifdef CONFIG_MTD_PARTITIONS
+
+/*
+ * MTD partitioning stuff 
+ */
+static struct mtd_partition static_partitions[] =
+{
+    {
+	name: "FileSystem",
+	  size: 0x800000,
+	  offset: 0x00000000
+    },
+};
+
+#define NB_OF(x) (sizeof (x) / sizeof (x[0]))
+
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+int parse_cmdline_partitions(struct mtd_info *master, 
+			     struct mtd_partition **pparts,
+			     const char *mtd_id);
+#endif
+
+#endif
+
+static int                   mtd_parts_nb = 0;
+static struct mtd_partition *mtd_parts    = 0;
+
+int __init init_impa7(void)
+{
+	static const char *rom_probe_types[] = PROBETYPES;
+	const char **type;
+	const char *part_type = 0;
+	int i;
+	static struct { u_long addr; u_long size; } pt[NUM_FLASHBANKS] = {
+	  { WINDOW_ADDR0, WINDOW_SIZE0 },
+	  { WINDOW_ADDR1, WINDOW_SIZE1 },
+        };
+	char mtdid[10];
+	int devicesfound = 0;
+
+	for(i=0; i<NUM_FLASHBANKS; i++)
+	{
+		printk(KERN_NOTICE MSG_PREFIX "probing 0x%08lx at 0x%08lx\n",
+		       pt[i].size, pt[i].addr);
+		impa7_map[i].map_priv_1 = (unsigned long)
+		  ioremap(pt[i].addr, pt[i].size);
+
+		if (!impa7_map[i].map_priv_1) {
+			printk(MSG_PREFIX "failed to ioremap\n");
+			return -EIO;
+		}
+
+		impa7_mtd[i] = 0;
+		type = rom_probe_types;
+		for(; !impa7_mtd[i] && *type; type++) {
+			impa7_mtd[i] = do_map_probe(*type, &impa7_map[i]);
+		}
+
+		if (impa7_mtd[i]) 
+		{
+			impa7_mtd[i]->module = THIS_MODULE;
+			add_mtd_device(impa7_mtd[i]);
+			devicesfound++;
+#ifdef CONFIG_MTD_PARTITIONS
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+			sprintf(mtdid, MTDID, i);
+			mtd_parts_nb = parse_cmdline_partitions(impa7_mtd[i], 
+								&mtd_parts, 
+								mtdid);
+			if (mtd_parts_nb > 0)
+			  part_type = "command line";
+#endif
+			if (mtd_parts_nb <= 0)
+			{
+				mtd_parts = static_partitions;
+				mtd_parts_nb = NB_OF(static_partitions);
+				part_type = "static";
+			}
+			if (mtd_parts_nb <= 0)
+			{
+				printk(KERN_NOTICE MSG_PREFIX 
+				       "no partition info available\n");
+			}
+			else
+			{
+				printk(KERN_NOTICE MSG_PREFIX
+				       "using %s partition definition\n", 
+				       part_type);
+				add_mtd_partitions(impa7_mtd[i], 
+						   mtd_parts, mtd_parts_nb);
+			}
+#endif
+		}
+		else 
+		  iounmap((void *)impa7_map[i].map_priv_1);
+	}
+	return devicesfound == 0 ? -ENXIO : 0;
+}
+
+static void __exit cleanup_impa7(void)
+{
+	int i;
+	for (i=0; i<NUM_FLASHBANKS; i++) 
+	{
+		if (impa7_mtd[i]) 
+		{
+			del_mtd_device(impa7_mtd[i]);
+			map_destroy(impa7_mtd[i]);
+		}
+		if (impa7_map[i].map_priv_1)
+		{
+			iounmap((void *)impa7_map[i].map_priv_1);
+			impa7_map[i].map_priv_1 = 0;
+		}
+	}
+}
+
+module_init(init_impa7);
+module_exit(cleanup_impa7);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Pavel Bartusek <pba@sysgo.de>");
+MODULE_DESCRIPTION("MTD map driver for implementa impA7");
diff -urN linux-2.4.21-pre3/drivers/mtd/maps/lasat.c linux-2.4.21-pre4/drivers/mtd/maps/lasat.c
--- linux-2.4.21-pre3/drivers/mtd/maps/lasat.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/drivers/mtd/maps/lasat.c	Tue Jan 28 19:44:30 2003
@@ -0,0 +1,140 @@
+/*
+ * Flash device on lasat 100 and 200 boards
+ *
+ * Presumably (C) 2002 Brian Murphy <brian@murphy.dk> or whoever he
+ * works for.
+ *
+ * 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.
+ *
+ * $Id: lasat.c,v 1.1 2003/01/24 14:26:38 dwmw2 Exp $
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/config.h>
+#include <asm/lasat/lasat.h>
+#include <asm/lasat/lasat_mtd.h>
+
+static struct mtd_info *mymtd;
+
+static __u8 sp_read8(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readb(map->map_priv_1 + ofs);
+}
+
+static __u16 sp_read16(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readw(map->map_priv_1 + ofs);
+}
+
+static __u32 sp_read32(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readl(map->map_priv_1 + ofs);
+}
+
+static void sp_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	memcpy_fromio(to, map->map_priv_1 + from, len);
+}
+
+static void sp_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+	__raw_writeb(d, map->map_priv_1 + adr);
+	mb();
+}
+
+static void sp_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+	__raw_writew(d, map->map_priv_1 + adr);
+	mb();
+}
+
+static void sp_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+	__raw_writel(d, map->map_priv_1 + adr);
+	mb();
+}
+
+static void sp_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	memcpy_toio(map->map_priv_1 + to, from, len);
+}
+
+static struct map_info sp_map = {
+	.name = "SP flash",
+	.buswidth = 4,
+	.read8 = sp_read8,
+	.read16 = sp_read16,
+	.read32 = sp_read32,
+	.copy_from = sp_copy_from,
+	.write8 = sp_write8,
+	.write16 = sp_write16,
+	.write32 = sp_write32,
+	.copy_to = sp_copy_to
+};
+
+static struct mtd_partition partition_info[LASAT_MTD_LAST];
+static char *lasat_mtd_partnames[] = {"Bootloader", "Service", "Normal", "Filesystem", "Config"};
+
+static int __init init_sp(void)
+{
+	int i;
+	/* this does not play well with the old flash code which 
+	 * protects and uprotects the flash when necessary */
+       	printk(KERN_NOTICE "Unprotecting flash\n");
+	*lasat_misc->flash_wp_reg |= 1 << lasat_misc->flash_wp_bit;
+
+	sp_map.map_priv_1 = lasat_flash_partition_start(LASAT_MTD_BOOTLOADER);
+	sp_map.size = lasat_board_info.li_flash_size;
+
+       	printk(KERN_NOTICE "sp flash device: %lx at %lx\n", 
+			sp_map.size, sp_map.map_priv_1);
+
+	for (i=0; i < LASAT_MTD_LAST; i++)
+		partition_info[i].name = lasat_mtd_partnames[i];
+
+	mymtd = do_map_probe("cfi_probe", &sp_map);
+	if (mymtd) {
+		u32 size, offset = 0;
+
+		mymtd->module = THIS_MODULE;
+
+		for (i=0; i < LASAT_MTD_LAST; i++) {
+			size = lasat_flash_partition_size(i);
+			partition_info[i].size = size;
+			partition_info[i].offset = offset;
+			offset += size;
+		}
+
+		add_mtd_partitions( mymtd, partition_info, LASAT_MTD_LAST );
+		return 0;
+	}
+
+	return -ENXIO;
+}
+
+static void __exit cleanup_sp(void)
+{
+	if (mymtd) {
+		del_mtd_partitions(mymtd);
+		map_destroy(mymtd);
+	}
+	if (sp_map.map_priv_1) {
+		sp_map.map_priv_1 = 0;
+	}
+}
+
+module_init(init_sp);
+module_exit(cleanup_sp);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Brian Murphy <brian@murphy.dk>");
+MODULE_DESCRIPTION("Lasat Safepipe/Masquerade MTD map driver");
diff -urN linux-2.4.21-pre3/drivers/mtd/maps/nettel.c linux-2.4.21-pre4/drivers/mtd/maps/nettel.c
--- linux-2.4.21-pre3/drivers/mtd/maps/nettel.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/drivers/mtd/maps/nettel.c	Tue Jan 28 19:44:30 2003
@@ -0,0 +1,551 @@
+/****************************************************************************/
+
+/*
+ *      nettel.c -- mappings for NETtel/SecureEdge/SnapGear (x86) boards.
+ *
+ *      (C) Copyright 2000-2001, Greg Ungerer (gerg@snapgear.com)
+ *      (C) Copyright 2001-2002, SnapGear (www.snapgear.com)
+ *
+ *	$Id: nettel.c,v 1.1 2002/08/08 06:30:13 gerg Exp $
+ */
+
+/****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/cfi.h>
+#include <linux/reboot.h>
+#include <asm/io.h>
+
+/****************************************************************************/
+
+#define INTEL_BUSWIDTH		1
+#define AMD_WINDOW_MAXSIZE	0x00200000
+#define AMD_BUSWIDTH	 	1
+
+/*
+ *	PAR masks and shifts, assuming 64K pages.
+ */
+#define SC520_PAR_ADDR_MASK	0x00003fff
+#define SC520_PAR_ADDR_SHIFT	16
+#define SC520_PAR_TO_ADDR(par) \
+	(((par)&SC520_PAR_ADDR_MASK) << SC520_PAR_ADDR_SHIFT)
+
+#define SC520_PAR_SIZE_MASK	0x01ffc000
+#define SC520_PAR_SIZE_SHIFT	2
+#define SC520_PAR_TO_SIZE(par) \
+	((((par)&SC520_PAR_SIZE_MASK) << SC520_PAR_SIZE_SHIFT) + (64*1024))
+
+#define SC520_PAR(cs, addr, size) \
+	((cs) | \
+	((((size)-(64*1024)) >> SC520_PAR_SIZE_SHIFT) & SC520_PAR_SIZE_MASK) | \
+	(((addr) >> SC520_PAR_ADDR_SHIFT) & SC520_PAR_ADDR_MASK))
+
+#define SC520_PAR_BOOTCS	0x8a000000
+#define	SC520_PAR_ROMCS1	0xaa000000
+#define SC520_PAR_ROMCS2	0xca000000	/* Cache disabled, 64K page */
+
+static void *nettel_mmcrp = NULL;
+
+#ifdef CONFIG_MTD_CFI_INTELEXT
+static struct mtd_info *intel_mtd;
+#endif
+static struct mtd_info *amd_mtd;
+
+/****************************************************************************/
+
+static __u8 nettel_read8(struct map_info *map, unsigned long ofs)
+{
+	return(readb(map->map_priv_1 + ofs));
+}
+
+static __u16 nettel_read16(struct map_info *map, unsigned long ofs)
+{
+	return(readw(map->map_priv_1 + ofs));
+}
+
+static __u32 nettel_read32(struct map_info *map, unsigned long ofs)
+{
+	return(readl(map->map_priv_1 + ofs));
+}
+
+static void nettel_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	memcpy_fromio(to, map->map_priv_1 + from, len);
+}
+
+static void nettel_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+	writeb(d, map->map_priv_1 + adr);
+}
+
+static void nettel_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+	writew(d, map->map_priv_1 + adr);
+}
+
+static void nettel_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+	writel(d, map->map_priv_1 + adr);
+}
+
+static void nettel_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	memcpy_toio(map->map_priv_1 + to, from, len);
+}
+
+/****************************************************************************/
+
+#ifdef CONFIG_MTD_CFI_INTELEXT
+static struct map_info nettel_intel_map = {
+	name: "SnapGear Intel",
+	size: 0,
+	buswidth: INTEL_BUSWIDTH,
+	read8: nettel_read8,
+	read16: nettel_read16,
+	read32: nettel_read32,
+	copy_from: nettel_copy_from,
+	write8: nettel_write8,
+	write16: nettel_write16,
+	write32: nettel_write32,
+	copy_to: nettel_copy_to
+};
+
+static struct mtd_partition nettel_intel_partitions[] = {
+	{
+		name: "SnapGear kernel",
+		offset: 0,
+		size: 0x000e0000
+	},
+	{
+		name: "SnapGear filesystem",
+		offset: 0x00100000,
+	},
+	{
+		name: "SnapGear config",
+		offset: 0x000e0000,
+		size: 0x00020000
+	},
+	{
+		name: "SnapGear Intel",
+		offset: 0
+	},
+	{
+		name: "SnapGear BIOS Config",
+		offset: 0x007e0000,
+		size: 0x00020000
+	},
+	{
+		name: "SnapGear BIOS",
+		offset: 0x007e0000,
+		size: 0x00020000
+	},
+};
+#endif
+
+static struct map_info nettel_amd_map = {
+	name: "SnapGear AMD",
+	size: AMD_WINDOW_MAXSIZE,
+	buswidth: AMD_BUSWIDTH,
+	read8: nettel_read8,
+	read16: nettel_read16,
+	read32: nettel_read32,
+	copy_from: nettel_copy_from,
+	write8: nettel_write8,
+	write16: nettel_write16,
+	write32: nettel_write32,
+	copy_to: nettel_copy_to
+};
+
+static struct mtd_partition nettel_amd_partitions[] = {
+	{
+		name: "SnapGear BIOS config",
+		offset: 0x000e0000,
+		size: 0x00010000
+	},
+	{
+		name: "SnapGear BIOS",
+		offset: 0x000f0000,
+		size: 0x00010000
+	},
+	{
+		name: "SnapGear AMD",
+		offset: 0
+	},
+	{
+		name: "SnapGear high BIOS",
+		offset: 0x001f0000,
+		size: 0x00010000
+	}
+};
+
+#define NUM_AMD_PARTITIONS \
+	(sizeof(nettel_amd_partitions)/sizeof(nettel_amd_partitions[0]))
+
+/****************************************************************************/
+
+#ifdef CONFIG_MTD_CFI_INTELEXT
+
+/*
+ *	Set the Intel flash back to read mode since some old boot
+ *	loaders don't.
+ */
+static int nettel_reboot_notifier(struct notifier_block *nb, unsigned long val, void *v)
+{
+	struct cfi_private *cfi = nettel_intel_map.fldrv_priv;
+	unsigned long b;
+	
+	/* Make sure all FLASH chips are put back into read mode */
+	for (b = 0; (b < nettel_intel_partitions[3].size); b += 0x100000) {
+		cfi_send_gen_cmd(0xff, 0x55, b, &nettel_intel_map, cfi,
+			cfi->device_type, NULL);
+	}
+	return(NOTIFY_OK);
+}
+
+static struct notifier_block nettel_notifier_block = {
+	nettel_reboot_notifier, NULL, 0
+};
+
+/*
+ *	Erase the configuration file system.
+ *	Used to support the software reset button.
+ */
+static void nettel_erasecallback(struct erase_info *done)
+{
+	wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv;
+	wake_up(wait_q);
+}
+
+static struct erase_info nettel_erase;
+
+int nettel_eraseconfig(void)
+{
+	struct mtd_info *mtd;
+	DECLARE_WAITQUEUE(wait, current);
+	wait_queue_head_t wait_q;
+	int ret;
+
+	init_waitqueue_head(&wait_q);
+	mtd = get_mtd_device(NULL, 2);
+	if (mtd) {
+		nettel_erase.mtd = mtd;
+		nettel_erase.callback = nettel_erasecallback;
+		nettel_erase.callback = 0;
+		nettel_erase.addr = 0;
+		nettel_erase.len = mtd->size;
+		nettel_erase.priv = (u_long) &wait_q;
+		nettel_erase.priv = 0;
+
+		set_current_state(TASK_INTERRUPTIBLE);
+		add_wait_queue(&wait_q, &wait);
+
+		ret = MTD_ERASE(mtd, &nettel_erase);
+		if (ret) {
+			set_current_state(TASK_RUNNING);
+			remove_wait_queue(&wait_q, &wait);
+			put_mtd_device(mtd);
+			return(ret);
+		}
+
+		schedule();  /* Wait for erase to finish. */
+		remove_wait_queue(&wait_q, &wait);
+		
+		put_mtd_device(mtd);
+	}
+
+	return(0);
+}
+
+#else
+
+int nettel_eraseconfig(void)
+{
+	return(0);
+}
+
+#endif
+
+/****************************************************************************/
+
+int __init nettel_init(void)
+{
+	volatile unsigned long *amdpar;
+	unsigned long amdaddr, maxsize;
+	int num_amd_partitions=0;
+#ifdef CONFIG_MTD_CFI_INTELEXT
+	volatile unsigned long *intel0par, *intel1par;
+	unsigned long orig_bootcspar, orig_romcs1par;
+	unsigned long intel0addr, intel0size;
+	unsigned long intel1addr, intel1size;
+	int intelboot, intel0cs, intel1cs;
+	int num_intel_partitions;
+#endif
+	int rc = 0;
+
+	nettel_mmcrp = (void *) ioremap_nocache(0xfffef000, 4096);
+	if (nettel_mmcrp == NULL) {
+		printk("SNAPGEAR: failed to disable MMCR cache??\n");
+		return(-EIO);
+	}
+
+	/* Set CPU clock to be 33.000MHz */
+	*((unsigned char *) (nettel_mmcrp + 0xc64)) = 0x01;
+
+	amdpar = (volatile unsigned long *) (nettel_mmcrp + 0xc4);
+
+#ifdef CONFIG_MTD_CFI_INTELEXT
+	intelboot = 0;
+	intel0cs = SC520_PAR_ROMCS1;
+	intel0par = (volatile unsigned long *) (nettel_mmcrp + 0xc0);
+	intel1cs = SC520_PAR_ROMCS2;
+	intel1par = (volatile unsigned long *) (nettel_mmcrp + 0xbc);
+
+	/*
+	 *	Save the CS settings then ensure ROMCS1 and ROMCS2 are off,
+	 *	otherwise they might clash with where we try to map BOOTCS.
+	 */
+	orig_bootcspar = *amdpar;
+	orig_romcs1par = *intel0par;
+	*intel0par = 0;
+	*intel1par = 0;
+#endif
+
+	/*
+	 *	The first thing to do is determine if we have a separate
+	 *	boot FLASH device. Typically this is a small (1 to 2MB)
+	 *	AMD FLASH part. It seems that device size is about the
+	 *	only way to tell if this is the case...
+	 */
+	amdaddr = 0x20000000;
+	maxsize = AMD_WINDOW_MAXSIZE;
+
+	*amdpar = SC520_PAR(SC520_PAR_BOOTCS, amdaddr, maxsize);
+	__asm__ ("wbinvd");
+
+	nettel_amd_map.map_priv_1 = (unsigned long)
+		ioremap_nocache(amdaddr, maxsize);
+	if (!nettel_amd_map.map_priv_1) {
+		printk("SNAPGEAR: failed to ioremap() BOOTCS\n");
+		return(-EIO);
+	}
+
+	if ((amd_mtd = do_map_probe("jedec_probe", &nettel_amd_map))) {
+		printk(KERN_NOTICE "SNAPGEAR: AMD flash device size = %dK\n",
+			amd_mtd->size>>10);
+
+		amd_mtd->module = THIS_MODULE;
+
+		/* The high BIOS partition is only present for 2MB units */
+		num_amd_partitions = NUM_AMD_PARTITIONS;
+		if (amd_mtd->size < AMD_WINDOW_MAXSIZE)
+			num_amd_partitions--;
+		/* Don't add the partition until after the primary INTEL's */
+
+#ifdef CONFIG_MTD_CFI_INTELEXT
+		/*
+		 *	Map the Intel flash into memory after the AMD
+		 *	It has to start on a multiple of maxsize.
+		 */
+		maxsize = SC520_PAR_TO_SIZE(orig_romcs1par);
+		if (maxsize < (32 * 1024 * 1024))
+			maxsize = (32 * 1024 * 1024);
+		intel0addr = amdaddr + maxsize;
+#endif
+	} else {
+#ifdef CONFIG_MTD_CFI_INTELEXT
+		/* INTEL boot FLASH */
+		intelboot++;
+
+		if (!orig_romcs1par) {
+			intel0cs = SC520_PAR_BOOTCS;
+			intel0par = (volatile unsigned long *)
+				(nettel_mmcrp + 0xc4);
+			intel1cs = SC520_PAR_ROMCS1;
+			intel1par = (volatile unsigned long *)
+				(nettel_mmcrp + 0xc0);
+
+			intel0addr = SC520_PAR_TO_ADDR(orig_bootcspar);
+			maxsize = SC520_PAR_TO_SIZE(orig_bootcspar);
+		} else {
+			/* Kernel base is on ROMCS1, not BOOTCS */
+			intel0cs = SC520_PAR_ROMCS1;
+			intel0par = (volatile unsigned long *)
+				(nettel_mmcrp + 0xc0);
+			intel1cs = SC520_PAR_BOOTCS;
+			intel1par = (volatile unsigned long *)
+				(nettel_mmcrp + 0xc4);
+
+			intel0addr = SC520_PAR_TO_ADDR(orig_romcs1par);
+			maxsize = SC520_PAR_TO_SIZE(orig_romcs1par);
+		}
+
+		/* Destroy useless AMD MTD mapping */
+		amd_mtd = NULL;
+		iounmap((void *) nettel_amd_map.map_priv_1);
+		nettel_amd_map.map_priv_1 = (unsigned long) NULL;
+#else
+		/* Only AMD flash supported */
+		return(-ENXIO);
+#endif
+	}
+
+#ifdef CONFIG_MTD_CFI_INTELEXT
+	/*
+	 *	We have determined the INTEL FLASH configuration, so lets
+	 *	go ahead and probe for them now.
+	 */
+
+	/* Set PAR to the maximum size */
+	if (maxsize < (32 * 1024 * 1024))
+		maxsize = (32 * 1024 * 1024);
+	*intel0par = SC520_PAR(intel0cs, intel0addr, maxsize);
+
+	/* Turn other PAR off so the first probe doesn't find it */
+	*intel1par = 0;
+
+	/* Probe for the the size of the first Intel flash */
+	nettel_intel_map.size = maxsize;
+	nettel_intel_map.map_priv_1 = (unsigned long)
+		ioremap_nocache(intel0addr, maxsize);
+	if (!nettel_intel_map.map_priv_1) {
+		printk("SNAPGEAR: failed to ioremap() ROMCS1\n");
+		return(-EIO);
+	}
+
+	intel_mtd = do_map_probe("cfi_probe", &nettel_intel_map);
+	if (! intel_mtd) {
+		iounmap((void *) nettel_intel_map.map_priv_1);
+		return(-ENXIO);
+	}
+
+	/* Set PAR to the detected size */
+	intel0size = intel_mtd->size;
+	*intel0par = SC520_PAR(intel0cs, intel0addr, intel0size);
+
+	/*
+	 *	Map second Intel FLASH right after first. Set its size to the
+	 *	same maxsize used for the first Intel FLASH.
+	 */
+	intel1addr = intel0addr + intel0size;
+	*intel1par = SC520_PAR(intel1cs, intel1addr, maxsize);
+	__asm__ ("wbinvd");
+
+	maxsize += intel0size;
+
+	/* Delete the old map and probe again to do both chips */
+	map_destroy(intel_mtd);
+	intel_mtd = NULL;
+	iounmap((void *) nettel_intel_map.map_priv_1);
+
+	nettel_intel_map.size = maxsize;
+	nettel_intel_map.map_priv_1 = (unsigned long)
+		ioremap_nocache(intel0addr, maxsize);
+	if (!nettel_intel_map.map_priv_1) {
+		printk("SNAPGEAR: failed to ioremap() ROMCS1/2\n");
+		return(-EIO);
+	}
+
+	intel_mtd = do_map_probe("cfi_probe", &nettel_intel_map);
+	if (! intel_mtd) {
+		iounmap((void *) nettel_intel_map.map_priv_1);
+		return(-ENXIO);
+	}
+
+	intel1size = intel_mtd->size - intel0size;
+	if (intel1size > 0) {
+		*intel1par = SC520_PAR(intel1cs, intel1addr, intel1size);
+		__asm__ ("wbinvd");
+	} else {
+		*intel1par = 0;
+	}
+
+	printk(KERN_NOTICE "SNAPGEAR: Intel flash device size = %dK\n",
+		(intel_mtd->size >> 10));
+
+	intel_mtd->module = THIS_MODULE;
+
+#ifndef CONFIG_BLK_DEV_INITRD
+	ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, 1);
+#endif
+
+	num_intel_partitions = sizeof(nettel_intel_partitions) /
+		sizeof(nettel_intel_partitions[0]);
+
+	if (intelboot) {
+		/*
+		 *	Adjust offset and size of last boot partition.
+		 *	Must allow for BIOS region at end of FLASH.
+		 */
+		nettel_intel_partitions[1].size = (intel0size + intel1size) -
+			(1024*1024 + intel_mtd->erasesize);
+		nettel_intel_partitions[3].size = intel0size + intel1size;
+		nettel_intel_partitions[4].offset = 
+			(intel0size + intel1size) - intel_mtd->erasesize;
+		nettel_intel_partitions[4].size = intel_mtd->erasesize;
+		nettel_intel_partitions[5].offset =
+			nettel_intel_partitions[4].offset;
+		nettel_intel_partitions[5].size =
+			nettel_intel_partitions[4].size;
+	} else {
+		/* No BIOS regions when AMD boot */
+		num_intel_partitions -= 2;
+	}
+	rc = add_mtd_partitions(intel_mtd, nettel_intel_partitions,
+		num_intel_partitions);
+#endif
+
+	if (amd_mtd) {
+		rc = add_mtd_partitions(amd_mtd, nettel_amd_partitions,
+			num_amd_partitions);
+	}
+
+#ifdef CONFIG_MTD_CFI_INTELEXT
+	register_reboot_notifier(&nettel_notifier_block);
+#endif
+
+	return(rc);
+}
+
+/****************************************************************************/
+
+void __exit nettel_cleanup(void)
+{
+#ifdef CONFIG_MTD_CFI_INTELEXT
+	unregister_reboot_notifier(&nettel_notifier_block);
+#endif
+	if (amd_mtd) {
+		del_mtd_partitions(amd_mtd);
+		map_destroy(amd_mtd);
+	}
+	if (nettel_amd_map.map_priv_1) {
+		iounmap((void *)nettel_amd_map.map_priv_1);
+		nettel_amd_map.map_priv_1 = 0;
+	}
+#ifdef CONFIG_MTD_CFI_INTELEXT
+	if (intel_mtd) {
+		del_mtd_partitions(intel_mtd);
+		map_destroy(intel_mtd);
+	}
+	if (nettel_intel_map.map_priv_1) {
+		iounmap((void *)nettel_intel_map.map_priv_1);
+		nettel_intel_map.map_priv_1 = 0;
+	}
+#endif
+}
+
+/****************************************************************************/
+
+module_init(nettel_init);
+module_exit(nettel_cleanup);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com>");
+MODULE_DESCRIPTION("SnapGear/SecureEdge FLASH support");
+
+/****************************************************************************/
diff -urN linux-2.4.21-pre3/drivers/mtd/maps/octagon-5066.c linux-2.4.21-pre4/drivers/mtd/maps/octagon-5066.c
--- linux-2.4.21-pre3/drivers/mtd/maps/octagon-5066.c	Thu Oct  4 15:14:59 2001
+++ linux-2.4.21-pre4/drivers/mtd/maps/octagon-5066.c	Tue Jan 28 19:44:30 2003
@@ -1,4 +1,4 @@
-// $Id: octagon-5066.c,v 1.19 2001/10/02 15:05:14 dwmw2 Exp $
+// $Id: octagon-5066.c,v 1.20 2003/01/07 17:21:55 dwmw2 Exp $
 /* ######################################################################
 
    Octagon 5066 MTD Driver. 
@@ -223,33 +223,32 @@
 		}
 	}
 	iounmap((void *)iomapadr);
-	release_region(PAGE_IO,1);
+	release_region(PAGE_IO, 1);
 }
 
 int __init init_oct5066(void)
 {
 	int i;
-	
+	int ret = 0;
+
 	// Do an autoprobe sequence
-	if (check_region(PAGE_IO,1) != 0)
-		{
-			printk("5066: Page Register in Use\n");
-			return -EAGAIN;
-		}
+	if (!request_region(PAGE_IO,1,"Octagon SSD")) {
+		printk(KERN_NOTICE "5066: Page Register in Use\n");
+		return -EAGAIN;
+	}
 	iomapadr = (unsigned long)ioremap(WINDOW_START, WINDOW_LENGTH);
 	if (!iomapadr) {
-		printk("Failed to ioremap memory region\n");
-		return -EIO;
+		printk(KERN_NOTICE "Failed to ioremap memory region\n");
+		ret = -EIO;
+		goto out_rel;
 	}
-	if (OctProbe() != 0)
-		{
-			printk("5066: Octagon Probe Failed, is this an Octagon 5066 SBC?\n");
-			iounmap((void *)iomapadr);
-			return -EAGAIN;
-		}
-	
-	request_region(PAGE_IO,1,"Octagon SSD");
-	
+	if (OctProbe() != 0) {
+		printk(KERN_NOTICE "5066: Octagon Probe Failed, is this an Octagon 5066 SBC?\n");
+		iounmap((void *)iomapadr);
+		ret = -EAGAIN;
+		goto out_unmap;
+	}
+      	
 	// Print out our little header..
 	printk("Octagon 5066 SSD IO:0x%x MEM:0x%x-0x%x\n",PAGE_IO,WINDOW_START,
 	       WINDOW_START+WINDOW_LENGTH);
@@ -272,8 +271,14 @@
 		cleanup_oct5066();
 		return -ENXIO;
 	}	  
-	
+
 	return 0;
+
+ out_unmap:
+	iounmap((void *)iomapadr);
+ out_rel:
+	release_region(PAGE_IO, 1);
+	return ret;
 }
 
 module_init(init_oct5066);
diff -urN linux-2.4.21-pre3/drivers/mtd/maps/pb1xxx-flash.c linux-2.4.21-pre4/drivers/mtd/maps/pb1xxx-flash.c
--- linux-2.4.21-pre3/drivers/mtd/maps/pb1xxx-flash.c	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre4/drivers/mtd/maps/pb1xxx-flash.c	Tue Jan 28 19:44:30 2003
@@ -3,7 +3,7 @@
  * 
  * (C) 2001 Pete Popov <ppopov@mvista.com>
  * 
- * $Id: pb1xxx-flash.c,v 1.5 2002/02/01 23:08:50 ppopov Exp $
+ * $Id: pb1xxx-flash.c,v 1.4 2002/09/13 13:51:54 dwmw2 Exp $
  */
 
 #include <linux/config.h>
@@ -131,8 +131,8 @@
 
 static unsigned char flash_buswidth = 4;
 #if defined(CONFIG_MTD_PB1500_BOOT) && defined(CONFIG_MTD_PB1500_USER)
-/* both 32MB banks will be used. Combine the first 32MB bank and the
- * first 28MB of the second bank together into a single jffs/jffs2
+/* both 32MiB banks will be used. Combine the first 32MiB bank and the
+ * first 28MiB of the second bank together into a single jffs/jffs2
  * partition.
  */
 static unsigned long flash_size = 0x04000000;
diff -urN linux-2.4.21-pre3/drivers/mtd/maps/pci.c linux-2.4.21-pre4/drivers/mtd/maps/pci.c
--- linux-2.4.21-pre3/drivers/mtd/maps/pci.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.21-pre4/drivers/mtd/maps/pci.c	Tue Jan 28 19:44:30 2003
@@ -7,7 +7,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  *
- *  $Id: pci.c,v 1.1 2001/09/27 20:28:45 rmk Exp $
+ *  $Id: pci.c,v 1.2 2003/01/24 13:11:43 dwmw2 Exp $
  * 
  * Generic PCI memory map driver.  We support the following boards:
  *  - Intel IQ80310 ATU.
diff -urN linux-2.4.21-pre3/drivers/mtd/maps/pcmciamtd.c linux-2.4.21-pre4/drivers/mtd/maps/pcmciamtd.c
--- linux-2.4.21-pre3/drivers/mtd/maps/pcmciamtd.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/drivers/mtd/maps/pcmciamtd.c	Tue Jan 28 19:44:30 2003
@@ -0,0 +1,895 @@
+/*
+ * $Id: pcmciamtd.c,v 1.39 2003/01/06 17:51:38 spse Exp $
+ *
+ * pcmciamtd.c - MTD driver for PCMCIA flash memory cards
+ *
+ * Author: Simon Evans <spse@secret.org.uk>
+ *
+ * Copyright (C) 2002 Simon Evans
+ *
+ * Licence: GPL
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/timer.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+#include <linux/mtd/map.h>
+
+#ifdef CONFIG_MTD_DEBUG
+static int debug = CONFIG_MTD_DEBUG_VERBOSE;
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Set Debug Level 0=quiet, 5=noisy");
+#undef DEBUG
+#define DEBUG(n, format, arg...) \
+	if (n <= debug) {	 \
+		printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __FUNCTION__ , ## arg); \
+	}
+
+#else
+#undef DEBUG
+#define DEBUG(n, arg...)
+static const int debug = 0;
+#endif
+
+#define err(format, arg...) printk(KERN_ERR "pcmciamtd: " format "\n" , ## arg)
+#define info(format, arg...) printk(KERN_INFO "pcmciamtd: " format "\n" , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING "pcmciamtd: " format "\n" , ## arg)
+
+
+#define DRIVER_DESC	"PCMCIA Flash memory card driver"
+#define DRIVER_VERSION	"$Revision: 1.39 $"
+
+/* Size of the PCMCIA address space: 26 bits = 64 MB */
+#define MAX_PCMCIA_ADDR	0x4000000
+
+struct pcmciamtd_dev {
+	dev_link_t	link;		/* PCMCIA link */
+	dev_node_t	node;		/* device node */
+	caddr_t		win_base;	/* ioremapped address of PCMCIA window */
+	unsigned int	win_size;	/* size of window */
+	unsigned int	offset;		/* offset into card the window currently points at */
+	struct map_info	pcmcia_map;
+	struct mtd_info	*mtd_info;
+	int		vpp;
+	char		mtd_name[sizeof(struct cistpl_vers_1_t)];
+};
+
+
+static dev_info_t dev_info = "pcmciamtd";
+static dev_link_t *dev_list;
+
+/* Module parameters */
+
+/* 2 = do 16-bit transfers, 1 = do 8-bit transfers */
+static int buswidth = 2;
+
+/* Speed of memory accesses, in ns */
+static int mem_speed;
+
+/* Force the size of an SRAM card */
+static int force_size;
+
+/* Force Vpp */
+static int vpp;
+
+/* Set Vpp */
+static int setvpp;
+
+/* Force card to be treated as FLASH, ROM or RAM */
+static int mem_type;
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Simon Evans <spse@secret.org.uk>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_PARM(buswidth, "i");
+MODULE_PARM_DESC(buswidth, "Set buswidth (1=8 bit, 2=16 bit, default=2)");
+MODULE_PARM(mem_speed, "i");
+MODULE_PARM_DESC(mem_speed, "Set memory access speed in ns");
+MODULE_PARM(force_size, "i");
+MODULE_PARM_DESC(force_size, "Force size of card in MB (1-64)");
+MODULE_PARM(setvpp, "i");
+MODULE_PARM_DESC(setvpp, "Set Vpp (0=Never, 1=On writes, 2=Always on, default=0)");
+MODULE_PARM(vpp, "i");
+MODULE_PARM_DESC(vpp, "Vpp value in 1/10ths eg 33=3.3V 120=12V (Dangerous)");
+MODULE_PARM(mem_type, "i");
+MODULE_PARM_DESC(mem_type, "Set Memory type (0=Flash, 1=RAM, 2=ROM, default=0)");
+
+
+
+static inline void cs_error(client_handle_t handle, int func, int ret)
+{
+	error_info_t err = { func, ret };
+	CardServices(ReportError, handle, &err);
+}
+
+
+/* read/write{8,16} copy_{from,to} routines with window remapping to access whole card */
+
+static caddr_t remap_window(struct map_info *map, unsigned long to)
+{
+	struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1;
+	window_handle_t win = (window_handle_t)map->map_priv_2;
+	memreq_t mrq;
+	int ret;
+
+	if(!(dev->link.state & DEV_PRESENT)) {
+		DEBUG(1, "device removed state = 0x%4.4X", dev->link.state);
+		return 0;
+	}
+
+	mrq.CardOffset = to & ~(dev->win_size-1);
+	if(mrq.CardOffset != dev->offset) {
+		DEBUG(2, "Remapping window from 0x%8.8x to 0x%8.8x",
+		      dev->offset, mrq.CardOffset);
+		mrq.Page = 0;
+		if( (ret = CardServices(MapMemPage, win, &mrq)) != CS_SUCCESS) {
+			cs_error(dev->link.handle, MapMemPage, ret);
+			return NULL;
+		}
+		dev->offset = mrq.CardOffset;
+	}
+	return dev->win_base + (to & (dev->win_size-1));
+}
+
+
+static u8 pcmcia_read8_remap(struct map_info *map, unsigned long ofs)
+{
+	caddr_t addr;
+	u8 d;
+
+	addr = remap_window(map, ofs);
+	if(!addr)
+		return 0;
+
+	d = readb(addr);
+	DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%02x", ofs, addr, d);
+	return d;
+}
+
+
+static u16 pcmcia_read16_remap(struct map_info *map, unsigned long ofs)
+{
+	caddr_t addr;
+	u16 d;
+
+	addr = remap_window(map, ofs);
+	if(!addr)
+		return 0;
+
+	d = readw(addr);
+	DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%04x", ofs, addr, d);
+	return d;
+}
+
+
+static void pcmcia_copy_from_remap(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1;
+	unsigned long win_size = dev->win_size;
+
+	DEBUG(3, "to = %p from = %lu len = %u", to, from, len);
+	while(len) {
+		int toread = win_size - (from & (win_size-1));
+		caddr_t addr;
+
+		if(toread > len)
+			toread = len;
+		
+		addr = remap_window(map, from);
+		if(!addr)
+			return;
+
+		DEBUG(4, "memcpy from %p to %p len = %d", addr, to, toread);
+		memcpy_fromio(to, addr, toread);
+		len -= toread;
+		to += toread;
+		from += toread;
+	}
+}
+
+
+static void pcmcia_write8_remap(struct map_info *map, u8 d, unsigned long adr)
+{
+	caddr_t addr = remap_window(map, adr);
+
+	if(!addr)
+		return;
+
+	DEBUG(3, "adr = 0x%08lx (%p)  data = 0x%02x", adr, addr, d);
+	writeb(d, addr);
+}
+
+
+static void pcmcia_write16_remap(struct map_info *map, u16 d, unsigned long adr)
+{
+	caddr_t addr = remap_window(map, adr);
+	if(!addr)
+		return;
+
+	DEBUG(3, "adr = 0x%08lx (%p)  data = 0x%04x", adr, addr, d);
+	writew(d, addr);
+}
+
+
+static void pcmcia_copy_to_remap(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1;
+	unsigned long win_size = dev->win_size;
+
+	DEBUG(3, "to = %lu from = %p len = %u", to, from, len);
+	while(len) {
+		int towrite = win_size - (to & (win_size-1));
+		caddr_t addr;
+
+		if(towrite > len)
+			towrite = len;
+
+		addr = remap_window(map, to);
+		if(!addr)
+			return;
+
+		DEBUG(4, "memcpy from %p to %p len = %d", from, addr, towrite);
+		memcpy_toio(addr, from, towrite);
+		len -= towrite;
+		to += towrite;
+		from += towrite;
+	}
+}
+
+
+/* read/write{8,16} copy_{from,to} routines with direct access */
+
+#define DEV_REMOVED(x)  (!(*(u_int *)x->map_priv_1 & DEV_PRESENT))
+
+static u8 pcmcia_read8(struct map_info *map, unsigned long ofs)
+{
+	caddr_t win_base = (caddr_t)map->map_priv_2;
+	u8 d;
+
+	if(DEV_REMOVED(map))
+		return 0;
+
+	d = readb(win_base + ofs);
+	DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%02x", ofs, win_base + ofs, d);
+	return d;
+}
+
+
+static u16 pcmcia_read16(struct map_info *map, unsigned long ofs)
+{
+	caddr_t win_base = (caddr_t)map->map_priv_2;
+	u16 d;
+
+	if(DEV_REMOVED(map))
+		return 0;
+
+	d = readw(win_base + ofs);
+	DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%04x", ofs, win_base + ofs, d);
+	return d;
+}
+
+
+static void pcmcia_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	caddr_t win_base = (caddr_t)map->map_priv_2;
+
+	if(DEV_REMOVED(map))
+		return;
+
+	DEBUG(3, "to = %p from = %lu len = %u", to, from, len);
+	memcpy_fromio(to, win_base + from, len);
+}
+
+
+static void pcmcia_write8(struct map_info *map, u8 d, unsigned long adr)
+{
+	caddr_t win_base = (caddr_t)map->map_priv_2;
+
+	if(DEV_REMOVED(map))
+		return;
+
+	DEBUG(3, "adr = 0x%08lx (%p)  data = 0x%02x", adr, win_base + adr, d);
+	writeb(d, win_base + adr);
+}
+
+
+static void pcmcia_write16(struct map_info *map, u16 d, unsigned long adr)
+{
+	caddr_t win_base = (caddr_t)map->map_priv_2;
+
+	if(DEV_REMOVED(map))
+		return;
+
+	DEBUG(3, "adr = 0x%08lx (%p)  data = 0x%04x", adr, win_base + adr, d);
+	writew(d, win_base + adr);
+}
+
+
+static void pcmcia_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	caddr_t win_base = (caddr_t)map->map_priv_2;
+
+	if(DEV_REMOVED(map))
+		return;
+
+	DEBUG(3, "to = %lu from = %p len = %u", to, from, len);
+	memcpy_toio(win_base + to, from, len);
+}
+
+
+static void pcmciamtd_set_vpp(struct map_info *map, int on)
+{
+	struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1;
+	dev_link_t *link = &dev->link;
+	modconf_t mod;
+	int ret;
+
+	mod.Attributes = CONF_VPP1_CHANGE_VALID | CONF_VPP2_CHANGE_VALID;
+	mod.Vcc = 0;
+	mod.Vpp1 = mod.Vpp2 = on ? dev->vpp : 0;
+
+	DEBUG(2, "dev = %p on = %d vpp = %d\n", dev, on, dev->vpp);
+	ret = CardServices(ModifyConfiguration, link->handle, &mod);
+	if(ret != CS_SUCCESS) {
+		cs_error(link->handle, ModifyConfiguration, ret);
+	}
+}
+
+
+/* After a card is removed, pcmciamtd_release() will unregister the
+ * device, and release the PCMCIA configuration.  If the device is
+ * still open, this will be postponed until it is closed.
+ */
+
+static void pcmciamtd_release(u_long arg)
+{
+	dev_link_t *link = (dev_link_t *)arg;
+	struct pcmciamtd_dev *dev = link->priv;
+
+	DEBUG(3, "link = 0x%p", link);
+
+	if (link->win) {
+		if(dev->win_base) {
+			iounmap(dev->win_base);
+			dev->win_base = NULL;
+		}
+		CardServices(ReleaseWindow, link->win);
+	}
+	CardServices(ReleaseConfiguration, link->handle);
+	link->state &= ~DEV_CONFIG;
+}
+
+
+static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_name)
+{
+	int rc;
+	tuple_t tuple;
+	cisparse_t parse;
+	u_char buf[64];
+
+	tuple.Attributes = 0;
+	tuple.TupleData = (cisdata_t *)buf;
+	tuple.TupleDataMax = sizeof(buf);
+	tuple.TupleOffset = 0;
+	tuple.DesiredTuple = RETURN_FIRST_TUPLE;
+
+	rc = CardServices(GetFirstTuple, link->handle, &tuple);
+	while(rc == CS_SUCCESS) {
+		rc = CardServices(GetTupleData, link->handle, &tuple);
+		if(rc != CS_SUCCESS) {
+			cs_error(link->handle, GetTupleData, rc);
+			break;
+		}
+		rc = CardServices(ParseTuple, link->handle, &tuple, &parse);
+		if(rc != CS_SUCCESS) {
+			cs_error(link->handle, ParseTuple, rc);
+			break;
+		}
+		
+		switch(tuple.TupleCode) {
+		case  CISTPL_FORMAT: {
+			cistpl_format_t *t = &parse.format;
+			(void)t; /* Shut up, gcc */
+			DEBUG(2, "Format type: %u, Error Detection: %u, offset = %u, length =%u",
+			      t->type, t->edc, t->offset, t->length);
+			break;
+			
+		}
+			
+		case CISTPL_DEVICE: {
+			cistpl_device_t *t = &parse.device;
+			int i;
+			DEBUG(2, "Common memory:");
+			dev->pcmcia_map.size = t->dev[0].size;
+			for(i = 0; i < t->ndev; i++) {
+				DEBUG(2, "Region %d, type = %u", i, t->dev[i].type);
+				DEBUG(2, "Region %d, wp = %u", i, t->dev[i].wp);
+				DEBUG(2, "Region %d, speed = %u ns", i, t->dev[i].speed);
+				DEBUG(2, "Region %d, size = %u bytes", i, t->dev[i].size);
+			}
+			break;
+		}
+			
+		case CISTPL_VERS_1: {
+			cistpl_vers_1_t *t = &parse.version_1;
+			int i;
+			if(t->ns) {
+				dev->mtd_name[0] = '\0';
+				for(i = 0; i < t->ns; i++) {
+					if(i)
+						strcat(dev->mtd_name, " ");
+					strcat(dev->mtd_name, t->str+t->ofs[i]);
+				}
+			}
+			DEBUG(2, "Found name: %s", dev->mtd_name);
+			break;
+		}
+			
+		case CISTPL_JEDEC_C: {
+			cistpl_jedec_t *t = &parse.jedec;
+			int i;
+			for(i = 0; i < t->nid; i++) {
+				DEBUG(2, "JEDEC: 0x%02x 0x%02x", t->id[i].mfr, t->id[i].info);
+			}
+			break;
+		}
+			
+		case CISTPL_DEVICE_GEO: {
+			cistpl_device_geo_t *t = &parse.device_geo;
+			int i;
+			dev->pcmcia_map.buswidth = t->geo[0].buswidth;
+			for(i = 0; i < t->ngeo; i++) {
+				DEBUG(2, "region: %d buswidth = %u", i, t->geo[i].buswidth);
+				DEBUG(2, "region: %d erase_block = %u", i, t->geo[i].erase_block);
+				DEBUG(2, "region: %d read_block = %u", i, t->geo[i].read_block);
+				DEBUG(2, "region: %d write_block = %u", i, t->geo[i].write_block);
+				DEBUG(2, "region: %d partition = %u", i, t->geo[i].partition);
+				DEBUG(2, "region: %d interleave = %u", i, t->geo[i].interleave);
+			}
+			break;
+		}
+			
+		default:
+			DEBUG(2, "Unknown tuple code %d", tuple.TupleCode);
+		}
+		
+		rc = CardServices(GetNextTuple, link->handle, &tuple, &parse);
+	}
+	if(!dev->pcmcia_map.size)
+		dev->pcmcia_map.size = MAX_PCMCIA_ADDR;
+
+	if(!dev->pcmcia_map.buswidth)
+		dev->pcmcia_map.buswidth = 2;
+
+	if(force_size) {
+		dev->pcmcia_map.size = force_size << 20;
+		DEBUG(2, "size forced to %dM", force_size);
+	}
+
+	if(buswidth) {
+		dev->pcmcia_map.buswidth = buswidth;
+		DEBUG(2, "buswidth forced to %d", buswidth);
+	}		
+
+	dev->pcmcia_map.name = dev->mtd_name;
+	if(!dev->mtd_name[0]) {
+		strcpy(dev->mtd_name, "PCMCIA Memory card");
+		*new_name = 1;
+	}
+
+	DEBUG(1, "Device: Size: %lu Width:%d Name: %s",
+	      dev->pcmcia_map.size, dev->pcmcia_map.buswidth << 3, dev->mtd_name);
+}
+
+
+/* pcmciamtd_config() is scheduled to run after a CARD_INSERTION event
+ * is received, to configure the PCMCIA socket, and to make the
+ * MTD device available to the system.
+ */
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
+
+static void pcmciamtd_config(dev_link_t *link)
+{
+	struct pcmciamtd_dev *dev = link->priv;
+	struct mtd_info *mtd = NULL;
+	cs_status_t status;
+	win_req_t req;
+	int last_ret = 0, last_fn = 0;
+	int ret;
+	int i;
+	config_info_t t;
+	static char *probes[] = { "jedec_probe", "cfi_probe" };
+	cisinfo_t cisinfo;
+	int new_name = 0;
+
+	DEBUG(3, "link=0x%p", link);
+
+	/* Configure card */
+	link->state |= DEV_CONFIG;
+
+	DEBUG(2, "Validating CIS");
+	ret = CardServices(ValidateCIS, link->handle, &cisinfo);
+	if(ret != CS_SUCCESS) {
+		cs_error(link->handle, GetTupleData, ret);
+	} else {
+		DEBUG(2, "ValidateCIS found %d chains", cisinfo.Chains);
+	}
+
+	card_settings(dev, link, &new_name);
+
+	dev->pcmcia_map.read8 = pcmcia_read8_remap;
+	dev->pcmcia_map.read16 = pcmcia_read16_remap;
+	dev->pcmcia_map.copy_from = pcmcia_copy_from_remap;
+	dev->pcmcia_map.write8 = pcmcia_write8_remap;
+	dev->pcmcia_map.write16 = pcmcia_write16_remap;
+	dev->pcmcia_map.copy_to = pcmcia_copy_to_remap;
+	if(setvpp == 1)
+		dev->pcmcia_map.set_vpp = pcmciamtd_set_vpp;
+
+	/* Request a memory window for PCMCIA. Some architeures can map windows upto the maximum
+	   that PCMCIA can support (64Mb) - this is ideal and we aim for a window the size of the
+	   whole card - otherwise we try smaller windows until we succeed */
+
+	req.Attributes =  WIN_MEMORY_TYPE_CM | WIN_ENABLE;
+	req.Attributes |= (dev->pcmcia_map.buswidth == 1) ? WIN_DATA_WIDTH_8 : WIN_DATA_WIDTH_16;
+	req.Base = 0;
+	req.AccessSpeed = mem_speed;
+	link->win = (window_handle_t)link->handle;
+	req.Size = (force_size) ? force_size << 20 : MAX_PCMCIA_ADDR;
+	dev->win_size = 0;
+
+	do {
+		int ret;
+		DEBUG(2, "requesting window with size = %dKB memspeed = %d",
+		      req.Size >> 10, req.AccessSpeed);
+		link->win = (window_handle_t)link->handle;
+		ret = CardServices(RequestWindow, &link->win, &req);
+		DEBUG(2, "ret = %d dev->win_size = %d", ret, dev->win_size);
+		if(ret) {
+			req.Size >>= 1;
+		} else {
+			DEBUG(2, "Got window of size %dKB", req.Size >> 10);
+			dev->win_size = req.Size;
+			break;
+		}
+	} while(req.Size >= 0x1000);
+
+	DEBUG(2, "dev->win_size = %d", dev->win_size);
+
+	if(!dev->win_size) {
+		err("Cant allocate memory window");
+		pcmciamtd_release((u_long)link);
+		return;
+	}
+	DEBUG(1, "Allocated a window of %dKB", dev->win_size >> 10);
+		
+	/* Get write protect status */
+	CS_CHECK(GetStatus, link->handle, &status);
+	DEBUG(2, "status value: 0x%x window handle = 0x%8.8lx",
+	      status.CardState, (unsigned long)link->win);
+	dev->win_base = ioremap(req.Base, req.Size);
+	if(!dev->win_base) {
+		err("ioremap(%lu, %u) failed", req.Base, req.Size);
+		pcmciamtd_release((u_long)link);
+		return;
+	}
+	DEBUG(1, "mapped window dev = %p req.base = 0x%lx base = %p size = 0x%x",
+	      dev, req.Base, dev->win_base, req.Size);
+
+	dev->offset = 0;
+	dev->pcmcia_map.map_priv_1 = (unsigned long)dev;
+	dev->pcmcia_map.map_priv_2 = (unsigned long)link->win;
+
+	DEBUG(2, "Getting configuration");
+	CS_CHECK(GetConfigurationInfo, link->handle, &t);
+	DEBUG(2, "Vcc = %d Vpp1 = %d Vpp2 = %d", t.Vcc, t.Vpp1, t.Vpp2);
+	dev->vpp = (vpp) ? vpp : t.Vpp1;
+	link->conf.Attributes = 0;
+	link->conf.Vcc = t.Vcc;
+	if(setvpp == 2) {
+		link->conf.Vpp1 = dev->vpp;
+		link->conf.Vpp2 = dev->vpp;
+	} else {
+		link->conf.Vpp1 = 0;
+		link->conf.Vpp2 = 0;
+	}
+
+	link->conf.IntType = INT_MEMORY;
+	link->conf.ConfigBase = t.ConfigBase;
+	link->conf.Status = t.Status;
+	link->conf.Pin = t.Pin;
+	link->conf.Copy = t.Copy;
+	link->conf.ExtStatus = t.ExtStatus;
+	link->conf.ConfigIndex = 0;
+	link->conf.Present = t.Present;
+	DEBUG(2, "Setting Configuration");
+	ret = CardServices(RequestConfiguration, link->handle, &link->conf);
+	if(ret != CS_SUCCESS) {
+		cs_error(link->handle, RequestConfiguration, ret);
+	}
+
+	if(mem_type == 1) {
+		mtd = do_map_probe("map_ram", &dev->pcmcia_map);
+	} else if(mem_type == 2) {
+		mtd = do_map_probe("map_rom", &dev->pcmcia_map);
+	} else {
+		for(i = 0; i < sizeof(probes) / sizeof(char *); i++) {
+			DEBUG(1, "Trying %s", probes[i]);
+			mtd = do_map_probe(probes[i], &dev->pcmcia_map);
+			if(mtd)
+				break;
+			
+			DEBUG(1, "FAILED: %s", probes[i]);
+		}
+	}
+	
+	if(!mtd) {
+		DEBUG(1, "Cant find an MTD");
+		pcmciamtd_release((u_long)link);
+		return;
+	}
+
+	dev->mtd_info = mtd;
+	mtd->module = THIS_MODULE;
+
+	if(new_name) {
+		int size = 0;
+		char unit = ' ';
+		/* Since we are using a default name, make it better by adding in the
+		   size */
+		if(mtd->size < 1048576) { /* <1MB in size, show size in K */
+			size = mtd->size >> 10;
+			unit = 'K';
+		} else {
+			size = mtd->size >> 20;
+			unit = 'M';
+		}
+		snprintf(dev->mtd_name, sizeof(dev->mtd_name), "%d%cB %s", size, unit, "PCMCIA Memory card");
+	}
+
+	/* If the memory found is fits completely into the mapped PCMCIA window,
+	   use the faster non-remapping read/write functions */
+	if(mtd->size <= dev->win_size) {
+		DEBUG(1, "Using non remapping memory functions");
+		dev->pcmcia_map.map_priv_1 = (unsigned long)&(dev->link.state);
+		dev->pcmcia_map.map_priv_2 = (unsigned long)dev->win_base;
+		dev->pcmcia_map.read8 = pcmcia_read8;
+		dev->pcmcia_map.read16 = pcmcia_read16;
+		dev->pcmcia_map.copy_from = pcmcia_copy_from;
+		dev->pcmcia_map.write8 = pcmcia_write8;
+		dev->pcmcia_map.write16 = pcmcia_write16;
+		dev->pcmcia_map.copy_to = pcmcia_copy_to;
+	}
+
+	if(add_mtd_device(mtd)) {
+		map_destroy(mtd);
+		dev->mtd_info = NULL;
+		err("Couldnt register MTD device");
+		pcmciamtd_release((u_long)link);
+		return;
+	}
+	snprintf(dev->node.dev_name, sizeof(dev->node.dev_name), "mtd%d", mtd->index);
+	info("mtd%d: %s", mtd->index, mtd->name);
+	link->state &= ~DEV_CONFIG_PENDING;
+	link->dev = &dev->node;
+	return;
+
+ cs_failed:
+	cs_error(link->handle, last_fn, last_ret);
+	err("CS Error, exiting");
+	pcmciamtd_release((u_long)link);
+	return;
+}
+
+
+/* The card status event handler.  Mostly, this schedules other
+ * stuff to run after an event is received.  A CARD_REMOVAL event
+ * also sets some flags to discourage the driver from trying
+ * to talk to the card any more.
+ */
+
+static int pcmciamtd_event(event_t event, int priority,
+			event_callback_args_t *args)
+{
+	dev_link_t *link = args->client_data;
+
+	DEBUG(1, "event=0x%06x", event);
+	switch (event) {
+	case CS_EVENT_CARD_REMOVAL:
+		DEBUG(2, "EVENT_CARD_REMOVAL");
+		link->state &= ~DEV_PRESENT;
+		if (link->state & DEV_CONFIG) {
+			struct pcmciamtd_dev *dev = link->priv;
+			if(dev->mtd_info) {
+				del_mtd_device(dev->mtd_info);
+				info("mtd%d: Removed", dev->mtd_info->index);
+			}
+			mod_timer(&link->release, jiffies + HZ/20);
+		}
+		break;
+	case CS_EVENT_CARD_INSERTION:
+		DEBUG(2, "EVENT_CARD_INSERTION");
+		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+		pcmciamtd_config(link);
+		break;
+	case CS_EVENT_PM_SUSPEND:
+		DEBUG(2, "EVENT_PM_SUSPEND");
+		link->state |= DEV_SUSPEND;
+		/* Fall through... */
+	case CS_EVENT_RESET_PHYSICAL:
+		DEBUG(2, "EVENT_RESET_PHYSICAL");
+		/* get_lock(link); */
+		break;
+	case CS_EVENT_PM_RESUME:
+		DEBUG(2, "EVENT_PM_RESUME");
+		link->state &= ~DEV_SUSPEND;
+		/* Fall through... */
+	case CS_EVENT_CARD_RESET:
+		DEBUG(2, "EVENT_CARD_RESET");
+		/* free_lock(link); */
+		break;
+	default:
+		DEBUG(2, "Unknown event %d", event);
+	}
+	return 0;
+}
+
+
+/* This deletes a driver "instance".  The device is de-registered
+ * with Card Services.  If it has been released, all local data
+ * structures are freed.  Otherwise, the structures will be freed
+ * when the device is released.
+ */
+
+static void pcmciamtd_detach(dev_link_t *link)
+{
+	DEBUG(3, "link=0x%p", link);
+
+	del_timer(&link->release);
+
+	if(link->state & DEV_CONFIG) {
+		pcmciamtd_release((u_long)link);
+	}
+
+	if (link->handle) {
+		int ret;
+		DEBUG(2, "Deregistering with card services");
+		ret = CardServices(DeregisterClient, link->handle);
+		if (ret != CS_SUCCESS)
+			cs_error(link->handle, DeregisterClient, ret);
+	}
+
+	link->state |= DEV_STALE_LINK;
+}
+
+
+/* pcmciamtd_attach() creates an "instance" of the driver, allocating
+ * local data structures for one device.  The device is registered
+ * with Card Services.
+ */
+
+static dev_link_t *pcmciamtd_attach(void)
+{
+	struct pcmciamtd_dev *dev;
+	dev_link_t *link;
+	client_reg_t client_reg;
+	int ret;
+
+	/* Create new memory card device */
+	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev) return NULL;
+	DEBUG(1, "dev=0x%p", dev);
+
+	memset(dev, 0, sizeof(*dev));
+	link = &dev->link;
+	link->priv = dev;
+
+	init_timer(&link->release);
+	link->release.function = &pcmciamtd_release;
+	link->release.data = (u_long)link;
+
+	link->conf.Attributes = 0;
+	link->conf.IntType = INT_MEMORY;
+
+	link->next = dev_list;
+	dev_list = link;
+
+	/* Register with Card Services */
+	client_reg.dev_info = &dev_info;
+	client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+	client_reg.EventMask =
+		CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+		CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+	client_reg.event_handler = &pcmciamtd_event;
+	client_reg.Version = 0x0210;
+	client_reg.event_callback_args.client_data = link;
+	DEBUG(2, "Calling RegisterClient");
+	ret = CardServices(RegisterClient, &link->handle, &client_reg);
+	if (ret != 0) {
+		cs_error(link->handle, RegisterClient, ret);
+		pcmciamtd_detach(link);
+		return NULL;
+	}
+	DEBUG(2, "link = %p", link);
+	return link;
+}
+
+
+static int __init init_pcmciamtd(void)
+{
+	servinfo_t serv;
+
+	info(DRIVER_DESC " " DRIVER_VERSION);
+	CardServices(GetCardServicesInfo, &serv);
+	if (serv.Revision != CS_RELEASE_CODE) {
+		err("Card Services release does not match!");
+		return -1;
+	}
+
+	if(buswidth && buswidth != 1 && buswidth != 2) {
+		info("bad buswidth (%d), using default", buswidth);
+		buswidth = 2;
+	}
+	if(force_size && (force_size < 1 || force_size > 64)) {
+		info("bad force_size (%d), using default", force_size);
+		force_size = 0;
+	}
+	if(mem_type && mem_type != 1 && mem_type != 2) {
+		info("bad mem_type (%d), using default", mem_type);
+		mem_type = 0;
+	}
+	register_pccard_driver(&dev_info, &pcmciamtd_attach, &pcmciamtd_detach);
+	return 0;
+}
+
+
+static void __exit exit_pcmciamtd(void)
+{
+	DEBUG(1, DRIVER_DESC " unloading");
+	unregister_pccard_driver(&dev_info);
+
+	while(dev_list) {
+		dev_link_t *link = dev_list;
+
+		dev_list = link->next;
+		if (link) {
+			struct pcmciamtd_dev *dev = link->priv;
+			
+ 			if(dev) {
+				if(link->state & DEV_PRESENT) {
+					if (!(link->state & DEV_STALE_LINK)) {
+						pcmciamtd_detach(link);
+					}
+					link->state &= ~DEV_PRESENT;
+					if(dev->mtd_info) {
+						del_mtd_device(dev->mtd_info);
+						info("mtd%d: Removed",
+						     dev->mtd_info->index);
+					}
+				}
+				if(dev->mtd_info) {
+					DEBUG(2, "Destroying map for mtd%d",
+					      dev->mtd_info->index);
+					map_destroy(dev->mtd_info);
+				}
+				kfree(dev);
+			}
+		}
+	}
+}
+
+module_init(init_pcmciamtd);
+module_exit(exit_pcmciamtd);
diff -urN linux-2.4.21-pre3/drivers/mtd/maps/physmap.c linux-2.4.21-pre4/drivers/mtd/maps/physmap.c
--- linux-2.4.21-pre3/drivers/mtd/maps/physmap.c	Thu Oct  4 15:14:59 2001
+++ linux-2.4.21-pre4/drivers/mtd/maps/physmap.c	Tue Jan 28 19:44:30 2003
@@ -1,5 +1,5 @@
 /*
- * $Id: physmap.c,v 1.15 2001/10/02 15:05:14 dwmw2 Exp $
+ * $Id: physmap.c,v 1.21 2002/09/05 05:12:54 acurtis Exp $
  *
  * Normal mappings of chips in physical memory
  */
@@ -12,6 +12,9 @@
 #include <linux/mtd/map.h>
 #include <linux/config.h>
 
+#ifdef CONFIG_MTD_PARTITIONS
+#include <linux/mtd/partitions.h>
+#endif
 
 #define WINDOW_ADDR CONFIG_MTD_PHYSMAP_START
 #define WINDOW_SIZE CONFIG_MTD_PHYSMAP_LEN
@@ -76,8 +79,47 @@
 	copy_to: physmap_copy_to
 };
 
+#ifdef CONFIG_MTD_PARTITIONS
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+static struct mtd_partition *mtd_parts = 0;
+static int                   mtd_parts_nb = 0;
+#else
+static struct mtd_partition physmap_partitions[] = {
+/* Put your own partition definitions here */
+#if 0
+	{
+		name:		"bootROM",
+		size:		0x80000,
+		offset:		0,
+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
+	}, {
+		name:		"zImage",
+		size:		0x100000,
+		offset:		MTDPART_OFS_APPEND,
+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
+	}, {
+		name:		"ramdisk.gz",
+		size:		0x300000,
+		offset:		MTDPART_OFS_APPEND,
+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
+	}, {
+		name:		"User FS",
+		size:		MTDPART_SIZ_FULL,
+		offset:		MTDPART_OFS_APPEND,
+	}
+#endif
+};
+
+#define NUM_PARTITIONS	(sizeof(physmap_partitions)/sizeof(struct mtd_partition))
+
+#endif
+#endif
+
 int __init init_physmap(void)
 {
+	static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", 0 };
+	const char **type;
+
        	printk(KERN_NOTICE "physmap flash device: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR);
 	physmap_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
 
@@ -85,11 +127,36 @@
 		printk("Failed to ioremap\n");
 		return -EIO;
 	}
-	mymtd = do_map_probe("cfi_probe", &physmap_map);
+	
+	mymtd = 0;
+	type = rom_probe_types;
+	for(; !mymtd && *type; type++) {
+		mymtd = do_map_probe(*type, &physmap_map);
+	}
 	if (mymtd) {
 		mymtd->module = THIS_MODULE;
 
 		add_mtd_device(mymtd);
+#ifdef CONFIG_MTD_PARTITIONS
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+		mtd_parts_nb = parse_cmdline_partitions(mymtd, &mtd_parts, 
+							"phys");
+		if (mtd_parts_nb > 0)
+		{
+			printk(KERN_NOTICE 
+			       "Using command line partition definition\n");
+			add_mtd_partitions (mymtd, mtd_parts, mtd_parts_nb);
+		}
+#else
+		if (NUM_PARTITIONS != 0) 
+		{
+			printk(KERN_NOTICE 
+			       "Using physmap partition definition\n");
+			add_mtd_partitions (mymtd, physmap_partitions, NUM_PARTITIONS);
+		}
+
+#endif
+#endif
 		return 0;
 	}
 
diff -urN linux-2.4.21-pre3/drivers/mtd/maps/physmap64.c linux-2.4.21-pre4/drivers/mtd/maps/physmap64.c
--- linux-2.4.21-pre3/drivers/mtd/maps/physmap64.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/drivers/mtd/maps/physmap64.c	Tue Jan 28 19:44:30 2003
@@ -0,0 +1,199 @@
+/*
+ * $Id: physmap64.c,v 1.1 2002/09/05 05:12:32 acurtis Exp $
+ *
+ * Normal mappings of chips in physical memory
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/config.h>
+#include <linux/mtd/cfi.h>
+
+#ifdef CONFIG_MTD_PARTITIONS
+#include <linux/mtd/partitions.h>
+#endif
+
+#define WINDOW_ADDR CONFIG_MTD_PHYSMAP_START
+#define WINDOW_SIZE CONFIG_MTD_PHYSMAP_LEN
+#define BUSWIDTH CONFIG_MTD_PHYSMAP_BUSWIDTH
+
+static struct mtd_info *mymtd;
+
+__u8 physmap_read8(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readb(map->map_priv_1 + ofs);
+}
+
+__u16 physmap_read16(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readw(map->map_priv_1 + ofs);
+}
+
+__u32 physmap_read32(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readl(map->map_priv_1 + ofs);
+}
+
+__u64 physmap_read64(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readll(map->map_priv_1 + ofs);
+}
+
+void physmap_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	memcpy_fromio(to, map->map_priv_1 + from, len);
+}
+
+void physmap_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+	__raw_writeb(d, map->map_priv_1 + adr);
+	mb();
+}
+
+void physmap_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+	__raw_writew(d, map->map_priv_1 + adr);
+	mb();
+}
+
+void physmap_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+	__raw_writel(d, map->map_priv_1 + adr);
+	mb();
+}
+
+void physmap_write64(struct map_info *map, __u64 d, unsigned long adr)
+{
+	__raw_writell(d, map->map_priv_1 + adr);
+	mb();
+}
+
+void physmap_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	memcpy_toio(map->map_priv_1 + to, from, len);
+}
+
+struct map_info physmap_map = {
+	name: "Physically mapped flash",
+	size: WINDOW_SIZE,
+	buswidth: BUSWIDTH,
+	read8: physmap_read8,
+	read16: physmap_read16,
+	read32: physmap_read32,
+	read64: physmap_read64,
+	copy_from: physmap_copy_from,
+	write8: physmap_write8,
+	write16: physmap_write16,
+	write32: physmap_write32,
+	write64: physmap_write64,
+	copy_to: physmap_copy_to
+};
+
+#ifdef CONFIG_MTD_PARTITIONS
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+static struct mtd_partition *mtd_parts = 0;
+static int                   mtd_parts_nb = 0;
+#else
+static struct mtd_partition physmap_partitions[] = {
+/* Put your own partition definitions here */
+#if 0
+	{
+		name:		"bootROM",
+		size:		0x80000,
+		offset:		0,
+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
+	}, {
+		name:		"zImage",
+		size:		0x100000,
+		offset:		MTDPART_OFS_APPEND,
+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
+	}, {
+		name:		"ramdisk.gz",
+		size:		0x300000,
+		offset:		MTDPART_OFS_APPEND,
+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
+	}, {
+		name:		"User FS",
+		size:		MTDPART_SIZ_FULL,
+		offset:		MTDPART_OFS_APPEND,
+	}
+#endif
+};
+
+#define NUM_PARTITIONS	(sizeof(physmap_partitions)/sizeof(struct mtd_partition))
+
+#endif
+#endif
+
+int __init init_physmap(void)
+{
+	static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", 0 };
+	const char **type;
+
+       	printk(KERN_NOTICE "physmap flash device: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR);
+	physmap_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
+
+	if (!physmap_map.map_priv_1) {
+		printk("Failed to ioremap\n");
+		return -EIO;
+	}
+	
+	mymtd = 0;
+	type = rom_probe_types;
+	for(; !mymtd && *type; type++) {
+		mymtd = do_map_probe(*type, &physmap_map);
+	}
+	if (mymtd) {
+		mymtd->module = THIS_MODULE;
+
+		add_mtd_device(mymtd);
+#ifdef CONFIG_MTD_PARTITIONS
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+		mtd_parts_nb = parse_cmdline_partitions(mymtd, &mtd_parts, 
+							"phys");
+		if (mtd_parts_nb > 0)
+		{
+			printk(KERN_NOTICE 
+			       "Using command line partition definition\n");
+			add_mtd_partitions (mymtd, mtd_parts, mtd_parts_nb);
+		}
+#else
+		if (NUM_PARTITIONS != 0) 
+		{
+			printk(KERN_NOTICE 
+			       "Using physmap partition definition\n");
+			add_mtd_partitions (mymtd, physmap_partitions, NUM_PARTITIONS);
+		}
+
+#endif
+#endif
+		return 0;
+	}
+
+	iounmap((void *)physmap_map.map_priv_1);
+	return -ENXIO;
+}
+
+static void __exit cleanup_physmap(void)
+{
+	if (mymtd) {
+		del_mtd_device(mymtd);
+		map_destroy(mymtd);
+	}
+	if (physmap_map.map_priv_1) {
+		iounmap((void *)physmap_map.map_priv_1);
+		physmap_map.map_priv_1 = 0;
+	}
+}
+
+module_init(init_physmap);
+module_exit(cleanup_physmap);
+
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
+MODULE_DESCRIPTION("Generic configurable MTD map driver");
diff -urN linux-2.4.21-pre3/drivers/mtd/maps/redwood.c linux-2.4.21-pre4/drivers/mtd/maps/redwood.c
--- linux-2.4.21-pre3/drivers/mtd/maps/redwood.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/drivers/mtd/maps/redwood.c	Tue Jan 28 19:44:30 2003
@@ -0,0 +1,173 @@
+/*
+ * $Id:
+ *
+ * redwood.c - mapper for IBM Redwood-4/5 board.
+ *	
+ * Copyright 2001 MontaVista Softare 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.
+ *
+ *  History: 12/17/2001 - Armin
+ *  		migrated to use do_map_probe
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/io.h>
+
+#define WINDOW_ADDR 0xffc00000
+#define WINDOW_SIZE 0x00400000
+
+__u8 redwood_flash_read8(struct map_info *map, unsigned long ofs)
+{
+        return *(__u8 *)(map->map_priv_1 + ofs);
+}
+
+__u16 redwood_flash_read16(struct map_info *map, unsigned long ofs)
+{
+        return *(__u16 *)(map->map_priv_1 + ofs);
+}
+
+__u32 redwood_flash_read32(struct map_info *map, unsigned long ofs)
+{
+        return *(volatile unsigned int *)(map->map_priv_1 + ofs);
+}
+
+void redwood_flash_copy_from(struct map_info *map, void *to,
+                             unsigned long from, ssize_t len)
+{
+        memcpy(to, (void *)(map->map_priv_1 + from), len);
+}
+
+void redwood_flash_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+        *(__u8 *)(map->map_priv_1 + adr) = d;
+}
+
+void redwood_flash_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+        *(__u16 *)(map->map_priv_1 + adr) = d;
+}
+
+void redwood_flash_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+        *(__u32 *)(map->map_priv_1 + adr) = d;
+}
+
+void redwood_flash_copy_to(struct map_info *map, unsigned long to,
+                           const void *from, ssize_t len)
+{
+        memcpy((void *)(map->map_priv_1 + to), from, len);
+}
+
+struct map_info redwood_flash_map = {
+        name: "IBM Redwood",
+        size: WINDOW_SIZE,
+        buswidth: 2,
+        read8: redwood_flash_read8,
+        read16: redwood_flash_read16,
+        read32: redwood_flash_read32,
+        copy_from: redwood_flash_copy_from,
+        write8: redwood_flash_write8,
+        write16: redwood_flash_write16,
+        write32: redwood_flash_write32,
+        copy_to: redwood_flash_copy_to
+};
+
+
+static struct mtd_partition redwood_flash_partitions[] = {
+        {
+                name: "Redwood OpenBIOS Vital Product Data",
+                offset: 0,
+                size:   0x10000,
+                mask_flags: MTD_WRITEABLE       /* force read-only */
+        },
+        {
+                name: "Redwood kernel",
+                offset: 0x10000,
+                size:   0x200000 - 0x10000
+        },
+        {
+                name: "Redwood OpenBIOS non-volatile storage",
+                offset: 0x200000,
+                size:   0x10000,
+                mask_flags: MTD_WRITEABLE       /* force read-only */
+        },
+        {
+                name: "Redwood filesystem",
+                offset: 0x210000,
+                size:   0x200000 - (0x10000 + 0x20000)
+        },
+        {
+                name: "Redwood OpenBIOS",
+                offset: 0x3e0000,
+                size:   0x20000,
+                mask_flags: MTD_WRITEABLE       /* force read-only */
+        }
+};
+#define NUM_REDWOOD_FLASH_PARTITIONS \
+        (sizeof(redwood_flash_partitions)/sizeof(redwood_flash_partitions[0]))
+
+static struct mtd_info *redwood_mtd;
+
+int __init init_redwood_flash(void)
+{
+        printk(KERN_NOTICE "redwood: flash mapping: %x at %x\n",
+               WINDOW_SIZE, WINDOW_ADDR);
+
+        redwood_flash_map.map_priv_1 =
+                (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
+
+        if (!redwood_flash_map.map_priv_1) {
+                printk("init_redwood_flash: failed to ioremap\n");
+                return -EIO;
+        }
+
+        redwood_mtd = do_map_probe("cfi_probe",&redwood_flash_map);
+
+        if (redwood_mtd) {
+                redwood_mtd->module = THIS_MODULE;
+                return add_mtd_partitions(redwood_mtd,
+                                          redwood_flash_partitions,
+                                          NUM_REDWOOD_FLASH_PARTITIONS);
+        }
+
+        return -ENXIO;
+}
+
+static void __exit cleanup_redwood_flash(void)
+{
+        if (redwood_mtd) {
+                del_mtd_partitions(redwood_mtd);
+                iounmap((void *)redwood_flash_map.map_priv_1);
+                map_destroy(redwood_mtd);
+        }
+}
+
+module_init(init_redwood_flash);
+module_exit(cleanup_redwood_flash);
diff -urN linux-2.4.21-pre3/drivers/mtd/maps/sa1100-flash.c linux-2.4.21-pre4/drivers/mtd/maps/sa1100-flash.c
--- linux-2.4.21-pre3/drivers/mtd/maps/sa1100-flash.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.21-pre4/drivers/mtd/maps/sa1100-flash.c	Tue Jan 28 19:44:30 2003
@@ -3,7 +3,7 @@
  * 
  * (C) 2000 Nicolas Pitre <nico@cam.org>
  * 
- * $Id: sa1100-flash.c,v 1.26 2002/03/13 16:30:44 rmk Exp $
+ * $Id: sa1100-flash.c,v 1.29 2002/09/06 14:36:19 abz Exp $
  */
 
 #include <linux/config.h>
@@ -393,27 +393,23 @@
 static struct mtd_partition frodo_partitions[] =
 {
 	{
-		name:		"bootloader",
+		name:		"Boot Loader",
 		size:		0x00040000,
-		offset:		0x00000000,
-		mask_flags:	MTD_WRITEABLE
+		offset:		0x00000000
 	}, {
-		name:		"bootloader params",
+		name:		"Parameter Block",
 		size:		0x00040000,
-		offset:		MTDPART_OFS_APPEND,
-		mask_flags:	MTD_WRITEABLE
+		offset:		MTDPART_OFS_APPEND
 	}, {
-		name:		"kernel",
+		name:		"Linux Kernel",
 		size:		0x00100000,
-		offset:		MTDPART_OFS_APPEND,
-		mask_flags:	MTD_WRITEABLE
+		offset:		MTDPART_OFS_APPEND
 	}, {
-		name:		"ramdisk",
-		size:		0x00400000,
-		offset:		MTDPART_OFS_APPEND,
-		mask_flags:	MTD_WRITEABLE
+		name:		"Ramdisk",
+		size:		0x00680000,
+		offset:		MTDPART_OFS_APPEND
 	}, {
-		name:		"file system",
+		name:		"Flash File System",
 		size:		MTDPART_SIZ_FULL,
 		offset:		MTDPART_OFS_APPEND
 	}
@@ -848,6 +844,7 @@
 		sa1100_map.size = FRODO_FLASH_SIZE;
 		base = 0x00000000;
 	}
+#endif
 #ifdef CONFIG_SA1100_GRAPHICSCLIENT
 	if (machine_is_graphicsclient()) {
 		parts = graphicsclient_partitions;
@@ -975,11 +972,11 @@
 		}
 	}
 #endif
-#ifdef CONFIG_MTD_BOOTLDR_PARTS
+#ifdef CONFIG_MTD_CMDLINE_PARTS
 	if (parsed_nr_parts == 0) {
-		int ret = parse_bootldr_partitions(mymtd, &parsed_parts);
+		int ret = parse_cmdline_partitions(mymtd, &parsed_parts, "sa1100");
 		if (ret > 0) {
-			part_type = "Compaq bootldr";
+			part_type = "Command Line";
 			parsed_nr_parts = ret;
 		}
 	}
diff -urN linux-2.4.21-pre3/drivers/mtd/maps/sbc_gxx.c linux-2.4.21-pre4/drivers/mtd/maps/sbc_gxx.c
--- linux-2.4.21-pre3/drivers/mtd/maps/sbc_gxx.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.21-pre4/drivers/mtd/maps/sbc_gxx.c	Tue Jan 28 19:44:30 2003
@@ -17,7 +17,7 @@
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 
-   $Id: sbc_gxx.c,v 1.20 2002/02/13 15:30:20 dwmw2 Exp $
+   $Id: sbc_gxx.c,v 1.21 2003/01/24 13:40:14 dwmw2 Exp $
 
 The SBC-MediaGX / SBC-GXx has up to 16 MiB of 
 Intel StrataFlash (28F320/28F640) in x8 mode.  
@@ -26,7 +26,7 @@
 
 The flash is accessed as follows:
 
-   16 kbyte memory window at 0xdc000-0xdffff
+   16 KiB memory window at 0xdc000-0xdffff
    
    Two IO address locations for paging
    
diff -urN linux-2.4.21-pre3/drivers/mtd/maps/scb2_flash.c linux-2.4.21-pre4/drivers/mtd/maps/scb2_flash.c
--- linux-2.4.21-pre3/drivers/mtd/maps/scb2_flash.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/drivers/mtd/maps/scb2_flash.c	Tue Jan 28 19:44:30 2003
@@ -0,0 +1,302 @@
+/*
+ * MTD map driver for BIOS Flash on Intel SCB2 boards
+ * $Id: scb2_flash.c,v 1.2 2003/01/24 13:09:56 dwmw2 Exp $
+ * Copyright (C) 2002 Sun Microsystems, Inc.
+ * Tim Hockin <thockin@sun.com>
+ *
+ * A few notes on this MTD map:
+ *
+ * This was developed with a small number of SCB2 boards to test on.
+ * Hopefully, Intel has not introducted too many unaccounted variables in the
+ * making of this board.
+ *
+ * The BIOS marks its own memory region as 'reserved' in the e820 map.  We
+ * try to request it here, but if it fails, we carry on anyway.
+ *
+ * This is how the chip is attached, so said the schematic:
+ * * a 4 MiB (32 Mb) 16 bit chip
+ * * a 1 MiB memory region
+ * * A20 and A21 pulled up
+ * * D8-D15 ignored
+ * What this means is that, while we are addressing bytes linearly, we are
+ * really addressing words, and discarding the other byte.  This means that
+ * the chip MUST BE at least 2 MiB.  This also means that every block is
+ * actually half as big as the chip reports.  It also means that accesses of
+ * logical address 0 hit higher-address sections of the chip, not physical 0.
+ * One can only hope that these 4MiB x16 chips were a lot cheaper than 1MiB x8
+ * chips.
+ *
+ * This driver assumes the chip is not write-protected by an external signal.
+ * As of the this writing, that is true, but may change, just to spite me.
+ *
+ * The actual BIOS layout has been mostly reverse engineered.  Intel BIOS
+ * updates for this board include 10 related (*.bio - &.bi9) binary files and
+ * another seperate (*.bbo) binary file.  The 10 files are 64k of data + a
+ * small header.  If the headers are stripped off, the 10 64k files can be
+ * concatenated into a 640k image.  This is your BIOS image, proper.  The
+ * seperate .bbo file also has a small header.  It is the 'Boot Block'
+ * recovery BIOS.  Once the header is stripped, no further prep is needed.
+ * As best I can tell, the BIOS is arranged as such:
+ * offset 0x00000 to 0x4ffff (320k):  unknown - SCSI BIOS, etc?
+ * offset 0x50000 to 0xeffff (640k):  BIOS proper
+ * offset 0xf0000 ty 0xfffff (64k):   Boot Block region
+ *
+ * Intel's BIOS update program flashes the BIOS and Boot Block in seperate
+ * steps.  Probably a wise thing to do.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/cfi.h>
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+
+#define MODNAME		"scb2_flash"
+#define SCB2_ADDR	0xfff00000
+#define SCB2_WINDOW	0x00100000
+
+static __u8 scb2_read8(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readb(map->map_priv_1 + ofs);
+}
+
+static __u16 scb2_read16(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readw(map->map_priv_1 + ofs);
+}
+
+static __u32 scb2_read32(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readl(map->map_priv_1 + ofs);
+}
+
+static void scb2_copy_from(struct map_info *map, void *to,
+				 unsigned long from, ssize_t len)
+{
+	memcpy_fromio(to, map->map_priv_1 + from, len);
+}
+
+static void scb2_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+	__raw_writeb(d, map->map_priv_1 + adr);
+	mb();
+}
+
+static void scb2_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+	__raw_writew(d, map->map_priv_1 + adr);
+	mb();
+}
+
+static void scb2_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+	__raw_writel(d, map->map_priv_1 + adr);
+	mb();
+}
+
+static void scb2_copy_to(struct map_info *map, unsigned long to,
+			       const void *from, ssize_t len)
+{
+	memcpy_toio(map->map_priv_1 + to, from, len);
+}
+
+static void *scb2_ioaddr;
+static struct mtd_info *scb2_mtd;
+struct map_info scb2_map = {
+	name:      "SCB2 BIOS Flash",
+	size:      0,
+	buswidth:  1,
+	read8:     scb2_read8,
+	read16:    scb2_read16,
+	read32:    scb2_read32,
+	copy_from: scb2_copy_from,
+	write8:    scb2_write8,
+	write16:   scb2_write16,
+	write32:   scb2_write32,
+	copy_to:   scb2_copy_to,
+};
+static int region_fail;
+
+static int __devinit
+scb2_fixup_mtd(struct mtd_info *mtd)
+{
+	int i;
+	int done = 0;
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+
+	/* barf if this doesn't look right */
+	if (cfi->cfiq->InterfaceDesc != 1) {
+		printk(KERN_ERR MODNAME ": unsupported InterfaceDesc: %#x\n",
+		    cfi->cfiq->InterfaceDesc);
+		return -1;
+	}
+
+	/* the chip is sometimes bigger than the map - what a waste */
+	mtd->size = map->size;
+
+	/*
+	 * We only REALLY get half the chip, due to the way it is
+	 * wired up - D8-D15 are tossed away.  We read linear bytes,
+	 * but in reality we are getting 1/2 of each 16-bit read,
+	 * which LOOKS linear to us.  Because CFI code accounts for
+	 * things like lock/unlock/erase by eraseregions, we need to
+	 * fudge them to reflect this.  Erases go like this:
+	 *   * send an erase to an address
+	 *   * the chip samples the address and erases the block
+	 *   * add the block erasesize to the address and repeat
+	 *   -- the problem is that addresses are 16-bit addressable
+	 *   -- we end up erasing every-other block
+	 */
+	mtd->erasesize /= 2;
+	for (i = 0; i < mtd->numeraseregions; i++) {
+		struct mtd_erase_region_info *region = &mtd->eraseregions[i];
+		region->erasesize /= 2;
+	}
+
+	/*
+	 * If the chip is bigger than the map, it is wired with the high
+	 * address lines pulled up.  This makes us access the top portion of
+	 * the chip, so all our erase-region info is wrong.  Start cutting from
+	 * the bottom.
+	 */
+	for (i = 0; !done && i < mtd->numeraseregions; i++) {
+		struct mtd_erase_region_info *region = &mtd->eraseregions[i];
+
+		if (region->numblocks * region->erasesize > mtd->size) {
+			region->numblocks = (mtd->size / region->erasesize);
+			done = 1;
+		} else {
+			region->numblocks = 0;
+		}
+		region->offset = 0;
+	}
+
+	return 0;
+}
+
+/* CSB5's 'Function Control Register' has bits for decoding @ >= 0xffc00000 */
+#define CSB5_FCR	0x41
+#define CSB5_FCR_DECODE_ALL 0x0e
+static int __devinit
+scb2_flash_probe(struct pci_dev *dev, const struct pci_device_id *ent)
+{
+	u8 reg;
+
+	/* enable decoding of the flash region in the south bridge */
+	pci_read_config_byte(dev, CSB5_FCR, &reg);
+	pci_write_config_byte(dev, CSB5_FCR, reg | CSB5_FCR_DECODE_ALL);
+
+	if (!request_mem_region(SCB2_ADDR, SCB2_WINDOW, scb2_map.name)) {
+		/*
+		 * The BIOS seems to mark the flash region as 'reserved'
+		 * in the e820 map.  Warn and go about our business.
+		 */
+		printk(KERN_WARNING MODNAME
+		    ": warning - can't reserve rom window, continuing\n");
+		region_fail = 1;
+	}
+
+	/* remap the IO window (w/o caching) */
+	scb2_ioaddr = ioremap_nocache(SCB2_ADDR, SCB2_WINDOW);
+	if (!scb2_ioaddr) {
+		printk(KERN_ERR MODNAME ": Failed to ioremap window!\n");
+		if (!region_fail)
+			release_mem_region(SCB2_ADDR, SCB2_WINDOW);
+		return -ENOMEM;
+	}
+
+	scb2_map.map_priv_1 = (unsigned long)scb2_ioaddr;
+	scb2_map.size = SCB2_WINDOW;
+
+	/* try to find a chip */
+	scb2_mtd = do_map_probe("cfi_probe", &scb2_map);
+
+	if (!scb2_mtd) {
+		printk(KERN_ERR MODNAME ": flash probe failed!\n");
+		iounmap(scb2_ioaddr);
+		if (!region_fail)
+			release_mem_region(SCB2_ADDR, SCB2_WINDOW);
+		return -ENODEV;
+	}
+
+	scb2_mtd->module = THIS_MODULE;
+	if (scb2_fixup_mtd(scb2_mtd) < 0) {
+		del_mtd_device(scb2_mtd);
+		map_destroy(scb2_mtd);
+		iounmap(scb2_ioaddr);
+		if (!region_fail)
+			release_mem_region(SCB2_ADDR, SCB2_WINDOW);
+		return -ENODEV;
+	}
+
+	printk(KERN_NOTICE MODNAME ": chip size %x at offset %x\n",
+	       scb2_mtd->size, SCB2_WINDOW - scb2_mtd->size);
+
+	add_mtd_device(scb2_mtd);
+
+	return 0;
+}
+
+static void __devexit
+scb2_flash_remove(struct pci_dev *dev)
+{
+	if (!scb2_mtd)
+		return;
+
+	/* disable flash writes */
+	if (scb2_mtd->lock)
+		scb2_mtd->lock(scb2_mtd, 0, scb2_mtd->size);
+
+	del_mtd_device(scb2_mtd);
+	map_destroy(scb2_mtd);
+
+	iounmap(scb2_ioaddr);
+	scb2_ioaddr = NULL;
+
+	if (!region_fail)
+		release_mem_region(SCB2_ADDR, SCB2_WINDOW);
+	pci_set_drvdata(dev, NULL);
+}
+
+static struct pci_device_id scb2_flash_pci_ids[] __devinitdata = {
+	{
+	  vendor: PCI_VENDOR_ID_SERVERWORKS,
+	  device: PCI_DEVICE_ID_SERVERWORKS_CSB5,
+	  subvendor: PCI_ANY_ID,
+	  subdevice: PCI_ANY_ID
+	},
+	{ 0, }
+};
+
+static struct pci_driver scb2_flash_driver = {
+	name:     "Intel SCB2 BIOS Flash",
+	id_table: scb2_flash_pci_ids,
+	probe:    scb2_flash_probe,
+	remove:   __devexit_p(scb2_flash_remove),
+};
+
+static int __init
+scb2_flash_init(void)
+{
+	return pci_module_init(&scb2_flash_driver);
+}
+
+static void __exit
+scb2_flash_exit(void)
+{
+	pci_unregister_driver(&scb2_flash_driver);
+}
+
+module_init(scb2_flash_init);
+module_exit(scb2_flash_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tim Hockin <thockin@sun.com>");
+MODULE_DESCRIPTION("MTD map driver for Intel SCB2 BIOS Flash");
+MODULE_DEVICE_TABLE(pci, scb2_flash_pci_ids);
diff -urN linux-2.4.21-pre3/drivers/mtd/maps/scx200_docflash.c linux-2.4.21-pre4/drivers/mtd/maps/scx200_docflash.c
--- linux-2.4.21-pre3/drivers/mtd/maps/scx200_docflash.c	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/drivers/mtd/maps/scx200_docflash.c	Tue Jan 28 19:44:30 2003
@@ -2,6 +2,8 @@
 
    Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
 
+   $Id: scx200_docflash.c,v 1.1 2003/01/24 13:20:40 dwmw2 Exp $ 
+
    National Semiconductor SCx200 flash mapped with DOCCS
 */
 
@@ -36,7 +38,7 @@
 MODULE_PARM_DESC(flashtype, "Type of MTD probe to do");
 
 static int probe = 0;		/* Don't autoprobe */
-static unsigned size = 0x1000000; /* 16 MB the whole ISA address space */
+static unsigned size = 0x1000000; /* 16 MiB the whole ISA address space */
 static unsigned width = 8;	/* Default to 8 bits wide */
 static char *flashtype = "cfi_probe";
 
diff -urN linux-2.4.21-pre3/drivers/mtd/maps/tqm8xxl.c linux-2.4.21-pre4/drivers/mtd/maps/tqm8xxl.c
--- linux-2.4.21-pre3/drivers/mtd/maps/tqm8xxl.c	Thu Oct  4 15:14:59 2001
+++ linux-2.4.21-pre4/drivers/mtd/maps/tqm8xxl.c	Tue Jan 28 19:44:30 2003
@@ -2,7 +2,7 @@
  * Handle mapping of the flash memory access routines 
  * on TQM8xxL based devices.
  *
- * $Id: tqm8xxl.c,v 1.3 2001/10/02 15:05:14 dwmw2 Exp $
+ * $Id: tqm8xxl.c,v 1.4 2002/06/20 13:41:20 mag Exp $
  *
  * based on rpxlite.c
  *
@@ -91,20 +91,6 @@
 	memcpy_toio((void *)(map->map_priv_1 + to), from, len);
 }
 
-struct map_info tqm8xxl_map = {
-	name: "TQM8xxL",
-	//size: WINDOW_SIZE,
-	buswidth: 4,
-	read8: tqm8xxl_read8,
-	read16: tqm8xxl_read16,
-	read32: tqm8xxl_read32,
-	copy_from: tqm8xxl_copy_from,
-	write8: tqm8xxl_write8,
-	write16: tqm8xxl_write16,
-	write32: tqm8xxl_write32,
-	copy_to: tqm8xxl_copy_to
-};
-
 /*
  * Here are partition information for all known TQM8xxL series devices.
  * See include/linux/mtd/partitions.h for definition of the mtd_partition
@@ -204,8 +190,9 @@
 			goto error_mem;
 		}
 		memset((void *)map_banks[idx]->name, 0, 16);
-		
+
 		sprintf(map_banks[idx]->name, "TQM8xxL%d", idx);
+		map_banks[idx]->size = flash_size;
 		map_banks[idx]->buswidth = 4;
 		map_banks[idx]->read8 = tqm8xxl_read8;
 		map_banks[idx]->read16 = tqm8xxl_read16;
diff -urN linux-2.4.21-pre3/drivers/mtd/maps/uclinux.c linux-2.4.21-pre4/drivers/mtd/maps/uclinux.c
--- linux-2.4.21-pre3/drivers/mtd/maps/uclinux.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/drivers/mtd/maps/uclinux.c	Tue Jan 28 19:44:30 2003
@@ -0,0 +1,172 @@
+/****************************************************************************/
+
+/*
+ *	uclinux.c -- generic memory mapped MTD driver for uclinux
+ *
+ *	(C) Copyright 2002, Greg Ungerer (gerg@snapgear.com)
+ *
+ * 	$Id: uclinux.c,v 1.2 2002/08/07 00:43:45 gerg Exp $
+ */
+
+/****************************************************************************/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/major.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <asm/io.h>
+
+/****************************************************************************/
+
+__u8 uclinux_read8(struct map_info *map, unsigned long ofs)
+{
+	return(*((__u8 *) (map->map_priv_1 + ofs)));
+}
+
+__u16 uclinux_read16(struct map_info *map, unsigned long ofs)
+{
+	return(*((__u16 *) (map->map_priv_1 + ofs)));
+}
+
+__u32 uclinux_read32(struct map_info *map, unsigned long ofs)
+{
+	return(*((__u32 *) (map->map_priv_1 + ofs)));
+}
+
+void uclinux_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	memcpy(to, (void *)(map->map_priv_1 + from), len);
+}
+
+void uclinux_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+	*((__u8 *) (map->map_priv_1 + adr)) = d;
+}
+
+void uclinux_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+	*((__u16 *) (map->map_priv_1 + adr)) = d;
+}
+
+void uclinux_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+	*((__u32 *) (map->map_priv_1 + adr)) = d;
+}
+
+void uclinux_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	memcpy((void *) (map->map_priv_1 + to), from, len);
+}
+
+/****************************************************************************/
+
+struct map_info uclinux_ram_map = {
+	name:		"RAM",
+	read8:		uclinux_read8,
+	read16:		uclinux_read16,
+	read32:		uclinux_read32,
+	copy_from:	uclinux_copy_from,
+	write8:		uclinux_write8,
+	write16:	uclinux_write16,
+	write32:	uclinux_write32,
+	copy_to:	uclinux_copy_to,
+};
+
+struct mtd_info *uclinux_ram_mtdinfo;
+
+/****************************************************************************/
+
+struct mtd_partition uclinux_romfs[] = {
+	{ name: "ROMfs", offset: 0 }
+};
+
+#define	NUM_PARTITIONS	(sizeof(uclinux_romfs) / sizeof(uclinux_romfs[0]))
+
+/****************************************************************************/
+
+int uclinux_point(struct mtd_info *mtd, loff_t from, size_t len,
+	size_t *retlen, u_char **mtdbuf)
+{
+	struct map_info *map = (struct map_info *) mtd->priv;
+	*mtdbuf = (u_char *) (map->map_priv_1 + ((int) from));
+	*retlen = len;
+	return(0);
+}
+
+/****************************************************************************/
+
+int __init uclinux_mtd_init(void)
+{
+	struct mtd_info *mtd;
+	struct map_info *mapp;
+	extern char _ebss;
+
+	mapp = &uclinux_ram_map;
+	mapp->map_priv_2 = (unsigned long) &_ebss;
+	mapp->size = PAGE_ALIGN(*((unsigned long *)((&_ebss) + 8)));
+	mapp->buswidth = 4;
+
+	printk("uclinux[mtd]: RAM probe address=0x%x size=0x%x\n",
+	       	(int) mapp->map_priv_2, (int) mapp->size);
+
+	mapp->map_priv_1 = (unsigned long)
+		ioremap_nocache(mapp->map_priv_2, mapp->size);
+
+	if (mapp->map_priv_1 == 0) {
+		printk("uclinux[mtd]: ioremap_nocache() failed\n");
+		return(-EIO);
+	}
+
+	mtd = do_map_probe("map_ram", mapp);
+	if (!mtd) {
+		printk("uclinux[mtd]: failed to find a mapping?\n");
+		iounmap((void *) mapp->map_priv_1);
+		return(-ENXIO);
+	}
+		
+	mtd->module = THIS_MODULE;
+	mtd->point = uclinux_point;
+	mtd->priv = mapp;
+
+	uclinux_ram_mtdinfo = mtd;
+	add_mtd_partitions(mtd, uclinux_romfs, NUM_PARTITIONS);
+
+	printk("uclinux[mtd]: set %s to be root filesystem\n",
+	     	uclinux_romfs[0].name);
+	ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, 0);
+	put_mtd_device(mtd);
+
+	return(0);
+}
+
+/****************************************************************************/
+
+void __exit uclinux_mtd_cleanup(void)
+{
+	if (uclinux_ram_mtdinfo) {
+		del_mtd_partitions(uclinux_ram_mtdinfo);
+		map_destroy(uclinux_ram_mtdinfo);
+		uclinux_ram_mtdinfo = NULL;
+	}
+	if (uclinux_ram_map.map_priv_1) {
+		iounmap((void *) uclinux_ram_map.map_priv_1);
+		uclinux_ram_map.map_priv_1 = 0;
+	}
+}
+
+/****************************************************************************/
+
+module_init(uclinux_mtd_init);
+module_exit(uclinux_mtd_cleanup);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com>");
+MODULE_DESCRIPTION("Generic RAM based MTD for uClinux");
+
+/****************************************************************************/
diff -urN linux-2.4.21-pre3/drivers/mtd/mtdblock.c linux-2.4.21-pre4/drivers/mtd/mtdblock.c
--- linux-2.4.21-pre3/drivers/mtd/mtdblock.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.21-pre4/drivers/mtd/mtdblock.c	Tue Jan 28 19:44:30 2003
@@ -311,6 +311,7 @@
 	if (mtdblks[dev]) {
 		mtdblks[dev]->count++;
 		spin_unlock(&mtdblks_lock);
+		put_mtd_device(mtd);
 		return 0;
 	}
 	
@@ -432,7 +433,7 @@
 		res = 0;
 
 		if (MINOR(req->rq_dev) >= MAX_MTD_DEVICES)
-			panic(__FUNCTION__": minor out of bound");
+			panic("%s: minor out of bounds", __FUNCTION__);
 
 		if ((req->sector + req->current_nr_sectors) > (mtdblk->mtd->size >> 9))
 			goto end_req;
@@ -483,20 +484,14 @@
 	struct task_struct *tsk = current;
 	DECLARE_WAITQUEUE(wait, tsk);
 
-	tsk->session = 1;
-	tsk->pgrp = 1;
 	/* we might get involved when memory gets low, so use PF_MEMALLOC */
 	tsk->flags |= PF_MEMALLOC;
 	strcpy(tsk->comm, "mtdblockd");
-	tsk->tty = NULL;
 	spin_lock_irq(&tsk->sigmask_lock);
 	sigfillset(&tsk->blocked);
 	recalc_sigpending(tsk);
 	spin_unlock_irq(&tsk->sigmask_lock);
-	exit_mm(tsk);
-	exit_files(tsk);
-	exit_sighand(tsk);
-	exit_fs(tsk);
+	daemonize();
 
 	while (!leaving) {
 		add_wait_queue(&thr_wq, &wait);
diff -urN linux-2.4.21-pre3/drivers/mtd/mtdblock_ro.c linux-2.4.21-pre4/drivers/mtd/mtdblock_ro.c
--- linux-2.4.21-pre3/drivers/mtd/mtdblock_ro.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.21-pre4/drivers/mtd/mtdblock_ro.c	Tue Jan 28 19:44:30 2003
@@ -138,10 +138,11 @@
       }
 
       if (current_request->sector << 9 > mtd->size ||
-	  (current_request->sector + current_request->nr_sectors) << 9 > mtd->size)
+	  (current_request->sector + current_request->current_nr_sectors) << 9 > mtd->size)
       {
 	 printk("mtd: Attempt to read past end of device!\n");
-	 printk("size: %x, sector: %lx, nr_sectors %lx\n", mtd->size, current_request->sector, current_request->nr_sectors);
+	 printk("size: %x, sector: %lx, nr_sectors %lx\n", mtd->size, 
+		current_request->sector, current_request->current_nr_sectors);
 	 end_request(0);
 	 continue;
       }
@@ -162,7 +163,7 @@
 
 	 case READ:
 	 if (MTD_READ(mtd,current_request->sector<<9, 
-		      current_request->nr_sectors << 9, 
+		      current_request->current_nr_sectors << 9, 
 		      &retlen, current_request->buffer) == 0)
 	    res = 1;
 	 else
@@ -172,7 +173,7 @@
 	 case WRITE:
 
 	 /* printk("mtdblock_request WRITE sector=%d(%d)\n",current_request->sector,
-		current_request->nr_sectors);
+		current_request->current_nr_sectors);
 	 */
 
 	 // Read only device
@@ -184,7 +185,7 @@
 
 	 // Do the write
 	 if (MTD_WRITE(mtd,current_request->sector<<9, 
-		       current_request->nr_sectors << 9, 
+		       current_request->current_nr_sectors << 9, 
 		       &retlen, current_request->buffer) == 0)
 	    res = 1;
 	 else
@@ -287,7 +288,7 @@
 static void __exit cleanup_mtdblock(void)
 {
 	unregister_blkdev(MAJOR_NR,DEVICE_NAME);
-	blksize_size[MAJOR_NR] = NULL;
+	blk_size[MAJOR_NR] = NULL;
 	blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
 }
 
diff -urN linux-2.4.21-pre3/drivers/mtd/mtdchar.c linux-2.4.21-pre4/drivers/mtd/mtdchar.c
--- linux-2.4.21-pre3/drivers/mtd/mtdchar.c	Thu Oct  4 15:14:59 2001
+++ linux-2.4.21-pre4/drivers/mtd/mtdchar.c	Tue Jan 28 19:44:30 2003
@@ -1,5 +1,5 @@
 /*
- * $Id: mtdchar.c,v 1.44 2001/10/02 15:05:11 dwmw2 Exp $
+ * $Id: mtdchar.c,v 1.49 2003/01/24 12:02:58 dwmw2 Exp $
  *
  * Character-device access to raw MTD devices.
  * Pure 2.4 version - compatibility cruft removed to mtdchar-compat.c
@@ -60,7 +60,7 @@
 
 static int mtd_open(struct inode *inode, struct file *file)
 {
-	int minor = MINOR(inode->i_rdev);
+	int minor = minor(inode->i_rdev);
 	int devnum = minor >> 1;
 	struct mtd_info *mtd;
 
@@ -287,7 +287,12 @@
 
 	case MEMERASE:
 	{
-		struct erase_info *erase=kmalloc(sizeof(struct erase_info),GFP_KERNEL);
+		struct erase_info *erase;
+
+		if(!(file->f_mode & 2))
+			return -EPERM;
+
+		erase=kmalloc(sizeof(struct erase_info),GFP_KERNEL);
 		if (!erase)
 			ret = -ENOMEM;
 		else {
@@ -338,6 +343,9 @@
 		void *databuf;
 		ssize_t retlen;
 		
+		if(!(file->f_mode & 2))
+			return -EPERM;
+
 		if (copy_from_user(&buf, (struct mtd_oob_buf *)arg, sizeof(struct mtd_oob_buf)))
 			return -EFAULT;
 		
@@ -434,6 +442,80 @@
 		break;
 	}
 
+	case MEMWRITEDATA:
+	{
+		struct mtd_oob_buf buf;
+		void *databuf;
+		ssize_t retlen;
+		
+		if (copy_from_user(&buf, (struct mtd_oob_buf *)arg, sizeof(struct mtd_oob_buf)))
+			return -EFAULT;
+		
+		if (buf.length > 0x4096)
+			return -EINVAL;
+
+		if (!mtd->write_ecc)
+			ret = -EOPNOTSUPP;
+		else
+			ret = verify_area(VERIFY_READ, (char *)buf.ptr, buf.length);
+
+		if (ret)
+			return ret;
+
+		databuf = kmalloc(buf.length, GFP_KERNEL);
+		if (!databuf)
+			return -ENOMEM;
+		
+		if (copy_from_user(databuf, buf.ptr, buf.length)) {
+			kfree(databuf);
+			return -EFAULT;
+		}
+
+		ret = (mtd->write_ecc)(mtd, buf.start, buf.length, &retlen, databuf, NULL, 0);
+
+		if (copy_to_user((void *)arg + sizeof(u_int32_t), &retlen, sizeof(u_int32_t)))
+			ret = -EFAULT;
+
+		kfree(databuf);
+		break;
+
+	}
+
+	case MEMREADDATA:
+	{
+		struct mtd_oob_buf buf;
+		void *databuf;
+		ssize_t retlen = 0;
+
+		if (copy_from_user(&buf, (struct mtd_oob_buf *)arg, sizeof(struct mtd_oob_buf)))
+			return -EFAULT;
+		
+		if (buf.length > 0x4096)
+			return -EINVAL;
+
+		if (!mtd->read_ecc)
+			ret = -EOPNOTSUPP;
+		else
+			ret = verify_area(VERIFY_WRITE, (char *)buf.ptr, buf.length);
+
+		if (ret)
+			return ret;
+
+		databuf = kmalloc(buf.length, GFP_KERNEL);
+		if (!databuf)
+			return -ENOMEM;
+		
+		ret = (mtd->read_ecc)(mtd, buf.start, buf.length, &retlen, databuf, NULL, 0);
+
+		if (copy_to_user((void *)arg + sizeof(u_int32_t), &retlen, sizeof(u_int32_t)))
+			ret = -EFAULT;
+		else if (retlen && copy_to_user(buf.ptr, databuf, retlen))
+			ret = -EFAULT;
+		
+		kfree(databuf);
+		break;
+	}
+
 		
 	default:
 		DEBUG(MTD_DEBUG_LEVEL0, "Invalid ioctl %x (MEMGETINFO = %x)\n", cmd, MEMGETINFO);
@@ -474,7 +556,7 @@
 	sprintf(name, "%dro", mtd->index);
 	devfs_ro_handle[mtd->index] = devfs_register(devfs_dir_handle, name,
 			DEVFS_FL_DEFAULT, MTD_CHAR_MAJOR, mtd->index*2+1,
-			S_IFCHR | S_IRUGO | S_IWUGO,
+			S_IFCHR | S_IRUGO,
 			&mtd_fops, NULL);
 }
 
diff -urN linux-2.4.21-pre3/drivers/mtd/mtdconcat.c linux-2.4.21-pre4/drivers/mtd/mtdconcat.c
--- linux-2.4.21-pre3/drivers/mtd/mtdconcat.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.21-pre4/drivers/mtd/mtdconcat.c	Tue Jan 28 19:44:30 2003
@@ -5,7 +5,7 @@
  *
  * This code is GPL
  *
- * $Id: mtdconcat.c,v 1.2 2002/03/22 08:45:22 dwmw2 Exp $
+ * $Id: mtdconcat.c,v 1.3 2002/05/21 21:04:25 dwmw2 Exp $
  */
 
 #include <linux/module.h>
@@ -303,11 +303,14 @@
 		 */
 		erase->addr = 0;
 	}
+	kfree(erase);
+	if (err)
+		return err;
+
 	instr->state = MTD_ERASE_DONE;
 	if (instr->callback)
 		instr->callback(instr);
-	kfree(erase);
-	return err;
+	return 0;
 }
 
 static int concat_lock (struct mtd_info *mtd, loff_t ofs, size_t len)
diff -urN linux-2.4.21-pre3/drivers/mtd/mtdcore.c linux-2.4.21-pre4/drivers/mtd/mtdcore.c
--- linux-2.4.21-pre3/drivers/mtd/mtdcore.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.21-pre4/drivers/mtd/mtdcore.c	Tue Jan 28 19:44:30 2003
@@ -1,5 +1,5 @@
 /*
- * $Id: mtdcore.c,v 1.32 2002/03/07 18:38:10 joern Exp $
+ * $Id: mtdcore.c,v 1.34 2003/01/24 23:32:25 dwmw2 Exp $
  *
  * Core registration and callback routines for MTD
  * drivers and users.
@@ -17,7 +17,6 @@
 #include <linux/major.h>
 #include <linux/fs.h>
 #include <linux/ioctl.h>
-#include <stdarg.h>
 #include <linux/mtd/compatmac.h>
 #ifdef CONFIG_PROC_FS
 #include <linux/proc_fs.h>
@@ -203,11 +202,74 @@
 	return ret;
 }
 
+
+/* default_mtd_writev - default mtd writev method for MTD devices that
+ *			dont implement their own
+ */
+
+int default_mtd_writev(struct mtd_info *mtd, const struct iovec *vecs,
+		       unsigned long count, loff_t to, size_t *retlen)
+{
+	unsigned long i;
+	size_t totlen = 0, thislen;
+	int ret = 0;
+
+	if(!mtd->write) {
+		ret = -EROFS;
+	} else {
+		for (i=0; i<count; i++) {
+			if (!vecs[i].iov_len)
+				continue;
+			ret = mtd->write(mtd, to, vecs[i].iov_len, &thislen, vecs[i].iov_base);
+			totlen += thislen;
+			if (ret || thislen != vecs[i].iov_len)
+				break;
+			to += vecs[i].iov_len;
+		}
+	}
+	if (retlen)
+		*retlen = totlen;
+	return ret;
+}
+
+
+/* default_mtd_readv - default mtd readv method for MTD devices that dont
+ *		       implement their own
+ */
+
+int default_mtd_readv(struct mtd_info *mtd, struct iovec *vecs,
+		      unsigned long count, loff_t from, size_t *retlen)
+{
+	unsigned long i;
+	size_t totlen = 0, thislen;
+	int ret = 0;
+
+	if(!mtd->read) {
+		ret = -EIO;
+	} else {
+		for (i=0; i<count; i++) {
+			if (!vecs[i].iov_len)
+				continue;
+			ret = mtd->read(mtd, from, vecs[i].iov_len, &thislen, vecs[i].iov_base);
+			totlen += thislen;
+			if (ret || thislen != vecs[i].iov_len)
+				break;
+			from += vecs[i].iov_len;
+		}
+	}
+	if (retlen)
+		*retlen = totlen;
+	return ret;
+}
+
+
 EXPORT_SYMBOL(add_mtd_device);
 EXPORT_SYMBOL(del_mtd_device);
 EXPORT_SYMBOL(__get_mtd_device);
 EXPORT_SYMBOL(register_mtd_user);
 EXPORT_SYMBOL(unregister_mtd_user);
+EXPORT_SYMBOL(default_mtd_writev);
+EXPORT_SYMBOL(default_mtd_readv);
 
 /*====================================================================*/
 /* Power management code */
diff -urN linux-2.4.21-pre3/drivers/mtd/mtdpart.c linux-2.4.21-pre4/drivers/mtd/mtdpart.c
--- linux-2.4.21-pre3/drivers/mtd/mtdpart.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.21-pre4/drivers/mtd/mtdpart.c	Tue Jan 28 19:44:30 2003
@@ -5,8 +5,7 @@
  *
  * This code is GPL
  *
- * $Id: mtdpart.c,v 1.27 2002/03/08 16:34:35 rkaiser Exp $
- * - with protection register access removed until that code is merged in 2.4.
+ * $Id: mtdpart.c,v 1.32 2002/10/21 13:40:05 jocke Exp $
  *
  * 	02-21-2002	Thomas Gleixner <gleixner@autronix.de>
  *			added support for read_oob, write_oob
@@ -59,6 +58,37 @@
 					len, retlen, buf);
 }
 
+static int part_point (struct mtd_info *mtd, loff_t from, size_t len, 
+			size_t *retlen, u_char **buf)
+{
+	struct mtd_part *part = PART(mtd);
+	if (from >= mtd->size)
+		len = 0;
+	else if (from + len > mtd->size)
+		len = mtd->size - from;
+	return part->master->point (part->master, from + part->offset, 
+				    len, retlen, buf);
+}
+static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
+{
+	struct mtd_part *part = PART(mtd);
+
+	part->master->unpoint (part->master, addr, from + part->offset, len);
+}
+
+
+static int part_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, 
+			size_t *retlen, u_char *buf, u_char *eccbuf, int oobsel)
+{
+	struct mtd_part *part = PART(mtd);
+	if (from >= mtd->size)
+		len = 0;
+	else if (from + len > mtd->size)
+		len = mtd->size - from;
+	return part->master->read_ecc (part->master, from + part->offset, 
+					len, retlen, buf, eccbuf, oobsel);
+}
+
 static int part_read_oob (struct mtd_info *mtd, loff_t from, size_t len, 
 			size_t *retlen, u_char *buf)
 {
@@ -71,6 +101,22 @@
 					len, retlen, buf);
 }
 
+static int part_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, 
+			size_t *retlen, u_char *buf)
+{
+	struct mtd_part *part = PART(mtd);
+	return part->master->read_user_prot_reg (part->master, from, 
+					len, retlen, buf);
+}
+
+static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, 
+			size_t *retlen, u_char *buf)
+{
+	struct mtd_part *part = PART(mtd);
+	return part->master->read_user_prot_reg (part->master, from, 
+					len, retlen, buf);
+}
+
 static int part_write (struct mtd_info *mtd, loff_t to, size_t len,
 			size_t *retlen, const u_char *buf)
 {
@@ -85,6 +131,21 @@
 					len, retlen, buf);
 }
 
+static int part_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
+			size_t *retlen, const u_char *buf,
+			 u_char *eccbuf, int oobsel)
+{
+	struct mtd_part *part = PART(mtd);
+	if (!(mtd->flags & MTD_WRITEABLE))
+		return -EROFS;
+	if (to >= mtd->size)
+		len = 0;
+	else if (to + len > mtd->size)
+		len = mtd->size - to;
+	return part->master->write_ecc (part->master, to + part->offset, 
+					len, retlen, buf, eccbuf, oobsel);
+}
+
 static int part_write_oob (struct mtd_info *mtd, loff_t to, size_t len,
 			size_t *retlen, const u_char *buf)
 {
@@ -99,6 +160,14 @@
 					len, retlen, buf);
 }
 
+static int part_write_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, 
+			size_t *retlen, u_char *buf)
+{
+	struct mtd_part *part = PART(mtd);
+	return part->master->write_user_prot_reg (part->master, from, 
+					len, retlen, buf);
+}
+
 static int part_writev (struct mtd_info *mtd,  const struct iovec *vecs,
 			 unsigned long count, loff_t to, size_t *retlen)
 {
@@ -117,6 +186,28 @@
 					from + part->offset, retlen);
 }
 
+static int part_writev_ecc (struct mtd_info *mtd,  const struct iovec *vecs,
+			 unsigned long count, loff_t to, size_t *retlen,
+			 u_char *eccbuf, int oobsel)
+{
+	struct mtd_part *part = PART(mtd);
+	if (!(mtd->flags & MTD_WRITEABLE))
+		return -EROFS;
+	return part->master->writev_ecc (part->master, vecs, count,
+					to + part->offset, retlen,
+					eccbuf, oobsel);
+}
+
+static int part_readv_ecc (struct mtd_info *mtd,  struct iovec *vecs,
+			 unsigned long count, loff_t from, size_t *retlen,
+			 u_char *eccbuf, int oobsel)
+{
+	struct mtd_part *part = PART(mtd);
+	return part->master->readv_ecc (part->master, vecs, count,
+					from + part->offset, retlen, 
+					eccbuf, oobsel);
+}
+
 static int part_erase (struct mtd_info *mtd, struct erase_info *instr)
 {
 	struct mtd_part *part = PART(mtd);
@@ -235,10 +326,25 @@
 		slave->mtd.read = part_read;
 		slave->mtd.write = part_write;
 
+		if(master->point && master->unpoint){
+			slave->mtd.point = part_point;
+			slave->mtd.unpoint = part_unpoint;
+		}
+		
+		if (master->read_ecc)
+			slave->mtd.read_ecc = part_read_ecc;
+		if (master->write_ecc)
+			slave->mtd.write_ecc = part_write_ecc;
 		if (master->read_oob)
 			slave->mtd.read_oob = part_read_oob;
 		if (master->write_oob)
 			slave->mtd.write_oob = part_write_oob;
+		if(master->read_user_prot_reg)
+			slave->mtd.read_user_prot_reg = part_read_user_prot_reg;
+		if(master->read_fact_prot_reg)
+			slave->mtd.read_fact_prot_reg = part_read_fact_prot_reg;
+		if(master->write_user_prot_reg)
+			slave->mtd.write_user_prot_reg = part_write_user_prot_reg;
 		if (master->sync)
 			slave->mtd.sync = part_sync;
 		if (!i && master->suspend && master->resume) {
@@ -249,6 +355,10 @@
 			slave->mtd.writev = part_writev;
 		if (master->readv)
 			slave->mtd.readv = part_readv;
+		if (master->writev_ecc)
+			slave->mtd.writev_ecc = part_writev_ecc;
+		if (master->readv_ecc)
+			slave->mtd.readv_ecc = part_readv_ecc;
 		if (master->lock)
 			slave->mtd.lock = part_lock;
 		if (master->unlock)
diff -urN linux-2.4.21-pre3/drivers/mtd/nand/Config.in linux-2.4.21-pre4/drivers/mtd/nand/Config.in
--- linux-2.4.21-pre3/drivers/mtd/nand/Config.in	Thu Oct  4 15:13:18 2001
+++ linux-2.4.21-pre4/drivers/mtd/nand/Config.in	Tue Jan 28 19:44:30 2003
@@ -1,6 +1,6 @@
 # drivers/mtd/nand/Config.in
 
-# $Id: Config.in,v 1.4 2001/09/19 09:35:23 dwmw2 Exp $
+# $Id: Config.in,v 1.11 2002/12/01 13:23:05 gleixner Exp $
 
 mainmenu_option next_comment
 
@@ -8,11 +8,29 @@
 
 dep_tristate '  NAND Device Support' CONFIG_MTD_NAND $CONFIG_MTD
 if [ "$CONFIG_MTD_NAND" = "y" -o "$CONFIG_MTD_NAND" = "m" ]; then
-   bool '    Enable ECC correction algorithm'  CONFIG_MTD_NAND_ECC
    bool '    Verify NAND page writes' CONFIG_MTD_NAND_VERIFY_WRITE
 fi
+
 if [ "$CONFIG_ARM" = "y" -a "$CONFIG_ARCH_P720T" = "y" ]; then
    dep_tristate '  NAND Flash device on SPIA board' CONFIG_MTD_NAND_SPIA $CONFIG_MTD_NAND
 fi
 
+if [ "$CONFIG_ARCH_AUTCPU12" = "y" ]; then
+   dep_tristate ' SmartMedia Card on AUTCPU12 board' CONFIG_MTD_NAND_AUTCPU12 $CONFIG_MTD_NAND
+fi
+
+if [ "$CONFIG_ARCH_EDB7312" = "y" ]; then
+   dep_tristate '  NAND Flash device on EDP7312 board' CONFIG_MTD_NAND_EDB7312 $CONFIG_MTD_NAND
+fi
+
+if [ "$CONFIG_MTD_DOC2001" = "y" -o "$CONFIG_MTD_DOC2000" = "y" -o "$CONFIG_MTD_NAND" = "y" ]; then
+   define_bool CONFIG_MTD_NAND_IDS y
+fi
+
+if [ "$CONFIG_MTD_NAND_IDS" != "y" ]; then
+if [ "$CONFIG_MTD_DOC2001" = "m" -o "$CONFIG_MTD_DOC2000" = "m" -o "$CONFIG_MTD_NAND" = "m" ]; then
+   define_bool CONFIG_MTD_NAND_IDS m
+fi
+fi
+
 endmenu
diff -urN linux-2.4.21-pre3/drivers/mtd/nand/Makefile linux-2.4.21-pre4/drivers/mtd/nand/Makefile
--- linux-2.4.21-pre3/drivers/mtd/nand/Makefile	Thu Oct  4 15:13:18 2001
+++ linux-2.4.21-pre4/drivers/mtd/nand/Makefile	Tue Jan 28 19:44:30 2003
@@ -1,16 +1,16 @@
 #
 # linux/drivers/nand/Makefile
 #
-# $Id: Makefile,v 1.5 2001/09/19 22:39:59 dwmw2 Exp $
+# $Id: Makefile,v 1.10 2002/12/01 13:23:05 gleixner Exp $
 
 O_TARGET	:= nandlink.o
 
-export-objs	:= nand.o nand_ecc.o
+export-objs	:= nand.o nand_ecc.o nand_ids.o
 
-nandobjs-y			:= nand.o
-nandobjs-$(CONFIG_MTD_NAND_ECC) += nand_ecc.o
-
-obj-$(CONFIG_MTD_NAND)		+= $(nandobjs-y)
+obj-$(CONFIG_MTD_NAND)		+= nand.o nand_ecc.o
 obj-$(CONFIG_MTD_NAND_SPIA)	+= spia.o
+obj-$(CONFIG_MTD_NAND_AUTCPU12)	+= autcpu12.o
+obj-$(CONFIG_MTD_NAND_EDB7312)  += edb7312.o
+obj-$(CONFIG_MTD_NAND_IDS)	+= nand_ids.o
 
 include $(TOPDIR)/Rules.make
diff -urN linux-2.4.21-pre3/drivers/mtd/nand/autcpu12.c linux-2.4.21-pre4/drivers/mtd/nand/autcpu12.c
--- linux-2.4.21-pre3/drivers/mtd/nand/autcpu12.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/drivers/mtd/nand/autcpu12.c	Tue Jan 28 19:44:30 2003
@@ -0,0 +1,266 @@
+/*
+ *  drivers/mtd/autcpu12.c
+ *
+ *  Copyright (c) 2002 Thomas Gleixner <tgxl@linutronix.de>
+ *
+ *  Derived from drivers/mtd/spia.c
+ * 	 Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
+ * 
+ * $Id: autcpu12.c,v 1.6 2002/11/11 15:47:56 gleixner Exp $
+ *
+ * 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.
+ *
+ *  Overview:
+ *   This is a device driver for the NAND flash device found on the
+ *   autronix autcpu12 board, which is a SmartMediaCard. It supports 
+ *   16MB, 32MB and 64MB cards.
+ *
+ *
+ *	02-12-2002 TG	Cleanup of module params
+ *
+ *	02-20-2002 TG	adjusted for different rd/wr adress support
+ *			added support for read device ready/busy line
+ *			added page_cache
+ *
+ *	10-06-2002 TG	128K card support added
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <asm/io.h>
+#include <asm/arch/hardware.h>
+#include <asm/sizes.h>
+#include <asm/arch/autcpu12.h>
+
+/*
+ * MTD structure for AUTCPU12 board
+ */
+static struct mtd_info *autcpu12_mtd = NULL;
+
+/*
+ * Module stuff
+ */
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
+#define autcpu12_init init_module
+#define autcpu12_cleanup cleanup_module
+#endif
+
+static int autcpu12_io_base = CS89712_VIRT_BASE;
+static int autcpu12_fio_pbase = AUTCPU12_PHYS_SMC;
+static int autcpu12_fio_ctrl = AUTCPU12_SMC_SELECT_OFFSET;
+static int autcpu12_pedr = AUTCPU12_SMC_PORT_OFFSET;
+static int autcpu12_fio_base;
+
+#ifdef MODULE
+MODULE_PARM(autcpu12_fio_pbase, "i");
+MODULE_PARM(autcpu12_fio_ctrl, "i");
+MODULE_PARM(autcpu12_pedr, "i");
+
+__setup("autcpu12_fio_pbase=",autcpu12_fio_pbase);
+__setup("autcpu12_fio_ctrl=",autcpu12_fio_ctrl);
+__setup("autcpu12_pedr=",autcpu12_pedr);
+#endif
+
+/*
+ * Define partitions for flash devices
+ */
+
+static struct mtd_partition partition_info16k[] = {
+	{ name: "AUTCPU12 flash partition 1",
+	  offset:  0,
+	  size:    8 * SZ_1M },
+	{ name: "AUTCPU12 flash partition 2",
+	  offset:  8 * SZ_1M,
+	  size:    8 * SZ_1M },
+};
+
+static struct mtd_partition partition_info32k[] = {
+	{ name: "AUTCPU12 flash partition 1",
+	  offset:  0,
+	  size:    8 * SZ_1M },
+	{ name: "AUTCPU12 flash partition 2",
+	  offset:  8 * SZ_1M,
+	  size:   24 * SZ_1M },
+};
+
+static struct mtd_partition partition_info64k[] = {
+	{ name: "AUTCPU12 flash partition 1",
+	  offset:  0,
+	  size:   16 * SZ_1M },
+	{ name: "AUTCPU12 flash partition 2",
+	  offset: 16 * SZ_1M,
+	  size:   48 * SZ_1M},
+};
+
+static struct mtd_partition partition_info128k[] = {
+	{ name: "AUTCPU12 flash partition 1",
+	  offset:  0,
+	  size:   16 * SZ_1M },
+	{ name: "AUTCPU12 flash partition 2",
+	  offset: 16 * SZ_1M,
+	  size:   112 * SZ_1M},
+};
+
+#define NUM_PARTITIONS16K 2
+#define NUM_PARTITIONS32K 2
+#define NUM_PARTITIONS64K 2
+#define NUM_PARTITIONS128K 2
+/* 
+ *	hardware specific access to control-lines
+*/
+void autcpu12_hwcontrol(int cmd)
+{
+
+	switch(cmd){
+
+		case NAND_CTL_SETCLE: (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) |=  AUTCPU12_SMC_CLE; break;
+		case NAND_CTL_CLRCLE: (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) &= ~AUTCPU12_SMC_CLE; break;
+
+		case NAND_CTL_SETALE: (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) |=  AUTCPU12_SMC_ALE; break;
+		case NAND_CTL_CLRALE: (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) &= ~AUTCPU12_SMC_ALE; break;
+
+		case NAND_CTL_SETNCE: (*(volatile unsigned char *) (autcpu12_fio_base + autcpu12_fio_ctrl)) = 0x01; break;
+		case NAND_CTL_CLRNCE: (*(volatile unsigned char *) (autcpu12_fio_base + autcpu12_fio_ctrl)) = 0x00; break;
+	}
+}
+
+/*
+*	read device ready pin
+*/
+int autcpu12_device_ready(void)
+{
+
+	return ( (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) & AUTCPU12_SMC_RDY) ? 1 : 0;
+
+}
+/*
+ * Main initialization routine
+ */
+int __init autcpu12_init (void)
+{
+	struct nand_chip *this;
+	int err = 0;
+
+	/* Allocate memory for MTD device structure and private data */
+	autcpu12_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip),
+				GFP_KERNEL);
+	if (!autcpu12_mtd) {
+		printk ("Unable to allocate AUTCPU12 NAND MTD device structure.\n");
+		err = -ENOMEM;
+		goto out;
+	}
+
+	/* map physical adress */
+	autcpu12_fio_base=(unsigned long)ioremap(autcpu12_fio_pbase,SZ_1K);
+	if(!autcpu12_fio_base){
+		printk("Ioremap autcpu12 SmartMedia Card failed\n");
+		err = -EIO;
+		goto out_mtd;
+	}
+
+	/* Get pointer to private data */
+	this = (struct nand_chip *) (&autcpu12_mtd[1]);
+
+	/* Initialize structures */
+	memset((char *) autcpu12_mtd, 0, sizeof(struct mtd_info));
+	memset((char *) this, 0, sizeof(struct nand_chip));
+
+	/* Link the private data with the MTD structure */
+	autcpu12_mtd->priv = this;
+
+	/* Set address of NAND IO lines */
+	this->IO_ADDR_R = autcpu12_fio_base;
+	this->IO_ADDR_W = autcpu12_fio_base;
+	this->hwcontrol = autcpu12_hwcontrol;
+	this->dev_ready = autcpu12_device_ready;
+	/* 20 us command delay time */
+	this->chip_delay = 20;		
+	this->eccmode = NAND_ECC_SOFT;
+
+	/* Scan to find existance of the device */
+	if (nand_scan (autcpu12_mtd)) {
+		err = -ENXIO;
+		goto out_ior;
+	}
+
+	/* Allocate memory for internal data buffer */
+	this->data_buf = kmalloc (sizeof(u_char) * (autcpu12_mtd->oobblock + autcpu12_mtd->oobsize), GFP_KERNEL);
+	if (!this->data_buf) {
+		printk ("Unable to allocate NAND data buffer for AUTCPU12.\n");
+		err = -ENOMEM;
+		goto out_ior;
+	}
+
+	/* Allocate memory for internal data buffer */
+	this->data_cache = kmalloc (sizeof(u_char) * (autcpu12_mtd->oobblock + autcpu12_mtd->oobsize), GFP_KERNEL);
+	if (!this->data_cache) {
+		printk ("Unable to allocate NAND data cache for AUTCPU12.\n");
+		err = -ENOMEM;
+		goto out_buf;
+	}
+	this->cache_page = -1;
+
+	/* Register the partitions */
+	switch(autcpu12_mtd->size){
+		case SZ_16M: add_mtd_partitions(autcpu12_mtd, partition_info16k, NUM_PARTITIONS16K); break;
+		case SZ_32M: add_mtd_partitions(autcpu12_mtd, partition_info32k, NUM_PARTITIONS32K); break;
+		case SZ_64M: add_mtd_partitions(autcpu12_mtd, partition_info64k, NUM_PARTITIONS64K); break; 
+		case SZ_128M: add_mtd_partitions(autcpu12_mtd, partition_info128k, NUM_PARTITIONS128K); break; 
+		default: {
+			printk ("Unsupported SmartMedia device\n"); 
+			err = -ENXIO;
+			goto out_cac;
+		}
+	}
+	goto out;
+
+out_cac:
+	kfree (this->data_cache);    
+out_buf:
+	kfree (this->data_buf);    
+out_ior:
+	iounmap((void *)autcpu12_fio_base);
+out_mtd:
+	kfree (autcpu12_mtd);
+out:
+	return err;
+}
+
+module_init(autcpu12_init);
+
+/*
+ * Clean up routine
+ */
+#ifdef MODULE
+static void __exit autcpu12_cleanup (void)
+{
+	struct nand_chip *this = (struct nand_chip *) &autcpu12_mtd[1];
+
+	/* Unregister partitions */
+	del_mtd_partitions(autcpu12_mtd);
+	
+	/* Unregister the device */
+	del_mtd_device (autcpu12_mtd);
+
+	/* Free internal data buffers */
+	kfree (this->data_buf);
+	kfree (this->data_cache);
+
+	/* unmap physical adress */
+	iounmap((void *)autcpu12_fio_base);
+
+	/* Free the MTD device structure */
+	kfree (autcpu12_mtd);
+}
+module_exit(autcpu12_cleanup);
+#endif
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>");
+MODULE_DESCRIPTION("Glue layer for SmartMediaCard on autronix autcpu12");
diff -urN linux-2.4.21-pre3/drivers/mtd/nand/edb7312.c linux-2.4.21-pre4/drivers/mtd/nand/edb7312.c
--- linux-2.4.21-pre3/drivers/mtd/nand/edb7312.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/drivers/mtd/nand/edb7312.c	Tue Jan 28 19:44:30 2003
@@ -0,0 +1,248 @@
+/*
+ *  drivers/mtd/nand/edb7312.c
+ *
+ *  Copyright (C) 2002 Marius Gröger (mag@sysgo.de)
+ *
+ *  Derived from drivers/mtd/nand/autcpu12.c
+ *       Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
+ *
+ * $Id: edb7312.c,v 1.3 2002/06/06 12:58:16 mag Exp $
+ *
+ * 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.
+ *
+ *  Overview:
+ *   This is a device driver for the NAND flash device found on the
+ *   CLEP7312 board which utilizes the Toshiba TC58V64AFT part. This is
+ *   a 64Mibit (8MiB x 8 bits) NAND flash device.
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <asm/io.h>
+#include <asm/arch/hardware.h> /* for CLPS7111_VIRT_BASE */
+#include <asm/sizes.h>
+#include <asm/hardware/clps7111.h>
+
+/*
+ * MTD structure for EDB7312 board
+ */
+static struct mtd_info *ep7312_mtd = NULL;
+
+/*
+ * Values specific to the EDB7312 board (used with EP7312 processor)
+ */
+#define EP7312_FIO_PBASE 0x10000000	/* Phys address of flash */
+#define EP7312_PXDR	0x0001	/*
+				 * IO offset to Port B data register
+				 * where the CLE, ALE and NCE pins
+				 * are wired to.
+				 */
+#define EP7312_PXDDR	0x0041	/*
+				 * IO offset to Port B data direction
+				 * register so we can control the IO
+				 * lines.
+				 */
+
+/*
+ * Module stuff
+ */
+
+static int ep7312_fio_pbase = EP7312_FIO_PBASE;
+static int ep7312_pxdr = EP7312_PXDR;
+static int ep7312_pxddr = EP7312_PXDDR;
+
+#ifdef MODULE
+MODULE_PARM(ep7312_fio_pbase, "i");
+MODULE_PARM(ep7312_pxdr, "i");
+MODULE_PARM(ep7312_pxddr, "i");
+
+__setup("ep7312_fio_pbase=",ep7312_fio_pbase);
+__setup("ep7312_pxdr=",ep7312_pxdr);
+__setup("ep7312_pxddr=",ep7312_pxddr);
+#endif
+
+#ifdef CONFIG_MTD_PARTITIONS
+/*
+ * Define static partitions for flash device
+ */
+static struct mtd_partition partition_info[] = {
+	{ name: "EP7312 Nand Flash",
+		  offset: 0,
+		  size: 8*1024*1024 }
+};
+#define NUM_PARTITIONS 1
+
+extern int parse_cmdline_partitions(struct mtd_info *master, 
+				    struct mtd_partition **pparts,
+				    const char *mtd_id);
+#endif
+
+
+/* 
+ *	hardware specific access to control-lines
+ */
+static void ep7312_hwcontrol(int cmd) 
+{
+	switch(cmd) {
+		
+	case NAND_CTL_SETCLE: 
+		clps_writeb(clps_readb(ep7312_pxdr) | 0x10, ep7312_pxdr); 
+		break;
+	case NAND_CTL_CLRCLE: 
+		clps_writeb(clps_readb(ep7312_pxdr) & ~0x10, ep7312_pxdr);
+		break;
+		
+	case NAND_CTL_SETALE:
+		clps_writeb(clps_readb(ep7312_pxdr) | 0x20, ep7312_pxdr);
+		break;
+	case NAND_CTL_CLRALE:
+		clps_writeb(clps_readb(ep7312_pxdr) & ~0x20, ep7312_pxdr);
+		break;
+		
+	case NAND_CTL_SETNCE:
+		clps_writeb((clps_readb(ep7312_pxdr) | 0x80) & ~0x40, ep7312_pxdr);
+		break;
+	case NAND_CTL_CLRNCE:
+		clps_writeb((clps_readb(ep7312_pxdr) | 0x80) | 0x40, ep7312_pxdr);
+		break;
+	}
+}
+
+/*
+ *	read device ready pin
+ */
+static int ep7312_device_ready(void)
+{
+	return 1;
+}
+
+/*
+ * Main initialization routine
+ */
+static int __init ep7312_init (void)
+{
+	struct nand_chip *this;
+	const char *part_type = 0;
+	int mtd_parts_nb = 0;
+	struct mtd_partition *mtd_parts = 0;
+	int ep7312_fio_base;
+	
+	/* Allocate memory for MTD device structure and private data */
+	ep7312_mtd = kmalloc(sizeof(struct mtd_info) + 
+			     sizeof(struct nand_chip),
+			     GFP_KERNEL);
+	if (!ep7312_mtd) {
+		printk("Unable to allocate EDB7312 NAND MTD device structure.\n");
+		return -ENOMEM;
+	}
+	
+	/* map physical adress */
+	ep7312_fio_base = (unsigned long)ioremap(ep7312_fio_pbase, SZ_1K);
+	if(!ep7312_fio_base) {
+		printk("ioremap EDB7312 NAND flash failed\n");
+		kfree(ep7312_mtd);
+		return -EIO;
+	}
+	
+	/* Get pointer to private data */
+	this = (struct nand_chip *) (&ep7312_mtd[1]);
+	
+	/* Initialize structures */
+	memset((char *) ep7312_mtd, 0, sizeof(struct mtd_info));
+	memset((char *) this, 0, sizeof(struct nand_chip));
+	
+	/* Link the private data with the MTD structure */
+	ep7312_mtd->priv = this;
+	
+	/*
+	 * Set GPIO Port B control register so that the pins are configured
+	 * to be outputs for controlling the NAND flash.
+	 */
+	clps_writeb(0xf0, ep7312_pxddr);
+	
+	/* insert callbacks */
+	this->IO_ADDR_R = ep7312_fio_base;
+	this->IO_ADDR_W = ep7312_fio_base;
+	this->hwcontrol = ep7312_hwcontrol;
+	this->dev_ready = ep7312_device_ready;
+	/* 15 us command delay time */
+	this->chip_delay = 15;
+	
+	/* Scan to find existence of the device */
+	if (nand_scan (ep7312_mtd)) {
+		iounmap((void *)ep7312_fio_base);
+		kfree (ep7312_mtd);
+		return -ENXIO;
+	}
+	
+	/* Allocate memory for internal data buffer */
+	this->data_buf = kmalloc (sizeof(u_char) * (ep7312_mtd->oobblock + ep7312_mtd->oobsize), GFP_KERNEL);
+	if (!this->data_buf) {
+		printk("Unable to allocate NAND data buffer for EDB7312.\n");
+		iounmap((void *)ep7312_fio_base);
+		kfree (ep7312_mtd);
+		return -ENOMEM;
+	}
+	
+	/* Allocate memory for internal data buffer */
+	this->data_cache = kmalloc (sizeof(u_char) * (ep7312_mtd->oobblock + ep7312_mtd->oobsize), GFP_KERNEL);
+	if (!this->data_cache) {
+		printk("Unable to allocate NAND data cache for EDB7312.\n");
+		kfree (this->data_buf);
+		iounmap((void *)ep7312_fio_base);
+		kfree (ep7312_mtd);
+		return -ENOMEM;
+	}
+	this->cache_page = -1;
+	
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+	mtd_parts_nb = parse_cmdline_partitions(ep7312_mtd, &mtd_parts, 
+						"edb7312-nand");
+	if (mtd_parts_nb > 0)
+	  part_type = "command line";
+	else
+	  mtd_parts_nb = 0;
+#endif
+	if (mtd_parts_nb == 0)
+	{
+		mtd_parts = partition_info;
+		mtd_parts_nb = NUM_PARTITIONS;
+		part_type = "static";
+	}
+	
+	/* Register the partitions */
+	printk(KERN_NOTICE "Using %s partition definition\n", part_type);
+	add_mtd_partitions(ep7312_mtd, mtd_parts, mtd_parts_nb);
+	
+	/* Return happy */
+	return 0;
+}
+module_init(ep7312_init);
+
+/*
+ * Clean up routine
+ */
+static void __exit ep7312_cleanup (void)
+{
+	struct nand_chip *this = (struct nand_chip *) &ep7312_mtd[1];
+	
+	/* Unregister the device */
+	del_mtd_device (ep7312_mtd);
+	
+	/* Free internal data buffer */
+	kfree (this->data_buf);
+	kfree (this->data_cache);
+	
+	/* Free the MTD device structure */
+	kfree (ep7312_mtd);
+}
+module_exit(ep7312_cleanup);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Marius Groeger <mag@sysgo.de>");
+MODULE_DESCRIPTION("MTD map driver for Cogent EDB7312 board");
diff -urN linux-2.4.21-pre3/drivers/mtd/nand/nand.c linux-2.4.21-pre4/drivers/mtd/nand/nand.c
--- linux-2.4.21-pre3/drivers/mtd/nand/nand.c	Thu Oct  4 15:14:59 2001
+++ linux-2.4.21-pre4/drivers/mtd/nand/nand.c	Tue Jan 28 19:44:30 2003
@@ -1,17 +1,126 @@
 /*
  *  drivers/mtd/nand.c
  *
+ *  Overview:
+ *   This is the generic MTD driver for NAND flash devices. It should be
+ *   capable of working with almost all NAND chips currently available.
+ *   
+ *	Additional technical information is available on
+ *	http://www.linux-mtd.infradead.org/tech/nand.html
+ *	
  *  Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
+ * 		  2002 Thomas Gleixner (tglx@linutronix.de)
+ *
+ *  10-29-2001  Thomas Gleixner (tglx@linutronix.de)
+ * 		- Changed nand_chip structure for controlline function to
+ *		support different hardware structures (Access to
+ *		controllines ALE,CLE,NCE via hardware specific function. 
+ *		- exit out of "failed erase block" changed, to avoid
+ *		driver hangup
+ *		- init_waitqueue_head added in function nand_scan !!
+ *
+ *  01-30-2002  Thomas Gleixner (tglx@linutronix.de)
+ *		change in nand_writev to block invalid vecs entries
+ *
+ *  02-11-2002  Thomas Gleixner (tglx@linutronix.de)
+ *		- major rewrite to avoid duplicated code
+ *		  common nand_write_page function  
+ *		  common get_chip function 
+ *		- added oob_config structure for out of band layouts
+ *		- write_oob changed for partial programming
+ *		- read cache for faster access for subsequent reads
+ *		from the same page.
+ *		- support for different read/write address
+ *		- support for device ready/busy line
+ *		- read oob for more than one page enabled
+ *
+ *  02-27-2002	Thomas Gleixner (tglx@linutronix.de)
+ *		- command-delay can be programmed
+ *		- fixed exit from erase with callback-function enabled
+ *
+ *  03-21-2002  Thomas Gleixner (tglx@linutronix.de)
+ *		- DEBUG improvements provided by Elizabeth Clarke 
+ *		(eclarke@aminocom.com)
+ *		- added zero check for this->chip_delay
+ *
+ *  04-03-2002  Thomas Gleixner (tglx@linutronix.de)
+ *		- added added hw-driver supplied command and wait functions
+ *		- changed blocking for erase (erase suspend enabled)
+ *		- check pointers before accessing flash provided by
+ *		John Hall (john.hall@optionexist.co.uk)
+ *
+ *  04-09-2002  Thomas Gleixner (tglx@linutronix.de)
+ *		- nand_wait repaired
+ *
+ *  04-28-2002  Thomas Gleixner (tglx@linutronix.de)	
+ *		- OOB config defines moved to nand.h 
+ *
+ *  08-01-2002  Thomas Gleixner (tglx@linutronix.de)	
+ *		- changed my mailaddress, added pointer to tech/nand.html
+ *
+ *  08-07-2002 	Thomas Gleixner (tglx@linutronix.de)
+ *		forced bad block location to byte 5 of OOB, even if
+ *		CONFIG_MTD_NAND_ECC_JFFS2 is not set, to prevent
+ *		erase /dev/mtdX from erasing bad blocks and destroying
+ *		bad block info
+ *
+ *  08-10-2002 	Thomas Gleixner (tglx@linutronix.de)
+ *		Fixed writing tail of data. Thanks to Alice Hennessy
+ *		<ahennessy@mvista.com>.
  *
- * $Id: nand.c,v 1.12 2001/10/02 15:05:14 dwmw2 Exp $
+ *  08-10-2002 	Thomas Gleixner (tglx@linutronix.de)
+ *		nand_read_ecc and nand_write_page restructured to support
+ *		hardware ECC. Thanks to Steven Hein (ssh@sgi.com)
+ *		for basic implementation and suggestions.
+ *		3 new pointers in nand_chip structure:
+ *		calculate_ecc, correct_data, enabled_hwecc 					 
+ *		forcing all hw-drivers to support page cache
+ *		eccvalid_pos is now mandatory
+ *
+ *  08-17-2002	tglx: fixed signed/unsigned missmatch in write.c
+ *		Thanks to Ken Offer <koffer@arlut.utexas.edu> 	
+ *
+ *  08-29-2002  tglx: use buffered read/write only for non pagealigned 
+ *		access, speed up the aligned path by using the fs-buffer
+ *		reset chip removed from nand_select(), implicit done
+ *		only, when erase is interrupted
+ *		waitfuntion use yield, instead of schedule_timeout
+ *		support for 6byte/512byte hardware ECC
+ *		read_ecc, write_ecc extended for different oob-layout
+ *		selections: Implemented NAND_NONE_OOB, NAND_JFFS2_OOB,
+ *		NAND_YAFFS_OOB. fs-driver gives one of these constants
+ *		to select the oob-layout fitting the filesystem.
+ *		oobdata can be read together with the raw data, when
+ *		the fs-driver supplies a big enough buffer.
+ *		size = 12 * number of pages to read (256B pagesize)
+ *		       24 * number of pages to read (512B pagesize)
+ *		the buffer contains 8/16 byte oobdata and 4/8 byte
+ *		returncode from calculate_ecc
+ *		oobdata can be given from filesystem to program them
+ *		in one go together with the raw data. ECC codes are
+ *		filled in at the place selected by oobsel.
+ *
+ *  09-04-2002  tglx: fixed write_verify (John Hall (john.hall@optionexist.co.uk))
+ *
+ *  11-11-2002  tglx: fixed debug output in nand_write_page 
+ *		(John Hall (john.hall@optionexist.co.uk))
+ *
+ *  11-25-2002  tglx: Moved device ID/ manufacturer ID from nand_ids.h
+ *		Splitted device ID and manufacturer ID table. 
+ *		Removed CONFIG_MTD_NAND_ECC, as it defaults to ECC_NONE for
+ *		mtd->read / mtd->write and is controllable by the fs driver
+ *		for mtd->read_ecc / mtd->write_ecc
+ *		some minor cleanups
+ *
+ *  12-05-2000  tglx: Dave Ellis (DGE@sixnetio) provided the fix for
+ *		WRITE_VERIFY long time ago. Thanks for remembering me.	
+ *	
+ * $Id: nand.c,v 1.36 2002/12/05 20:59:11 gleixner Exp $
  *
  * 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.
  *
- *  Overview:
- *   This is the generic MTD driver for NAND flash devices. It should be
- *   capable of working with almost all NAND chips currently available.
  */
 
 #include <linux/delay.h>
@@ -20,178 +129,452 @@
 #include <linux/types.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
-#include <linux/mtd/nand_ids.h>
+#include <linux/mtd/nand_ecc.h>
 #include <linux/interrupt.h>
 #include <asm/io.h>
 
-#ifdef CONFIG_MTD_NAND_ECC
-#include <linux/mtd/nand_ecc.h>
-#endif
-
 /*
  * Macros for low-level register control
  */
-#define NAND_CTRL (*(volatile unsigned char *) \
-			((struct nand_chip *) mtd->priv)->CTRL_ADDR)
-#define nand_select()	NAND_CTRL &= ~this->NCE; \
-			nand_command(mtd, NAND_CMD_RESET, -1, -1); \
-			udelay (10);
-#define nand_deselect() NAND_CTRL |= ~this->NCE;
+#define nand_select()	this->hwcontrol(NAND_CTL_SETNCE);
+
+#define nand_deselect() this->hwcontrol(NAND_CTL_CLRNCE);
+
+/*
+ * out of band configuration for different filesystems
+ */
+static int oobconfigs[][6] = {
+	{ 0,0,0,0,0,0},
+
+	{ NAND_JFFS2_OOB_ECCPOS0, NAND_JFFS2_OOB_ECCPOS1, NAND_JFFS2_OOB_ECCPOS2,
+	NAND_JFFS2_OOB_ECCPOS3, NAND_JFFS2_OOB_ECCPOS4, NAND_JFFS2_OOB_ECCPOS5 },
+
+	{ NAND_YAFFS_OOB_ECCPOS0, NAND_YAFFS_OOB_ECCPOS1, NAND_YAFFS_OOB_ECCPOS2,
+	NAND_YAFFS_OOB_ECCPOS3, NAND_YAFFS_OOB_ECCPOS4, NAND_YAFFS_OOB_ECCPOS5 }	
+};
 
 /*
  * NAND low-level MTD interface functions
  */
-static int nand_read (struct mtd_info *mtd, loff_t from, size_t len,
-			size_t *retlen, u_char *buf);
+static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf);
 static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
-				size_t *retlen, u_char *buf, u_char *ecc_code);
-static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len,
-				size_t *retlen, u_char *buf);
-static int nand_write (struct mtd_info *mtd, loff_t to, size_t len,
-			size_t *retlen, const u_char *buf);
+			  size_t * retlen, u_char * buf, u_char * eccbuf, int oobsel);
+static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf);
+static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf);
 static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
-				size_t *retlen, const u_char *buf,
-				u_char *ecc_code);
-static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len,
-				size_t *retlen, const u_char *buf);
+			   size_t * retlen, const u_char * buf, u_char * eccbuf, int oobsel);
+static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char *buf);
 static int nand_writev (struct mtd_info *mtd, const struct iovec *vecs,
-				unsigned long count, loff_t to, size_t *retlen);
+			unsigned long count, loff_t to, size_t * retlen);
+static int nand_writev_ecc (struct mtd_info *mtd, const struct iovec *vecs,
+			unsigned long count, loff_t to, size_t * retlen, u_char *eccbuf, int oobsel);
 static int nand_erase (struct mtd_info *mtd, struct erase_info *instr);
 static void nand_sync (struct mtd_info *mtd);
-
+static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, int col, 
+			int last, u_char *oob_buf, int oobsel);
 /*
  * Send command to NAND device
  */
-static void nand_command (struct mtd_info *mtd, unsigned command,
-				int column, int page_addr)
+static void nand_command (struct mtd_info *mtd, unsigned command, int column, int page_addr)
 {
 	register struct nand_chip *this = mtd->priv;
-	register unsigned long NAND_IO_ADDR = this->IO_ADDR;
+	register unsigned long NAND_IO_ADDR = this->IO_ADDR_W;
 
 	/* Begin command latch cycle */
-	NAND_CTRL |= this->CLE;
-
+	this->hwcontrol (NAND_CTL_SETCLE);
 	/*
 	 * Write out the command to the device.
 	 */
-	if (command != NAND_CMD_SEQIN)	
+	if (command != NAND_CMD_SEQIN)
 		writeb (command, NAND_IO_ADDR);
 	else {
 		if (mtd->oobblock == 256 && column >= 256) {
 			column -= 256;
-			writeb(NAND_CMD_RESET, NAND_IO_ADDR);
-			writeb(NAND_CMD_READOOB, NAND_IO_ADDR);
-			writeb(NAND_CMD_SEQIN, NAND_IO_ADDR);
-		}
-		else if (mtd->oobblock == 512 && column >= 256) {
+			writeb (NAND_CMD_READOOB, NAND_IO_ADDR);
+			writeb (NAND_CMD_SEQIN, NAND_IO_ADDR);
+		} else if (mtd->oobblock == 512 && column >= 256) {
 			if (column < 512) {
 				column -= 256;
-				writeb(NAND_CMD_READ1, NAND_IO_ADDR);
-				writeb(NAND_CMD_SEQIN, NAND_IO_ADDR);
-			}
-			else {
+				writeb (NAND_CMD_READ1, NAND_IO_ADDR);
+				writeb (NAND_CMD_SEQIN, NAND_IO_ADDR);
+			} else {
 				column -= 512;
-				writeb(NAND_CMD_READOOB, NAND_IO_ADDR);
-				writeb(NAND_CMD_SEQIN, NAND_IO_ADDR);
+				writeb (NAND_CMD_READOOB, NAND_IO_ADDR);
+				writeb (NAND_CMD_SEQIN, NAND_IO_ADDR);
 			}
-		}
-		else {
-			writeb(NAND_CMD_READ0, NAND_IO_ADDR);
-			writeb(NAND_CMD_SEQIN, NAND_IO_ADDR);
+		} else {
+			writeb (NAND_CMD_READ0, NAND_IO_ADDR);
+			writeb (NAND_CMD_SEQIN, NAND_IO_ADDR);
 		}
 	}
 
 	/* Set ALE and clear CLE to start address cycle */
-	NAND_CTRL &= ~this->CLE;
-	NAND_CTRL |= this->ALE;
+	this->hwcontrol (NAND_CTL_CLRCLE);
+
+	if (column != -1 || page_addr != -1) {
+		this->hwcontrol (NAND_CTL_SETALE);
 
-	/* Serially input address */
-	if (column != -1)
-		writeb (column, NAND_IO_ADDR);
-	if (page_addr != -1) {
-		writeb ((unsigned char) (page_addr & 0xff), NAND_IO_ADDR);
-		writeb ((unsigned char) ((page_addr >> 8) & 0xff), NAND_IO_ADDR);
-		/* One more address cycle for higher density devices */
-		if (mtd->size & 0x0c000000) {
-			writeb ((unsigned char) ((page_addr >> 16) & 0x0f),
-					NAND_IO_ADDR);
+		/* Serially input address */
+		if (column != -1)
+			writeb (column, NAND_IO_ADDR);
+		if (page_addr != -1) {
+			writeb ((unsigned char) (page_addr & 0xff), NAND_IO_ADDR);
+			writeb ((unsigned char) ((page_addr >> 8) & 0xff), NAND_IO_ADDR);
+			/* One more address cycle for higher density devices */
+			if (mtd->size & 0x0c000000) 
+				writeb ((unsigned char) ((page_addr >> 16) & 0x0f), NAND_IO_ADDR);
 		}
+		/* Latch in address */
+		this->hwcontrol (NAND_CTL_CLRALE);
 	}
+	
+	/* 
+	 * program and erase have their own busy handlers 
+	 * status and sequential in needs no delay
+	*/
+	switch (command) {
+			
+	case NAND_CMD_PAGEPROG:
+	case NAND_CMD_ERASE1:
+	case NAND_CMD_ERASE2:
+	case NAND_CMD_SEQIN:
+	case NAND_CMD_STATUS:
+		return;
 
-	/* Latch in address */
-	NAND_CTRL &= ~this->ALE;
+	case NAND_CMD_RESET:
+		if (this->dev_ready)	
+			break;
+		this->hwcontrol (NAND_CTL_SETCLE);
+		writeb (NAND_CMD_STATUS, NAND_IO_ADDR);
+		this->hwcontrol (NAND_CTL_CLRCLE);
+		while ( !(readb (this->IO_ADDR_R) & 0x40));
+		return;
 
-	/* Pause for 15us */
-	udelay (15);
+	/* This applies to read commands */	
+	default:
+		/* 
+		 * If we don't have access to the busy pin, we apply the given
+		 * command delay
+		*/
+		if (!this->dev_ready) {
+			udelay (this->chip_delay);
+			return;
+		}	
+	}
+	
+	/* wait until command is processed */
+	while (!this->dev_ready());
 }
 
 /*
- * NAND read
+ *	Get chip for selected access
  */
-static int nand_read (struct mtd_info *mtd, loff_t from, size_t len,
-			size_t *retlen, u_char *buf)
+static inline void nand_get_chip (struct nand_chip *this, struct mtd_info *mtd, int new_state, int *erase_state)
 {
-#ifdef CONFIG_MTD_NAND_ECC
-	struct nand_chip *this = mtd->priv;
+
+	DECLARE_WAITQUEUE (wait, current);
+
+	/* 
+	 * Grab the lock and see if the device is available 
+	 * For erasing, we keep the spinlock until the
+	 * erase command is written. 
+	*/
+retry:
+	spin_lock_bh (&this->chip_lock);
+
+	if (this->state == FL_READY) {
+		this->state = new_state;
+		if (new_state != FL_ERASING)
+			spin_unlock_bh (&this->chip_lock);
+		return;
+	}
+
+	if (this->state == FL_ERASING) {
+		if (new_state != FL_ERASING) {
+			this->state = new_state;
+			spin_unlock_bh (&this->chip_lock);
+			nand_select ();	/* select in any case */
+			this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+			return;
+		}
+	}
+
+	set_current_state (TASK_UNINTERRUPTIBLE);
+	add_wait_queue (&this->wq, &wait);
+	spin_unlock_bh (&this->chip_lock);
+	schedule ();
+	remove_wait_queue (&this->wq, &wait);
+	goto retry;
+}
+
+/*
+ * Wait for command done. This applies to erase and program only
+ * Erase can take up to 400ms and program up to 20ms according to 
+ * general NAND and SmartMedia specs
+ *
+*/
+static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state)
+{
+
+	unsigned long	timeo = jiffies;
+	int	status;
+	
+	if (state == FL_ERASING)
+		 timeo += (HZ * 400) / 1000;
+	else
+		 timeo += (HZ * 20) / 1000;
+
+	spin_lock_bh (&this->chip_lock);
+	this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
+
+	while (time_before(jiffies, timeo)) {		
+		/* Check, if we were interrupted */
+		if (this->state != state) {
+			spin_unlock_bh (&this->chip_lock);
+			return 0;
+		}
+		if (this->dev_ready) {
+			if (this->dev_ready ())
+				break;
+		}
+		if (readb (this->IO_ADDR_R) & 0x40)
+			break;
+						
+		spin_unlock_bh (&this->chip_lock);
+		yield ();
+		spin_lock_bh (&this->chip_lock);
+	}
+	status = (int) readb (this->IO_ADDR_R);
+	spin_unlock_bh (&this->chip_lock);
+
+	return status;
+}
+
+/*
+ *	Nand_page_program function is used for write and writev !
+ */
+static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this,
+			    int page, int col, int last, u_char *oob_buf, int oobsel)
+{
+	int 	i, status;
+	u_char	ecc_code[6], *oob_data;
+	int	eccmode = oobsel ? this->eccmode : NAND_ECC_NONE;
+	int  	*oob_config = oobconfigs[oobsel];
+
+	/* pad oob area, if we have no oob buffer from fs-driver */
+	if (!oob_buf) {
+		oob_data = &this->data_buf[mtd->oobblock];
+		for (i = 0; i < mtd->oobsize; i++)
+			oob_data[i] = 0xff;
+	} else 
+		oob_data = oob_buf;
 	
-	return nand_read_ecc (mtd, from, len, retlen, buf, this->ecc_code_buf);
-#else
-	return nand_read_ecc (mtd, from, len, retlen, buf, NULL);
+	/* software ecc 3 Bytes ECC / 256 Byte Data ? */
+	if (eccmode == NAND_ECC_SOFT) {
+		/* Read back previous written data, if col > 0 */
+		if (col) {
+			this->cmdfunc (mtd, NAND_CMD_READ0, 0, page);
+			for (i = 0; i < col; i++)
+				this->data_poi[i] = readb (this->IO_ADDR_R);
+		}
+		if ((col < this->eccsize) && (last >= this->eccsize)) {
+			this->calculate_ecc (&this->data_poi[0], &(ecc_code[0]));
+			for (i = 0; i < 3; i++)
+				oob_data[oob_config[i]] = ecc_code[i];
+		}
+		/* Calculate and write the second ECC if we have enough data */
+		if ((mtd->oobblock == 512) && (last == 512)) {
+			this->calculate_ecc (&this->data_poi[256], &(ecc_code[3]));
+			for (i = 3; i < 6; i++)
+				oob_data[oob_config[i]] = ecc_code[i];
+		} 
+	} else {
+		/* For hardware ECC skip ECC, if we have no full page write */
+		if (eccmode != NAND_ECC_NONE && (col || last != mtd->oobblock))
+			eccmode = NAND_ECC_NONE;
+	}			
+
+	/* Prepad for partial page programming !!! */
+	for (i = 0; i < col; i++)
+		this->data_poi[i] = 0xff;
+
+	/* Postpad for partial page programming !!! oob is already padded */
+	for (i = last; i < mtd->oobblock; i++)
+		this->data_poi[i] = 0xff;
+
+	/* Send command to begin auto page programming */
+	this->cmdfunc (mtd, NAND_CMD_SEQIN, 0x00, page);
+
+	/* Write out complete page of data, take care of eccmode */
+	switch (this->eccmode) {
+	/* No ecc and software ecc 3/256, write all */
+	case NAND_ECC_NONE:
+	case NAND_ECC_SOFT:
+		for (i = 0; i < mtd->oobblock; i++) 
+			writeb ( this->data_poi[i] , this->IO_ADDR_W);
+		break;
+		
+	/* Hardware ecc 3 byte / 256 data, write first half, get ecc, then second, if 512 byte pagesize */	
+	case NAND_ECC_HW3_256:		
+		this->enable_hwecc (NAND_ECC_WRITE);	/* enable hardware ecc logic for write */
+		for (i = 0; i < mtd->eccsize; i++) 
+			writeb ( this->data_poi[i] , this->IO_ADDR_W);
+		
+		this->calculate_ecc (NULL, &(ecc_code[0]));
+		for (i = 0; i < 3; i++)
+			oob_data[oob_config[i]] = ecc_code[i];
+			
+		if (mtd->oobblock == 512) {
+			this->enable_hwecc (NAND_ECC_WRITE);	/* enable hardware ecc logic for write*/
+			for (i = mtd->eccsize; i < mtd->oobblock; i++) 
+				writeb ( this->data_poi[i] , this->IO_ADDR_W);
+			this->calculate_ecc (NULL, &(ecc_code[3]));
+			for (i = 3; i < 6; i++)
+				oob_data[oob_config[i]] = ecc_code[i];
+		}
+		break;
+				
+	/* Hardware ecc 3 byte / 512 byte data, write full page */	
+	case NAND_ECC_HW3_512:	
+		this->enable_hwecc (NAND_ECC_WRITE);	/* enable hardware ecc logic */
+		for (i = 0; i < mtd->oobblock; i++) 
+			writeb ( this->data_poi[i] , this->IO_ADDR_W);
+		this->calculate_ecc (NULL, &(ecc_code[0]));
+		for (i = 0; i < 3; i++)
+			oob_data[oob_config[i]] = ecc_code[i];
+		break;
+
+	/* Hardware ecc 6 byte / 512 byte data, write full page */	
+	case NAND_ECC_HW6_512:	
+		this->enable_hwecc (NAND_ECC_WRITE);	/* enable hardware ecc logic */
+		for (i = 0; i < mtd->oobblock; i++) 
+			writeb ( this->data_poi[i] , this->IO_ADDR_W);
+		this->calculate_ecc (NULL, &(ecc_code[0]));
+		for (i = 0; i < 6; i++)
+			oob_data[oob_config[i]] = ecc_code[i];
+		break;
+		
+	default:
+		printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode);
+		BUG();	
+	}	
+	
+	/* Write out OOB data */
+	for (i = 0; i <  mtd->oobsize; i++)
+		writeb ( oob_data[i] , this->IO_ADDR_W);
+
+	/* Send command to actually program the data */
+	this->cmdfunc (mtd, NAND_CMD_PAGEPROG, -1, -1);
+
+	/* call wait ready function */
+	status = this->waitfunc (mtd, this, FL_WRITING);
+
+	/* See if device thinks it succeeded */
+	if (status & 0x01) {
+		DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page);
+		return -EIO;
+	}
+
+#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
+	/*
+	 * The NAND device assumes that it is always writing to
+	 * a cleanly erased page. Hence, it performs its internal
+	 * write verification only on bits that transitioned from
+	 * 1 to 0. The device does NOT verify the whole page on a
+	 * byte by byte basis. It is possible that the page was
+	 * not completely erased or the page is becoming unusable
+	 * due to wear. The read with ECC would catch the error
+	 * later when the ECC page check fails, but we would rather
+	 * catch it early in the page write stage. Better to write
+	 * no data than invalid data.
+	 */
+
+	/* Send command to read back the page */
+	this->cmdfunc (mtd, NAND_CMD_READ0, col, page);
+	/* Loop through and verify the data */
+	for (i = col; i < last; i++) {
+		if (this->data_poi[i] != readb (this->IO_ADDR_R)) {
+			DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
+			return -EIO;
+		}
+	}
+
+	/* check, if we have a fs-supplied oob-buffer */
+	if (oob_buf) {
+		for (i = 0; i < mtd->oobsize; i++) {
+			if (oob_data[i] != readb (this->IO_ADDR_R)) {
+				DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
+				return -EIO;
+			}
+		}
+	} else {
+		if (eccmode != NAND_ECC_NONE && !col && last == mtd->oobblock) {
+			int ecc_bytes = 0;
+
+			switch (this->eccmode) {
+			case NAND_ECC_SOFT:
+			case NAND_ECC_HW3_256: ecc_bytes = (mtd->oobblock == 512) ? 6 : 3; break;
+			case NAND_ECC_HW3_512: ecc_bytes = 3; break;
+			case NAND_ECC_HW6_512: ecc_bytes = 6; break;
+			}
+
+			for (i = 0; i < mtd->oobsize; i++)
+				oob_data[i] = readb (this->IO_ADDR_R);
+
+			for (i = 0; i < ecc_bytes; i++) {
+				if (oob_data[oob_config[i]] != ecc_code[i]) {
+					DEBUG (MTD_DEBUG_LEVEL0,
+					       "%s: Failed ECC write "
+				       "verify, page 0x%08x, " "%6i bytes were succesful\n", __FUNCTION__, page, i);
+				return -EIO;
+				}
+			}
+		}
+	}
 #endif
+	return 0;
 }
 
 /*
+*	Use NAND read ECC
+*/
+static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf)
+{
+	return (nand_read_ecc (mtd, from, len, retlen, buf, NULL, 0));
+}			   
+
+
+/*
  * NAND read with ECC
  */
 static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
-				size_t *retlen, u_char *buf, u_char *ecc_code)
+			  size_t * retlen, u_char * buf, u_char * oob_buf, int oobsel)
 {
-	int j, col, page, state;
+	int j, col, page, end, ecc;
 	int erase_state = 0;
+	int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0;
 	struct nand_chip *this = mtd->priv;
-	DECLARE_WAITQUEUE(wait, current);
-#ifdef CONFIG_MTD_NAND_ECC
-	int ecc_result;
+	u_char *data_poi, *oob_data = oob_buf;
 	u_char ecc_calc[6];
-#endif
+	u_char ecc_code[6];
+	int	eccmode = oobsel ? this->eccmode : NAND_ECC_NONE;
 
-	DEBUG (MTD_DEBUG_LEVEL3,
-		"nand_read_ecc: from = 0x%08x, len = %i\n", (unsigned int) from,
-		(int) len);
+	int *oob_config = oobconfigs[oobsel];
+	
+	DEBUG (MTD_DEBUG_LEVEL3, "nand_read_ecc: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
 
 	/* Do not allow reads past end of device */
 	if ((from + len) > mtd->size) {
-		DEBUG (MTD_DEBUG_LEVEL0,
-			"nand_read_ecc: Attempt read beyond end of device\n");
+		DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: Attempt read beyond end of device\n");
 		*retlen = 0;
 		return -EINVAL;
 	}
 
 	/* Grab the lock and see if the device is available */
-retry:
-	spin_lock_bh (&this->chip_lock);
-
-	switch (this->state) {
-	case FL_READY:
-		this->state = FL_READING;
-		spin_unlock_bh (&this->chip_lock);
-		break;
-
-	case FL_ERASING:
-		this->state = FL_READING;
-		erase_state = 1;
-		spin_unlock_bh (&this->chip_lock);
-		break;
-
-	default:
-		set_current_state (TASK_UNINTERRUPTIBLE);
-		add_wait_queue (&this->wq, &wait);
-		spin_unlock_bh (&this->chip_lock);
-		schedule();
+	nand_get_chip (this, mtd ,FL_READING, &erase_state);
 
-		remove_wait_queue (&this->wq, &wait);
-		goto retry;
-	};
+	/* Select the NAND device */
+	nand_select ();
 
 	/* First we calculate the starting page */
 	page = from >> this->page_shift;
@@ -199,122 +582,126 @@
 	/* Get raw starting column */
 	col = from & (mtd->oobblock - 1);
 
-	/* State machine for devices having pages larger than 256 bytes */
-	state = (col < mtd->eccsize) ? 0 : 1;
-
-	/* Calculate column address within ECC block context */
-	col = (col >= mtd->eccsize) ? (col - mtd->eccsize) : col;
-
-	/* Initialize return value */
-	*retlen = 0;
-
-	/* Select the NAND device */
-	nand_select ();
+	end = mtd->oobblock;
+	ecc = mtd->eccsize;
 
+	/* Send the read command */
+	this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page);
+	
 	/* Loop until all data read */
-	while (*retlen < len) {
-
-#ifdef CONFIG_MTD_NAND_ECC
-		/* Send the read command */
-		if (!state)
-			nand_command (mtd, NAND_CMD_READ0, 0x00, page);
-		else 
-			nand_command (mtd, NAND_CMD_READ1, 0x00, page);
-
-		/* Read in a block big enough for ECC */
-		for (j=0 ; j < mtd->eccsize ; j++)
-			this->data_buf[j] = readb (this->IO_ADDR);
-
-		/* Read in the out-of-band data */
-		if (!state) {
-			nand_command (mtd, NAND_CMD_READOOB, 0x00, page);
-			for (j=0 ; j<3 ; j++)
-				ecc_code[j] = readb(this->IO_ADDR);
-			nand_command (mtd, NAND_CMD_READ0, 0x00, page);
-		}
-		else {
-			nand_command (mtd, NAND_CMD_READOOB, 0x03, page);
-			for (j=3 ; j<6 ; j++)
-				ecc_code[j] = readb(this->IO_ADDR);
-			nand_command (mtd, NAND_CMD_READ0, 0x00, page);
-		}
-
-		/* Calculate the ECC and verify it */
-		if (!state) {
-			nand_calculate_ecc (&this->data_buf[0],
-						&ecc_calc[0]);
-			ecc_result = nand_correct_data (&this->data_buf[0],
-						&ecc_code[0], &ecc_calc[0]);
-		}
-		else {
-			nand_calculate_ecc (&this->data_buf[0],
-						&ecc_calc[3]);
-			ecc_result = nand_correct_data (&this->data_buf[0],
-						&ecc_code[3], &ecc_calc[3]);
-		}
-		if (ecc_result == -1) {
-			DEBUG (MTD_DEBUG_LEVEL0,
-				"nand_read_ecc: " \
-				"Failed ECC read, page 0x%08x\n", page);
-			nand_deselect ();
-			spin_lock_bh (&this->chip_lock);
-			if (erase_state)
-				this->state = FL_ERASING;
+	while (read < len) {
+		
+		/* If we have consequent page reads, apply delay or wait for ready/busy pin */
+		if (read) {
+			if (!this->dev_ready) 
+				udelay (this->chip_delay);
 			else
-				this->state = FL_READY;
-			wake_up (&this->wq);
-			spin_unlock_bh (&this->chip_lock);
-			return -EIO;
+				while (!this->dev_ready());	
 		}
 
-		/* Read the data from ECC data buffer into return buffer */
-		if ((*retlen + (mtd->eccsize - col)) >= len) {
-			while (*retlen < len)
-				buf[(*retlen)++] = this->data_buf[col++];
-			/* We're done */
-			continue;
-		}
-		else
-			for (j=col ; j < mtd->eccsize ; j++)
-				buf[(*retlen)++] = this->data_buf[j];
-#else
-		/* Send the read command */
-		if (!state)
-			nand_command (mtd, NAND_CMD_READ0, col, page);
+		/* 
+		 * If the read is not page aligned, we have to read into data buffer
+		 * due to ecc, else we read into return buffer direct
+		 */
+		if (!col && (len - read) >= end)  
+			data_poi = &buf[read];
 		else 
-			nand_command (mtd, NAND_CMD_READ1, col, page);
+			data_poi = this->data_buf;
 
-		/* Read the data directly into the return buffer */ 
-		if ((*retlen + (mtd->eccsize - col)) >= len) {
-			while (*retlen < len)
-				buf[(*retlen)++] = readb (this->IO_ADDR);
-			/* We're done */
-			continue;
-		}
-		else
-			for (j=col ; j < mtd->eccsize ; j++)
-				buf[(*retlen)++] = readb (this->IO_ADDR);
-#endif
+		/* get oob area, if we have no oob buffer from fs-driver */
+		if (!oob_buf) {
+			oob_data = &this->data_buf[end];
+			oob = 0;
+		} 	
+			
+		j = 0;
+		switch (eccmode) {
+		case NAND_ECC_NONE:	/* No ECC, Read in a page */		
+			while (j < end)
+				data_poi[j++] = readb (this->IO_ADDR_R);
+			break;
+			
+		case NAND_ECC_SOFT:	/* Software ECC 3/256: Read in a page + oob data */
+			while (j < end)
+				data_poi[j++] = readb (this->IO_ADDR_R);
+			this->calculate_ecc (&data_poi[0], &ecc_calc[0]);
+			if (mtd->oobblock == 512)
+				this->calculate_ecc (&data_poi[256], &ecc_calc[3]);
+			break;	
+			
+		case NAND_ECC_HW3_256: /* Hardware ECC 3 byte /256 byte data: Read in first 256 byte, get ecc, */
+			this->enable_hwecc (NAND_ECC_READ);	
+			while (j < ecc)
+				data_poi[j++] = readb (this->IO_ADDR_R);
+			this->calculate_ecc (&data_poi[0], &ecc_calc[0]);	/* read from hardware */
+			
+			if (mtd->oobblock == 512) { /* read second, if pagesize = 512 */
+				this->enable_hwecc (NAND_ECC_READ);	
+				while (j < end)
+					data_poi[j++] = readb (this->IO_ADDR_R);
+				this->calculate_ecc (&data_poi[256], &ecc_calc[3]); /* read from hardware */
+			}					
+			break;						
+				
+		case NAND_ECC_HW3_512:	
+		case NAND_ECC_HW6_512: /* Hardware ECC 3/6 byte / 512 byte data : Read in a page  */
+			this->enable_hwecc (NAND_ECC_READ);	
+			while (j < end)
+				data_poi[j++] = readb (this->IO_ADDR_R);
+			this->calculate_ecc (&data_poi[0], &ecc_calc[0]);	/* read from hardware */
+			break;
 
-		/*
-		 * If the amount of data to be read is greater than
-		 * (256 - col), then all subsequent reads will take
-		 * place on page or half-page (in the case of 512 byte
-		 * page devices) aligned boundaries and the column
-		 * address will be zero. Setting the column address to
-		 * to zero after the first read allows us to simplify
-		 * the reading of data and the if/else statements above.
-		 */
-		if (col)
-			col = 0x00;
+		default:
+			printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode);
+			BUG();	
+		}
 
+		/* read oobdata */
+		for (j = 0; j <  mtd->oobsize; j++) 
+			oob_data[oob + j] = readb (this->IO_ADDR_R);
+		
+		/* Skip ECC, if not active */
+		if (eccmode == NAND_ECC_NONE)
+			goto readdata;	
+		
+		/* Pick the ECC bytes out of the oob data */
+		for (j = 0; j < 6; j++)
+			ecc_code[j] = oob_data[oob + oob_config[j]];
+
+		/* correct data, if neccecary */
+		ecc_status = this->correct_data (&data_poi[0], &ecc_code[0], &ecc_calc[0]);
+		/* check, if we have a fs supplied oob-buffer */
+		if (oob_buf) { 
+			oob += mtd->oobsize;
+			*((int *)&oob_data[oob]) = ecc_status;
+			oob += sizeof(int);
+		}
+		if (ecc_status == -1) {	
+			DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page);
+			ecc_failed++;
+		}
+		
+		if (mtd->oobblock == 512 && eccmode != NAND_ECC_HW3_512) {
+			ecc_status = this->correct_data (&data_poi[256], &ecc_code[3], &ecc_calc[3]);
+			if (oob_buf) {
+				*((int *)&oob_data[oob]) = ecc_status;
+				oob += sizeof(int);
+			}
+			if (ecc_status == -1) {
+				DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page);
+				ecc_failed++;
+			}
+		}
+readdata:
+		if (col || (len - read) < end) { 
+			for (j = col; j < end && read < len; j++)
+				buf[read++] = data_poi[j];
+		} else		
+			read += mtd->oobblock;
+		/* For subsequent reads align to page boundary. */
+		col = 0;
 		/* Increment page address */
-		if ((mtd->oobblock == 256) || state)
-			page++;
-
-		/* Toggle state machine */
-		if (mtd->oobblock == 512)
-			state = state ? 0 : 1;
+		page++;
 	}
 
 	/* De-select the NAND device */
@@ -322,31 +709,29 @@
 
 	/* Wake up anyone waiting on the device */
 	spin_lock_bh (&this->chip_lock);
-	if (erase_state)
-		this->state = FL_ERASING;
-	else
-		this->state = FL_READY;
+	this->state = FL_READY;
 	wake_up (&this->wq);
 	spin_unlock_bh (&this->chip_lock);
-	
-	/* Return happy */
-	return 0;
+
+	/*
+	 * Return success, if no ECC failures, else -EIO
+	 * fs driver will take care of that, because
+	 * retlen == desired len and result == -EIO
+	 */
+	*retlen = read;
+	return ecc_failed ? -EIO : 0;
 }
 
 /*
  * NAND read out-of-band
  */
-static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len,
-				size_t *retlen, u_char *buf)
+static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf)
 {
 	int i, col, page;
 	int erase_state = 0;
 	struct nand_chip *this = mtd->priv;
-	DECLARE_WAITQUEUE(wait, current);
-	
-	DEBUG (MTD_DEBUG_LEVEL3,
-		"nand_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from,
-		(int) len);
+
+	DEBUG (MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
 
 	/* Shift to get page */
 	page = ((int) from) >> this->page_shift;
@@ -357,59 +742,36 @@
 	/* Initialize return length value */
 	*retlen = 0;
 
-	/* Do not allow read past end of page */
-	if ((col + len) > mtd->oobsize) {
-		DEBUG (MTD_DEBUG_LEVEL0,
-			"nand_read_oob: Attempt read past end of page " \
-			"0x%08x, column %i, length %i\n", page, col, len);
+	/* Do not allow reads past end of device */
+	if ((from + len) > mtd->size) {
+		DEBUG (MTD_DEBUG_LEVEL0, "nand_read_oob: Attempt read beyond end of device\n");
+		*retlen = 0;
 		return -EINVAL;
 	}
 
-retry:
 	/* Grab the lock and see if the device is available */
-	spin_lock_bh (&this->chip_lock);
-
-	switch (this->state) {
-	case FL_READY:
-		this->state = FL_READING;
-		spin_unlock_bh (&this->chip_lock);
-		break;
-
-	case FL_ERASING:
-		this->state = FL_READING;
-		erase_state = 1;
-		spin_unlock_bh (&this->chip_lock);
-		break;
-
-	default:
-		set_current_state (TASK_UNINTERRUPTIBLE);
-		add_wait_queue (&this->wq, &wait);
-		spin_unlock_bh (&this->chip_lock);
-		schedule();
-
-		remove_wait_queue (&this->wq, &wait);
-		goto retry;
-	};
+	nand_get_chip (this, mtd , FL_READING, &erase_state);
 
 	/* Select the NAND device */
 	nand_select ();
 
 	/* Send the read command */
-	nand_command (mtd, NAND_CMD_READOOB, col, page);	
-
-	/* Read the data */
-	for (i = 0 ; i < len ; i++)
-		buf[i] = readb (this->IO_ADDR);
-
+	this->cmdfunc (mtd, NAND_CMD_READOOB, col, page);
+	/* 
+	 * Read the data, if we read more than one page
+	 * oob data, let the device transfer the data !
+	 */
+	for (i = 0; i < len; i++) {
+		buf[i] = readb (this->IO_ADDR_R);
+		if ((col++ & (mtd->oobsize - 1)) == (mtd->oobsize - 1))
+			udelay (this->chip_delay);
+	}
 	/* De-select the NAND device */
 	nand_deselect ();
 
 	/* Wake up anyone waiting on the device */
 	spin_lock_bh (&this->chip_lock);
-	if (erase_state)
-		this->state = FL_ERASING;
-	else
-		this->state = FL_READY;
+	this->state = FL_READY;
 	wake_up (&this->wq);
 	spin_unlock_bh (&this->chip_lock);
 
@@ -419,264 +781,85 @@
 }
 
 /*
- * NAND write
- */
-static int nand_write (struct mtd_info *mtd, loff_t to, size_t len,
-			size_t *retlen, const u_char *buf)
+*	Use NAND write ECC
+*/
+static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf)
 {
-#ifdef CONFIG_MTD_NAND_ECC
-	struct nand_chip *this = mtd->priv;
-	
-	return nand_write_ecc (mtd, to, len, retlen, buf, this->ecc_code_buf);
-#else
-	return nand_write_ecc (mtd, to, len, retlen, buf, NULL);
-#endif
-}
-
+	return (nand_write_ecc (mtd, to, len, retlen, buf, NULL, 0));
+}			   
 /*
  * NAND write with ECC
  */
 static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
-				size_t *retlen, const u_char *buf,
-				u_char *ecc_code)
+			   size_t * retlen, const u_char * buf, u_char * eccbuf, int oobsel)
 {
-	int i, page, col, cnt, status;
+	int i, page, col, cnt, ret = 0, oob = 0, written = 0;
 	struct nand_chip *this = mtd->priv;
-	DECLARE_WAITQUEUE(wait, current);
-#ifdef CONFIG_MTD_NAND_ECC
-	int ecc_bytes = (mtd->oobblock == 512) ? 6 : 3;
-#endif
 
-	DEBUG (MTD_DEBUG_LEVEL3,
-		"nand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int) to,
-		(int) len);
+	DEBUG (MTD_DEBUG_LEVEL3, "nand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
 
-	/* Do not allow write past end of page */
+	/* Do not allow write past end of device */
 	if ((to + len) > mtd->size) {
-		DEBUG (MTD_DEBUG_LEVEL0,
-			"nand_write_ecc: Attempted write past end of device\n");
+		DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Attempt to write past end of page\n");
 		return -EINVAL;
 	}
 
-retry:
-	/* Grab the lock and see if the device is available */
-	spin_lock_bh (&this->chip_lock);
-
-	switch (this->state) {
-	case FL_READY:
-		this->state = FL_WRITING;
-		spin_unlock_bh (&this->chip_lock);
-		break;
-
-	default:
-		set_current_state (TASK_UNINTERRUPTIBLE);
-		add_wait_queue (&this->wq, &wait);
-		spin_unlock_bh (&this->chip_lock);
-		schedule();
-
-		remove_wait_queue (&this->wq, &wait);
-		goto retry;
-	};
-
 	/* Shift to get page */
 	page = ((int) to) >> this->page_shift;
 
 	/* Get the starting column */
 	col = to & (mtd->oobblock - 1);
 
-	/* Initialize return length value */
-	*retlen = 0;
+	/* Grab the lock and see if the device is available */
+	nand_get_chip (this, mtd, FL_WRITING, NULL);
 
 	/* Select the NAND device */
 	nand_select ();
 
 	/* Check the WP bit */
-	nand_command (mtd, NAND_CMD_STATUS, -1, -1);
-	if (!(readb (this->IO_ADDR) & 0x80)) {
-		DEBUG (MTD_DEBUG_LEVEL0,
-			"nand_write_ecc: Device is write protected!!!\n");
-		nand_deselect ();
-		spin_lock_bh (&this->chip_lock);
-		this->state = FL_READY;
-		wake_up (&this->wq);
-		spin_unlock_bh (&this->chip_lock);
-		return -EIO;
+	this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
+	if (!(readb (this->IO_ADDR_R) & 0x80)) {
+		DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: Device is write protected!!!\n");
+		ret = -EIO;
+		goto out;
 	}
 
 	/* Loop until all data is written */
-	while (*retlen < len) {
-		/* Write data into buffer */
-		if ((col + len) >= mtd->oobblock)
-			for(i=col, cnt=0 ; i < mtd->oobblock ; i++, cnt++)
-				this->data_buf[i] = buf[(*retlen + cnt)];
-		else
-			for(i=col, cnt=0 ; cnt < (len - *retlen) ; i++, cnt++)
-				this->data_buf[i] = buf[(*retlen + cnt)];
-		
-#ifdef CONFIG_MTD_NAND_ECC
-		/* Zero out the ECC array */
-		for (i=0 ; i < 6 ; i++)
-			ecc_code[i] = 0x00;
-
-		/* Calculate and write the ECC if we have enough data */
-		if ((col < mtd->eccsize) &&
-			((col + (len - *retlen)) >= mtd->eccsize)) {
-			nand_command (mtd, NAND_CMD_READ0, col, page);
-			for (i=0 ; i < col ; i++)
-				this->data_buf[i] = readb (this->IO_ADDR); 
-			nand_calculate_ecc (&this->data_buf[0], &ecc_code[0]);
-			for (i=0 ; i<3 ; i++)
-				this->data_buf[(mtd->oobblock + i)] =
-					ecc_code[i];
-		}
-
-		/* Calculate and write the second ECC if we have enough data */
-		if ((mtd->oobblock == 512) &&
-			((col + (len - *retlen)) >= mtd->oobblock)) {
-			nand_calculate_ecc (&this->data_buf[256], &ecc_code[3]);
-			for (i=3 ; i<6 ; i++)
-				this->data_buf[(mtd->oobblock + i)] =
-					ecc_code[i];
-		}
-
-		/* Write ones for partial page programming */
-		for (i=ecc_bytes ; i < mtd->oobsize ; i++)
-			this->data_buf[(mtd->oobblock + i)] = 0xff;
-#else
-		/* Write ones for partial page programming */
-		for (i=mtd->oobblock ; i < (mtd->oobblock + mtd->oobsize) ; i++)
-			this->data_buf[i] = 0xff;
-#endif
-
-		/* Write pre-padding bytes into buffer */
-		for (i=0 ; i < col ; i++)
-			this->data_buf[i] = 0xff;
-
-		/* Write post-padding bytes into buffer */
-		if ((col + (len - *retlen)) < mtd->oobblock) {
-			for(i=(col + cnt) ; i < mtd->oobblock ; i++)
-				this->data_buf[i] = 0xff;
-		}
-
-		/* Send command to begin auto page programming */
-		nand_command (mtd, NAND_CMD_SEQIN, 0x00, page);
-
-		/* Write out complete page of data */
-		for (i=0 ; i < (mtd->oobblock + mtd->oobsize) ; i++)
-			writeb (this->data_buf[i], this->IO_ADDR);
-
-		/* Send command to actually program the data */
-		nand_command (mtd, NAND_CMD_PAGEPROG, -1, -1);
-
-		/*
-		 * Wait for program operation to complete. This could
-		 * take up to 3000us (3ms) on some devices, so we try
-		 * and exit as quickly as possible.
+	while (written < len) {
+		/* 
+		 * Check, if we have a full page write, then we can
+		 * use the given buffer, else we have to copy
 		 */
-		status = 0;
-		for (i=0 ; i<24 ; i++) {
-			/* Delay for 125us */
-			udelay (125);
-
-			/* Check the status */
-			nand_command (mtd, NAND_CMD_STATUS, -1, -1);
-			status = (int) readb (this->IO_ADDR);
-			if (status & 0x40)
-				break;
-		}
-
-		/* See if device thinks it succeeded */
-		if (status & 0x01) {
-			DEBUG (MTD_DEBUG_LEVEL0,
-				"nand_write_ecc: " \
-				"Failed write, page 0x%08x, " \
-				"%6i bytes were succesful\n", page, *retlen);
-			nand_deselect ();
-			spin_lock_bh (&this->chip_lock);
-			this->state = FL_READY;
-			wake_up (&this->wq);
-			spin_unlock_bh (&this->chip_lock);
-			return -EIO;
-		}
-
-#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
-		/*
-		 * The NAND device assumes that it is always writing to
-		 * a cleanly erased page. Hence, it performs its internal
-		 * write verification only on bits that transitioned from
-		 * 1 to 0. The device does NOT verify the whole page on a
-		 * byte by byte basis. It is possible that the page was
-		 * not completely erased or the page is becoming unusable
-		 * due to wear. The read with ECC would catch the error
-		 * later when the ECC page check fails, but we would rather
-		 * catch it early in the page write stage. Better to write
-		 * no data than invalid data.
-		 */
-		
-		/* Send command to read back the page */
-		if (col < mtd->eccsize)
-			nand_command (mtd, NAND_CMD_READ0, col, page);
-		else
-			nand_command (mtd, NAND_CMD_READ1, col - 256, page);
-
-		/* Loop through and verify the data */
-		for (i=col ; i < cnt ; i++) {
-			if (this->data_buf[i] != readb (this->IO_ADDR)) {
-				DEBUG (MTD_DEBUG_LEVEL0,
-					"nand_write_ecc: " \
-					"Failed write verify, page 0x%08x, " \
-					"%6i bytes were succesful\n",
-					page, *retlen);
-				nand_deselect ();
-				spin_lock_bh (&this->chip_lock);
-				this->state = FL_READY;
-				wake_up (&this->wq);
-				spin_unlock_bh (&this->chip_lock);
-				return -EIO;
+		if (!col && (len - written) >= mtd->oobblock) {   
+			this->data_poi = (u_char*) &buf[written];
+			cnt = mtd->oobblock;
+		} else {
+			cnt = 0;
+			for (i = col; i < len && i < mtd->oobblock; i++) {
+				this->data_buf[i] = buf[written + i];
+				cnt++;
 			}
+			this->data_poi = this->data_buf;		
 		}
-
-#ifdef CONFIG_MTD_NAND_ECC
-		/*
-		 * We also want to check that the ECC bytes wrote
-		 * correctly for the same reasons stated above.
-		 */
-		nand_command (mtd, NAND_CMD_READOOB, 0x00, page);
-		for (i=0 ; i < ecc_bytes ; i++) {
-			if ((readb (this->IO_ADDR) != ecc_code[i]) &&
-					ecc_code[i]) {
-				DEBUG (MTD_DEBUG_LEVEL0,
-					"nand_write_ecc: Failed ECC write " \
-					"verify, page 0x%08x, " \
-					"%6i bytes were succesful\n",
-					page, i);
-				nand_deselect ();
-				spin_lock_bh (&this->chip_lock);
-				this->state = FL_READY;
-				wake_up (&this->wq);
-				spin_unlock_bh (&this->chip_lock);
-				return -EIO;
-			}
-		}
-#endif
-
-#endif
-
-		/*
-		 * If we are writing a large amount of data and/or it
-		 * crosses page or half-page boundaries, we set the
-		 * the column to zero. It simplifies the program logic.
-		 */
-		if (col)
-			col = 0x00;
+		/* We use the same function for write and writev !) */
+		if (eccbuf) {
+			ret = nand_write_page (mtd, this, page, col, cnt ,&eccbuf[oob], oobsel);
+			oob += mtd->oobsize;
+		} else 
+			ret = nand_write_page (mtd, this, page, col, cnt, NULL, oobsel);	
+		
+		if (ret)
+			goto out;
 
 		/* Update written bytes count */
-		*retlen += cnt;
-
+		written += cnt;
+		/* Next write is aligned */
+		col = 0;
 		/* Increment page address */
 		page++;
 	}
 
+out:
 	/* De-select the NAND device */
 	nand_deselect ();
 
@@ -686,24 +869,19 @@
 	wake_up (&this->wq);
 	spin_unlock_bh (&this->chip_lock);
 
-	/* Return happy */
-	*retlen = len;
-	return 0;
+	*retlen = written;
+	return ret;
 }
 
 /*
  * NAND write out-of-band
  */
-static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len,
-				size_t *retlen, const u_char *buf)
+static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf)
 {
-	int i, column, page, status;
+	int i, column, page, status, ret = 0;
 	struct nand_chip *this = mtd->priv;
-	DECLARE_WAITQUEUE(wait, current);
-	
-	DEBUG (MTD_DEBUG_LEVEL3,
-		"nand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to,
-		(int) len);
+
+	DEBUG (MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
 
 	/* Shift to get page */
 	page = ((int) to) >> this->page_shift;
@@ -716,105 +894,65 @@
 
 	/* Do not allow write past end of page */
 	if ((column + len) > mtd->oobsize) {
-		DEBUG (MTD_DEBUG_LEVEL0,
-			"nand_write_oob: Attempt to write past end of page\n");
+		DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Attempt to write past end of page\n");
 		return -EINVAL;
 	}
 
-retry:
 	/* Grab the lock and see if the device is available */
-	spin_lock_bh (&this->chip_lock);
-
-	switch (this->state) {
-	case FL_READY:
-		this->state = FL_WRITING;
-		spin_unlock_bh (&this->chip_lock);
-		break;
-
-	default:
-		set_current_state (TASK_UNINTERRUPTIBLE);
-		add_wait_queue (&this->wq, &wait);
-		spin_unlock_bh (&this->chip_lock);
-		schedule();
-
-		remove_wait_queue (&this->wq, &wait);
-		goto retry;
-	};
+	nand_get_chip (this, mtd, FL_WRITING, NULL);
 
 	/* Select the NAND device */
 	nand_select ();
 
 	/* Check the WP bit */
-	nand_command (mtd, NAND_CMD_STATUS, -1, -1);
-	if (!(readb (this->IO_ADDR) & 0x80)) {
-		DEBUG (MTD_DEBUG_LEVEL0,
-			"nand_write_oob: Device is write protected!!!\n");
-		nand_deselect ();
-		spin_lock_bh (&this->chip_lock);
-		this->state = FL_READY;
-		wake_up (&this->wq);
-		spin_unlock_bh (&this->chip_lock);
-		return -EIO;
+	this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
+	if (!(readb (this->IO_ADDR_R) & 0x80)) {
+		DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Device is write protected!!!\n");
+		ret = -EIO;
+		goto out;
 	}
 
 	/* Write out desired data */
-	nand_command (mtd, NAND_CMD_SEQIN, column + 512, page);
-	for (i=0 ; i<len ; i++)
-		writeb (buf[i], this->IO_ADDR);
+	this->cmdfunc (mtd, NAND_CMD_SEQIN, mtd->oobblock, page);
+	/* prepad 0xff for partial programming */
+	for (i = 0; i < column; i++)
+		writeb (0xff, this->IO_ADDR_W);
+	/* write data */
+	for (i = 0; i < len; i++)
+		writeb (buf[i], this->IO_ADDR_W);	
+	/* postpad 0xff for partial programming */
+	for (i = len + column; i < mtd->oobsize; i++)
+		writeb (0xff, this->IO_ADDR_W);
 
 	/* Send command to program the OOB data */
-	nand_command (mtd, NAND_CMD_PAGEPROG, -1, -1);
+	this->cmdfunc (mtd, NAND_CMD_PAGEPROG, -1, -1);
 
-	/*
-	 * Wait for program operation to complete. This could
-	 * take up to 3000us (3ms) on some devices, so we try
-	 * and exit as quickly as possible.
-	 */
-	status = 0;
-	for (i=0 ; i<24 ; i++) {
-		/* Delay for 125us */
-		udelay (125);
-
-		/* Check the status */
-		nand_command (mtd, NAND_CMD_STATUS, -1, -1);
-		status = (int) readb (this->IO_ADDR);
-		if (status & 0x40)
-			break;
-	}
+	status = this->waitfunc (mtd, this, FL_WRITING);
 
 	/* See if device thinks it succeeded */
 	if (status & 0x01) {
-		DEBUG (MTD_DEBUG_LEVEL0,
-			"nand_write_oob: " \
-			"Failed write, page 0x%08x\n", page);
-		nand_deselect ();
-		spin_lock_bh (&this->chip_lock);
-		this->state = FL_READY;
-		wake_up (&this->wq);
-		spin_unlock_bh (&this->chip_lock);
-		return -EIO;
+		DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write, page 0x%08x\n", page);
+		ret = -EIO;
+		goto out;
 	}
+	/* Return happy */
+	*retlen = len;
 
 #ifdef CONFIG_MTD_NAND_VERIFY_WRITE
 	/* Send command to read back the data */
-	nand_command (mtd, NAND_CMD_READOOB, column, page);
+	this->cmdfunc (mtd, NAND_CMD_READOOB, column, page);
 
 	/* Loop through and verify the data */
-	for (i=0 ; i<len ; i++) {
-		if (buf[i] != readb (this->IO_ADDR)) {
-			DEBUG (MTD_DEBUG_LEVEL0,
-				"nand_write_oob: " \
-				"Failed write verify, page 0x%08x\n", page);
-			nand_deselect ();
-			spin_lock_bh (&this->chip_lock);
-			this->state = FL_READY;
-			wake_up (&this->wq);
-			spin_unlock_bh (&this->chip_lock);
-			return -EIO;
+	for (i = 0; i < len; i++) {
+		if (buf[i] != readb (this->IO_ADDR_R)) {
+			DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write verify, page 0x%08x\n", page);
+			ret = -EIO;
+			goto out;
 		}
 	}
 #endif
 
+out:
 	/* De-select the NAND device */
 	nand_deselect ();
 
@@ -824,250 +962,107 @@
 	wake_up (&this->wq);
 	spin_unlock_bh (&this->chip_lock);
 
-	/* Return happy */
-	*retlen = len;
-	return 0;
+	return ret;
 }
 
+
 /*
  * NAND write with iovec
  */
-static int nand_writev (struct mtd_info *mtd, const struct iovec *vecs,
-				unsigned long count, loff_t to, size_t *retlen)
+static int nand_writev (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, 
+		loff_t to, size_t * retlen)
+{
+	return (nand_writev_ecc (mtd, vecs, count, to, retlen, NULL, 0));	
+}
+
+static int nand_writev_ecc (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, 
+		loff_t to, size_t * retlen, u_char *eccbuf, int oobsel)
 {
-	int i, page, col, cnt, len, total_len, status;
+	int i, page, col, cnt, len, total_len, ret = 0, written = 0;
 	struct nand_chip *this = mtd->priv;
-	DECLARE_WAITQUEUE(wait, current);
-#ifdef CONFIG_MTD_NAND_ECC
-	int ecc_bytes = (mtd->oobblock == 512) ? 6 : 3;
-#endif
 
 	/* Calculate total length of data */
 	total_len = 0;
-	for (i=0 ; i < count ; i++)
+	for (i = 0; i < count; i++)
 		total_len += (int) vecs[i].iov_len;
 
 	DEBUG (MTD_DEBUG_LEVEL3,
-		"nand_writev: to = 0x%08x, len = %i\n", (unsigned int) to,
-			(unsigned int) total_len);
+	       "nand_writev: to = 0x%08x, len = %i, count = %ld\n", (unsigned int) to, (unsigned int) total_len, count);
 
 	/* Do not allow write past end of page */
 	if ((to + total_len) > mtd->size) {
-		DEBUG (MTD_DEBUG_LEVEL0,
-			"nand_writev: Attempted write past end of device\n");
+		DEBUG (MTD_DEBUG_LEVEL0, "nand_writev: Attempted write past end of device\n");
 		return -EINVAL;
 	}
 
-retry:
-	/* Grab the lock and see if the device is available */
-	spin_lock_bh (&this->chip_lock);
-
-	switch (this->state) {
-	case FL_READY:
-		this->state = FL_WRITING;
-		spin_unlock_bh (&this->chip_lock);
-		break;
-
-	default:
-		set_current_state (TASK_UNINTERRUPTIBLE);
-		add_wait_queue (&this->wq, &wait);
-		spin_unlock_bh (&this->chip_lock);
-		schedule();
-
-		remove_wait_queue (&this->wq, &wait);
-		goto retry;
-	};
-
 	/* Shift to get page */
 	page = ((int) to) >> this->page_shift;
 
 	/* Get the starting column */
 	col = to & (mtd->oobblock - 1);
 
-	/* Initialize return length value */
-	*retlen = 0;
+	/* Grab the lock and see if the device is available */
+	nand_get_chip (this, mtd, FL_WRITING, NULL);
 
 	/* Select the NAND device */
 	nand_select ();
 
 	/* Check the WP bit */
-	nand_command (mtd, NAND_CMD_STATUS, -1, -1);
-	if (!(readb (this->IO_ADDR) & 0x80)) {
-		DEBUG (MTD_DEBUG_LEVEL0,
-			"nand_writev: Device is write protected!!!\n");
-		nand_deselect ();
-		spin_lock_bh (&this->chip_lock);
-		this->state = FL_READY;
-		wake_up (&this->wq);
-		spin_unlock_bh (&this->chip_lock);
-		return -EIO;
+	this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
+	if (!(readb (this->IO_ADDR_R) & 0x80)) {
+		DEBUG (MTD_DEBUG_LEVEL0, "nand_writev: Device is write protected!!!\n");
+		ret = -EIO;
+		goto out;
 	}
 
 	/* Loop until all iovecs' data has been written */
 	cnt = col;
 	len = 0;
+	
 	while (count) {
-		/* Do any need pre-fill for partial page programming */
-		for (i=0 ; i < cnt ; i++)
-			this->data_buf[i] = 0xff;
-
-		/*
-		 * Read data out of each tuple until we have a full page
-		 * to write or we've read all the tuples.
+		/* 
+		 *  Check, if we write from offset 0 and if the tuple
+		 *  gives us not enough data for a full page write. Then we
+		 *  can use the iov direct, else we have to copy into
+		 *  data_buf.		
 		 */
-		while ((cnt < mtd->oobblock) && count) {
-			this->data_buf[cnt++] =
-				((u_char *) vecs->iov_base)[len++];
+		if (!cnt && (vecs->iov_len - len) >= mtd->oobblock) {
+			cnt = mtd->oobblock;
+			this->data_poi = (u_char *) vecs->iov_base;
+			this->data_poi += len;
+			len += mtd->oobblock; 
+			/* Check, if we have to switch to the next tuple */
 			if (len >= (int) vecs->iov_len) {
 				vecs++;
 				len = 0;
 				count--;
 			}
+		} else {
+			/*
+			 * Read data out of each tuple until we have a full page
+			 * to write or we've read all the tuples.
+		 	*/
+			while ((cnt < mtd->oobblock) && count) {
+				if (vecs->iov_base != NULL && vecs->iov_len) {
+					this->data_buf[cnt++] = ((u_char *) vecs->iov_base)[len++];
+				}
+				/* Check, if we have to switch to the next tuple */
+				if (len >= (int) vecs->iov_len) {
+					vecs++;
+					len = 0;
+					count--;
+				}
+			}	
+			this->data_poi = this->data_buf;	
 		}
 		
-		/* Do any need post-fill for partial page programming */
-		for (i=cnt ; i < mtd->oobblock ; i++)
-			this->data_buf[i] = 0xff;
-
-#ifdef CONFIG_MTD_NAND_ECC
-		/* Zero out the ECC array */
-		for (i=0 ; i < 6 ; i++)
-			this->ecc_code_buf[i] = 0x00;
-
-		/* Calculate and write the first ECC */
-		if (col >= mtd->eccsize) {
-			nand_command (mtd, NAND_CMD_READ0, col, page);
-			for (i=0 ; i < col ; i++)
-				this->data_buf[i] = readb (this->IO_ADDR); 
-			nand_calculate_ecc (&this->data_buf[0],
-				&(this->ecc_code_buf[0]));
-			for (i=0 ; i<3 ; i++)
-				this->data_buf[(mtd->oobblock + i)] =
-					this->ecc_code_buf[i];
-		}
-
-		/* Calculate and write the second ECC */
-		if ((mtd->oobblock == 512) && (cnt == mtd->oobblock)) {
-			nand_calculate_ecc (&this->data_buf[256],
-				&(this->ecc_code_buf[3]));
-			for (i=3 ; i<6 ; i++)
-				this->data_buf[(mtd->oobblock + i)] =
-					this->ecc_code_buf[i];
-		}
-
-		/* Write ones for partial page programming */
-		for (i=ecc_bytes ; i < mtd->oobsize ; i++)
-			this->data_buf[(mtd->oobblock + i)] = 0xff;
-#else
-		/* Write ones for partial page programming */
-		for (i=mtd->oobblock ; i < (mtd->oobblock + mtd->oobsize) ; i++)
-			this->data_buf[i] = 0xff;
-#endif
-		/* Send command to begin auto page programming */
-		nand_command (mtd, NAND_CMD_SEQIN, 0x00, page);
-
-		/* Write out complete page of data */
-		for (i=0 ; i < (mtd->oobblock + mtd->oobsize) ; i++)
-			writeb (this->data_buf[i], this->IO_ADDR);
-
-		/* Send command to actually program the data */
-		nand_command (mtd, NAND_CMD_PAGEPROG, -1, -1);
-
-		/*
-		 * Wait for program operation to complete. This could
-		 * take up to 3000us (3ms) on some devices, so we try
-		 * and exit as quickly as possible.
-		 */
-		status = 0;
-		for (i=0 ; i<24 ; i++) {
-			/* Delay for 125us */
-			udelay (125);
-
-			/* Check the status */
-			nand_command (mtd, NAND_CMD_STATUS, -1, -1);
-			status = (int) readb (this->IO_ADDR);
-			if (status & 0x40)
-				break;
-		}
-
-		/* See if device thinks it succeeded */
-		if (status & 0x01) {
-			DEBUG (MTD_DEBUG_LEVEL0,
-				"nand_writev: " \
-				"Failed write, page 0x%08x, " \
-				"%6i bytes were succesful\n", page, *retlen);
-			nand_deselect ();
-			spin_lock_bh (&this->chip_lock);
-			this->state = FL_READY;
-			wake_up (&this->wq);
-			spin_unlock_bh (&this->chip_lock);
-			return -EIO;
-		}
-
-#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
-		/*
-		 * The NAND device assumes that it is always writing to
-		 * a cleanly erased page. Hence, it performs its internal
-		 * write verification only on bits that transitioned from
-		 * 1 to 0. The device does NOT verify the whole page on a
-		 * byte by byte basis. It is possible that the page was
-		 * not completely erased or the page is becoming unusable
-		 * due to wear. The read with ECC would catch the error
-		 * later when the ECC page check fails, but we would rather
-		 * catch it early in the page write stage. Better to write
-		 * no data than invalid data.
-		 */
-		
-		/* Send command to read back the page */
-		if (col < mtd->eccsize)
-			nand_command (mtd, NAND_CMD_READ0, col, page);
-		else
-			nand_command (mtd, NAND_CMD_READ1, col - 256, page);
-
-		/* Loop through and verify the data */
-		for (i=col ; i < cnt ; i++) {
-			if (this->data_buf[i] != readb (this->IO_ADDR)) {
-				DEBUG (MTD_DEBUG_LEVEL0,
-					"nand_writev: " \
-					"Failed write verify, page 0x%08x, " \
-					"%6i bytes were succesful\n",
-					page, *retlen);
-				nand_deselect ();
-				spin_lock_bh (&this->chip_lock);
-				this->state = FL_READY;
-				wake_up (&this->wq);
-				spin_unlock_bh (&this->chip_lock);
-				return -EIO;
-			}
-		}
-
-#ifdef CONFIG_MTD_NAND_ECC
-		/*
-		 * We also want to check that the ECC bytes wrote
-		 * correctly for the same reasons stated above.
-		 */
-		nand_command (mtd, NAND_CMD_READOOB, 0x00, page);
-		for (i=0 ; i < ecc_bytes ; i++) {
-			if ((readb (this->IO_ADDR) != this->ecc_code_buf[i]) &&
-					this->ecc_code_buf[i]) {
-				DEBUG (MTD_DEBUG_LEVEL0,
-					"nand_writev: Failed ECC write " \
-					"verify, page 0x%08x, " \
-					"%6i bytes were succesful\n",
-					page, i);
-				nand_deselect ();
-				spin_lock_bh (&this->chip_lock);
-				this->state = FL_READY;
-				wake_up (&this->wq);
-				spin_unlock_bh (&this->chip_lock);
-				return -EIO;
-			}
-		}
-#endif
+		/* We use the same function for write and writev !) */
+		ret = nand_write_page (mtd, this, page, col, cnt, NULL, oobsel);
+		if (ret)
+			goto out;
 
-#endif
 		/* Update written bytes count */
-		*retlen += (cnt - col);
+		written += (cnt - col);
 
 		/* Reset written byte counter and column */
 		col = cnt = 0;
@@ -1076,6 +1071,7 @@
 		page++;
 	}
 
+out:
 	/* De-select the NAND device */
 	nand_deselect ();
 
@@ -1085,8 +1081,8 @@
 	wake_up (&this->wq);
 	spin_unlock_bh (&this->chip_lock);
 
-	/* Return happy */
-	return 0;
+	*retlen = written;
+	return ret;
 }
 
 /*
@@ -1094,53 +1090,33 @@
  */
 static int nand_erase (struct mtd_info *mtd, struct erase_info *instr)
 {
-	int i, page, len, status, pages_per_block;
+	int page, len, status, pages_per_block, ret;
 	struct nand_chip *this = mtd->priv;
-	DECLARE_WAITQUEUE(wait, current);
+	DECLARE_WAITQUEUE (wait, current);
 
 	DEBUG (MTD_DEBUG_LEVEL3,
-		"nand_erase: start = 0x%08x, len = %i\n",
-		(unsigned int) instr->addr, (unsigned int) instr->len);
+	       "nand_erase: start = 0x%08x, len = %i\n", (unsigned int) instr->addr, (unsigned int) instr->len);
 
 	/* Start address must align on block boundary */
 	if (instr->addr & (mtd->erasesize - 1)) {
-		DEBUG (MTD_DEBUG_LEVEL0,
-			"nand_erase: Unaligned address\n");
+		DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Unaligned address\n");
 		return -EINVAL;
 	}
 
 	/* Length must align on block boundary */
 	if (instr->len & (mtd->erasesize - 1)) {
-		DEBUG (MTD_DEBUG_LEVEL0,
-			"nand_erase: Length not block aligned\n");
+		DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Length not block aligned\n");
 		return -EINVAL;
 	}
 
 	/* Do not allow erase past end of device */
 	if ((instr->len + instr->addr) > mtd->size) {
-		DEBUG (MTD_DEBUG_LEVEL0,
-			"nand_erase: Erase past end of device\n");
+		DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Erase past end of device\n");
 		return -EINVAL;
 	}
 
-retry:
 	/* Grab the lock and see if the device is available */
-	spin_lock_bh (&this->chip_lock);
-
-	switch (this->state) {
-	case FL_READY:
-		this->state = FL_ERASING;
-		break;
-
-	default:
-		set_current_state (TASK_UNINTERRUPTIBLE);
-		add_wait_queue (&this->wq, &wait);
-		spin_unlock_bh (&this->chip_lock);
-		schedule();
-
-		remove_wait_queue (&this->wq, &wait);
-		goto retry;
-	};
+	nand_get_chip (this, mtd, FL_ERASING, NULL);
 
 	/* Shift to get first page */
 	page = (int) (instr->addr >> this->page_shift);
@@ -1152,81 +1128,78 @@
 	nand_select ();
 
 	/* Check the WP bit */
-	nand_command (mtd, NAND_CMD_STATUS, -1, -1);
-	if (!(readb (this->IO_ADDR) & 0x80)) {
-		DEBUG (MTD_DEBUG_LEVEL0,
-			"nand_erase: Device is write protected!!!\n");
-		nand_deselect ();
-		this->state = FL_READY;
-		spin_unlock_bh (&this->chip_lock);
-		return -EIO;
+	this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
+	if (!(readb (this->IO_ADDR_R) & 0x80)) {
+		DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Device is write protected!!!\n");
+		instr->state = MTD_ERASE_FAILED;
+		goto erase_exit;
 	}
 
 	/* Loop through the pages */
 	len = instr->len;
+
+	instr->state = MTD_ERASING;
+
 	while (len) {
+		/* Check if we have a bad block, we do not erase bad blocks ! */
+		this->cmdfunc (mtd, NAND_CMD_READOOB, NAND_BADBLOCK_POS, page);
+		if (readb (this->IO_ADDR_R) != 0xff) {
+			printk (KERN_WARNING "nand_erase: attempt to erase a bad block at page 0x%08x\n", page);
+			instr->state = MTD_ERASE_FAILED;
+			goto erase_exit;
+		}
+
 		/* Send commands to erase a page */
-		nand_command(mtd, NAND_CMD_ERASE1, -1, page);
-		nand_command(mtd, NAND_CMD_ERASE2, -1, -1);
+		this->cmdfunc (mtd, NAND_CMD_ERASE1, -1, page);
+		this->cmdfunc (mtd, NAND_CMD_ERASE2, -1, -1);
 
-		/*
-		 * Wait for program operation to complete. This could
-		 * take up to 4000us (4ms) on some devices, so we try
-		 * and exit as quickly as possible.
-		 */
-		status = 0;
-		for (i=0 ; i<32 ; i++) {
-			/* Delay for 125us */
-			udelay (125);
-
-			/* Check the status */
-			nand_command (mtd, NAND_CMD_STATUS, -1, -1);
-			status = (int) readb (this->IO_ADDR);
-			if (status & 0x40)
-				break;
-		}
+		spin_unlock_bh (&this->chip_lock);
+		status = this->waitfunc (mtd, this, FL_ERASING);
 
+		/* Get spinlock, in case we exit */
+		spin_lock_bh (&this->chip_lock);
 		/* See if block erase succeeded */
 		if (status & 0x01) {
-			DEBUG (MTD_DEBUG_LEVEL0,
-				"nand_erase: " \
-				"Failed erase, page 0x%08x\n", page);
-			nand_deselect ();
-			this->state = FL_READY;
-			spin_unlock_bh (&this->chip_lock);
-			return -EIO;
+			DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page);
+			instr->state = MTD_ERASE_FAILED;
+			goto erase_exit;
+		}
+		
+		/* Check, if we were interupted */
+		if (this->state == FL_ERASING) {
+			/* Increment page address and decrement length */
+			len -= mtd->erasesize;
+			page += pages_per_block;
 		}
-
-		/* Increment page address and decrement length */
-		len -= mtd->erasesize;
-		page += pages_per_block;
-
 		/* Release the spin lock */
 		spin_unlock_bh (&this->chip_lock);
-
 erase_retry:
-		/* Check the state and sleep if it changed */
 		spin_lock_bh (&this->chip_lock);
-		if (this->state == FL_ERASING) {
+		/* Check the state and sleep if it changed */
+		if (this->state == FL_ERASING || this->state == FL_READY) {
+			/* Select the NAND device again, if we were interrupted */
+			this->state = FL_ERASING;
+			nand_select ();
 			continue;
-		}
-		else {
+		} else {
 			set_current_state (TASK_UNINTERRUPTIBLE);
 			add_wait_queue (&this->wq, &wait);
 			spin_unlock_bh (&this->chip_lock);
-			schedule();
-
+			schedule ();
 			remove_wait_queue (&this->wq, &wait);
 			goto erase_retry;
 		}
 	}
-	spin_unlock_bh (&this->chip_lock);
+	instr->state = MTD_ERASE_DONE;
 
+erase_exit:
 	/* De-select the NAND device */
 	nand_deselect ();
+	spin_unlock_bh (&this->chip_lock);
 
+	ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;;
 	/* Do call back function */
-	if (instr->callback)
+	if (!ret && instr->callback)
 		instr->callback (instr);
 
 	/* The device is ready */
@@ -1234,8 +1207,8 @@
 	this->state = FL_READY;
 	spin_unlock_bh (&this->chip_lock);
 
-	/* Return happy */
-	return 0;
+	/* Return more or less happy */
+	return ret;
 }
 
 /*
@@ -1244,16 +1217,16 @@
 static void nand_sync (struct mtd_info *mtd)
 {
 	struct nand_chip *this = mtd->priv;
-	DECLARE_WAITQUEUE(wait, current);
+	DECLARE_WAITQUEUE (wait, current);
 
 	DEBUG (MTD_DEBUG_LEVEL3, "nand_sync: called\n");
 
 retry:
 	/* Grab the spinlock */
-	spin_lock_bh(&this->chip_lock);
+	spin_lock_bh (&this->chip_lock);
 
 	/* See what's going on */
-	switch(this->state) {
+	switch (this->state) {
 	case FL_READY:
 	case FL_SYNCING:
 		this->state = FL_SYNCING;
@@ -1270,7 +1243,7 @@
 		goto retry;
 	}
 
-        /* Lock the device */
+	/* Lock the device */
 	spin_lock_bh (&this->chip_lock);
 
 	/* Set the device to be ready again */
@@ -1279,7 +1252,7 @@
 		wake_up (&this->wq);
 	}
 
-        /* Unlock the device */
+	/* Unlock the device */
 	spin_unlock_bh (&this->chip_lock);
 }
 
@@ -1291,46 +1264,99 @@
 	int i, nand_maf_id, nand_dev_id;
 	struct nand_chip *this = mtd->priv;
 
+	/* check for proper chip_delay setup, set 20us if not */
+	if (!this->chip_delay)
+		this->chip_delay = 20;
+
+	/* check, if a user supplied command function given */
+	if (this->cmdfunc == NULL)
+		this->cmdfunc = nand_command;
+
+	/* check, if a user supplied wait function given */
+	if (this->waitfunc == NULL)
+		this->waitfunc = nand_wait;
+
 	/* Select the device */
 	nand_select ();
 
 	/* Send the command for reading device ID */
-	nand_command (mtd, NAND_CMD_READID, 0x00, -1);
+	this->cmdfunc (mtd, NAND_CMD_READID, 0x00, -1);
 
 	/* Read manufacturer and device IDs */
-	nand_maf_id = readb (this->IO_ADDR);
-	nand_dev_id = readb (this->IO_ADDR);
+	nand_maf_id = readb (this->IO_ADDR_R);
+	nand_dev_id = readb (this->IO_ADDR_R);
 
 	/* Print and store flash device information */
 	for (i = 0; nand_flash_ids[i].name != NULL; i++) {
-		if (nand_maf_id == nand_flash_ids[i].manufacture_id &&
-		    nand_dev_id == nand_flash_ids[i].model_id) {
-			if (!mtd->size) {
-				mtd->name = nand_flash_ids[i].name;
-				mtd->erasesize = nand_flash_ids[i].erasesize;
-				mtd->size = (1 << nand_flash_ids[i].chipshift);
-				mtd->eccsize = 256;
-				if (nand_flash_ids[i].page256) {
-					mtd->oobblock = 256;
-					mtd->oobsize = 8;
-					this->page_shift = 8;
-				}
-				else {
-					mtd->oobblock = 512;
-					mtd->oobsize = 16;
-					this->page_shift = 9;
-				}
+		if (nand_dev_id == nand_flash_ids[i].id && !mtd->size) {
+			mtd->name = nand_flash_ids[i].name;
+			mtd->erasesize = nand_flash_ids[i].erasesize;
+			mtd->size = (1 << nand_flash_ids[i].chipshift);
+			mtd->eccsize = 256;
+			if (nand_flash_ids[i].page256) {
+				mtd->oobblock = 256;
+				mtd->oobsize = 8;
+				this->page_shift = 8;
+			} else {
+				mtd->oobblock = 512;
+				mtd->oobsize = 16;
+				this->page_shift = 9;
 			}
-			printk (KERN_INFO "NAND device: Manufacture ID:" \
-				" 0x%02x, Chip ID: 0x%02x (%s)\n",
-			       nand_maf_id, nand_dev_id, mtd->name);
+			/* Try to identify manufacturer */
+			for (i = 0; nand_manuf_ids[i].id != 0x0; i++) {
+				if (nand_manuf_ids[i].id == nand_maf_id)
+					break;
+			}	
+			printk (KERN_INFO "NAND device: Manufacture ID:"
+				" 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, 
+				nand_manuf_ids[i].name , mtd->name);
 			break;
 		}
 	}
 
-	/* Initialize state and spinlock */
+	/* 
+	 * check ECC mode, default to software
+	 * if 3byte/512byte hardware ECC is selected and we have 256 byte pagesize
+	 * fallback to software ECC 
+	*/
+	this->eccsize = 256;	/* set default eccsize */	
+
+	switch (this->eccmode) {
+
+	case NAND_ECC_HW3_512: 
+		if (mtd->oobblock == 256) {
+			printk (KERN_WARNING "512 byte HW ECC not possible on 256 Byte pagesize, fallback to SW ECC \n");
+			this->eccmode = NAND_ECC_SOFT;
+			this->calculate_ecc = nand_calculate_ecc;
+			this->correct_data = nand_correct_data;
+			break;		
+		} else 
+			this->eccsize = 512; /* set eccsize to 512 and fall through for function check */
+
+	case NAND_ECC_HW3_256:
+		if (this->calculate_ecc && this->correct_data && this->enable_hwecc)
+			break;
+		printk (KERN_WARNING "No ECC functions supplied, Hardware ECC not possible\n");
+		BUG();	
+
+	case NAND_ECC_NONE: 
+		this->eccmode = NAND_ECC_NONE;
+		break;
+
+	case NAND_ECC_SOFT:	
+		this->calculate_ecc = nand_calculate_ecc;
+		this->correct_data = nand_correct_data;
+		break;
+
+	default:
+		printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode);
+		BUG();	
+	}	
+
+	/* Initialize state, waitqueue and spinlock */
 	this->state = FL_READY;
-	spin_lock_init(&this->chip_lock);
+	init_waitqueue_head (&this->wq);
+	spin_lock_init (&this->chip_lock);
 
 	/* De-select the device */
 	nand_deselect ();
@@ -1357,6 +1383,7 @@
 	mtd->write_oob = nand_write_oob;
 	mtd->readv = NULL;
 	mtd->writev = nand_writev;
+	mtd->writev_ecc = nand_writev_ecc;
 	mtd->sync = nand_sync;
 	mtd->lock = NULL;
 	mtd->unlock = NULL;
@@ -1367,8 +1394,8 @@
 	return 0;
 }
 
-EXPORT_SYMBOL(nand_scan);
+EXPORT_SYMBOL (nand_scan);
 
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Steven J. Hill <sjhill@cotw.com");
-MODULE_DESCRIPTION("Generic NAND flash driver code");
+MODULE_LICENSE ("GPL");
+MODULE_AUTHOR ("Steven J. Hill <sjhill@cotw.com>, Thomas Gleixner <tglx@linutronix.de>");
+MODULE_DESCRIPTION ("Generic NAND flash driver code");
diff -urN linux-2.4.21-pre3/drivers/mtd/nand/nand_ecc.c linux-2.4.21-pre4/drivers/mtd/nand/nand_ecc.c
--- linux-2.4.21-pre3/drivers/mtd/nand/nand_ecc.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.21-pre4/drivers/mtd/nand/nand_ecc.c	Tue Jan 28 19:44:30 2003
@@ -4,11 +4,11 @@
  *  Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
  *                     Toshiba America Electronics Components, Inc.
  *
- * $Id: nand_ecc.c,v 1.7 2002/03/21 14:13:50 dwmw2 Exp $
+ * $Id: nand_ecc.c,v 1.8 2002/09/16 09:19:53 dwmw2 Exp $
  *
- * 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.
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
  *
  * This file contains an ECC algorithm from Toshiba that detects and
  * corrects 1 bit errors in a 256 byte block of data.
diff -urN linux-2.4.21-pre3/drivers/mtd/nand/nand_ids.c linux-2.4.21-pre4/drivers/mtd/nand/nand_ids.c
--- linux-2.4.21-pre3/drivers/mtd/nand/nand_ids.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/drivers/mtd/nand/nand_ids.c	Tue Jan 28 19:44:30 2003
@@ -0,0 +1,56 @@
+/*
+ *  drivers/mtd/nandids.c
+ *
+ *  Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de)
+ *
+ *
+ * $Id: nand_ids.c,v 1.1 2002/12/02 22:06:04 gleixner Exp $
+ *
+ * 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/module.h>
+#include <linux/mtd/nand.h>
+
+/*
+*	Chip ID list
+*/
+struct nand_flash_dev nand_flash_ids[] = {
+	{"NAND 1MB 5V", 0x6e, 20, 0x1000, 1},	// 1Mb 5V
+	{"NAND 2MB 5V", 0x64, 21, 0x1000, 1},	// 2Mb 5V
+	{"NAND 4MB 5V", 0x6b, 22, 0x2000, 0},	// 4Mb 5V
+	{"NAND 1MB 3,3V", 0xe8, 20, 0x1000, 1},	// 1Mb 3.3V
+	{"NAND 1MB 3,3V", 0xec, 20, 0x1000, 1},	// 1Mb 3.3V
+	{"NAND 2MB 3,3V", 0xea, 21, 0x1000, 1},	// 2Mb 3.3V
+	{"NAND 4MB 3,3V", 0xd5, 22, 0x2000, 0},	// 4Mb 3.3V
+	{"NAND 4MB 3,3V", 0xe3, 22, 0x2000, 0},	// 4Mb 3.3V
+	{"NAND 4MB 3,3V", 0xe5, 22, 0x2000, 0},	// 4Mb 3.3V
+	{"NAND 8MB 3,3V", 0xd6, 23, 0x2000, 0},	// 8Mb 3.3V
+	{"NAND 8MB 3,3V", 0xe6, 23, 0x2000, 0},	// 8Mb 3.3V
+	{"NAND 16MB 3,3V", 0x73, 24, 0x4000, 0},// 16Mb 3,3V
+	{"NAND 32MB 3,3V", 0x75, 25, 0x4000, 0}, // 32Mb 3,3V
+	{"NAND 64MB 3,3V", 0x76, 26, 0x4000, 0}, // 64Mb 3,3V
+	{"NAND 128MB 3,3V", 0x79, 27, 0x4000, 0}, // 128Mb 3,3V
+	{NULL,}
+};
+
+/*
+*	Manufacturer ID list
+*/
+struct nand_manufacturers nand_manuf_ids[] = {
+	{NAND_MFR_TOSHIBA, "Toshiba"},
+	{NAND_MFR_SAMSUNG, "Samsung"},
+	{NAND_MFR_FUJITSU, "Fujitsu"},
+	{NAND_MFR_NATIONAL, "National"},
+	{0x0, "Unknown"}
+};
+
+
+EXPORT_SYMBOL (nand_manuf_ids);
+EXPORT_SYMBOL (nand_flash_ids);
+
+MODULE_LICENSE ("GPL");
+MODULE_AUTHOR ("Thomas Gleixner <tglx@linutronix.de>");
+MODULE_DESCRIPTION ("Nand device & manufacturer ID's");
diff -urN linux-2.4.21-pre3/drivers/mtd/nand/spia.c linux-2.4.21-pre4/drivers/mtd/nand/spia.c
--- linux-2.4.21-pre3/drivers/mtd/nand/spia.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.21-pre4/drivers/mtd/nand/spia.c	Tue Jan 28 19:44:30 2003
@@ -3,7 +3,12 @@
  *
  *  Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
  *
- * $Id: spia.c,v 1.12 2001/10/02 15:05:14 dwmw2 Exp $
+ *
+ *	10-29-2001 TG	change to support hardwarespecific access
+ *			to controllines	(due to change in nand.c)
+ *			page_cache added
+ *
+ * $Id: spia.c,v 1.16 2002/03/05 13:50:47 dwmw2 Exp $
  *
  * 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
@@ -75,6 +80,25 @@
 };
 #define NUM_PARTITIONS 2
 
+
+/* 
+ *	hardware specific access to control-lines
+*/
+void spia_hwcontrol(int cmd){
+
+    switch(cmd){
+
+	case NAND_CTL_SETCLE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) |=  0x01; break;
+	case NAND_CTL_CLRCLE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) &= ~0x01; break;
+
+	case NAND_CTL_SETALE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) |=  0x02; break;
+	case NAND_CTL_CLRALE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) &= ~0x02; break;
+
+	case NAND_CTL_SETNCE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) &= ~0x04; break;
+	case NAND_CTL_CLRNCE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) |=  0x04; break;
+    }
+}
+
 /*
  * Main initialization routine
  */
@@ -107,11 +131,12 @@
 	(*(volatile unsigned char *) (spia_io_base + spia_peddr)) = 0x07;
 
 	/* Set address of NAND IO lines */
-	this->IO_ADDR = spia_fio_base;
-	this->CTRL_ADDR = spia_io_base + spia_pedr;
-	this->CLE = 0x01;
-	this->ALE = 0x02;
-	this->NCE = 0x04;
+	this->IO_ADDR_R = spia_fio_base;
+	this->IO_ADDR_W = spia_fio_base;
+	/* Set address of hardware control function */
+	this->hwcontrol = spia_hwcontrol;
+	/* 15 us command delay time */
+	this->chip_delay = 15;		
 
 	/* Scan to find existence of the device */
 	if (nand_scan (spia_mtd)) {
@@ -127,6 +152,16 @@
 		return -ENOMEM;
 	}
 
+	/* Allocate memory for internal data buffer */
+	this->data_cache = kmalloc (sizeof(u_char) * (spia_mtd->oobblock + spia_mtd->oobsize), GFP_KERNEL);
+	if (!this->data_cache) {
+		printk ("Unable to allocate NAND data cache for SPIA.\n");
+		kfree (this->data_buf);
+		kfree (spia_mtd);
+		return = -ENOMEM;
+	}
+	this->cache_page = -1;
+
 	/* Register the partitions */
 	add_mtd_partitions(spia_mtd, partition_info, NUM_PARTITIONS);
 
@@ -148,6 +183,7 @@
 
 	/* Free internal data buffer */
 	kfree (this->data_buf);
+	kfree (this->page_cache);
 
 	/* Free the MTD device structure */
 	kfree (spia_mtd);
diff -urN linux-2.4.21-pre3/drivers/mtd/nftlcore.c linux-2.4.21-pre4/drivers/mtd/nftlcore.c
--- linux-2.4.21-pre3/drivers/mtd/nftlcore.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.21-pre4/drivers/mtd/nftlcore.c	Tue Jan 28 19:44:30 2003
@@ -1,7 +1,7 @@
 /* Linux driver for NAND Flash Translation Layer      */
 /* (c) 1999 Machine Vision Holdings, Inc.             */
 /* Author: David Woodhouse <dwmw2@infradead.org>      */
-/* $Id: nftlcore.c,v 1.85 2001/11/20 11:42:33 dwmw2 Exp $ */
+/* $Id: nftlcore.c,v 1.87 2002/09/13 14:35:33 dwmw2 Exp $ */
 
 /*
   The contents of this file are distributed under the GNU General
@@ -29,6 +29,7 @@
 #include <linux/kmod.h>
 #endif
 #include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
 #include <linux/mtd/nftl.h>
 #include <linux/mtd/compatmac.h>
 
@@ -118,9 +119,6 @@
 
 	init_MUTEX(&nftl->mutex);
 
-        /* get physical parameters */
-	nftl->EraseSize = mtd->erasesize;
-        nftl->nb_blocks = mtd->size / mtd->erasesize;
 	nftl->mtd = mtd;
 
         if (NFTL_mount(nftl) < 0) {
@@ -155,7 +153,7 @@
 
 	if (nftl->nr_sects != nftl->heads * nftl->cylinders * nftl->sectors) {
 		printk(KERN_WARNING "Cannot calculate an NFTL geometry to "
-		       "match size of 0x%lx.\n", nftl->nr_sects);
+		       "match size of 0x%x.\n", nftl->nr_sects);
 		printk(KERN_WARNING "Using C:%d H:%d S:%d (== 0x%lx sects)\n", 
 		       nftl->cylinders, nftl->heads , nftl->sectors, 
 		       (long)nftl->cylinders * (long)nftl->heads * (long)nftl->sectors );
@@ -446,17 +444,17 @@
                 if (BlockMap[block] == BLOCK_NIL)
                         continue;
                 
-                ret = MTD_READECC(nftl->mtd, (nftl->EraseSize * BlockMap[block])
-                                  + (block * 512), 512, &retlen, movebuf, (char *)&oob); 
+                ret = MTD_READECC(nftl->mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512),
+				  512, &retlen, movebuf, (char *)&oob, NAND_ECC_DISKONCHIP); 
                 if (ret < 0) {
                     ret = MTD_READECC(nftl->mtd, (nftl->EraseSize * BlockMap[block])
                                       + (block * 512), 512, &retlen,
-                                      movebuf, (char *)&oob); 
+                                      movebuf, (char *)&oob, NAND_ECC_DISKONCHIP); 
                     if (ret != -EIO) 
                         printk("Error went away on retry.\n");
                 }
                 MTD_WRITEECC(nftl->mtd, (nftl->EraseSize * targetEUN) + (block * 512),
-                             512, &retlen, movebuf, (char *)&oob);
+                             512, &retlen, movebuf, (char *)&oob, NAND_ECC_DISKONCHIP);
 	}
         
         /* add the header so that it is now a valid chain */
@@ -723,7 +721,7 @@
 	}
 
 	MTD_WRITEECC(nftl->mtd, (writeEUN * nftl->EraseSize) + blockofs,
-		     512, &retlen, (char *)buffer, (char *)eccbuf);
+		     512, &retlen, (char *)buffer, (char *)eccbuf, NAND_ECC_DISKONCHIP);
         /* no need to write SECTOR_USED flags since they are written in mtd_writeecc */
 
 	return 0;
@@ -785,7 +783,7 @@
 		loff_t ptr = (lastgoodEUN * nftl->EraseSize) + blockofs;
 		size_t retlen;
 		u_char eccbuf[6];
-		if (MTD_READECC(nftl->mtd, ptr, 512, &retlen, buffer, eccbuf))
+		if (MTD_READECC(nftl->mtd, ptr, 512, &retlen, buffer, eccbuf, NAND_ECC_DISKONCHIP))
 			return -EIO;
 	}
 	return 0;
@@ -1062,7 +1060,7 @@
 	int i;
 
 #ifdef PRERELEASE 
-	printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.85 $, nftlmount.c %s\n", nftlmountrev);
+	printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.87 $, nftlmount.c %s\n", nftlmountrev);
 #endif
 
 	if (register_blkdev(MAJOR_NR, "nftl", &nftl_fops)){
diff -urN linux-2.4.21-pre3/drivers/mtd/nftlmount.c linux-2.4.21-pre4/drivers/mtd/nftlmount.c
--- linux-2.4.21-pre3/drivers/mtd/nftlmount.c	Mon Feb 25 11:37:58 2002
+++ linux-2.4.21-pre4/drivers/mtd/nftlmount.c	Tue Jan 28 19:44:30 2003
@@ -4,7 +4,7 @@
  * Author: Fabrice Bellard (fabrice.bellard@netgem.com) 
  * Copyright (C) 2000 Netgem S.A.
  *
- * $Id: nftlmount.c,v 1.25 2001/11/30 16:46:27 dwmw2 Exp $
+ * $Id: nftlmount.c,v 1.31 2002/11/15 16:34:43 dwmw2 Exp $
  *
  * 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
@@ -34,12 +34,13 @@
 #include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
 #include <linux/mtd/nftl.h>
 #include <linux/mtd/compatmac.h>
 
 #define SECTORSIZE 512
 
-char nftlmountrev[]="$Revision: 1.25 $";
+char nftlmountrev[]="$Revision: 1.31 $";
 
 /* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the
  *	various device information of the NFTL partition and Bad Unit Table. Update
@@ -51,11 +52,16 @@
 	struct nftl_uci1 h1;
 	struct nftl_oob oob;
 	unsigned int block, boot_record_count = 0;
-	int retlen;
+	size_t retlen;
 	u8 buf[SECTORSIZE];
 	struct NFTLMediaHeader *mh = &nftl->MediaHdr;
 	unsigned int i;
 
+        /* Assume logical EraseSize == physical erasesize for starting the scan. 
+	   We'll sort it out later if we find a MediaHeader which says otherwise */
+	nftl->EraseSize = nftl->mtd->erasesize;
+        nftl->nb_blocks = nftl->mtd->size / nftl->EraseSize;
+
 	nftl->MediaUnit = BLOCK_NIL;
 	nftl->SpareMediaUnit = BLOCK_NIL;
 
@@ -107,7 +113,7 @@
 
 		/* Finally reread to check ECC */
 		if ((ret = MTD_READECC(nftl->mtd, block * nftl->EraseSize, SECTORSIZE,
-				&retlen, buf, (char *)&oob) < 0)) {
+				&retlen, buf, (char *)&oob, NAND_ECC_DISKONCHIP) < 0)) {
 			printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but ECC read failed (err %d)\n",
 			       block * nftl->EraseSize, nftl->mtd->index, ret);
 			continue;
@@ -122,7 +128,6 @@
 			continue;
 		}
 #endif
-			       
 		/* OK, we like it. */
 
 		if (boot_record_count) {
@@ -137,6 +142,10 @@
 			if (boot_record_count == 1)
 				nftl->SpareMediaUnit = block;
 
+			/* Mark this boot record (NFTL MediaHeader) block as reserved */
+			nftl->ReplUnitTable[block] = BLOCK_RESERVED;
+
+
 			boot_record_count++;
 			continue;
 		}
@@ -145,12 +154,18 @@
 		memcpy(mh, buf, sizeof(struct NFTLMediaHeader));
 
 		/* Do some sanity checks on it */
-		if (mh->UnitSizeFactor != 0xff) {
-			printk(KERN_NOTICE "Sorry, we don't support UnitSizeFactor "
-			       "of != 1 yet.\n");
+		if (mh->UnitSizeFactor == 0) {
+			printk(KERN_NOTICE "NFTL: UnitSizeFactor 0x00 detected. This violates the spec but we think we know what it means...\n");
+		} else if (mh->UnitSizeFactor < 0xfc) {
+			printk(KERN_NOTICE "Sorry, we don't support UnitSizeFactor 0x%02x\n",
+			       mh->UnitSizeFactor);
 			return -1;
+		} else if (mh->UnitSizeFactor != 0xff) {
+			printk(KERN_NOTICE "WARNING: Support for NFTL with UnitSizeFactor 0x%02x is experimental\n",
+			       mh->UnitSizeFactor);
+			nftl->EraseSize = nftl->mtd->erasesize << (0xff - mh->UnitSizeFactor);
+			nftl->nb_blocks = nftl->mtd->size / nftl->EraseSize;
 		}
-
 		nftl->nb_boot_blocks = le16_to_cpu(mh->FirstPhysicalEUN);
 		if ((nftl->nb_boot_blocks + 2) >= nftl->nb_blocks) {
 			printk(KERN_NOTICE "NFTL Media Header sanity check failed:\n");
@@ -168,20 +183,50 @@
 		}
 		
 		nftl->nr_sects  = nftl->numvunits * (nftl->EraseSize / SECTORSIZE);
-		
+
 		/* If we're not using the last sectors in the device for some reason,
 		   reduce nb_blocks accordingly so we forget they're there */
 		nftl->nb_blocks = le16_to_cpu(mh->NumEraseUnits) + le16_to_cpu(mh->FirstPhysicalEUN);
 
+		/* XXX: will be suppressed */
+		nftl->lastEUN = nftl->nb_blocks - 1;
+
+		/* memory alloc */
+		nftl->EUNtable = kmalloc(nftl->nb_blocks * sizeof(u16), GFP_KERNEL);
+		if (!nftl->EUNtable) {
+			printk(KERN_NOTICE "NFTL: allocation of EUNtable failed\n");
+			return -ENOMEM;
+		}
+
+		nftl->ReplUnitTable = kmalloc(nftl->nb_blocks * sizeof(u16), GFP_KERNEL);
+		if (!nftl->ReplUnitTable) {
+			kfree(nftl->EUNtable);
+			printk(KERN_NOTICE "NFTL: allocation of ReplUnitTable failed\n");
+			return -ENOMEM;
+		}
+		
+		/* mark the bios blocks (blocks before NFTL MediaHeader) as reserved */
+		for (i = 0; i < nftl->nb_boot_blocks; i++)
+			nftl->ReplUnitTable[i] = BLOCK_RESERVED;
+		/* mark all remaining blocks as potentially containing data */
+		for (; i < nftl->nb_blocks; i++) { 
+			nftl->ReplUnitTable[i] = BLOCK_NOTEXPLORED;
+		}
+
+		/* Mark this boot record (NFTL MediaHeader) block as reserved */
+		nftl->ReplUnitTable[block] = BLOCK_RESERVED;
+
 		/* read the Bad Erase Unit Table and modify ReplUnitTable[] accordingly */
 		for (i = 0; i < nftl->nb_blocks; i++) {
 			if ((i & (SECTORSIZE - 1)) == 0) {
 				/* read one sector for every SECTORSIZE of blocks */
 				if ((ret = MTD_READECC(nftl->mtd, block * nftl->EraseSize +
-						       i + SECTORSIZE, SECTORSIZE,
-						       &retlen, buf, (char *)&oob)) < 0) {
+						       i + SECTORSIZE, SECTORSIZE, &retlen, buf,
+						       (char *)&oob, NAND_ECC_DISKONCHIP)) < 0) {
 					printk(KERN_NOTICE "Read of bad sector table failed (err %d)\n",
 					       ret);
+					kfree(nftl->ReplUnitTable);
+					kfree(nftl->EUNtable);
 					return -1;
 				}
 			}
@@ -246,7 +291,7 @@
  */
 int NFTL_formatblock(struct NFTLrecord *nftl, int block)
 {
-	int retlen;
+	size_t retlen;
 	unsigned int nb_erases, erase_mark;
 	struct nftl_uci1 uci;
 	struct erase_info *instr = &nftl->instr;
@@ -428,7 +473,7 @@
 {
 	struct nftl_uci1 h1;
 	unsigned int erase_mark;
-	int retlen;
+	size_t retlen;
 
 	/* check erase mark. */
 	if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, 
@@ -486,7 +531,7 @@
 static int get_fold_mark(struct NFTLrecord *nftl, unsigned int block)
 {
 	struct nftl_uci2 uci;
-	int retlen;
+	size_t retlen;
 
 	if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + 2 * SECTORSIZE + 8,
 			8, &retlen, (char *)&uci) < 0)
@@ -503,44 +548,14 @@
 	int chain_length, do_format_chain;
 	struct nftl_uci0 h0;
 	struct nftl_uci1 h1;
-	int retlen;
-
-	/* XXX: will be suppressed */
-	s->lastEUN = s->nb_blocks - 1;
-
-	/* memory alloc */
-	s->EUNtable = kmalloc(s->nb_blocks * sizeof(u16), GFP_KERNEL);
-	s->ReplUnitTable = kmalloc(s->nb_blocks * sizeof(u16), GFP_KERNEL);
-	if (!s->EUNtable || !s->ReplUnitTable) {
-	fail:
-		if (s->EUNtable)
-			kfree(s->EUNtable);
-		if (s->ReplUnitTable)
-			kfree(s->ReplUnitTable);
-		return -1;
-	}
-
-	/* mark all blocks as potentially containing data */
-	for (i = 0; i < s->nb_blocks; i++) { 
-		s->ReplUnitTable[i] = BLOCK_NOTEXPLORED;
-	}
+	size_t retlen;
 
 	/* search for NFTL MediaHeader and Spare NFTL Media Header */
 	if (find_boot_record(s) < 0) {
 		printk("Could not find valid boot record\n");
-		goto fail;
+		return -1;
 	}
 
-	/* mark the bios blocks (blocks before NFTL MediaHeader) as reserved */
-	for (i = 0; i < s->nb_boot_blocks; i++)
-		s->ReplUnitTable[i] = BLOCK_RESERVED;
-
-	/* also mark the boot records (NFTL MediaHeader) blocks as reserved */
-	if (s->MediaUnit != BLOCK_NIL)
-		s->ReplUnitTable[s->MediaUnit] = BLOCK_RESERVED;
-	if (s->SpareMediaUnit != BLOCK_NIL)
-		s->ReplUnitTable[s->SpareMediaUnit] = BLOCK_RESERVED;
-
 	/* init the logical to physical table */
 	for (i = 0; i < s->nb_blocks; i++) {
 		s->EUNtable[i] = BLOCK_NIL;
@@ -725,7 +740,7 @@
 
 	/* second pass to format unreferenced blocks  and init free block count */
 	s->numfreeEUNs = 0;
-	s->LastFreeEUN = BLOCK_NIL;
+	s->LastFreeEUN = le16_to_cpu(s->MediaHdr.FirstPhysicalEUN);
 
 	for (block = 0; block < s->nb_blocks; block++) {
 		if (s->ReplUnitTable[block] == BLOCK_NOTEXPLORED) {
diff -urN linux-2.4.21-pre3/drivers/net/3c501.c linux-2.4.21-pre4/drivers/net/3c501.c
--- linux-2.4.21-pre3/drivers/net/3c501.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.21-pre4/drivers/net/3c501.c	Tue Jan 28 19:44:30 2003
@@ -35,6 +35,9 @@
     Cleaned up for 2.3.x because we broke SMP now. 
     		20000208 Alan Cox <alan@redhat.com>
     		
+    Fixed zero fill corner case 
+    		20030104 Alan Cox <alan@redhat.com>
+    		
 */
 
 
@@ -503,8 +506,15 @@
 
 	do
 	{
-		int gp_start = 0x800 - (ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN);
+		int len = skb->len;
+		int pad = 0;
+		int gp_start;
 		unsigned char *buf = skb->data;
+		
+		if(len < ETH_ZLEN)
+			pad = ETH_ZLEN - len;
+			
+		gp_start = 0x800 - ( len + pad );
 
 		lp->tx_pkt_start = gp_start;
     		lp->collisions = 0;
@@ -532,7 +542,12 @@
 		
 		outw(0x00, RX_BUF_CLR);		/* Set rx packet area to 0. */
 		outw(gp_start, GP_LOW);		/* aim - packet will be loaded into buffer start */
-		outsb(DATAPORT,buf,skb->len);	/* load buffer (usual thing each byte increments the pointer) */
+		outsb(DATAPORT,buf,len);	/* load buffer (usual thing each byte increments the pointer) */
+		if(pad)
+		{
+			while(pad--)		/* Zero fill buffer tail */
+				outb(0, DATAPORT);
+		}
 		outw(gp_start, GP_LOW);		/* the board reuses the same register */
 	
 		if(lp->loading != 2)
diff -urN linux-2.4.21-pre3/drivers/net/3c505.c linux-2.4.21-pre4/drivers/net/3c505.c
--- linux-2.4.21-pre3/drivers/net/3c505.c	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre4/drivers/net/3c505.c	Tue Jan 28 19:44:30 2003
@@ -1036,8 +1036,9 @@
 	adapter->current_dma.direction = 1;
 	adapter->current_dma.start_time = jiffies;
 
-	if ((unsigned long)(skb->data + nlen) >= MAX_DMA_ADDRESS) {
-		memcpy(adapter->dma_buffer, skb->data, nlen);
+	if ((unsigned long)(skb->data + nlen) >= MAX_DMA_ADDRESS || nlen != skb->len) {
+		memcpy(adapter->dma_buffer, skb->data, skb->len);
+		memset(adapter->dma_buffer+skb->len, 0, nlen-skb->len);
 		target = virt_to_bus(adapter->dma_buffer);
 	}
 	else {
diff -urN linux-2.4.21-pre3/drivers/net/3c507.c linux-2.4.21-pre4/drivers/net/3c507.c
--- linux-2.4.21-pre3/drivers/net/3c507.c	Mon Feb 25 11:37:58 2002
+++ linux-2.4.21-pre4/drivers/net/3c507.c	Tue Jan 28 19:44:30 2003
@@ -303,7 +303,7 @@
 static struct net_device_stats *el16_get_stats(struct net_device *dev);
 static void el16_tx_timeout (struct net_device *dev);
 
-static void hardware_send_packet(struct net_device *dev, void *buf, short length);
+static void hardware_send_packet(struct net_device *dev, void *buf, short length, short pad);
 static void init_82586_mem(struct net_device *dev);
 static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
 
@@ -505,7 +505,7 @@
 	/* Disable the 82586's input to the interrupt line. */
 	outb (0x80, ioaddr + MISC_CTRL);
 
-	hardware_send_packet (dev, buf, length);
+	hardware_send_packet (dev, buf, skb->len, length - skb->len);
 
 	dev->trans_start = jiffies;
 	/* Enable the 82586 interrupt input. */
@@ -758,12 +758,13 @@
 	return;
 }
 
-static void hardware_send_packet(struct net_device *dev, void *buf, short length)
+static void hardware_send_packet(struct net_device *dev, void *buf, short length, short pad)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
 	short ioaddr = dev->base_addr;
 	ushort tx_block = lp->tx_head;
 	unsigned long write_ptr = dev->mem_start + tx_block;
+	static char padding[ETH_ZLEN];
 
 	/* Set the write pointer to the Tx block, and put out the header. */
 	isa_writew(0x0000,write_ptr);			/* Tx status */
@@ -772,7 +773,7 @@
 	isa_writew(tx_block+8,write_ptr+=2);			/* Data Buffer offset. */
 
 	/* Output the data buffer descriptor. */
-	isa_writew(length | 0x8000,write_ptr+=2);		/* Byte count parameter. */
+	isa_writew((pad + length) | 0x8000,write_ptr+=2);		/* Byte count parameter. */
 	isa_writew(-1,write_ptr+=2);			/* No next data buffer. */
 	isa_writew(tx_block+22+SCB_BASE,write_ptr+=2);	/* Buffer follows the NoOp command. */
 	isa_writew(0x0000,write_ptr+=2);			/* Buffer address high bits (always zero). */
@@ -784,6 +785,8 @@
 
 	/* Output the packet at the write pointer. */
 	isa_memcpy_toio(write_ptr+2, buf, length);
+	if(pad)
+		isa_memcpy_toio(write_ptr+length+2, padding, pad);
 
 	/* Set the old command link pointing to this send packet. */
 	isa_writew(tx_block,dev->mem_start + lp->tx_cmd_link);
diff -urN linux-2.4.21-pre3/drivers/net/3c523.c linux-2.4.21-pre4/drivers/net/3c523.c
--- linux-2.4.21-pre3/drivers/net/3c523.c	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/drivers/net/3c523.c	Tue Jan 28 19:44:30 2003
@@ -1122,8 +1122,11 @@
 
 	netif_stop_queue(dev);
 
-	memcpy((char *) p->xmit_cbuffs[p->xmit_count], (char *) (skb->data), skb->len);
 	len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
+	
+	if(len != skb->len)
+		memset((char *) p->xmit_cbuffs[p->xmit)count], 0, ETH_ZLEN);
+	memcpy((char *) p->xmit_cbuffs[p->xmit_count], (char *) (skb->data), skb->len);
 
 #if (NUM_XMIT_BUFFS == 1)
 #ifdef NO_NOPCOMMANDS
diff -urN linux-2.4.21-pre3/drivers/net/3c59x.c linux-2.4.21-pre4/drivers/net/3c59x.c
--- linux-2.4.21-pre3/drivers/net/3c59x.c	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/drivers/net/3c59x.c	Tue Jan 28 19:44:30 2003
@@ -441,6 +441,7 @@
 
 	CH_3CCFEM656_1,
 	CH_3C450,
+	CH_3C920,
 };
 
 
@@ -532,6 +533,8 @@
 									MAX_COLLISION_RESET|HAS_HWCKSM, 128, },
 	{"3c450 HomePNA Tornado",						/* AKPM: from Don's 0.99Q */
 	 PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, },
+	{"3c920 Tornado",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, },
 	{0,}, /* 0 terminated list. */
 };
 
@@ -575,6 +578,7 @@
 
 	{ 0x10B7, 0x6564, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFEM656_1 },
 	{ 0x10B7, 0x4500, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C450 },
+	{ 0x10B7, 0x9201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C920 },
 	{0,}						/* 0 terminated list. */
 };
 MODULE_DEVICE_TABLE(pci, vortex_pci_tbl);
@@ -975,7 +979,7 @@
 	int i, step;
 	struct net_device *dev;
 	static int printed_version;
-	int retval, print_info;
+	int retval;
 	struct vortex_chip_info * const vci = &vortex_info_tbl[chip_idx];
 	char *print_name;
 
@@ -1017,10 +1021,7 @@
 			vp->enable_wol = 1;
 	}
 
-	print_info = (vortex_debug > 1);
-	if (print_info)
-		printk (KERN_INFO "See Documentation/networking/vortex.txt\n");
-
+	printk (KERN_INFO "See Documentation/networking/vortex.txt\n");
 	printk(KERN_INFO "%s: 3Com %s %s at 0x%lx. Vers " DRV_VERSION "\n",
 	       print_name,
 	       pdev ? "PCI" : "EISA",
@@ -1146,20 +1147,16 @@
 		printk(" ***INVALID CHECKSUM %4.4x*** ", checksum);
 	for (i = 0; i < 3; i++)
 		((u16 *)dev->dev_addr)[i] = htons(eeprom[i + 10]);
-	if (print_info) {
-		for (i = 0; i < 6; i++)
-			printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]);
-	}
+	for (i = 0; i < 6; i++)
+		printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]);
 	EL3WINDOW(2);
 	for (i = 0; i < 6; i++)
 		outb(dev->dev_addr[i], ioaddr + i);
 
 #ifdef __sparc__
-	if (print_info)
-		printk(", IRQ %s\n", __irq_itoa(dev->irq));
+	printk(", IRQ %s\n", __irq_itoa(dev->irq));
 #else
-	if (print_info)
-		printk(", IRQ %d\n", dev->irq);
+	printk(", IRQ %d\n", dev->irq);
 	/* Tell them about an invalid IRQ. */
 	if (dev->irq <= 0 || dev->irq >= NR_IRQS)
 		printk(KERN_WARNING " *** Warning: IRQ %d is unlikely to work! ***\n",
@@ -1168,12 +1165,9 @@
 
 	EL3WINDOW(4);
 	step = (inb(ioaddr + Wn4_NetDiag) & 0x1e) >> 1;
-	if (print_info) {
-		printk(KERN_INFO "  product code %02x%02x rev %02x.%d date %02d-"
-			"%02d-%02d\n", eeprom[6]&0xff, eeprom[6]>>8, eeprom[0x14],
-			step, (eeprom[4]>>5) & 15, eeprom[4] & 31, eeprom[4]>>9);
-	}
-
+	printk(KERN_INFO "  product code %02x%02x rev %02x.%d date %02d-"
+		"%02d-%02d\n", eeprom[6]&0xff, eeprom[6]>>8, eeprom[0x14],
+		step, (eeprom[4]>>5) & 15, eeprom[4] & 31, eeprom[4]>>9);
 
 	if (pdev && vci->drv_flags & HAS_CB_FNS) {
 		unsigned long fn_st_addr;			/* Cardbus function status space */
@@ -1186,10 +1180,8 @@
 			if (!vp->cb_fn_base)
 				goto free_ring;
 		}
-		if (print_info) {
-			printk(KERN_INFO "%s: CardBus functions mapped %8.8lx->%p\n",
-				print_name, fn_st_addr, vp->cb_fn_base);
-		}
+		printk(KERN_INFO "%s: CardBus functions mapped %8.8lx->%p\n",
+			print_name, fn_st_addr, vp->cb_fn_base);
 		EL3WINDOW(2);
 
 		n = inw(ioaddr + Wn2_ResetOptions) & ~0x4010;
@@ -1207,8 +1199,7 @@
 
 	if (vp->info1 & 0x8000) {
 		vp->full_duplex = 1;
-		if (print_info)
-			printk(KERN_INFO "Full duplex capable\n");
+		printk(KERN_INFO "Full duplex capable\n");
 	}
 
 	{
@@ -1219,17 +1210,16 @@
 		if ((vp->available_media & 0xff) == 0)		/* Broken 3c916 */
 			vp->available_media = 0x40;
 		config = inl(ioaddr + Wn3_Config);
-		if (print_info) {
-			printk(KERN_DEBUG "  Internal config register is %4.4x, "
-				   "transceivers %#x.\n", config, inw(ioaddr + Wn3_Options));
-			printk(KERN_INFO "  %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n",
-				   8 << RAM_SIZE(config),
-				   RAM_WIDTH(config) ? "word" : "byte",
-				   ram_split[RAM_SPLIT(config)],
-				   AUTOSELECT(config) ? "autoselect/" : "",
-				   XCVR(config) > XCVR_ExtMII ? "<invalid transceiver>" :
-				   media_tbl[XCVR(config)].name);
-		}
+		printk(KERN_DEBUG "  Internal config register is %4.4x, "
+				"transceivers %#x.\n", config,
+				inw(ioaddr + Wn3_Options));
+		printk(KERN_INFO "  %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n",
+			   8 << RAM_SIZE(config),
+			   RAM_WIDTH(config) ? "word" : "byte",
+			   ram_split[RAM_SPLIT(config)],
+			   AUTOSELECT(config) ? "autoselect/" : "",
+			   XCVR(config) > XCVR_ExtMII ? "<invalid transceiver>" :
+			   media_tbl[XCVR(config)].name);
 		vp->default_media = XCVR(config);
 		if (vp->default_media == XCVR_NWAY)
 			vp->has_nway = 1;
@@ -1266,10 +1256,9 @@
 			mii_status = mdio_read(dev, phyx, 1);
 			if (mii_status  &&  mii_status != 0xffff) {
 				vp->phys[phy_idx++] = phyx;
-				if (print_info) {
-					printk(KERN_INFO "  MII transceiver found at address %d,"
-						" status %4x.\n", phyx, mii_status);
-				}
+				printk(KERN_INFO "  MII transceiver found at "
+					"address %d, status %4x.\n",
+					phyx, mii_status);
 				if ((mii_status & 0x0040) == 0)
 					mii_preamble_required++;
 			}
@@ -1290,10 +1279,9 @@
 
 	if (vp->capabilities & CapBusMaster) {
 		vp->full_bus_master_tx = 1;
-		if (print_info) {
-			printk(KERN_INFO "  Enabling bus-master transmits and %s receives.\n",
+		printk(KERN_INFO "  Enabling bus-master transmits and %s "
+				"receives.\n",
 			(vp->info2 & 1) ? "early" : "whole-frame" );
-		}
 		vp->full_bus_master_rx = (vp->info2 & 1) ? 1 : 2;
 		vp->bus_master = 0;		/* AKPM: vortex only */
 	}
@@ -1312,12 +1300,10 @@
 		dev->hard_start_xmit = vortex_start_xmit;
 	}
 
-	if (print_info) {
-		printk(KERN_INFO "%s: scatter/gather %sabled. h/w checksums %sabled\n",
-				print_name,
-				(dev->features & NETIF_F_SG) ? "en":"dis",
-				(dev->features & NETIF_F_IP_CSUM) ? "en":"dis");
-	}
+	printk(KERN_INFO "%s: scatter/gather %sabled. h/w checksums %sabled\n",
+			print_name,
+			(dev->features & NETIF_F_SG) ? "en":"dis",
+			(dev->features & NETIF_F_IP_CSUM) ? "en":"dis");
 
 	dev->stop = vortex_close;
 	dev->get_stats = vortex_get_stats;
diff -urN linux-2.4.21-pre3/drivers/net/7990.c linux-2.4.21-pre4/drivers/net/7990.c
--- linux-2.4.21-pre3/drivers/net/7990.c	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre4/drivers/net/7990.c	Tue Jan 28 19:44:30 2003
@@ -532,6 +532,8 @@
         ib->btx_ring [entry].length = (-len) | 0xf000;
         ib->btx_ring [entry].misc = 0;
     
+    	if(skb->len < ETH_ZLEN)
+    		memset((char *)&ib->tx_buf[entry][0], 0, ETH_ZLEN);
         memcpy ((char *)&ib->tx_buf [entry][0], skb->data, skblen);
     
         /* Now, give the packet to the lance */
diff -urN linux-2.4.21-pre3/drivers/net/8139too.c linux-2.4.21-pre4/drivers/net/8139too.c
--- linux-2.4.21-pre3/drivers/net/8139too.c	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/drivers/net/8139too.c	Tue Jan 28 19:44:30 2003
@@ -1687,6 +1687,8 @@
 	entry = tp->cur_tx % NUM_TX_DESC;
 
 	if (likely(len < TX_BUF_SIZE)) {
+		if(len < ETH_ZLEN)
+			memset(tp->tx_buf[entry], 0, ETH_ZLEN);
 		skb_copy_and_csum_dev(skb, tp->tx_buf[entry]);
 		dev_kfree_skb(skb);
 	} else {
diff -urN linux-2.4.21-pre3/drivers/net/8390.c linux-2.4.21-pre4/drivers/net/8390.c
--- linux-2.4.21-pre3/drivers/net/8390.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.21-pre4/drivers/net/8390.c	Tue Jan 28 19:44:30 2003
@@ -271,6 +271,7 @@
 	struct ei_device *ei_local = (struct ei_device *) dev->priv;
 	int length, send_length, output_page;
 	unsigned long flags;
+	char scratch[ETH_ZLEN];
 
 	length = skb->len;
 
@@ -341,8 +342,16 @@
 	 * isn't already sending. If it is busy, the interrupt handler will
 	 * trigger the send later, upon receiving a Tx done interrupt.
 	 */
-
-	ei_block_output(dev, length, skb->data, output_page);
+	 
+	if(length == send_length)
+		ei_block_output(dev, length, skb->data, output_page);
+	else
+	{
+		memset(scratch, 0, ETH_ZLEN);
+		memcpy(scratch, skb->data, skb->len);
+		ei_block_output(dev, ETH_ZLEN, scratch, output_page);
+	}
+		
 	if (! ei_local->txing) 
 	{
 		ei_local->txing = 1;
@@ -374,7 +383,14 @@
 	 * reasonable hardware if you only use one Tx buffer.
 	 */
 
-	ei_block_output(dev, length, skb->data, ei_local->tx_start_page);
+	if(length == send_length)
+		ei_block_output(dev, length, skb->data, ei_local->tx_start_page);
+	else
+	{
+		memset(scratch, 0, ETH_ZLEN);
+		memcpy(scratch, skb->data, skb->len);
+		ei_block_output(dev, ETH_ZLEN, scratch, ei_local->tx_start_page);
+	}
 	ei_local->txing = 1;
 	NS8390_trigger_send(dev, send_length, ei_local->tx_start_page);
 	dev->trans_start = jiffies;
diff -urN linux-2.4.21-pre3/drivers/net/Makefile linux-2.4.21-pre4/drivers/net/Makefile
--- linux-2.4.21-pre3/drivers/net/Makefile	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/drivers/net/Makefile	Tue Jan 28 19:44:30 2003
@@ -119,7 +119,7 @@
 obj-$(CONFIG_SEEQ8005) += seeq8005.o
 obj-$(CONFIG_ETHERTAP) += ethertap.o
 obj-$(CONFIG_NET_SB1000) += sb1000.o
-obj-$(CONFIG_MAC8390) += daynaport.o 8390.o
+obj-$(CONFIG_MAC8390) += mac8390.o 8390.o
 obj-$(CONFIG_APNE) += apne.o 8390.o
 obj-$(CONFIG_PCMCIA_PCNET) += 8390.o
 obj-$(CONFIG_SHAPER) += shaper.o
diff -urN linux-2.4.21-pre3/drivers/net/at1700.c linux-2.4.21-pre4/drivers/net/at1700.c
--- linux-2.4.21-pre3/drivers/net/at1700.c	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/drivers/net/at1700.c	Tue Jan 28 19:44:30 2003
@@ -576,7 +576,9 @@
 	struct net_local *lp = (struct net_local *) dev->priv;
 	int ioaddr = dev->base_addr;
 	short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+	short len = skb->len;
 	unsigned char *buf = skb->data;
+	static u8 pad[ETH_ZLEN];
 
 	netif_stop_queue (dev);
 
@@ -588,7 +590,17 @@
 	lp->tx_queue_ready = 0;
 	{
 		outw (length, ioaddr + DATAPORT);
-		outsw (ioaddr + DATAPORT, buf, (length + 1) >> 1);
+		/* Packet data */
+		outsw (ioaddr + DATAPORT, buf, len >> 1);
+		/* Check for dribble byte */
+		if(len & 1)
+		{
+			outw(skb->data[skb->len-1], ioaddr + DATAPORT);
+			len++;
+		}
+		/* Check for packet padding */
+		if(length != skb->len)
+			outsw(ioaddr + DATAPORT, pad, (length - len + 1) >> 1);
 
 		lp->tx_queue++;
 		lp->tx_queue_len += length + 2;
diff -urN linux-2.4.21-pre3/drivers/net/atp.c linux-2.4.21-pre4/drivers/net/atp.c
--- linux-2.4.21-pre3/drivers/net/atp.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.21-pre4/drivers/net/atp.c	Tue Jan 28 19:44:30 2003
@@ -203,7 +203,7 @@
 static unsigned short eeprom_op(long ioaddr, unsigned int cmd);
 static int net_open(struct net_device *dev);
 static void hardware_init(struct net_device *dev);
-static void write_packet(long ioaddr, int length, unsigned char *packet, int mode);
+static void write_packet(long ioaddr, int length, unsigned char *packet, int pad, int mode);
 static void trigger_send(long ioaddr, int length);
 static int	atp_send_packet(struct sk_buff *skb, struct net_device *dev);
 static void atp_interrupt(int irq, void *dev_id, struct pt_regs *regs);
@@ -500,15 +500,23 @@
 	write_reg(ioaddr, CMR1, CMR1_Xmit);
 }
 
-static void write_packet(long ioaddr, int length, unsigned char *packet, int data_mode)
+static void write_packet(long ioaddr, int length, unsigned char *packet, int pad_len, int data_mode)
 {
-    length = (length + 1) & ~1;		/* Round up to word length. */
+    if(length & 1)
+    {
+    	length++;
+    	pad_len++;
+    }
+
     outb(EOC+MAR, ioaddr + PAR_DATA);
     if ((data_mode & 1) == 0) {
 		/* Write the packet out, starting with the write addr. */
 		outb(WrAddr+MAR, ioaddr + PAR_DATA);
 		do {
 			write_byte_mode0(ioaddr, *packet++);
+		} while (--length > pad_len) ;
+		do {
+			write_byte_mode0(ioaddr, 0);
 		} while (--length > 0) ;
     } else {
 		/* Write the packet out in slow mode. */
@@ -522,8 +530,10 @@
 		outbyte >>= 4;
 		outb(outbyte & 0x0f, ioaddr + PAR_DATA);
 		outb(Ctrl_HNibWrite + Ctrl_IRQEN, ioaddr + PAR_CONTROL);
-		while (--length > 0)
+		while (--length > pad_len)
 			write_byte_mode1(ioaddr, *packet++);
+		while (--length > 0)
+			write_byte_mode1(ioaddr, 0);
     }
     /* Terminate the Tx frame.  End of write: ECB. */
     outb(0xff, ioaddr + PAR_DATA);
@@ -565,7 +575,7 @@
 	write_reg_high(ioaddr, IMR, 0);
 	spin_unlock_irqrestore(&lp->lock, flags);
 
-	write_packet(ioaddr, length, skb->data, dev->if_port);
+	write_packet(ioaddr, length, skb->data, length-skb->len, dev->if_port);
 
 	lp->pac_cnt_in_tx_buf++;
 	if (lp->tx_unit_busy == 0) {
diff -urN linux-2.4.21-pre3/drivers/net/daynaport.c linux-2.4.21-pre4/drivers/net/daynaport.c
--- linux-2.4.21-pre3/drivers/net/daynaport.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.21-pre4/drivers/net/daynaport.c	Wed Dec 31 16:00:00 1969
@@ -1,922 +0,0 @@
-/* daynaport.c: A Macintosh 8390 based ethernet driver for linux. */
-/*
-	Derived from code:
-	
-	Written 1993-94 by Donald Becker.
-
-	Copyright 1993 United States Government as represented by the
-	Director, National Security Agency.
-
-	This software may be used and distributed according to the terms
-	of the GNU General Public License, incorporated herein by reference.
-
-	    TODO:
-
-	    The block output routines may be wrong for non Dayna
-	    cards
-
-		Fix this driver so that it will attempt to use the info
-		(i.e. iobase, iosize) given to it by the new and improved
-		NuBus code.
-
-		Despite its misleading filename, this driver is not Dayna-specific
-		anymore. */
-/* Cabletron E6100 card support added by Tony Mantler (eek@escape.ca) April 1999 */
-
-static const char *version =
-	"daynaport.c: v0.02 1999-05-17 Alan Cox (Alan.Cox@linux.org) and others\n";
-static int version_printed;
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/nubus.h>
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/hwtest.h>
-#include <asm/macints.h>
-#include <linux/delay.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include "8390.h"
-
-static int ns8390_probe1(struct net_device *dev, int word16, char *name, int id,
-				  int prom, struct nubus_dev *ndev);
-
-static int ns8390_open(struct net_device *dev);
-static void ns8390_no_reset(struct net_device *dev);
-static int ns8390_close_card(struct net_device *dev);
-
-/* Interlan */
-static void interlan_reset(struct net_device *dev);
-
-/* Dayna */
-static void dayna_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
-						int ring_page);
-static void dayna_block_input(struct net_device *dev, int count,
-						  struct sk_buff *skb, int ring_offset);
-static void dayna_block_output(struct net_device *dev, int count,
-						   const unsigned char *buf, const int start_page);
-
-/* Sane (32-bit chunk memory read/write) */
-static void sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
-						int ring_page);
-static void sane_block_input(struct net_device *dev, int count,
-						  struct sk_buff *skb, int ring_offset);
-static void sane_block_output(struct net_device *dev, int count,
-						   const unsigned char *buf, const int start_page);
-
-/* Slow Sane (16-bit chunk memory read/write) */
-static void slow_sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
-						int ring_page);
-static void slow_sane_block_input(struct net_device *dev, int count,
-						  struct sk_buff *skb, int ring_offset);
-static void slow_sane_block_output(struct net_device *dev, int count,
-						   const unsigned char *buf, const int start_page);
-
-
-#define WD_START_PG	0x00	/* First page of TX buffer */
-#define WD03_STOP_PG	0x20	/* Last page +1 of RX ring */
-#define WD13_STOP_PG	0x40	/* Last page +1 of RX ring */
-
-#define CABLETRON_RX_START_PG          0x00    /* First page of RX buffer */
-#define CABLETRON_RX_STOP_PG           0x30    /* Last page +1 of RX ring */
-#define CABLETRON_TX_START_PG          CABLETRON_RX_STOP_PG  /* First page of TX buffer */
-
-
-#define DAYNA_MAC_BASE		0xf0007
-#define DAYNA_8390_BASE		0x80000 /* 3 */
-#define DAYNA_8390_MEM		0x00000
-#define DAYNA_MEMSIZE		0x04000	/* First word of each long ! */
-
-#define APPLE_8390_BASE		0xE0000
-#define APPLE_8390_MEM		0xD0000
-#define APPLE_MEMSIZE		8192    /* FIXME: need to dynamically check */
-
-#define KINETICS_MAC_BASE	0xf0004 /* first byte of each long */
-#define KINETICS_8390_BASE	0x80000
-#define KINETICS_8390_MEM	0x00000 /* first word of each long */
-#define KINETICS_MEMSIZE	8192    /* FIXME: need to dynamically check */
-/*#define KINETICS_MEMSIZE	(0x10000/2) * CSA: on the board I have, at least */
-
-#define CABLETRON_8390_BASE		0x90000	
-#define CABLETRON_8390_MEM		0x00000
-
-static int test_8390(volatile char *ptr, int scale)
-{
-	int regd;
-	int v;
-	
-	if(hwreg_present(&ptr[0x00])==0)
-		return -EIO;
-	if(hwreg_present(&ptr[0x0D<<scale])==0)
-		return -EIO;
-	if(hwreg_present(&ptr[0x0D<<scale])==0)
-		return -EIO;
-	ptr[0x00]=E8390_NODMA+E8390_PAGE1+E8390_STOP;
-	regd=ptr[0x0D<<scale];
-	ptr[0x0D<<scale]=0xFF;
-	ptr[0x00]=E8390_NODMA+E8390_PAGE0;
-	v=ptr[0x0D<<scale];
-	if(ptr[0x0D<<scale]!=0)
-	{
-		ptr[0x0D<<scale]=regd;
-		return -ENODEV;
-	}
-/*	printk("NS8390 found at %p scaled %d\n", ptr,scale);*/
-	return 0;
-}
-/*
- *    Identify the species of NS8390 card/driver we need
- */
-
-enum mac8390_type {
-	NS8390_DAYNA,
-	NS8390_INTERLAN,
-	NS8390_KINETICS,
-	NS8390_APPLE,
-	NS8390_FARALLON,
-	NS8390_ASANTE,
-	NS8390_CABLETRON
-};
-
-static int __init ns8390_ident(struct nubus_dev* ndev)
-{
-	/* This really needs to be tested and tested hard.  */
-		
-	/* Summary of what we know so far --
-	 * SW: 0x0104 -- asante,    16 bit, back4_offsets
-	 * SW: 0x010b -- daynaport, 16 bit, fwrd4_offsets
-	 * SW: 0x010c -- farallon,  16 bit, back4_offsets, no long word access
-	 * SW: 0x011a -- focus,     [no details yet]
-	 * SW: ?????? -- interlan,  16 bit, back4_offsets, funny reset
-	 * SW: ?????? -- kinetics,   8 bit, back4_offsets
-	 * -- so i've this hypothesis going that says DrSW&1 says whether the
-	 *    map is forward or backwards -- and maybe DrSW&256 says what the
-	 *    register spacing is -- for all cards that report a DrSW in some
-	 *    range.
-	 *    This would allow the "apple compatible" driver to drive many
-	 *    seemingly different types of cards.  More DrSW info is needed
-	 *    to investigate this properly. [CSA, 21-May-1999]
-	 */
-	/* Dayna ex Kinetics board */
-	if(ndev->dr_sw == NUBUS_DRSW_DAYNA)
-		return NS8390_DAYNA;
-	if(ndev->dr_sw == NUBUS_DRSW_ASANTE)
-		return NS8390_ASANTE;
-	if(ndev->dr_sw == NUBUS_DRSW_FARALLON) /* farallon or sonic systems */
-		return NS8390_FARALLON;
-	if(ndev->dr_sw == NUBUS_DRSW_KINETICS)
-		return NS8390_KINETICS;
-	/* My ATI Engineering card with this combination crashes the */
-	/* driver trying to xmit packets. Best not touch it for now. */
-	/*     - 1999-05-20 (funaho@jurai.org)                       */
-	if(ndev->dr_sw == NUBUS_DRSW_FOCUS)
-		return -1;
-
-	/* Check the HW on this one, because it shares the same DrSW as
-	   the on-board SONIC chips */
-	if(ndev->dr_hw == NUBUS_DRHW_CABLETRON)
-		return NS8390_CABLETRON;
-	/* does anyone have one of these? */
-	if(ndev->dr_hw == NUBUS_DRHW_INTERLAN)
-		return NS8390_INTERLAN;
-
-	/* FIXME: what do genuine Apple boards look like? */
-	return -1;
-}
-
-/*
- *	Memory probe for 8390 cards
- */
- 
-static int __init apple_8390_mem_probe(volatile unsigned short *p)
-{
-	int i, j;
-	/*
-	 *	Algorithm.
-	 *	1.	Check each block size of memory doesn't fault
-	 *	2.	Write a value to it
-	 *	3.	Check all previous blocks are unaffected
-	 */
-	
-	for(i=0;i<2;i++)
-	{
-		volatile unsigned short *m=p+4096*i;
-		/* Unwriteable - we have a fully decoded card and the
-		   RAM end located */
-		   
-		if(hwreg_present(m)==0)
-			return 8192*i;
-			
-		*m=0xA5A0|i;
-		
-		for(j=0;j<i;j++)
-		{
-			/* Partial decode and wrap ? */
-			if(p[4096*j]!=(0xA5A0|j))
-			{
-				/* This is the first misdecode, so it had
-				   one less page than we tried */
-				return 8192*i;
-			}
- 			j++;
- 		}
- 		/* Ok it still decodes.. move on 8K */
- 	}
- 	/* 
- 	 *	We don't look past 16K. That should cover most cards
- 	 *	and above 16K there isnt really any gain.
- 	 */
- 	return 16384;
- }
- 		
-/*
- *    Probe for 8390 cards.  
- *    The ns8390_probe1() routine initializes the card and fills the
- *    station address field.
- *
- *    The NuBus interface has changed!  We now scan for these somewhat
- *    like how the PCI and Zorro drivers do.  It's not clear whether
- *    this is actually better, but it makes things more consistent.
- *
- *    dev->mem_start points
- *    at the memory ring, dev->mem_end gives the end of it.
- */
-
-int __init mac8390_probe(struct net_device *dev)
-{
-	static int slots;
-	volatile unsigned short *i;
-	volatile unsigned char *p;
-	int plen;
-	int id;
-	static struct nubus_dev* ndev;
-
-	/* Find the first card that hasn't already been seen */
-	while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK,
-								   NUBUS_TYPE_ETHERNET, ndev)) != NULL) {
-		/* Have we seen it already? */
-		if (slots & (1<<ndev->board->slot))
-			continue;
-		slots |= 1<<ndev->board->slot;
-
-		/* Is it one of ours? */
-		if ((id = ns8390_ident(ndev)) != -1)
-			break;
-	}
-
-	/* Hm.  No more cards, then */
-	if (ndev == NULL)
-		return -ENODEV;
-
-	dev = init_etherdev(dev, 0);
-	if (!dev)
-		return -ENOMEM;
-	SET_MODULE_OWNER(dev);
-
-	if (!version_printed) {
-		printk(KERN_INFO "%s", version);
-		version_printed = 1;
-	}
-
-	/*
-	 *	Dayna specific init
-	 */
-	if(id==NS8390_DAYNA)
-	{
-		dev->base_addr = (int)(ndev->board->slot_addr+DAYNA_8390_BASE);
-		dev->mem_start = (int)(ndev->board->slot_addr+DAYNA_8390_MEM);
-		dev->mem_end = dev->mem_start+DAYNA_MEMSIZE; /* 8K it seems */
-	
-		printk(KERN_INFO "%s: daynaport. testing board: ", dev->name);
-			
-		printk("memory - ");	
-			
-		i = (void *)dev->mem_start;
-		memset((void *)i,0xAA, DAYNA_MEMSIZE);
-		while(i<(volatile unsigned short *)dev->mem_end)
-		{
-			if(*i!=0xAAAA)
-				goto membad;
-			*i=0x5678; /* make sure we catch byte smearing */
-			if(*i!=0x5678)
-				goto membad;
-			i+=2;	/* Skip a word */
-		}
-			
-		printk("controller - ");
-			
-		p=(void *)dev->base_addr;
-		plen=0;
-			
-		while(plen<0x3FF00)
-		{
-			if(test_8390(p,0)==0)
-				break;
-			if(test_8390(p,1)==0)
-				break;
-			if(test_8390(p,2)==0)
-				break;
-			if(test_8390(p,3)==0)
-				break;
-			plen++;
-			p++;
-		}
-		if(plen==0x3FF00)
-			goto membad;
-		printk("OK\n");
-		dev->irq = SLOT2IRQ(ndev->board->slot);
-		if(ns8390_probe1(dev, 0, "dayna", id, -1, ndev)==0)
-			return 0;
-	}
-	/* Cabletron */
-	if (id==NS8390_CABLETRON) {
-		int memsize = 16<<10; /* fix this */
-		  
-		dev->base_addr=(int)(ndev->board->slot_addr+CABLETRON_8390_BASE);
-		dev->mem_start=(int)(ndev->board->slot_addr+CABLETRON_8390_MEM);
-		dev->mem_end=dev->mem_start+memsize;
-		dev->irq = SLOT2IRQ(ndev->board->slot);
-		  
-		/* The base address is unreadable if 0x00 has been written to the command register */
-		/* Reset the chip by writing E8390_NODMA+E8390_PAGE0+E8390_STOP just to be sure */
-		i = (void *)dev->base_addr;
-		*i = 0x21;
-		  
-		printk(KERN_INFO "%s: cabletron: testing board: ", dev->name);
-		printk("%dK memory - ", memsize>>10);		
-		i=(void *)dev->mem_start;
-		while(i<(volatile unsigned short *)(dev->mem_start+memsize))
-		{
-			*i=0xAAAA;
-			if(*i!=0xAAAA)
-				goto membad;
-			*i=0x5555;
-			if(*i!=0x5555)
-				goto membad;
-			i+=2;	/* Skip a word */
-		}
-		printk("OK\n");
-		  
-		if(ns8390_probe1(dev, 1, "cabletron", id, -1, ndev)==0)
-			return 0;
-	}
-	/* Apple, Farallon, Asante */
-	if(id==NS8390_APPLE || id==NS8390_FARALLON || id==NS8390_ASANTE)
-	{
-		int memsize;
-			
-		dev->base_addr=(int)(ndev->board->slot_addr+APPLE_8390_BASE);
-		dev->mem_start=(int)(ndev->board->slot_addr+APPLE_8390_MEM);
-			
-		memsize = apple_8390_mem_probe((void *)dev->mem_start);
-			
-		dev->mem_end=dev->mem_start+memsize;
-		dev->irq = SLOT2IRQ(ndev->board->slot);
-			
-		switch(id)
-		{
-		case NS8390_FARALLON:
-			printk(KERN_INFO "%s: farallon: testing board: ", dev->name);
-			break;
-		case NS8390_ASANTE:
-			printk(KERN_INFO "%s: asante: testing board: ", dev->name);
-			break;
-		case NS8390_APPLE:
-		default:
-			printk(KERN_INFO "%s: apple/clone: testing board: ", dev->name);
-			break;
-		}
-			
-		printk("%dK memory - ", memsize>>10);		
-			
-		i=(void *)dev->mem_start;
-		memset((void *)i,0xAA, memsize);
-		while(i<(volatile unsigned short *)dev->mem_end)
-		{
-			if(*i!=0xAAAA)
-				goto membad;
-			*i=0x5555;
-			if(*i!=0x5555)
-				goto membad;
-			i+=2;	/* Skip a word */
-		}
-		printk("OK\n");
-			
-		switch (id)
-		{
-		case NS8390_FARALLON:
-			if(ns8390_probe1(dev, 1, "farallon", id, -1, ndev)==0)
-				return 0;
-			break;
-		case NS8390_ASANTE:
-			if(ns8390_probe1(dev, 1, "asante", id, -1, ndev)==0)
-				return 0;
-			break;
-		case NS8390_APPLE:
-		default:
-			if(ns8390_probe1(dev, 1, "apple/clone", id, -1, ndev)==0)
-				return 0;
-			break;
-		}
-	}
-	/* Interlan */
-	if(id==NS8390_INTERLAN)
-	{
-		/* As apple and asante */
-		dev->base_addr=(int)(ndev->board->slot_addr+APPLE_8390_BASE);
-		dev->mem_start=(int)(ndev->board->slot_addr+APPLE_8390_MEM);
-		dev->mem_end=dev->mem_start+APPLE_MEMSIZE; /* 8K it seems */
-		dev->irq = SLOT2IRQ(ndev->board->slot);
-		if(ns8390_probe1(dev, 1, "interlan", id, -1, ndev)==0)
-			return 0;
-	}
-	/* Kinetics (Shiva Etherport) */
-	if(id==NS8390_KINETICS)
-	{
-		dev->base_addr=(int)(ndev->board->slot_addr+KINETICS_8390_BASE);
-		dev->mem_start=(int)(ndev->board->slot_addr+KINETICS_8390_MEM);
-		dev->mem_end=dev->mem_start+KINETICS_MEMSIZE; /* 8K it seems */
-		dev->irq = SLOT2IRQ(ndev->board->slot);
-		if(ns8390_probe1(dev, 0, "kinetics", id, -1, ndev)==0)
-			return 0;
-	}
-
-	/* We should hopefully not get here */
-	printk(KERN_ERR "Probe unsuccessful.\n");
-	return -ENODEV;
-
- membad:
-	printk(KERN_ERR "failed at %p in %p - %p.\n", i,
-		   (void *)dev->mem_start, (void *)dev->mem_end);
-	return -ENODEV;
-}
-
-static int __init mac8390_ethernet_addr(struct nubus_dev* ndev, unsigned char addr[6])
-{
-	struct nubus_dir dir;
-	struct nubus_dirent ent;
-
-	/* Get the functional resource for this device */
-	if (nubus_get_func_dir(ndev, &dir) == -1)
-		return -1;
-	if (nubus_find_rsrc(&dir, NUBUS_RESID_MAC_ADDRESS, &ent) == -1)
-		return -1;
-	
-	nubus_get_rsrc_mem(addr, &ent, 6);
-	return 0;
-}
-
-static int __init ns8390_probe1(struct net_device *dev, int word16, char *model_name,
-			 	int type, int promoff, struct nubus_dev *ndev)
-{
-	static u32 fwrd4_offsets[16]={
-		0,      4,      8,      12,
-		16,     20,     24,     28,
-		32,     36,     40,     44,
-		48,     52,     56,     60
-	};
-	static u32 back4_offsets[16]={
-		60,     56,     52,     48,
-		44,     40,     36,     32,
-		28,     24,     20,     16,
-		12,     8,      4,      0
-	};
-	static u32 fwrd2_offsets[16]={
-		0,      2,      4,      6,
-		8,     10,     12,     14,
-		16,    18,     20,     22,
-		24,    26,     28,     30
-	};
-
-	unsigned char *prom = (unsigned char*) ndev->board->slot_addr + promoff;
-
-	/* Allocate dev->priv and fill in 8390 specific dev fields. */
-	if (ethdev_init(dev)) 
-	{	
-		printk ("%s: unable to get memory for dev->priv.\n", dev->name);
-		return -ENOMEM;
-	}
-
-	/* OK, we are certain this is going to work.  Setup the device. */
-
-	ei_status.name = model_name;
-	ei_status.word16 = word16;
-
-       if (type==NS8390_CABLETRON) {
-               /* Cabletron card puts the RX buffer before the TX buffer */
-               ei_status.tx_start_page = CABLETRON_TX_START_PG;
-               ei_status.rx_start_page = CABLETRON_RX_START_PG;
-               ei_status.stop_page = CABLETRON_RX_STOP_PG;
-               dev->rmem_start = dev->mem_start;
-               dev->rmem_end = dev->mem_start + CABLETRON_RX_STOP_PG*256;
-       } else {
-               ei_status.tx_start_page = WD_START_PG;
-               ei_status.rx_start_page = WD_START_PG + TX_PAGES;
-               ei_status.stop_page = (dev->mem_end - dev->mem_start)/256;
-               dev->rmem_start = dev->mem_start + TX_PAGES*256;
-               dev->rmem_end = dev->mem_end;
-       }
-	
-	if(promoff==-1)		/* Use nubus resources ? */
-	{
-		if(mac8390_ethernet_addr(ndev, dev->dev_addr))
-		{
-		  printk("mac_ns8390: MAC address not in resources!\n");
-		  return -ENODEV;
-		}
-	}
-	else			/* Pull it off the card */
-	{
-		int i=0;
-		int x=1;
-		/* These should go in the end I hope */
-		if(type==NS8390_DAYNA)
-			x=2;
-		if(type==NS8390_INTERLAN || type==NS8390_KINETICS)
-			x=4;
-		while(i<6)
-		{
-			dev->dev_addr[i]=*prom;
-			prom+=x;
-			if(i)
-				printk(":");
-			printk("%02X",dev->dev_addr[i++]);
-		}
-	}
-
-	printk(KERN_INFO "%s: %s in slot %X (type %s)\n",
-		   dev->name, ndev->board->name, ndev->board->slot, model_name);
-	printk(KERN_INFO "MAC ");
-	{
-		int i;
-		for (i = 0; i < 6; i++) {
-			printk("%2.2x", dev->dev_addr[i]);
-			if (i < 5)
-				printk(":");
-		}
-	}
-	printk(" IRQ %d, shared memory at %#lx-%#lx.\n",
-		   dev->irq, dev->mem_start, dev->mem_end-1);
-
-	switch(type)
-	{
-		case NS8390_DAYNA:      /* Dayna card */
-		case NS8390_KINETICS:   /* Kinetics --  8 bit config, but 16 bit mem */
-			/* 16 bit, 4 word offsets */
-			ei_status.reset_8390 = &ns8390_no_reset;
-			ei_status.block_input = &dayna_block_input;
-			ei_status.block_output = &dayna_block_output;
-			ei_status.get_8390_hdr = &dayna_get_8390_hdr;
-			ei_status.reg_offset = fwrd4_offsets;
-			break;
-		case NS8390_CABLETRON: /* Cabletron */
-			/*		16 bit card, register map is short forward */
-			ei_status.reset_8390 = &ns8390_no_reset;
-			/* Ctron card won't accept 32bit values read or written to it */
-			ei_status.block_input = &slow_sane_block_input;
-			ei_status.block_output = &slow_sane_block_output;
-			ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
-			ei_status.reg_offset = fwrd2_offsets;
-			break;
-		case NS8390_FARALLON:
-		case NS8390_APPLE:	/* Apple/Asante/Farallon */
-			/*      16 bit card, register map is reversed */
-			ei_status.reset_8390 = &ns8390_no_reset;
-			ei_status.block_input = &slow_sane_block_input;
-			ei_status.block_output = &slow_sane_block_output;
-			ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
-			ei_status.reg_offset = back4_offsets;
-			break;
-		case NS8390_ASANTE:
-			/*      16 bit card, register map is reversed */
-			ei_status.reset_8390 = &ns8390_no_reset;
-			ei_status.block_input = &sane_block_input;
-			ei_status.block_output = &sane_block_output;
-			ei_status.get_8390_hdr = &sane_get_8390_hdr;
-			ei_status.reg_offset = back4_offsets;
-			break;
-		case NS8390_INTERLAN:   /* Interlan */
-			/*      16 bit card, map is forward */
-			ei_status.reset_8390 = &interlan_reset;
-			ei_status.block_input = &sane_block_input;
-			ei_status.block_output = &sane_block_output;
-			ei_status.get_8390_hdr = &sane_get_8390_hdr;
-			ei_status.reg_offset = back4_offsets;
-			break;
-#if 0 /* i think this suffered code rot.  my kinetics card has much
-	   * different settings.  -- CSA [22-May-1999] */
-		case NS8390_KINETICS:   /* Kinetics */
-			/*      8bit card, map is forward */
-			ei_status.reset_8390 = &ns8390_no_reset;
-			ei_status.block_input = &sane_block_input;
-			ei_status.block_output = &sane_block_output;
-			ei_status.get_8390_hdr = &sane_get_8390_hdr;
-			ei_status.reg_offset = back4_offsets;
-			break;
-#endif
-		default:
-			panic("Detected a card I can't drive - whoops\n");
-	}
-	dev->open = &ns8390_open;
-	dev->stop = &ns8390_close_card;
-
-	NS8390_init(dev, 0);
-
-	return 0;
-}
-
-static int ns8390_open(struct net_device *dev)
-{
-	int ret;
-
-	ei_open(dev);
-
-	/* At least on my card (a Focus Enhancements PDS card) I start */
-	/* getting interrupts right away, so the driver needs to be    */
-	/* completely initialized before enabling the interrupt.        */
-	/*                             - funaho@jurai.org (1999-05-17) */
-
-	/* Non-slow interrupt, works around issues with the SONIC driver */
-	ret = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev); 
-	if (ret) {
-		printk ("%s: unable to get IRQ %d.\n", dev->name, dev->irq);
-		return ret;
-	}
-	return 0;
-}
-
-static void ns8390_no_reset(struct net_device *dev)
-{
-	if (ei_debug > 1) 
-		printk("Need to reset the NS8390 t=%lu...", jiffies);
-	ei_status.txing = 0;
-	if (ei_debug > 1) printk("reset not supported\n");
-}
-
-static int ns8390_close_card(struct net_device *dev)
-{
-	if (ei_debug > 1)
-		printk("%s: Shutting down ethercard.\n", dev->name);
-	free_irq(dev->irq, dev);
-	ei_close(dev);
-	return 0;
-}
-
-/*
- *    Interlan Specific Code Starts Here
- */
-
-static void interlan_reset(struct net_device *dev)
-{
-	unsigned char *target=nubus_slot_addr(IRQ2SLOT(dev->irq));
-	if (ei_debug > 1) 
-		printk("Need to reset the NS8390 t=%lu...", jiffies);
-	ei_status.txing = 0;
-	/* This write resets the card */
-	target[0xC0000]=0;
-	if (ei_debug > 1) printk("reset complete\n");
-	return;
-}
-
-/*
- *    Daynaport code (some is used by other drivers)
- */
-
-
-/* Grab the 8390 specific header. Similar to the block_input routine, but
-   we don't need to be concerned with ring wrap as the header will be at
-   the start of a page, so we optimize accordingly. */
-
-
-/* Block input and output are easy on shared memory ethercards, and trivial
-   on the Daynaport card where there is no choice of how to do it.
-   The only complications are that the ring buffer wraps.
-*/
-
-static void dayna_memcpy_fromcard(struct net_device *dev, void *to, int from, int count)
-{
-	volatile unsigned short *ptr;
-	unsigned short *target=to;
-	from<<=1;	/* word, skip overhead */
-	ptr=(unsigned short *)(dev->mem_start+from);
-	/*
-	 * Leading byte?
-	 */
-	if (from&2) {
-		*((char *)target)++ = *(((char *)ptr++)-1);
-		count--;
-	}
-	while(count>=2)
-	{
-		*target++=*ptr++;	/* Copy and */
-		ptr++;			/* skip cruft */
-		count-=2;
-	}
-	/*
-	 *	Trailing byte ?
-	 */
-	if(count)
-	{
-		/* Big endian */
-		unsigned short v=*ptr;
-		*((char *)target)=v>>8;
-	}
-}
-
-static void dayna_memcpy_tocard(struct net_device *dev, int to, const void *from, int count)
-{
-	volatile unsigned short *ptr;
-	const unsigned short *src=from;
-	to<<=1;	/* word, skip overhead */
-	ptr=(unsigned short *)(dev->mem_start+to);
-	/*
-	 * Leading byte?
-	 */
-	if (to&2) { /* avoid a byte write (stomps on other data) */
-		ptr[-1] = (ptr[-1]&0xFF00)|*((unsigned char *)src)++;
-		ptr++;
-		count--;
-	}
-	while(count>=2)
-	{
-		*ptr++=*src++;		/* Copy and */
-		ptr++;			/* skip cruft */
-		count-=2;
-	}
-	/*
-	 *	Trailing byte ?
-	 */
-	if(count)
-	{
-		/* Big endian */
-		unsigned short v=*src;
-		/* card doesn't like byte writes */
-		*ptr=(*ptr&0x00FF)|(v&0xFF00);
-	}
-}
-
-static void dayna_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
-{
-	unsigned long hdr_start = (ring_page - WD_START_PG)<<8;
-	dayna_memcpy_fromcard(dev, (void *)hdr, hdr_start, 4);
-	/* Register endianism - fix here rather than 8390.c */
-	hdr->count=(hdr->count&0xFF)<<8|(hdr->count>>8);
-}
-
-static void dayna_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
-{
-	unsigned long xfer_base = ring_offset - (WD_START_PG<<8);
-	unsigned long xfer_start = xfer_base+dev->mem_start;
-
-	/*
-	 *	Note the offset maths is done in card memory space which
-	 *	is word per long onto our space.
-	 */
-	 
-	if (xfer_start + count > dev->rmem_end) 
-	{
-		/* We must wrap the input move. */
-		int semi_count = dev->rmem_end - xfer_start;
-		dayna_memcpy_fromcard(dev, skb->data, xfer_base, semi_count);
-		count -= semi_count;
-		dayna_memcpy_fromcard(dev, skb->data + semi_count, 
-			dev->rmem_start - dev->mem_start, count);
-	}
-	else
-	{
-		dayna_memcpy_fromcard(dev, skb->data, xfer_base, count);
-	}
-}
-
-static void dayna_block_output(struct net_device *dev, int count, const unsigned char *buf,
-				int start_page)
-{
-	long shmem = (start_page - WD_START_PG)<<8;
-	
-	dayna_memcpy_tocard(dev, shmem, buf, count);
-}
-
-/*
- *	Cards with full width memory
- */
-
-
-static void sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
-{
-	unsigned long hdr_start = (ring_page - WD_START_PG)<<8;
-	memcpy((void *)hdr, (char *)dev->mem_start+hdr_start, 4);
-	/* Register endianism - fix here rather than 8390.c */
-	hdr->count=(hdr->count&0xFF)<<8|(hdr->count>>8);
-}
-
-static void sane_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
-{
-	unsigned long xfer_base = ring_offset - (WD_START_PG<<8);
-	unsigned long xfer_start = xfer_base+dev->mem_start;
-
-	if (xfer_start + count > dev->rmem_end) 
-	{
-		/* We must wrap the input move. */
-		int semi_count = dev->rmem_end - xfer_start;
-		memcpy(skb->data, (char *)dev->mem_start+xfer_base, semi_count);
-		count -= semi_count;
-		memcpy(skb->data + semi_count, 
-			(char *)dev->rmem_start, count);
-	}
-	else
-	{
-		memcpy(skb->data, (char *)dev->mem_start+xfer_base, count);
-	}
-}
-
-
-static void sane_block_output(struct net_device *dev, int count, const unsigned char *buf,
-				int start_page)
-{
-	long shmem = (start_page - WD_START_PG)<<8;
-	
-	memcpy((char *)dev->mem_start+shmem, buf, count);
-}
-
-static void word_memcpy_tocard(void *tp, const void *fp, int count)
-{
-	volatile unsigned short *to = tp;
-	const unsigned short *from = fp;
-	
-	count++;
-	count/=2;
-	
-	while(count--)
-		*to++=*from++;
-}
-
-static void word_memcpy_fromcard(void *tp, const void *fp, int count)
-{
-	unsigned short *to = tp;
-	const volatile unsigned short *from = fp;
-	
-	count++;
-	count/=2;
-	
-	while(count--)
-		*to++=*from++;
-}
-
-static void slow_sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
-{
-	unsigned long hdr_start = (ring_page - WD_START_PG)<<8;
-	word_memcpy_fromcard((void *)hdr, (char *)dev->mem_start+hdr_start, 4);
-	/* Register endianism - fix here rather than 8390.c */
-	hdr->count=(hdr->count&0xFF)<<8|(hdr->count>>8);
-}
-
-static void slow_sane_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
-{
-	unsigned long xfer_base = ring_offset - (WD_START_PG<<8);
-	unsigned long xfer_start = xfer_base+dev->mem_start;
-
-	if (xfer_start + count > dev->rmem_end) 
-	{
-		/* We must wrap the input move. */
-		int semi_count = dev->rmem_end - xfer_start;
-		word_memcpy_fromcard(skb->data, (char *)dev->mem_start+xfer_base, semi_count);
-		count -= semi_count;
-		word_memcpy_fromcard(skb->data + semi_count, 
-			(char *)dev->rmem_start, count);
-	}
-	else
-	{
-		word_memcpy_fromcard(skb->data, (char *)dev->mem_start+xfer_base, count);
-	}
-}
-
-static void slow_sane_block_output(struct net_device *dev, int count, const unsigned char *buf,
-				int start_page)
-{
-	long shmem = (start_page - WD_START_PG)<<8;
-	
-	word_memcpy_tocard((char *)dev->mem_start+shmem, buf, count);
-#if 0
-	long shmem = (start_page - WD_START_PG)<<8;
-	volatile unsigned short *to=(unsigned short *)(dev->mem_start+shmem);
-	volatile int p;
-	unsigned short *bp=(unsigned short *)buf;
-	
-	count=(count+1)/2;
-	
-	while(count--)
-	{
-		*to++=*bp++;
-		for(p=0;p<10;p++)
-			p++;
-	}
-#endif	
-}
-
-MODULE_LICENSE("GPL");
diff -urN linux-2.4.21-pre3/drivers/net/de600.c linux-2.4.21-pre4/drivers/net/de600.c
--- linux-2.4.21-pre3/drivers/net/de600.c	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre4/drivers/net/de600.c	Tue Jan 28 19:44:30 2003
@@ -403,6 +403,7 @@
 	int	len;
 	int	tickssofar;
 	byte	*buffer = skb->data;
+	int	i;
 
 	if (free_tx_pages <= 0) {	/* Do timeouts, to avoid hangs. */
 		tickssofar = jiffies - dev->trans_start;
@@ -447,8 +448,10 @@
 #endif
 
 	de600_setup_address(transmit_from, RW_ADDR);
-	for ( ; len > 0; --len, ++buffer)
+	for (i = 0;  i < skb->len ; ++i, ++buffer)
 		de600_put_byte(*buffer);
+	for (; i < len; ++i)
+		de600_put_byte(0);
 
 	if (free_tx_pages-- == TX_PAGES) { /* No transmission going on */
 		dev->trans_start = jiffies;
diff -urN linux-2.4.21-pre3/drivers/net/de620.c linux-2.4.21-pre4/drivers/net/de620.c
--- linux-2.4.21-pre3/drivers/net/de620.c	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/drivers/net/de620.c	Tue Jan 28 19:44:30 2003
@@ -316,7 +316,7 @@
 }
 
 static inline void
-de620_write_block(struct net_device *dev, byte *buffer, int count)
+de620_write_block(struct net_device *dev, byte *buffer, int count, int pad)
 {
 #ifndef LOWSPEED
 	byte uflip = NIC_Cmd ^ (DS0 | DS1);
@@ -335,6 +335,9 @@
 	for ( ; count > 0; --count, ++buffer) {
 		de620_put_byte(dev,*buffer);
 	}
+	for ( count = pad ; count > 0; --count, ++buffer) {
+		de620_put_byte(dev, 0);
+	}
 	de620_send_command(dev,W_DUMMY);
 #ifdef COUNT_LOOPS
 	/* trial debug output: loops per byte in de620_ready() */
@@ -576,7 +579,7 @@
 		restore_flags(flags);
 		return 1;
 	}
-	de620_write_block(dev, buffer, len);
+	de620_write_block(dev, buffer, skb->len, len-skb->len);
 
 	dev->trans_start = jiffies;
 	if(!(using_txbuf == (TXBF0 | TXBF1)))
diff -urN linux-2.4.21-pre3/drivers/net/e100/Makefile linux-2.4.21-pre4/drivers/net/e100/Makefile
--- linux-2.4.21-pre3/drivers/net/e100/Makefile	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre4/drivers/net/e100/Makefile	Tue Jan 28 19:44:30 2003
@@ -4,7 +4,7 @@
 
 O_TARGET := e100.o
 
-obj-y	 :=	e100_main.o e100_config.o e100_proc.o e100_phy.o \
+obj-y	 :=	e100_main.o e100_config.o e100_phy.o \
 		e100_eeprom.o e100_test.o
 obj-m	 := $(O_TARGET)
 
diff -urN linux-2.4.21-pre3/drivers/net/e100/e100.h linux-2.4.21-pre4/drivers/net/e100/e100.h
--- linux-2.4.21-pre3/drivers/net/e100/e100.h	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/drivers/net/e100/e100.h	Tue Jan 28 19:44:30 2003
@@ -56,7 +56,6 @@
 
 #include <linux/if.h>
 #include <asm/uaccess.h>
-#include <linux/proc_fs.h>
 #include <linux/ip.h>
 
 #define E100_REGS_LEN 1
@@ -926,20 +925,7 @@
 
 	struct cfg_params params;	/* adapter's command line parameters */
 
-	struct proc_dir_entry *proc_parent;
-
 	char *id_string;
-	char *cable_status;
-	char *mdix_status;
-
-	/* Variables for HWI */
-	int saved_open_circut;
-	int saved_short_circut;
-	int saved_distance;
-	int saved_i;
-	int saved_same;
-	unsigned char hwi_started;
-	struct timer_list hwi_timer;	/* hwi timer id */
 
 	u32 speed_duplex_caps;	/* adapter's speed/duplex capabilities */
 
diff -urN linux-2.4.21-pre3/drivers/net/e100/e100_main.c linux-2.4.21-pre4/drivers/net/e100/e100_main.c
--- linux-2.4.21-pre3/drivers/net/e100/e100_main.c	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/drivers/net/e100/e100_main.c	Tue Jan 28 19:44:30 2003
@@ -83,13 +83,15 @@
 #include "e100_phy.h"
 #include "e100_vendor.h"
 
-#ifdef CONFIG_PROC_FS
-extern int e100_create_proc_subdir(struct e100_private *, char *);
-extern void e100_remove_proc_subdir(struct e100_private *, char *);
-#else
-#define e100_create_proc_subdir(X, Y) 0
-#define e100_remove_proc_subdir(X, Y) do {} while(0)
-#endif
+static char e100_gstrings_stats[][ETH_GSTRING_LEN] = {
+	"rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors",
+	"tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions",
+	"rx_length_errors", "rx_over_errors", "rx_crc_errors",
+	"rx_frame_errors", "rx_fifo_errors", "rx_missed_errors",
+	"tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors",
+	"tx_heartbeat_errors", "tx_window_errors",
+};
+#define E100_STATS_LEN	sizeof(e100_gstrings_stats) / ETH_GSTRING_LEN
 
 static int e100_do_ethtool_ioctl(struct net_device *, struct ifreq *);
 static void e100_get_speed_duplex_caps(struct e100_private *);
@@ -135,7 +137,7 @@
 
 /* Global Data structures and variables */
 char e100_copyright[] __devinitdata = "Copyright (c) 2002 Intel Corporation";
-char e100_driver_version[]="2.1.29-k1";
+char e100_driver_version[]="2.1.29-k3";
 const char *e100_full_driver_name = "Intel(R) PRO/100 Network Driver";
 char e100_short_driver_name[] = "e100";
 static int e100nics = 0;
@@ -150,15 +152,6 @@
         .priority       = 0
 };
 #endif
-static int e100_notify_netdev(struct notifier_block *, unsigned long event, void *ptr);
- 
-struct notifier_block e100_notifier_netdev = {
-	.notifier_call  = e100_notify_netdev,
-	.next           = NULL,
-	.priority       = 0
-};
-
-static void e100_get_mdix_status(struct e100_private *bdp);
 
 /*********************************************************************/
 /*! This is a GCC extension to ANSI C.
@@ -196,6 +189,7 @@
 char *e100_get_brand_msg(struct e100_private *);
 static u8 e100_pci_setup(struct pci_dev *, struct e100_private *);
 static u8 e100_sw_init(struct e100_private *);
+static void e100_tco_walkaround(struct e100_private *);
 static unsigned char e100_alloc_space(struct e100_private *);
 static void e100_dealloc_space(struct e100_private *);
 static int e100_alloc_tcb_pool(struct e100_private *);
@@ -213,7 +207,7 @@
 
 static unsigned char e100_clr_cntrs(struct e100_private *);
 static unsigned char e100_load_microcode(struct e100_private *);
-static unsigned char e100_hw_init(struct e100_private *, u32);
+static unsigned char e100_hw_init(struct e100_private *);
 static unsigned char e100_setup_iaaddr(struct e100_private *, u8 *);
 static unsigned char e100_update_stats(struct e100_private *bdp);
 
@@ -349,8 +343,6 @@
 u32 e100_rx_srv(struct e100_private *);
 
 void e100_watchdog(struct net_device *);
-static void e100_do_hwi(struct net_device *);
-static void e100_hwi_restore(struct e100_private *);
 void e100_refresh_txthld(struct e100_private *);
 void e100_manage_adaptive_ifs(struct e100_private *);
 void e100_clear_pools(struct e100_private *);
@@ -610,10 +602,6 @@
 	bdp->watchdog_timer.data = (unsigned long) dev;
 	bdp->watchdog_timer.function = (void *) &e100_watchdog;
 
-	init_timer(&bdp->hwi_timer);
-	bdp->hwi_timer.data = (unsigned long) dev;
-	bdp->hwi_timer.function = (void *) &e100_do_hwi;
-
 	if ((rc = e100_pci_setup(pcid, bdp)) != 0) {
 		goto err_dealloc;
 	}
@@ -686,21 +674,6 @@
 	       bdp->device->name, e100_get_brand_msg(bdp));
 	e100_print_brd_conf(bdp);
 	bdp->id_string = e100_get_brand_msg(bdp);
-	e100_get_mdix_status(bdp);
-
-	if (netif_carrier_ok(bdp->device)) 
-		bdp->cable_status = "Cable OK";
-	else {
-		if (bdp->rev_id < D102_REV_ID) 
-			bdp->cable_status = "Not supported";
-		else
-			bdp->cable_status = "Not available";
-	}
-
-	if (e100_create_proc_subdir(bdp, bdp->ifname) < 0) {
-		printk(KERN_ERR "e100: Failed to create proc dir for %s\n",
-		       bdp->device->name);
-	}
 
 	bdp->wolsupported = 0;
 	bdp->wolopts = 0;
@@ -766,8 +739,6 @@
 
 	unregister_netdev(dev);
 
-	e100_remove_proc_subdir(bdp, bdp->ifname);
-
 	e100_sw_reset(bdp, PORT_SELECTIVE_RESET);
 
 	if (bdp->non_tx_command_state != E100_NON_TX_IDLE) {
@@ -804,7 +775,6 @@
 #ifdef CONFIG_PM
 		register_reboot_notifier(&e100_notifier_reboot);
 #endif 
-		register_netdevice_notifier(&e100_notifier_netdev);
 	}
 
 	return ret;
@@ -816,7 +786,6 @@
 #ifdef CONFIG_PM	
 	unregister_reboot_notifier(&e100_notifier_reboot);
 #endif 
-	unregister_netdevice_notifier(&e100_notifier_netdev);
 
 	pci_unregister_driver(&e100_driver);
 }
@@ -1265,7 +1234,7 @@
 	/* read NIC's part number */
 	e100_rd_pwa_no(bdp);
 
-	if (!e100_hw_init(bdp, PORT_SOFTWARE_RESET)) {
+	if (!e100_hw_init(bdp)) {
 		printk(KERN_ERR "e100: hw init failed\n");
 		return false;
 	}
@@ -1314,10 +1283,46 @@
 	return 1;
 }
 
+static void __devinit
+e100_tco_walkaround(struct e100_private *bdp)
+{
+	int i;
+
+	/* Do software reset */
+	e100_sw_reset(bdp, PORT_SOFTWARE_RESET);
+
+	/* Do a dummy LOAD CU BASE command. */
+	/* This gets us out of pre-driver to post-driver. */
+	e100_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE);
+
+	/* Wait 20 msec for reset to take effect */
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(HZ / 50);
+
+	/* disable interrupts since they are enabled */
+	/* after device reset                        */
+	e100_disable_clear_intr(bdp);
+
+	/* Wait for command to be cleared up to 1 sec */
+	for (i=0; i<1000; i++) {
+		if (!readb(&bdp->scb->scb_cmd_low))
+			break;
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(HZ / 1000);
+	}
+
+	/* Wait for TCO request bit in PMDR register to be clear */
+	for (i=0; i<500; i++) {
+		if (!(readb(&bdp->scb->scb_ext.d101m_scb.scb_pmdr) & BIT_1))
+			break;
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(HZ / 1000);
+	}
+}
+
 /**
  * e100_hw_init - initialized tthe hardware
  * @bdp: atapter's private data struct
- * @reset_cmd: s/w reset or selective reset
  *
  * This routine performs a reset on the adapter, and configures the adapter.
  * This includes configuring the 82557 LAN controller, validating and setting
@@ -1329,13 +1334,16 @@
  *      false - If the adapter failed initialization
  */
 unsigned char __devinit
-e100_hw_init(struct e100_private *bdp, u32 reset_cmd)
+e100_hw_init(struct e100_private *bdp)
 {
 	if (!e100_phy_init(bdp))
 		return false;
 
-	/* Issue a software reset to the e100 */
-	e100_sw_reset(bdp, reset_cmd);
+	e100_sw_reset(bdp, PORT_SELECTIVE_RESET);
+
+	/* Only 82559 or above needs TCO walkaround */
+	if (bdp->rev_id >= D101MA_REV_ID)
+		e100_tco_walkaround(bdp);
 
 	/* Load the CU BASE (set to 0, because we use linear mode) */
 	if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE, 0))
@@ -1391,6 +1399,7 @@
 	u32 next_phys;		/* the next phys addr */
 	u16 txcommand = CB_S_BIT | CB_TX_SF_BIT;
 
+	bdp->tx_count = 0;
 	if (bdp->flags & USE_IPCB) {
 		txcommand |= CB_IPCB_TRANSMIT | CB_CID_DEFAULT;
 	} else if (bdp->flags & IS_BACHELOR) {
@@ -1634,7 +1643,6 @@
 	if (!netif_running(dev)) {
 		return;
 	}
-	e100_get_mdix_status(bdp);
 
 	/* check if link state has changed */
 	if (e100_phy_check(bdp)) {
@@ -1647,37 +1655,10 @@
 
 			e100_config_fc(bdp);
 			e100_config(bdp);  
-			bdp->cable_status = "Cable OK";
 
 		} else {
 			printk(KERN_ERR "e100: %s NIC Link is Down\n",
 			       bdp->device->name);
-                	if (bdp->rev_id < D102_REV_ID)
-				bdp->cable_status = "Not supported";
-		        else {				
-				/* Initiate hwi, ie, cable diagnostic */
-				bdp->saved_open_circut = 0xffff;
-				bdp->saved_short_circut = 0xffff;
-				bdp->saved_distance = 0xffff;
-				bdp->saved_i = 0;
-				bdp->saved_same = 0;
-				bdp->hwi_started = 1;
-				
-				/* Disable MDI/MDI-X auto switching */
-                		e100_mdi_write(bdp, MII_NCONFIG, bdp->phy_addr,
-		                	MDI_MDIX_RESET_ALL_MASK);
-
-				/* Set to 100 Full as required by hwi test */
-				e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr,
-				       BMCR_SPEED100 | BMCR_FULLDPLX);
-
-				/* Enable and execute HWI test */
-				e100_mdi_write(bdp, HWI_CONTROL_REG, bdp->phy_addr,
-					(HWI_TEST_ENABLE | HWI_TEST_EXECUTE));
-
-				/* Launch hwi timer in 1 msec */
-				mod_timer(&(bdp->hwi_timer), jiffies + (HZ / 1000) );
-			}
 		}
 	}
 
@@ -1836,10 +1817,8 @@
 		bdp->drv_stats.rx_intr_pkts += e100_rx_srv(bdp);
 
 	/* clean up after tx'ed packets */
-	if (intr_status & (SCB_STATUS_ACK_CNA | SCB_STATUS_ACK_CX)) {
-		bdp->tx_count = 0;	/* restart tx interrupt batch count */
+	if (intr_status & (SCB_STATUS_ACK_CNA | SCB_STATUS_ACK_CX))
 		e100_tx_srv(bdp);
-	}
 
 	e100_set_intr_mask(bdp);
 }
@@ -1851,7 +1830,7 @@
  *
  * This routine frees resources of TX skbs.
  */
-static void inline
+static inline void
 e100_tx_skb_free(struct e100_private *bdp, tcb_t *tcb)
 {
 	if (tcb->tcb_skb) {
@@ -2147,11 +2126,12 @@
 	tcb->tcb_thrshld = bdp->tx_thld;
 	tcb->tcb_hdr.cb_cmd |= __constant_cpu_to_le16(CB_S_BIT);
 
-	/* set the I bit on the modulo tcbs, so we will get an interrupt * to
-	 * clean things up */
-	if (!(++bdp->tx_count % TX_FRAME_CNT)) {
+	/* Set I (Interrupt) bit on every (TX_FRAME_CNT)th packet */
+	if (!(++bdp->tx_count % TX_FRAME_CNT))
 		tcb->tcb_hdr.cb_cmd |= __constant_cpu_to_le16(CB_I_BIT);
-	}
+	else
+		/* Clear I bit on other packets */
+		tcb->tcb_hdr.cb_cmd &= ~__constant_cpu_to_le16(CB_I_BIT);
 
 	tcb->tcb_skb = skb;
 
@@ -3054,12 +3034,6 @@
 	if (bdp->device->flags & IFF_UP) {
 		e100_disable_clear_intr(bdp);
 		del_timer_sync(&bdp->watchdog_timer);
-		del_timer_sync(&bdp->hwi_timer);
-		/* If in middle of cable diag, */
-		if (bdp->hwi_started) {
-			bdp->hwi_started = 0;
-			e100_hwi_restore(bdp);
-		}
 		netif_carrier_off(bdp->device);
 		netif_stop_queue(bdp->device); 
 		bdp->last_tcb = NULL;
@@ -3205,6 +3179,22 @@
 	case ETHTOOL_SEEPROM:
 		rc = e100_ethtool_eeprom(dev, ifr);
 		break;
+	case ETHTOOL_GSTATS: {
+		struct {
+			struct ethtool_stats cmd;
+			uint64_t data[E100_STATS_LEN];
+		} stats = { {ETHTOOL_GSTATS, E100_STATS_LEN} };
+		struct e100_private *bdp = dev->priv;
+		void *addr = ifr->ifr_data;
+		int i;
+
+		for(i = 0; i < E100_STATS_LEN; i++)
+			stats.data[i] =
+				((unsigned long *)&bdp->drv_stats.net_stats)[i];
+		if(copy_to_user(addr, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
 	case ETHTOOL_GWOL:
 	case ETHTOOL_SWOL:
 		rc = e100_ethtool_wol(dev, ifr);
@@ -3456,6 +3446,7 @@
 		sizeof (info.fw_version) - 1);
 	strncpy(info.bus_info, bdp->pdev->slot_name,
 		sizeof (info.bus_info) - 1);
+	info.n_stats = E100_STATS_LEN;
 	info.regdump_len  = E100_REGS_LEN * sizeof(u32);
 	info.eedump_len = (bdp->eeprom_size << 1);	
 	info.testinfo_len = E100_MAX_TEST_RES;
@@ -3816,6 +3807,19 @@
 				test_strings[i]);
 		}
 		break;
+	case ETH_SS_STATS: {
+		char *strings = NULL;
+		void *addr = ifr->ifr_data;
+		info.len = E100_STATS_LEN;
+		strings = *e100_gstrings_stats;
+		if(copy_to_user(ifr->ifr_data, &info, sizeof(info)))
+			return -EFAULT;
+		addr += offsetof(struct ethtool_gstrings, data);
+		if(copy_to_user(addr, strings,
+		   info.len * ETH_GSTRING_LEN))
+			return -EFAULT;
+		return 0;
+	}
 	default:
 		return -EOPNOTSUPP;
 	}
@@ -4054,29 +4058,6 @@
 	spin_unlock_bh(&(bdp->bd_non_tx_lock));
 }
 
-int e100_notify_netdev(struct notifier_block *nb, unsigned long event, void *p)
-{
-	struct e100_private *bdp;
-	struct net_device *netdev = p;
-	
-	if(netdev == NULL)
-		return NOTIFY_DONE;
-	
-	switch(event) {
-	case NETDEV_CHANGENAME:
-		if(netdev->open == e100_open) {
-			bdp = netdev->priv;
-			/* rename the proc nodes the easy way */
-			e100_remove_proc_subdir(bdp, bdp->ifname);
-			memcpy(bdp->ifname, netdev->name, IFNAMSIZ);
-			bdp->ifname[IFNAMSIZ-1] = 0;
-			e100_create_proc_subdir(bdp, bdp->ifname);
-		}
-		break;
-	}
-	return NOTIFY_DONE;
-}
-
 #ifdef CONFIG_PM
 static int
 e100_notify_reboot(struct notifier_block *nb, unsigned long event, void *p)
@@ -4140,128 +4121,6 @@
 }
 #endif /* CONFIG_PM */
 
-static void
-e100_get_mdix_status(struct e100_private *bdp)
-{	
-	if (bdp->rev_id < D102_REV_ID) {
-		if (netif_carrier_ok(bdp->device))
-			bdp->mdix_status = "MDI";				
-		else			
-			bdp->mdix_status = "None";
-	} else {	
-		u16 ctrl_reg;
-		/* Read the MDIX control register */
-		e100_mdi_read(bdp, MII_NCONFIG, bdp->phy_addr, &ctrl_reg);
-		if (ctrl_reg & MDI_MDIX_CONFIG_IS_OK) {
-			if (ctrl_reg & MDI_MDIX_STATUS)
-				bdp->mdix_status = "MDI-X";
-			else
-				bdp->mdix_status = "MDI";
-		} else
-			bdp->mdix_status = "None";
-	}
-}
-
-static void
-e100_do_hwi(struct net_device *dev)
-{
-	struct e100_private *bdp = dev->priv;
-	u16 ctrl_reg;
-	int distance, open_circut, short_circut;
-
-	e100_mdi_read(bdp, HWI_CONTROL_REG, bdp->phy_addr, &ctrl_reg);
-
-	distance = ctrl_reg & HWI_TEST_DISTANCE;
-	open_circut = ctrl_reg & HWI_TEST_HIGHZ_PROBLEM;
-	short_circut = ctrl_reg & HWI_TEST_LOWZ_PROBLEM;
-
-	if ((distance == bdp->saved_distance) &&
-	    (open_circut == bdp->saved_open_circut) &&
-	    (short_circut == bdp->saved_short_circut)) 
-		bdp->saved_same++;
-	else {
-		bdp->saved_same = 0;
-		bdp->saved_distance = distance;
-		bdp->saved_open_circut = open_circut;
-		bdp->saved_short_circut = short_circut;
-	}
-		
-	if (bdp->saved_same == MAX_SAME_RESULTS) {
-		if ((open_circut && !(short_circut)) ||
-		    (!(open_circut) && short_circut)) {
-
-			u8 near_end = ((distance * HWI_REGISTER_GRANULARITY) <
-				       HWI_NEAR_END_BOUNDARY);
-			if (open_circut) {
-				if (near_end) 
-					bdp->cable_status = "Open Circut Near End";
-				else 
-					bdp->cable_status = "Open Circut Far End";
-			} else {
-				if (near_end) 
-					bdp->cable_status = "Short Circut Near End";
-				else 
-					bdp->cable_status = "Short Circut Far End";
-			}
-			goto done;
-		}
-	}
-	else if (bdp->saved_i == HWI_MAX_LOOP) {
-		bdp->cable_status = "Test failed";
-		goto done;
-	}
-		
-	/* Do another hwi test */
-	e100_mdi_write(bdp, HWI_CONTROL_REG, bdp->phy_addr,
-		       (HWI_TEST_ENABLE | HWI_TEST_EXECUTE));
-	bdp->saved_i++;
-	/* relaunch hwi timer in 1 msec */
-	mod_timer(&(bdp->hwi_timer), jiffies + (HZ / 1000) );
-	return;
-
-done:
-	e100_hwi_restore(bdp);
-	bdp->hwi_started = 0;
-	return;
-}
-
-static void e100_hwi_restore(struct e100_private *bdp)
-{
-	u16 control = 0;
-
-	/* Restore speed, duplex and autoneg before */
-	/* hwi test, i.e., cable diagnostic         */
-	
-	/* Reset hwi test */
-        e100_mdi_write(bdp, HWI_CONTROL_REG, bdp->phy_addr,					       HWI_RESET_ALL_MASK);
-				
-	if ((bdp->params.e100_speed_duplex == E100_AUTONEG) &&
-        	(bdp->rev_id >= D102_REV_ID)) 
-		/* Enable MDI/MDI-X auto switching */
-                e100_mdi_write(bdp, MII_NCONFIG, bdp->phy_addr,
-			MDI_MDIX_AUTO_SWITCH_ENABLE);
-
-	switch (bdp->params.e100_speed_duplex) {
-	case E100_SPEED_10_HALF:
-		break;
-	case E100_SPEED_10_FULL:
-		control = BMCR_FULLDPLX;
-		break;
-	case E100_SPEED_100_HALF:
-		control = BMCR_SPEED100;
-		break;
-	case E100_SPEED_100_FULL:
-		control = BMCR_SPEED100 | BMCR_FULLDPLX;
-		break;
-	case E100_AUTONEG:
-		control = BMCR_ANENABLE | BMCR_ANRESTART;
-		break;
-	}
-	/* Restore original speed/duplex */
-	e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, control);
-	return;
-}
-
 #ifdef E100_CU_DEBUG
 unsigned char
 e100_cu_unknown_state(struct e100_private *bdp)
diff -urN linux-2.4.21-pre3/drivers/net/e100/e100_proc.c linux-2.4.21-pre4/drivers/net/e100/e100_proc.c
--- linux-2.4.21-pre3/drivers/net/e100/e100_proc.c	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre4/drivers/net/e100/e100_proc.c	Wed Dec 31 16:00:00 1969
@@ -1,474 +0,0 @@
-/*******************************************************************************
-
-  
-  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
-*******************************************************************************/
-
-/**********************************************************************
-*                                                                       *
-* INTEL CORPORATION                                                     *
-*                                                                       *
-* This software is supplied under the terms of the license included     *
-* above.  All use of this driver must be in accordance with the terms   *
-* of that license.                                                      *
-*                                                                       *
-* Module Name:  e100_proc.c                                             *
-*                                                                       *
-* Abstract:     Functions to handle the proc file system.               *
-*               Create the proc directories and files and run read and  *
-*               write requests from the user                            *
-*                                                                       *
-* Environment:  This file is intended to be specific to the Linux       *
-*               operating system.                                       *
-*                                                                       *
-**********************************************************************/
-
-#include <linux/config.h>
-
-#ifdef CONFIG_PROC_FS
-#include "e100.h"
-/* MDI sleep time is at least 50 ms, in jiffies */
-#define MDI_SLEEP_TIME ((HZ / 20) + 1)
-/***************************************************************************/
-/*       /proc File System Interaface Support Functions                    */
-/***************************************************************************/
-
-static struct proc_dir_entry *adapters_proc_dir = 0;
-
-/* externs from e100_main.c */
-extern char e100_short_driver_name[];
-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 int e100_mdi_write(struct e100_private *, u32, u32, u16);
-
-static void e100_proc_cleanup(void);
-static unsigned char e100_init_proc_dir(void);
-
-#define ADAPTERS_PROC_DIR "PRO_LAN_Adapters"
-#define WRITE_BUF_MAX_LEN 20	
-#define READ_BUF_MAX_LEN  256
-#define E100_PE_LEN       25
-
-#define bdp_drv_off(off) (unsigned long)(offsetof(struct e100_private, drv_stats.off))
-#define bdp_prm_off(off) (unsigned long)(offsetof(struct e100_private, params.off))
-
-typedef struct _e100_proc_entry {
-	char *name;
-	read_proc_t *read_proc;
-	write_proc_t *write_proc;
-	unsigned long offset;	/* offset into bdp. ~0 means no value, pass NULL. */
-} e100_proc_entry;
-
-static int
-generic_read(char *page, char **start, off_t off, int count, int *eof, int len)
-{
-	if (len <= off + count)
-		*eof = 1;
-
-	*start = page + off;
-	len -= off;
-	if (len > count)
-		len = count;
-
-	if (len < 0)
-		len = 0;
-
-	return len;
-}
-
-static int
-read_ulong(char *page, char **start, off_t off,
-	   int count, int *eof, unsigned long l)
-{
-	int len;
-
-	len = sprintf(page, "%lu\n", l);
-
-	return generic_read(page, start, off, count, eof, len);
-}
-
-static int
-read_gen_ulong(char *page, char **start, off_t off,
-	       int count, int *eof, void *data)
-{
-	unsigned long val = 0;
-
-	if (data)
-		val = *((unsigned long *) data);
-
-	return read_ulong(page, start, off, count, eof, val);
-}
-
-static int
-read_hwaddr(char *page, char **start, off_t off,
-	    int count, int *eof, unsigned char *hwaddr)
-{
-	int len;
-
-	len = sprintf(page, "%02X:%02X:%02X:%02X:%02X:%02X\n",
-		      hwaddr[0], hwaddr[1], hwaddr[2],
-		      hwaddr[3], hwaddr[4], hwaddr[5]);
-
-	return generic_read(page, start, off, count, eof, len);
-}
-
-static int
-read_descr(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
-	struct e100_private *bdp = data;
-	int len;
-
-	len = sprintf(page, "%s\n", bdp->id_string);
-
-	return generic_read(page, start, off, count, eof, len);
-}
-
-static int
-read_permanent_hwaddr(char *page, char **start, off_t off,
-		      int count, int *eof, void *data)
-{
-	struct e100_private *bdp = data;
-	unsigned char *hwaddr = bdp->perm_node_address;
-
-	return read_hwaddr(page, start, off, count, eof, hwaddr);
-}
-
-static int
-read_part_number(char *page, char **start, off_t off,
-		 int count, int *eof, void *data)
-{
-	struct e100_private *bdp = data;
-	int len;
-
-	len = sprintf(page, "%06lx-%03x\n",
-		      (unsigned long) (bdp->pwa_no >> 8),
-		      (unsigned int) (bdp->pwa_no & 0xFF));
-
-	return generic_read(page, start, off, count, eof, len);
-}
-
-static void
-set_led(struct e100_private *bdp, u16 led_mdi_op)
-{
-	e100_mdi_write(bdp, PHY_82555_LED_SWITCH_CONTROL,
-		       bdp->phy_addr, led_mdi_op);
-
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(MDI_SLEEP_TIME);
-
-	/* turn led ownership to the chip */
-	e100_mdi_write(bdp, PHY_82555_LED_SWITCH_CONTROL,
-		       bdp->phy_addr, PHY_82555_LED_NORMAL_CONTROL);
-}
-
-static int
-write_blink_led_timer(struct file *file, const char *buffer,
-		      unsigned long count, void *data)
-{
-	struct e100_private *bdp = data;
-	char s_blink_op[WRITE_BUF_MAX_LEN + 1];
-	char *res;
-	unsigned long i_blink_op;
-
-	if (!buffer)
-		return -EINVAL;
-
-	if (count > WRITE_BUF_MAX_LEN) {
-		count = WRITE_BUF_MAX_LEN;
-	}
-	if (copy_from_user(s_blink_op, buffer, count))
-		return -EFAULT;
-	s_blink_op[count] = '\0';
-	i_blink_op = simple_strtoul(s_blink_op, &res, 0);
-	if (res == s_blink_op) {
-		return -EINVAL;
-	}
-
-	switch (i_blink_op) {
-
-	case LED_OFF:
-		set_led(bdp, PHY_82555_LED_OFF);
-		break;
-	case LED_ON:
-		if (bdp->rev_id >= D101MA_REV_ID)
-			set_led(bdp, PHY_82555_LED_ON_559);
-		else
-			set_led(bdp, PHY_82555_LED_ON_PRE_559);
-
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return count;
-}
-
-static e100_proc_entry e100_proc_list[] = {
-	{"Description",           read_descr,            0, 0},
-	{"Permanent_HWaddr",      read_permanent_hwaddr, 0, 0},
-	{"Part_Number",           read_part_number,      0, 0},
-	{"\n",},
-	{"Rx_TCP_Checksum_Good",  read_gen_ulong, 0, ~0},
-	{"Rx_TCP_Checksum_Bad",   read_gen_ulong, 0, ~0},
-	{"Tx_TCP_Checksum_Good",  read_gen_ulong, 0, ~0},
-	{"Tx_TCP_Checksum_Bad",   read_gen_ulong, 0, ~0},
-	{"\n",},
-	{"Tx_Abort_Late_Coll",    read_gen_ulong, 0, bdp_drv_off(tx_late_col)},
-	{"Tx_Deferred_Ok",        read_gen_ulong, 0, bdp_drv_off(tx_ok_defrd)},
-	{"Tx_Single_Coll_Ok",     read_gen_ulong, 0, bdp_drv_off(tx_one_retry)},
-	{"Tx_Multi_Coll_Ok",      read_gen_ulong, 0, bdp_drv_off(tx_mt_one_retry)},
-	{"Rx_Long_Length_Errors", read_gen_ulong, 0, ~0},
-	{"\n",},
-	{"Tx_Flow_Control_Pause", read_gen_ulong, 0, bdp_drv_off(xmt_fc_pkts)},
-	{"Rx_Flow_Control_Pause", read_gen_ulong, 0, bdp_drv_off(rcv_fc_pkts)},
-	{"Rx_Flow_Control_Unsup", read_gen_ulong, 0, bdp_drv_off(rcv_fc_unsupported)},
-	{"\n",},
-	{"Tx_TCO_Packets",        read_gen_ulong, 0, bdp_drv_off(xmt_tco_pkts)},
-	{"Rx_TCO_Packets",        read_gen_ulong, 0, bdp_drv_off(rcv_tco_pkts)},
-	{"\n",},
-	{"Rx_Interrupt_Packets",  read_gen_ulong, 0, bdp_drv_off(rx_intr_pkts)},
-	{"Identify_Adapter", 0, write_blink_led_timer, 0},
-	{"", 0, 0, 0}
-};
-
-static int
-read_info(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
-	struct e100_private *bdp = data;
-	e100_proc_entry *pe;
-	int tmp;
-	void *val;
-	int len = 0;
-
-	for (pe = e100_proc_list; pe->name[0]; pe++) {
-		if (pe->name[0] == '\n') {
-			len += sprintf(page + len, "\n");
-			continue;
-		}
-
-		if (pe->read_proc) {
-			if ((len + READ_BUF_MAX_LEN + E100_PE_LEN + 1) >=
-			    PAGE_SIZE)
-				break;
-
-			if (pe->offset != ~0)
-				val = ((char *) bdp) + pe->offset;
-			else
-				val = NULL;
-
-			len += sprintf(page + len, "%-"
-				       __MODULE_STRING(E100_PE_LEN)
-				       "s ", pe->name);
-			len += pe->read_proc(page + len, start, 0,
-					     READ_BUF_MAX_LEN + 1, &tmp, val);
-		}
-	}
-
-	return generic_read(page, start, off, count, eof, len);
-}
-
-static struct proc_dir_entry *
-create_proc_rw(char *name, void *data, struct proc_dir_entry *parent,
-	       read_proc_t * read_proc, write_proc_t * write_proc)
-{
-	struct proc_dir_entry *pdep;
-	mode_t mode = S_IFREG;
-
-	if (write_proc) {
-		mode |= S_IWUSR;
-		if (read_proc) {
-			mode |= S_IRUSR;
-		}
-
-	} else if (read_proc) {
-		mode |= S_IRUGO;
-	}
-
-	if (!(pdep = create_proc_entry(name, mode, parent)))
-		return NULL;
-
-	pdep->read_proc = read_proc;
-	pdep->write_proc = write_proc;
-	pdep->data = data;
-	return pdep;
-}
-
-void
-e100_remove_proc_subdir(struct e100_private *bdp, char *name)
-{
-	e100_proc_entry *pe;
-	char info[256];
-	int len;
-
-	/* If our root /proc dir was not created, there is nothing to remove */
-	if (adapters_proc_dir == NULL) {
-		return;
-	}
-
-	len = strlen(bdp->ifname);
-	strncpy(info, bdp->ifname, sizeof (info));
-	strncat(info + len, ".info", sizeof (info) - len);
-
-	if (bdp->proc_parent) {
-		for (pe = e100_proc_list; pe->name[0]; pe++) {
-			if (pe->name[0] == '\n')
-				continue;
-
-			remove_proc_entry(pe->name, bdp->proc_parent);
-		}
-
-		remove_proc_entry(bdp->ifname, adapters_proc_dir);
-		bdp->proc_parent = NULL;
-	}
-
-	remove_proc_entry(info, adapters_proc_dir);
-
-	/* try to remove the main /proc dir, if it's empty */
-	e100_proc_cleanup();
-}
-
-int
-e100_create_proc_subdir(struct e100_private *bdp)
-{
-	struct proc_dir_entry *dev_dir;
-	e100_proc_entry *pe;
-	char info[256];
-	int len;
-	void *data;
-
-	/* create the main /proc dir if needed */
-	if (!adapters_proc_dir) {
-		if (!e100_init_proc_dir())
-			return -ENOMEM;
-	}
-
-	strncpy(info, bdp->ifname, sizeof (info));
-	len = strlen(info);
-	strncat(info + len, ".info", sizeof (info) - len);
-
-	/* info */
-	if (!(create_proc_rw(info, bdp, adapters_proc_dir, read_info, 0))) {
-		e100_proc_cleanup();
-		return -ENOMEM;
-	}
-
-	dev_dir = create_proc_entry(bdp->ifname, S_IFDIR,
-				    adapters_proc_dir);
-	bdp->proc_parent = dev_dir;
-
-	if (!dev_dir) {
-		e100_remove_proc_subdir(bdp, bdp->ifname);
-		return -ENOMEM;
-	}
-
-	for (pe = e100_proc_list; pe->name[0]; pe++) {
-		if (pe->name[0] == '\n')
-			continue;
-
-		if (pe->offset != ~0)
-			data = ((char *) bdp) + pe->offset;
-		else
-			data = NULL;
-
-		if (!(create_proc_rw(pe->name, data, dev_dir,
-				     pe->read_proc, pe->write_proc))) {
-			e100_remove_proc_subdir(bdp, bdp->ifname);
-			return -ENOMEM;
-		}
-	}
-
-	return 0;
-}
-
-/****************************************************************************
- * Name:          e100_init_proc_dir
- *
- * Description:   This routine creates the top-level /proc directory for the
- *                driver in /proc/net
- *
- * Arguments:     none
- *
- * Returns:       true on success, false on fail
- *
- ***************************************************************************/
-static unsigned char
-e100_init_proc_dir(void)
-{
-	int len;
-
-	/* first check if adapters_proc_dir already exists */
-	len = strlen(ADAPTERS_PROC_DIR);
-	for (adapters_proc_dir = proc_net->subdir;
-	     adapters_proc_dir; adapters_proc_dir = adapters_proc_dir->next) {
-
-		if ((adapters_proc_dir->namelen == len) &&
-		    (!memcmp(adapters_proc_dir->name, ADAPTERS_PROC_DIR, len)))
-			break;
-	}
-
-	if (!adapters_proc_dir)
-		adapters_proc_dir =
-			create_proc_entry(ADAPTERS_PROC_DIR, S_IFDIR, proc_net);
-
-	if (!adapters_proc_dir)
-		return false;
-
-	return true;
-}
-
-/****************************************************************************
- * Name:          e100_proc_cleanup
- *
- * Description:   This routine clears the top-level /proc directory, if empty.
- *
- * Arguments:     none
- *
- * Returns:       none
- *
- ***************************************************************************/
-static void
-e100_proc_cleanup(void)
-{
-	struct proc_dir_entry *de;
-
-	if (adapters_proc_dir == NULL) {
-		return;
-	}
-
-	/* check if subdir list is empty before removing adapters_proc_dir */
-	for (de = adapters_proc_dir->subdir; de; de = de->next) {
-		/* ignore . and .. */
-		if (*(de->name) != '.')
-			break;
-	}
-
-	if (de)
-		return;
-
-	remove_proc_entry(ADAPTERS_PROC_DIR, proc_net);
-	adapters_proc_dir = NULL;
-}
-
-#endif /* CONFIG_PROC_FS */
diff -urN linux-2.4.21-pre3/drivers/net/e1000/Makefile linux-2.4.21-pre4/drivers/net/e1000/Makefile
--- linux-2.4.21-pre3/drivers/net/e1000/Makefile	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre4/drivers/net/e1000/Makefile	Tue Jan 28 19:44:30 2003
@@ -32,8 +32,7 @@
 
 O_TARGET := e1000.o
 
-obj-y	:= e1000_main.o e1000_hw.o e1000_ethtool.o e1000_param.o \
-	   e1000_proc.o
+obj-y	:= e1000_main.o e1000_hw.o e1000_ethtool.o e1000_param.o
 obj-m	:= $(O_TARGET)
 
 include $(TOPDIR)/Rules.make
diff -urN linux-2.4.21-pre3/drivers/net/e1000/e1000.h linux-2.4.21-pre4/drivers/net/e1000/e1000.h
--- linux-2.4.21-pre3/drivers/net/e1000/e1000.h	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/drivers/net/e1000/e1000.h	Tue Jan 28 19:44:30 2003
@@ -156,9 +156,6 @@
 struct e1000_adapter {
 	struct timer_list watchdog_timer;
 	struct timer_list phy_info_timer;
-#ifdef CONFIG_PROC_FS
-	struct list_head proc_list_head;
-#endif
 	struct vlan_group *vlgrp;
 	char *id_string;
 	uint32_t bd_number;
diff -urN linux-2.4.21-pre3/drivers/net/e1000/e1000_ethtool.c linux-2.4.21-pre4/drivers/net/e1000/e1000_ethtool.c
--- linux-2.4.21-pre3/drivers/net/e1000/e1000_ethtool.c	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/drivers/net/e1000/e1000_ethtool.c	Tue Jan 28 19:44:30 2003
@@ -39,6 +39,16 @@
 extern void e1000_down(struct e1000_adapter *adapter);
 extern void e1000_reset(struct e1000_adapter *adapter);
 
+static char e1000_gstrings_stats[][ETH_GSTRING_LEN] = {
+	"rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors",
+	"tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions",
+	"rx_length_errors", "rx_over_errors", "rx_crc_errors",
+	"rx_frame_errors", "rx_fifo_errors", "rx_missed_errors",
+	"tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors",
+	"tx_heartbeat_errors", "tx_window_errors",
+};
+#define E1000_STATS_LEN	sizeof(e1000_gstrings_stats) / ETH_GSTRING_LEN
+
 static void
 e1000_ethtool_gset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd)
 {
@@ -173,6 +183,7 @@
 	strncpy(drvinfo->version, e1000_driver_version, 32);
 	strncpy(drvinfo->fw_version, "N/A", 32);
 	strncpy(drvinfo->bus_info, adapter->pdev->slot_name, 32);
+	drvinfo->n_stats = E1000_STATS_LEN;
 #define E1000_REGS_LEN 32
 	drvinfo->regdump_len  = E1000_REGS_LEN * sizeof(uint32_t);
 	drvinfo->eedump_len  = e1000_eeprom_size(&adapter->hw);
@@ -209,18 +220,24 @@
                       struct ethtool_eeprom *eeprom, uint16_t *eeprom_buff)
 {
 	struct e1000_hw *hw = &adapter->hw;
-	int i, max_len, first_word, last_word;
-
-	if(eeprom->len == 0)
-		return -EINVAL;
+	int max_len, first_word, last_word;
+	int ret_val = 0;
+	int i;
+
+	if(eeprom->len == 0) {
+		ret_val = -EINVAL;
+		goto geeprom_error;
+	}
 
 	eeprom->magic = hw->vendor_id | (hw->device_id << 16);
 
 	max_len = e1000_eeprom_size(hw);
 
-	if(eeprom->offset > eeprom->offset + eeprom->len)
-		return -EINVAL;
-	
+	if(eeprom->offset > eeprom->offset + eeprom->len) {
+		ret_val = -EINVAL;
+		goto geeprom_error;
+	}
+
 	if((eeprom->offset + eeprom->len) > max_len)
 		eeprom->len = (max_len - eeprom->offset);
 
@@ -230,7 +247,8 @@
 	for(i = 0; i <= (last_word - first_word); i++)
 		e1000_read_eeprom(hw, first_word + i, &eeprom_buff[i]);
 
-	return 0;
+geeprom_error:
+	return ret_val;
 }
 
 static int
@@ -238,9 +256,10 @@
                       struct ethtool_eeprom *eeprom, void *user_data)
 {
 	struct e1000_hw *hw = &adapter->hw;
-	uint16_t eeprom_buff[256];
-	int i, max_len, first_word, last_word;
+	uint16_t *eeprom_buff;
+	int max_len, first_word, last_word;
 	void *ptr;
+	int i;
 
 	if(eeprom->len == 0)
 		return -EOPNOTSUPP;
@@ -255,6 +274,10 @@
 
 	first_word = eeprom->offset >> 1;
 	last_word = (eeprom->offset + eeprom->len - 1) >> 1;
+	eeprom_buff = kmalloc(max_len, GFP_KERNEL);
+	if(eeprom_buff == NULL)
+		return -ENOMEM;
+
 	ptr = (void *)eeprom_buff;
 
 	if(eeprom->offset & 1) {
@@ -269,8 +292,10 @@
 		e1000_read_eeprom(hw, last_word,
 		                  &eeprom_buff[last_word - first_word]);
 	}
-	if(copy_from_user(ptr, user_data, eeprom->len))
+	if(copy_from_user(ptr, user_data, eeprom->len)) {
+		kfree(eeprom_buff);
 		return -EFAULT;
+	}
 
 	for(i = 0; i <= (last_word - first_word); i++)
 		e1000_write_eeprom(hw, first_word + i, eeprom_buff[i]);
@@ -279,6 +304,8 @@
 	if(first_word <= EEPROM_CHECKSUM_REG)
 		e1000_update_eeprom_checksum(hw);
 
+	kfree(eeprom_buff);
+
 	return 0;
 }
 
@@ -438,6 +465,28 @@
 			return -EFAULT;
 		return 0;
 	}
+	case ETHTOOL_GSTRINGS: {
+		struct ethtool_gstrings gstrings = { ETHTOOL_GSTRINGS };
+		char *strings = NULL;
+
+		if(copy_from_user(&gstrings, addr, sizeof(gstrings)))
+			return -EFAULT;
+		switch(gstrings.string_set) {
+		case ETH_SS_STATS:
+			gstrings.len = E1000_STATS_LEN;
+			strings = *e1000_gstrings_stats;
+			break;
+		default:
+			return -EOPNOTSUPP;
+		}
+		if(copy_to_user(addr, &gstrings, sizeof(gstrings)))
+			return -EFAULT;
+		addr += offsetof(struct ethtool_gstrings, data);
+		if(copy_to_user(addr, strings,
+		   gstrings.len * ETH_GSTRING_LEN))
+			return -EFAULT;
+		return 0;
+	}
 	case ETHTOOL_GREGS: {
 		struct ethtool_regs regs = {ETHTOOL_GREGS};
 		uint32_t regs_buff[E1000_REGS_LEN];
@@ -493,26 +542,40 @@
 	}
 	case ETHTOOL_GEEPROM: {
 		struct ethtool_eeprom eeprom = {ETHTOOL_GEEPROM};
-		uint16_t eeprom_buff[256];
+		uint16_t *eeprom_buff;
 		void *ptr;
-		int err;
+		int max_len, err = 0;
 
-		if(copy_from_user(&eeprom, addr, sizeof(eeprom)))
-			return -EFAULT;
+		max_len = e1000_eeprom_size(&adapter->hw);
 
-		if((err = e1000_ethtool_geeprom(adapter, 
-			&eeprom, eeprom_buff)))
-			return err;
+		eeprom_buff = kmalloc(max_len, GFP_KERNEL);
 
-		if(copy_to_user(addr, &eeprom, sizeof(eeprom)))
-			return -EFAULT;
+		if(eeprom_buff == NULL)
+			return -ENOMEM;
+
+		if(copy_from_user(&eeprom, addr, sizeof(eeprom))) {
+			err = -EFAULT;
+			goto err_geeprom_ioctl;
+		}
+
+		if((err = e1000_ethtool_geeprom(adapter, &eeprom,
+						eeprom_buff)))
+			goto err_geeprom_ioctl;
+
+		if(copy_to_user(addr, &eeprom, sizeof(eeprom))) {
+			err = -EFAULT;
+			goto err_geeprom_ioctl;
+		}
 
 		addr += offsetof(struct ethtool_eeprom, data);
 		ptr = ((void *)eeprom_buff) + (eeprom.offset & 1);
 
 		if(copy_to_user(addr, ptr, eeprom.len))
-			return -EFAULT;
-		return 0;
+			err = -EFAULT;
+
+err_geeprom_ioctl:
+		kfree(eeprom_buff);
+		return err;
 	}
 	case ETHTOOL_SEEPROM: {
 		struct ethtool_eeprom eeprom;
@@ -526,6 +589,20 @@
 		addr += offsetof(struct ethtool_eeprom, data);
 		return e1000_ethtool_seeprom(adapter, &eeprom, addr);
 	}
+	case ETHTOOL_GSTATS: {
+		struct {
+			struct ethtool_stats cmd;
+			uint64_t data[E1000_STATS_LEN];
+		} stats = { {ETHTOOL_GSTATS, E1000_STATS_LEN} };
+		int i;
+
+		for(i = 0; i < E1000_STATS_LEN; i++)
+			stats.data[i] =
+				((unsigned long *)&adapter->net_stats)[i];
+		if(copy_to_user(addr, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
 	default:
 		return -EOPNOTSUPP;
 	}
diff -urN linux-2.4.21-pre3/drivers/net/e1000/e1000_main.c linux-2.4.21-pre4/drivers/net/e1000/e1000_main.c
--- linux-2.4.21-pre3/drivers/net/e1000/e1000_main.c	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/drivers/net/e1000/e1000_main.c	Tue Jan 28 19:44:30 2003
@@ -59,7 +59,7 @@
 
 char e1000_driver_name[] = "e1000";
 char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
-char e1000_driver_version[] = "4.4.19-k1";
+char e1000_driver_version[] = "4.4.19-k2";
 char e1000_copyright[] = "Copyright (c) 1999-2002 Intel Corporation.";
 
 /* e1000_pci_tbl - PCI Device ID Table
@@ -167,7 +167,6 @@
 static void e1000_restore_vlan(struct e1000_adapter *adapter);
 
 static int e1000_notify_reboot(struct notifier_block *, unsigned long event, void *ptr);
-static int e1000_notify_netdev(struct notifier_block *, unsigned long event, void *ptr);
 static int e1000_suspend(struct pci_dev *pdev, uint32_t state);
 #ifdef CONFIG_PM
 static int e1000_resume(struct pci_dev *pdev);
@@ -179,17 +178,9 @@
 	.priority	= 0
 };
 
-struct notifier_block e1000_notifier_netdev = {
-	.notifier_call	= e1000_notify_netdev,
-	.next		= NULL,
-	.priority	= 0
-};
-
 /* Exported from other modules */
 
 extern void e1000_check_options(struct e1000_adapter *adapter);
-extern void e1000_proc_dev_setup(struct e1000_adapter *adapter);
-extern void e1000_proc_dev_free(struct e1000_adapter *adapter);
 extern int e1000_ethtool_ioctl(struct net_device *netdev, struct ifreq *ifr);
 
 static struct pci_driver e1000_driver = {
@@ -225,10 +216,8 @@
 	printk(KERN_INFO "%s\n", e1000_copyright);
 
 	ret = pci_module_init(&e1000_driver);
-	if(ret >= 0) {
+	if(ret >= 0)
 		register_reboot_notifier(&e1000_notifier_reboot);
-		register_netdevice_notifier(&e1000_notifier_netdev);
-	}
 	return ret;
 }
 
@@ -245,7 +234,6 @@
 e1000_exit_module(void)
 {
 	unregister_reboot_notifier(&e1000_notifier_reboot);
-	unregister_netdevice_notifier(&e1000_notifier_netdev);
 	pci_unregister_driver(&e1000_driver);
 }
 
@@ -477,7 +465,6 @@
 
 	printk(KERN_INFO "%s: %s\n", netdev->name, adapter->id_string);
 	e1000_check_options(adapter);
-	e1000_proc_dev_setup(adapter);
 
 	/* Initial Wake on LAN setting
 	 * If APM wake is enabled in the EEPROM,
@@ -535,8 +522,6 @@
 
 	e1000_phy_hw_reset(&adapter->hw);
 
-	e1000_proc_dev_free(adapter);
-
 	iounmap(adapter->hw.hw_addr);
 	pci_release_regions(pdev);
 
@@ -2182,29 +2167,6 @@
 	}
 	return NOTIFY_DONE;
 }
-
-static int
-e1000_notify_netdev(struct notifier_block *nb, unsigned long event, void *p)
-{
-	struct e1000_adapter *adapter;
-	struct net_device *netdev = p;
-	if(netdev == NULL)
-		return NOTIFY_DONE;
-
-	switch(event) {
-	case NETDEV_CHANGENAME:
-		if(netdev->open == e1000_open) {
-			adapter = netdev->priv;
-			/* rename the proc nodes the easy way */
-			e1000_proc_dev_free(adapter);
-			memcpy(adapter->ifname, netdev->name, IFNAMSIZ);
-			adapter->ifname[IFNAMSIZ-1] = 0;
-			e1000_proc_dev_setup(adapter);
-		}
-		break;
-	}
-	return NOTIFY_DONE;
-}
 
 static int
 e1000_suspend(struct pci_dev *pdev, uint32_t state)
diff -urN linux-2.4.21-pre3/drivers/net/e1000/e1000_proc.c linux-2.4.21-pre4/drivers/net/e1000/e1000_proc.c
--- linux-2.4.21-pre3/drivers/net/e1000/e1000_proc.c	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/drivers/net/e1000/e1000_proc.c	Wed Dec 31 16:00:00 1969
@@ -1,699 +0,0 @@
-/*******************************************************************************
-
-  
-  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
-
-*******************************************************************************/
-
-/*
- * Proc fs support.
- *
- * Read-only files created by driver (if CONFIG_PROC_FS):
- *
- * /proc/net/PRO_LAN_Adapters/<ethx>.info
- * /proc/net/PRO_LAN_Adapters/<ethx>/<attribute>
- *
- * where <ethx>      is the system device name, i.e eth0.
- *       <attribute> is the driver attribute name.
- *
- * There is one file for each driver attribute, where the contents
- * of the file is the attribute value.  The ethx.info file contains
- * a list of all driver attributes in one file.
- *
- */
-
-#include "e1000.h"
-
-#ifdef CONFIG_PROC_FS
-
-#include <linux/proc_fs.h>
-
-#define ADAPTERS_PROC_DIR           "PRO_LAN_Adapters"
-#define TAG_MAX_LENGTH              32
-#define LINE_MAX_LENGTH             80
-#define FIELD_MAX_LENGTH            LINE_MAX_LENGTH - TAG_MAX_LENGTH - 3
-
-extern char e1000_driver_name[];
-extern char e1000_driver_version[];
-
-/*
- * The list of driver proc attributes is stored in a proc_list link
- * list.  The list is build with proc_list_setup and is used to
- * build the proc fs nodes.  The private data for each node is the
- * corresponding link in the link list.
- */
-
-struct proc_list {
-	struct list_head list;                  /* link list */
-	char tag[TAG_MAX_LENGTH + 1];           /* attribute name */
-	void *data;                             /* attribute data */
-	size_t len;				/* sizeof data */
-	char *(*func)(void *, size_t, char *);  /* format data func */
-};
-
-static int
-e1000_proc_read(char *page, char **start, off_t off, int count, int *eof)
-{
-	int len = strlen(page);
-
-	page[len++] = '\n';
-
-	if(len <= off + count)
-		*eof = 1;
-	*start = page + off;
-	len -= off;
-	if(len > count)
-		len = count;
-	if(len < 0)
-		len = 0;
-
-	return len;
-}
-
-static int
-e1000_proc_info_read(char *page, char **start, off_t off,
-                     int count, int *eof, void *data)
-{
-	struct list_head *proc_list_head = data, *curr;
-	struct proc_list *elem;
-	char *p = page;
-	char buf[FIELD_MAX_LENGTH + 1];
-
-	list_for_each(curr, proc_list_head) {
-		elem = list_entry(curr, struct proc_list, list);
-
-		if (p - page + LINE_MAX_LENGTH >= PAGE_SIZE)
-			break;
-
-		if(!strlen(elem->tag))
-			p += sprintf(p, "\n");
-		else
-			p += sprintf(p, "%-*.*s %.*s\n",
-				TAG_MAX_LENGTH, TAG_MAX_LENGTH,
-				elem->tag, FIELD_MAX_LENGTH,
-				elem->func(elem->data, elem->len, buf));
-	}
-
-	*p = '\0';
-
-	return e1000_proc_read(page, start, off, count, eof);
-}
-
-static int
-e1000_proc_single_read(char *page, char **start, off_t off,
-                       int count, int *eof, void *data)
-{
-	struct proc_list *elem = data;
-
-	sprintf(page, "%.*s", FIELD_MAX_LENGTH, elem->func(elem->data,
-	        elem->len, page));
-
-	return e1000_proc_read(page, start, off, count, eof);
-}
-
-static void
-e1000_proc_dirs_free(char *name, struct list_head *proc_list_head)
-{
-	struct proc_dir_entry *intel_proc_dir, *proc_dir;
-	char info_name[strlen(name) + strlen(".info")];
-
-	for(intel_proc_dir = proc_net->subdir; intel_proc_dir;
-		intel_proc_dir = intel_proc_dir->next) {
-		if((intel_proc_dir->namelen == strlen(ADAPTERS_PROC_DIR)) &&
-		   !memcmp(intel_proc_dir->name, ADAPTERS_PROC_DIR, strlen(ADAPTERS_PROC_DIR)))
-			break;
-	}
-
-	if(!intel_proc_dir)
-		return;
-
-	for(proc_dir = intel_proc_dir->subdir; proc_dir;
-		proc_dir = proc_dir->next) {
-		if ((proc_dir->namelen == strlen(name)) &&
-		    !memcmp(proc_dir->name, name, strlen(name)))
-			break;
-	}
-
-	if(proc_dir) {
-		struct list_head *curr;
-		struct proc_list *elem;
-
-		list_for_each(curr, proc_list_head) {
-			elem = list_entry(curr, struct proc_list, list);
-			remove_proc_entry(elem->tag, proc_dir);
-		}
-
-		strcpy(info_name, name);
-		strcat(info_name, ".info");
-
-		remove_proc_entry(info_name, intel_proc_dir);
-		remove_proc_entry(name, intel_proc_dir);
-	}
-
-	/* If the intel dir is empty, remove it */
-
-	for(proc_dir = intel_proc_dir->subdir; proc_dir;
-		proc_dir = proc_dir->next) {
-
-		/* ignore . and .. */
-
-		if(*(proc_dir->name) == '.')
-			continue;
-		break;
-	}
-
-	if(!proc_dir)
-		remove_proc_entry(ADAPTERS_PROC_DIR, proc_net);
-}
-
-
-static int
-e1000_proc_singles_create(struct proc_dir_entry *parent,
-                          struct list_head *proc_list_head)
-{
-	struct list_head *curr;
-	struct proc_list *elem;
-
-	list_for_each(curr, proc_list_head) {
-		struct proc_dir_entry *proc_entry;
-
-		elem = list_entry(curr, struct proc_list, list);
-
-		if(!strlen(elem->tag))
-			continue;
-
-		if(!(proc_entry =
-			create_proc_entry(elem->tag, S_IFREG, parent)))
-			return 0;
-
-		proc_entry->read_proc = e1000_proc_single_read;
-		proc_entry->data = elem;
-		SET_MODULE_OWNER(proc_entry);
-	}
-
-	return 1;
-}
-
-static void
-e1000_proc_dirs_create(void *data, char *name,
-                       struct list_head *proc_list_head)
-{
-	struct proc_dir_entry *intel_proc_dir, *proc_dir, *info_entry;
-	char info_name[strlen(name) + strlen(".info")];
-
-	for(intel_proc_dir = proc_net->subdir; intel_proc_dir;
-		intel_proc_dir = intel_proc_dir->next) {
-		if((intel_proc_dir->namelen == strlen(ADAPTERS_PROC_DIR)) &&
-		   !memcmp(intel_proc_dir->name, ADAPTERS_PROC_DIR, strlen(ADAPTERS_PROC_DIR)))
-			break;
-	}
-
-	if(!intel_proc_dir)
-		if(!(intel_proc_dir =
-			create_proc_entry(ADAPTERS_PROC_DIR,
-				S_IFDIR, proc_net)))
-			return;
-
-	if(!(proc_dir =
-		create_proc_entry(name, S_IFDIR, intel_proc_dir)))
-		return;
-	SET_MODULE_OWNER(proc_dir);
-
-	if(!e1000_proc_singles_create(proc_dir, proc_list_head))
-		return;
-
-	strcpy(info_name, name);
-	strcat(info_name, ".info");
-
-	if(!(info_entry =
-		create_proc_entry(info_name, S_IFREG, intel_proc_dir)))
-		return;
-	SET_MODULE_OWNER(info_entry);
-
-	info_entry->read_proc = e1000_proc_info_read;
-	info_entry->data = proc_list_head;
-}
-
-static void
-e1000_proc_list_add(struct list_head *proc_list_head, char *tag,
-                    void *data, size_t len,
-		    char *(*func)(void *, size_t, char *))
-{
-	struct proc_list *new = (struct proc_list *)
-		kmalloc(sizeof(struct proc_list), GFP_KERNEL);
-
-	if(!new)
-		return;
-
-	strncpy(new->tag, tag, TAG_MAX_LENGTH);
-	new->data = data;
-	new->len  = len;
-	new->func = func;
-
-	list_add_tail(&new->list, proc_list_head);
-}
-
-static void
-e1000_proc_list_free(struct list_head *proc_list_head)
-{
-	struct proc_list *elem;
-
-	while(!list_empty(proc_list_head)) {
-		elem = list_entry(proc_list_head->next, struct proc_list, list);
-		list_del(&elem->list);
-		kfree(elem);
-	}
-}
-
-/*
- * General purpose formating functions
- */
-
-static char *
-e1000_proc_str(void *data, size_t len, char *buf)
-{
-	sprintf(buf, "%s", (char *)data);
-	return buf;
-}
-
-static char *
-e1000_proc_hex(void *data, size_t len, char *buf)
-{
-	switch(len) {
-	case sizeof(uint8_t):
-		sprintf(buf, "0x%02x", *(uint8_t *)data);
-		break;
-	case sizeof(uint16_t):
-		sprintf(buf, "0x%04x", *(uint16_t *)data);
-		break;
-	case sizeof(uint32_t):
-		sprintf(buf, "0x%08x", *(uint32_t *)data);
-		break;
-	case sizeof(uint64_t):
-		sprintf(buf, "0x%08Lx", (unsigned long long)*(uint64_t *)data);
-		break;
-	}
-	return buf;
-}
-
-static char *
-e1000_proc_unsigned(void *data, size_t len, char *buf)
-{
-	switch(len) {
-	case sizeof(uint8_t):
-		sprintf(buf, "%u", *(uint8_t *)data);
-		break;
-	case sizeof(uint16_t):
-		sprintf(buf, "%u", *(uint16_t *)data);
-		break;
-	case sizeof(uint32_t):
-		sprintf(buf, "%u", *(uint32_t *)data);
-		break;
-	case sizeof(uint64_t):
-		sprintf(buf, "%Lu", (unsigned long long)*(uint64_t *)data);
-		break;
-	}
-	return buf;
-}
-
-/*
- * Specific formating functions
- */
-
-static char *
-e1000_proc_part_number(void *data, size_t len, char *buf)
-{
-	sprintf(buf, "%06x-%03x", *(uint32_t *)data >> 8,
-	        *(uint32_t *)data & 0x000000FF);
-	return buf;
-}
-
-static char *
-e1000_proc_slot(void *data, size_t len, char *buf)
-{
-	struct e1000_adapter *adapter = data;
-	sprintf(buf, "%u", PCI_SLOT(adapter->pdev->devfn));
-	return buf;
-}
-
-static char *
-e1000_proc_bus_type(void *data, size_t len, char *buf)
-{
-	e1000_bus_type bus_type = *(e1000_bus_type *)data;
-	sprintf(buf,
-		bus_type == e1000_bus_type_pci  ? "PCI"   :
-		bus_type == e1000_bus_type_pcix ? "PCI-X" :
-		"UNKNOWN");
-	return buf;
-}
-
-static char *
-e1000_proc_bus_speed(void *data, size_t len, char *buf)
-{
-	e1000_bus_speed bus_speed = *(e1000_bus_speed *)data;
-	sprintf(buf,
-		bus_speed == e1000_bus_speed_33  ? "33MHz"  :
-		bus_speed == e1000_bus_speed_66  ? "66MHz"  :
-		bus_speed == e1000_bus_speed_100 ? "100MHz" :
-		bus_speed == e1000_bus_speed_133 ? "133MHz" :
-		"UNKNOWN");
-	return buf;
-}
-
-static char *
-e1000_proc_bus_width(void *data, size_t len, char *buf)
-{
-	e1000_bus_width bus_width = *(e1000_bus_width *)data;
-	sprintf(buf,
-		bus_width == e1000_bus_width_32 ? "32-bit"   :
-		bus_width == e1000_bus_width_64 ? "64-bit" :
-		"UNKNOWN");
-	return buf;
-}
-
-static char *
-e1000_proc_hwaddr(void *data, size_t len, char *buf)
-{
-	unsigned char *hwaddr = data;
-	sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X",
-		hwaddr[0], hwaddr[1], hwaddr[2],
-		hwaddr[3], hwaddr[4], hwaddr[5]);
-	return buf;
-}
-
-static char *
-e1000_proc_link(void *data, size_t len, char *buf)
-{
-	struct e1000_adapter *adapter = data;
-	sprintf(buf, netif_running(adapter->netdev) ?
-		netif_carrier_ok(adapter->netdev) ?
-		"up" : "down" : "N/A");
-	return buf;
-}
-
-static char *
-e1000_proc_link_speed(void *data, size_t len, char *buf)
-{
-	uint16_t link_speed = *(uint16_t *)data;
-	sprintf(buf, link_speed ? "%u" : "N/A", link_speed);
-	return buf;
-}
-
-static char *
-e1000_proc_link_duplex(void *data, size_t len, char *buf)
-{
-	uint16_t link_duplex = *(uint16_t *)data;
-	sprintf(buf,
-		link_duplex == FULL_DUPLEX ? "Full" :
-		link_duplex == HALF_DUPLEX ? "Half" :
-		"N/A");
-	return buf;
-}
-
-static char *
-e1000_proc_state(void *data, size_t len, char *buf)
-{
-	struct e1000_adapter *adapter = data;
-	sprintf(buf, adapter->netdev->flags & IFF_UP ? "up" : "down");
-	return buf;
-}
-
-static char *
-e1000_proc_media_type(void *data, size_t len, char *buf)
-{
-	struct e1000_adapter *adapter = data;
-	sprintf(buf,
-		adapter->hw.media_type == e1000_media_type_copper ?
-		"Copper" : "Fiber");
-	return buf;
-}
-
-static char *
-e1000_proc_cable_length(void *data, size_t len, char *buf)
-{
-	struct e1000_adapter *adapter = data;
-	e1000_cable_length cable_length = adapter->phy_info.cable_length;
-	sprintf(buf, "%s%s",
-		cable_length == e1000_cable_length_50      ? "0-50"    :
-		cable_length == e1000_cable_length_50_80   ? "50-80"   :
-		cable_length == e1000_cable_length_80_110  ? "80-110"  :
-		cable_length == e1000_cable_length_110_140 ? "110-140" :
-		cable_length == e1000_cable_length_140     ? "> 140"   :
-		"Unknown",
-		cable_length != e1000_cable_length_undefined ?
-		" Meters (+/- 20 Meters)" : "");
-	return buf;
-}
-
-static char *
-e1000_proc_extended(void *data, size_t len, char *buf)
-{
-	struct e1000_adapter *adapter = data;
-	e1000_10bt_ext_dist_enable dist_enable =
-		adapter->phy_info.extended_10bt_distance;
-	sprintf(buf,
-		dist_enable == e1000_10bt_ext_dist_enable_normal ? "Disabled" :
-		dist_enable == e1000_10bt_ext_dist_enable_lower  ? "Enabled"  :
-		"Unknown");
-	return buf;
-}
-
-static char *
-e1000_proc_cable_polarity(void *data, size_t len, char *buf)
-{
-	struct e1000_adapter *adapter = data;
-	e1000_rev_polarity polarity = adapter->phy_info.cable_polarity;
-	sprintf(buf,
-		polarity == e1000_rev_polarity_normal   ? "Normal"   :
-		polarity == e1000_rev_polarity_reversed ? "Reversed" :
-		"Unknown");
-	return buf;
-}
-
-static char *
-e1000_proc_polarity_correction(void *data, size_t len, char *buf)
-{
-	struct e1000_adapter *adapter = data;
-	e1000_polarity_reversal correction =
-		adapter->phy_info.polarity_correction;
-	sprintf(buf,
-		correction == e1000_polarity_reversal_enabled  ? "Disabled" :
-		correction == e1000_polarity_reversal_disabled ? "Enabled"  :
-		"Unknown");
-	return buf;
-}
-
-static char *
-e1000_proc_mdi_x_enabled(void *data, size_t len, char *buf)
-{
-	struct e1000_adapter *adapter = data;
-	e1000_auto_x_mode mdix_mode = adapter->phy_info.mdix_mode;
-	sprintf(buf,
-		mdix_mode == e1000_auto_x_mode_manual_mdi  ? "MDI"   :
-		mdix_mode == e1000_auto_x_mode_manual_mdix ? "MDI-X" :
-		"Unknown");
-	return buf;
-}
-
-static char *
-e1000_proc_rx_status(void *data, size_t len, char *buf)
-{
-	e1000_1000t_rx_status rx_status = *(e1000_1000t_rx_status *)data;
-	sprintf(buf,
-		rx_status == e1000_1000t_rx_status_not_ok ? "NOT_OK" :
-		rx_status == e1000_1000t_rx_status_ok     ? "OK"     :
-		"Unknown");
-	return buf;
-}
-
-/*
- * e1000_proc_list_setup - build link list of proc praramters
- * @adapter: board private structure
- *
- * Order matters - ethx.info entries are ordered in the order links
- * are added to list.
- */
-
-#define LIST_ADD_F(T,D,F) \
-	e1000_proc_list_add(proc_list_head, (T), (D), sizeof(*(D)), (F))
-#define LIST_ADD_BLANK() LIST_ADD_F("", NULL, NULL)
-#define LIST_ADD_S(T,D) LIST_ADD_F((T), (D), e1000_proc_str)
-#define LIST_ADD_H(T,D) LIST_ADD_F((T), (D), e1000_proc_hex)
-#define LIST_ADD_U(T,D) LIST_ADD_F((T), (D), e1000_proc_unsigned)
-
-static void
-e1000_proc_list_setup(struct e1000_adapter *adapter)
-{
-	struct e1000_hw *hw = &adapter->hw;
-	struct list_head *proc_list_head = &adapter->proc_list_head;
-
-	INIT_LIST_HEAD(proc_list_head);
-
-	LIST_ADD_S("Description", adapter->id_string);
-	LIST_ADD_F("Part_Number", &adapter->part_num, e1000_proc_part_number);
-	LIST_ADD_S("Driver_Name", e1000_driver_name);
-	LIST_ADD_S("Driver_Version", e1000_driver_version);
-	LIST_ADD_H("PCI_Vendor", &hw->vendor_id);
-	LIST_ADD_H("PCI_Device_ID", &hw->device_id);
-	LIST_ADD_H("PCI_Subsystem_Vendor", &hw->subsystem_vendor_id);
-	LIST_ADD_H("PCI_Subsystem_ID", &hw->subsystem_id);
-	LIST_ADD_H("PCI_Revision_ID", &hw->revision_id);
-	LIST_ADD_U("PCI_Bus", &adapter->pdev->bus->number);
-	LIST_ADD_F("PCI_Slot", adapter, e1000_proc_slot);
-
-	if(adapter->hw.mac_type >= e1000_82543) {
-		LIST_ADD_F("PCI_Bus_Type",
-		           &hw->bus_type, e1000_proc_bus_type);
-		LIST_ADD_F("PCI_Bus_Speed",
-		           &hw->bus_speed, e1000_proc_bus_speed);
-		LIST_ADD_F("PCI_Bus_Width",
-		           &hw->bus_width, e1000_proc_bus_width);
-	}
-
-	LIST_ADD_U("IRQ", &adapter->pdev->irq);
-	LIST_ADD_S("System_Device_Name", adapter->ifname);
-	LIST_ADD_F("Current_HWaddr",
-	            adapter->netdev->dev_addr, e1000_proc_hwaddr);
-	LIST_ADD_F("Permanent_HWaddr",
-	            adapter->hw.perm_mac_addr, e1000_proc_hwaddr);
-
-	LIST_ADD_BLANK();
-
-	LIST_ADD_F("Link", adapter, e1000_proc_link);
-	LIST_ADD_F("Speed", &adapter->link_speed, e1000_proc_link_speed);
-	LIST_ADD_F("Duplex", &adapter->link_duplex, e1000_proc_link_duplex);
-	LIST_ADD_F("State", adapter, e1000_proc_state);
-
-	LIST_ADD_BLANK();
-
-	/* Standard net device stats */
-	LIST_ADD_U("Rx_Packets", &adapter->net_stats.rx_packets);
-	LIST_ADD_U("Tx_Packets", &adapter->net_stats.tx_packets);
-	LIST_ADD_U("Rx_Bytes", &adapter->net_stats.rx_bytes);
-	LIST_ADD_U("Tx_Bytes", &adapter->net_stats.tx_bytes);
-	LIST_ADD_U("Rx_Errors", &adapter->net_stats.rx_errors);
-	LIST_ADD_U("Tx_Errors", &adapter->net_stats.tx_errors);
-	LIST_ADD_U("Rx_Dropped", &adapter->net_stats.rx_dropped);
-	LIST_ADD_U("Tx_Dropped", &adapter->net_stats.tx_dropped);
-
-	LIST_ADD_U("Multicast", &adapter->net_stats.multicast);
-	LIST_ADD_U("Collisions", &adapter->net_stats.collisions);
-
-	LIST_ADD_U("Rx_Length_Errors", &adapter->net_stats.rx_length_errors);
-	LIST_ADD_U("Rx_Over_Errors", &adapter->net_stats.rx_over_errors);
-	LIST_ADD_U("Rx_CRC_Errors", &adapter->net_stats.rx_crc_errors);
-	LIST_ADD_U("Rx_Frame_Errors", &adapter->net_stats.rx_frame_errors);
-	LIST_ADD_U("Rx_FIFO_Errors", &adapter->net_stats.rx_fifo_errors);
-	LIST_ADD_U("Rx_Missed_Errors", &adapter->net_stats.rx_missed_errors);
-
-	LIST_ADD_U("Tx_Aborted_Errors", &adapter->net_stats.tx_aborted_errors);
-	LIST_ADD_U("Tx_Carrier_Errors", &adapter->net_stats.tx_carrier_errors);
-	LIST_ADD_U("Tx_FIFO_Errors", &adapter->net_stats.tx_fifo_errors);
-	LIST_ADD_U("Tx_Heartbeat_Errors",
-	           &adapter->net_stats.tx_heartbeat_errors);
-	LIST_ADD_U("Tx_Window_Errors", &adapter->net_stats.tx_window_errors);
-
-	/* 8254x-specific stats */
-	LIST_ADD_U("Tx_Abort_Late_Coll", &adapter->stats.latecol);
-	LIST_ADD_U("Tx_Deferred_Ok", &adapter->stats.dc);
-	LIST_ADD_U("Tx_Single_Coll_Ok", &adapter->stats.scc);
-	LIST_ADD_U("Tx_Multi_Coll_Ok", &adapter->stats.mcc);
-	LIST_ADD_U("Rx_Long_Length_Errors", &adapter->stats.roc);
-	LIST_ADD_U("Rx_Short_Length_Errors", &adapter->stats.ruc);
-
-	/* The 82542 does not have an alignment error count register */
-	if(adapter->hw.mac_type >= e1000_82543)
-		LIST_ADD_U("Rx_Align_Errors", &adapter->stats.algnerrc);
-
-	LIST_ADD_U("Rx_Flow_Control_XON", &adapter->stats.xonrxc);
-	LIST_ADD_U("Rx_Flow_Control_XOFF", &adapter->stats.xoffrxc);
-	LIST_ADD_U("Tx_Flow_Control_XON", &adapter->stats.xontxc);
-	LIST_ADD_U("Tx_Flow_Control_XOFF", &adapter->stats.xofftxc);
-	LIST_ADD_U("Rx_CSum_Offload_Good", &adapter->hw_csum_good);
-	LIST_ADD_U("Rx_CSum_Offload_Errors", &adapter->hw_csum_err);
-
-	LIST_ADD_BLANK();
-
-	/* Cable diags */
-	LIST_ADD_F("PHY_Media_Type", adapter, e1000_proc_media_type);
-	if(adapter->hw.media_type == e1000_media_type_copper) {
-		LIST_ADD_F("PHY_Cable_Length",
-		           adapter, e1000_proc_cable_length);
-		LIST_ADD_F("PHY_Extended_10Base_T_Distance",
-		           adapter, e1000_proc_extended);
-		LIST_ADD_F("PHY_Cable_Polarity",
-		           adapter, e1000_proc_cable_polarity);
-		LIST_ADD_F("PHY_Disable_Polarity_Correction",
-		           adapter, e1000_proc_polarity_correction);
-		LIST_ADD_U("PHY_Idle_Errors",
-		           &adapter->phy_stats.idle_errors);
-		LIST_ADD_U("PHY_Receive_Errors",
-		           &adapter->phy_stats.receive_errors);
-		LIST_ADD_F("PHY_MDI_X_Enabled",
-		           adapter, e1000_proc_mdi_x_enabled);
-		LIST_ADD_F("PHY_Local_Receiver_Status",
-		           &adapter->phy_info.local_rx,
-			   e1000_proc_rx_status);
-		LIST_ADD_F("PHY_Remote_Receiver_Status",
-		           &adapter->phy_info.remote_rx,
-			   e1000_proc_rx_status);
-	}
-
-}
-
-/*
- * e1000_proc_dev_setup - create proc fs nodes and link list
- * @adapter: board private structure
- */
-
-void
-e1000_proc_dev_setup(struct e1000_adapter *adapter)
-{
-	e1000_proc_list_setup(adapter);
-
-	e1000_proc_dirs_create(adapter,
-	                       adapter->ifname,
-	                       &adapter->proc_list_head);
-}
-
-/*
- * e1000_proc_dev_free - free proc fs nodes and link list
- * @adapter: board private structure
- */
-
-void
-e1000_proc_dev_free(struct e1000_adapter *adapter)
-{
-	e1000_proc_dirs_free(adapter->ifname, &adapter->proc_list_head);
-
-	e1000_proc_list_free(&adapter->proc_list_head);
-}
-
-#else /* CONFIG_PROC_FS */
-
-void e1000_proc_dev_setup(struct e1000_adapter *adapter) {}
-void e1000_proc_dev_free(struct e1000_adapter *adapter) {}
-
-#endif /* CONFIG_PROC_FS */
-
diff -urN linux-2.4.21-pre3/drivers/net/mac8390.c linux-2.4.21-pre4/drivers/net/mac8390.c
--- linux-2.4.21-pre3/drivers/net/mac8390.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/drivers/net/mac8390.c	Tue Jan 28 19:44:30 2003
@@ -0,0 +1,752 @@
+/* mac8390.c: New driver for 8390-based Nubus (or Nubus-alike)
+   Ethernet cards on Linux */
+/* Based on the former daynaport.c driver, by Alan Cox.  Some code
+   taken from or inspired by skeleton.c by Donald Becker, acenic.c by
+   Jes Sorensen, and ne2k-pci.c by Donald Becker and Paul Gortmaker.
+
+   This software may be used and distributed according to the terms of
+   the GNU Public License, incorporated herein by reference.  */
+
+/* 2000-02-28: support added for Dayna and Kinetics cards by 
+   A.G.deWijn@phys.uu.nl */
+/* 2000-04-04: support added for Dayna2 by bart@etpmod.phys.tue.nl */
+/* 2001-04-18: support for DaynaPort E/LC-M by rayk@knightsmanor.org */
+/* 2001-05-15: support for Cabletron ported from old daynaport driver
+ * and fixed access to Sonic Sys card which masquerades as a Farallon 
+ * by rayk@knightsmanor.org */
+
+#include <linux/version.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/nubus.h>
+#include <linux/in.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/hwtest.h>
+#include <asm/macints.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include "8390.h"
+
+#if (LINUX_VERSION_CODE < 0x02030e)
+#define net_device device
+#endif
+
+#define WD_START_PG			0x00	/* First page of TX buffer */
+#define CABLETRON_RX_START_PG		0x00    /* First page of RX buffer */
+#define CABLETRON_RX_STOP_PG		0x30    /* Last page +1 of RX ring */
+#define CABLETRON_TX_START_PG		CABLETRON_RX_STOP_PG  /* First page of TX buffer */
+
+/* Unfortunately it seems we have to hardcode these for the moment */
+/* Shouldn't the card know about this? Does anyone know where to read it off the card? Do we trust the data provided by the card? */
+
+#define DAYNA_8390_BASE		0x80000
+#define DAYNA_8390_MEM		0x00000
+
+#define KINETICS_8390_BASE	0x80000
+#define KINETICS_8390_MEM	0x00000
+
+#define CABLETRON_8390_BASE	0x90000	
+#define CABLETRON_8390_MEM	0x00000
+
+enum mac8390_type {
+	MAC8390_NONE = -1,
+	MAC8390_APPLE,
+	MAC8390_ASANTE,
+	MAC8390_FARALLON,  /* Apple, Asante, and Farallon are all compatible */
+	MAC8390_CABLETRON,
+	MAC8390_DAYNA,
+	MAC8390_INTERLAN,
+	MAC8390_KINETICS,
+	MAC8390_FOCUS,
+	MAC8390_SONICSYS,
+	MAC8390_DAYNA2,
+	MAC8390_DAYNA3,
+};
+
+static const char * cardname[] = {
+	"apple",
+	"asante",
+	"farallon",
+	"cabletron",
+	"dayna",
+	"interlan",
+	"kinetics",
+	"focus",
+	"sonic systems",
+	"dayna2",
+	"dayna_lc",
+};
+
+static int word16[] = {
+	1, /* apple */
+	1, /* asante */
+	1, /* farallon */
+	1, /* cabletron */
+	0, /* dayna */
+	1, /* interlan */
+	0, /* kinetics */
+	1, /* focus (??) */
+	1, /* sonic systems  */
+	1, /* dayna2 */
+	1, /* dayna-lc */
+};
+
+/* on which cards do we use NuBus resources? */
+static int useresources[] = {
+	1, /* apple */
+	1, /* asante */
+	1, /* farallon */
+	0, /* cabletron */
+	0, /* dayna */
+	0, /* interlan */
+	0, /* kinetics */
+	0, /* focus (??) */
+	1, /* sonic systems */
+	1, /* dayna2 */
+	1, /* dayna-lc */
+};
+
+static const char __initdata * version =
+	"mac8390.c: v0.4 2001-05-15 David Huggins-Daines <dhd@debian.org> and others\n";
+		
+extern int mac8390_probe(struct net_device * dev);
+extern enum mac8390_type mac8390_ident(struct nubus_dev * dev);
+extern int mac8390_memsize(unsigned long membase);
+extern int mac8390_memtest(struct net_device * dev);
+extern int mac8390_initdev(struct net_device * dev, struct nubus_dev * ndev,
+			   enum mac8390_type type);
+
+static int mac8390_open(struct net_device * dev);
+static int mac8390_close(struct net_device * dev);
+static void mac8390_no_reset(struct net_device *dev);
+
+/* Sane (32-bit chunk memory read/write) - Apple/Asante/Farallon do this*/
+static void sane_get_8390_hdr(struct net_device *dev,
+			      struct e8390_pkt_hdr *hdr, int ring_page);
+static void sane_block_input(struct net_device * dev, int count,
+			     struct sk_buff * skb, int ring_offset);
+static void sane_block_output(struct net_device * dev, int count,
+			      const unsigned char * buf, const int start_page);
+
+/* dayna_memcpy to and from card */
+static void dayna_memcpy_fromcard(struct net_device *dev, void *to,
+				int from, int count);
+static void dayna_memcpy_tocard(struct net_device *dev, int to,
+			      const void *from, int count);
+
+/* Dayna - Dayna/Kinetics use this */
+static void dayna_get_8390_hdr(struct net_device *dev,
+			       struct e8390_pkt_hdr *hdr, int ring_page);
+static void dayna_block_input(struct net_device *dev, int count,
+			      struct sk_buff *skb, int ring_offset);
+static void dayna_block_output(struct net_device *dev, int count,
+			       const unsigned char *buf, int start_page);
+
+#define memcpy_fromio(a,b,c)	memcpy((a),(void *)(b),(c))
+#define memcpy_toio(a,b,c)	memcpy((void *)(a),(b),(c))
+
+/* Slow Sane (16-bit chunk memory read/write) Cabletron uses this */
+static void slow_sane_get_8390_hdr(struct net_device *dev,
+				   struct e8390_pkt_hdr *hdr, int ring_page);
+static void slow_sane_block_input(struct net_device *dev, int count,
+				  struct sk_buff *skb, int ring_offset);
+static void slow_sane_block_output(struct net_device *dev, int count,
+				   const unsigned char *buf, int start_page);
+static void word_memcpy_tocard(void *tp, const void *fp, int count);
+static void word_memcpy_fromcard(void *tp, const void *fp, int count);
+
+enum mac8390_type __init mac8390_ident(struct nubus_dev * dev)
+{
+	if (dev->dr_sw == NUBUS_DRSW_ASANTE)
+		return MAC8390_ASANTE;
+	if (dev->dr_sw == NUBUS_DRSW_FARALLON) 
+		return MAC8390_FARALLON;
+	if (dev->dr_sw == NUBUS_DRSW_KINETICS)
+		return MAC8390_KINETICS;
+	if (dev->dr_sw == NUBUS_DRSW_DAYNA)
+		return MAC8390_DAYNA;
+	if (dev->dr_sw == NUBUS_DRSW_DAYNA2)
+		return MAC8390_DAYNA2;
+	if (dev->dr_sw == NUBUS_DRSW_DAYNA_LC)
+		return MAC8390_DAYNA3;
+	if (dev->dr_hw == NUBUS_DRHW_CABLETRON)
+		return MAC8390_CABLETRON;
+	return MAC8390_NONE;
+}
+
+int __init mac8390_memsize(unsigned long membase)
+{
+	unsigned long flags;
+	int i, j;
+	
+	save_flags(flags); cli();
+	/* Check up to 32K in 4K increments */
+	for (i = 0; i < 8; i++) {
+		volatile unsigned short *m = (unsigned short *) (membase + (i * 0x1000));
+
+		/* Unwriteable - we have a fully decoded card and the
+		   RAM end located */
+		if (hwreg_present(m) == 0)
+			break;
+		
+		/* write a distinctive byte */
+		*m = 0xA5A0 | i;
+		/* check that we read back what we wrote */
+		if (*m != (0xA5A0 | i))
+			break;
+
+		/* check for partial decode and wrap */
+		for (j = 0; j < i; j++) {
+			volatile unsigned short *p = (unsigned short *) (membase + (j * 0x1000));
+			if (*p != (0xA5A0 | j))
+				break;
+ 		}
+ 	}
+	restore_flags(flags);
+	/* in any case, we stopped once we tried one block too many,
+           or once we reached 32K */
+ 	return i * 0x1000;
+}
+
+static int probed __initdata = 0;
+
+int __init mac8390_probe(struct net_device * dev)
+{
+	volatile unsigned short *i;
+	int boards_found = 0;
+	int version_disp = 0;
+	struct nubus_dev * ndev = NULL;
+	
+	struct nubus_dir dir;
+	struct nubus_dirent ent;
+	int offset;
+
+	enum mac8390_type cardtype;
+
+	if (probed)
+		return -ENODEV;
+	probed++;
+
+	/* probably should check for Nubus instead */
+
+	if (!MACH_IS_MAC)
+		return -ENODEV;
+
+	while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK, NUBUS_TYPE_ETHERNET, ndev))) {
+		
+		dev = NULL;
+		
+		if ((cardtype = mac8390_ident(ndev)) == MAC8390_NONE)
+			continue;
+
+		dev = init_etherdev(dev, 0);
+		if (dev == NULL) {
+			printk(KERN_ERR "Unable to allocate etherdev"
+					"structure!\n");
+			return -ENOMEM;
+		}
+
+		if (version_disp == 0) {
+			version_disp = 1;
+			printk(version);
+		}
+
+		dev->irq = SLOT2IRQ(ndev->board->slot);
+		/* This is getting to be a habit */
+		dev->base_addr = ndev->board->slot_addr | ((ndev->board->slot&0xf) << 20);
+
+		/* Get some Nubus info - we will trust the card's idea
+		   of where its memory and registers are. */
+
+		if (nubus_get_func_dir(ndev, &dir) == -1) {
+			printk(KERN_ERR "%s: Unable to get Nubus functional"
+					" directory for slot %X!\n",
+			       dev->name, ndev->board->slot);
+			continue;
+		}
+		
+		/* Get the MAC address */
+		if ((nubus_find_rsrc(&dir, NUBUS_RESID_MAC_ADDRESS, &ent)) == -1) {
+			printk(KERN_INFO "%s: Couldn't get MAC address!\n",
+					dev->name);
+			continue;
+		} else {
+			nubus_get_rsrc_mem(dev->dev_addr, &ent, 6);
+			/* Some Sonic Sys cards masquerade as Farallon */
+			if (cardtype == MAC8390_FARALLON && 
+					dev->dev_addr[0] == 0x0 &&
+					dev->dev_addr[1] == 0x40 &&
+					dev->dev_addr[2] == 0x10) {
+				/* This is really Sonic Sys card */
+				cardtype = MAC8390_SONICSYS;
+			}
+		}
+		
+		if (useresources[cardtype] == 1) {
+			nubus_rewinddir(&dir);
+			if (nubus_find_rsrc(&dir, NUBUS_RESID_MINOR_BASEOS, &ent) == -1) {
+				printk(KERN_ERR "%s: Memory offset resource"
+						" for slot %X not found!\n",
+				       dev->name, ndev->board->slot);
+				continue;
+			}
+			nubus_get_rsrc_mem(&offset, &ent, 4);
+			dev->mem_start = dev->base_addr + offset;
+			/* yes, this is how the Apple driver does it */
+			dev->base_addr = dev->mem_start + 0x10000;
+			nubus_rewinddir(&dir);
+			if (nubus_find_rsrc(&dir, NUBUS_RESID_MINOR_LENGTH, &ent) == -1) {
+				printk(KERN_INFO "%s: Memory length resource"
+						 " for slot %X not found"
+						 ", probing\n",
+				       dev->name, ndev->board->slot);
+				offset = mac8390_memsize(dev->mem_start);
+				} else {
+					nubus_get_rsrc_mem(&offset, &ent, 4);
+				}
+			dev->mem_end = dev->mem_start + offset;
+		} else {
+			switch (cardtype) {
+				case MAC8390_KINETICS:
+				case MAC8390_DAYNA: /* it's the same */
+					dev->base_addr = 
+						(int)(ndev->board->slot_addr +
+						DAYNA_8390_BASE);
+					dev->mem_start = 
+						(int)(ndev->board->slot_addr +
+						DAYNA_8390_MEM);
+					dev->mem_end =
+						dev->mem_start +
+						mac8390_memsize(dev->mem_start);
+					break;
+				case MAC8390_CABLETRON:
+					dev->base_addr =
+						(int)(ndev->board->slot_addr +
+						CABLETRON_8390_BASE);
+					dev->mem_start =
+						(int)(ndev->board->slot_addr +
+						CABLETRON_8390_MEM);
+					/* The base address is unreadable if 0x00
+					 * has been written to the command register
+					 * Reset the chip by writing E8390_NODMA +
+					 *   E8390_PAGE0 + E8390_STOP just to be
+					 *   sure
+					 */
+					i = (void *)dev->base_addr;
+					*i = 0x21;
+					dev->mem_end = 
+						dev->mem_start +
+						mac8390_memsize(dev->mem_start);
+					break;
+					
+				default:
+					printk(KERN_ERR "Card type %s is"
+							" unsupported, sorry\n",
+					       cardname[cardtype]);
+					return -ENODEV;
+			}
+		}
+
+		/* Do the nasty 8390 stuff */
+		if (mac8390_initdev(dev, ndev, cardtype))
+			continue;
+		boards_found++;
+	}
+
+	/* We're outta here */
+	if (boards_found > 0)
+		return 0;
+	else
+		return -ENODEV;
+}
+
+#ifdef MODULE
+#if LINUX_VERSION_CODE > 0x20118
+MODULE_AUTHOR("David Huggins-Daines <dhd@debian.org> and others");
+MODULE_DESCRIPTION("Macintosh NS8390-based Nubus Ethernet driver");
+MODUEL_LICENSE("GPL");
+#endif
+
+int init_module(void)
+{
+	if (mac8390_probe(NULL)) {
+		printk(KERN_NOTICE "mac8390.c: No useable cards found, driver NOT installed.\n");
+		return -ENODEV;
+	}
+	lock_8390_module();
+	return 0;
+}
+
+void cleanup_module(void)
+{
+	/* FIXME: should probably keep track of net_device structs
+           somewhere and unregister them here? */
+	unlock_8390_module();
+}
+
+#endif /* MODULE */
+
+int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * ndev,
+			    enum mac8390_type type)
+{
+	static u32 fwrd4_offsets[16]={
+		0,      4,      8,      12,
+		16,     20,     24,     28,
+		32,     36,     40,     44,
+		48,     52,     56,     60
+	};
+	static u32 back4_offsets[16]={
+		60,     56,     52,     48,
+		44,     40,     36,     32,
+		28,     24,     20,     16,
+		12,     8,      4,      0
+	};
+	static u32 fwrd2_offsets[16]={
+		0,      2,      4,      6,
+		8,     10,     12,     14,
+		16,    18,     20,     22,
+		24,    26,     28,     30
+	};
+
+	int access_bitmode;
+	
+	/* 8390 specific init for dev - allocates dev->priv */
+	if (ethdev_init(dev)) {
+		printk(KERN_ERR "%s: Unable to allocate memory for dev->priv!\n", dev->name);
+		return -ENOMEM;
+	}
+
+	/* Now fill in our stuff */
+	dev->open = &mac8390_open;
+	dev->stop = &mac8390_close;
+
+	/* GAR, ei_status is actually a macro even though it looks global */
+	ei_status.name = cardname[type];
+	ei_status.word16 = word16[type];
+
+	/* Cabletron's TX/RX buffers are backwards */
+	if (type == MAC8390_CABLETRON) {
+               ei_status.tx_start_page = CABLETRON_TX_START_PG;
+               ei_status.rx_start_page = CABLETRON_RX_START_PG;
+               ei_status.stop_page = CABLETRON_RX_STOP_PG;
+               dev->rmem_start = dev->mem_start;
+               dev->rmem_end = dev->mem_start + CABLETRON_RX_STOP_PG*256;
+	} else {
+               ei_status.tx_start_page = WD_START_PG;
+               ei_status.rx_start_page = WD_START_PG + TX_PAGES;
+               ei_status.stop_page = (dev->mem_end - dev->mem_start)/256;
+               dev->rmem_start = dev->mem_start + TX_PAGES*256;
+               dev->rmem_end = dev->mem_end;
+	}
+	
+	/* Fill in model-specific information and functions */
+	switch(type) {
+	case MAC8390_SONICSYS:
+		/* 16 bit card, register map is reversed */
+		ei_status.reset_8390 = &mac8390_no_reset;
+		ei_status.block_input = &slow_sane_block_input;
+		ei_status.block_output = &slow_sane_block_output;
+		ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
+		ei_status.reg_offset = back4_offsets;
+		access_bitmode = 0;
+		break;
+	case MAC8390_FARALLON:
+	case MAC8390_APPLE:
+	case MAC8390_ASANTE:
+	case MAC8390_DAYNA2:
+	case MAC8390_DAYNA3:
+		/* 32 bit card, register map is reversed */
+		/* sane */
+		ei_status.reset_8390 = &mac8390_no_reset;
+		ei_status.block_input = &sane_block_input;
+		ei_status.block_output = &sane_block_output;
+		ei_status.get_8390_hdr = &sane_get_8390_hdr;
+		ei_status.reg_offset = back4_offsets;
+		access_bitmode = 1;
+		break;
+	case MAC8390_CABLETRON:
+		/* 16 bit card, register map is short forward */
+		ei_status.reset_8390 = &mac8390_no_reset;
+		ei_status.block_input = &slow_sane_block_input;
+		ei_status.block_output = &slow_sane_block_output;
+		ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
+		ei_status.reg_offset = fwrd2_offsets;
+		access_bitmode = 0;
+		break;
+	case MAC8390_DAYNA:
+	case MAC8390_KINETICS:
+		/* 16 bit memory */
+		/* dayna and similar */
+		ei_status.reset_8390 = &mac8390_no_reset;
+		ei_status.block_input = &dayna_block_input;
+		ei_status.block_output = &dayna_block_output;
+		ei_status.get_8390_hdr = &dayna_get_8390_hdr;
+		ei_status.reg_offset = fwrd4_offsets;
+		access_bitmode = 0;
+		break;
+	default:
+		printk(KERN_ERR "Card type %s is unsupported, sorry\n", cardname[type]);
+		return -ENODEV;
+	}
+		
+	NS8390_init(dev, 0);
+
+	/* Good, done, now spit out some messages */
+	printk(KERN_INFO "%s: %s in slot %X (type %s)\n",
+		   dev->name, ndev->board->name, ndev->board->slot, cardname[type]);
+	printk(KERN_INFO "MAC ");
+	{
+		int i;
+		for (i = 0; i < 6; i++) {
+			printk("%2.2x", dev->dev_addr[i]);
+			if (i < 5)
+				printk(":");
+		}
+	}
+	printk(" IRQ %d, shared memory at %#lx-%#lx,  %d-bit access.\n",
+		   dev->irq, dev->mem_start, dev->mem_end-1, 
+		   access_bitmode?32:16);
+	return 0;
+}
+
+static int mac8390_open(struct net_device *dev)
+{
+	ei_open(dev);
+	if (request_irq(dev->irq, ei_interrupt, 0, "8390 Ethernet", dev)) {
+		printk ("%s: unable to get IRQ %d.\n", dev->name, dev->irq);
+		return -EAGAIN;
+	}	
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int mac8390_close(struct net_device *dev)
+{
+	free_irq(dev->irq, dev);
+	ei_close(dev);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static void mac8390_no_reset(struct net_device *dev)
+{
+	ei_status.txing = 0;
+	if (ei_debug > 1)
+		printk("reset not supported\n");
+	return;
+}
+
+/* dayna_memcpy_fromio/dayna_memcpy_toio */
+/* directly from daynaport.c by Alan Cox */
+static void dayna_memcpy_fromcard(struct net_device *dev, void *to, int from, int count)
+{
+	volatile unsigned short *ptr;
+	unsigned short *target=to;
+	from<<=1;	/* word, skip overhead */
+	ptr=(unsigned short *)(dev->mem_start+from);
+	/* Leading byte? */
+	if (from&2) {
+		*((char *)target)++ = *(((char *)ptr++)-1);
+		count--;
+	}
+	while(count>=2)
+	{
+		*target++=*ptr++;	/* Copy and */
+		ptr++;			/* skip cruft */
+		count-=2;
+	}
+	/* Trailing byte? */
+	if(count)
+	{
+		/* Big endian */
+		unsigned short v=*ptr;
+		*((char *)target)=v>>8;
+	}
+}
+
+static void dayna_memcpy_tocard(struct net_device *dev, int to, const void *from, int count)
+{
+	volatile unsigned short *ptr;
+	const unsigned short *src=from;
+	to<<=1;	/* word, skip overhead */
+	ptr=(unsigned short *)(dev->mem_start+to);
+	/* Leading byte? */
+	if (to&2) { /* avoid a byte write (stomps on other data) */
+		ptr[-1] = (ptr[-1]&0xFF00)|*((unsigned char *)src)++;
+		ptr++;
+		count--;
+	}
+	while(count>=2)
+	{
+		*ptr++=*src++;		/* Copy and */
+		ptr++;			/* skip cruft */
+		count-=2;
+	}
+	/* Trailing byte? */
+	if(count)
+	{
+		/* Big endian */
+		unsigned short v=*src;
+		/* card doesn't like byte writes */
+		*ptr=(*ptr&0x00FF)|(v&0xFF00);
+	}
+}
+
+/* sane block input/output */
+static void sane_get_8390_hdr(struct net_device *dev,
+			      struct e8390_pkt_hdr *hdr, int ring_page)
+{
+	unsigned long hdr_start = (ring_page - WD_START_PG)<<8;
+	memcpy_fromio((void *)hdr, (char *)dev->mem_start + hdr_start, 4);
+	/* Fix endianness */
+	hdr->count = swab16(hdr->count);
+}
+
+static void sane_block_input(struct net_device *dev, int count,
+			     struct sk_buff *skb, int ring_offset)
+{
+	unsigned long xfer_base = ring_offset - (WD_START_PG<<8);
+	unsigned long xfer_start = xfer_base + dev->mem_start;
+
+	if (xfer_start + count > dev->rmem_end) {
+		/* We must wrap the input move. */
+		int semi_count = dev->rmem_end - xfer_start;
+		memcpy_fromio(skb->data, (char *)dev->mem_start + xfer_base, semi_count);
+		count -= semi_count;
+		memcpy_toio(skb->data + semi_count, (char *)dev->rmem_start, count);
+	} else {
+		memcpy_fromio(skb->data, (char *)dev->mem_start + xfer_base, count);
+	}
+}
+
+static void sane_block_output(struct net_device *dev, int count,
+			      const unsigned char *buf, int start_page)
+{
+	long shmem = (start_page - WD_START_PG)<<8;
+	
+	memcpy_toio((char *)dev->mem_start + shmem, buf, count);
+}
+
+/* dayna block input/output */
+static void dayna_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
+{
+	unsigned long hdr_start = (ring_page - WD_START_PG)<<8;
+
+	dayna_memcpy_fromcard(dev, (void *)hdr, hdr_start, 4);
+	/* Fix endianness */
+	hdr->count=(hdr->count&0xFF)<<8|(hdr->count>>8);
+}
+
+static void dayna_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
+{
+	unsigned long xfer_base = ring_offset - (WD_START_PG<<8);
+	unsigned long xfer_start = xfer_base+dev->mem_start;
+
+	/* Note the offset math is done in card memory space which is word
+	   per long onto our space. */
+	 
+	if (xfer_start + count > dev->rmem_end) 
+	{
+		/* We must wrap the input move. */
+		int semi_count = dev->rmem_end - xfer_start;
+		dayna_memcpy_fromcard(dev, skb->data, xfer_base, semi_count);
+		count -= semi_count;
+		dayna_memcpy_fromcard(dev, skb->data + semi_count, 
+			dev->rmem_start - dev->mem_start, count);
+	}
+	else
+	{
+		dayna_memcpy_fromcard(dev, skb->data, xfer_base, count);
+	}
+}
+
+static void dayna_block_output(struct net_device *dev, int count, const unsigned char *buf,
+				int start_page)
+{
+	long shmem = (start_page - WD_START_PG)<<8;
+	
+	dayna_memcpy_tocard(dev, shmem, buf, count);
+}
+
+/* Cabletron block I/O */
+static void slow_sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, 
+	int ring_page)
+{
+	unsigned long hdr_start = (ring_page - WD_START_PG)<<8;
+	word_memcpy_fromcard((void *)hdr, (char *)dev->mem_start+hdr_start, 4);
+	/* Register endianism - fix here rather than 8390.c */
+	hdr->count = (hdr->count&0xFF)<<8|(hdr->count>>8);
+}
+
+static void slow_sane_block_input(struct net_device *dev, int count, struct sk_buff *skb,
+	int ring_offset)
+{
+	unsigned long xfer_base = ring_offset - (WD_START_PG<<8);
+	unsigned long xfer_start = xfer_base+dev->mem_start;
+
+	if (xfer_start + count > dev->rmem_end)
+	{
+		/* We must wrap the input move. */
+		int semi_count = dev->rmem_end - xfer_start;
+		word_memcpy_fromcard(skb->data, (char *)dev->mem_start +
+			xfer_base, semi_count);
+		count -= semi_count;
+		word_memcpy_fromcard(skb->data + semi_count,
+			(char *)dev->rmem_start, count);
+	}
+	else
+	{
+		word_memcpy_fromcard(skb->data, (char *)dev->mem_start +
+			xfer_base, count);
+	}
+}
+
+static void slow_sane_block_output(struct net_device *dev, int count, const unsigned char *buf,
+	int start_page)
+{
+	long shmem = (start_page - WD_START_PG)<<8;
+
+	word_memcpy_tocard((char *)dev->mem_start + shmem, buf, count);
+}
+
+static void word_memcpy_tocard(void *tp, const void *fp, int count)
+{
+	volatile unsigned short *to = tp;
+	const unsigned short *from = fp;
+
+	count++;
+	count/=2;
+
+	while(count--)
+		*to++=*from++;
+}
+
+static void word_memcpy_fromcard(void *tp, const void *fp, int count)
+{
+	unsigned short *to = tp;
+	const volatile unsigned short *from = fp;
+
+	count++;
+	count/=2;
+
+	while(count--)
+		*to++=*from++;
+}
+
+	
diff -urN linux-2.4.21-pre3/drivers/net/ni5010.c linux-2.4.21-pre4/drivers/net/ni5010.c
--- linux-2.4.21-pre3/drivers/net/ni5010.c	Sun Sep 30 12:26:07 2001
+++ linux-2.4.21-pre4/drivers/net/ni5010.c	Tue Jan 28 19:44:30 2003
@@ -114,7 +114,7 @@
 
 static int	process_xmt_interrupt(struct net_device *dev);
 #define tx_done(dev) 1
-static void	hardware_send_packet(struct net_device *dev, char *buf, int length);
+static void	hardware_send_packet(struct net_device *dev, char *buf, int length, int pad);
 static void 	chipset_init(struct net_device *dev, int startp);
 static void	dump_packet(void *buf, int len);
 static void 	ni5010_show_registers(struct net_device *dev);
@@ -437,7 +437,7 @@
 	 */
 	
 	netif_stop_queue(dev);
-	hardware_send_packet(dev, (unsigned char *)skb->data, length);
+	hardware_send_packet(dev, (unsigned char *)skb->data, skb->len, length-skb->len);
 	dev->trans_start = jiffies;
 	dev_kfree_skb (skb);
 	return 0;
@@ -661,7 +661,7 @@
 	}
 }
 
-static void hardware_send_packet(struct net_device *dev, char *buf, int length)
+static void hardware_send_packet(struct net_device *dev, char *buf, int length, int pad)
 {
 	struct ni5010_local *lp = (struct ni5010_local *)dev->priv;
 	int ioaddr = dev->base_addr;
@@ -686,8 +686,8 @@
 	
 	if (NI5010_DEBUG > 3) dump_packet(buf, length);
 
-        buf_offs = NI5010_BUFSIZE - length;
-        lp->o_pkt_size = length;
+        buf_offs = NI5010_BUFSIZE - length - pad;
+        lp->o_pkt_size = length + pad;
 
 	save_flags(flags);	
 	cli();
@@ -698,6 +698,9 @@
 
 	outw(buf_offs, IE_GP); /* Point GP at start of packet */
 	outsb(IE_XBUF, buf, length); /* Put data in buffer */
+	while(pad--)
+		outb(0, IE_XBUF);
+		
 	outw(buf_offs, IE_GP); /* Rewrite where packet starts */
 
 	/* should work without that outb() (Crynwr used it) */
diff -urN linux-2.4.21-pre3/drivers/net/ni52.c linux-2.4.21-pre4/drivers/net/ni52.c
--- linux-2.4.21-pre3/drivers/net/ni52.c	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/drivers/net/ni52.c	Tue Jan 28 19:44:30 2003
@@ -1163,7 +1163,12 @@
 #endif
 	{
 		memcpy((char *)p->xmit_cbuffs[p->xmit_count],(char *)(skb->data),skb->len);
-		len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
+		len = skb->len;
+		if(len < ETH_ZLEN)
+		{
+			len = ETH_ZLEN;
+			memset((char *)p->xmit_cbuffs[p->xmit_count]+skb->len, 0, len - skb->len);
+		}
 
 #if (NUM_XMIT_BUFFS == 1)
 #	ifdef NO_NOPCOMMANDS
diff -urN linux-2.4.21-pre3/drivers/net/ni65.c linux-2.4.21-pre4/drivers/net/ni65.c
--- linux-2.4.21-pre3/drivers/net/ni65.c	Thu Nov 28 15:53:14 2002
+++ linux-2.4.21-pre4/drivers/net/ni65.c	Tue Jan 28 19:44:30 2003
@@ -1113,6 +1113,8 @@
 
 			memcpy((char *) p->tmdbounce[p->tmdbouncenum] ,(char *)skb->data,
 							 (skb->len > T_BUF_SIZE) ? T_BUF_SIZE : skb->len);
+			if(len > skb->len)
+				memset((char *)p->tmdbounce[p->tmdbouncenum]+skb->len, 0, len-skb->len);
 			dev_kfree_skb (skb);
 
 			save_flags(flags);
diff -urN linux-2.4.21-pre3/drivers/net/pcmcia/axnet_cs.c linux-2.4.21-pre4/drivers/net/pcmcia/axnet_cs.c
--- linux-2.4.21-pre3/drivers/net/pcmcia/axnet_cs.c	Thu Nov 28 15:53:14 2002
+++ linux-2.4.21-pre4/drivers/net/pcmcia/axnet_cs.c	Tue Jan 28 19:44:30 2003
@@ -1216,7 +1216,8 @@
 	struct ei_device *ei_local = (struct ei_device *) dev->priv;
 	int length, send_length, output_page;
 	unsigned long flags;
-
+	u8 packet[ETH_ZLEN];
+	
 	netif_stop_queue(dev);
 
 	length = skb->len;
@@ -1241,7 +1242,7 @@
 	ei_local->irqlock = 1;
 
 	send_length = ETH_ZLEN < length ? length : ETH_ZLEN;
-    
+	
 	/*
 	 * We have two Tx slots available for use. Find the first free
 	 * slot, and then perform some sanity checks. With two Tx bufs,
@@ -1286,7 +1287,15 @@
 	 * trigger the send later, upon receiving a Tx done interrupt.
 	 */
 
-	ei_block_output(dev, length, skb->data, output_page);
+	if(length == skb->len)
+		ei_block_output(dev, length, skb->data, output_page);
+	else
+	{
+		memset(packet, 0, ETH_ZLEN);
+		memcpy(packet, skb->data, skb->len);
+		ei_block_output(dev, length, packet, output_page);
+	}
+	
 	if (! ei_local->txing) 
 	{
 		ei_local->txing = 1;
diff -urN linux-2.4.21-pre3/drivers/net/ppp_generic.c linux-2.4.21-pre4/drivers/net/ppp_generic.c
--- linux-2.4.21-pre3/drivers/net/ppp_generic.c	Thu Nov 28 15:53:14 2002
+++ linux-2.4.21-pre4/drivers/net/ppp_generic.c	Tue Jan 28 19:44:30 2003
@@ -965,11 +965,10 @@
 		if (ppp->pass_filter.filter
 		    && sk_run_filter(skb, ppp->pass_filter.filter,
 				     ppp->pass_filter.len) == 0) {
-			if (ppp->debug & 1) {
+			if (ppp->debug & 1)
 				printk(KERN_DEBUG "PPP: outbound frame not passed\n");
-				kfree_skb(skb);
-				return;
-			}
+			kfree_skb(skb);
+			return;
 		}
 		/* if this packet passes the active filter, record the time */
 		if (!(ppp->active_filter.filter
diff -urN linux-2.4.21-pre3/drivers/net/sgiseeq.c linux-2.4.21-pre4/drivers/net/sgiseeq.c
--- linux-2.4.21-pre3/drivers/net/sgiseeq.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.21-pre4/drivers/net/sgiseeq.c	Tue Jan 28 19:44:30 2003
@@ -537,6 +537,8 @@
 	 *    added this new entry and restarted it.
 	 */
 	memcpy((char *)(long)td->buf_vaddr, skb->data, skblen);
+	if(len != skblen)
+		memset((char *)(long)td->buf_vaddr + skb->len, 0, len-skblen);
 	td->tdma.cntinfo = (len & HPCDMA_BCNT) |
 	                   (HPCDMA_XIU | HPCDMA_EOXP | HPCDMA_XIE | HPCDMA_EOX);
 	if (sp->tx_old != sp->tx_new) {
diff -urN linux-2.4.21-pre3/drivers/net/sk_g16.c linux-2.4.21-pre4/drivers/net/sk_g16.c
--- linux-2.4.21-pre3/drivers/net/sk_g16.c	Tue Oct 16 21:56:29 2001
+++ linux-2.4.21-pre4/drivers/net/sk_g16.c	Tue Jan 28 19:44:30 2003
@@ -1256,6 +1256,7 @@
 {
     struct priv *p = (struct priv *) dev->priv;
     struct tmd *tmdp;
+    static char pad[64];
 
     PRINTK2(("## %s: SK_send_packet() called, CSR0 %#04x.\n", 
 	    SK_NAME, SK_read_reg(CSR0)));
@@ -1280,6 +1281,8 @@
 	/* Copy data into dual ported ram */
 
 	memcpy_toio((tmdp->u.buffer & 0x00ffffff), skb->data, skb->len);
+	if(len != skb->len)
+		memcpy_toio((tmdp->u.buffer & 0x00ffffff) + sb->len, pad, len-skb->len);
 
 	writew(-len, &tmdp->blen);            /* set length to transmit */
 
diff -urN linux-2.4.21-pre3/drivers/net/sun3_82586.c linux-2.4.21-pre4/drivers/net/sun3_82586.c
--- linux-2.4.21-pre3/drivers/net/sun3_82586.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.21-pre4/drivers/net/sun3_82586.c	Tue Jan 28 19:44:30 2003
@@ -1024,8 +1024,13 @@
 	else
 #endif
 	{
+		len = skb->len;
+		if(len < ETH_ZLEN)
+		{
+			memset((char *)p->xmit_cbuffs[p->xmit_count], 0, ETH_ZLEN);
+			len = ETH_ZLEN;
+		}
 		memcpy((char *)p->xmit_cbuffs[p->xmit_count],(char *)(skb->data),skb->len);
-		len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
 
 #if (NUM_XMIT_BUFFS == 1)
 #	ifdef NO_NOPCOMMANDS
diff -urN linux-2.4.21-pre3/drivers/net/sun3lance.c linux-2.4.21-pre4/drivers/net/sun3lance.c
--- linux-2.4.21-pre3/drivers/net/sun3lance.c	Thu Nov 28 15:53:14 2002
+++ linux-2.4.21-pre4/drivers/net/sun3lance.c	Tue Jan 28 19:44:30 2003
@@ -616,6 +616,9 @@
 	head->misc = 0;
 
 	memcpy( PKTBUF_ADDR(head), (void *)skb->data, skb->len );
+	if(len != skb->len)
+		memset(PKTBUF_ADDR(head) + skb->len, 0, len-skb->len);
+
 	head->flag = TMD1_OWN_CHIP | TMD1_ENP | TMD1_STP;
 	lp->new_tx = (lp->new_tx + 1) & TX_RING_MOD_MASK;
 	lp->stats.tx_bytes += skb->len;
diff -urN linux-2.4.21-pre3/drivers/net/sunlance.c linux-2.4.21-pre4/drivers/net/sunlance.c
--- linux-2.4.21-pre3/drivers/net/sunlance.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.21-pre4/drivers/net/sunlance.c	Tue Jan 28 19:44:30 2003
@@ -1502,6 +1502,7 @@
 #ifdef CONFIG_SUN4
 
 #include <asm/sun4paddr.h>
+#include <asm/machines.h>
 
 /* Find all the lance cards on the system and initialize them */
 static int __init sparc_lance_probe(void)
diff -urN linux-2.4.21-pre3/drivers/net/tg3.c linux-2.4.21-pre4/drivers/net/tg3.c
--- linux-2.4.21-pre3/drivers/net/tg3.c	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/drivers/net/tg3.c	Tue Jan 28 19:44:30 2003
@@ -209,28 +209,11 @@
 	tw32(TG3PCI_MISC_HOST_CTRL,
 	     (tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT));
 	tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000000);
-
-	if (tp->hw_status->status & SD_STATUS_UPDATED) {
-		tw32(GRC_LOCAL_CTRL,
-		     tp->grc_local_ctrl | GRC_LCLCTRL_SETINT);
-	}
 	tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
-}
 
-static inline void tg3_mask_ints(struct tg3 *tp)
-{
-	tw32(TG3PCI_MISC_HOST_CTRL,
-	     (tp->misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT));
-}
-
-static inline void tg3_unmask_ints(struct tg3 *tp)
-{
-	tw32(TG3PCI_MISC_HOST_CTRL,
-	     (tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT));
-	if (tp->hw_status->status & SD_STATUS_UPDATED) {
+	if (tp->hw_status->status & SD_STATUS_UPDATED)
 		tw32(GRC_LOCAL_CTRL,
 		     tp->grc_local_ctrl | GRC_LCLCTRL_SETINT);
-	}
 }
 
 static void tg3_switch_clocks(struct tg3 *tp)
@@ -2013,9 +1996,10 @@
 {
 	struct tg3 *tp = netdev->priv;
 	struct tg3_hw_status *sblk = tp->hw_status;
+	unsigned long flags;
 	int done;
 
-	spin_lock_irq(&tp->lock);
+	spin_lock_irqsave(&tp->lock, flags);
 
 	if (!(tp->tg3_flags &
 	      (TG3_FLAG_USE_LINKCHG_REG |
@@ -2052,18 +2036,18 @@
 
 	if (done) {
 		netif_rx_complete(netdev);
-		tg3_unmask_ints(tp);
+		tg3_enable_ints(tp);
 	}
 
-	spin_unlock_irq(&tp->lock);
+	spin_unlock_irqrestore(&tp->lock, flags);
 
 	return (done ? 0 : 1);
 }
 
-static __inline__ void tg3_interrupt_main_work(struct net_device *dev, struct tg3 *tp)
+static inline unsigned int tg3_has_work(struct net_device *dev, struct tg3 *tp)
 {
 	struct tg3_hw_status *sblk = tp->hw_status;
-	int work_exists = 0;
+	unsigned int work_exists = 0;
 
 	if (!(tp->tg3_flags &
 	      (TG3_FLAG_USE_LINKCHG_REG |
@@ -2075,19 +2059,7 @@
 	    sblk->idx[0].rx_producer != tp->rx_rcb_ptr)
 		work_exists = 1;
 
-	if (!work_exists)
-		return;
-
-	if (netif_rx_schedule_prep(dev)) {
-		/* NOTE: These writes are posted by the readback of
-		 *       the mailbox register done by our caller.
-		 */
-		tg3_mask_ints(tp);
-		__netif_rx_schedule(dev);
-	} else {
-		printk(KERN_ERR PFX "%s: Error, poll already scheduled\n",
-		       dev->name);
-	}
+	return work_exists;
 }
 
 static void tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
@@ -2102,13 +2074,16 @@
 	if (sblk->status & SD_STATUS_UPDATED) {
 		tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
 			     0x00000001);
+		tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
 		sblk->status &= ~SD_STATUS_UPDATED;
 
-		tg3_interrupt_main_work(dev, tp);
-
-		tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
-			     0x00000000);
-		tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
+		if (likely(tg3_has_work(dev, tp)))
+			netif_rx_schedule(dev);
+		else {
+			tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
+			     	0x00000000);
+			tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
+		}
 	}
 
 	spin_unlock_irqrestore(&tp->lock, flags);
@@ -2619,6 +2594,17 @@
 	return 0;
 }
 
+static inline void tg3_set_mtu(struct net_device *dev, struct tg3 *tp,
+			       int new_mtu)
+{
+	dev->mtu = new_mtu;
+
+	if (new_mtu > ETH_DATA_LEN)
+		tp->tg3_flags |= TG3_FLAG_JUMBO_ENABLE;
+	else
+		tp->tg3_flags &= ~TG3_FLAG_JUMBO_ENABLE;
+}
+
 static int tg3_change_mtu(struct net_device *dev, int new_mtu)
 {
 	struct tg3 *tp = dev->priv;
@@ -2630,7 +2616,7 @@
 		/* We'll just catch it later when the
 		 * device is up'd.
 		 */
-		dev->mtu = new_mtu;
+		tg3_set_mtu(dev, tp, new_mtu);
 		return 0;
 	}
 
@@ -2639,12 +2625,7 @@
 
 	tg3_halt(tp);
 
-	dev->mtu = new_mtu;
-
-	if (new_mtu > ETH_DATA_LEN)
-		tp->tg3_flags |= TG3_FLAG_JUMBO_ENABLE;
-	else
-		tp->tg3_flags &= ~TG3_FLAG_JUMBO_ENABLE;
+	tg3_set_mtu(dev, tp, new_mtu);
 
 	tg3_init_rings(tp);
 	tg3_init_hw(tp);
@@ -4321,8 +4302,9 @@
 static void tg3_timer(unsigned long __opaque)
 {
 	struct tg3 *tp = (struct tg3 *) __opaque;
+	unsigned long flags;
 
-	spin_lock_irq(&tp->lock);
+	spin_lock_irqsave(&tp->lock, flags);
 	spin_lock(&tp->tx_lock);
 
 	/* All of this garbage is because when using non-tagged
@@ -4404,7 +4386,7 @@
 	}
 
 	spin_unlock(&tp->tx_lock);
-	spin_unlock_irq(&tp->lock);
+	spin_unlock_irqrestore(&tp->lock, flags);
 
 	tp->timer.expires = jiffies + tp->timer_offset;
 	add_timer(&tp->timer);
@@ -5761,7 +5743,8 @@
 		tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x2aaa);
 	}
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
+	if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) &&
+	    (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0)) {
 		tg3_writephy(tp, 0x1c, 0x8d68);
 		tg3_writephy(tp, 0x1c, 0x8d68);
 	}
@@ -5981,8 +5964,11 @@
 
 	/* Force the chip into D0. */
 	err = tg3_set_power_state(tp, 0);
-	if (err)
+	if (err) {
+		printk(KERN_ERR PFX "(%s) transition to D0 failed\n",
+		       tp->pdev->slot_name);
 		return err;
+	}
 
 	/* 5700 B0 chips do not support checksumming correctly due
 	 * to hardware bugs.
@@ -6090,8 +6076,12 @@
 	    grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5703 &&
 	    grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5703S &&
 	    grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5704 &&
-	    grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_AC91002A1)
+	    grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5704_A2 &&
+	    grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_AC91002A1) {
+		printk(KERN_ERR PFX "(%s) unknown board id 0x%x\n",
+		       tp->pdev->slot_name, grc_misc_cfg);
 		return -ENODEV;
+	}
 
 	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 &&
 	    grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5704CIOBE) {
@@ -6107,6 +6097,11 @@
 		tp->tg3_flags |= TG3_FLAG_10_100_ONLY;
 
 	err = tg3_phy_probe(tp);
+	if (err) {
+		printk(KERN_ERR PFX "(%s) phy probe failed, err %d\n",
+		       tp->pdev->slot_name, err);
+		/* ... but do not return immediately ... */
+	}
 
 	tg3_read_partno(tp);
 
diff -urN linux-2.4.21-pre3/drivers/net/tg3.h linux-2.4.21-pre4/drivers/net/tg3.h
--- linux-2.4.21-pre3/drivers/net/tg3.h	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/drivers/net/tg3.h	Tue Jan 28 19:44:30 2003
@@ -113,6 +113,8 @@
 #define  CHIPREV_ID_5703_A2		 0x1002
 #define  CHIPREV_ID_5703_A3		 0x1003
 #define  CHIPREV_ID_5704_A0		 0x2000
+#define  CHIPREV_ID_5704_A1		 0x2001
+#define  CHIPREV_ID_5704_A2		 0x2002
 #define  GET_ASIC_REV(CHIP_REV_ID)	((CHIP_REV_ID) >> 12)
 #define   ASIC_REV_5700			 0x07
 #define   ASIC_REV_5701			 0x00
@@ -1136,6 +1138,7 @@
 #define  GRC_MISC_CFG_BOARD_ID_5703S	0x00002000
 #define  GRC_MISC_CFG_BOARD_ID_5704	0x00000000
 #define  GRC_MISC_CFG_BOARD_ID_5704CIOBE 0x00004000
+#define  GRC_MISC_CFG_BOARD_ID_5704_A2	0x00008000
 #define  GRC_MISC_CFG_BOARD_ID_AC91002A1 0x00018000
 #define GRC_LOCAL_CTRL			0x00006808
 #define  GRC_LCLCTRL_INT_ACTIVE		0x00000001
diff -urN linux-2.4.21-pre3/drivers/net/wan/dscc4.c linux-2.4.21-pre4/drivers/net/wan/dscc4.c
--- linux-2.4.21-pre3/drivers/net/wan/dscc4.c	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/drivers/net/wan/dscc4.c	Tue Jan 28 19:44:31 2003
@@ -467,8 +467,8 @@
 	skbuff = dpriv->rx_skbuff;
 	for (i = 0; i < RX_RING_SIZE; i++) {
 		if (*skbuff) {
-			pci_unmap_single(pdev, rx_fd->data, (*skbuff)->len,
-				PCI_DMA_FROMDEVICE);
+			pci_unmap_single(pdev, rx_fd->data,
+				RX_MAX(HDLC_MAX_MRU), PCI_DMA_FROMDEVICE);
 			dev_kfree_skb(*skbuff);
 		}
 		skbuff++;
@@ -480,17 +480,18 @@
 {
 	unsigned int dirty = dpriv->rx_dirty%RX_RING_SIZE;
 	struct RxFD *rx_fd = dpriv->rx_fd + dirty;
+	const int len = RX_MAX(HDLC_MAX_MRU);
 	struct sk_buff *skb;
 	int ret = 0;
 
-	skb = dev_alloc_skb(RX_MAX(HDLC_MAX_MRU));
+	skb = dev_alloc_skb(len);
 	dpriv->rx_skbuff[dirty] = skb;
 	if (skb) {
 	skb->dev = dev;
-	skb->protocol = htons(ETH_P_IP);
+		skb->protocol = htons(ETH_P_HDLC);
 	skb->mac.raw = skb->data;
 		rx_fd->data = pci_map_single(dpriv->pci_priv->pdev, skb->data,
-					       skb->len, PCI_DMA_FROMDEVICE);
+					     len, PCI_DMA_FROMDEVICE);
 	} else {
 		rx_fd->data = (u32) NULL;
 		ret = -1;
@@ -613,14 +614,11 @@
 	}
 	pkt_len = TO_SIZE(rx_fd->state2);
 	pci_dma_sync_single(pdev, rx_fd->data, pkt_len, PCI_DMA_FROMDEVICE);
-	pci_unmap_single(pdev, rx_fd->data, pkt_len, PCI_DMA_FROMDEVICE);
+	pci_unmap_single(pdev, rx_fd->data, RX_MAX(HDLC_MAX_MRU), PCI_DMA_FROMDEVICE);
 	if ((skb->data[--pkt_len] & FrameOk) == FrameOk) {
 		stats->rx_packets++;
 		stats->rx_bytes += pkt_len;
-		skb->tail += pkt_len;
-		skb->len = pkt_len;
-       	if (netif_running(dev))
-			skb->protocol = htons(ETH_P_HDLC);
+		skb_put(skb, pkt_len);
 		skb->dev->last_rx = jiffies;
 		netif_rx(skb);
 	} else {
@@ -1769,7 +1767,7 @@
 	        rx_fd->state1 = HiDesc;
 	        rx_fd->state2 = 0x00000000;
 	        rx_fd->end = 0xbabeface;
-	        rx_fd->state1 |= (RX_MAX(HDLC_MAX_MRU) << 16);
+	        rx_fd->state1 |= TO_STATE(RX_MAX(HDLC_MAX_MRU));
 		// FIXME: return value verifiee mais traitement suspect
 		if (try_get_rx_skb(dpriv, dev) >= 0)
 			dpriv->rx_dirty++;
diff -urN linux-2.4.21-pre3/drivers/scsi/hosts.h linux-2.4.21-pre4/drivers/scsi/hosts.h
--- linux-2.4.21-pre3/drivers/scsi/hosts.h	Thu Nov 28 15:53:14 2002
+++ linux-2.4.21-pre4/drivers/scsi/hosts.h	Tue Jan 28 19:44:31 2003
@@ -291,6 +291,9 @@
      */
     unsigned emulated:1;
 
+    /*
+     * True for drivers that can do I/O from highmem
+     */
     unsigned highmem_io:1;
 
     /*
diff -urN linux-2.4.21-pre3/drivers/scsi/ide-scsi.c linux-2.4.21-pre4/drivers/scsi/ide-scsi.c
--- linux-2.4.21-pre3/drivers/scsi/ide-scsi.c	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/drivers/scsi/ide-scsi.c	Tue Jan 28 19:44:31 2003
@@ -86,6 +86,7 @@
 #define PC_DMA_IN_PROGRESS	0	/* 1 while DMA in progress */
 #define PC_WRITING		1	/* Data direction */
 #define PC_TRANSFORM		2	/* transform SCSI commands */
+#define PC_DMA_OK		4	/* Use DMA */
 
 /*
  *	SCSI command transformation layer
@@ -513,6 +514,10 @@
 	ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL);
 	/* Send the actual packet */
 	HWIF(drive)->atapi_output_bytes(drive, scsi->pc->c, 12);
+	if (test_bit (PC_DMA_OK, &pc->flags)) {
+		set_bit(PC_DMA_IN_PROGRESS, &pc->flags);
+		(void) (HWIF(drive)->ide_dma_begin(drive));
+	}
 	return ide_started;
 }
 
@@ -549,8 +554,7 @@
 	HWIF(drive)->OUTB(bcount.b.low, IDE_BCOUNTL_REG);
 
 	if (feature.b.dma) {
-		set_bit(PC_DMA_IN_PROGRESS, &pc->flags);
-		(void) (HWIF(drive)->ide_dma_begin(drive));
+		set_bit(PC_DMA_OK, &pc->flags);
 	}
 	if (test_bit(IDESCSI_DRQ_INTERRUPT, &scsi->flags)) {
 		if (HWGROUP(drive)->handler != NULL)
diff -urN linux-2.4.21-pre3/drivers/scsi/mac_scsi.c linux-2.4.21-pre4/drivers/scsi/mac_scsi.c
--- linux-2.4.21-pre3/drivers/scsi/mac_scsi.c	Mon Feb 25 11:38:04 2002
+++ linux-2.4.21-pre4/drivers/scsi/mac_scsi.c	Tue Jan 28 19:44:31 2003
@@ -25,26 +25,10 @@
  * 1+ (800) 334-5454
  */
 
-
-/*
- * Options :
- *
- * PARITY - enable parity checking.  Not supported.
- *
- * SCSI2 - enable support for SCSI-II tagged queueing.  Untested.
- *
- * USLEEP - enable support for devices that don't disconnect.  Untested.
- */
-
 /*
  * $Log: mac_NCR5380.c,v $
  */
 
-#define AUTOSENSE
-#if 0
-#define PSEUDO_DMA
-#endif
-
 #include <linux/types.h>
 #include <linux/stddef.h>
 #include <linux/ctype.h>
@@ -81,33 +65,28 @@
 #define RESET_BOOT
 #define DRIVER_SETUP
 
-/*
- * BUG can be used to trigger a strange code-size related hang on 2.1 kernels
- */
-#ifdef BUG
-#undef RESET_BOOT
-#undef DRIVER_SETUP
-#endif
-
 #define	ENABLE_IRQ()	mac_enable_irq( IRQ_MAC_SCSI ); 
 #define	DISABLE_IRQ()	mac_disable_irq( IRQ_MAC_SCSI );
 
+extern void via_scsi_clear(void);
+
 #ifdef RESET_BOOT
 static void mac_scsi_reset_boot(struct Scsi_Host *instance);
 #endif
-static char macscsi_read(struct Scsi_Host *instance, int reg);
-static void macscsi_write(struct Scsi_Host *instance, int reg, int value);
 
+static __inline__ char macscsi_read(struct Scsi_Host *instance, int reg);
+static __inline__ void macscsi_write(struct Scsi_Host *instance, int reg, int value);
+
+static int setup_called = 0;
 static int setup_can_queue = -1;
 static int setup_cmd_per_lun = -1;
 static int setup_sg_tablesize = -1;
+static int setup_use_pdma = -1;
 #ifdef SUPPORT_TAGS
 static int setup_use_tagged_queuing = -1;
 #endif
 static int setup_hostid = -1;
 
-static int polled_scsi_on = 0;
-
 /* Time (in jiffies) to wait after a reset; the SCSI standard calls for 250ms,
  * we usually do 0.5s to be on the safe side. But Toshiba CD-ROMs once more
  * need ten times the standard value... */
@@ -124,44 +103,27 @@
 static volatile unsigned char *mac_scsi_nodrq = NULL;
 
 /*
- * Function : mac_scsi_setup(char *str, int *ints)
+ * Function : mac_scsi_setup(char *str)
  *
  * Purpose : booter command line initialization of the overrides array,
  *
- * Inputs : str - unused, ints - array of integer parameters with ints[0]
- *	equal to the number of ints.
+ * Inputs : str - comma delimited list of options
  *
  */
 
-static int __init mac_scsi_setup(char *str, int *ints) {
-#ifdef DRIVER_SETUP
-	/* Format of mac5380 parameter is:
-	 *   mac5380=<can_queue>,<cmd_per_lun>,<sg_tablesize>,<hostid>,<use_tags>
-	 * Negative values mean don't change.
-	 */
+static int __init mac_scsi_setup(char *str) {
+#ifdef DRIVER_SETUP	
+	int ints[7];
 	
-	/* Grmbl... the standard parameter parsing can't handle negative numbers
-	 * :-( So let's do it ourselves!
-	 */
-
-	int i = ints[0]+1, fact;
-
-	while( str && (isdigit(*str) || *str == '-') && i <= 10) {
-		if (*str == '-')
-			fact = -1, ++str;
-		else
-			fact = 1;
-		ints[i++] = simple_strtoul( str, NULL, 0 ) * fact;
-		if ((str = strchr( str, ',' )) != NULL)
-			++str;
-	}
-	ints[0] = i-1;
+	(void)get_options( str, ARRAY_SIZE(ints), ints);
 	
-	if (ints[0] < 1) {
-		printk( "mac_scsi_setup: no arguments!\n" );
-		return 0;
+	if (setup_called++ || ints[0] < 1 || ints[0] > 6) {
+	    printk(KERN_WARNING "scsi: <mac5380>"
+		" Usage: mac5380=<can_queue>[,<cmd_per_lun>,<sg_tablesize>,<hostid>,<use_tags>,<use_pdma>]\n");
+	    printk(KERN_ALERT "scsi: <mac5380> Bad Penguin parameters?\n");
+	    return 0;
 	}
-
+	    
 	if (ints[0] >= 1) {
 		if (ints[1] > 0)
 			/* no limits on this, just > 0 */
@@ -184,25 +146,31 @@
 		if (ints[4] >= 0 && ints[4] <= 7)
 			setup_hostid = ints[4];
 		else if (ints[4] > 7)
-			printk( "mac_scsi_setup: invalid host ID %d !\n", ints[4] );
+			printk(KERN_WARNING "mac_scsi_setup: invalid host ID %d !\n", ints[4] );
 	}
-#ifdef SUPPORT_TAGS
+#ifdef SUPPORT_TAGS	
 	if (ints[0] >= 5) {
 		if (ints[5] >= 0)
 			setup_use_tagged_queuing = !!ints[5];
 	}
+	
+	if (ints[0] == 6) {
+	    if (ints[6] >= 0)
+		setup_use_pdma = ints[6];
+	}
+#else
+	if (ints[0] == 5) {
+	    if (ints[5] >= 0)
+		setup_use_pdma = ints[5];
+	}
 #endif
+	
 #endif
-	return 1; 
+	return 1;
 }
 
 __setup("mac5380=", mac_scsi_setup);
 
-#if 0
-#define MAC_ADDRESS(card) (ecard_address((card), ECARD_IOC, ECARD_SLOW) + 0x800)
-#define MAC_IRQ(card)     ((card)->irq)
-#endif
-
 /*
  * XXX: status debug
  */
@@ -222,93 +190,89 @@
  
 int macscsi_detect(Scsi_Host_Template * tpnt)
 {
-    int count = 0;
     static int called = 0;
+    int flags = 0;
     struct Scsi_Host *instance;
 
     if (!MACH_IS_MAC || called)
 	return( 0 );
 
     if (macintosh_config->scsi_type != MAC_SCSI_OLD)
-	 return( 0 );
-
-    tpnt->proc_name = "mac5380";
+	return( 0 );
 
     /* setup variables */
     tpnt->can_queue =
-      (setup_can_queue > 0) ? setup_can_queue : CAN_QUEUE;
+	(setup_can_queue > 0) ? setup_can_queue : CAN_QUEUE;
     tpnt->cmd_per_lun =
-      (setup_cmd_per_lun > 0) ? setup_cmd_per_lun : CMD_PER_LUN;
+	(setup_cmd_per_lun > 0) ? setup_cmd_per_lun : CMD_PER_LUN;
     tpnt->sg_tablesize = 
-      (setup_sg_tablesize >= 0) ? setup_sg_tablesize : SG_TABLESIZE;
+	(setup_sg_tablesize >= 0) ? setup_sg_tablesize : SG_TABLESIZE;
 
     if (setup_hostid >= 0)
-      tpnt->this_id = setup_hostid;
+	tpnt->this_id = setup_hostid;
     else {
-      /* use 7 as default */
-      tpnt->this_id = 7;
+	/* use 7 as default */
+	tpnt->this_id = 7;
     }
 
 #ifdef SUPPORT_TAGS
-	if (setup_use_tagged_queuing < 0)
-		setup_use_tagged_queuing = DEFAULT_USE_TAGGED_QUEUING;
+    if (setup_use_tagged_queuing < 0)
+	setup_use_tagged_queuing = USE_TAGGED_QUEUING;
 #endif
 
-#if 0	/* loop over multiple adapters (Powerbooks ??) */
-    for (count = 0; count < mac_num_scsi; count++) {
-#endif
-        instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
-        if(instance == NULL)
-        	continue;
-	default_instance = instance;
-
-	if (macintosh_config->ident == MAC_MODEL_IIFX) {
-		mac_scsi_regp  = via1+0x8000;
-		mac_scsi_drq   = via1+0xE000;
-		mac_scsi_nodrq = via1+0xC000;
-	} else {
-		mac_scsi_regp  = via1+0x10000;
-		mac_scsi_drq   = via1+0x6000;
-		mac_scsi_nodrq = via1+0x12000;
-	}
-
+    /* Once we support multiple 5380s (e.g. DuoDock) we'll do
+       something different here */
+    instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
+    default_instance = instance;
+    
+    if (macintosh_config->ident == MAC_MODEL_IIFX) {
+	mac_scsi_regp  = via1+0x8000;
+	mac_scsi_drq   = via1+0xE000;
+	mac_scsi_nodrq = via1+0xC000;
+	/* The IIFX should be able to do true DMA, but pseudo-dma doesn't work */
+	flags = FLAG_NO_PSEUDO_DMA;
+    } else {
+	mac_scsi_regp  = via1+0x10000;
+	mac_scsi_drq   = via1+0x6000;
+	mac_scsi_nodrq = via1+0x12000;
+    }
 
-        instance->io_port = (unsigned long) mac_scsi_regp;
-	instance->irq = IRQ_MAC_SCSI;
+    if (! setup_use_pdma)
+	flags = FLAG_NO_PSEUDO_DMA;
+	
+    instance->io_port = (unsigned long) mac_scsi_regp;
+    instance->irq = IRQ_MAC_SCSI;
 
-#ifdef RESET_BOOT
-	mac_scsi_reset_boot(instance);
+#ifdef RESET_BOOT   
+    mac_scsi_reset_boot(instance);
 #endif
+    
+    NCR5380_init(instance, flags);
 
-	NCR5380_init(instance, 0);
+    instance->n_io_port = 255;
 
-	instance->n_io_port = 255;
+    ((struct NCR5380_hostdata *)instance->hostdata)->ctrl = 0;
 
-        ((struct NCR5380_hostdata *)instance->hostdata)->ctrl = 0;
+    if (instance->irq != IRQ_NONE)
+	if (request_irq(instance->irq, NCR5380_intr, IRQ_FLG_SLOW, 
+		"ncr5380", NCR5380_intr)) {
+	    printk(KERN_WARNING "scsi%d: IRQ%d not free, interrupts disabled\n",
+		   instance->host_no, instance->irq);
+	    instance->irq = IRQ_NONE;
+	}
 
-	if (instance->irq != IRQ_NONE)
-	    if (request_irq(instance->irq, NCR5380_intr, IRQ_FLG_SLOW, "ncr5380", NCR5380_intr)) {
-		printk("scsi%d: IRQ%d not free, interrupts disabled\n",
-		    instance->host_no, instance->irq);
-		instance->irq = IRQ_NONE;
-	    }
-
-	printk("scsi%d: generic 5380 at port %lX irq", instance->host_no, instance->io_port);
-	if (instance->irq == IRQ_NONE)
-	    printk ("s disabled");
-	else
-	    printk (" %d", instance->irq);
-	printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
-	    instance->can_queue, instance->cmd_per_lun, MACSCSI_PUBLIC_RELEASE);
-	printk("\nscsi%d:", instance->host_no);
-	NCR5380_print_options(instance);
-	printk("\n");
-#if 0	/* multiple adapters */
-    }
-#endif
+    printk(KERN_INFO "scsi%d: generic 5380 at port %lX irq", instance->host_no, instance->io_port);
+    if (instance->irq == IRQ_NONE)
+	printk (KERN_INFO "s disabled");
+    else
+	printk (KERN_INFO " %d", instance->irq);
+    printk(KERN_INFO " options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
+	   instance->can_queue, instance->cmd_per_lun, MACSCSI_PUBLIC_RELEASE);
+    printk(KERN_INFO "\nscsi%d:", instance->host_no);
+    NCR5380_print_options(instance);
+    printk("\n");
     called = 1;
     return 1;
-
 }
 
 int macscsi_release (struct Scsi_Host *shpnt)
@@ -336,10 +300,10 @@
 	 * with the queues, interrupts, or locks necessary here.
 	 */
 
-	printk( "Macintosh SCSI: resetting the SCSI bus..." );
+	printk(KERN_INFO "Macintosh SCSI: resetting the SCSI bus..." );
 
 	/* switch off SCSI IRQ - catch an interrupt without IRQ bit set else */
-       	mac_disable_irq(IRQ_MAC_SCSI);
+	mac_disable_irq(IRQ_MAC_SCSI);
 
 	/* get in phase */
 	NCR5380_write( TARGET_COMMAND_REG,
@@ -357,207 +321,22 @@
 		barrier();
 
 	/* switch on SCSI IRQ again */
-       	mac_enable_irq(IRQ_MAC_SCSI);
+	mac_enable_irq(IRQ_MAC_SCSI);
 
-	printk( " done\n" );
+	printk(KERN_INFO " done\n" );
 }
 #endif
 
 const char * macscsi_info (struct Scsi_Host *spnt) {
-    return "";
-}
-
-void restore_irq(struct pt_regs *regs)
-{
-	unsigned long flags;
-
-	save_flags(flags);
-	flags = (flags & ~0x0700) | (regs->sr & 0x0700);
-	restore_flags(flags);
+	return "";
 }
 
 /*
- * pseudo-DMA transfer functions, copied and modified from Russel King's
- * ARM 5380 driver (cumana_1)
- *
- * Work in progress (sort of), didn't work last time I checked, don't use!
- */
-
-#ifdef NOT_EFFICIENT
-#define CTRL(p,v)     outb(*ctrl = (v), (p) - 577)
-#define STAT(p)       inb((p)+1)
-#define IN(p)         inb((p))
-#define OUT(v,p)      outb((v), (p))
-#else
-#if 0
-#define CTRL(p,v)	(p[-2308] = (*ctrl = (v)))
-#else
-#define CTRL(p,v)	(*ctrl = (v))
-#endif
-#define STAT(p)		(p[1<<4])
-#define IN(p)		(*(p))
-#define IN2(p)		((unsigned short)(*(volatile unsigned long *)(p)))
-#define OUT(v,p)	(*(p) = (v))
-#define OUT2(v,p)	(*((volatile unsigned long *)(p)) = (v))
-#endif
-#define L(v)		(((v)<<16)|((v) & 0x0000ffff))
-#define H(v)		(((v)>>16)|((v) & 0xffff0000))
-#define ioaddr(v)	(v)
-
-static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *addr,
-              int len)
-{
-  int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
-  int oldctrl = *ctrl;
-  unsigned long *laddr;
-#ifdef NOT_EFFICIENT
-  int iobase = instance->io_port;
-  int dma_io = mac_scsi_nodrq;
-#else
-  volatile unsigned char *iobase = (unsigned char *)ioaddr(instance->io_port);
-  volatile unsigned char *dma_io = (unsigned char *)(mac_scsi_nodrq);
-#endif
-
-  if(!len) return 0;
-
-  CTRL(iobase, 0x02);
-  laddr = (unsigned long *)addr;
-  while(len >= 32)
-  {
-    int status;
-    unsigned long v;
-    status = STAT(iobase);
-    if(status & 0x80)
-      goto end;
-    if(!(status & 0x40))
-      continue;
-    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
-    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
-    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
-    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
-    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
-    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
-    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
-    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
-    len -= 32;
-    if(len == 0)
-      break;
-  }
-
-  addr = (unsigned char *)laddr;
-  CTRL(iobase, 0x12);
-  while(len > 0)
-  {
-    int status;
-    status = STAT(iobase);
-    if(status & 0x80)
-      goto end;
-    if(status & 0x40)
-    {
-      OUT(*addr++, dma_io);
-      if(--len == 0)
-        break;
-    }
-
-    status = STAT(iobase);
-    if(status & 0x80)
-      goto end;
-    if(status & 0x40)
-    {
-      OUT(*addr++, dma_io);
-      if(--len == 0)
-        break;
-    }
-  }
-end:
-  CTRL(iobase, oldctrl|0x40);
-  return len;
-}
-
-static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *addr,
-              int len)
-{
-  int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
-  int oldctrl = *ctrl;
-  unsigned long *laddr;
-#ifdef NOT_EFFICIENT
-  int iobase = instance->io_port;
-  int dma_io = mac_scsi_nodrq;
-#else
-  volatile unsigned char *iobase = (unsigned char *)ioaddr(instance->io_port);
-  volatile unsigned char *dma_io = (unsigned char *)((int)mac_scsi_nodrq);
-#endif
-
-  if(!len) return 0;
-
-  CTRL(iobase, 0x00);
-  laddr = (unsigned long *)addr;
-  while(len >= 32)
-  {
-    int status;
-    status = STAT(iobase);
-    if(status & 0x80)
-      goto end;
-    if(!(status & 0x40))
-      continue;
-    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
-    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
-    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
-    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
-    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
-    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
-    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
-    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
-    len -= 32;
-    if(len == 0)
-      break;
-  }
-
-  addr = (unsigned char *)laddr;
-  CTRL(iobase, 0x10);
-  while(len > 0)
-  {
-    int status;
-    status = STAT(iobase);
-    if(status & 0x80)
-      goto end;
-    if(status & 0x40)
-    {
-      *addr++ = IN(dma_io);
-      if(--len == 0)
-        break;
-    }
-
-    status = STAT(iobase);
-    if(status & 0x80)
-      goto end;
-    if(status & 0x40)
-    {
-      *addr++ = IN(dma_io);
-      if(--len == 0)
-        break;
-    }
-  }
-end:
-  CTRL(iobase, oldctrl|0x40);
-  return len;
-}
-
-#undef STAT
-#undef CTRL
-#undef IN
-#undef OUT
-
-/*
  * NCR 5380 register access functions
  */
 
-#ifdef ORIG
-#if 0
-#define CTRL(p,v) outb(*ctrl = (v), (p) - 577)
-#else
+/* Debug versions
 #define CTRL(p,v) (*ctrl = (v))
-#endif
 
 static char macscsi_read(struct Scsi_Host *instance, int reg)
 {
@@ -566,11 +345,7 @@
   int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
 
   CTRL(iobase, 0);
-#if 0
-  i = inb(iobase + 64 + reg);
-#else
-  i = inb(iobase + reg<<4);
-#endif
+  i = in_8(iobase + (reg<<4));
   CTRL(iobase, 0x40);
 
   return i;
@@ -582,87 +357,224 @@
   int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
 
   CTRL(iobase, 0);
-#if 0
-  outb(value, iobase + 64 + reg);
-#else
-  outb(value, iobase + reg<<4);
-#endif
+  out_8(value, iobase + (reg<<4));
   CTRL(iobase, 0x40);
 }
+*/
 
-#undef CTRL
-
-#else
-static char macscsi_read(struct Scsi_Host *instance, int reg)
+/* Fast versions */
+static __inline__ char macscsi_read(struct Scsi_Host *instance, int reg)
 {
-	return( mac_scsi_regp[reg << 4] );
+  return in_8(instance->io_port + (reg<<4));
 }
 
-static void macscsi_write(struct Scsi_Host *instance, int reg, int value)
-{
-	mac_scsi_regp[reg << 4] = value;
+static __inline__ void macscsi_write(struct Scsi_Host *instance, int reg, int value)
+{
+  out_8(value, instance->io_port + (reg<<4));
+}
+
+
+/* 
+   Pseudo-DMA: (Ove Edlund)
+   The code attempts to catch bus errors that occur if one for example
+   "trips over the cable".
+   XXX: Since bus errors in the PDMA routines never happen on my 
+   computer, the bus error code is untested. 
+   If the code works as intended, a bus error results in Pseudo-DMA 
+   beeing disabled, meaning that the driver switches to slow handshake. 
+   If bus errors are NOT extremely rare, this has to be changed. 
+*/
+
+#define CP_IO_TO_MEM(s,d,len)				\
+__asm__ __volatile__					\
+    ("    cmp.w  #4,%2\n"				\
+     "    bls    8f\n"					\
+     "    move.w %1,%%d0\n"				\
+     "    neg.b  %%d0\n"				\
+     "    and.w  #3,%%d0\n"				\
+     "    sub.w  %%d0,%2\n"				\
+     "    bra    2f\n"					\
+     " 1: move.b (%0),(%1)+\n"				\
+     " 2: dbf    %%d0,1b\n"				\
+     "    move.w %2,%%d0\n"				\
+     "    lsr.w  #5,%%d0\n"				\
+     "    bra    4f\n"					\
+     " 3: move.l (%0),(%1)+\n"				\
+     "31: move.l (%0),(%1)+\n"				\
+     "32: move.l (%0),(%1)+\n"				\
+     "33: move.l (%0),(%1)+\n"				\
+     "34: move.l (%0),(%1)+\n"				\
+     "35: move.l (%0),(%1)+\n"				\
+     "36: move.l (%0),(%1)+\n"				\
+     "37: move.l (%0),(%1)+\n"				\
+     " 4: dbf    %%d0,3b\n"				\
+     "    move.w %2,%%d0\n"				\
+     "    lsr.w  #2,%%d0\n"				\
+     "    and.w  #7,%%d0\n"				\
+     "    bra    6f\n"					\
+     " 5: move.l (%0),(%1)+\n"				\
+     " 6: dbf    %%d0,5b\n"				\
+     "    and.w  #3,%2\n"				\
+     "    bra    8f\n"					\
+     " 7: move.b (%0),(%1)+\n"				\
+     " 8: dbf    %2,7b\n"				\
+     "    moveq.l #0, %2\n"				\
+     " 9: \n"						\
+     ".section .fixup,\"ax\"\n"				\
+     "    .even\n"					\
+     "90: moveq.l #1, %2\n"				\
+     "    jra 9b\n"					\
+     ".previous\n"					\
+     ".section __ex_table,\"a\"\n"			\
+     "   .align 4\n"					\
+     "   .long  1b,90b\n"				\
+     "   .long  3b,90b\n"				\
+     "   .long 31b,90b\n"				\
+     "   .long 32b,90b\n"				\
+     "   .long 33b,90b\n"				\
+     "   .long 34b,90b\n"				\
+     "   .long 35b,90b\n"				\
+     "   .long 36b,90b\n"				\
+     "   .long 37b,90b\n"				\
+     "   .long  5b,90b\n"				\
+     "   .long  7b,90b\n"				\
+     ".previous"					\
+     : "=a"(s), "=a"(d), "=d"(len)			\
+     : "0"(s), "1"(d), "2"(len)				\
+     : "d0")
+
+
+static int macscsi_pread (struct Scsi_Host *instance,
+			  unsigned char *dst, int len)
+{
+   unsigned char *d;
+   volatile unsigned char *s;
+
+   NCR5380_local_declare();
+   NCR5380_setup(instance);
+
+   s = mac_scsi_drq+0x60;
+   d = dst;
+
+/* These conditions are derived from MacOS */
+
+   while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ) 
+         && !(NCR5380_read(STATUS_REG) & SR_REQ))
+      ;
+   if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ) 
+         && (NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH)) {
+      printk(KERN_ERR "Error in macscsi_pread\n");
+      return -1;
+   }
+
+   CP_IO_TO_MEM(s, d, len);
+   
+   if (len != 0) {
+      printk(KERN_NOTICE "Bus error in macscsi_pread\n");
+      return -1;
+   }
+   
+   return 0;
+}
+
+
+#define CP_MEM_TO_IO(s,d,len)				\
+__asm__ __volatile__					\
+    ("    cmp.w  #4,%2\n"				\
+     "    bls    8f\n"					\
+     "    move.w %0,%%d0\n"				\
+     "    neg.b  %%d0\n"				\
+     "    and.w  #3,%%d0\n"				\
+     "    sub.w  %%d0,%2\n"				\
+     "    bra    2f\n"					\
+     " 1: move.b (%0)+,(%1)\n"				\
+     " 2: dbf    %%d0,1b\n"				\
+     "    move.w %2,%%d0\n"				\
+     "    lsr.w  #5,%%d0\n"				\
+     "    bra    4f\n"					\
+     " 3: move.l (%0)+,(%1)\n"				\
+     "31: move.l (%0)+,(%1)\n"				\
+     "32: move.l (%0)+,(%1)\n"				\
+     "33: move.l (%0)+,(%1)\n"				\
+     "34: move.l (%0)+,(%1)\n"				\
+     "35: move.l (%0)+,(%1)\n"				\
+     "36: move.l (%0)+,(%1)\n"				\
+     "37: move.l (%0)+,(%1)\n"				\
+     " 4: dbf    %%d0,3b\n"				\
+     "    move.w %2,%%d0\n"				\
+     "    lsr.w  #2,%%d0\n"				\
+     "    and.w  #7,%%d0\n"				\
+     "    bra    6f\n"					\
+     " 5: move.l (%0)+,(%1)\n"				\
+     " 6: dbf    %%d0,5b\n"				\
+     "    and.w  #3,%2\n"				\
+     "    bra    8f\n"					\
+     " 7: move.b (%0)+,(%1)\n"				\
+     " 8: dbf    %2,7b\n"				\
+     "    moveq.l #0, %2\n"				\
+     " 9: \n"						\
+     ".section .fixup,\"ax\"\n"				\
+     "    .even\n"					\
+     "90: moveq.l #1, %2\n"				\
+     "    jra 9b\n"					\
+     ".previous\n"					\
+     ".section __ex_table,\"a\"\n"			\
+     "   .align 4\n"					\
+     "   .long  1b,90b\n"				\
+     "   .long  3b,90b\n"				\
+     "   .long 31b,90b\n"				\
+     "   .long 32b,90b\n"				\
+     "   .long 33b,90b\n"				\
+     "   .long 34b,90b\n"				\
+     "   .long 35b,90b\n"				\
+     "   .long 36b,90b\n"				\
+     "   .long 37b,90b\n"				\
+     "   .long  5b,90b\n"				\
+     "   .long  7b,90b\n"				\
+     ".previous"					\
+     : "=a"(s), "=a"(d), "=d"(len)			\
+     : "0"(s), "1"(d), "2"(len)				\
+     : "d0")
+
+static int macscsi_pwrite (struct Scsi_Host *instance,
+				  unsigned char *src, int len)
+{
+   unsigned char *s;
+   volatile unsigned char *d;
+
+   NCR5380_local_declare();
+   NCR5380_setup(instance);
+
+   s = src;
+   d = mac_scsi_drq;
+   
+/* These conditions are derived from MacOS */
+
+   while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ) 
+         && (!(NCR5380_read(STATUS_REG) & SR_REQ) 
+            || (NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH))) 
+      ;
+   if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ)) {
+      printk(KERN_ERR "Error in macscsi_pwrite\n");
+      return -1;
+   }
+
+   CP_MEM_TO_IO(s, d, len);   
+
+   if (len != 0) {
+      printk(KERN_NOTICE "Bus error in macscsi_pwrite\n");
+      return -1;
+   }
+   
+   return 0;
 }
 
-#endif
-
-#include "NCR5380.c"
-
-/*
- * Debug stuff - to be called on NMI, or sysrq key. Use at your own risk; 
- * reentering NCR5380_print_status seems to have ugly side effects
- */
-
-void scsi_mac_debug (void)
-{
-	unsigned long flags;
-	NCR5380_local_declare();
-
-	if (default_instance) {
-#if 0
-		NCR5380_setup(default_instance);
-		if(NCR5380_read(BUS_AND_STATUS_REG)&BASR_IRQ)
-#endif
-			save_flags(flags);
-			cli();
-			NCR5380_print_status(default_instance);
-			restore_flags(flags);
-	}
-#if 0
-	polled_scsi_on = 1;
-#endif
-}
-/*
- * Helper function for interrupt trouble. More ugly side effects here.
- */
-
-void scsi_mac_polled (void)
-{
-	unsigned long flags;
-	NCR5380_local_declare();
-	struct Scsi_Host *instance;
-	
-#if 0
-	for (instance = first_instance; instance && (instance->hostt == 
-	    the_template); instance = instance->next)
-	    if (instance->irq == IRQ_MAC_SCSI && polled_scsi_on) {
-#else
-		instance = default_instance;
-#endif
-		NCR5380_setup(instance);
-		if(NCR5380_read(BUS_AND_STATUS_REG)&BASR_IRQ)
-		{
-			printk("SCSI poll\n");
-			save_flags(flags);
-			cli();
-			NCR5380_intr(IRQ_MAC_SCSI, instance, NULL);
-			restore_flags(flags);
-		}
-#if 0
-	    }
-#endif
-}
 
+/* These control the behaviour of the generic 5380 core */
+#define AUTOSENSE
+#define PSEUDO_DMA
 
+#include "NCR5380.c"
 
 static Scsi_Host_Template driver_template = MAC_NCR5380;
 
diff -urN linux-2.4.21-pre3/drivers/scsi/mac_scsi.h linux-2.4.21-pre4/drivers/scsi/mac_scsi.h
--- linux-2.4.21-pre3/drivers/scsi/mac_scsi.h	Tue Jan 25 13:01:14 2000
+++ linux-2.4.21-pre4/drivers/scsi/mac_scsi.h	Tue Jan 28 19:44:31 2003
@@ -29,8 +29,7 @@
 #ifndef MAC_NCR5380_H
 #define MAC_NCR5380_H
 
-#define MACSCSI_PUBLIC_RELEASE 1
-
+#define MACSCSI_PUBLIC_RELEASE 2
 
 #ifndef ASM
 int macscsi_abort (Scsi_Cmnd *);
@@ -65,6 +64,8 @@
 #include <scsi/scsicam.h>
 
 #define MAC_NCR5380 {						\
+proc_name:		"Mac5380",					\
+proc_info:		macscsi_proc_info,                              \
 name:			"Macintosh NCR5380 SCSI",			\
 detect:			macscsi_detect,					\
 release:		macscsi_release,	/* Release */		\
@@ -95,6 +96,9 @@
 #define NCR5380_read(reg) macscsi_read(_instance, reg)
 #define NCR5380_write(reg, value) macscsi_write(_instance, reg, value)
 
+#define NCR5380_pread 	macscsi_pread
+#define NCR5380_pwrite 	macscsi_pwrite
+	
 #define NCR5380_intr macscsi_intr
 #define NCR5380_queue_command macscsi_queue_command
 #define NCR5380_abort macscsi_abort
diff -urN linux-2.4.21-pre3/drivers/scsi/sd.c linux-2.4.21-pre4/drivers/scsi/sd.c
--- linux-2.4.21-pre3/drivers/scsi/sd.c	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/drivers/scsi/sd.c	Tue Jan 28 19:44:31 2003
@@ -1446,7 +1446,7 @@
 	}
 	for (i = 0; i < N_USED_SD_MAJORS; i++) {
 		del_gendisk(&sd_gendisks[i]);
-		blk_size[SD_MAJOR(i)] = NULL;	/* XXX blksize_size actually? */
+		blksize_size[SD_MAJOR(i)] = NULL;
 		hardsect_size[SD_MAJOR(i)] = NULL;
 		read_ahead[SD_MAJOR(i)] = 0;
 	}
diff -urN linux-2.4.21-pre3/drivers/sound/ad1889.c linux-2.4.21-pre4/drivers/sound/ad1889.c
--- linux-2.4.21-pre3/drivers/sound/ad1889.c	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/drivers/sound/ad1889.c	Tue Jan 28 19:44:31 2003
@@ -816,7 +816,7 @@
 	ad1889_dev_t *dev = ac97->private_data;
 
 	//DBG("Writing 0x%x to 0x%lx\n", val, dev->regbase + 0x100 + reg);
-	return AD1889_WRITEW(dev, 0x100 + reg, val);
+	AD1889_WRITEW(dev, 0x100 + reg, val);
 }
 
 static u16 ad1889_codec_read(struct ac97_codec *ac97, u8 reg)
diff -urN linux-2.4.21-pre3/drivers/usb/Config.in linux-2.4.21-pre4/drivers/usb/Config.in
--- linux-2.4.21-pre3/drivers/usb/Config.in	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/drivers/usb/Config.in	Tue Jan 28 19:44:31 2003
@@ -82,6 +82,7 @@
       comment '  Video4Linux support is needed for USB Multimedia device support'
    else
       dep_tristate '  USB IBM (Xirlink) C-it Camera support' CONFIG_USB_IBMCAM $CONFIG_USB $CONFIG_VIDEO_DEV
+      dep_tristate '  USB Konica Webcam support' CONFIG_USB_KONICAWC $CONFIG_USB $CONFIG_VIDEO_DEV
       dep_tristate '  USB OV511 Camera support' CONFIG_USB_OV511 $CONFIG_USB $CONFIG_VIDEO_DEV
       dep_tristate '  USB Philips Cameras' CONFIG_USB_PWC $CONFIG_USB $CONFIG_VIDEO_DEV
       dep_tristate '  USB SE401 Camera support' CONFIG_USB_SE401 $CONFIG_USB $CONFIG_VIDEO_DEV
diff -urN linux-2.4.21-pre3/drivers/usb/Makefile linux-2.4.21-pre4/drivers/usb/Makefile
--- linux-2.4.21-pre3/drivers/usb/Makefile	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/drivers/usb/Makefile	Tue Jan 28 19:44:31 2003
@@ -73,6 +73,7 @@
 obj-$(CONFIG_USB_EMI26)		+= emi26.o
 obj-$(CONFIG_USB_MIDI)		+= usb-midi.o
 obj-$(CONFIG_USB_IBMCAM)	+= ibmcam.o usbvideo.o ultracam.o
+obj-$(CONFIG_USB_KONICAWC)	+= konicawc.o usbvideo.o
 obj-$(CONFIG_USB_PWC)		+= pwc.o
 obj-$(CONFIG_USB_DC2XX)		+= dc2xx.o
 obj-$(CONFIG_USB_MDC800)	+= mdc800.o
diff -urN linux-2.4.21-pre3/drivers/usb/hcd/ehci-dbg.c linux-2.4.21-pre4/drivers/usb/hcd/ehci-dbg.c
--- linux-2.4.21-pre3/drivers/usb/hcd/ehci-dbg.c	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/drivers/usb/hcd/ehci-dbg.c	Tue Jan 28 19:44:31 2003
@@ -18,37 +18,23 @@
 
 /* this file is part of ehci-hcd.c */
 
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,50)
-
-#define ehci_dbg(ehci, fmt, args...) \
-	dev_dbg (*(ehci)->hcd.controller, fmt, ## args )
-#define ehci_err(ehci, fmt, args...) \
-	dev_err (*(ehci)->hcd.controller, fmt, ## args )
-#define ehci_info(ehci, fmt, args...) \
-	dev_info (*(ehci)->hcd.controller, fmt, ## args )
-#define ehci_warn(ehci, fmt, args...) \
-	dev_warn (*(ehci)->hcd.controller, fmt, ## args )
-
-#else
-
 #ifdef DEBUG
 #define ehci_dbg(ehci, fmt, args...) \
-	printk(KERN_DEBUG "%s %s: " fmt, hcd_name, \
-		(ehci)->hcd.pdev->slot_name, ## args )
+	printk(KERN_DEBUG "%s %s: " fmt , hcd_name , \
+		(ehci)->hcd.pdev->slot_name , ## args )
 #else
 #define ehci_dbg(ehci, fmt, args...) do { } while (0)
 #endif
 
 #define ehci_err(ehci, fmt, args...) \
-	printk(KERN_ERR "%s %s: " fmt, hcd_name, \
-		(ehci)->hcd.pdev->slot_name, ## args )
+	printk(KERN_ERR "%s %s: " fmt , hcd_name , \
+		(ehci)->hcd.pdev->slot_name , ## args )
 #define ehci_info(ehci, fmt, args...) \
-	printk(KERN_INFO "%s %s: " fmt, hcd_name, \
-		(ehci)->hcd.pdev->slot_name, ## args )
+	printk(KERN_INFO "%s %s: " fmt , hcd_name , \
+		(ehci)->hcd.pdev->slot_name , ## args )
 #define ehci_warn(ehci, fmt, args...) \
-	printk(KERN_WARNING "%s %s: " fmt, hcd_name, \
-		(ehci)->hcd.pdev->slot_name, ## args )
-#endif
+	printk(KERN_WARNING "%s %s: " fmt , hcd_name , \
+		(ehci)->hcd.pdev->slot_name , ## args )
 
 
 #ifdef EHCI_VERBOSE_DEBUG
diff -urN linux-2.4.21-pre3/drivers/usb/hcd.c linux-2.4.21-pre4/drivers/usb/hcd.c
--- linux-2.4.21-pre3/drivers/usb/hcd.c	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/drivers/usb/hcd.c	Tue Jan 28 19:44:31 2003
@@ -311,9 +311,9 @@
 	} else
 	    return 0;
 
-	data [0] = 2 + ascii2utf (buf, data + 2, len - 2);
+	data [0] = 2 * (strlen (buf) + 1);
 	data [1] = 3;	/* type == string */
-	return data [0];
+	return 2 + ascii2utf (buf, data + 2, len - 2);
 }
 
 
diff -urN linux-2.4.21-pre3/drivers/usb/konicawc.c linux-2.4.21-pre4/drivers/usb/konicawc.c
--- linux-2.4.21-pre3/drivers/usb/konicawc.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/drivers/usb/konicawc.c	Tue Jan 28 19:44:31 2003
@@ -0,0 +1,938 @@
+/*
+ * konicawc.c - konica webcam driver
+ *
+ * Author: Simon Evans <spse@secret.org.uk>
+ *
+ * Copyright (C) 2002 Simon Evans
+ *
+ * Licence: GPL
+ *
+ * Driver for USB webcams based on Konica chipset. This
+ * chipset is used in Intel YC76 camera.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+
+#include "usbvideo.h"
+
+#define MAX_BRIGHTNESS	108
+#define MAX_CONTRAST	108
+#define MAX_SATURATION	108
+#define MAX_SHARPNESS	108
+#define MAX_WHITEBAL	372
+#define MAX_SPEED	6
+
+
+#define MAX_CAMERAS	1
+
+#define DRIVER_VERSION	"v1.4"
+#define DRIVER_DESC	"Konica Webcam driver"
+
+enum ctrl_req {
+	SetWhitebal	= 0x01,
+	SetBrightness	= 0x02,
+        SetSharpness	= 0x03,
+	SetContrast	= 0x04,
+	SetSaturation	= 0x05,
+};
+
+
+enum frame_sizes {
+	SIZE_160X120	= 0,
+	SIZE_160X136	= 1,
+	SIZE_176X144	= 2,
+	SIZE_320X240	= 3,
+	
+};
+
+#define MAX_FRAME_SIZE	SIZE_320X240
+
+static struct usbvideo *cams;
+
+#ifdef CONFIG_USB_DEBUG
+static int debug;
+#define DEBUG(n, format, arg...) \
+	if (n <= debug) {	 \
+		printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __FUNCTION__ , ## arg); \
+	}
+#else
+#define DEBUG(n, arg...)
+static const int debug = 0;
+#endif
+
+
+/* Some default values for inital camera settings,
+   can be set by modprobe */
+
+static enum frame_sizes size;	
+static int speed = 6;		/* Speed (fps) 0 (slowest) to 6 (fastest) */
+static int brightness =	MAX_BRIGHTNESS/2;
+static int contrast =	MAX_CONTRAST/2;
+static int saturation =	MAX_SATURATION/2;
+static int sharpness =	MAX_SHARPNESS/2;
+static int whitebal =	3*(MAX_WHITEBAL/4);
+
+static int spd_to_iface[] = { 1, 0, 3, 2, 4, 5, 6 };
+
+/* These FPS speeds are from the windows config box. They are
+ * indexed on size (0-3) and speed (0-6). Divide by 3 to get the
+ * real fps.
+ */
+
+static int spd_to_fps[][7] = { { 24, 40, 48, 60, 72, 80, 100 },
+			       { 24, 40, 48, 60, 72, 80, 100 },
+			       { 18, 30, 36, 45, 54, 60, 75  },
+			       { 6,  10, 12, 15, 18, 21, 25  } };
+
+struct cam_size {
+	u16	width;
+	u16	height;
+	u8	cmd;
+};
+
+static struct cam_size camera_sizes[] = { { 160, 120, 0x7 },
+					  { 160, 136, 0xa },
+					  { 176, 144, 0x4 },
+					  { 320, 240, 0x5 } };
+
+struct konicawc {
+	u8 brightness;		/* camera uses 0 - 9, x11 for real value */
+	u8 contrast;		/* as above */
+	u8 saturation;		/* as above */
+	u8 sharpness;		/* as above */
+	u8 white_bal;		/* 0 - 33, x11 for real value */
+	u8 speed;		/* Stored as 0 - 6, used as index in spd_to_* (above) */
+	u8 size;		/* Frame Size */
+	int height;
+	int width;
+	struct urb *sts_urb[USBVIDEO_NUMSBUF];
+	u8 sts_buf[USBVIDEO_NUMSBUF][FRAMES_PER_DESC];
+	struct urb *last_data_urb, *last_sts_urb;
+	int lastframe;
+	int cur_frame_size;	/* number of bytes in current frame size */
+	int maxline;		/* number of lines per frame */
+	int yplanesz;		/* Number of bytes in the Y plane */
+	unsigned int buttonsts:1;
+#ifdef CONFIG_INPUT
+	struct input_dev input;
+#endif
+};
+
+
+#define konicawc_set_misc(uvd, req, value, index)		konicawc_ctrl_msg(uvd, USB_DIR_OUT, req, value, index, NULL, 0)
+#define konicawc_get_misc(uvd, req, value, index, buf, sz)	konicawc_ctrl_msg(uvd, USB_DIR_IN, req, value, index, buf, sz)
+#define konicawc_set_value(uvd, value, index)			konicawc_ctrl_msg(uvd, USB_DIR_OUT, 2, value, index, NULL, 0)
+
+
+static int konicawc_ctrl_msg(struct uvd *uvd, u8 dir, u8 request, u16 value, u16 index, void *buf, int len)
+{
+        int retval = usb_control_msg(uvd->dev,
+		dir ? usb_rcvctrlpipe(uvd->dev, 0) : usb_sndctrlpipe(uvd->dev, 0),
+		    request, 0x40 | dir, value, index, buf, len, HZ);
+        return retval < 0 ? retval : 0;
+}
+
+
+static inline void konicawc_camera_on(struct uvd *uvd)
+{
+        DEBUG(0, "camera on");
+        konicawc_set_misc(uvd, 0x2, 1, 0x0b);
+}
+
+
+static inline void konicawc_camera_off(struct uvd *uvd)
+{
+        DEBUG(0, "camera off");
+        konicawc_set_misc(uvd, 0x2, 0, 0x0b);
+}
+
+
+static void konicawc_set_camera_size(struct uvd *uvd)
+{
+	struct konicawc *cam = (struct konicawc *)uvd->user_data;
+
+	konicawc_set_misc(uvd, 0x2, camera_sizes[cam->size].cmd, 0x08);
+	cam->width = camera_sizes[cam->size].width;
+	cam->height = camera_sizes[cam->size].height;
+	cam->yplanesz = cam->height * cam->width;
+	cam->cur_frame_size = (cam->yplanesz * 3) / 2;
+	cam->maxline = cam->yplanesz / 256;
+	uvd->videosize = VIDEOSIZE(cam->width, cam->height);
+}
+
+
+static int konicawc_setup_on_open(struct uvd *uvd)
+{
+	struct konicawc *cam = (struct konicawc *)uvd->user_data;
+
+	DEBUG(1, "setting brightness to %d (%d)", cam->brightness,
+	    cam->brightness * 11);
+	konicawc_set_value(uvd, cam->brightness, SetBrightness);
+	DEBUG(1, "setting white balance to %d (%d)", cam->white_bal,
+	    cam->white_bal * 11);
+	konicawc_set_value(uvd, cam->white_bal, SetWhitebal);
+	DEBUG(1, "setting contrast to %d (%d)", cam->contrast,
+	    cam->contrast * 11);
+	konicawc_set_value(uvd, cam->contrast, SetContrast);
+	DEBUG(1, "setting saturation to %d (%d)", cam->saturation,
+	    cam->saturation * 11);
+	konicawc_set_value(uvd, cam->saturation, SetSaturation);
+	DEBUG(1, "setting sharpness to %d (%d)", cam->sharpness,
+	    cam->sharpness * 11);
+	konicawc_set_value(uvd, cam->sharpness, SetSharpness);
+	konicawc_set_camera_size(uvd);
+	cam->lastframe = -2;
+	cam->buttonsts = 0;
+	return 0;
+}
+
+
+static void konicawc_adjust_picture(struct uvd *uvd)
+{
+	struct konicawc *cam = (struct konicawc *)uvd->user_data;
+
+	konicawc_camera_off(uvd);
+	DEBUG(1, "new brightness: %d", uvd->vpic.brightness);
+	uvd->vpic.brightness = (uvd->vpic.brightness > MAX_BRIGHTNESS) ? MAX_BRIGHTNESS : uvd->vpic.brightness;
+	if(cam->brightness != uvd->vpic.brightness / 11) {
+	   cam->brightness = uvd->vpic.brightness / 11;
+	   DEBUG(1, "setting brightness to %d (%d)", cam->brightness,
+	       cam->brightness * 11);
+	   konicawc_set_value(uvd, cam->brightness, SetBrightness);
+	}
+
+	DEBUG(1, "new contrast: %d", uvd->vpic.contrast);
+	uvd->vpic.contrast = (uvd->vpic.contrast > MAX_CONTRAST) ? MAX_CONTRAST : uvd->vpic.contrast;
+	if(cam->contrast != uvd->vpic.contrast / 11) {
+		cam->contrast = uvd->vpic.contrast / 11;
+		DEBUG(1, "setting contrast to %d (%d)", cam->contrast,
+		    cam->contrast * 11);
+		konicawc_set_value(uvd, cam->contrast, SetContrast);
+	}
+	konicawc_camera_on(uvd);
+}
+
+
+static int konicawc_compress_iso(struct uvd *uvd, struct urb *dataurb, struct urb *stsurb)
+{
+	char *cdata;
+	int i, totlen = 0;
+	unsigned char *status = stsurb->transfer_buffer;
+	int keep = 0, discard = 0, bad = 0;
+	struct konicawc *cam = (struct konicawc *)uvd->user_data;
+
+	for (i = 0; i < dataurb->number_of_packets; i++) {
+		int button = cam->buttonsts;
+		unsigned char sts;
+		int n = dataurb->iso_frame_desc[i].actual_length;
+		int st = dataurb->iso_frame_desc[i].status;
+		cdata = dataurb->transfer_buffer +
+			dataurb->iso_frame_desc[i].offset;
+
+		/* Detect and ignore errored packets */
+		if (st < 0) {
+			DEBUG(1, "Data error: packet=%d. len=%d. status=%d.",
+			      i, n, st);
+			uvd->stats.iso_err_count++;
+			continue;
+		}
+
+		/* Detect and ignore empty packets */
+		if (n <= 0) {
+			uvd->stats.iso_skip_count++;
+			continue;
+		}
+
+		/* See what the status data said about the packet */
+		sts = *(status+stsurb->iso_frame_desc[i].offset);
+
+		/* sts: 0x80-0xff: frame start with frame number (ie 0-7f)
+		 * otherwise:
+		 * bit 0 0: keep packet
+		 *	 1: drop packet (padding data)
+		 *
+		 * bit 4 0 button not clicked
+		 *       1 button clicked
+		 * button is used to `take a picture' (in software)
+		 */
+
+		if(sts < 0x80) {
+			button = !!(sts & 0x40);
+			sts &= ~0x40;
+		}
+		
+		/* work out the button status, but dont do
+		   anything with it for now */
+
+		if(button != cam->buttonsts) {
+			DEBUG(2, "button: %sclicked", button ? "" : "un");
+			cam->buttonsts = button;
+#ifdef CONFIG_INPUT
+			input_report_key(&cam->input, BTN_0, cam->buttonsts);
+#endif
+		}
+
+		if(sts == 0x01) { /* drop frame */
+			discard++;
+			continue;
+		}
+		
+		if((sts > 0x01) && (sts < 0x80)) {
+			info("unknown status %2.2x", sts);
+			bad++;
+			continue;
+		}
+		if(!sts && cam->lastframe == -2) {
+			DEBUG(2, "dropping frame looking for image start");
+			continue;
+		}
+
+		keep++;
+		if(sts & 0x80) { /* frame start */
+			unsigned char marker[] = { 0, 0xff, 0, 0x00 };
+
+			if(cam->lastframe == -2) {
+				DEBUG(2, "found initial image");
+				cam->lastframe = -1;
+			}
+				
+			marker[3] = sts & 0x7F;
+			RingQueue_Enqueue(&uvd->dp, marker, 4);
+			totlen += 4;
+		}
+
+		totlen += n;	/* Little local accounting */
+		RingQueue_Enqueue(&uvd->dp, cdata, n);
+	}
+	DEBUG(8, "finished: keep = %d discard = %d bad = %d added %d bytes",
+		    keep, discard, bad, totlen);
+	return totlen;
+}
+
+
+static void resubmit_urb(struct uvd *uvd, struct urb *urb)
+{
+        int i, ret;
+        for (i = 0; i < FRAMES_PER_DESC; i++) {
+                urb->iso_frame_desc[i].status = 0;
+        }
+        urb->dev = uvd->dev;
+        urb->status = 0;
+        ret = usb_submit_urb(urb);
+	DEBUG(3, "submitting urb of length %d", urb->transfer_buffer_length);
+        if(ret)
+                err("usb_submit_urb error (%d)", ret);
+
+}
+
+
+static void konicawc_isoc_irq(struct urb *urb)
+{
+	struct uvd *uvd = urb->context;
+	struct konicawc *cam = (struct konicawc *)uvd->user_data;
+
+	/* We don't want to do anything if we are about to be removed! */
+	if (!CAMERA_IS_OPERATIONAL(uvd))
+		return;
+
+	if (!uvd->streaming) {
+		DEBUG(1, "Not streaming, but interrupt!");
+		return;
+	}
+
+	DEBUG(3, "got frame %d len = %d buflen =%d", urb->start_frame, urb->actual_length, urb->transfer_buffer_length);
+
+	uvd->stats.urb_count++;
+
+	if (urb->transfer_buffer_length > 32) {
+		cam->last_data_urb = urb;
+	} else {
+		cam->last_sts_urb = urb;
+	}
+	/* Copy the data received into ring queue */
+	if(cam->last_data_urb && cam->last_sts_urb) {
+		int len = 0;
+		if(cam->last_sts_urb->start_frame != cam->last_data_urb->start_frame)
+			err("Lost sync on frames (%d != %d)",
+			    cam->last_sts_urb->start_frame, cam->last_data_urb->start_frame);
+		else if (!cam->last_sts_urb->status && !cam->last_data_urb->status)
+			len = konicawc_compress_iso(uvd, cam->last_data_urb,
+						    cam->last_sts_urb);
+
+		resubmit_urb(uvd, cam->last_sts_urb);
+		resubmit_urb(uvd, cam->last_data_urb);
+		cam->last_data_urb = NULL;
+		cam->last_sts_urb = NULL;
+		uvd->stats.urb_length = len;
+		uvd->stats.data_count += len;
+		if(len)
+			RingQueue_WakeUpInterruptible(&uvd->dp);
+		return;
+	}
+	return;
+}
+
+
+static int konicawc_start_data(struct uvd *uvd)
+{
+	struct usb_device *dev = uvd->dev;
+	int i, errFlag;
+	struct konicawc *cam = (struct konicawc *)uvd->user_data;
+	int pktsz;
+	struct usb_interface_descriptor *interface;
+
+	interface = &dev->actconfig->interface[uvd->iface].altsetting[spd_to_iface[cam->speed]];
+	pktsz = interface->endpoint[1].wMaxPacketSize;
+	DEBUG(1, "pktsz = %d", pktsz);
+	if (!CAMERA_IS_OPERATIONAL(uvd)) {
+		err("Camera is not operational");
+		return -EFAULT;
+	}
+	uvd->curframe = -1;
+	konicawc_camera_on(uvd);
+	/* Alternate interface 1 is is the biggest frame size */
+	i = usb_set_interface(dev, uvd->iface, uvd->ifaceAltActive);
+	if (i < 0) {
+		err("usb_set_interface error");
+		uvd->last_error = i;
+		return -EBUSY;
+	}
+
+	/* We double buffer the Iso lists */
+	for (i=0; i < USBVIDEO_NUMSBUF; i++) {
+		int j, k;
+		struct urb *urb = uvd->sbuf[i].urb;
+		urb->dev = dev;
+		urb->context = uvd;
+		urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp);
+		urb->interval = 1;
+		urb->transfer_flags = USB_ISO_ASAP;
+		urb->transfer_buffer = uvd->sbuf[i].data;
+		urb->complete = konicawc_isoc_irq;
+		urb->number_of_packets = FRAMES_PER_DESC;
+		urb->transfer_buffer_length = pktsz * FRAMES_PER_DESC;
+		for (j=k=0; j < FRAMES_PER_DESC; j++, k += pktsz) {
+			urb->iso_frame_desc[j].offset = k;
+			urb->iso_frame_desc[j].length = pktsz;
+		}
+
+		urb = cam->sts_urb[i];
+		urb->dev = dev;
+		urb->context = uvd;
+		urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp-1);
+		urb->interval = 1;
+		urb->transfer_flags = USB_ISO_ASAP;
+		urb->transfer_buffer = cam->sts_buf[i];
+		urb->complete = konicawc_isoc_irq;
+		urb->number_of_packets = FRAMES_PER_DESC;
+		urb->transfer_buffer_length = FRAMES_PER_DESC;
+		for (j=0; j < FRAMES_PER_DESC; j++) {
+			urb->iso_frame_desc[j].offset = j;
+			urb->iso_frame_desc[j].length = 1;
+		}
+	}
+
+	cam->last_data_urb = NULL;
+	cam->last_sts_urb = NULL;
+	
+	/* Submit all URBs */
+	for (i=0; i < USBVIDEO_NUMSBUF; i++) {
+		errFlag = usb_submit_urb(cam->sts_urb[i]);
+		if (errFlag)
+			err("usb_submit_isoc(%d) ret %d", i, errFlag);
+
+		errFlag = usb_submit_urb(uvd->sbuf[i].urb);
+		if (errFlag)
+			err ("usb_submit_isoc(%d) ret %d", i, errFlag);
+	}
+
+	uvd->streaming = 1;
+	DEBUG(1, "streaming=1 video_endp=$%02x", uvd->video_endp);
+	return 0;
+}
+
+
+static void konicawc_stop_data(struct uvd *uvd)
+{
+	int i, j;
+	struct konicawc *cam;
+
+	if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL))
+		return;
+
+	konicawc_camera_off(uvd);
+	uvd->streaming = 0;
+	cam = (struct konicawc *)uvd->user_data;
+	cam->last_data_urb = NULL;
+	cam->last_sts_urb = NULL;
+
+	/* Unschedule all of the iso td's */
+	for (i=0; i < USBVIDEO_NUMSBUF; i++) {
+		j = usb_unlink_urb(uvd->sbuf[i].urb);
+		if (j < 0)
+			err("usb_unlink_urb() error %d.", j);
+
+		j = usb_unlink_urb(cam->sts_urb[i]);
+		if (j < 0)
+			err("usb_unlink_urb() error %d.", j);
+	}
+
+	if (!uvd->remove_pending) {
+		/* Set packet size to 0 */
+		j = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltInactive);
+		if (j < 0) {
+			err("usb_set_interface() error %d.", j);
+			uvd->last_error = j;
+		}
+	}
+}
+
+
+static void konicawc_process_isoc(struct uvd *uvd, struct usbvideo_frame *frame)
+{	
+	struct konicawc *cam = (struct konicawc *)uvd->user_data;
+	int maxline = cam->maxline;
+	int yplanesz = cam->yplanesz;
+
+	assert(frame != NULL);
+
+	DEBUG(5, "maxline = %d yplanesz = %d", maxline, yplanesz);
+	DEBUG(3, "Frame state = %d", frame->scanstate);
+
+	if(frame->scanstate == ScanState_Scanning) {
+		int drop = 0;
+		int curframe;
+		int fdrops = 0;
+		DEBUG(3, "Searching for marker, queue len = %d", RingQueue_GetLength(&uvd->dp));
+		while(RingQueue_GetLength(&uvd->dp) >= 4) {
+			if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) &&
+			    (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xff) &&
+			    (RING_QUEUE_PEEK(&uvd->dp, 2) == 0x00) &&
+			    (RING_QUEUE_PEEK(&uvd->dp, 3) < 0x80)) {
+				curframe = RING_QUEUE_PEEK(&uvd->dp, 3);
+				if(cam->lastframe >= 0) {
+					fdrops = (0x80 + curframe - cam->lastframe) & 0x7F;
+					fdrops--;
+					if(fdrops) {
+						info("Dropped %d frames (%d -> %d)", fdrops,
+						     cam->lastframe, curframe);
+					}
+				}
+				cam->lastframe = curframe;
+				frame->curline = 0;
+				frame->scanstate = ScanState_Lines;
+				RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 4);
+				break;
+			}
+			RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1);
+			drop++;
+		}
+		if(drop)
+			DEBUG(2, "dropped %d bytes looking for new frame", drop);
+	}
+
+	if(frame->scanstate == ScanState_Scanning)
+		return;
+		
+	/* Try to move data from queue into frame buffer
+	 * We get data in blocks of 384 bytes made up of:
+	 * 256 Y, 64 U, 64 V.
+	 * This needs to be written out as a Y plane, a U plane and a V plane.
+	 */
+		
+	while ( frame->curline < maxline && (RingQueue_GetLength(&uvd->dp) >= 384)) {
+		/* Y */
+		RingQueue_Dequeue(&uvd->dp, frame->data + (frame->curline * 256), 256);
+		/* U */
+		RingQueue_Dequeue(&uvd->dp, frame->data + yplanesz + (frame->curline * 64), 64);
+		/* V */
+		RingQueue_Dequeue(&uvd->dp, frame->data + (5 * yplanesz)/4 + (frame->curline * 64), 64);
+		frame->seqRead_Length += 384;
+		frame->curline++;
+	}
+	/* See if we filled the frame */
+	if (frame->curline == maxline) {
+		DEBUG(5, "got whole frame");
+
+		frame->frameState = FrameState_Done_Hold;
+		frame->curline = 0;
+		uvd->curframe = -1;
+		uvd->stats.frame_num++;
+	}
+}
+
+
+static int konicawc_find_fps(int size, int fps)
+{
+	int i;
+
+	fps *= 3;
+	DEBUG(1, "konica_find_fps: size = %d fps = %d", size, fps);
+	if(fps <= spd_to_fps[size][0])
+		return 0;
+
+	if(fps >= spd_to_fps[size][MAX_SPEED])
+		return MAX_SPEED;
+
+	for(i = 0; i < MAX_SPEED; i++) {
+		if((fps >= spd_to_fps[size][i]) && (fps <= spd_to_fps[size][i+1])) {
+			DEBUG(2, "fps %d between %d and %d", fps, i, i+1);
+			if( (fps - spd_to_fps[size][i]) < (spd_to_fps[size][i+1] - fps))
+				return i;
+			else
+				return i+1;
+		}
+	}
+	return MAX_SPEED+1;
+}
+
+
+static int konicawc_set_video_mode(struct uvd *uvd, struct video_window *vw)
+{
+	struct konicawc *cam = (struct konicawc *)uvd->user_data;
+	int newspeed = cam->speed;
+	int newsize;
+	int x = vw->width;
+	int y = vw->height;
+	int fps = vw->flags;
+
+	if(x > 0 && y > 0) {
+		DEBUG(2, "trying to find size %d,%d", x, y);
+		for(newsize = 0; newsize <= MAX_FRAME_SIZE; newsize++) {
+			if((camera_sizes[newsize].width == x) && (camera_sizes[newsize].height == y))
+				break;
+		}
+	} else {
+		newsize = cam->size;
+	}
+
+	if(newsize > MAX_FRAME_SIZE) {
+		DEBUG(1, "couldnt find size %d,%d", x, y);
+		return -EINVAL;
+	}
+
+	if(fps > 0) {
+		DEBUG(1, "trying to set fps to %d", fps);
+		newspeed = konicawc_find_fps(newsize, fps);
+		DEBUG(1, "find_fps returned %d (%d)", newspeed, spd_to_fps[newsize][newspeed]);
+	}
+
+	if(newspeed > MAX_SPEED)
+		return -EINVAL;
+
+	DEBUG(1, "setting size to %d speed to %d", newsize, newspeed);
+	if((newsize == cam->size) && (newspeed == cam->speed)) {
+		DEBUG(1, "Nothing to do");
+		return 0;
+	}
+	DEBUG(0, "setting to  %dx%d @ %d fps", camera_sizes[newsize].width,
+	     camera_sizes[newsize].height, spd_to_fps[newsize][newspeed]/3);
+
+	konicawc_stop_data(uvd);
+	uvd->ifaceAltActive = spd_to_iface[newspeed];
+	DEBUG(1, "new interface = %d", uvd->ifaceAltActive);
+	cam->speed = newspeed;
+
+	if(cam->size != newsize) {
+		cam->size = newsize;
+		konicawc_set_camera_size(uvd);
+	}
+
+	/* Flush the input queue and clear any current frame in progress */
+
+	RingQueue_Flush(&uvd->dp);
+	cam->lastframe = -2;
+	if(uvd->curframe != -1) {
+	  uvd->frame[uvd->curframe].curline = 0;
+	  uvd->frame[uvd->curframe].seqRead_Length = 0;
+	  uvd->frame[uvd->curframe].seqRead_Index = 0;
+	}
+
+	konicawc_start_data(uvd);
+	return 0;
+}
+
+
+static int konicawc_calculate_fps(struct uvd *uvd)
+{
+	struct konicawc *cam = uvd->user_data;
+	return spd_to_fps[cam->size][cam->speed]/3;
+}
+
+
+static void konicawc_configure_video(struct uvd *uvd)
+{
+	struct konicawc *cam = (struct konicawc *)uvd->user_data;
+	u8 buf[2];
+
+	memset(&uvd->vpic, 0, sizeof(uvd->vpic));
+	memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old));
+
+	RESTRICT_TO_RANGE(brightness, 0, MAX_BRIGHTNESS);
+	RESTRICT_TO_RANGE(contrast, 0, MAX_CONTRAST);
+	RESTRICT_TO_RANGE(saturation, 0, MAX_SATURATION);
+	RESTRICT_TO_RANGE(sharpness, 0, MAX_SHARPNESS);
+	RESTRICT_TO_RANGE(whitebal, 0, MAX_WHITEBAL);
+
+	cam->brightness = brightness / 11;
+	cam->contrast = contrast / 11;
+	cam->saturation = saturation / 11;
+	cam->sharpness = sharpness / 11;
+	cam->white_bal = whitebal / 11;
+
+	uvd->vpic.colour = 108;
+	uvd->vpic.hue = 108;
+	uvd->vpic.brightness = brightness;
+	uvd->vpic.contrast = contrast;
+	uvd->vpic.whiteness = whitebal;
+	uvd->vpic.depth = 6;
+	uvd->vpic.palette = VIDEO_PALETTE_YUV420P;
+
+	memset(&uvd->vcap, 0, sizeof(uvd->vcap));
+	strcpy(uvd->vcap.name, "Konica Webcam");
+	uvd->vcap.type = VID_TYPE_CAPTURE;
+	uvd->vcap.channels = 1;
+	uvd->vcap.audios = 0;
+	uvd->vcap.minwidth = camera_sizes[SIZE_160X120].width;
+	uvd->vcap.minheight = camera_sizes[SIZE_160X120].height;
+	uvd->vcap.maxwidth = camera_sizes[SIZE_320X240].width;
+	uvd->vcap.maxheight = camera_sizes[SIZE_320X240].height;
+
+	memset(&uvd->vchan, 0, sizeof(uvd->vchan));
+	uvd->vchan.flags = 0 ;
+	uvd->vchan.tuners = 0;
+	uvd->vchan.channel = 0;
+	uvd->vchan.type = VIDEO_TYPE_CAMERA;
+	strcpy(uvd->vchan.name, "Camera");
+
+	/* Talk to device */
+	DEBUG(1, "device init");
+	if(!konicawc_get_misc(uvd, 0x3, 0, 0x10, buf, 2))
+		DEBUG(2, "3,10 -> %2.2x %2.2x", buf[0], buf[1]);
+	if(!konicawc_get_misc(uvd, 0x3, 0, 0x10, buf, 2))
+		DEBUG(2, "3,10 -> %2.2x %2.2x", buf[0], buf[1]);
+	if(konicawc_set_misc(uvd, 0x2, 0, 0xd))
+		DEBUG(2, "2,0,d failed");
+	DEBUG(1, "setting initial values");
+}
+
+
+static void *konicawc_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *devid)
+{
+	struct uvd *uvd = NULL;
+	int i, nas;
+	int actInterface=-1, inactInterface=-1, maxPS=0;
+	unsigned char video_ep = 0;
+
+	DEBUG(1, "konicawc_probe(%p,%u.)", dev, ifnum);
+
+	/* We don't handle multi-config cameras */
+	if (dev->descriptor.bNumConfigurations != 1)
+		return NULL;
+
+	info("Konica Webcam (rev. 0x%04x)", dev->descriptor.bcdDevice);
+	RESTRICT_TO_RANGE(speed, 0, MAX_SPEED);
+
+	/* Validate found interface: must have one ISO endpoint */
+	nas = dev->actconfig->interface[ifnum].num_altsetting;
+	if (nas != 8) {
+		err("Incorrect number of alternate settings (%d) for this camera!", nas);
+		return NULL;
+	}
+	/* Validate all alternate settings */
+	for (i=0; i < nas; i++) {
+		const struct usb_interface_descriptor *interface;
+		const struct usb_endpoint_descriptor *endpoint;
+
+		interface = &dev->actconfig->interface[ifnum].altsetting[i];
+		if (interface->bNumEndpoints != 2) {
+			err("Interface %d. has %u. endpoints!",
+			    ifnum, (unsigned)(interface->bNumEndpoints));
+			return NULL;
+		}
+		endpoint = &interface->endpoint[1];
+		DEBUG(1, "found endpoint: addr: 0x%2.2x maxps = 0x%4.4x",
+		    endpoint->bEndpointAddress, endpoint->wMaxPacketSize);
+		if (video_ep == 0)
+			video_ep = endpoint->bEndpointAddress;
+		else if (video_ep != endpoint->bEndpointAddress) {
+			err("Alternate settings have different endpoint addresses!");
+			return NULL;
+		}
+		if ((endpoint->bmAttributes & 0x03) != 0x01) {
+			err("Interface %d. has non-ISO endpoint!", ifnum);
+			return NULL;
+		}
+		if ((endpoint->bEndpointAddress & 0x80) == 0) {
+			err("Interface %d. has ISO OUT endpoint!", ifnum);
+			return NULL;
+		}
+		if (endpoint->wMaxPacketSize == 0) {
+			if (inactInterface < 0)
+				inactInterface = i;
+			else {
+				err("More than one inactive alt. setting!");
+				return NULL;
+			}
+		} else {
+			if (i == spd_to_iface[speed]) {
+				/* This one is the requested one */
+				actInterface = i;
+			}
+		}
+		if(endpoint->wMaxPacketSize > maxPS)
+			maxPS = endpoint->wMaxPacketSize;
+	}
+	if(actInterface == -1) {
+		err("Cant find required endpoint");
+		return NULL;
+	}
+
+	DEBUG(1, "Selecting requested active setting=%d. maxPS=%d.", actInterface, maxPS);
+
+	/* Code below may sleep, need to lock module while we are here */
+	MOD_INC_USE_COUNT;
+	uvd = usbvideo_AllocateDevice(cams);
+	if (uvd != NULL) {
+		struct konicawc *cam = (struct konicawc *)(uvd->user_data);
+		/* Here uvd is a fully allocated uvd object */
+		for(i = 0; i < USBVIDEO_NUMSBUF; i++) {
+			cam->sts_urb[i] = usb_alloc_urb(FRAMES_PER_DESC);
+			if(cam->sts_urb[i] == NULL) {
+				while(i--) {
+					usb_free_urb(cam->sts_urb[i]);
+				}
+				err("cant allocate urbs");
+				return NULL;
+			}
+		}
+		cam->speed = speed;
+		RESTRICT_TO_RANGE(size, SIZE_160X120, SIZE_320X240);
+		cam->width = camera_sizes[size].width;
+		cam->height = camera_sizes[size].height;
+		cam->size = size;
+
+		uvd->flags = 0;
+		uvd->debug = debug;
+		uvd->dev = dev;
+		uvd->iface = ifnum;
+		uvd->ifaceAltInactive = inactInterface;
+		uvd->ifaceAltActive = actInterface;
+		uvd->video_endp = video_ep;
+		uvd->iso_packet_len = maxPS;
+		uvd->paletteBits = 1L << VIDEO_PALETTE_YUV420P;
+		uvd->defaultPalette = VIDEO_PALETTE_YUV420P;
+		uvd->canvas = VIDEOSIZE(320, 240);
+		uvd->videosize = VIDEOSIZE(cam->width, cam->height);
+
+		/* Initialize konicawc specific data */
+		konicawc_configure_video(uvd);
+
+		i = usbvideo_RegisterVideoDevice(uvd);
+		uvd->max_frame_size = (320 * 240 * 3)/2;
+		if (i != 0) {
+			err("usbvideo_RegisterVideoDevice() failed.");
+			uvd = NULL;
+		}
+#ifdef CONFIG_INPUT
+		/* Register input device for button */
+		memset(&cam->input, 0, sizeof(struct input_dev));
+		cam->input.name = "Konicawc snapshot button";
+		cam->input.private = cam;
+		cam->input.evbit[0] = BIT(EV_KEY);
+		cam->input.keybit[LONG(BTN_0)] = BIT(BTN_0);
+		cam->input.idbus = BUS_USB;
+		cam->input.idvendor = dev->descriptor.idVendor;
+		cam->input.idproduct = dev->descriptor.idProduct;
+		cam->input.idversion = dev->descriptor.bcdDevice;
+		input_register_device(&cam->input);
+#endif
+	}
+	MOD_DEC_USE_COUNT;
+	return uvd;
+}
+
+
+static void konicawc_free_uvd(struct uvd *uvd)
+{
+	int i;
+	struct konicawc *cam = (struct konicawc *)uvd->user_data;
+
+#ifdef CONFIG_INPUT
+	input_unregister_device(&cam->input);
+#endif
+	for (i=0; i < USBVIDEO_NUMSBUF; i++) {
+		usb_free_urb(cam->sts_urb[i]);
+		cam->sts_urb[i] = NULL;
+	}
+}
+
+
+static struct usb_device_id id_table[] = {
+	{ USB_DEVICE(0x04c8, 0x0720) }, /* Intel YC 76 */
+	{ }  /* Terminating entry */
+};
+
+
+static int __init konicawc_init(void)
+{
+	struct usbvideo_cb cbTbl;
+	info(DRIVER_DESC " " DRIVER_VERSION);
+	memset(&cbTbl, 0, sizeof(cbTbl));
+	cbTbl.probe = konicawc_probe;
+	cbTbl.setupOnOpen = konicawc_setup_on_open;
+	cbTbl.processData = konicawc_process_isoc;
+	cbTbl.getFPS = konicawc_calculate_fps;
+	cbTbl.setVideoMode = konicawc_set_video_mode;
+	cbTbl.startDataPump = konicawc_start_data;
+	cbTbl.stopDataPump = konicawc_stop_data;
+	cbTbl.adjustPicture = konicawc_adjust_picture;
+	cbTbl.userFree = konicawc_free_uvd;
+	return usbvideo_register(
+		&cams,
+		MAX_CAMERAS,
+		sizeof(struct konicawc),
+		"konicawc",
+		&cbTbl,
+		THIS_MODULE,
+		id_table);
+}
+
+
+static void __exit konicawc_cleanup(void)
+{
+	usbvideo_Deregister(&cams);
+}
+
+
+MODULE_DEVICE_TABLE(usb, id_table);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Simon Evans <spse@secret.org.uk>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_PARM(speed, "i");
+MODULE_PARM_DESC(speed, "Initial speed: 0 (slowest) - 6 (fastest)");
+MODULE_PARM(size, "i");
+MODULE_PARM_DESC(size, "Initial Size 0: 160x120 1: 160x136 2: 176x144 3: 320x240");
+MODULE_PARM(brightness, "i");
+MODULE_PARM_DESC(brightness, "Initial brightness 0 - 108");
+MODULE_PARM(contrast, "i");
+MODULE_PARM_DESC(contrast, "Initial contrast 0 - 108");
+MODULE_PARM(saturation, "i");
+MODULE_PARM_DESC(saturation, "Initial saturation 0 - 108");
+MODULE_PARM(sharpness, "i");
+MODULE_PARM_DESC(sharpness, "Initial sharpness 0 - 108");
+MODULE_PARM(whitebal, "i");
+MODULE_PARM_DESC(whitebal, "Initial white balance 0 - 363");
+
+#ifdef CONFIG_USB_DEBUG
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)");
+#endif
+
+module_init(konicawc_init);
+module_exit(konicawc_cleanup);
diff -urN linux-2.4.21-pre3/drivers/usb/rtl8150.c linux-2.4.21-pre4/drivers/usb/rtl8150.c
--- linux-2.4.21-pre3/drivers/usb/rtl8150.c	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/drivers/usb/rtl8150.c	Tue Jan 28 19:44:31 2003
@@ -17,6 +17,7 @@
 #include <linux/ethtool.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/usb.h>
+#include <linux/init.h>
 #include <asm/uaccess.h>
 
 /* Version Information */
diff -urN linux-2.4.21-pre3/drivers/usb/scanner.c linux-2.4.21-pre4/drivers/usb/scanner.c
--- linux-2.4.21-pre3/drivers/usb/scanner.c	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/drivers/usb/scanner.c	Tue Jan 28 19:44:31 2003
@@ -4,10 +4,13 @@
  * Driver for USB Scanners (linux-2.4.21)
  *
  * Copyright (C) 1999, 2000, 2001, 2002 David E. Nelson
+ * Copyright (C) 2002, 2003 Henning Meier-Geinitz
  *
  * Portions may be copyright Brad Keryan and Michael Gee.
  *
- * Brian Beattie <beattie@beattie-home.net>
+ * Previously maintained by Brian Beattie
+ *
+ * Current maintainer: Henning Meier-Geinitz <henning@meier-geinitz.de>
  * 
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -330,12 +333,21 @@
  *    - Add locking to ioctl_scanner(). Thanks to Oliver Neukum
  *      <oliver@neukum.name>.
  *
+ * 0.4.10  01/07/2003
+ *    - Added vendor/product ids for Visioneer scanners.
+ *    - Print information about user-supplied ids only once at startup instead
+ *      of everytime any USB device is plugged in.
+ *    - Removed PV8630 ioctls. Use the standard ioctls instead.
+ *    - Made endpoint detection more generic. Basically, only one bulk-in 
+ *      endpoint is required, everything else is optional.
+ *    - Move the scanner ioctls to usb_scanner_ioctl.h to allow access by archs
+ *      that need it (by Greg KH).
+ *    - New maintainer: Henning Meier-Geinitz.
+ *      
  * TODO
- *    - Remove the 2/3 endpoint limitation
  *    - Performance
  *    - Select/poll methods
  *    - More testing
- *    - Proper registry/assignment for LM9830 ioctl's
  *    - More general usage ioctl's
  *
  *
@@ -353,7 +365,7 @@
  *    - All the developers that are working on USB SANE backends or other
  *      applications to use USB scanners.
  *    - Thanks to Greg KH <greg@kroah.com> for setting up Brian Beattie
- *      to be the new USB Scanner maintainer.
+ *      and Henning Meier-Geinitz to be the new USB Scanner maintainer.
  *
  *  Performance:
  *
@@ -362,6 +374,14 @@
  *      24 Bit Color ~ 70 secs - 3.6 Mbit/sec
  *       8 Bit Gray ~ 17 secs - 4.2 Mbit/sec */
 
+/*
+ * For documentation, see Documentation/usb/scanner.txt.
+ * Website: http://www.meier-geinitz.de/kernel/
+ * Please contact the maintainer if your scanner is not detected by this
+ * driver automatically.
+ */
+
+
 /* 
  * Scanner definitions, macros, module info, 
  * debug/ioctl/data_dump enable, and other constants.
@@ -718,54 +738,6 @@
 	case SCANNER_IOCTL_PRODUCT :
 		retval = (put_user(dev->descriptor.idProduct, (unsigned int *) arg));
 		break;
-#ifdef PV8630
-	case PV8630_IOCTL_INREQUEST :
-	{
-		struct {
-			__u8  data;
-			__u8  request;
-			__u16 value;
-			__u16 index;
-		} args;
-
-		if (copy_from_user(&args, (void *)arg, sizeof(args))) {
-			retval = -EFAULT;
-			break;
-		}
-
-		retval = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-					 args.request, USB_TYPE_VENDOR|
-					 USB_RECIP_DEVICE|USB_DIR_IN,
-					 args.value, args.index, &args.data,
-					 1, HZ*5);
-
-		if (copy_to_user((void *)arg, &args, sizeof(args)))
-			retval = -EFAULT;
-
-		break;
-	}
-	case PV8630_IOCTL_OUTREQUEST :
-	{
-		struct {
-			__u8  request;
-			__u16 value;
-			__u16 index;
-		} args;
-
-		if (copy_from_user(&args, (void *)arg, sizeof(args))) {
-			retval = -EFAULT;
-			break;
-		}
-
-		retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-					 args.request, USB_TYPE_VENDOR|
-					 USB_RECIP_DEVICE|USB_DIR_OUT,
-					 args.value, args.index, NULL,
-					 0, HZ*5);
-
-		break;
-	}
-#endif /* PV8630 */
  	case SCANNER_IOCTL_CTRLMSG:
  	{
  		struct ctrlmsg_ioctl {
@@ -849,10 +821,6 @@
 	char have_bulk_in, have_bulk_out, have_intr;
 	char name[10];
 
-	if (vendor != -1 && product != -1) {
-		info("probe_scanner: User specified USB scanner -- Vendor:Product - %x:%x", vendor, product);
-	}
-
 	dbg("probe_scanner: USB dev address:%p", dev);
 	dbg("probe_scanner: ifnum:%u", ifnum);
 
@@ -907,7 +875,7 @@
 
 	if (interface[0].bInterfaceClass != USB_CLASS_VENDOR_SPEC &&
 	    interface[0].bInterfaceClass != USB_CLASS_PER_INTERFACE &&
-	    interface[0].bInterfaceClass != 16) {
+	    interface[0].bInterfaceClass != SCN_CLASS_SCANJET) {
 		dbg("probe_scanner: This interface doesn't look like a scanner (class=0x%x).", interface[0].bInterfaceClass);
 		return NULL;
 	}
@@ -915,38 +883,45 @@
 	endpoint = interface[0].endpoint;
 
 /*
- * Start checking for one or two bulk endpoints and an optional
- * interrupt endpoint. If we have an interrupt endpoint go ahead and
+ * Start checking for bulk and interrupt endpoints. We are only using the first
+ * one of each type of endpoint. If we have an interrupt endpoint go ahead and
  * setup the handler. FIXME: This is a future enhancement...
  */
 
 	dbg("probe_scanner: Number of Endpoints:%d", (int) interface->bNumEndpoints);
 
-	if ((interface->bNumEndpoints < 1) || (interface->bNumEndpoints > 3)) {
-		info("probe_scanner: Only 1, 2, or 3 endpoints supported.");
-		return NULL;
-	}
-
 	ep_cnt = have_bulk_in = have_bulk_out = have_intr = 0;
 
 	while (ep_cnt < interface->bNumEndpoints) {
 
-		if (!have_bulk_in && IS_EP_BULK_IN(endpoint[ep_cnt])) {
+		if (IS_EP_BULK_IN(endpoint[ep_cnt])) {
 			ep_cnt++;
+			if (have_bulk_in) {
+				info ("probe_scanner: ignoring additional bulk_in_ep:%d", ep_cnt);
+				continue;
+			}
 			have_bulk_in = ep_cnt;
 			dbg("probe_scanner: bulk_in_ep:%d", have_bulk_in);
 			continue;
 		}
 
-		if (!have_bulk_out && IS_EP_BULK_OUT(endpoint[ep_cnt])) {
+		if (IS_EP_BULK_OUT(endpoint[ep_cnt])) {
 			ep_cnt++;
+			if (have_bulk_out) {
+				info ("probe_scanner: ignoring additional bulk_out_ep:%d", ep_cnt);
+				continue;
+			}
 			have_bulk_out = ep_cnt;
 			dbg("probe_scanner: bulk_out_ep:%d", have_bulk_out);
 			continue;
 		}
 
-		if (!have_intr && IS_EP_INTR(endpoint[ep_cnt])) {
+		if (IS_EP_INTR(endpoint[ep_cnt])) {
 			ep_cnt++;
+			if (have_intr) {
+				info ("probe_scanner: ignoring additional intr_ep:%d", ep_cnt);
+				continue;
+			}
 			have_intr = ep_cnt;
 			dbg("probe_scanner: intr_ep:%d", have_intr);
 			continue;
@@ -960,28 +935,8 @@
  * Perform a quick check to make sure that everything worked as it
  * should have.
  */
-
-	switch(interface->bNumEndpoints) {
-	case 1:
-		if (!have_bulk_in) {
-			info("probe_scanner: One bulk-in endpoint required.");
-			return NULL;
-		}
-		break;
-	case 2:
-		if (!have_bulk_in || !have_bulk_out) {
-			info("probe_scanner: Two bulk endpoints required.");
-			return NULL;
-		}
-		break;
-	case 3:
-		if (!have_bulk_in || !have_bulk_out || !have_intr) {
-			info("probe_scanner: Two bulk endpoints and one interrupt endpoint required.");
-			return NULL;
-		}
-		break;
-	default:
-		info("probe_scanner: Endpoint determination failed --  consult Documentation/usb/scanner.txt");
+	if (!have_bulk_in) {
+		err("probe_scanner: One bulk-in endpoint required.");
 		return NULL;
 	}
 
@@ -1062,7 +1017,6 @@
 		break;
 	case 0x055f:		/* Mustek */
 	case 0x0400:		/* Another Mustek */
-	case 0x0ff5:		/* And yet another Mustek */
 		scn->rd_nak_timeout = HZ * 1;
 	default:
 		scn->rd_nak_timeout = RD_NAK_TIMEOUT;
@@ -1151,6 +1105,8 @@
                 return -1;
 
 	info(DRIVER_VERSION ":" DRIVER_DESC);
+	if (vendor != -1 && product != -1)
+		info("probe_scanner: User specified USB scanner -- Vendor:Product - %x:%x", vendor, product);
 	return 0;
 }
 
diff -urN linux-2.4.21-pre3/drivers/usb/scanner.h linux-2.4.21-pre4/drivers/usb/scanner.h
--- linux-2.4.21-pre3/drivers/usb/scanner.h	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/drivers/usb/scanner.h	Tue Jan 28 19:44:31 2003
@@ -2,8 +2,9 @@
  * Driver for USB Scanners (linux-2.4.21)
  *
  * Copyright (C) 1999, 2000, 2001, 2002 David E. Nelson
+ * Previously maintained by Brian Beattie
  *
- * Brian Beattie <beattie@beattie-home.net>
+ * Current maintainer: Henning Meier-Geinitz <henning@meier-geinitz.de>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -21,6 +22,13 @@
  *
  */ 
 
+/*
+ * For documentation, see Documentation/usb/scanner.txt.
+ * Website: http://www.meier-geinitz.de/kernel/
+ * Please contact the maintainer if your scanner is not detected by this
+ * driver automatically.
+ */
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
@@ -32,23 +40,18 @@
 #include <linux/sched.h>
 #include <linux/smp_lock.h>
 #include <linux/devfs_fs_kernel.h>
+#include <linux/usb_scanner_ioctl.h>
 
 // #define DEBUG
 
-/* Enable this to support the older ioctl interfaces scanners that
- * a PV8630 Scanner-On-Chip.  The prefered method is the
- * SCANNER_IOCTL_CTRLMSG ioctl.
- */
-// #define PV8630 
-
-#define DRIVER_VERSION "0.4.9"
+#define DRIVER_VERSION "0.4.10"
 #define DRIVER_DESC "USB Scanner Driver"
 
 #include <linux/usb.h>
 
 static __s32 vendor=-1, product=-1, read_timeout=0;
 
-MODULE_AUTHOR("Brian Beattie, beattie@beattie-home.net");
+MODULE_AUTHOR("Henning Meier-Geinitz, henning@meier-geinitz.de");
 MODULE_DESCRIPTION(DRIVER_DESC" "DRIVER_VERSION);
 MODULE_LICENSE("GPL");
 
@@ -119,6 +122,7 @@
 	{ USB_DEVICE(0x0458, 0x2016) }, /* ColorPage-HR6X */
 	/* Hewlett Packard */
 	{ USB_DEVICE(0x03f0, 0x0505) }, /* ScanJet 2100C */
+	{ USB_DEVICE(0x03f0, 0x0605) },	/* 2200C */
 	{ USB_DEVICE(0x03f0, 0x0901) }, /* 2300C */
 	{ USB_DEVICE(0x03f0, 0x0205) },	/* 3300C */
 	{ USB_DEVICE(0x03f0, 0x0405) }, /* 3400C */
@@ -131,7 +135,6 @@
 	//	{ USB_DEVICE(0x03f0, 0x0701) },	/* 5300C - NOT SUPPORTED - see http://www.neatech.nl/oss/HP5300C/ */
 	{ USB_DEVICE(0x03f0, 0x0201) },	/* 6200C */
 	{ USB_DEVICE(0x03f0, 0x0601) },	/* 6300C */
-	{ USB_DEVICE(0x03f0, 0x605) },	/* 2200C */
 	/* iVina */
 	{ USB_DEVICE(0x0638, 0x0268) }, /* 1200U */
 	/* Lexmark */
@@ -239,6 +242,8 @@
 	{ USB_DEVICE(0x04a7, 0x0311) },	/* 6200 EPP/USB */
 	{ USB_DEVICE(0x04a7, 0x0321) },	/* OneTouch 8100 EPP/USB */
 	{ USB_DEVICE(0x04a7, 0x0331) }, /* OneTouch 8600 EPP/USB */
+	{ USB_DEVICE(0x0461, 0x0345) }, /* 6200 (actually Primax?) */
+	{ USB_DEVICE(0x0461, 0x0371) }, /* Onetouch 8920 USB (actually Primax?) */
 	{ }				/* Terminating entry */
 };
 
@@ -265,19 +270,9 @@
 #define RD_EXPIRE 12		/* Number of attempts to wait X seconds */
 
 
-/* FIXME: These are NOT registered ioctls()'s */
-#ifdef PV8630
-#define PV8630_IOCTL_INREQUEST 69
-#define PV8630_IOCTL_OUTREQUEST 70
-#endif /* PV8630 */
-
-
-/* read vendor and product IDs from the scanner */
-#define SCANNER_IOCTL_VENDOR _IOR('U', 0x20, int)
-#define SCANNER_IOCTL_PRODUCT _IOR('U', 0x21, int)
-/* send/recv a control message to the scanner */
-#define SCANNER_IOCTL_CTRLMSG _IOWR('U', 0x22, struct usb_ctrlrequest )
-
+/* USB bInterfaceClass used by Hewlett-Packard ScanJet 3300c and Genius HR6
+   USB - Vivid III */
+#define SCN_CLASS_SCANJET 16
 
 #define SCN_MAX_MNR 16		/* We're allocated 16 minors */
 #define SCN_BASE_MNR 48		/* USB Scanners start at minor 48 */
diff -urN linux-2.4.21-pre3/drivers/usb/serial/ipaq.c linux-2.4.21-pre4/drivers/usb/serial/ipaq.c
--- linux-2.4.21-pre3/drivers/usb/serial/ipaq.c	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/drivers/usb/serial/ipaq.c	Tue Jan 28 19:44:31 2003
@@ -106,6 +106,7 @@
 	{ USB_DEVICE(CASIO_VENDOR_ID, CASIO_EM500_ID) },
 	{ USB_DEVICE(COMPAQ_VENDOR_ID, COMPAQ_IPAQ_ID) },
 	{ USB_DEVICE(COMPAQ_VENDOR_ID, COMPAQ_0032_ID) },
+	{ USB_DEVICE(DELL_VENDOR_ID, DELL_AXIM_ID) },
 	{ USB_DEVICE(HP_VENDOR_ID, HP_JORNADA_548_ID) },
 	{ USB_DEVICE(HP_VENDOR_ID, HP_JORNADA_568_ID) },
 	{ USB_DEVICE(HP_VENDOR_ID, HP_2016_ID) },
@@ -126,6 +127,7 @@
 	{ USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_WIRELESS_ID) },
 	{ USB_DEVICE(SOCKET_VENDOR_ID, SOCKET_PRODUCT_ID) },
 	{ USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_PRODUCT_ID) },
+	{ USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_E740_ID) },
 	{ USB_DEVICE(HTC_VENDOR_ID, HTC_PRODUCT_ID) },
 	{ USB_DEVICE(NEC_VENDOR_ID, NEC_PRODUCT_ID) },
 	{ }					/* Terminating entry */
diff -urN linux-2.4.21-pre3/drivers/usb/serial/ipaq.h linux-2.4.21-pre4/drivers/usb/serial/ipaq.h
--- linux-2.4.21-pre3/drivers/usb/serial/ipaq.h	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/drivers/usb/serial/ipaq.h	Tue Jan 28 19:44:31 2003
@@ -30,6 +30,9 @@
 #define COMPAQ_IPAQ_ID		0x0003
 #define COMPAQ_0032_ID		0x0032
 
+#define DELL_VENDOR_ID		0x413c
+#define DELL_AXIM_ID		0x4001
+
 #define HP_VENDOR_ID		0x03f0
 #define HP_JORNADA_548_ID	0x1016
 #define HP_JORNADA_568_ID	0x1116
@@ -63,6 +66,7 @@
 
 #define TOSHIBA_VENDOR_ID	0x0930
 #define TOSHIBA_PRODUCT_ID	0x0700
+#define TOSHIBA_E740_ID		0x0706
 
 #define HTC_VENDOR_ID		0x0bb4
 #define HTC_PRODUCT_ID		0x00ce
diff -urN linux-2.4.21-pre3/drivers/usb/serial/usbserial.c linux-2.4.21-pre4/drivers/usb/serial/usbserial.c
--- linux-2.4.21-pre3/drivers/usb/serial/usbserial.c	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/drivers/usb/serial/usbserial.c	Tue Jan 28 19:44:31 2003
@@ -1188,8 +1188,10 @@
 	     (dev->descriptor.idProduct == ATEN_PRODUCT_ID))) {
 		if (ifnum == 1) {
 			/* check out the endpoints of the other interface*/
-			interface = &dev->actconfig->interface[ifnum ^ 1];
-			iface_desc = &interface->altsetting[0];
+			struct usb_interface *other_iface;
+
+			other_iface = &dev->actconfig->interface[ifnum ^ 1];
+			iface_desc = &other_iface->altsetting[0];
 			for (i = 0; i < iface_desc->bNumEndpoints; ++i) {
 				endpoint = &iface_desc->endpoint[i];
 				if ((endpoint->bEndpointAddress & 0x80) &&
diff -urN linux-2.4.21-pre3/drivers/usb/storage/unusual_devs.h linux-2.4.21-pre4/drivers/usb/storage/unusual_devs.h
--- linux-2.4.21-pre3/drivers/usb/storage/unusual_devs.h	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/drivers/usb/storage/unusual_devs.h	Tue Jan 28 19:44:31 2003
@@ -97,6 +97,22 @@
 		"DVD-CAM DZ-MV100A Camcorder",
 		US_SC_SCSI, US_PR_CB, NULL, US_FL_SINGLE_LUN),
 
+/* Reported by Khalid Aziz <khalid@gonehiking.org>
+ * This entry is needed because the device reports Sub=ff */
+UNUSUAL_DEV(  0x04b8, 0x0602, 0x0110, 0x0110,
+		"Epson",
+		"785EPX Storage",
+		US_SC_SCSI, US_PR_BULK, NULL, US_FL_SINGLE_LUN),
+
+/* Reported by Jan Willamowius <jan@willamowius.de>
+ * The device needs the flags only.
+ */
+UNUSUAL_DEV(  0x04c8, 0x0723, 0x0000, 0x9999,
+		"Konica",
+		"KD-200Z",
+		US_SC_SCSI, US_PR_BULK, NULL,
+		US_FL_START_STOP),
+
 UNUSUAL_DEV(  0x04cb, 0x0100, 0x0000, 0x2210,
 		"Fujifilm",
 		"FinePix 1400Zoom",
@@ -518,6 +534,12 @@
  		US_SC_SCSI, US_PR_CB, NULL,
 		US_FL_MODE_XLATE ),
 
+UNUSUAL_DEV(  0x0a16, 0x8888, 0x0100, 0x0100,
+		"IBM",
+		"IBM USB Memory Key",
+		US_SC_SCSI, US_PR_BULK, NULL,
+		US_FL_FIX_INQUIRY ),
+		
 #ifdef CONFIG_USB_STORAGE_ISD200
 UNUSUAL_DEV(  0x0bf6, 0xa001, 0x0100, 0x0110,
                 "ATI",
diff -urN linux-2.4.21-pre3/drivers/usb/usb-skeleton.c linux-2.4.21-pre4/drivers/usb/usb-skeleton.c
--- linux-2.4.21-pre3/drivers/usb/usb-skeleton.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.21-pre4/drivers/usb/usb-skeleton.c	Tue Jan 28 19:44:31 2003
@@ -87,7 +87,7 @@
 
 
 /* Get a minor range for your devices from the usb maintainer */
-#define USB_SKEL_MINOR_BASE	200	
+#define USB_SKEL_MINOR_BASE	192	
 
 /* we can have up to this number of device plugged in at once */
 #define MAX_DEVICES		16
diff -urN linux-2.4.21-pre3/drivers/usb/usbnet.c linux-2.4.21-pre4/drivers/usb/usbnet.c
--- linux-2.4.21-pre3/drivers/usb/usbnet.c	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/drivers/usb/usbnet.c	Tue Jan 28 19:44:31 2003
@@ -1416,6 +1416,16 @@
 	.in = 1, .out = 2,
 	.epsize = 64,
 };
+static const struct driver_info	zaurus_slb500_info = {
+	/* Japanese B500 ~= US SL-5600 */
+	.description =	"Sharp Zaurus SL-B500",
+	.flags =	FLAG_FRAMING_Z,
+	.check_connect = always_connected,
+	.tx_fixup = 	zaurus_tx_fixup,
+
+	.in = 1, .out = 2,
+	.epsize = 64,
+};
 
 // SL-5600 and C-700 are PXA based; should resemble A300
 
@@ -2374,8 +2384,7 @@
 	.bInterfaceSubClass	= 0x00,
 	.bInterfaceProtocol	= 0x00,
 	.driver_info =  (unsigned long) &zaurus_sl5x00_info,
-},
-{
+}, {
 	.match_flags	=   USB_DEVICE_ID_MATCH_INT_INFO
 			  | USB_DEVICE_ID_MATCH_DEVICE, 
 	.idVendor		= 0x04DD,
@@ -2384,6 +2393,15 @@
 	.bInterfaceSubClass	= 0x0a,
 	.bInterfaceProtocol	= 0x00,
 	.driver_info =  (unsigned long) &zaurus_sla300_info,
+}, {
+	.match_flags	=   USB_DEVICE_ID_MATCH_INT_INFO
+			  | USB_DEVICE_ID_MATCH_DEVICE, 
+	.idVendor		= 0x04DD,
+	.idProduct		= 0x8006,
+	.bInterfaceClass	= 0x02,
+	.bInterfaceSubClass	= 0x0a,
+	.bInterfaceProtocol	= 0x00,
+	.driver_info =  (unsigned long) &zaurus_slb500_info,
 },
 #endif
 
diff -urN linux-2.4.21-pre3/drivers/video/matrox/matroxfb_DAC1064.c linux-2.4.21-pre4/drivers/video/matrox/matroxfb_DAC1064.c
--- linux-2.4.21-pre3/drivers/video/matrox/matroxfb_DAC1064.c	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/drivers/video/matrox/matroxfb_DAC1064.c	Tue Jan 28 19:44:31 2003
@@ -276,6 +276,7 @@
 	hw->MXoptionReg = mx;
 }
 
+#ifdef CONFIG_FB_MATROX_G450
 static void g450_set_plls(WPMINFO2) {
 	u_int32_t c2_ctl;
 	unsigned int pxc;
@@ -365,6 +366,7 @@
 		}
 	}
 }
+#endif
 
 void DAC1064_global_init(WPMINFO2) {
 	struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
@@ -372,6 +374,7 @@
 	hw->DACreg[POS1064_XMISCCTRL] &= M1064_XMISCCTRL_DAC_WIDTHMASK;
 	hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_LUT_EN;
 	hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL;
+#ifdef CONFIG_FB_MATROX_G450
 	if (ACCESS_FBINFO(devflags.g450dac)) {
 		hw->DACreg[POS1064_XPWRCTRL] = 0x1F;	/* powerup everything */
 		hw->DACreg[POS1064_XOUTPUTCONN] = 0x00;	/* disable outputs */
@@ -420,7 +423,9 @@
 		}
 		/* Now set timming related variables... */
 		g450_set_plls(PMINFO2);
-	} else {
+	} else
+#endif
+	{
 		if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC1) {
 			hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_EXT;
 			hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_MAFC12;
@@ -622,6 +627,7 @@
 	.compute = m1064_compute,
 };
 
+#ifdef CONFIG_FB_MATROX_G450
 static int g450_compute(void* out, struct my_timming* m) {
 #define minfo ((struct matrox_fb_info*)out)
 	if (m->mnp < 0) {
@@ -639,6 +645,7 @@
 	.name	 = "Primary output",
 	.compute = g450_compute,
 };
+#endif
 
 #endif /* NEED_DAC1064 */
 
@@ -821,6 +828,7 @@
 #endif
 
 #ifdef CONFIG_FB_MATROX_G100
+#ifdef CONFIG_FB_MATROX_G450
 static void g450_mclk_init(WPMINFO2) {
 	/* switch all clocks to PCI source */
 	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, ACCESS_FBINFO(hw).MXoptionReg | 4);
@@ -938,6 +946,10 @@
 	
 	return;
 }
+#else
+static inline void g450_preinit(WPMINFO2) {
+}
+#endif
 
 static int MGAG100_preinit(WPMINFO2) {
 	static const int vxres_g100[] = {  512,        640, 768,  800,  832,  960,
@@ -975,9 +987,12 @@
 	ACCESS_FBINFO(capable.plnwt) = ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG100
 			? ACCESS_FBINFO(devflags.sgram) : 1;
 
+#ifdef CONFIG_FB_MATROX_G450
 	if (ACCESS_FBINFO(devflags.g450dac)) {
 		ACCESS_FBINFO(outputs[0]).output = &g450out;
-	} else {
+	} else
+#endif
+	{
 		ACCESS_FBINFO(outputs[0]).output = &m1064;
 	}
 	ACCESS_FBINFO(outputs[0]).src = MATROXFB_SRC_CRTC1;
diff -urN linux-2.4.21-pre3/drivers/video/matrox/matroxfb_base.h linux-2.4.21-pre4/drivers/video/matrox/matroxfb_base.h
--- linux-2.4.21-pre3/drivers/video/matrox/matroxfb_base.h	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/drivers/video/matrox/matroxfb_base.h	Tue Jan 28 19:44:31 2003
@@ -108,7 +108,7 @@
 #endif
 #endif
 
-#if defined(__alpha__) || defined(__m68k__)
+#if defined(__alpha__) || defined(__mc68000__)
 #define READx_WORKS
 #define MEMCPYTOIO_WORKS
 #else
@@ -124,7 +124,7 @@
 #endif
 #endif
 
-#if defined(__m68k__)
+#if defined(__mc68000__)
 #define MAP_BUSTOVIRT
 #else
 #define MAP_IOREMAP
diff -urN linux-2.4.21-pre3/fs/dcache.c linux-2.4.21-pre4/fs/dcache.c
--- linux-2.4.21-pre3/fs/dcache.c	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/fs/dcache.c	Tue Jan 28 19:44:31 2003
@@ -977,21 +977,24 @@
 		namelen = dentry->d_name.len;
 		buflen -= namelen + 1;
 		if (buflen < 0)
-			break;
+			return ERR_PTR(-ENAMETOOLONG);
 		end -= namelen;
 		memcpy(end, dentry->d_name.name, namelen);
 		*--end = '/';
 		retval = end;
 		dentry = parent;
 	}
+
 	return retval;
+
 global_root:
 	namelen = dentry->d_name.len;
 	buflen -= namelen;
 	if (buflen >= 0) {
 		retval -= namelen-1;	/* hit the slash */
 		memcpy(retval, dentry->d_name.name, namelen);
-	}
+	} else
+		retval = ERR_PTR(-ENAMETOOLONG);
 	return retval;
 }
 
@@ -1040,6 +1043,10 @@
 		cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE);
 		spin_unlock(&dcache_lock);
 
+		error = PTR_ERR(cwd);
+		if (IS_ERR(cwd))
+			goto out;
+
 		error = -ERANGE;
 		len = PAGE_SIZE + page - cwd;
 		if (len <= size) {
@@ -1049,6 +1056,8 @@
 		}
 	} else
 		spin_unlock(&dcache_lock);
+
+out:
 	dput(pwd);
 	mntput(pwdmnt);
 	dput(root);
diff -urN linux-2.4.21-pre3/fs/ext3/inode.c linux-2.4.21-pre4/fs/ext3/inode.c
--- linux-2.4.21-pre3/fs/ext3/inode.c	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/fs/ext3/inode.c	Tue Jan 28 19:44:31 2003
@@ -2553,7 +2553,7 @@
 	handle_t *handle;
 
 	lock_kernel();
-	handle = ext3_journal_start(inode, 1);
+	handle = ext3_journal_start(inode, 2);
 	if (IS_ERR(handle))
 		goto out;
 	if (current_handle &&
diff -urN linux-2.4.21-pre3/fs/jbd/transaction.c linux-2.4.21-pre4/fs/jbd/transaction.c
--- linux-2.4.21-pre3/fs/jbd/transaction.c	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/fs/jbd/transaction.c	Tue Jan 28 19:44:31 2003
@@ -669,7 +669,8 @@
 			spin_unlock(&journal_datalist_lock);
 			unlock_journal(journal);
 			/* commit wakes up all shadow buffers after IO */
-			sleep_on(&jh2bh(jh)->b_wait);
+			wait_event(jh2bh(jh)->b_wait,
+						jh->b_jlist != BJ_Shadow);
 			lock_journal(journal);
 			goto repeat;
 		}
diff -urN linux-2.4.21-pre3/fs/jfs/inode.c linux-2.4.21-pre4/fs/jfs/inode.c
--- linux-2.4.21-pre3/fs/jfs/inode.c	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/fs/jfs/inode.c	Tue Jan 28 19:44:31 2003
@@ -21,6 +21,7 @@
 //#include <linux/locks.h>
 #include "jfs_incore.h"
 #include "jfs_filsys.h"
+#include "jfs_dmap.h"
 #include "jfs_imap.h"
 #include "jfs_extent.h"
 #include "jfs_unicode.h"
@@ -49,10 +50,8 @@
 	jFYI(1, ("jfs_clear_inode called ip = 0x%p\n", inode));
 
 	if (ji->active_ag != -1) {
-		printk(KERN_ERR "jfs_clear_inode, active_ag = %d\n",
-		       ji->active_ag);
-		printk(KERN_ERR "i_ino = %ld, i_mode = %o\n",
-		       inode->i_ino, inode->i_mode);
+		struct bmap *bmap = JFS_SBI(inode->i_sb)->bmap;
+		atomic_dec(&bmap->db_active[ji->active_ag]);
 	}
 
 	ASSERT(list_empty(&ji->anon_inode_list));
diff -urN linux-2.4.21-pre3/fs/jfs/jfs_incore.h linux-2.4.21-pre4/fs/jfs/jfs_incore.h
--- linux-2.4.21-pre3/fs/jfs/jfs_incore.h	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/fs/jfs/jfs_incore.h	Tue Jan 28 19:44:31 2003
@@ -111,7 +111,6 @@
 	COMMIT_Inlineea,	/* commit inode inline EA */
 	COMMIT_Freewmap,	/* free WMAP at iClose() */
 	COMMIT_Dirty,		/* Inode is really dirty */
-	COMMIT_Holdlock,	/* Hold the IWRITE_LOCK until commit is done */
 	COMMIT_Dirtable,	/* commit changes to di_dirtable */
 	COMMIT_Stale,		/* data extent is no longer valid */
 	COMMIT_Synclist,	/* metadata pages on group commit synclist */
diff -urN linux-2.4.21-pre3/fs/jfs/jfs_logmgr.c linux-2.4.21-pre4/fs/jfs/jfs_logmgr.c
--- linux-2.4.21-pre3/fs/jfs/jfs_logmgr.c	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/fs/jfs/jfs_logmgr.c	Tue Jan 28 19:44:31 2003
@@ -183,9 +183,8 @@
 static void lbmDirectWrite(struct jfs_log * log, struct lbuf * bp, int flag);
 static int lbmIOWait(struct lbuf * bp, int flag);
 static void lbmIODone(struct buffer_head *bh, int);
-
-void lbmStartIO(struct lbuf * bp);
-void lmGCwrite(struct jfs_log * log, int cant_block);
+static void lbmStartIO(struct lbuf * bp);
+static void lmGCwrite(struct jfs_log * log, int cant_block);
 
 
 /*
@@ -744,7 +743,7 @@
  *	LOGGC_LOCK must be held by caller.
  *	N.B. LOG_LOCK is NOT held during lmGroupCommit().
  */
-void lmGCwrite(struct jfs_log * log, int cant_write)
+static void lmGCwrite(struct jfs_log * log, int cant_write)
 {
 	struct lbuf *bp;
 	struct logpage *lp;
@@ -893,8 +892,7 @@
 	 */
 	if ((tblk = log->cqueue.head) &&
 	    ((log->gcrtc > 0) || (tblk->bp->l_wqnext != NULL) ||
-	     test_bit(log_SYNCBARRIER, &log->flag) ||
-	     test_bit(log_QUIESCE, &log->flag)))
+	     test_bit(log_FLUSH, &log->flag)))
 		/*
 		 * Call lmGCwrite with new group leader
 		 */
@@ -902,11 +900,13 @@
 
 	/* no transaction are ready yet (transactions are only just
 	 * queued (GC_QUEUE) and not entered for group commit yet).
-	 * let the first transaction entering group commit
-	 * will elect hetself as new group leader.
+	 * the first transaction entering group commit
+	 * will elect herself as new group leader.
 	 */
-	else
+	else {
 		log->cflag &= ~logGC_PAGEOUT;
+		clear_bit(log_FLUSH, &log->flag);
+	}
 
 	//LOGGC_UNLOCK(log);
 	spin_unlock_irqrestore(&log->gclock, flags);
@@ -1046,18 +1046,12 @@
 		set_bit(log_SYNCBARRIER, &log->flag);
 		jFYI(1, ("log barrier on: lsn=0x%x syncpt=0x%x\n", lsn,
 			 log->syncpt));
+		/*
+		 * We may have to initiate group commit
+		 */
+		jfs_flush_journal(log, 0);
 	}
 
-	/*
-	 * We may have to initiate group commit
-	 */
-	LOGGC_LOCK(log);
-	if (log->cqueue.head && !(log->cflag & logGC_PAGEOUT)) {
-		log->cflag |= logGC_PAGEOUT;
-		lmGCwrite(log, 0);
-	}
-	LOGGC_UNLOCK(log);
-
 	return lsn;
 }
 
@@ -1408,21 +1402,22 @@
 
 
 /*
- * NAME:	lmLogWait()
+ * NAME:	jfs_flush_journal()
  *
- * FUNCTION:	wait for all outstanding log records to be written to disk
+ * FUNCTION:	initiate write of any outstanding transactions to the journal
+ *		and optionally wait until they are all written to disk
  */
-void lmLogWait(struct jfs_log *log)
+void jfs_flush_journal(struct jfs_log *log, int wait)
 {
 	int i;
 
-	jFYI(1, ("lmLogWait: log:0x%p\n", log));
+	jFYI(1, ("jfs_flush_journal: log:0x%p wait=%d\n", log, wait));
 
 	/*
 	 * This ensures that we will keep writing to the journal as long
 	 * as there are unwritten commit records
 	 */
-	set_bit(log_QUIESCE, &log->flag);
+	set_bit(log_FLUSH, &log->flag);
 
 	/*
 	 * Initiate I/O on outstanding transactions
@@ -1434,6 +1429,9 @@
 	}
 	LOGGC_UNLOCK(log);
 
+	if (!wait)
+		return;
+
 	if (log->cqueue.head || !list_empty(&log->synclist)) {
 		/*
 		 * If there was very recent activity, we may need to wait
@@ -1451,7 +1449,7 @@
 	assert(log->cqueue.head == NULL);
 	assert(list_empty(&log->synclist));
 
-	clear_bit(log_QUIESCE, &log->flag);	/* Probably not needed */
+	clear_bit(log_FLUSH, &log->flag);
 }
 
 /*
@@ -1480,7 +1478,7 @@
 
 	jFYI(1, ("lmLogShutdown: log:0x%p\n", log));
 
-	lmLogWait(log);
+	jfs_flush_journal(log, 1);
 
 	/*
 	 * We need to make sure all of the "written" metapages
@@ -1939,7 +1937,7 @@
  *
  * serialization: LCACHE_LOCK() is NOT held during log i/o;
  */
-void lbmStartIO(struct lbuf * bp)
+static void lbmStartIO(struct lbuf * bp)
 {
 	jFYI(1, ("lbmStartIO\n"));
 
diff -urN linux-2.4.21-pre3/fs/jfs/jfs_logmgr.h linux-2.4.21-pre4/fs/jfs/jfs_logmgr.h
--- linux-2.4.21-pre3/fs/jfs/jfs_logmgr.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/fs/jfs/jfs_logmgr.h	Tue Jan 28 19:44:31 2003
@@ -424,6 +424,7 @@
 #define log_INLINELOG	1
 #define log_SYNCBARRIER	2
 #define log_QUIESCE	3
+#define log_FLUSH	4
 
 /*
  * group commit flag
@@ -502,11 +503,11 @@
 }
 
 extern int lmLogOpen(struct super_block *sb, struct jfs_log ** log);
-extern void lmLogWait(struct jfs_log * log);
 extern int lmLogClose(struct super_block *sb, struct jfs_log * log);
 extern int lmLogSync(struct jfs_log * log, int nosyncwait);
 extern int lmLogShutdown(struct jfs_log * log);
 extern int lmLogInit(struct jfs_log * log);
 extern int lmLogFormat(struct jfs_log *log, s64 logAddress, int logSize);
+extern void jfs_flush_journal(struct jfs_log * log, int wait);
 
 #endif				/* _H_JFS_LOGMGR */
diff -urN linux-2.4.21-pre3/fs/jfs/jfs_txnmgr.c linux-2.4.21-pre4/fs/jfs/jfs_txnmgr.c
--- linux-2.4.21-pre3/fs/jfs/jfs_txnmgr.c	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/fs/jfs/jfs_txnmgr.c	Tue Jan 28 19:44:31 2003
@@ -157,7 +157,6 @@
  * external references
  */
 extern int lmGroupCommit(struct jfs_log *, struct tblock *);
-extern int lmGCwrite(struct jfs_log *, int);
 extern void lmSync(struct jfs_log *);
 extern int jfs_commit_inode(struct inode *, int);
 extern int jfs_stop_threads;
@@ -1832,18 +1831,10 @@
 		} else {
 			/*
 			 * xdlist will point to into inode's xtree, ensure
-			 * that transaction is not committed lazily unless
-			 * we're deleting the inode (unlink).  In that case
-			 * we have special logic for the inode to be
-			 * unlocked by the lazy commit thread.
+			 * that transaction is not committed lazily.
 			 */
 			xadlock->xdlist = &p->xad[XTENTRYSTART];
-			if ((tblk->xflag & COMMIT_LAZY) &&
-			    (tblk->xflag & COMMIT_DELETE) &&
-			    (tblk->ip == ip))
-				set_cflag(COMMIT_Holdlock, ip);
-			else
-				tblk->xflag &= ~COMMIT_LAZY;
+			tblk->xflag &= ~COMMIT_LAZY;
 		}
 		jFYI(1,
 		     ("xtLog: free ip:0x%p mp:0x%p count:%d lwm:2\n",
@@ -2375,10 +2366,6 @@
 		ip = tblk->ip;
 		diUpdatePMap(ipimap, ip->i_ino, TRUE, tblk);
 		ipimap->i_state |= I_DIRTY;
-		if (test_and_clear_cflag(COMMIT_Holdlock, ip)) {
-			if (tblk->flag & tblkGC_LAZY)
-				IWRITE_UNLOCK(ip);
-		}
 		iput(ip);
 	}
 }
@@ -2964,12 +2951,7 @@
 	/*
 	 * We may need to kick off the group commit
 	 */
-	spin_lock_irq(&log->gclock);	// LOGGC_LOCK
-	if (log->cqueue.head && !(log->cflag & logGC_PAGEOUT)) {
-		log->cflag |= logGC_PAGEOUT;
-		lmGCwrite(log, 0);
-	}
-	spin_unlock_irq(&log->gclock);	// LOGGC_UNLOCK
+	jfs_flush_journal(log, 0);
 }
 
 /*
diff -urN linux-2.4.21-pre3/fs/jfs/jfs_umount.c linux-2.4.21-pre4/fs/jfs/jfs_umount.c
--- linux-2.4.21-pre3/fs/jfs/jfs_umount.c	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/fs/jfs/jfs_umount.c	Tue Jan 28 19:44:31 2003
@@ -68,7 +68,7 @@
 		/*
 		 * Wait for outstanding transactions to be written to log: 
 		 */
-		lmLogWait(log);
+		jfs_flush_journal(log, 1);
 
 	/*
 	 * close fileset inode allocation map (aka fileset inode)
@@ -150,7 +150,7 @@
 	 *
 	 * remove file system from log active file system list.
 	 */
-	lmLogWait(log);
+	jfs_flush_journal(log, 1);
 
 	/*
 	 * Make sure all metadata makes it to disk
diff -urN linux-2.4.21-pre3/fs/jfs/namei.c linux-2.4.21-pre4/fs/jfs/namei.c
--- linux-2.4.21-pre3/fs/jfs/namei.c	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/fs/jfs/namei.c	Tue Jan 28 19:44:31 2003
@@ -531,8 +531,7 @@
 	if (ip->i_nlink == 0)
 		set_cflag(COMMIT_Nolink, ip);
 
-	if (!test_cflag(COMMIT_Holdlock, ip))
-		IWRITE_UNLOCK(ip);
+	IWRITE_UNLOCK(ip);
 
 	/*
 	 * Truncating the directory index table is not guaranteed.  It
@@ -1242,14 +1241,6 @@
 
 	rc = txCommit(tid, ipcount, iplist, commit_flag);
 
-	/*
-	 * Don't unlock new_ip if COMMIT_HOLDLOCK is set
-	 */
-	if (new_ip && test_cflag(COMMIT_Holdlock, new_ip)) {
-		up(&JFS_IP(new_ip)->commit_sem);
-		new_ip = 0;
-	}
-
       out4:
 	txEnd(tid);
 
diff -urN linux-2.4.21-pre3/fs/jfs/resize.c linux-2.4.21-pre4/fs/jfs/resize.c
--- linux-2.4.21-pre3/fs/jfs/resize.c	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/fs/jfs/resize.c	Tue Jan 28 19:44:31 2003
@@ -29,6 +29,8 @@
 #include "jfs_txnmgr.h"
 #include "jfs_debug.h"
 
+extern s64 jfs_get_volume_size(struct super_block *);
+
 #define BITSPERPAGE     (PSIZE << 3)
 #define L2MEGABYTE      20
 #define MEGABYTE        (1 << L2MEGABYTE)
@@ -97,7 +99,7 @@
 		goto out;
 	}
 
-	VolumeSize = sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits;
+	VolumeSize = jfs_get_volume_size(sb);
 	if (VolumeSize) {
 		if (newLVSize > VolumeSize) {
 			printk(KERN_WARNING "jfs_extendfs: invalid size\n");
@@ -512,7 +514,7 @@
 		mark_buffer_dirty(bh);
 		ll_rw_block(WRITE, 1, &bh2);
 		wait_on_buffer(bh2);
-		brelse(bh);
+		brelse(bh2);
 	}
 
 	/* write primary superblock */
diff -urN linux-2.4.21-pre3/fs/jfs/super.c linux-2.4.21-pre4/fs/jfs/super.c
--- linux-2.4.21-pre3/fs/jfs/super.c	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/fs/jfs/super.c	Tue Jan 28 19:44:31 2003
@@ -20,6 +20,7 @@
 #include <linux/config.h>
 #include <linux/fs.h>
 #include <linux/module.h>
+#include <linux/blkdev.h>
 #include <linux/completion.h>
 #include <asm/uaccess.h>
 #include "jfs_incore.h"
@@ -124,6 +125,24 @@
 	kfree(sbi);
 }
 
+s64 jfs_get_volume_size(struct super_block *sb)
+{
+	uint blocks = 0;
+	s64 bytes;
+	kdev_t dev = sb->s_dev;
+	int major = MAJOR(dev);
+	int minor = MINOR(dev);
+
+	if (blk_size[major]) {
+		blocks = blk_size[major][minor];
+		if (blocks) {
+			bytes = ((s64)blocks) << BLOCK_SIZE_BITS;
+			return bytes >> sb->s_blocksize_bits;
+		}
+	}
+	return 0;
+}
+
 static int parse_options(char *options, struct super_block *sb, s64 *newLVSize)
 {
 	void *nls_map = NULL;
@@ -152,8 +171,7 @@
 			}
 		} else if (!strcmp(this_char, "resize")) {
 			if (!value || !*value) {
-				*newLVSize = sb->s_bdev->bd_inode->i_size >>
-					sb->s_blocksize_bits;
+				*newLVSize = jfs_get_volume_size(sb);
 				if (*newLVSize == 0)
 					printk(KERN_ERR
 					 "JFS: Cannot determine volume size\n");
@@ -342,6 +360,17 @@
 }
 
 
+static int jfs_sync_fs(struct super_block *sb)
+{
+	struct jfs_log *log = JFS_SBI(sb)->log;
+
+	/* log == NULL indicates read-only mount */
+	if (log)
+		jfs_flush_journal(log, 1);
+
+	return 0;
+}
+
 static struct super_operations jfs_super_operations = {
 	.read_inode	= jfs_read_inode,
 	.dirty_inode	= jfs_dirty_inode,
@@ -349,6 +378,7 @@
 	.clear_inode	= jfs_clear_inode,
 	.delete_inode	= jfs_delete_inode,
 	.put_super	= jfs_put_super,
+	.sync_fs	= jfs_sync_fs,
 	.write_super_lockfs = jfs_write_super_lockfs,
 	.unlockfs       = jfs_unlockfs,
 	.statfs		= jfs_statfs,
diff -urN linux-2.4.21-pre3/fs/namespace.c linux-2.4.21-pre4/fs/namespace.c
--- linux-2.4.21-pre3/fs/namespace.c	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/fs/namespace.c	Tue Jan 28 19:44:31 2003
@@ -24,13 +24,12 @@
 struct vfsmount *do_kern_mount(const char *type, int flags, char *name, void *data);
 int do_remount_sb(struct super_block *sb, int flags, void * data);
 void kill_super(struct super_block *sb);
+extern int __init init_rootfs(void);
 
 static struct list_head *mount_hashtable;
 static int hash_mask, hash_bits;
 static kmem_cache_t *mnt_cache; 
 
-extern void init_rootfs(void);
-
 static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry)
 {
 	unsigned long tmp = ((unsigned long) mnt / L1_CACHE_BYTES);
@@ -1023,15 +1022,10 @@
 	if (!mnt_cache)
 		panic("Cannot create vfsmount cache");
 
-	mempages >>= (16 - PAGE_SHIFT);
-	mempages *= sizeof(struct list_head);
-	for (order = 0; ((1UL << order) << PAGE_SHIFT) < mempages; order++)
-		;
-
-	do {
-		mount_hashtable = (struct list_head *)
-			__get_free_pages(GFP_ATOMIC, order);
-	} while (mount_hashtable == NULL && --order >= 0);
+	/* using single pointer list heads would save half of the hash table. */
+	order = 0; 
+	mount_hashtable = (struct list_head *)
+		__get_free_pages(GFP_ATOMIC, order);
 
 	if (!mount_hashtable)
 		panic("Failed to allocate mount hash table\n");
@@ -1055,8 +1049,9 @@
 	nr_hash = 1UL << hash_bits;
 	hash_mask = nr_hash-1;
 
-	printk("Mount-cache hash table entries: %d (order: %ld, %ld bytes)\n",
-			nr_hash, order, (PAGE_SIZE << order));
+	printk(KERN_INFO "Mount cache hash table entries: %d"
+		" (order: %ld, %ld bytes)\n",
+		nr_hash, order, (PAGE_SIZE << order));
 
 	/* And initialize the newly allocated array */
 	d = mount_hashtable;
diff -urN linux-2.4.21-pre3/fs/nfs/pagelist.c linux-2.4.21-pre4/fs/nfs/pagelist.c
--- linux-2.4.21-pre3/fs/nfs/pagelist.c	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/fs/nfs/pagelist.c	Tue Jan 28 19:44:31 2003
@@ -134,9 +134,12 @@
 		req->wb_cred = NULL;
 	}
 	if (req->wb_page) {
+		atomic_dec(&NFS_REQUESTLIST(req->wb_inode)->nr_requests);
+#ifdef NFS_PARANOIA
+		BUG_ON(atomic_read(&NFS_REQUESTLIST(req->wb_inode)->nr_requests) < 0);
+#endif
 		page_cache_release(req->wb_page);
 		req->wb_page = NULL;
-		atomic_dec(&NFS_REQUESTLIST(req->wb_inode)->nr_requests);
 	}
 }
 
@@ -159,14 +162,9 @@
 	spin_unlock(&nfs_wreq_lock);
 
 #ifdef NFS_PARANOIA
-	if (!list_empty(&req->wb_list))
-		BUG();
-	if (!list_empty(&req->wb_hash))
-		BUG();
-	if (NFS_WBACK_BUSY(req))
-		BUG();
-	if (atomic_read(&NFS_REQUESTLIST(req->wb_inode)->nr_requests) < 0)
-		BUG();
+	BUG_ON(!list_empty(&req->wb_list));
+	BUG_ON(!list_empty(&req->wb_hash));
+	BUG_ON(NFS_WBACK_BUSY(req));
 #endif
 
 	/* Release struct file or cached credential */
diff -urN linux-2.4.21-pre3/fs/proc/proc_misc.c linux-2.4.21-pre4/fs/proc/proc_misc.c
--- linux-2.4.21-pre3/fs/proc/proc_misc.c	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/fs/proc/proc_misc.c	Tue Jan 28 19:44:31 2003
@@ -344,7 +344,7 @@
 			kstat.pswpout,
 			sum
 	);
-#if !defined(CONFIG_ARCH_S390)
+#if !defined(CONFIG_ARCH_S390) && !defined(CONFIG_ALPHA)
 	for (i = 0 ; i < NR_IRQS ; i++)
 		proc_sprintf(page, &off, &len,
 			     " %u", kstat_irqs(i));
diff -urN linux-2.4.21-pre3/fs/reiserfs/inode.c linux-2.4.21-pre4/fs/reiserfs/inode.c
--- linux-2.4.21-pre3/fs/reiserfs/inode.c	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/fs/reiserfs/inode.c	Tue Jan 28 19:44:31 2003
@@ -1463,13 +1463,22 @@
 /* inserts the stat data into the tree, and then calls
    reiserfs_new_directory (to insert ".", ".." item if new object is
    directory) or reiserfs_new_symlink (to insert symlink body if new
-   object is symlink) or nothing (if new object is regular file) */
-struct inode * reiserfs_new_inode (struct reiserfs_transaction_handle *th,
-				   struct inode * dir, int mode, 
-				   const char * symname, 
-				   int i_size, /* 0 for regular, EMTRY_DIR_SIZE for dirs,
-						  strlen (symname) for symlinks)*/
-				   struct dentry *dentry, struct inode *inode, int * err)
+   object is symlink) or nothing (if new object is regular file)
+
+   NOTE! uid and gid must already be set in the inode.  If we return
+   non-zero due to an error, we have to drop the quota previously allocated
+   for the fresh inode.  This can only be done outside a transaction, so
+   if we return non-zero, we also end the transaction.
+
+   */
+int reiserfs_new_inode (struct reiserfs_transaction_handle *th,
+				struct inode * dir, int mode,
+				const char * symname,
+				/* 0 for regular, EMTRY_DIR_SIZE for dirs,
+				   strlen (symname) for symlinks) */
+				int i_size,
+				struct dentry *dentry,
+				struct inode *inode)
 {
     struct super_block * sb;
     INITIALIZE_PATH (path_to_key);
@@ -1477,11 +1486,11 @@
     struct item_head ih;
     struct stat_data sd;
     int retval;
+    int err ;
   
     if (!dir || !dir->i_nlink) {
-	*err = -EPERM;
-	iput(inode) ;
-	return NULL;
+	err = -EPERM ;
+	goto out_bad_inode ;
     }
 
     sb = dir->i_sb;
@@ -1489,13 +1498,16 @@
 	    dir -> u.reiserfs_i.i_attrs & REISERFS_INHERIT_MASK;
     sd_attrs_to_i_attrs( inode -> u.reiserfs_i.i_attrs, inode );
 
+    /* symlink cannot be immutable or append only, right? */
+    if( S_ISLNK( inode -> i_mode ) )
+	    inode -> i_flags &= ~ ( S_IMMUTABLE | S_APPEND );
+
     /* item head of new item */
     ih.ih_key.k_dir_id = INODE_PKEY (dir)->k_objectid;
     ih.ih_key.k_objectid = cpu_to_le32 (reiserfs_get_unused_objectid (th));
     if (!ih.ih_key.k_objectid) {
-	iput(inode) ;
-	*err = -ENOMEM;
-	return NULL;
+	err = -ENOMEM ;
+	goto out_bad_inode ;
     }
     if (old_format_only (sb))
       /* not a perfect generation count, as object ids can be reused, but this
@@ -1511,12 +1523,24 @@
 #else
       inode->i_generation = ++event;
 #endif
+    /* fill stat data */
+    inode->i_nlink = (S_ISDIR (mode) ? 2 : 1);
+
+    /* uid and gid must already be set by the caller for quota init */
+
+    inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+    inode->i_size = i_size;
+    inode->i_blocks = (inode->i_size + 511) >> 9;
+    inode->u.reiserfs_i.i_first_direct_byte = S_ISLNK(mode) ? 1 : 
+      U32_MAX/*NO_BYTES_IN_DIRECT_ITEM*/;
+
+    INIT_LIST_HEAD(&inode->u.reiserfs_i.i_prealloc_list) ;
+
     if (old_format_only (sb))
 	make_le_item_head (&ih, 0, KEY_FORMAT_3_5, SD_OFFSET, TYPE_STAT_DATA, SD_V1_SIZE, MAX_US_INT);
     else
 	make_le_item_head (&ih, 0, KEY_FORMAT_3_6, SD_OFFSET, TYPE_STAT_DATA, SD_SIZE, MAX_US_INT);
 
-
     /* key to search for correct place for new stat data */
     _make_cpu_key (&key, KEY_FORMAT_3_6, le32_to_cpu (ih.ih_key.k_dir_id),
 		   le32_to_cpu (ih.ih_key.k_objectid), SD_OFFSET, TYPE_STAT_DATA, 3/*key length*/);
@@ -1524,47 +1548,21 @@
     /* find proper place for inserting of stat data */
     retval = search_item (sb, &key, &path_to_key);
     if (retval == IO_ERROR) {
-	iput (inode);
-	*err = -EIO;
-	return NULL;
+	err = -EIO;
+	goto out_bad_inode;
     }
     if (retval == ITEM_FOUND) {
 	pathrelse (&path_to_key);
-	iput (inode);
-	*err = -EEXIST;
-	return NULL;
+	err = -EEXIST;
+	goto out_bad_inode;
     }
 
-    /* fill stat data */
-    inode->i_mode = mode;
-    inode->i_nlink = (S_ISDIR (mode) ? 2 : 1);
-    inode->i_uid = current->fsuid;
-    if (dir->i_mode & S_ISGID) {
-	inode->i_gid = dir->i_gid;
-	if (S_ISDIR(mode))
-	    inode->i_mode |= S_ISGID;
-    } else
-	inode->i_gid = current->fsgid;
-
-    /* symlink cannot be immutable or append only, right? */
-    if( S_ISLNK( inode -> i_mode ) )
-	    inode -> i_flags &= ~ ( S_IMMUTABLE | S_APPEND );
-
-    inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
-    inode->i_size = i_size;
-    inode->i_blocks = (inode->i_size + 511) >> 9;
-    inode->u.reiserfs_i.i_first_direct_byte = S_ISLNK(mode) ? 1 : 
-      U32_MAX/*NO_BYTES_IN_DIRECT_ITEM*/;
-
-    INIT_LIST_HEAD(&inode->u.reiserfs_i.i_prealloc_list) ;
-
     if (old_format_only (sb)) {
 	if (inode->i_uid & ~0xffff || inode->i_gid & ~0xffff) {
 	    pathrelse (&path_to_key);
 	    /* i_uid or i_gid is too big to be stored in stat data v3.5 */
-	    iput (inode);
-	    *err = -EINVAL;
-	    return NULL;
+	    err = -EINVAL;
+	    goto out_bad_inode;
 	}
 	inode2sd_v1 (&sd, inode);
     } else
@@ -1595,10 +1593,9 @@
 #endif
     retval = reiserfs_insert_item (th, &path_to_key, &key, &ih, (char *)(&sd));
     if (retval) {
-	iput (inode);
-	*err = retval;
 	reiserfs_check_path(&path_to_key) ;
-	return NULL;
+	err = retval;
+	goto out_bad_inode;
     }
 
 #ifdef DISPLACE_NEW_PACKING_LOCALITIES
@@ -1617,19 +1614,30 @@
 	retval = reiserfs_new_symlink (th, &ih, &path_to_key, symname, i_size);
     }
     if (retval) {
-      inode->i_nlink = 0;
-	iput (inode);
-	*err = retval;
+	err = retval;
 	reiserfs_check_path(&path_to_key) ;
-	return NULL;
+	journal_end(th, th->t_super, th->t_blocks_allocated) ;
+	goto out_inserted_sd;
     }
 
     insert_inode_hash (inode);
-    // we do not mark inode dirty: on disk content matches to the
-    // in-core one
+    reiserfs_update_sd(th, inode) ;
     reiserfs_check_path(&path_to_key) ;
 
-    return inode;
+    return 0;
+out_bad_inode:
+    /* Invalidate the object, nothing was inserted yet */
+    INODE_PKEY(inode)->k_objectid = 0;
+
+    /* dquot_drop must be done outside a transaction */
+    journal_end(th, th->t_super, th->t_blocks_allocated) ;
+    make_bad_inode(inode);
+
+out_inserted_sd:
+    inode->i_nlink = 0;
+    th->t_trans_id = 0 ; /* so the caller can't use this handle later */
+    iput(inode) ;
+    return err;
 }
 
 /*
diff -urN linux-2.4.21-pre3/fs/reiserfs/namei.c linux-2.4.21-pre4/fs/reiserfs/namei.c
--- linux-2.4.21-pre3/fs/reiserfs/namei.c	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/fs/reiserfs/namei.c	Tue Jan 28 19:44:31 2003
@@ -488,27 +488,58 @@
     return 0;
 }
 
+/* quota utility function, call if you've had to abort after calling
+** new_inode_init, and have not called reiserfs_new_inode yet.
+** This should only be called on inodes that do not hav stat data
+** inserted into the tree yet.
+*/
+static int drop_new_inode(struct inode *inode) {
+    make_bad_inode(inode) ;
+    iput(inode) ;
+    return 0 ;
+}
+
+/* utility function that does setup for reiserfs_new_inode.  
+** DQUOT_ALLOC_INODE cannot be called inside a transaction, so we had
+** to pull some bits of reiserfs_new_inode out into this func.
+*/
+static int new_inode_init(struct inode *inode, struct inode *dir, int mode) {
+
+    /* the quota init calls have to know who to charge the quota to, so
+    ** we have to set uid and gid here
+    */
+    inode->i_uid = current->fsuid;
+    inode->i_mode = mode;
+
+    if (dir->i_mode & S_ISGID) {
+        inode->i_gid = dir->i_gid;
+        if (S_ISDIR(mode))
+            inode->i_mode |= S_ISGID;
+    } else
+        inode->i_gid = current->fsgid;
 
+    return 0 ;
+}
+  
 static int reiserfs_create (struct inode * dir, struct dentry *dentry, int mode)
 {
     int retval;
     struct inode * inode;
-    int windex ;
     int jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 ;
     struct reiserfs_transaction_handle th ;
 
-
     if (!(inode = new_inode(dir->i_sb))) {
 	return -ENOMEM ;
     }
+    retval = new_inode_init(inode, dir, mode) ;
+    if (retval)
+	return retval ;
+
     journal_begin(&th, dir->i_sb, jbegin_count) ;
     th.t_caller = "create" ;
-    windex = push_journal_writer("reiserfs_create") ;
-    inode = reiserfs_new_inode (&th, dir, mode, 0, 0/*i_size*/, dentry, inode, &retval);
-    if (!inode) {
-	pop_journal_writer(windex) ;
-	journal_end(&th, dir->i_sb, jbegin_count) ;
-	return retval;
+    retval = reiserfs_new_inode (&th, dir, mode, 0, 0/*i_size*/, dentry, inode);
+    if (retval) {
+	goto out_failed ;
     }
 	
     inode->i_op = &reiserfs_file_inode_operations;
@@ -520,20 +551,19 @@
     if (retval) {
 	inode->i_nlink--;
 	reiserfs_update_sd (&th, inode);
-	pop_journal_writer(windex) ;
-	// FIXME: should we put iput here and have stat data deleted
-	// in the same transactioin
 	journal_end(&th, dir->i_sb, jbegin_count) ;
-	iput (inode);
-	return retval;
+	iput(inode) ;
+	goto out_failed ;
     }
     reiserfs_update_inode_transaction(inode) ;
     reiserfs_update_inode_transaction(dir) ;
 
     d_instantiate(dentry, inode);
-    pop_journal_writer(windex) ;
     journal_end(&th, dir->i_sb, jbegin_count) ;
     return 0;
+
+out_failed:
+    return retval ;
 }
 
 
@@ -541,21 +571,21 @@
 {
     int retval;
     struct inode * inode;
-    int windex ;
     struct reiserfs_transaction_handle th ;
     int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3; 
 
     if (!(inode = new_inode(dir->i_sb))) {
 	return -ENOMEM ;
     }
+    retval = new_inode_init(inode, dir, mode) ;
+    if (retval)
+        return retval ;
+
     journal_begin(&th, dir->i_sb, jbegin_count) ;
-    windex = push_journal_writer("reiserfs_mknod") ;
 
-    inode = reiserfs_new_inode (&th, dir, mode, 0, 0/*i_size*/, dentry, inode, &retval);
-    if (!inode) {
-	pop_journal_writer(windex) ;
-	journal_end(&th, dir->i_sb, jbegin_count) ;
-	return retval;
+    retval = reiserfs_new_inode(&th, dir, mode, 0, 0/*i_size*/, dentry, inode);
+    if (retval) {
+	goto out_failed; 
     }
 
     init_special_inode(inode, mode, rdev) ;
@@ -571,16 +601,17 @@
     if (retval) {
 	inode->i_nlink--;
 	reiserfs_update_sd (&th, inode);
-	pop_journal_writer(windex) ;
 	journal_end(&th, dir->i_sb, jbegin_count) ;
-	iput (inode);
-	return retval;
+	iput(inode) ;
+        goto out_failed; 
     }
 
     d_instantiate(dentry, inode);
-    pop_journal_writer(windex) ;
     journal_end(&th, dir->i_sb, jbegin_count) ;
     return 0;
+
+out_failed:
+    return retval ;
 }
 
 
@@ -588,15 +619,18 @@
 {
     int retval;
     struct inode * inode;
-    int windex ;
     struct reiserfs_transaction_handle th ;
     int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3; 
 
+    mode = S_IFDIR | mode;
     if (!(inode = new_inode(dir->i_sb))) {
 	return -ENOMEM ;
     }
+    retval = new_inode_init(inode, dir, mode) ;
+    if (retval)
+	return retval ;
+
     journal_begin(&th, dir->i_sb, jbegin_count) ;
-    windex = push_journal_writer("reiserfs_mkdir") ;
 
     /* inc the link count now, so another writer doesn't overflow it while
     ** we sleep later on.
@@ -607,15 +641,13 @@
     /* set flag that new packing locality created and new blocks for the content     * of that directory are not displaced yet */
     dir->u.reiserfs_i.new_packing_locality = 1;
 #endif
-    mode = S_IFDIR | mode;
-    inode = reiserfs_new_inode (&th, dir, mode, 0/*symlink*/,
-				old_format_only (dir->i_sb) ? EMPTY_DIR_SIZE_V1 : EMPTY_DIR_SIZE,
-				dentry, inode, &retval);
-    if (!inode) {
-	pop_journal_writer(windex) ;
+    retval = reiserfs_new_inode(&th, dir, mode, 0/*symlink*/,
+				old_format_only (dir->i_sb) ?
+				EMPTY_DIR_SIZE_V1 : EMPTY_DIR_SIZE,
+				dentry, inode) ;
+    if (retval) {
 	dir->i_nlink-- ;
-	journal_end(&th, dir->i_sb, jbegin_count) ;
-	return retval;
+	goto out_failed ;
     }
     reiserfs_update_inode_transaction(inode) ;
     reiserfs_update_inode_transaction(dir) ;
@@ -630,19 +662,20 @@
 	inode->i_nlink = 0;
 	DEC_DIR_INODE_NLINK(dir);
 	reiserfs_update_sd (&th, inode);
-	pop_journal_writer(windex) ;
 	journal_end(&th, dir->i_sb, jbegin_count) ;
-	iput (inode);
-	return retval;
+	iput(inode) ;
+	goto out_failed ;
     }
 
     // the above add_entry did not update dir's stat data
     reiserfs_update_sd (&th, dir);
 
     d_instantiate(dentry, inode);
-    pop_journal_writer(windex) ;
     journal_end(&th, dir->i_sb, jbegin_count) ;
     return 0;
+
+out_failed:
+    return retval ;
 }
 
 static inline int reiserfs_empty_dir(struct inode *inode) {
@@ -820,7 +853,7 @@
     struct inode * inode;
     char * name;
     int item_len;
-    int windex ;
+    int mode = S_IFLNK | S_IRWXUGO ;
     struct reiserfs_transaction_handle th ;
     int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3; 
 
@@ -828,31 +861,34 @@
     if (!(inode = new_inode(parent_dir->i_sb))) {
   	return -ENOMEM ;
     }
+    retval = new_inode_init(inode, parent_dir, mode) ;
+    if (retval) {
+	return retval ;
+    }
 
     item_len = ROUND_UP (strlen (symname));
     if (item_len > MAX_DIRECT_ITEM_LEN (parent_dir->i_sb->s_blocksize)) {
-	iput(inode) ;
-	return -ENAMETOOLONG;
+	retval = -ENAMETOOLONG;
+	drop_new_inode(inode) ;
+	goto out_failed ;
     }
   
     name = reiserfs_kmalloc (item_len, GFP_NOFS, parent_dir->i_sb);
     if (!name) {
-	iput(inode) ;
-	return -ENOMEM;
+	retval = -ENOMEM;
+	drop_new_inode(inode) ;
+	goto out_failed ;
     }
     memcpy (name, symname, strlen (symname));
     padd_item (name, item_len, strlen (symname));
 
     journal_begin(&th, parent_dir->i_sb, jbegin_count) ;
-    windex = push_journal_writer("reiserfs_symlink") ;
 
-    inode = reiserfs_new_inode (&th, parent_dir, S_IFLNK | S_IRWXUGO, name, strlen (symname), dentry,
-				inode, &retval);
+    retval = reiserfs_new_inode(&th, parent_dir, mode, name,
+				strlen(symname), dentry, inode) ;
     reiserfs_kfree (name, item_len, parent_dir->i_sb);
-    if (inode == 0) { /* reiserfs_new_inode iputs for us */
-	pop_journal_writer(windex) ;
-	journal_end(&th, parent_dir->i_sb, jbegin_count) ;
-	return retval;
+    if (retval) {
+	goto out_failed ;
     }
 
     reiserfs_update_inode_transaction(inode) ;
@@ -870,16 +906,17 @@
     if (retval) {
 	inode->i_nlink--;
 	reiserfs_update_sd (&th, inode);
-	pop_journal_writer(windex) ;
 	journal_end(&th, parent_dir->i_sb, jbegin_count) ;
-	iput (inode);
-	return retval;
+	iput(inode) ;
+	goto out_failed ;
     }
 
     d_instantiate(dentry, inode);
-    pop_journal_writer(windex) ;
     journal_end(&th, parent_dir->i_sb, jbegin_count) ;
     return 0;
+
+out_failed:
+    return retval ;
 }
 
 
diff -urN linux-2.4.21-pre3/fs/super.c linux-2.4.21-pre4/fs/super.c
--- linux-2.4.21-pre3/fs/super.c	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/fs/super.c	Tue Jan 28 19:44:31 2003
@@ -471,7 +471,7 @@
 			spin_unlock(&sb_lock);
 			down_read(&sb->s_umount);
 			write_super(sb);
-			if (wait && sb->s_op && sb->s_op->sync_fs)
+			if (wait && sb->s_root && sb->s_op && sb->s_op->sync_fs)
 				sb->s_op->sync_fs(sb);
 			drop_super(sb);
 			goto restart;
diff -urN linux-2.4.21-pre3/include/asm-alpha/agp_backend.h linux-2.4.21-pre4/include/asm-alpha/agp_backend.h
--- linux-2.4.21-pre3/include/asm-alpha/agp_backend.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/include/asm-alpha/agp_backend.h	Tue Jan 28 19:44:31 2003
@@ -0,0 +1,43 @@
+#ifndef _ALPHA_AGP_BACKEND_H
+#define _ALPHA_AGP_BACKEND_H 1
+
+typedef	union _alpha_agp_mode {
+	struct {
+		u32 rate : 3;
+		u32 reserved0 : 1;
+		u32 fw : 1;
+		u32 fourgb : 1;
+		u32 reserved1 : 2;
+		u32 enable : 1;
+		u32 sba : 1;
+		u32 reserved2 : 14;
+		u32 rq : 8;
+	} bits;
+	u32 lw;
+} alpha_agp_mode;
+
+typedef struct _alpha_agp_info {
+	enum chipset_type type;
+	struct pci_controller *hose;
+	struct {
+		dma_addr_t bus_base;
+		unsigned long size;
+		void *sysdata;
+	} aperture;
+	alpha_agp_mode capability;
+	alpha_agp_mode mode;
+	void *private;
+	struct alpha_agp_ops *ops;
+} alpha_agp_info;
+
+struct alpha_agp_ops {
+	int (*setup)(alpha_agp_info *);
+	void (*cleanup)(alpha_agp_info *);
+	int (*configure)(alpha_agp_info *);
+	int (*bind)(alpha_agp_info *, off_t, agp_memory *);
+	int (*unbind)(alpha_agp_info *, off_t, agp_memory *);
+	unsigned long (*translate)(alpha_agp_info *, dma_addr_t);
+};
+
+
+#endif /* _ALPHA_AGP_BACKEND_H */
diff -urN linux-2.4.21-pre3/include/asm-alpha/console.h linux-2.4.21-pre4/include/asm-alpha/console.h
--- linux-2.4.21-pre3/include/asm-alpha/console.h	Sun Aug 12 10:51:41 2001
+++ linux-2.4.21-pre4/include/asm-alpha/console.h	Tue Jan 28 19:44:31 2003
@@ -10,6 +10,8 @@
 #define CCB_SET_TERM_INT	0x04
 #define CCB_SET_TERM_CTL	0x05
 #define CCB_PROCESS_KEYCODE	0x06
+#define CCB_OPEN_CONSOLE	0x07
+#define CCB_CLOSE_CONSOLE	0x08
 
 #define CCB_OPEN		0x10
 #define CCB_CLOSE		0x11
@@ -47,6 +49,9 @@
 #ifdef __KERNEL__
 #ifndef __ASSEMBLY__
 extern long callback_puts(long unit, const char *s, long length);
+extern long callback_getc(long unit);
+extern long callback_open_console(void);
+extern long callback_close_console(void);
 extern long callback_open(const char *device, long length);
 extern long callback_close(long unit);
 extern long callback_read(long channel, long count, const char *buf, long lbn);
diff -urN linux-2.4.21-pre3/include/asm-alpha/core_marvel.h linux-2.4.21-pre4/include/asm-alpha/core_marvel.h
--- linux-2.4.21-pre3/include/asm-alpha/core_marvel.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/include/asm-alpha/core_marvel.h	Tue Jan 28 19:44:31 2003
@@ -0,0 +1,579 @@
+/*
+ * Marvel systems use the IO7 I/O chip provides PCI/PCIX/AGP access
+ *
+ * This file is based on:
+ *
+ * Marvel / EV7 System Programmer's Manual
+ * Revision 1.00
+ * 14 May 2001
+ */
+
+#ifndef __ALPHA_MARVEL__H__
+#define __ALPHA_MARVEL__H__
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+
+#include <asm/compiler.h>
+
+#define MARVEL_MAX_PIDS		 32 /* as long as we rely on 43-bit superpage */
+#define MARVEL_IRQ_VEC_PE_SHIFT	(10)
+#define MARVEL_IRQ_VEC_IRQ_MASK	((1 << MARVEL_IRQ_VEC_PE_SHIFT) - 1)
+#define MARVEL_NR_IRQS		\
+	(16 + (MARVEL_MAX_PIDS * (1 << MARVEL_IRQ_VEC_PE_SHIFT)))
+
+/*
+ * EV7 RBOX Registers
+ */
+typedef struct {
+	volatile unsigned long csr __attribute__((aligned(16)));
+} ev7_csr;
+
+typedef struct {
+	ev7_csr	RBOX_CFG;		/* 0x0000 */
+	ev7_csr	RBOX_NSVC;
+	ev7_csr	RBOX_EWVC;
+	ev7_csr	RBOX_WHAMI;
+	ev7_csr	RBOX_TCTL;		/* 0x0040 */
+	ev7_csr	RBOX_INT;
+	ev7_csr	RBOX_IMASK;
+	ev7_csr	RBOX_IREQ;
+	ev7_csr	RBOX_INTQ;		/* 0x0080 */
+	ev7_csr	RBOX_INTA;
+	ev7_csr	RBOX_IT;
+	ev7_csr	RBOX_SCRATCH1;
+	ev7_csr	RBOX_SCRATCH2;		/* 0x00c0 */
+	ev7_csr	RBOX_L_ERR;
+} ev7_csrs;
+
+/*
+ * EV7 CSR addressing macros
+ */
+#define EV7_MASK40(addr)        ((addr) & ((1UL << 41) - 1))
+#define EV7_KERN_ADDR(addr)	((void *)(IDENT_ADDR | EV7_MASK40(addr)))
+
+#define EV7_PE_MASK		0x1ffUL /* 9 bits ( 256 + mem/io ) */
+#define EV7_IPE(pe)		((~((long)(pe)) & EV7_PE_MASK) << 35)
+
+#define EV7_CSR_PHYS(pe, off)	(EV7_IPE(pe) | (0x7FFCUL << 20) | (off))
+#define EV7_CSRS_PHYS(pe)	(EV7_CSR_PHYS(pe, 0UL))
+
+#define EV7_CSR_KERN(pe, off)	(EV7_KERN_ADDR(EV7_CSR_PHYS(pe, off)))
+#define EV7_CSRS_KERN(pe)	(EV7_KERN_ADDR(EV7_CSRS_PHYS(pe)))
+
+#define EV7_CSR_OFFSET(name)	((unsigned long)&((ev7_csrs *)NULL)->name.csr)
+
+/*
+ * IO7 registers
+ */
+typedef struct {
+	volatile unsigned long csr __attribute__((aligned(64)));
+} io7_csr;
+
+typedef struct {
+	/* I/O Port Control Registers */
+	io7_csr	POx_CTRL;	       	/* 0x0000 */
+	io7_csr	POx_CACHE_CTL;
+	io7_csr POx_TIMER;
+	io7_csr POx_IO_ADR_EXT;
+	io7_csr	POx_MEM_ADR_EXT;	/* 0x0100 */
+	io7_csr POx_XCAL_CTRL;
+	io7_csr rsvd1[2];	/* ?? spec doesn't show 0x180 */
+	io7_csr POx_DM_SOURCE;		/* ox0200 */
+	io7_csr POx_DM_DEST;
+	io7_csr POx_DM_SIZE;
+	io7_csr POx_DM_STATE;
+	io7_csr rsvd2[4];		/* 0x0300 */
+
+	/* AGP Control Registers -- port 3 only */
+	io7_csr AGP_CAP_ID;		/* 0x0400 */
+	io7_csr AGP_STAT;
+	io7_csr	AGP_CMD;
+	io7_csr	rsvd3;
+
+	/* I/O Port Monitor Registers */
+	io7_csr	POx_MONCTL;		/* 0x0500 */
+	io7_csr POx_CTRA;
+	io7_csr POx_CTRB;
+	io7_csr POx_CTR56;
+	io7_csr POx_SCRATCH;		/* 0x0600 */
+	io7_csr POx_XTRA_A;
+	io7_csr POx_XTRA_TS;
+	io7_csr POx_XTRA_Z;
+	io7_csr rsvd4;			/* 0x0700 */
+	io7_csr POx_THRESHA;
+	io7_csr POx_THRESHB;
+	io7_csr rsvd5[33];
+
+	/* System Address Space Window Control Registers */
+
+	io7_csr POx_WBASE[4];		/* 0x1000 */
+	io7_csr POx_WMASK[4];
+	io7_csr POx_TBASE[4];
+	io7_csr POx_SG_TBIA;
+	io7_csr POx_MSI_WBASE;
+	io7_csr rsvd6[50];
+
+	/* I/O Port Error Registers */
+	io7_csr POx_ERR_SUM;
+	io7_csr POx_FIRST_ERR;
+	io7_csr POx_MSK_HEI;
+	io7_csr POx_TLB_ERR;
+	io7_csr POx_SPL_COMPLT;
+	io7_csr POx_TRANS_SUM;
+	io7_csr POx_FRC_PCI_ERR;
+	io7_csr POx_MULT_ERR;
+	io7_csr rsvd7[8];
+
+	/* I/O Port End of Interrupt Registers */
+	io7_csr EOI_DAT;
+	io7_csr rsvd8[7];
+	io7_csr POx_IACK_SPECIAL;
+	io7_csr rsvd9[103];
+} io7_ioport_csrs;
+
+typedef struct {
+	io7_csr IO_ASIC_REV;		/* 0x30.0000 */
+	io7_csr IO_SYS_REV;
+	io7_csr SER_CHAIN3;
+	io7_csr PO7_RST1;
+	io7_csr PO7_RST2;		/* 0x30.0100 */
+	io7_csr POx_RST[4];
+	io7_csr IO7_DWNH;
+	io7_csr IO7_MAF;
+	io7_csr IO7_MAF_TO;
+	io7_csr IO7_ACC_CLUMP;		/* 0x30.0300 */
+	io7_csr IO7_PMASK;
+	io7_csr IO7_IOMASK;
+	io7_csr IO7_UPH;
+	io7_csr IO7_UPH_TO;		/* 0x30.0400 */
+	io7_csr RBX_IREQ_OFF;
+	io7_csr RBX_INTA_OFF;
+	io7_csr INT_RTY;
+	io7_csr PO7_MONCTL;		/* 0x30.0500 */
+	io7_csr PO7_CTRA;
+	io7_csr PO7_CTRB;
+	io7_csr PO7_CTR56;
+	io7_csr PO7_SCRATCH;		/* 0x30.0600 */
+	io7_csr PO7_XTRA_A;
+	io7_csr PO7_XTRA_TS;
+	io7_csr PO7_XTRA_Z;
+	io7_csr PO7_PMASK;		/* 0x30.0700 */
+	io7_csr PO7_THRESHA;
+	io7_csr PO7_THRESHB;
+	io7_csr rsvd1[97];
+	io7_csr PO7_ERROR_SUM;		/* 0x30.2000 */
+	io7_csr PO7_BHOLE_MASK;
+	io7_csr PO7_HEI_MSK;
+	io7_csr PO7_CRD_MSK;
+	io7_csr PO7_UNCRR_SYM;		/* 0x30.2100 */
+	io7_csr PO7_CRRCT_SYM;
+	io7_csr PO7_ERR_PKT[2];
+	io7_csr PO7_UGBGE_SYM;		/* 0x30.2200 */
+	io7_csr rsbv2[887];
+	io7_csr PO7_LSI_CTL[128];	/* 0x31.0000 */
+	io7_csr rsvd3[123];
+	io7_csr HLT_CTL;		/* 0x31.3ec0 */
+	io7_csr HPI_CTL;		/* 0x31.3f00 */
+	io7_csr CRD_CTL;
+	io7_csr STV_CTL;
+	io7_csr HEI_CTL;
+	io7_csr PO7_MSI_CTL[16];	/* 0x31.4000 */
+	io7_csr rsvd4[240];
+
+	/*
+	 * Interrupt Diagnostic / Test
+	 */
+	struct {
+		io7_csr INT_PND;
+		io7_csr INT_CLR;
+		io7_csr INT_EOI;
+		io7_csr rsvd[29];
+	} INT_DIAG[4];
+	io7_csr rsvd5[125];	    	/* 0x31.a000 */
+	io7_csr MISC_PND;		/* 0x31.b800 */
+	io7_csr rsvd6[31];
+	io7_csr MSI_PND[16];		/* 0x31.c000 */
+	io7_csr rsvd7[16];
+	io7_csr MSI_CLR[16];		/* 0x31.c800 */
+} io7_port7_csrs;
+
+/* 
+ * IO7 DMA Window Base register (POx_WBASEx)
+ */
+#define wbase_m_ena  0x1
+#define wbase_m_sg   0x2
+#define wbase_m_dac  0x4
+#define wbase_m_addr 0xFFF00000
+union IO7_POx_WBASE {
+	struct {
+		unsigned ena : 1;	/* <0>			*/
+		unsigned sg : 1;	/* <1>			*/
+		unsigned dac : 1;	/* <2> -- window 3 only */
+		unsigned rsvd1 : 17; 
+		unsigned addr : 12;	/* <31:20>		*/
+		unsigned rsvd2 : 32;
+	} bits;
+	unsigned as_long[2];
+	unsigned as_quad;
+};
+
+/*
+ * IO7 IID (Interrupt IDentifier) format
+ *
+ * For level-sensitive interrupts, int_num is encoded as:
+ *
+ *	bus/port	slot/device	INTx
+ *	<7:5>		<4:2>		<1:0>
+ */
+union IO7_IID {
+	struct {
+		unsigned int_num : 9;		/* <8:0>    	*/
+		unsigned tpu_mask : 4;		/* <12:9> rsvd	*/
+		unsigned msi : 1;		/* 13		*/
+		unsigned ipe : 10;		/* <23:14>	*/
+		unsigned long rsvd : 40;		
+	} bits;
+	unsigned int as_long[2];
+	unsigned long as_quad;
+};
+
+/*
+ * IO7 addressing macros
+ */
+#define IO7_KERN_ADDR(addr)	(EV7_KERN_ADDR(addr))
+
+#define IO7_PORT_MASK	   	0x07UL	/* 3 bits of port 	   */
+
+#define IO7_IPE(pe)		(EV7_IPE(pe))
+#define IO7_IPORT(port)		((~((long)(port)) & IO7_PORT_MASK) << 32)
+
+#define IO7_HOSE(pe, port)	(IO7_IPE(pe) | IO7_IPORT(port))
+
+#define IO7_MEM_PHYS(pe, port)	(IO7_HOSE(pe, port) | 0x00000000UL)
+#define IO7_CONF_PHYS(pe, port)	(IO7_HOSE(pe, port) | 0xFE000000UL)
+#define IO7_IO_PHYS(pe, port)	(IO7_HOSE(pe, port) | 0xFF000000UL)
+#define IO7_CSR_PHYS(pe, port, off) \
+                                (IO7_HOSE(pe, port) | 0xFF800000UL | (off))
+#define IO7_CSRS_PHYS(pe, port)	(IO7_CSR_PHYS(pe, port, 0UL))
+#define IO7_PORT7_CSRS_PHYS(pe) (IO7_CSR_PHYS(pe, 7, 0x300000UL))
+
+#define IO7_MEM_KERN(pe, port)      (IO7_KERN_ADDR(IO7_MEM_PHYS(pe, port)))
+#define IO7_CONF_KERN(pe, port)     (IO7_KERN_ADDR(IO7_CONF_PHYS(pe, port)))
+#define IO7_IO_KERN(pe, port)       (IO7_KERN_ADDR(IO7_IO_PHYS(pe, port)))
+#define IO7_CSR_KERN(pe, port, off) (IO7_KERN_ADDR(IO7_CSR_PHYS(pe,port,off)))
+#define IO7_CSRS_KERN(pe, port)     (IO7_KERN_ADDR(IO7_CSRS_PHYS(pe, port)))
+#define IO7_PORT7_CSRS_KERN(pe)	    (IO7_KERN_ADDR(IO7_PORT7_CSRS_PHYS(pe)))
+
+#define IO7_PLL_RNGA(pll)	(((pll) >> 3) & 0x7)
+#define IO7_PLL_RNGB(pll)	(((pll) >> 6) & 0x7)
+
+#define IO7_MEM_SPACE		(2UL * 1024 * 1024 * 1024)	/* 2GB MEM */
+#define IO7_IO_SPACE		(8UL * 1024 * 1024)		/* 8MB I/O */
+
+ 
+/* 
+ * Offset between ram physical addresses and pci64 DAC addresses
+ */
+#define IO7_DAC_OFFSET		(1UL << 49)
+
+/*
+ * This is needed to satisify the IO() macro used in initializing the machvec
+ */
+#define MARVEL_IACK_SC 							\
+        ((unsigned long)						\
+	 (&(((io7_ioport_csrs *)IO7_CSRS_KERN(0, 0))->POx_IACK_SPECIAL)))
+
+#ifdef __KERNEL__
+
+/*
+ * IO7 structs
+ */
+#define IO7_NUM_PORTS 4
+#define IO7_AGP_PORT  3
+
+struct io7_port {
+	struct io7 *io7;
+	struct pci_controller *hose;
+
+	int enabled;
+	unsigned int port;
+	io7_ioport_csrs *csrs;
+
+	unsigned long saved_wbase[4];
+	unsigned long saved_wmask[4];
+	unsigned long saved_tbase[4];
+};
+
+struct io7 {
+	struct io7 *next;
+
+	unsigned int pe;
+	io7_port7_csrs *csrs;
+	struct io7_port ports[IO7_NUM_PORTS];
+
+	spinlock_t irq_lock;
+};
+
+#ifndef __EXTERN_INLINE
+# define __EXTERN_INLINE extern inline
+# define __IO_EXTERN_INLINE
+#endif
+
+/*
+ * I/O functions. All access through linear space.
+ */
+
+#define vucp	volatile unsigned char *
+#define vusp	volatile unsigned short *
+#define vuip	volatile unsigned int *
+#define vulp	volatile unsigned long *
+
+#ifdef CONFIG_VGA_HOSE
+extern struct pci_controller *pci_vga_hose;
+
+# define __marvel_is_port_vga(a)	\
+        (((a) >= 0x3b0) && ((a) < 0x3e0) && ((a) != 0x3b3) && ((a) != 0x3d3))
+# define __marvel_is_mem_vga(a)	(((a) >= 0xa0000) && ((a) <= 0xc0000))
+# define FIXUP_IOADDR_VGA(a) do {			\
+	if (pci_vga_hose && __marvel_is_port_vga(a))	\
+		a += pci_vga_hose->io_space->start;	\
+    } while(0)
+#else
+# define FIXUP_IOADDR_VGA(a)
+#endif 
+
+#define __marvel_is_port_kbd(a)	(((a) == 0x60) || ((a) == 0x64))
+#define __marvel_is_port_rtc(a)	(((a) == 0x70) || ((a) == 0x71))
+
+#define FIXUP_IOADDR_LEGACY(a)
+
+#define FIXUP_IOADDR(a) do {				\
+	FIXUP_IOADDR_VGA(a);				\
+        FIXUP_IOADDR_LEGACY(a);				\
+    } while(0)
+
+#if 0
+# define IOBUG(x) printk x
+# define IOBUG_FILTER_IOADDR(a, x)	\
+    if (!__marvel_is_port_kbd(a) && !__marvel_is_port_rtc(a)) IOBUG(x)
+#else
+# define IOBUG(x)
+# define IOBUG_FILTER_IOADDR(a, x)
+#endif
+
+extern u8 __marvel_rtc_io(int write, u8 b, unsigned long addr);
+#define __marvel_rtc_inb(a)	__marvel_rtc_io(0, 0, (a))
+#define __marvel_rtc_outb(b, a)	__marvel_rtc_io(1, (b), (a))
+
+__EXTERN_INLINE int marvel_is_ioaddr(unsigned long addr)
+{
+	return (addr & (1UL << 40)) != 0; /*FIXME - hardwire*/
+}
+
+__EXTERN_INLINE u8 marvel_inb(unsigned long addr)
+{
+	FIXUP_IOADDR(addr);
+	if (!marvel_is_ioaddr(addr)) {
+		if (__marvel_is_port_kbd(addr))
+			return (u8)0;
+		if (__marvel_is_port_rtc(addr))
+			return __marvel_rtc_inb(addr);
+		IOBUG_FILTER_IOADDR(addr, 
+				    ("Bad IO addr %lx - reading -1\n", addr));
+		return (u8)-1;
+	}
+	return __kernel_ldbu(*(vucp)addr);
+}
+
+__EXTERN_INLINE void marvel_outb(u8 b, unsigned long addr)
+{
+	FIXUP_IOADDR(addr);
+	if (!marvel_is_ioaddr(addr)) {
+		if (__marvel_is_port_rtc(addr)) 
+			return (void)__marvel_rtc_outb(b, addr);
+		IOBUG_FILTER_IOADDR(addr, 
+				    ("Bad IO addr %lx - reading -1\n", addr));
+		return;
+	}
+	__kernel_stb(b, *(vucp)addr);
+	mb();
+}
+
+__EXTERN_INLINE u16 marvel_inw(unsigned long addr)
+{
+	FIXUP_IOADDR(addr);
+	if (!marvel_is_ioaddr(addr)) {
+		IOBUG_FILTER_IOADDR(addr, 
+				    ("Bad IO addr %lx - reading -1\n", addr));
+		return (u16)-1;
+	}
+	return __kernel_ldwu(*(vusp)addr);
+}
+
+__EXTERN_INLINE void marvel_outw(u16 w, unsigned long addr)
+{
+	FIXUP_IOADDR(addr);
+	if (!marvel_is_ioaddr(addr)) {
+		IOBUG_FILTER_IOADDR(addr, 
+				    ("Bad IO addr %lx - reading -1\n", addr));
+		return;
+	}
+	__kernel_stw(w, *(vusp)addr);
+	mb();
+}
+
+__EXTERN_INLINE u32 marvel_inl(unsigned long addr)
+{
+	FIXUP_IOADDR(addr);
+	if (!marvel_is_ioaddr(addr)) {
+		IOBUG_FILTER_IOADDR(addr, 
+				    ("Bad IO addr %lx - reading -1\n", addr));
+		return (u32)-1;
+	}
+	return *(vuip)addr;
+}
+
+__EXTERN_INLINE void marvel_outl(u32 l, unsigned long addr)
+{
+	FIXUP_IOADDR(addr);
+	if (!marvel_is_ioaddr(addr)) {
+		IOBUG_FILTER_IOADDR(addr, 
+				    ("Bad IO addr %lx - reading -1\n", addr));
+		return;
+	}
+	*(vuip)addr = l;
+	mb();
+}
+
+/*
+ * Memory functions.  All accesses through linear space.
+ */
+
+extern unsigned long marvel_ioremap(unsigned long addr, unsigned long size);
+extern void marvel_iounmap(unsigned long addr);
+
+__EXTERN_INLINE u8 marvel_readb(unsigned long addr)
+{
+	if (!marvel_is_ioaddr(addr)) {
+		IOBUG(("Bad MEM addr %lx - reading -1\n", addr));
+		return (u8)-1;
+	}
+	return __kernel_ldbu(*(vucp)addr);
+}
+
+__EXTERN_INLINE u16 marvel_readw(unsigned long addr)
+{
+	if (!marvel_is_ioaddr(addr)) {
+		IOBUG(("Bad MEM addr %lx - reading -1\n", addr));
+		return (u16)-1;
+	}
+	return __kernel_ldwu(*(vusp)addr);
+}
+
+__EXTERN_INLINE u32 marvel_readl(unsigned long addr)
+{
+	if (!marvel_is_ioaddr(addr)) {
+		IOBUG(("Bad MEM addr %lx - reading -1\n", addr));
+		return (u32)-1;
+	}
+	return *(vuip)addr;
+}
+
+__EXTERN_INLINE u64 marvel_readq(unsigned long addr)
+{
+	if (!marvel_is_ioaddr(addr)) {
+		IOBUG(("Bad MEM addr %lx - reading -1\n", addr));
+		return (u64)-1;
+	}
+	return *(vulp)addr;
+}
+
+__EXTERN_INLINE void marvel_writeb(u8 b, unsigned long addr)
+{
+	if (!marvel_is_ioaddr(addr)) {
+		IOBUG(("Bad MEM addr %lx - dropping store\n", addr));
+		return;
+	}
+	__kernel_stb(b, *(vucp)addr);
+}
+
+__EXTERN_INLINE void marvel_writew(u16 w, unsigned long addr)
+{
+	if (!marvel_is_ioaddr(addr)) {
+		IOBUG(("Bad MEM addr %lx - dropping store\n", addr));
+		return;
+	}
+	__kernel_stw(w, *(vusp)addr);
+}
+
+__EXTERN_INLINE void marvel_writel(u32 l, unsigned long addr)
+{
+	if (!marvel_is_ioaddr(addr)) {
+		IOBUG(("Bad MEM addr %lx - dropping store\n", addr));
+		return;
+	}
+	*(vuip)addr = l;
+}
+
+__EXTERN_INLINE void marvel_writeq(u64 q, unsigned long addr)
+{
+	if (!marvel_is_ioaddr(addr)) {
+		IOBUG(("Bad MEM addr %lx - dropping store\n", addr));
+		return;
+	}
+	*(vulp)addr = q;
+}
+
+#undef FIXUP_IOADDR
+#undef FIXUP_IOADDR_LEGACY
+#undef FIXUP_IOADDR_VGA
+
+#undef vucp
+#undef vusp
+#undef vuip
+#undef vulp
+
+#ifdef __WANT_IO_DEF
+
+#define __inb(p)		marvel_inb((unsigned long)(p))
+#define __inw(p)		marvel_inw((unsigned long)(p))
+#define __inl(p)		marvel_inl((unsigned long)(p))
+#define __outb(x,p)		marvel_outb((x),(unsigned long)(p))
+#define __outw(x,p)		marvel_outw((x),(unsigned long)(p))
+#define __outl(x,p)		marvel_outl((x),(unsigned long)(p))
+#define __readb(a)		marvel_readb((unsigned long)(a))
+#define __readw(a)		marvel_readw((unsigned long)(a))
+#define __readl(a)		marvel_readl((unsigned long)(a))
+#define __readq(a)		marvel_readq((unsigned long)(a))
+#define __writeb(x,a)		marvel_writeb((x),(unsigned long)(a))
+#define __writew(x,a)		marvel_writew((x),(unsigned long)(a))
+#define __writel(x,a)		marvel_writel((x),(unsigned long)(a))
+#define __writeq(x,a)		marvel_writeq((x),(unsigned long)(a))
+#define __ioremap(a,s)		marvel_ioremap((unsigned long)(a),(s))
+#define __iounmap(a)		marvel_iounmap((unsigned long)(a))
+#define __is_ioaddr(a)		marvel_is_ioaddr((unsigned long)(a))
+
+/* Disable direct inlining of these calls with the debug checks present.  */
+#if 0
+#define __raw_readb(a)		__readb(a)
+#define __raw_readw(a)		__readw(a)
+#define __raw_readl(a)		__readl(a)
+#define __raw_readq(a)		__readq(a)
+#define __raw_writeb(v,a)	__writeb(v,a)
+#define __raw_writew(v,a)	__writew(v,a)
+#define __raw_writel(v,a)	__writel(v,a)
+#define __raw_writeq(v,a)	__writeq(v,a)
+#endif
+
+#endif /* __WANT_IO_DEF */
+
+#ifdef __IO_EXTERN_INLINE
+# undef __EXTERN_INLINE
+# undef __IO_EXTERN_INLINE
+#endif
+
+#endif /* __KERNEL__ */
+
+#endif /* __ALPHA_MARVEL__H__ */
diff -urN linux-2.4.21-pre3/include/asm-alpha/core_titan.h linux-2.4.21-pre4/include/asm-alpha/core_titan.h
--- linux-2.4.21-pre3/include/asm-alpha/core_titan.h	Fri Nov  9 13:45:35 2001
+++ linux-2.4.21-pre4/include/asm-alpha/core_titan.h	Tue Jan 28 19:44:31 2003
@@ -2,6 +2,7 @@
 #define __ALPHA_TITAN__H__
 
 #include <linux/types.h>
+#include <linux/pci.h>
 #include <asm/compiler.h>
 
 /*
@@ -293,13 +294,15 @@
  * 		2 - pachip 0 / A Port
  *      	3 - pachip 1 / A Port
  */
-#define TITAN_HOSE(h)		(((unsigned long)(h)) << 33)
+#define TITAN_HOSE_SHIFT       (33) 
+#define TITAN_HOSE(h)		(((unsigned long)(h)) << TITAN_HOSE_SHIFT)
 #define TITAN_BASE		(IDENT_ADDR + TI_BIAS)
 #define TITAN_MEM(h)	     	(TITAN_BASE+TITAN_HOSE(h)+0x000000000UL)
 #define _TITAN_IACK_SC(h)    	(TITAN_BASE+TITAN_HOSE(h)+0x1F8000000UL)
 #define TITAN_IO(h)	     	(TITAN_BASE+TITAN_HOSE(h)+0x1FC000000UL)
 #define TITAN_CONF(h)	     	(TITAN_BASE+TITAN_HOSE(h)+0x1FE000000UL)
 
+#define TITAN_HOSE_MASK		TITAN_HOSE(3)
 #define TITAN_IACK_SC	     	_TITAN_IACK_SC(0) /* hack! */
 
 /* 
@@ -427,17 +430,8 @@
  * Memory functions.  all accesses are done through linear space.
  */
 
-__EXTERN_INLINE unsigned long titan_ioremap(unsigned long addr, 
-					    unsigned long size
-					    __attribute__((unused)))
-{
-	return addr + TITAN_MEM_BIAS;
-}
-
-__EXTERN_INLINE void titan_iounmap(unsigned long addr)
-{
-	return;
-}
+extern unsigned long titan_ioremap(unsigned long addr, unsigned long size);
+extern void titan_iounmap(unsigned long addr);
 
 __EXTERN_INLINE int titan_is_ioaddr(unsigned long addr)
 {
diff -urN linux-2.4.21-pre3/include/asm-alpha/elf.h linux-2.4.21-pre4/include/asm-alpha/elf.h
--- linux-2.4.21-pre3/include/asm-alpha/elf.h	Fri Sep 22 14:07:43 2000
+++ linux-2.4.21-pre4/include/asm-alpha/elf.h	Tue Jan 28 19:44:31 2003
@@ -52,51 +52,13 @@
 
 #define ELF_PLAT_INIT(_r)       _r->r0 = 0
 
-/* Use the same format as the OSF/1 procfs interface.  The register
-   layout is sane.  However, since dump_thread() creates the funky
-   layout that ECOFF coredumps want, we need to undo that layout here.
-   Eventually, it would be nice if the ECOFF core-dump had to do the
-   translation, then ELF_CORE_COPY_REGS() would become trivial and
-   faster.  */
-#define ELF_CORE_COPY_REGS(_dest,_regs)				\
-{								\
-	struct user _dump;					\
-								\
-	dump_thread(_regs, &_dump);				\
-	_dest[ 0] = _dump.regs[EF_V0];				\
-	_dest[ 1] = _dump.regs[EF_T0];				\
-	_dest[ 2] = _dump.regs[EF_T1];				\
-	_dest[ 3] = _dump.regs[EF_T2];				\
-	_dest[ 4] = _dump.regs[EF_T3];				\
-	_dest[ 5] = _dump.regs[EF_T4];				\
-	_dest[ 6] = _dump.regs[EF_T5];				\
-	_dest[ 7] = _dump.regs[EF_T6];				\
-	_dest[ 8] = _dump.regs[EF_T7];				\
-	_dest[ 9] = _dump.regs[EF_S0];				\
-	_dest[10] = _dump.regs[EF_S1];				\
-	_dest[11] = _dump.regs[EF_S2];				\
-	_dest[12] = _dump.regs[EF_S3];				\
-	_dest[13] = _dump.regs[EF_S4];				\
-	_dest[14] = _dump.regs[EF_S5];				\
-	_dest[15] = _dump.regs[EF_S6];				\
-	_dest[16] = _dump.regs[EF_A0];				\
-	_dest[17] = _dump.regs[EF_A1];				\
-	_dest[18] = _dump.regs[EF_A2];				\
-	_dest[19] = _dump.regs[EF_A3];				\
-	_dest[20] = _dump.regs[EF_A4];				\
-	_dest[21] = _dump.regs[EF_A5];				\
-	_dest[22] = _dump.regs[EF_T8];				\
-	_dest[23] = _dump.regs[EF_T9];				\
-	_dest[24] = _dump.regs[EF_T10];				\
-	_dest[25] = _dump.regs[EF_T11];				\
-	_dest[26] = _dump.regs[EF_RA];				\
-	_dest[27] = _dump.regs[EF_T12];				\
-	_dest[28] = _dump.regs[EF_AT];				\
-	_dest[29] = _dump.regs[EF_GP];				\
-	_dest[30] = _dump.regs[EF_SP];				\
-	_dest[31] = _dump.regs[EF_PC];	/* store PC here */	\
-	_dest[32] = _dump.regs[EF_PS];				\
-}
+/* The registers are layed out in pt_regs for PAL and syscall
+   convenience.  Re-order them for the linear elf_gregset_t.  */
+
+extern void dump_elf_thread(elf_greg_t *, struct pt_regs *,
+			    struct task_struct *);
+#define ELF_CORE_COPY_REGS(DEST, REGS) \
+	dump_elf_thread(DEST, REGS, current);
 
 /* This yields a mask that user programs can use to figure out what
    instruction set this CPU supports.  This is trivial on Alpha, 
diff -urN linux-2.4.21-pre3/include/asm-alpha/gct.h linux-2.4.21-pre4/include/asm-alpha/gct.h
--- linux-2.4.21-pre3/include/asm-alpha/gct.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/include/asm-alpha/gct.h	Tue Jan 28 19:44:31 2003
@@ -0,0 +1,58 @@
+#ifndef __ALPHA_GCT_H
+#define __ALPHA_GCT_H
+
+typedef u64 gct_id;
+typedef u64 gct6_handle;
+
+typedef struct __gct6_node {
+	u8 type;	
+	u8 subtype;
+	u16 size;
+	u32 hd_extension;
+	gct6_handle owner;
+	gct6_handle active_user;
+	gct_id id;
+	u64 flags;
+	u16 rev;
+	u16 change_counter;
+	u16 max_child;
+	u16 reserved1;
+	gct6_handle saved_owner;
+	gct6_handle affinity;
+	gct6_handle parent;
+	gct6_handle next;
+	gct6_handle prev;
+	gct6_handle child;
+	u64 fw_flags;
+	u64 os_usage;
+	u64 fru_id;
+	u32 checksum;
+	u32 magic;	/* 'GLXY' */
+} gct6_node;
+
+typedef struct {
+	u8 type;	
+	u8 subtype;
+	void (*callout)(gct6_node *);
+} gct6_search_struct;
+
+#define GCT_NODE_MAGIC	  0x59584c47	/* 'GLXY' */
+
+/* 
+ * node types 
+ */
+#define GCT_TYPE_HOSE			0x0E
+
+/*
+ * node subtypes
+ */
+#define GCT_SUBTYPE_IO_PORT_MODULE	0x2C
+
+#define GCT_NODE_PTR(off) ((gct6_node *)((char *)hwrpb + 		\
+					 hwrpb->frut_offset + 		\
+					 (gct6_handle)(off)))		\
+
+int gct6_find_nodes(gct6_node *, gct6_search_struct *);
+
+#endif /* __ALPHA_GCT_H */
+
diff -urN linux-2.4.21-pre3/include/asm-alpha/hwrpb.h linux-2.4.21-pre4/include/asm-alpha/hwrpb.h
--- linux-2.4.21-pre3/include/asm-alpha/hwrpb.h	Fri Nov  2 17:39:20 2001
+++ linux-2.4.21-pre4/include/asm-alpha/hwrpb.h	Tue Jan 28 19:44:31 2003
@@ -64,6 +64,7 @@
 #define ST_DEC_CUSCO		 36	/* CUSCO systype	*/
 #define ST_DEC_EIGER		 37	/* Eiger systype	*/
 #define ST_DEC_TITAN		 38	/* Titan systype	*/
+#define ST_DEC_MARVEL		 39	/* Marvel systype	*/
 
 /* UNOFFICIAL!!! */
 #define ST_UNOFFICIAL_BIAS	100
@@ -109,6 +110,9 @@
 	unsigned long ipc_buffer[21];
 	unsigned long palcode_avail[16];
 	unsigned long compatibility;
+	unsigned long console_data_log_pa;
+	unsigned long console_data_log_length;
+	unsigned long bcache_info;
 };
 
 struct procdesc_struct {
diff -urN linux-2.4.21-pre3/include/asm-alpha/io.h linux-2.4.21-pre4/include/asm-alpha/io.h
--- linux-2.4.21-pre3/include/asm-alpha/io.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-alpha/io.h	Tue Jan 28 19:44:31 2003
@@ -19,6 +19,7 @@
 #include <linux/kernel.h>
 #include <asm/system.h>
 #include <asm/machvec.h>
+#include <asm/hwrpb.h>
 
 /*
  * We try to avoid hae updates (thus the cache), but when we
@@ -50,6 +51,7 @@
 /*
  * Change virtual addresses to physical addresses and vv.
  */
+#ifdef USE_48_BIT_KSEG
 static inline unsigned long virt_to_phys(void *address)
 {
 	return (unsigned long)address - IDENT_ADDR;
@@ -59,6 +61,26 @@
 {
 	return (void *) (address + IDENT_ADDR);
 }
+#else
+static inline unsigned long virt_to_phys(void *address)
+{
+        unsigned long phys = (unsigned long)address;
+
+	/* Sign-extend from bit 41.  */
+	phys <<= (64 - 41);
+	phys = (long)phys >> (64 - 41);
+
+	/* Crop to the physical address width of the processor.  */
+        phys &= (1ul << hwrpb->pa_bits) - 1;
+
+        return phys;
+}
+
+static inline void * phys_to_virt(unsigned long address)
+{
+        return (void *)(IDENT_ADDR + (address & ((1ul << 41) - 1)));
+}
+#endif
 
 #define page_to_phys(page)	PAGE_TO_PA(page)
 
@@ -164,6 +186,8 @@
 # include <asm/jensen.h>
 #elif defined(CONFIG_ALPHA_LCA)
 # include <asm/core_lca.h>
+#elif defined(CONFIG_ALPHA_MARVEL)
+# include <asm/core_marvel.h>
 #elif defined(CONFIG_ALPHA_MCPCIA)
 # include <asm/core_mcpcia.h>
 #elif defined(CONFIG_ALPHA_POLARIS)
diff -urN linux-2.4.21-pre3/include/asm-alpha/irq.h linux-2.4.21-pre4/include/asm-alpha/irq.h
--- linux-2.4.21-pre3/include/asm-alpha/irq.h	Sun Aug 12 10:38:47 2001
+++ linux-2.4.21-pre4/include/asm-alpha/irq.h	Tue Jan 28 19:44:31 2003
@@ -16,7 +16,7 @@
    many places throughout the kernel to size static arrays.  That's ok,
    we'll use alpha_mv.nr_irqs when we want the real thing.  */
 
-# define NR_IRQS	2048 /* enuff for WILDFIRE with 8 QBBs */
+# define NR_IRQS	(32768 + 16)	/* marvel - 32 pids */
 
 #elif defined(CONFIG_ALPHA_CABRIOLET) || \
       defined(CONFIG_ALPHA_EB66P)     || \
@@ -57,6 +57,9 @@
 #elif defined(CONFIG_ALPHA_WILDFIRE)
 # define NR_IRQS	2048 /* enuff for 8 QBBs */
 
+#elif defined(CONFIG_ALPHA_MARVEL)
+# define NR_IRQS	(32768 + 16)	/* marvel - 32 pids */
+
 #else /* everyone else */
 # define NR_IRQS	16
 #endif
diff -urN linux-2.4.21-pre3/include/asm-alpha/machvec.h linux-2.4.21-pre4/include/asm-alpha/machvec.h
--- linux-2.4.21-pre3/include/asm-alpha/machvec.h	Fri Nov  9 13:45:35 2001
+++ linux-2.4.21-pre4/include/asm-alpha/machvec.h	Tue Jan 28 19:44:31 2003
@@ -22,6 +22,7 @@
 struct pci_dev;
 struct pci_ops;
 struct pci_controller;
+struct _alpha_agp_info;
 
 struct alpha_machine_vector
 {
@@ -80,6 +81,7 @@
 	void (*device_interrupt)(unsigned long vector, struct pt_regs *regs);
 	void (*machine_check)(u64 vector, u64 la, struct pt_regs *regs);
 
+	void (*smp_callin)(void);
 	void (*init_arch)(void);
 	void (*init_irq)(void);
 	void (*init_rtc)(void);
@@ -90,8 +92,16 @@
 	int (*pci_map_irq)(struct pci_dev *, u8, u8);
 	struct pci_ops *pci_ops;
 
+	struct _alpha_agp_info *(*agp_info)(void);
+
 	const char *vector_name;
 
+	/* NUMA information */
+	int (*pa_to_nid)(unsigned long);
+	int (*cpuid_to_nid)(int);
+	unsigned long (*node_mem_start)(int);
+	unsigned long (*node_mem_size)(int);
+
 	/* System specific parameters.  */
 	union {
 	    struct {
diff -urN linux-2.4.21-pre3/include/asm-alpha/mmzone.h linux-2.4.21-pre4/include/asm-alpha/mmzone.h
--- linux-2.4.21-pre3/include/asm-alpha/mmzone.h	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/include/asm-alpha/mmzone.h	Tue Jan 28 19:44:31 2003
@@ -34,15 +34,19 @@
 
 extern plat_pg_data_t *plat_node_data[];
 
-#ifdef CONFIG_ALPHA_WILDFIRE
-# define ALPHA_PA_TO_NID(pa)	((pa) >> 36)	/* 16 nodes max due 43bit kseg */
-#define NODE_MAX_MEM_SIZE	(64L * 1024L * 1024L * 1024L) /* 64 GB */
-#define MAX_NUMNODES		WILDFIRE_MAX_QBB
-#else
-# define ALPHA_PA_TO_NID(pa)	(0)
-#define NODE_MAX_MEM_SIZE	(~0UL)
-#define MAX_NUMNODES		1
-#endif
+#define ALPHA_PA_TO_NID(pa)		\
+        (alpha_mv.pa_to_nid 		\
+	 ? alpha_mv.pa_to_nid(pa)	\
+	 : (0))
+#define NODE_MEM_START(nid)		\
+        (alpha_mv.node_mem_start 	\
+	 ? alpha_mv.node_mem_start(nid) \
+	 : (0UL))
+#define NODE_MEM_SIZE(nid)		\
+        (alpha_mv.node_mem_size 	\
+	 ? alpha_mv.node_mem_size(nid) 	\
+	 : ((nid) ? (0UL) : (~0UL)))
+#define MAX_NUMNODES		128		/* marvel */
 
 #define PHYSADDR_TO_NID(pa)		ALPHA_PA_TO_NID(pa)
 #define PLAT_NODE_DATA(n)		(plat_node_data[(n)])
@@ -112,12 +116,8 @@
 #define NODE_SCHEDULE_DATA(nid)	(&((PLAT_NODE_DATA(nid))->schedule_data))
 #endif
 
-#ifdef CONFIG_ALPHA_WILDFIRE
-/* With wildfire assume 4 CPUs per node */
-#define cputonode(cpu)	((cpu) >> 2)
-#else
-#define cputonode(cpu)	0
-#endif /* CONFIG_ALPHA_WILDFIRE */
+#define cputonode(cpu) 	\
+        (alpha_mv.cpuid_to_nid ? alpha_mv.cpuid_to_nid(cpu) : 0)
 
 #define numa_node_id()	cputonode(smp_processor_id())
 #endif /* CONFIG_NUMA */
diff -urN linux-2.4.21-pre3/include/asm-alpha/pci.h linux-2.4.21-pre4/include/asm-alpha/pci.h
--- linux-2.4.21-pre3/include/asm-alpha/pci.h	Mon Feb 25 11:38:09 2002
+++ linux-2.4.21-pre4/include/asm-alpha/pci.h	Tue Jan 28 19:44:31 2003
@@ -42,6 +42,8 @@
 
 	struct pci_iommu_arena *sg_pci;
 	struct pci_iommu_arena *sg_isa;
+
+	void *sysdata;
 };
 
 /* Override the logic in pci_scan_bus for skipping already-configured
diff -urN linux-2.4.21-pre3/include/asm-alpha/system.h linux-2.4.21-pre4/include/asm-alpha/system.h
--- linux-2.4.21-pre3/include/asm-alpha/system.h	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/include/asm-alpha/system.h	Tue Jan 28 19:44:31 2003
@@ -23,7 +23,7 @@
 #ifdef CONFIG_ALPHA_LEGACY_START_ADDRESS
 #define KERNEL_START_PHYS	0x300000 /* Old bootloaders hardcoded this.  */
 #else
-#define KERNEL_START_PHYS	0x800000 /* Wildfire has a huge console */
+#define KERNEL_START_PHYS	0x1000000 /* required: Wildfire/Titan/Marvel */
 #endif
 
 #define KERNEL_START	(PAGE_OFFSET+KERNEL_START_PHYS)
@@ -61,7 +61,8 @@
 	int		retry	:  1;	/* retry flag */
 	unsigned int	proc_offset;	/* processor-specific offset */
 	unsigned int	sys_offset;	/* system-specific offset */
-	unsigned long	code;		/* machine check code */
+	unsigned int	code;		/* machine check code */
+	unsigned int	frame_rev;	/* frame revision */
 };
 
 /* Machine Check Frame for uncorrectable errors (Large format)
@@ -117,11 +118,11 @@
 	unsigned long DC0_SYNDROME;
 	unsigned long C_STAT;
 	unsigned long C_STS;
-	unsigned long RESERVED0;
+	unsigned long MM_STAT;
 	unsigned long EXC_ADDR;
 	unsigned long IER_CM;
 	unsigned long ISUM;
-	unsigned long MM_STAT;
+	unsigned long RESERVED0;
 	unsigned long PAL_BASE;
 	unsigned long I_CTL;
 	unsigned long PCTX;
diff -urN linux-2.4.21-pre3/include/asm-i386/pci.h linux-2.4.21-pre4/include/asm-i386/pci.h
--- linux-2.4.21-pre3/include/asm-i386/pci.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.21-pre4/include/asm-i386/pci.h	Tue Jan 28 19:44:31 2003
@@ -103,7 +103,9 @@
 	if (direction == PCI_DMA_NONE)
 		out_of_line_bug();
 
-	return (dma_addr_t)(page - mem_map) * PAGE_SIZE + offset;
+	return ((dma_addr_t)(page - mem_map) *
+		(dma_addr_t) PAGE_SIZE +
+		(dma_addr_t) offset);
 }
 
 static inline void pci_unmap_page(struct pci_dev *hwdev, dma_addr_t dma_address,
diff -urN linux-2.4.21-pre3/include/asm-m68k/macintosh.h linux-2.4.21-pre4/include/asm-m68k/macintosh.h
--- linux-2.4.21-pre3/include/asm-m68k/macintosh.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-m68k/macintosh.h	Tue Jan 28 19:44:31 2003
@@ -74,9 +74,9 @@
 #define MAC_IDE_BABOON		3
 
 #define MAC_SCC_II		1
-#define MAC_SCC_QUADRA		2
-#define MAC_SCC_QUADRA2		3
-#define MAC_SCC_IOP		4
+#define MAC_SCC_IOP		2
+#define MAC_SCC_QUADRA		3
+#define MAC_SCC_PSC		4
 
 #define MAC_ETHER_NONE		0	
 #define MAC_ETHER_SONIC		1
@@ -137,6 +137,7 @@
 #define MAC_MODEL_P475F		90	/* aka: P475 w/ FPU (no LC040) */
 #define MAC_MODEL_P575		92	/* aka: LC575, P577/P578 */
 #define MAC_MODEL_Q605		94
+#define MAC_MODEL_Q605_ACC	95	/* Q605 accelerated to 33 MHz */
 #define MAC_MODEL_Q630		98	/* aka: LC630, P630/631/635/636/637/638/640 */
 #define MAC_MODEL_P588		99	/* aka: LC580, P580 */
 #define MAC_MODEL_PB280		102
diff -urN linux-2.4.21-pre3/include/asm-parisc/atomic.h linux-2.4.21-pre4/include/asm-parisc/atomic.h
--- linux-2.4.21-pre3/include/asm-parisc/atomic.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-parisc/atomic.h	Tue Jan 28 19:44:31 2003
@@ -13,8 +13,9 @@
  * And probably incredibly slow on parisc.  OTOH, we don't
  * have to write any serious assembly.   prumpf
  */
-
 #ifdef CONFIG_SMP
+#include <asm/spinlock_t.h>
+
 /* Use an array of spinlocks for our atomic_ts.
 ** Hash function to index into a different SPINLOCK.
 ** Since "a" is usually an address, ">>8" makes one spinlock per 64-bytes.
@@ -23,25 +24,33 @@
 #  define ATOMIC_HASH(a) (&__atomic_hash[(((unsigned long) a)>>8)&(ATOMIC_HASH_SIZE-1)])
 
 extern spinlock_t __atomic_hash[ATOMIC_HASH_SIZE];
-/* copied from <asm/spinlock.h> and modified */
-#  define SPIN_LOCK(x) \
-	do { while(__ldcw(&(x)->lock) == 0); } while(0)
-	
-#  define SPIN_UNLOCK(x) \
-	do { (x)->lock = 1; } while(0)
-#else
-#  define ATOMIC_HASH_SIZE 1
-#  define ATOMIC_HASH(a)	(0)
 
-/* copied from <linux/spinlock.h> and modified */
-#  define SPIN_LOCK(x) (void)(x)
-	
-#  define SPIN_UNLOCK(x) do { } while(0)
-#endif
+/* copied from <asm/spinlock.h> and modified.
+ * No CONFIG_DEBUG_SPINLOCK support.
+ *
+ * XXX REVISIT these could be renamed and moved to spinlock_t.h as well
+ */
+#define SPIN_LOCK(x)	do { while(__ldcw(&(x)->lock) == 0); } while(0)
+#define SPIN_UNLOCK(x)  do { (x)->lock = 1; } while(0)
+
+#else	/* CONFIG_SMP */
+
+#define ATOMIC_HASH_SIZE 1
+#define ATOMIC_HASH(a)	(0)
+
+#define SPIN_LOCK(x) (void)(x)
+#define SPIN_UNLOCK(x) do { } while(0)
+
+#endif	/* CONFIG_SMP */
 
 /* copied from <linux/spinlock.h> and modified */
-#define SPIN_LOCK_IRQSAVE(lock, flags)		do { local_irq_save(flags);       SPIN_LOCK(lock); } while (0)
-#define SPIN_UNLOCK_IRQRESTORE(lock, flags)	do { SPIN_UNLOCK(lock);  local_irq_restore(flags); } while (0)
+#define SPIN_LOCK_IRQSAVE(lock, flags)	do { \
+	local_irq_save(flags); 	SPIN_LOCK(lock); \
+} while (0)
+
+#define SPIN_UNLOCK_IRQRESTORE(lock, flags) do { \
+	SPIN_UNLOCK(lock);  local_irq_restore(flags); \
+} while (0)
 
 /* Note that we need not lock read accesses - aligned word writes/reads
  * are atomic, so a reader never sees unconsistent values.
@@ -54,22 +63,10 @@
 } atomic_t;
 
 
-/*
-** xchg/cmpxchg moved from asm/system.h - ggg
-*/
-
-#if 1
 /* This should get optimized out since it's never called.
 ** Or get a link error if xchg is used "wrong".
 */
 extern void __xchg_called_with_bad_pointer(void);
-#else
-static inline void __xchg_called_with_bad_pointer(void)
-{
-	extern void panic(const char * fmt, ...);
-	panic("xchg called with bad pointer");
-}
-#endif
 
 /* __xchg32/64 defined in arch/parisc/lib/bitops.c */
 extern unsigned long __xchg8(char, char *);
@@ -98,7 +95,7 @@
 /*
 ** REVISIT - Abandoned use of LDCW in xchg() for now:
 ** o need to test sizeof(*ptr) to avoid clearing adjacent bytes
-** o and while we are at it, could __LP64__ code use LDCD too?
+** o and while we are at it, could 64-bit code use LDCD too?
 **
 **	if (__builtin_constant_p(x) && (x == NULL))
 **		if (((unsigned long)p & 0xf) == 0)
diff -urN linux-2.4.21-pre3/include/asm-parisc/pci.h linux-2.4.21-pre4/include/asm-parisc/pci.h
--- linux-2.4.21-pre3/include/asm-parisc/pci.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-parisc/pci.h	Tue Jan 28 19:44:31 2003
@@ -81,6 +81,11 @@
 #define PCI_BUS_ADDR(hba,a)	((a) - hba->lmmio_space_offset)
 #define PCI_HOST_ADDR(hba,a)	((a) + hba->lmmio_space_offset)
 
+/* The PCI address space equals the physical memory address space.
+   The networking and block device layers use this boolean for bounce buffer
+   decisions.  */
+#define PCI_DMA_BUS_IS_PHYS  1
+
 /*
 ** KLUGE: linux/pci.h include asm/pci.h BEFORE declaring struct pci_bus
 ** (This eliminates some of the warnings).
@@ -273,7 +278,7 @@
 int ccio_allocate_resource(const struct parisc_device *dev,
 		struct resource *res, unsigned long size,
 		unsigned long min, unsigned long max, unsigned long align,
-		void (*alignf)(void *, struct resource *, unsigned long),
+		void (*alignf)(void *, struct resource *, unsigned long, unsigned long),
 		void *alignf_data);
 #else /* !CONFIG_IOMMU_CCIO */
 #define ccio_get_iommu(dev) NULL
diff -urN linux-2.4.21-pre3/include/asm-parisc/pdc.h linux-2.4.21-pre4/include/asm-parisc/pdc.h
--- linux-2.4.21-pre3/include/asm-parisc/pdc.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-parisc/pdc.h	Tue Jan 28 19:44:31 2003
@@ -476,7 +476,7 @@
 #define PDC_TYPE_SYSTEM_MAP	 1 /* 32-bit, but supports PDC_SYSTEM_MAP */
 #define PDC_TYPE_SNAKE		 2 /* Doesn't support SYSTEM_MAP */
 
-#define is_pdc_pat()    (pdc_type == PDC_TYPE_PAT)
+#define is_pdc_pat()	(pdc_type == PDC_TYPE_PAT)
 
 struct pdc_chassis_info {       /* for PDC_CHASSIS_INFO */
 	unsigned long actcnt;   /* actual number of bytes returned */
@@ -817,10 +817,13 @@
 
 /* IODC ENTRY_IO() */
 #define ENTRY_IO_BOOTIN		0
+#define ENTRY_IO_BOOTOUT	1
 #define ENTRY_IO_CIN		2
 #define ENTRY_IO_COUT		3
 #define ENTRY_IO_CLOSE		4
 #define ENTRY_IO_GETMSG		9
+#define ENTRY_IO_BBLOCK_IN	16
+#define ENTRY_IO_BBLOCK_OUT	17
 
 /* IODC ENTRY_SPA() */
 
@@ -912,6 +915,7 @@
 
 int pdc_add_valid(unsigned long address);
 int pdc_chassis_info(struct pdc_chassis_info *chassis_info, void *led_info, unsigned long len);
+int pdc_chassis_disp(unsigned long disp);
 int pdc_coproc_cfg(struct pdc_coproc_cfg *pdc_coproc_info);
 int pdc_iodc_read(unsigned long *actcnt, unsigned long hpa, unsigned int index,
 		  void *iodc_data, unsigned int iodc_data_size);
@@ -958,6 +962,8 @@
                  unsigned long glob_cfg);
 
 #ifdef __LP64__
+int pdc_pat_chassis_send_log(unsigned long status, unsigned long data);
+
 int pdc_pat_cell_get_number(struct pdc_pat_cell_num *cell_info);
 int pdc_pat_cell_module(unsigned long *actcnt, unsigned long ploc, unsigned long mod,
 			unsigned long view_type, void *mem_addr);
diff -urN linux-2.4.21-pre3/include/asm-parisc/pdc_chassis.h linux-2.4.21-pre4/include/asm-parisc/pdc_chassis.h
--- linux-2.4.21-pre3/include/asm-parisc/pdc_chassis.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/include/asm-parisc/pdc_chassis.h	Tue Jan 28 19:44:31 2003
@@ -0,0 +1,382 @@
+/*
+ *		include/asm-parisc/pdc_chassis.h
+ *
+ *		Copyright (C) 2002 Laurent Canet <canetl@esiee.fr>
+ *		Copyright (C) 2002 Thibaut Varene <varenet@esiee.fr>
+ *
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2, or (at your option)
+ *      any later version.
+ *      
+ *      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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *      TODO:	- handle processor number on SMP systems (Reporting Entity ID)
+ *      	- handle message ID
+ *      	- handle timestamps
+ */
+ 
+
+#ifndef _PARISC_PDC_CHASSIS_H
+#define _PARISC_PDC_CHASSIS_H
+
+/*
+ * ----------
+ * Prototypes
+ * ----------
+ */
+
+int pdc_chassis_send_status(int message);
+void __init parisc_pdc_chassis_init(void);
+
+
+/*
+ * -----------------
+ * Direct call names
+ * -----------------
+ * They setup everything for you, the Log message and the corresponding LED state
+ */
+
+#define PDC_CHASSIS_DIRECT_BSTART	0
+#define PDC_CHASSIS_DIRECT_BCOMPLETE	1
+#define PDC_CHASSIS_DIRECT_SHUTDOWN	2
+#define PDC_CHASSIS_DIRECT_PANIC	3
+#define PDC_CHASSIS_DIRECT_HPMC		4
+#define PDC_CHASSIS_DIRECT_LPMC		5
+#define PDC_CHASSIS_DIRECT_DUMP		6	/* not yet implemented */
+#define PDC_CHASSIS_DIRECT_OOPS		7	/* not yet implemented */
+
+
+/*
+ * ------------
+ * LEDs control
+ * ------------
+ * Set the three LEDs -- Run, Attn, and Fault.
+ */
+
+/* Old PDC LED control */
+#define PDC_CHASSIS_DISP_DATA(v)	((unsigned long)(v) << 17)
+
+/* 
+ * Available PDC PAT LED states
+ */
+
+#define PDC_CHASSIS_LED_RUN_OFF		(0ULL << 4)
+#define PDC_CHASSIS_LED_RUN_FLASH	(1ULL << 4)
+#define PDC_CHASSIS_LED_RUN_ON		(2ULL << 4)
+#define PDC_CHASSIS_LED_RUN_NC		(3ULL << 4)
+#define PDC_CHASSIS_LED_ATTN_OFF	(0ULL << 6)
+#define PDC_CHASSIS_LED_ATTN_FLASH	(1ULL << 6)
+#define PDC_CHASSIS_LED_ATTN_NC		(3ULL << 6)	/* ATTN ON is invalid */
+#define PDC_CHASSIS_LED_FAULT_OFF	(0ULL << 8)
+#define PDC_CHASSIS_LED_FAULT_FLASH	(1ULL << 8)
+#define PDC_CHASSIS_LED_FAULT_ON	(2ULL << 8)
+#define PDC_CHASSIS_LED_FAULT_NC	(3ULL << 8)
+#define PDC_CHASSIS_LED_VALID		(1ULL << 10)
+
+/* 
+ * Valid PDC PAT LED states combinations
+ */
+
+/* System running normally */
+#define PDC_CHASSIS_LSTATE_RUN_NORMAL	(PDC_CHASSIS_LED_RUN_ON		| \
+					 PDC_CHASSIS_LED_ATTN_OFF	| \
+					 PDC_CHASSIS_LED_FAULT_OFF	| \
+					 PDC_CHASSIS_LED_VALID		)
+/* System crashed and rebooted itself successfully */
+#define PDC_CHASSIS_LSTATE_RUN_CRASHREC	(PDC_CHASSIS_LED_RUN_ON		| \
+					 PDC_CHASSIS_LED_ATTN_OFF	| \
+					 PDC_CHASSIS_LED_FAULT_FLASH	| \
+					 PDC_CHASSIS_LED_VALID		)
+/* There was a system interruption that did not take the system down */
+#define PDC_CHASSIS_LSTATE_RUN_SYSINT	(PDC_CHASSIS_LED_RUN_ON		| \
+					 PDC_CHASSIS_LED_ATTN_FLASH	| \
+					 PDC_CHASSIS_LED_FAULT_OFF	| \
+					 PDC_CHASSIS_LED_VALID		)
+/* System running and unexpected reboot or non-critical error detected */
+#define PDC_CHASSIS_LSTATE_RUN_NCRIT	(PDC_CHASSIS_LED_RUN_ON		| \
+					 PDC_CHASSIS_LED_ATTN_FLASH	| \
+					 PDC_CHASSIS_LED_FAULT_FLASH	| \
+					 PDC_CHASSIS_LED_VALID		)
+/* Executing non-OS code */
+#define PDC_CHASSIS_LSTATE_NONOS	(PDC_CHASSIS_LED_RUN_FLASH	| \
+					 PDC_CHASSIS_LED_ATTN_OFF	| \
+					 PDC_CHASSIS_LED_FAULT_OFF	| \
+					 PDC_CHASSIS_LED_VALID		)
+/* Boot failed - Executing non-OS code */
+#define PDC_CHASSIS_LSTATE_NONOS_BFAIL	(PDC_CHASSIS_LED_RUN_FLASH	| \
+					 PDC_CHASSIS_LED_ATTN_OFF	| \
+					 PDC_CHASSIS_LED_FAULT_ON	| \
+					 PDC_CHASSIS_LED_VALID		)
+/* Unexpected reboot occured - Executing non-OS code */
+#define PDC_CHASSIS_LSTATE_NONOS_UNEXP	(PDC_CHASSIS_LED_RUN_FLASH	| \
+					 PDC_CHASSIS_LED_ATTN_OFF	| \
+					 PDC_CHASSIS_LED_FAULT_FLASH	| \
+					 PDC_CHASSIS_LED_VALID		)
+/* Executing non-OS code - Non-critical error detected */
+#define PDC_CHASSIS_LSTATE_NONOS_NCRIT	(PDC_CHASSIS_LED_RUN_FLASH	| \
+					 PDC_CHASSIS_LED_ATTN_FLASH	| \
+					 PDC_CHASSIS_LED_FAULT_OFF	| \
+					 PDC_CHASSIS_LED_VALID		)
+/* Boot failed - Executing non-OS code - Non-critical error detected */
+#define PDC_CHASSIS_LSTATE_BFAIL_NCRIT	(PDC_CHASSIS_LED_RUN_FLASH	| \
+					 PDC_CHASSIS_LED_ATTN_FLASH	| \
+					 PDC_CHASSIS_LED_FAULT_ON	| \
+					 PDC_CHASSIS_LED_VALID		)
+/* Unexpected reboot/recovering - Executing non-OS code - Non-critical error detected */
+#define PDC_CHASSIS_LSTATE_UNEXP_NCRIT	(PDC_CHASSIS_LED_RUN_FLASH	| \
+					 PDC_CHASSIS_LED_ATTN_FLASH	| \
+					 PDC_CHASSIS_LED_FAULT_FLASH	| \
+					 PDC_CHASSIS_LED_VALID		)
+/* Cannot execute PDC */
+#define PDC_CHASSIS_LSTATE_CANNOT_PDC	(PDC_CHASSIS_LED_RUN_OFF	| \
+					 PDC_CHASSIS_LED_ATTN_OFF	| \
+					 PDC_CHASSIS_LED_FAULT_OFF	| \
+					 PDC_CHASSIS_LED_VALID		)
+/* Boot failed - OS not up - PDC has detected a failure that prevents boot */
+#define PDC_CHASSIS_LSTATE_FATAL_BFAIL	(PDC_CHASSIS_LED_RUN_OFF	| \
+					 PDC_CHASSIS_LED_ATTN_OFF	| \
+					 PDC_CHASSIS_LED_FAULT_ON	| \
+					 PDC_CHASSIS_LED_VALID		)
+/* No code running - Non-critical error detected (double fault situation) */
+#define PDC_CHASSIS_LSTATE_NOCODE_NCRIT	(PDC_CHASSIS_LED_RUN_OFF	| \
+					 PDC_CHASSIS_LED_ATTN_FLASH	| \
+					 PDC_CHASSIS_LED_FAULT_OFF	| \
+					 PDC_CHASSIS_LED_VALID		)
+/* Boot failed - OS not up - Fatal failure detected - Non-critical error detected */
+#define PDC_CHASSIS_LSTATE_FATAL_NCRIT	(PDC_CHASSIS_LED_RUN_OFF	| \
+					 PDC_CHASSIS_LED_ATTN_FLASH	| \
+					 PDC_CHASSIS_LED_FAULT_ON	| \
+					 PDC_CHASSIS_LED_VALID		)
+/* All other states are invalid */
+
+
+/*
+ * --------------
+ * PDC Log events
+ * --------------
+ * Here follows bits needed to fill up the log event sent to PDC_CHASSIS
+ * The log message contains: Alert level, Source, Source detail,
+ * Source ID, Problem detail, Caller activity, Activity status, 
+ * Caller subactivity, Reporting entity type, Reporting entity ID,
+ * Data type, Unique message ID and EOM. 
+ */
+
+/* Alert level */
+#define PDC_CHASSIS_ALERT_FORWARD	(0ULL << 36)	/* no failure detected */
+#define PDC_CHASSIS_ALERT_SERPROC	(1ULL << 36)	/* service proc - no failure */
+#define PDC_CHASSIS_ALERT_NURGENT	(2ULL << 36)	/* non-urgent operator attn */
+#define PDC_CHASSIS_ALERT_BLOCKED	(3ULL << 36)	/* system blocked */
+#define PDC_CHASSIS_ALERT_CONF_CHG	(4ULL << 36)	/* unexpected configuration change */
+#define PDC_CHASSIS_ALERT_ENV_PB	(5ULL << 36)	/* boot possible, environmental pb */
+#define PDC_CHASSIS_ALERT_PENDING	(6ULL << 36)	/* boot possible, pending failure */
+#define PDC_CHASSIS_ALERT_PERF_IMP	(8ULL << 36)	/* boot possible, performance impaired */
+#define PDC_CHASSIS_ALERT_FUNC_IMP	(10ULL << 36)	/* boot possible, functionality impaired */
+#define PDC_CHASSIS_ALERT_SOFT_FAIL	(12ULL << 36)	/* software failure */
+#define PDC_CHASSIS_ALERT_HANG		(13ULL << 36)	/* system hang */
+#define PDC_CHASSIS_ALERT_ENV_FATAL	(14ULL << 36)	/* fatal power or environmental pb */
+#define PDC_CHASSIS_ALERT_HW_FATAL	(15ULL << 36)	/* fatal hardware problem */
+
+/* Source */
+#define PDC_CHASSIS_SRC_NONE		(0ULL << 28)	/* unknown, no source stated */
+#define PDC_CHASSIS_SRC_PROC		(1ULL << 28)	/* processor */
+/* For later use ? */
+#define PDC_CHASSIS_SRC_PROC_CACHE	(2ULL << 28)	/* processor cache*/
+#define PDC_CHASSIS_SRC_PDH		(3ULL << 28)	/* processor dependent hardware */
+#define PDC_CHASSIS_SRC_PWR		(4ULL << 28)	/* power */
+#define PDC_CHASSIS_SRC_FAB		(5ULL << 28)	/* fabric connector */
+#define PDC_CHASSIS_SRC_PLATi		(6ULL << 28)	/* platform */
+#define PDC_CHASSIS_SRC_MEM		(7ULL << 28)	/* memory */
+#define PDC_CHASSIS_SRC_IO		(8ULL << 28)	/* I/O */
+#define PDC_CHASSIS_SRC_CELL		(9ULL << 28)	/* cell */
+#define PDC_CHASSIS_SRC_PD		(10ULL << 28)	/* protected domain */
+
+/* Source detail field */
+#define PDC_CHASSIS_SRC_D_PROC		(1ULL << 24)	/* processor general */
+
+/* Source ID - platform dependent */
+#define PDC_CHASSIS_SRC_ID_UNSPEC	(0ULL << 16)
+
+/* Problem detail - problem source dependent */
+#define PDC_CHASSIS_PB_D_PROC_NONE	(0ULL << 32)	/* no problem detail */
+#define PDC_CHASSIS_PB_D_PROC_TIMEOUT	(4ULL << 32)	/* timeout */
+
+/* Caller activity */
+#define PDC_CHASSIS_CALL_ACT_HPUX_BL	(7ULL << 12)	/* Boot Loader */
+#define PDC_CHASSIS_CALL_ACT_HPUX_PD	(8ULL << 12)	/* SAL_PD activities */
+#define PDC_CHASSIS_CALL_ACT_HPUX_EVENT	(9ULL << 12)	/* SAL_EVENTS activities */
+#define PDC_CHASSIS_CALL_ACT_HPUX_IO	(10ULL << 12)	/* SAL_IO activities */
+#define PDC_CHASSIS_CALL_ACT_HPUX_PANIC	(11ULL << 12)	/* System panic */
+#define PDC_CHASSIS_CALL_ACT_HPUX_INIT	(12ULL << 12)	/* System initialization */
+#define PDC_CHASSIS_CALL_ACT_HPUX_SHUT	(13ULL << 12)	/* System shutdown */
+#define PDC_CHASSIS_CALL_ACT_HPUX_WARN	(14ULL << 12)	/* System warning */
+#define PDC_CHASSIS_CALL_ACT_HPUX_DU	(15ULL << 12)	/* Display_Activity() update */
+
+/* Activity status - implementation dependent */
+#define PDC_CHASSIS_ACT_STATUS_UNSPEC	(0ULL << 0)
+
+/* Caller subactivity - implementation dependent */
+/* FIXME: other subactivities ? */
+#define PDC_CHASSIS_CALL_SACT_UNSPEC	(0ULL << 4)	/* implementation dependent */
+
+/* Reporting entity type */
+#define PDC_CHASSIS_RET_GENERICOS	(12ULL << 52)	/* generic OSes */
+#define PDC_CHASSIS_RET_IA64_NT		(13ULL << 52)	/* IA-64 NT */
+#define PDC_CHASSIS_RET_HPUX		(14ULL << 52)	/* HP-UX */
+#define PDC_CHASSIS_RET_DIAG		(15ULL << 52)	/* offline diagnostics & utilities */
+
+/* Reporting entity ID */
+#define PDC_CHASSIS_REID_UNSPEC		(0ULL << 44)
+
+/* Data type */
+#define PDC_CHASSIS_DT_NONE		(0ULL << 59)	/* data field unused */
+/* For later use ? Do we need these ? */
+#define PDC_CHASSIS_DT_PHYS_ADDR	(1ULL << 59)	/* physical address */
+#define PDC_CHASSIS_DT_DATA_EXPECT	(2ULL << 59)	/* expected data */
+#define PDC_CHASSIS_DT_ACTUAL		(3ULL << 59)	/* actual data */
+#define PDC_CHASSIS_DT_PHYS_LOC		(4ULL << 59)	/* physical location */
+#define PDC_CHASSIS_DT_PHYS_LOC_EXT	(5ULL << 59)	/* physical location extension */
+#define PDC_CHASSIS_DT_TAG		(6ULL << 59)	/* tag */
+#define PDC_CHASSIS_DT_SYNDROME		(7ULL << 59)	/* syndrome */
+#define PDC_CHASSIS_DT_CODE_ADDR	(8ULL << 59)	/* code address */
+#define PDC_CHASSIS_DT_ASCII_MSG	(9ULL << 59)	/* ascii message */
+#define PDC_CHASSIS_DT_POST		(10ULL << 59)	/* POST code */
+#define PDC_CHASSIS_DT_TIMESTAMP	(11ULL << 59)	/* timestamp */
+#define PDC_CHASSIS_DT_DEV_STAT		(12ULL << 59)	/* device status */
+#define PDC_CHASSIS_DT_DEV_TYPE		(13ULL << 59)	/* device type */
+#define PDC_CHASSIS_DT_PB_DET		(14ULL << 59)	/* problem detail */
+#define PDC_CHASSIS_DT_ACT_LEV		(15ULL << 59)	/* activity level/timeout */
+#define PDC_CHASSIS_DT_SER_NUM		(16ULL << 59)	/* serial number */
+#define PDC_CHASSIS_DT_REV_NUM		(17ULL << 59)	/* revision number */
+#define PDC_CHASSIS_DT_INTERRUPT	(18ULL << 59)	/* interruption information */
+#define PDC_CHASSIS_DT_TEST_NUM		(19ULL << 59)	/* test number */
+#define PDC_CHASSIS_DT_STATE_CHG	(20ULL << 59)	/* major changes in system state */
+#define PDC_CHASSIS_DT_PROC_DEALLOC	(21ULL << 59)	/* processor deallocate */
+#define PDC_CHASSIS_DT_RESET		(30ULL << 59)	/* reset type and cause */
+#define PDC_CHASSIS_DT_PA_LEGACY	(31ULL << 59)	/* legacy PA hex chassis code */
+
+/* System states - part of major changes in system state data field */
+#define PDC_CHASSIS_SYSTATE_BSTART	(0ULL << 0)	/* boot start */
+#define PDC_CHASSIS_SYSTATE_BCOMP	(1ULL << 0)	/* boot complete */
+#define PDC_CHASSIS_SYSTATE_CHANGE	(2ULL << 0)	/* major change */
+#define PDC_CHASSIS_SYSTATE_LED		(3ULL << 0)	/* LED change */
+#define PDC_CHASSIS_SYSTATE_PANIC	(9ULL << 0)	/* OS Panic */
+#define PDC_CHASSIS_SYSTATE_DUMP	(10ULL << 0)	/* memory dump */
+#define PDC_CHASSIS_SYSTATE_HPMC	(11ULL << 0)	/* processing HPMC */
+#define PDC_CHASSIS_SYSTATE_HALT	(15ULL << 0)	/* system halted */
+
+/* Message ID */
+#define PDC_CHASSIS_MSG_ID		(0ULL << 40)	/* we do not handle msg IDs atm */
+
+/* EOM - separates log entries */
+#define PDC_CHASSIS_EOM_CLEAR		(0ULL << 43)
+#define PDC_CHASSIS_EOM_SET		(1ULL << 43)
+
+/*
+ * Preformated well known messages
+ */
+
+/* Boot started */
+#define PDC_CHASSIS_PMSG_BSTART		(PDC_CHASSIS_ALERT_SERPROC	| \
+					 PDC_CHASSIS_SRC_PROC		| \
+					 PDC_CHASSIS_SRC_D_PROC		| \
+					 PDC_CHASSIS_SRC_ID_UNSPEC	| \
+					 PDC_CHASSIS_PB_D_PROC_NONE	| \
+					 PDC_CHASSIS_CALL_ACT_HPUX_INIT	| \
+					 PDC_CHASSIS_ACT_STATUS_UNSPEC	| \
+					 PDC_CHASSIS_CALL_SACT_UNSPEC	| \
+					 PDC_CHASSIS_RET_HPUX		| \
+					 PDC_CHASSIS_REID_UNSPEC	| \
+					 PDC_CHASSIS_DT_STATE_CHG	| \
+					 PDC_CHASSIS_SYSTATE_BSTART	| \
+					 PDC_CHASSIS_MSG_ID		| \
+					 PDC_CHASSIS_EOM_SET		)
+
+/* Boot complete */
+#define PDC_CHASSIS_PMSG_BCOMPLETE	(PDC_CHASSIS_ALERT_SERPROC	| \
+					 PDC_CHASSIS_SRC_PROC		| \
+					 PDC_CHASSIS_SRC_D_PROC		| \
+					 PDC_CHASSIS_SRC_ID_UNSPEC	| \
+					 PDC_CHASSIS_PB_D_PROC_NONE	| \
+					 PDC_CHASSIS_CALL_ACT_HPUX_INIT	| \
+					 PDC_CHASSIS_ACT_STATUS_UNSPEC	| \
+					 PDC_CHASSIS_CALL_SACT_UNSPEC	| \
+					 PDC_CHASSIS_RET_HPUX		| \
+					 PDC_CHASSIS_REID_UNSPEC	| \
+					 PDC_CHASSIS_DT_STATE_CHG	| \
+					 PDC_CHASSIS_SYSTATE_BCOMP	| \
+					 PDC_CHASSIS_MSG_ID		| \
+					 PDC_CHASSIS_EOM_SET		)
+
+/* Shutdown */
+#define PDC_CHASSIS_PMSG_SHUTDOWN	(PDC_CHASSIS_ALERT_SERPROC	| \
+					 PDC_CHASSIS_SRC_PROC		| \
+					 PDC_CHASSIS_SRC_D_PROC		| \
+					 PDC_CHASSIS_SRC_ID_UNSPEC	| \
+					 PDC_CHASSIS_PB_D_PROC_NONE	| \
+					 PDC_CHASSIS_CALL_ACT_HPUX_SHUT	| \
+					 PDC_CHASSIS_ACT_STATUS_UNSPEC	| \
+					 PDC_CHASSIS_CALL_SACT_UNSPEC	| \
+					 PDC_CHASSIS_RET_HPUX		| \
+					 PDC_CHASSIS_REID_UNSPEC	| \
+					 PDC_CHASSIS_DT_STATE_CHG	| \
+					 PDC_CHASSIS_SYSTATE_HALT	| \
+					 PDC_CHASSIS_MSG_ID		| \
+					 PDC_CHASSIS_EOM_SET		)
+
+/* Panic */
+#define PDC_CHASSIS_PMSG_PANIC		(PDC_CHASSIS_ALERT_SOFT_FAIL	| \
+					 PDC_CHASSIS_SRC_PROC		| \
+					 PDC_CHASSIS_SRC_D_PROC		| \
+					 PDC_CHASSIS_SRC_ID_UNSPEC	| \
+					 PDC_CHASSIS_PB_D_PROC_NONE	| \
+					 PDC_CHASSIS_CALL_ACT_HPUX_PANIC| \
+					 PDC_CHASSIS_ACT_STATUS_UNSPEC	| \
+					 PDC_CHASSIS_CALL_SACT_UNSPEC	| \
+					 PDC_CHASSIS_RET_HPUX		| \
+					 PDC_CHASSIS_REID_UNSPEC	| \
+					 PDC_CHASSIS_DT_STATE_CHG	| \
+					 PDC_CHASSIS_SYSTATE_PANIC	| \
+					 PDC_CHASSIS_MSG_ID		| \
+					 PDC_CHASSIS_EOM_SET		)
+
+// FIXME: extrapolated data
+/* HPMC */
+#define PDC_CHASSIS_PMSG_HPMC		(PDC_CHASSIS_ALERT_CONF_CHG /*?*/	| \
+					 PDC_CHASSIS_SRC_PROC		| \
+					 PDC_CHASSIS_SRC_D_PROC		| \
+					 PDC_CHASSIS_SRC_ID_UNSPEC	| \
+					 PDC_CHASSIS_PB_D_PROC_NONE	| \
+					 PDC_CHASSIS_CALL_ACT_HPUX_WARN	| \
+					 PDC_CHASSIS_RET_HPUX		| \
+					 PDC_CHASSIS_DT_STATE_CHG	| \
+					 PDC_CHASSIS_SYSTATE_HPMC	| \
+					 PDC_CHASSIS_MSG_ID		| \
+					 PDC_CHASSIS_EOM_SET		)
+
+/* LPMC */
+#define PDC_CHASSIS_PMSG_LPMC		(PDC_CHASSIS_ALERT_BLOCKED /*?*/| \
+					 PDC_CHASSIS_SRC_PROC		| \
+					 PDC_CHASSIS_SRC_D_PROC		| \
+					 PDC_CHASSIS_SRC_ID_UNSPEC	| \
+					 PDC_CHASSIS_PB_D_PROC_NONE	| \
+					 PDC_CHASSIS_CALL_ACT_HPUX_WARN	| \
+					 PDC_CHASSIS_ACT_STATUS_UNSPEC	| \
+					 PDC_CHASSIS_CALL_SACT_UNSPEC	| \
+					 PDC_CHASSIS_RET_HPUX		| \
+					 PDC_CHASSIS_REID_UNSPEC	| \
+					 PDC_CHASSIS_DT_STATE_CHG	| \
+					 PDC_CHASSIS_SYSTATE_CHANGE	| \
+					 PDC_CHASSIS_MSG_ID		| \
+					 PDC_CHASSIS_EOM_SET		)
+
+#endif /* _PARISC_PDC_CHASSIS_H */
+/* vim: set ts=8 */
diff -urN linux-2.4.21-pre3/include/asm-parisc/pgalloc.h linux-2.4.21-pre4/include/asm-parisc/pgalloc.h
--- linux-2.4.21-pre3/include/asm-parisc/pgalloc.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-parisc/pgalloc.h	Tue Jan 28 19:44:31 2003
@@ -123,6 +123,9 @@
 
 #define flush_icache_page(vma,page)	do { flush_kernel_dcache_page(page_address(page)); flush_kernel_icache_page(page_address(page)); } while (0)
 
+#define flush_icache_user_range(vma, page, addr, len) \
+	flush_user_icache_range(addr, addr + len);
+
 #define flush_icache_range(s,e)		do { flush_kernel_dcache_range_asm(s,e); flush_kernel_icache_range_asm(s,e); } while (0)
 
 /* TLB flushing routines.... */
diff -urN linux-2.4.21-pre3/include/asm-parisc/pgtable.h linux-2.4.21-pre4/include/asm-parisc/pgtable.h
--- linux-2.4.21-pre3/include/asm-parisc/pgtable.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-parisc/pgtable.h	Tue Jan 28 19:44:31 2003
@@ -281,6 +281,11 @@
 	__pte;								\
 })
 
+/* 
+ * Change "struct page" to physical address.
+ */
+#define page_to_phys(page)      PAGE_TO_PA(page)
+
 #ifdef CONFIG_DISCONTIGMEM
 #define PAGE_TO_PA(page) \
 		((((page)-(page)->zone->zone_mem_map) << PAGE_SHIFT) \
diff -urN linux-2.4.21-pre3/include/asm-parisc/processor.h linux-2.4.21-pre4/include/asm-parisc/processor.h
--- linux-2.4.21-pre3/include/asm-parisc/processor.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-parisc/processor.h	Tue Jan 28 19:44:31 2003
@@ -9,6 +9,7 @@
 #define __ASM_PARISC_PROCESSOR_H
 
 #ifndef __ASSEMBLY__
+#include <linux/config.h>
 #include <linux/threads.h>
 
 #include <asm/hardware.h>
@@ -17,6 +18,9 @@
 #include <asm/ptrace.h>
 #include <asm/types.h>
 #include <asm/system.h>
+#ifdef CONFIG_SMP
+#include <asm/spinlock_t.h>
+#endif
 #endif /* __ASSEMBLY__ */
 
 /*
@@ -71,7 +75,6 @@
 */
 struct cpuinfo_parisc {
 
-	struct irq_region *region;
 	unsigned long it_value;     /* Interval Timer value at last timer Intr */
 	unsigned long it_delta;     /* Interval Timer delta (tic_10ms / HZ * 100) */
 	unsigned long irq_count;    /* number of IRQ's since boot */
diff -urN linux-2.4.21-pre3/include/asm-parisc/scatterlist.h linux-2.4.21-pre4/include/asm-parisc/scatterlist.h
--- linux-2.4.21-pre3/include/asm-parisc/scatterlist.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-parisc/scatterlist.h	Tue Jan 28 19:44:31 2003
@@ -23,7 +23,7 @@
 };
 
 #define sg_virt_addr(sg) (((sg)->address) ? ((sg)->address) : \
-		((sg)->page->virtual + (sg)->offset))
+		(page_address((sg)->page) + (sg)->offset))
 
 #define sg_dma_address(sg) ((sg)->iova)
 #define sg_dma_len(sg)     ((sg)->iova_length)
diff -urN linux-2.4.21-pre3/include/asm-parisc/spinlock.h linux-2.4.21-pre4/include/asm-parisc/spinlock.h
--- linux-2.4.21-pre3/include/asm-parisc/spinlock.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-parisc/spinlock.h	Tue Jan 28 19:44:31 2003
@@ -1,35 +1,9 @@
 #ifndef __ASM_SPINLOCK_H
 #define __ASM_SPINLOCK_H
 
-#include <asm/system.h>
-
-/* Note that PA-RISC has to use `1' to mean unlocked and `0' to mean locked
- * since it only has load-and-zero.
- */
-
-#undef SPIN_LOCK_UNLOCKED
-#define SPIN_LOCK_UNLOCKED (spinlock_t) { 1 }
-
-#define spin_lock_init(x)	do { (x)->lock = 1; } while(0)
-
-#define spin_is_locked(x) ((x)->lock == 0)
-
-#define spin_unlock_wait(x)	do { barrier(); } while(((volatile spinlock_t *)(x))->lock == 0)
-
-#if 1
-#define spin_lock(x) do { \
-	while (__ldcw (&(x)->lock) == 0) \
-		while (((x)->lock) == 0) ; } while (0)
-
-#else
-#define spin_lock(x) \
-	do { while(__ldcw(&(x)->lock) == 0); } while(0)
-#endif
-	
-#define spin_unlock(x) \
-	do { (x)->lock = 1; } while(0)
-
-#define spin_trylock(x) (__ldcw(&(x)->lock) != 0)
+#include <asm/spinlock_t.h>		/* get spinlock primitives */
+#include <asm/psw.h>			/* local_* primitives need PSW_I */
+#include <asm/system_irqsave.h>		/* get local_* primitives */
 
 /*
  * Read-write spinlocks, allowing multiple readers
diff -urN linux-2.4.21-pre3/include/asm-parisc/spinlock_t.h linux-2.4.21-pre4/include/asm-parisc/spinlock_t.h
--- linux-2.4.21-pre3/include/asm-parisc/spinlock_t.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/include/asm-parisc/spinlock_t.h	Tue Jan 28 19:44:31 2003
@@ -0,0 +1,59 @@
+#ifndef __PARISC_SPINLOCK_T_H
+#define __PARISC_SPINLOCK_T_H
+
+/* LDCW, the only atomic read-write operation PA-RISC has. *sigh*.
+ *
+ * Note that PA-RISC has to use `1' to mean unlocked and `0' to mean locked
+ * since it only has load-and-zero.
+ */
+#define __ldcw(a) ({ \
+	unsigned __ret; \
+	__asm__ __volatile__("ldcw 0(%1),%0" : "=r" (__ret) : "r" (a)); \
+	__ret; \
+})
+
+/*
+ * Your basic SMP spinlocks, allowing only a single CPU anywhere
+ */
+
+typedef struct {
+	volatile unsigned int __attribute__((aligned(16))) lock;
+#ifdef CONFIG_DEBUG_SPINLOCK
+	volatile unsigned long owner_pc;
+	volatile unsigned long owner_cpu;
+#endif
+} spinlock_t;
+
+#ifndef CONFIG_DEBUG_SPINLOCK
+#define SPIN_LOCK_UNLOCKED (spinlock_t) { 1 }
+
+/* Define 6 spinlock primitives that don't depend on anything else. */
+
+#define spin_lock_init(x)       do { (x)->lock = 1; } while(0)
+#define spin_is_locked(x)       ((x)->lock == 0)
+#define spin_trylock(x)		(__ldcw(&(x)->lock) != 0)
+#define spin_unlock(x)		do { (x)->lock = 1; } while(0)
+
+#define spin_unlock_wait(x)     do { barrier(); } while(((volatile spinlock_t *)(x))->lock == 0)
+
+#define spin_lock(x) do { \
+	while (__ldcw (&(x)->lock) == 0) \
+		while ((x)->lock == 0) ; \
+} while (0)
+
+#else
+
+#define SPIN_LOCK_UNLOCKED (spinlock_t) { 1, 0, 0 }
+
+/* Define 6 spinlock primitives that don't depend on anything else. */
+
+#define spin_lock_init(x)       do { (x)->lock = 1; (x)->owner_cpu = 0; (x)->owner_pc = 0; } while(0)
+#define spin_is_locked(x)       ((x)->lock == 0)
+void spin_lock(spinlock_t *lock);
+int spin_trylock(spinlock_t *lock);
+void spin_unlock(spinlock_t *lock);
+#define spin_unlock_wait(x)     do { barrier(); } while(((volatile spinlock_t *)(x))->lock == 0)
+
+#endif
+
+#endif /* __PARISC_SPINLOCK_T_H */
diff -urN linux-2.4.21-pre3/include/asm-parisc/system.h linux-2.4.21-pre4/include/asm-parisc/system.h
--- linux-2.4.21-pre3/include/asm-parisc/system.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-parisc/system.h	Tue Jan 28 19:44:31 2003
@@ -3,6 +3,11 @@
 
 #include <linux/config.h>
 #include <asm/psw.h>
+#include <asm/system_irqsave.h>
+
+#ifdef CONFIG_SMP
+#include <asm/spinlock_t.h>
+#endif
 
 /* The program status word as bitfields.  */
 struct pa_psw {
@@ -51,22 +56,6 @@
 } while(0)
 
 
-
-/* interrupt control */
-#define __save_flags(x)	__asm__ __volatile__("ssm 0, %0" : "=r" (x) : : "memory")
-#define __restore_flags(x) __asm__ __volatile__("mtsm %0" : : "r" (x) : "memory")
-#define __cli()	__asm__ __volatile__("rsm %0,%%r0\n" : : "i" (PSW_I) : "memory" )
-#define __sti()	__asm__ __volatile__("ssm %0,%%r0\n" : : "i" (PSW_I) : "memory" )
-
-#define local_irq_save(x) \
-	__asm__ __volatile__("rsm %1,%0" : "=r" (x) :"i" (PSW_I) : "memory" )
-#define local_irq_set(x) \
-	__asm__ __volatile__("ssm %1,%0" : "=r" (x) :"i" (PSW_I) : "memory" )
-#define local_irq_restore(x) \
-	__asm__ __volatile__("mtsm %0" : : "r" (x) : "memory" )
-#define local_irq_disable() __cli()
-#define local_irq_enable()  __sti()
-
 #ifdef CONFIG_SMP
 extern void __global_cli(void);
 extern void __global_sti(void);
@@ -77,7 +66,7 @@
 #define sti() __global_sti()
 #define save_flags(x) ((x)=__global_save_flags())
 #define restore_flags(x) __global_restore_flags(x)
- 
+
 #else
 
 #define cli() __cli()
@@ -153,23 +142,4 @@
 
 #define set_mb(var, value) do { var = value; mb(); } while (0)
 
-
-/* LDCW, the only atomic read-write operation PA-RISC has. *sigh*.  */
-#define __ldcw(a) ({ \
-	unsigned __ret; \
-	__asm__ __volatile__("ldcw 0(%1),%0" : "=r" (__ret) : "r" (a)); \
-	__ret; \
-})
-
-
-#ifdef CONFIG_SMP
-/*
- * Your basic SMP spinlocks, allowing only a single CPU anywhere
- */
-
-typedef struct {
-	volatile unsigned int __attribute__((aligned(16))) lock;
-} spinlock_t;
-#endif
-
 #endif
diff -urN linux-2.4.21-pre3/include/asm-parisc/uaccess.h linux-2.4.21-pre4/include/asm-parisc/uaccess.h
--- linux-2.4.21-pre3/include/asm-parisc/uaccess.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-parisc/uaccess.h	Tue Jan 28 19:44:31 2003
@@ -37,8 +37,8 @@
 #if BITS_PER_LONG == 32
 #define LDD_KERNEL(ptr)		BUG()
 #define LDD_USER(ptr)		BUG()
-#define STD_KERNEL(x, ptr)	BUG()
-#define STD_USER(x, ptr)	BUG()
+#define STD_KERNEL(x, ptr) __put_kernel_asm64(x,ptr)
+#define STD_USER(x, ptr) __put_user_asm64(x,ptr)
 #else
 #define LDD_KERNEL(ptr) __get_kernel_asm("ldd",ptr)
 #define LDD_USER(ptr) __get_user_asm("ldd",ptr)
@@ -210,6 +210,43 @@
 		 "\t.previous"                              \
 		: "=r"(__pu_err)                            \
 		: "r"(ptr), "r"(x), "0"(__pu_err))
+
+static inline void __put_kernel_asm64(u64 x, void *ptr)
+{
+	u32 hi = x>>32;
+	u32 lo = x&0xffffffff;
+	__asm__ __volatile__ (
+		"\n1:\tstw %1,0(%0)\n"
+		"\n2:\tstw %2,4(%0)\n"
+		"3:\n"
+		"\t.section __ex_table,\"a\"\n"
+		 "\t.word\t1b\n"
+		 "\t.word\t(3b-1b)+1\n"
+		 "\t.word\t2b\n"
+		 "\t.word\t(3b-2b)+1\n"
+		 "\t.previous"
+		: : "r"(ptr), "r"(hi), "r"(lo));
+
+}
+
+static inline void __put_user_asm64(u64 x, void *ptr)
+{
+	u32 hi = x>>32;
+	u32 lo = x&0xffffffff;
+	__asm__ __volatile__ (
+		"\n1:\tstw %1,0(%%sr3,%0)\n"
+		"\n2:\tstw %2,4(%%sr3,%0)\n"
+		"3:\n"
+		"\t.section __ex_table,\"a\"\n"
+		 "\t.word\t1b\n"
+		 "\t.word\t(3b-1b)+1\n"
+		 "\t.word\t2b\n"
+		 "\t.word\t(3b-2b)+1\n"
+		 "\t.previous"
+		: : "r"(ptr), "r"(hi), "r"(lo));
+
+}
+
 #endif
 
 
diff -urN linux-2.4.21-pre3/include/asm-parisc/unistd.h linux-2.4.21-pre4/include/asm-parisc/unistd.h
--- linux-2.4.21-pre3/include/asm-parisc/unistd.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-parisc/unistd.h	Tue Jan 28 19:44:31 2003
@@ -700,8 +700,9 @@
 #define __NR_acl_set            (__NR_Linux + 205)
 #define __NR_gettid             (__NR_Linux + 206)
 #define __NR_readahead          (__NR_Linux + 207)
+#define __NR_tkill              (__NR_Linux + 208)
 
-#define __NR_Linux_syscalls     207
+#define __NR_Linux_syscalls     208
 
 #define HPUX_GATEWAY_ADDR       0xC0000004
 #define LINUX_GATEWAY_ADDR      0x100
diff -urN linux-2.4.21-pre3/include/asm-ppc/processor.h linux-2.4.21-pre4/include/asm-ppc/processor.h
--- linux-2.4.21-pre3/include/asm-ppc/processor.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-ppc/processor.h	Tue Jan 28 19:44:31 2003
@@ -659,10 +659,10 @@
 
 struct thread_struct {
 	unsigned long	ksp;		/* Kernel stack pointer */
-	unsigned long	wchan;		/* Event task is sleeping on */
 	struct pt_regs	*regs;		/* Pointer to saved register state */
 	mm_segment_t	fs;		/* for get_fs() validation */
 	void		*pgdir;		/* root of page-table tree */
+	int		fpexc_mode;	/* floating-point exception mode */
 	signed long     last_syscall;
 	double		fpr[32];	/* Complete floating point set */
 	unsigned long	fpscr_pad;	/* fpr ... fpscr must be contiguous */
@@ -677,13 +677,10 @@
 #define INIT_SP		(sizeof(init_stack) + (unsigned long) &init_stack)
 
 #define INIT_THREAD  { \
-	INIT_SP, /* ksp */ \
-	0, /* wchan */ \
-	0, /* regs */ \
-	KERNEL_DS, /*fs*/ \
-	swapper_pg_dir, /* pgdir */ \
-	0, /* last_syscall */ \
-	{0}, 0, 0 \
+	.ksp = INIT_SP, \
+	.fs = KERNEL_DS, \
+	.pgdir = swapper_pg_dir, \
+	.fpexc_mode = MSR_FE0 | MSR_FE1, \
 }
 
 /*
@@ -702,6 +699,13 @@
 #define KSTK_EIP(tsk)  ((tsk)->thread.regs? (tsk)->thread.regs->nip: 0)
 #define KSTK_ESP(tsk)  ((tsk)->thread.regs? (tsk)->thread.regs->gpr[1]: 0)
 
+/* Get/set floating-point exception mode */
+#define GET_FPEXC_CTL(tsk, adr)	get_fpexc_mode((tsk), (adr))
+#define SET_FPEXC_CTL(tsk, val)	set_fpexc_mode((tsk), (val))
+
+extern int get_fpexc_mode(struct task_struct *tsk, unsigned long adr);
+extern int set_fpexc_mode(struct task_struct *tsk, unsigned int val);
+
 /*
  * NOTE! The task struct and the stack go together
  */
diff -urN linux-2.4.21-pre3/include/asm-ppc64/a.out.h linux-2.4.21-pre4/include/asm-ppc64/a.out.h
--- linux-2.4.21-pre3/include/asm-ppc64/a.out.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.21-pre4/include/asm-ppc64/a.out.h	Tue Jan 28 19:44:31 2003
@@ -31,7 +31,7 @@
 #ifdef __KERNEL__
 
 /* 64-bit user address space is less PGDIR_SIZE due to pgd_index() bug. */
-#define STACK_TOP_USER64 (TASK_SIZE_USER64 - PGDIR_SIZE)
+#define STACK_TOP_USER64 (TASK_SIZE_USER64)
 
 /* Give 32-bit user space a full 4G address space to live in. */
 #define STACK_TOP_USER32 (TASK_SIZE_USER32)
diff -urN linux-2.4.21-pre3/include/asm-ppc64/bitops.h linux-2.4.21-pre4/include/asm-ppc64/bitops.h
--- linux-2.4.21-pre3/include/asm-ppc64/bitops.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.21-pre4/include/asm-ppc64/bitops.h	Tue Jan 28 19:44:31 2003
@@ -33,7 +33,6 @@
 
 #ifdef __KERNEL__
 
-#include <asm/byteorder.h>
 #include <asm/memory.h>
 
 /*
@@ -243,35 +242,30 @@
 }
 
 
-
 /*
- * ffz = Find First Zero in word. Undefined if no zero exists,
- *    Determines the bit position of the LEAST significant
- *    (rightmost) 0 bit in the specified DOUBLE-WORD.
- *    The returned bit position will be zero-based, starting
- *    from the right side (63 - 0).
- *    the code should check against ~0UL first..
+ * ffz = Find First Zero in word.
+ * Determines the bit position of the least significant (rightmost) 0 bit
+ * in the specified double word. The returned bit position will be zero-based,
+ * starting from the right side (63 - 0).
  */
 static __inline__ unsigned long ffz(unsigned long x)
 {
-	u32  tempRC;
-
-	/* Change all of x's 1s to 0s and 0s to 1s in x.
-	 * And insure at least 1 zero exists in the 8 byte area.
-	 */
+	/* no zero exists anywhere in the 8 byte area. */
 	if ((x = ~x) == 0)
-		/* no zero exists anywhere in the 8 byte area. */
 		return 64;
 
-	/* Calculate the bit position of the least significant '1' bit in x
-	 * (since x has been changed this will actually be the least
-	 * significant '0' bit in the original x).
-	 * Note: (x & -x) gives us a mask that is the LEAST significant
-	 * (RIGHT-most) 1-bit of the value in x.
+	/*
+	 * Calculate the bit position of the least signficant '1' bit in x
+	 * (since x has been changed this will actually be the least signficant
+	 * '0' bit in * the original x).  Note: (x & -x) gives us a mask that
+	 * is the least significant * (RIGHT-most) 1-bit of the value in x.
 	 */
-	tempRC = __ilog2(x & -x);
+	return __ilog2(x & -x);
+}
 
-	return tempRC;
+static __inline__ int __ffs(unsigned long x)
+{
+	return __ilog2(x & -x);
 }
 
 /*
@@ -281,11 +275,17 @@
  */
 static __inline__ int ffs(int x)
 {
-	int result = ffz(~x);
-	return x ? result+1 : 0;
+	unsigned long i = (unsigned long)x;
+	return __ilog2(i & -i) + 1;
 }
 
 /*
+ * fls: find last (most-significant) bit set.
+ * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
+ */
+#define fls(x) generic_fls(x)
+
+/*
  * hweightN: returns the hamming weight (i.e. the number
  * of bits set) of a N-bit word
  */
@@ -293,139 +293,82 @@
 #define hweight16(x) generic_hweight16(x)
 #define hweight8(x) generic_hweight8(x)
 
-extern unsigned long find_next_zero_bit(void * addr, unsigned long size,
-					unsigned long offset);
-/*
- * The optimizer actually does good code for this case..
- */
-#define find_first_zero_bit(addr, size) find_next_zero_bit((addr), (size), 0)
-
-/* Bitmap functions for the ext2 filesystem. */
-#define _EXT2_HAVE_ASM_BITOPS_
+extern unsigned long find_next_zero_bit(unsigned long* addr, unsigned long size, unsigned long offset);
+#define find_first_zero_bit(addr, size) \
+	find_next_zero_bit((addr), (size), 0)
+
+extern unsigned long find_next_bit(unsigned long* addr, unsigned long size, unsigned long offset);
+#define find_first_bit(addr, size) \
+	find_next_bit((addr), (size), 0)
+
+extern unsigned long find_next_zero_le_bit(unsigned long *addr, unsigned long size, unsigned long offset);
+#define find_first_zero_le_bit(addr, size) \
+	find_next_zero_le_bit((addr), (size), 0)
 
-static __inline__ int ext2_set_bit(int nr, void* addr)
+static __inline__ int test_le_bit(unsigned long nr, __const__ unsigned long * addr)
 {
-	/* This method needs to take into account the fact that the ext2 file system represents
-	 *  it's bitmaps as "little endian" unsigned integers.
-	 * Note: this method is not atomic, but ext2 does not need it to be.
-	 */
-	int mask;
-	int oldbit;
-	unsigned char* ADDR = (unsigned char*) addr;
-
-	/* Determine the BYTE containing the specified bit
-	 * (nr) - important as if we go to a byte there are no
-	 * little endian concerns.
-	 */
-	ADDR += nr >> 3;
-	mask = 1 << (nr & 0x07);  /* Create a mask to the bit within this byte. */
-	oldbit = *ADDR & mask;  /* Save the bit's previous value. */
-	*ADDR |= mask;  /* Turn the bit on. */
-	return oldbit;  /* Return the bit's previous value. */
+	__const__ unsigned char	*ADDR = (__const__ unsigned char *) addr;
+	return (ADDR[nr >> 3] >> (nr & 7)) & 1;
 }
 
-static __inline__ int ext2_clear_bit(int nr, void* addr)
+/*
+ * non-atomic versions
+ */
+static __inline__ void __set_le_bit(unsigned long nr, unsigned long *addr)
 {
-	/* This method needs to take into account the fact that the ext2 file system represents
-	 * | it's bitmaps as "little endian" unsigned integers.
-	 * Note: this method is not atomic, but ext2 does not need it to be.
-	 */
-        int     mask;
-        int oldbit;
-        unsigned char* ADDR = (unsigned char*) addr;
-
-	/* Determine the BYTE containing the specified bit (nr)
-	 *  - important as if we go to a byte there are no little endian concerns.
-	 */
-        ADDR += nr >> 3;
-        mask = 1 << (nr & 0x07);  /* Create a mask to the bit within this byte. */
-        oldbit = *ADDR & mask;  /* Save the bit's previous value. */
-        *ADDR = *ADDR & ~mask;  /* Turn the bit off. */
-        return oldbit;  /* Return the bit's previous value. */
-}
+	unsigned char *ADDR = (unsigned char *)addr;
 
-static __inline__ int ext2_test_bit(int nr, __const__ void * addr)
-{
-	/* This method needs to take into account the fact that the ext2 file system represents
-	 * | it's bitmaps as "little endian" unsigned integers.
-	 * Determine the BYTE containing the specified bit (nr),
-	 *   then shift to the right the correct number of bits and return that bit's value.
-	 */
-	__const__ unsigned char	*ADDR = (__const__ unsigned char *) addr;
-	return (ADDR[nr >> 3] >> (nr & 7)) & 1;
+	ADDR += nr >> 3;
+	*ADDR |= 1 << (nr & 0x07);
 }
 
-/* Returns the bit position of the most significant 1 bit in a WORD. */
-static __inline__ int ext2_ilog2(unsigned int x)
+static __inline__ void __clear_le_bit(unsigned long nr, unsigned long *addr)
 {
-        int lz;
+	unsigned char *ADDR = (unsigned char *)addr;
 
-        asm ("cntlzw %0,%1" : "=r" (lz) : "r" (x));
-        return 31 - lz;
+	ADDR += nr >> 3;
+	*ADDR &= ~(1 << (nr & 0x07));
 }
 
-/* ext2_ffz = ext2's Find First Zero.
- *    Determines the bit position of the LEAST significant (rightmost) 0 bit in the specified WORD.
- *    The returned bit position will be zero-based, starting from the right side (31 - 0).
- */
-static __inline__ int ext2_ffz(unsigned int x)
+static __inline__ int __test_and_set_le_bit(unsigned long nr, unsigned long *addr)
 {
-	u32  tempRC;
-	/* Change all of x's 1s to 0s and 0s to 1s in x.  And insure at least 1 zero exists in the word. */
-	if ((x = ~x) == 0)
-		/* no zero exists anywhere in the 4 byte area. */
-		return 32;
-	/* Calculate the bit position of the least significant '1' bit in x
-	 * (since x has been changed this will actually be the least
-	 * significant '0' bit in the original x).
-	 * Note: (x & -x) gives us a mask that is the LEAST significant
-	 * (RIGHT-most) 1-bit of the value in x.
-	 */
-	tempRC = ext2_ilog2(x & -x);
-	return tempRC;
+	int mask, retval;
+	unsigned char *ADDR = (unsigned char *)addr;
+
+	ADDR += nr >> 3;
+	mask = 1 << (nr & 0x07);
+	retval = (mask & *ADDR) != 0;
+	*ADDR |= mask;
+	return retval;
 }
 
-static __inline__ u32 ext2_find_next_zero_bit(void* addr, u32 size, u32 offset)
+static __inline__ int __test_and_clear_le_bit(unsigned long nr, unsigned long *addr)
 {
-	/* This method needs to take into account the fact that the ext2 file system represents
-	 * | it's bitmaps as "little endian" unsigned integers.
-	 */
-        unsigned int *p = ((unsigned int *) addr) + (offset >> 5);
-        unsigned int result = offset & ~31;
-        unsigned int tmp;
-
-        if (offset >= size)
-                return size;
-        size -= result;
-        offset &= 31;
-        if (offset) {
-                tmp = cpu_to_le32p(p++);
-                tmp |= ~0U >> (32-offset); /* bug or feature ? */
-                if (size < 32)
-                        goto found_first;
-                if (tmp != ~0)
-                        goto found_middle;
-                size -= 32;
-                result += 32;
-        }
-        while (size >= 32) {
-                if ((tmp = cpu_to_le32p(p++)) != ~0)
-                        goto found_middle;
-                result += 32;
-                size -= 32;
-        }
-        if (!size)
-                return result;
-        tmp = cpu_to_le32p(p);
-found_first:
-        tmp |= ~0 << size;
-        if (tmp == ~0)          /* Are any bits zero? */
-                return result + size; /* Nope. */
-found_middle:
-        return result + ext2_ffz(tmp);
-}
+	int mask, retval;
+	unsigned char *ADDR = (unsigned char *)addr;
 
-#define ext2_find_first_zero_bit(addr, size) ext2_find_next_zero_bit((addr), (size), 0)
+	ADDR += nr >> 3;
+	mask = 1 << (nr & 0x07);
+	retval = (mask & *ADDR) != 0;
+	*ADDR &= ~mask;
+	return retval;
+}
+
+#define ext2_set_bit(nr,addr) \
+	__test_and_set_le_bit((nr),(unsigned long*)addr)
+#define ext2_clear_bit(nr, addr) \
+	__test_and_clear_le_bit((nr),(unsigned long*)addr)
+#define ext2_test_bit(nr, addr)      test_le_bit((nr),(unsigned long*)addr)
+#define ext2_find_first_zero_bit(addr, size) \
+	find_first_zero_le_bit((unsigned long*)addr, size)
+#define ext2_find_next_zero_bit(addr, size, off) \
+	find_next_zero_le_bit((unsigned long*)addr, size, off)
+
+#define minix_test_and_set_bit(nr,addr)		test_and_set_bit(nr,addr)
+#define minix_set_bit(nr,addr)			set_bit(nr,addr)
+#define minix_test_and_clear_bit(nr,addr)	test_and_clear_bit(nr,addr)
+#define minix_test_bit(nr,addr)			test_bit(nr,addr)
+#define minix_find_first_zero_bit(addr,size)	find_first_zero_bit(addr,size)
 
 #endif /* __KERNEL__ */
 #endif /* _PPC64_BITOPS_H */
diff -urN linux-2.4.21-pre3/include/asm-ppc64/delay.h linux-2.4.21-pre4/include/asm-ppc64/delay.h
--- linux-2.4.21-pre3/include/asm-ppc64/delay.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-ppc64/delay.h	Tue Jan 28 19:44:31 2003
@@ -19,6 +19,7 @@
 /* define these here to prevent circular dependencies */ 
 #define __HMT_low()	asm volatile("or 1,1,1")
 #define __HMT_medium()	asm volatile("or 2,2,2")
+#define __barrier()	asm volatile("":::"memory")
 
 static inline unsigned long __get_tb(void)
 {
@@ -34,6 +35,8 @@
 
 	while((__get_tb()-start) < loops)
 		__HMT_low();
+	__HMT_medium();
+	__barrier();
 }
 
 static inline void udelay(unsigned long usecs)
@@ -41,7 +44,6 @@
 	unsigned long loops = tb_ticks_per_usec * usecs;
 
 	__delay(loops);
-	__HMT_medium();
 }
 #endif /* !__ASSEMBLY__ */
 
diff -urN linux-2.4.21-pre3/include/asm-ppc64/eeh.h linux-2.4.21-pre4/include/asm-ppc64/eeh.h
--- linux-2.4.21-pre3/include/asm-ppc64/eeh.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-ppc64/eeh.h	Tue Jan 28 19:44:31 2003
@@ -27,25 +27,26 @@
 
 struct pci_dev;
 
-#define IO_UNMAPPED_REGION_ID 0xaUL
-
-#define IO_TOKEN_TO_ADDR(token) ((((unsigned long)(token)) & 0xFFFFFFFF) | (0xEUL << 60))
-/* Flag bits encoded in the 3 unused function bits of devfn */
-#define EEH_TOKEN_DISABLED (1UL << 34UL)	/* eeh is disabled for this token */
-#define IS_EEH_TOKEN_DISABLED(token) ((unsigned long)(token) & EEH_TOKEN_DISABLED)
-
-#define EEH_STATE_OVERRIDE 1   /* IOA does not require eeh traps */
-#define EEH_STATE_FAILURE  16  /* */
+/* I/O addresses are converted to EEH "tokens" such that a driver will cause
+ * a bad page fault if the address is used directly (i.e. these addresses are
+ * never actually mapped.  Translation between IO <-> EEH region is 1 to 1.
+ */
+#define IO_TOKEN_TO_ADDR(token) (((unsigned long)(token) & ~(0xfUL << REGION_SHIFT)) | \
+				(IO_REGION_ID << REGION_SHIFT))
+#define IO_ADDR_TO_TOKEN(addr) (((unsigned long)(addr) & ~(0xfUL << REGION_SHIFT)) | \
+				(EEH_REGION_ID << REGION_SHIFT))
+
+/* Values for eeh_mode bits in device_node */
+#define EEH_MODE_SUPPORTED	(1<<0)
+#define EEH_MODE_NOCHECK	(1<<1)
 
 /* This is for profiling only */
 extern unsigned long eeh_total_mmio_ffs;
 
-extern int eeh_implemented;
-
 void eeh_init(void);
-static inline int is_eeh_implemented(void) { return eeh_implemented; }
 int eeh_get_state(unsigned long ea);
 unsigned long eeh_check_failure(void *token, unsigned long val);
+void *eeh_ioremap(unsigned long addr, void *vaddr);
 
 #define EEH_DISABLE		0
 #define EEH_ENABLE		1
@@ -58,15 +59,11 @@
  */
 int is_eeh_configured(struct pci_dev *dev);
 
-/* Generate an EEH token.
- * The high nibble of the offset is cleared, otherwise bounds checking is performed.
- * Use IO_TOKEN_TO_ADDR(token) to translate this token back to a mapped virtual addr.
- * Do NOT do this to perform IO -- use the read/write macros!
- */
-unsigned long eeh_token(unsigned long phb,
-			unsigned long bus,
-			unsigned long devfn,
-			unsigned long offset);
+/* Translate a (possible) eeh token to a physical addr.
+ * If "token" is not an eeh token it is simply returned under
+ * the assumption that it is already a physical addr.
+ */
+unsigned long eeh_token_to_phys(unsigned long token);
 
 extern void *memcpy(void *, const void *, unsigned long);
 extern void *memset(void *,int, unsigned long);
@@ -77,15 +74,16 @@
  * If EEH is off for a device and it is a memory BAR, ioremap will
  * map it to the IOREGION.  In this case addr == vaddr and since these
  * should be in registers we compare them first.  Next we check for
- * all ones which is perhaps fastest as ~val.  Finally we weed out
- * EEH disabled IO BARs.
+ * ff's which indicates a (very) possible failure.
  *
  * If this macro yields TRUE, the caller relays to eeh_check_failure()
  * which does further tests out of line.
  */
-/* #define EEH_POSSIBLE_ERROR(addr, vaddr, val) ((vaddr) != (addr) && ~(val) == 0 && !IS_EEH_TOKEN_DISABLED(addr)) */
+/* #define EEH_POSSIBLE_IO_ERROR(val) (~(val) == 0) */
+/* #define EEH_POSSIBLE_ERROR(addr, vaddr, val) ((vaddr) != (addr) && EEH_POSSIBLE_IO_ERROR(val) */
 /* This version is rearranged to collect some profiling data */
-#define EEH_POSSIBLE_ERROR(addr, vaddr, val) (~(val) == 0 && (++eeh_total_mmio_ffs, (vaddr) != (addr) && !IS_EEH_TOKEN_DISABLED(addr)))
+#define EEH_POSSIBLE_IO_ERROR(val) (~(val) == 0 && ++eeh_total_mmio_ffs)
+#define EEH_POSSIBLE_ERROR(addr, vaddr, val) (EEH_POSSIBLE_IO_ERROR(val) && (vaddr) != (addr))
 
 /* 
  * MMIO read/write operations with EEH support.
@@ -149,38 +147,56 @@
 	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] */
-}
+/* The I/O macros must handle ISA ports as well as PCI I/O bars.
+ * ISA does not implement EEH and ISA may not exist in the system.
+ * For PCI we check for EEH failures.
+ */
+#define _IO_IS_ISA(port) ((port) < 0x10000)
+#define _IO_HAS_ISA_BUS	(isa_io_base != 0)
 
-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 u8 eeh_inb(unsigned long port) {
+	u8 val;
+	if (_IO_IS_ISA(port) && !_IO_HAS_ISA_BUS)
+		return ~0;
+	val = in_8((u8 *)(port+pci_io_base));
+	if (!_IO_IS_ISA(port) && EEH_POSSIBLE_IO_ERROR(val))
+		return eeh_check_failure((void*)(port+pci_io_base), val);
+	return val;
 }
 
-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_outb(u8 val, unsigned long port) {
+	if (!_IO_IS_ISA(port) || _IO_HAS_ISA_BUS)
+		return out_8((u8 *)(port+pci_io_base), val);
 }
 
-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 u16 eeh_inw(unsigned long port) {
+	u16 val;
+	if (_IO_IS_ISA(port) && !_IO_HAS_ISA_BUS)
+		return ~0;
+	val = in_le16((u16 *)(port+pci_io_base));
+	if (!_IO_IS_ISA(port) && EEH_POSSIBLE_IO_ERROR(val))
+		return eeh_check_failure((void*)(port+pci_io_base), val);
+	return val;
 }
 
-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_outw(u16 val, unsigned long port) {
+	if (!_IO_IS_ISA(port) || _IO_HAS_ISA_BUS)
+		return out_le16((u16 *)(port+pci_io_base), val);
 }
 
-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);
+static inline u32 eeh_inl(unsigned long port) {
+	u32 val;
+	if (_IO_IS_ISA(port) && !_IO_HAS_ISA_BUS)
+		return ~0;
+	val = in_le32((u32 *)(port+pci_io_base));
+	if (!_IO_IS_ISA(port) && EEH_POSSIBLE_IO_ERROR(val))
+		return eeh_check_failure((void*)(port+pci_io_base), val);
+	return val;
 }
 
+static inline void eeh_outl(u32 val, unsigned long port) {
+	if (!_IO_IS_ISA(port) || _IO_HAS_ISA_BUS)
+		return out_le32((u32 *)(port+pci_io_base), val);
+}
 
 #endif /* _EEH_H */
diff -urN linux-2.4.21-pre3/include/asm-ppc64/elf.h linux-2.4.21-pre4/include/asm-ppc64/elf.h
--- linux-2.4.21-pre3/include/asm-ppc64/elf.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.21-pre4/include/asm-ppc64/elf.h	Tue Jan 28 19:44:31 2003
@@ -43,6 +43,8 @@
 typedef double elf_fpreg_t;
 typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
 
+#ifdef __KERNEL__
+
 /*
  * This is used to ensure we don't load something for the wrong architecture.
  */
@@ -87,15 +89,14 @@
 #define ELF_PLATFORM	(NULL)
 
 
-#define ELF_PLAT_INIT(_r, load_addr)	do { \
+#define ELF_PLAT_INIT(_r, interp_load_addr)	do { \
 	memset(_r->gpr, 0, sizeof(_r->gpr)); \
 	_r->ctr = _r->link = _r->xer = _r->ccr = 0; \
-	_r->gpr[2] = load_addr; \
+	_r->gpr[2] = interp_load_addr; \
 } while (0)
 
 
 
-#ifdef __KERNEL__
 #define SET_PERSONALITY(ex, ibcs2)				\
 do {	if ((ex).e_ident[EI_CLASS] == ELFCLASS32)		\
 		current->thread.flags |= PPC_FLAG_32BIT;	\
@@ -106,7 +107,6 @@
 	else if (current->personality != PER_LINUX32)		\
 		set_personality(PER_LINUX);			\
 } while (0)
-#endif
 
 /*
  * We need to put in some extra aux table entries to tell glibc what
@@ -146,4 +146,5 @@
 	NEW_AUX_ENT(1, AT_IGNOREPPC, AT_IGNOREPPC);			\
  } while (0)
 
+#endif /* __KERNEL__ */
 #endif /* __PPC64_ELF_H */
diff -urN linux-2.4.21-pre3/include/asm-ppc64/hvcall.h linux-2.4.21-pre4/include/asm-ppc64/hvcall.h
--- linux-2.4.21-pre3/include/asm-ppc64/hvcall.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-ppc64/hvcall.h	Tue Jan 28 19:44:31 2003
@@ -57,6 +57,7 @@
 #define H_IPI			0x6c
 #define H_IPOLL			0x70
 #define H_XIRR			0x74
+#define H_PERFMON		0x7c
 
 #define HSC			".long 0x44000022\n"
 #define H_ENTER_r3		"li	3, 0x08\n"
diff -urN linux-2.4.21-pre3/include/asm-ppc64/hw_irq.h linux-2.4.21-pre4/include/asm-ppc64/hw_irq.h
--- linux-2.4.21-pre3/include/asm-ppc64/hw_irq.h	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/include/asm-ppc64/hw_irq.h	Tue Jan 28 19:44:31 2003
@@ -36,7 +36,10 @@
 #else
 
 #define __save_flags(flags)	((flags) = mfmsr())
-#define __restore_flags(flags)	mtmsrd(flags)
+#define __restore_flags(flags) do { \
+	__asm__ __volatile__("": : :"memory"); \
+	mtmsrd(flags); \
+} while(0)
 
 static inline void __cli(void)
 {
diff -urN linux-2.4.21-pre3/include/asm-ppc64/iSeries/HvCall.h linux-2.4.21-pre4/include/asm-ppc64/iSeries/HvCall.h
--- linux-2.4.21-pre3/include/asm-ppc64/iSeries/HvCall.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-ppc64/iSeries/HvCall.h	Tue Jan 28 19:44:31 2003
@@ -130,6 +130,7 @@
 #define HvCallBaseRouter28				HvCallBase + 28
 #define HvCallBaseRouter29				HvCallBase + 29
 #define HvCallBaseRouter30				HvCallBase + 30
+#define HvCallBaseSetDebugBus 				HvCallBase + 31
 
 #define HvCallCcSetDABR  				HvCallCc + 7
 
@@ -205,5 +206,10 @@
 	HvCall1(HvCallCcSetDABR, val);
 }
 
+static inline void HvCall_setDebugBus(unsigned long val)
+{
+	HvCall1(HvCallBaseSetDebugBus, val);
+}
+
 #endif // _HVCALL_H
 
diff -urN linux-2.4.21-pre3/include/asm-ppc64/ide.h linux-2.4.21-pre4/include/asm-ppc64/ide.h
--- linux-2.4.21-pre3/include/asm-ppc64/ide.h	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/include/asm-ppc64/ide.h	Tue Jan 28 19:44:31 2003
@@ -22,9 +22,6 @@
 #define MAX_HWIFS	4
 #endif
 
-void ppc64_ide_fix_driveid(struct hd_driveid *id);
-#define ide_fix_driveid(id)	ppc64_ide_fix_driveid((id))
-
 static __inline__ int ide_default_irq(ide_ioreg_t base) { return 0; }
 static __inline__ ide_ioreg_t ide_default_io_base(int index) { return 0; }
 
@@ -51,6 +48,8 @@
 {
 }
 
+#include <asm-generic/ide_iops.h>
+
 #endif /* __KERNEL__ */
 
 #endif /* __ASMPPC64_IDE_H */
diff -urN linux-2.4.21-pre3/include/asm-ppc64/io.h linux-2.4.21-pre4/include/asm-ppc64/io.h
--- linux-2.4.21-pre3/include/asm-ppc64/io.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-ppc64/io.h	Tue Jan 28 19:44:31 2003
@@ -50,7 +50,6 @@
 #define outw(data,addr)		writew(data,((unsigned long)(addr)))  
 #define outl(data,addr)		writel(data,((unsigned long)(addr)))
 #else
-#define IS_MAPPED_VADDR(port)	((unsigned long)(port) >> 60UL)
 #define readb(addr)		eeh_readb((void*)(addr))  
 #define readw(addr)		eeh_readw((void*)(addr))  
 #define readl(addr)		eeh_readl((void*)(addr))
@@ -60,26 +59,36 @@
 #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)
-#define outb(val, port)		_outb(val, (unsigned long)port)
-#define inw(port)		_inw((unsigned long)port)
-#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)
+#define inb(port)		eeh_inb((unsigned long)port)
+#define outb(val, port)		eeh_outb(val, (unsigned long)port)
+#define inw(port)		eeh_inw((unsigned long)port)
+#define outw(val, port)		eeh_outw(val, (unsigned long)port)
+#define inl(port)		eeh_inl((unsigned long)port)
+#define outl(val, port)		eeh_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))
+#define insb(port, buf, ns)	_insb((u8 *)((port)+pci_io_base), (buf), (ns))
+#define outsb(port, buf, ns)	_outsb((u8 *)((port)+pci_io_base), (buf), (ns))
+#define insw(port, buf, ns)	_insw_ns((u16 *)((port)+pci_io_base), (buf), (ns))
+#define outsw(port, buf, ns)	_outsw_ns((u16 *)((port)+pci_io_base), (buf), (ns))
+#define insl(port, buf, nl)	_insl_ns((u32 *)((port)+pci_io_base), (buf), (nl))
+#define outsl(port, buf, nl)	_outsl_ns((u32 *)((port)+pci_io_base), (buf), (nl))
 #endif
 
+extern void _insb(volatile u8 *port, void *buf, int ns);
+extern void _outsb(volatile u8 *port, const void *buf, int ns);
+extern void _insw(volatile u16 *port, void *buf, int ns);
+extern void _outsw(volatile u16 *port, const void *buf, int ns);
+extern void _insl(volatile u32 *port, void *buf, int nl);
+extern void _outsl(volatile u32 *port, const void *buf, int nl);
+extern void _insw_ns(volatile u16 *port, void *buf, int ns);
+extern void _outsw_ns(volatile u16 *port, const void *buf, int ns);
+extern void _insl_ns(volatile u32 *port, void *buf, int nl);
+extern void _outsl_ns(volatile u32 *port, const void *buf, int nl);
 
 /*
  * output pause versions need a delay at least for the
@@ -92,27 +101,15 @@
 #define inl_p(port)             inl(port)
 #define outl_p(val, port)       (udelay(1), outl((val, (port)))
 
-
-extern void _insb(volatile u8 *port, void *buf, int ns);
-extern void _outsb(volatile u8 *port, const void *buf, int ns);
-extern void _insw(volatile u16 *port, void *buf, int ns);
-extern void _outsw(volatile u16 *port, const void *buf, int ns);
-extern void _insl(volatile u32 *port, void *buf, int nl);
-extern void _outsl(volatile u32 *port, const void *buf, int nl);
-extern void _insw_ns(volatile u16 *port, void *buf, int ns);
-extern void _outsw_ns(volatile u16 *port, const void *buf, int ns);
-extern void _insl_ns(volatile u32 *port, void *buf, int nl);
-extern void _outsl_ns(volatile u32 *port, const void *buf, int nl);
-
 /*
  * The *_ns versions below don't do byte-swapping.
  * Neither do the standard versions now, these are just here
  * for older code.
  */
-#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 insw_ns(port, buf, ns)	_insw_ns((u16 *)((port)+pci_io_base), (buf), (ns))
+#define outsw_ns(port, buf, ns)	_outsw_ns((u16 *)((port)+pci_io_base), (buf), (ns))
+#define insl_ns(port, buf, nl)	_insl_ns((u32 *)((port)+pci_io_base), (buf), (nl))
+#define outsl_ns(port, buf, nl)	_outsl_ns((u32 *)((port)+pci_io_base), (buf), (nl))
 
 
 #define IO_SPACE_LIMIT ~(0UL)
@@ -151,11 +148,12 @@
 #endif
 	return (void *) __va(address);
 }
- 
+
 /*
  * Change "struct page" to physical address.
  */
-#define page_to_phys(page)	((page - mem_map) << PAGE_SHIFT)
+#define page_to_phys(page)      ((page - mem_map) << PAGE_SHIFT)
+
 
 #endif /* __KERNEL__ */
 
@@ -248,49 +246,6 @@
 
 #ifndef CONFIG_PPC_ISERIES 
 #include <asm/eeh.h>
-
-static inline u8 _inb(unsigned long port) {
-	if (IS_MAPPED_VADDR(port))
-		return readb((void *)port);
-	else if (_IO_BASE)
-		return in_8((u8 *)((port)+_IO_BASE));
-	else
-		return 0xff;
-}
-static inline void _outb(u8 val, unsigned long port) {
-	if (IS_MAPPED_VADDR(port))
-		return writeb(val, (void *)port);
-	else if (_IO_BASE)
-		out_8((u8 *)((port)+_IO_BASE), val);
-}
-static inline u16 _inw(unsigned long port) {
-	if (IS_MAPPED_VADDR(port))
-		return readw((void *)port);
-	else if (_IO_BASE)
-		return in_le16((u16 *)((port)+_IO_BASE));
-	else
-		return 0xffff;
-}
-static inline void _outw(u16 val, unsigned long port) {
-	if (IS_MAPPED_VADDR(port))
-		return writew(val, (void *)port);
-	else if (_IO_BASE)
-		out_le16((u16 *)((port)+_IO_BASE), val);
-}
-static inline u32 _inl(unsigned long port) {
-	if (IS_MAPPED_VADDR(port))
-		return readl((void *)port);
-	else if (_IO_BASE)
-		return in_le32((u32 *)((port)+_IO_BASE));
-	else
-		return 0xffffffff;
-}
-static inline void _outl(u32 val, unsigned long port) {
-	if (IS_MAPPED_VADDR(port))
-		return writel(val, (void *)port);
-	else if (_IO_BASE)
-		out_le32((u32 *)((port)+_IO_BASE), val);
-}
 #endif
 
 #ifdef __KERNEL__
diff -urN linux-2.4.21-pre3/include/asm-ppc64/ipc.h linux-2.4.21-pre4/include/asm-ppc64/ipc.h
--- linux-2.4.21-pre3/include/asm-ppc64/ipc.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.21-pre4/include/asm-ppc64/ipc.h	Tue Jan 28 19:44:31 2003
@@ -4,7 +4,7 @@
 /* 
  * These are used to wrap system calls on PowerPC.
  *
- * See arch/ppc/kernel/syscalls.c for ugly details..
+ * See arch/ppc64/kernel/syscalls.c for ugly details..
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -12,8 +12,8 @@
  * 2 of the License, or (at your option) any later version.
  */
 struct ipc_kludge {
-	u32 msgp;
-	s32 msgtyp;
+	struct msgbuf *msgp;
+	long msgtyp;
 };
 
 #define SEMOP		 1
diff -urN linux-2.4.21-pre3/include/asm-ppc64/kdb.h linux-2.4.21-pre4/include/asm-ppc64/kdb.h
--- linux-2.4.21-pre3/include/asm-ppc64/kdb.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/include/asm-ppc64/kdb.h	Tue Jan 28 19:44:31 2003
@@ -0,0 +1,72 @@
+/*
+ * Minimalist Kernel Debugger
+ *
+ * Copyright (C) 1999 Silicon Graphics, Inc.
+ * Copyright (C) Scott Lurndal (slurn@engr.sgi.com)
+ * Copyright (C) Scott Foehner (sfoehner@engr.sgi.com)
+ * Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com)
+ *
+ * See the file LIA-COPYRIGHT for additional information.
+ *
+ * Written March 1999 by Scott Lurndal at Silicon Graphics, Inc.
+ *
+ * Modifications from:
+ *      Richard Bass                    1999/07/20
+ *              Many bug fixes and enhancements.
+ *      Scott Foehner
+ *              Port to ia64
+ *	Scott Lurndal			1999/12/12
+ *		v1.0 restructuring.
+ */
+#if !defined(_ASM_KDB_H)
+#define _ASM_KDB_H
+	/*
+	 * KDB_ENTER() is a macro which causes entry into the kernel
+	 * debugger from any point in the kernel code stream.  If it 
+	 * is intended to be used from interrupt level, it must  use
+	 * a non-maskable entry method.
+	 */
+#define KDB_ENTER()	asm("\ttrap\n")
+
+	/*
+	 * Define the exception frame for this architecture
+	 */
+struct pt_regs;
+typedef struct pt_regs	*kdb_eframe_t;
+
+	/*
+	 * Needed for exported symbols.
+	 */
+typedef unsigned long kdb_machreg_t;
+
+#define kdb_machreg_fmt		"0x%016lx"
+#define kdb_machreg_fmt0	"0x%016lx"
+#define kdb_bfd_vma_fmt		"0x%016lx"
+#define kdb_bfd_vma_fmt0	"0x%016lx"
+#define kdb_elfw_addr_fmt	"0x%016lx"
+#define kdb_elfw_addr_fmt0	"0x%016lx"
+
+	/*
+	 * Per cpu arch specific kdb state.  Must be in range 0xff000000.
+	 */
+#define KDB_STATE_A_IF		0x01000000	/* Saved IF flag */
+
+	 /*
+	  * Interface from kernel trap handling code to kernel debugger.
+	  */
+extern int	kdba_callback_die(struct pt_regs *, int, long, void*);
+extern int	kdba_callback_bp(struct pt_regs *, int, long, void*);
+extern int	kdba_callback_debug(struct pt_regs *, int, long, void *);
+
+#include <linux/types.h>
+extern int kdba_putarea_size(unsigned long to_xxx, void *from, size_t size);
+extern int kdba_getarea_size(void *to, unsigned long from_xxx, size_t size);
+
+static inline int
+kdba_verify_rw(unsigned long addr, size_t size)
+{
+	unsigned char data[size];
+	return(kdba_getarea_size(data, addr, size) || kdba_putarea_size(addr, data, size));
+}
+
+#endif	/* ASM_KDB_H */
diff -urN linux-2.4.21-pre3/include/asm-ppc64/kdbprivate.h linux-2.4.21-pre4/include/asm-ppc64/kdbprivate.h
--- linux-2.4.21-pre3/include/asm-ppc64/kdbprivate.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/include/asm-ppc64/kdbprivate.h	Tue Jan 28 19:44:31 2003
@@ -0,0 +1,117 @@
+/*
+ * Minimalist Kernel Debugger
+ *
+ * Copyright (C) 1999 Silicon Graphics, Inc.
+ * Copyright (C) Scott Lurndal (slurn@engr.sgi.com)
+ * Copyright (C) Scott Foehner (sfoehner@engr.sgi.com)
+ * Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com)
+ *
+ * See the file LIA-COPYRIGHT for additional information.
+ *
+ * Written March 1999 by Scott Lurndal at Silicon Graphics, Inc.
+ *
+ * Modifications from:
+ *      Richard Bass                    1999/07/20
+ *              Many bug fixes and enhancements.
+ *      Scott Foehner
+ *              Port to ia64
+ *	Scott Lurndal			1999/12/12
+ *		v1.0 restructuring.
+ *	Keith Owens			2000/05/23
+ *		KDB v1.2
+ */
+#if !defined(_ASM_KDBPRIVATE_H)
+#define _ASM_KDBPRIVATE_H
+
+typedef unsigned char kdb_machinst_t;
+
+	/*
+	 * KDB_MAXBPT describes the total number of breakpoints
+	 * supported by this architecure.  
+	 */
+#define KDB_MAXBPT	16
+	/*
+	 * KDB_MAXHARDBPT describes the total number of hardware
+	 * breakpoint registers that exist.
+	 */
+#define KDB_MAXHARDBPT	 4
+        /*
+         * Provide space for KDB_MAX_COMMANDS commands.
+         */
+#define KDB_MAX_COMMANDS        125
+
+	/*
+	 * Platform specific environment entries
+	 */
+#define KDB_PLATFORM_ENV	"IDMODE=PPC", "BYTESPERWORD=8", "IDCOUNT=16"
+
+	/*
+	 * Define the direction that the stack grows
+	 */
+#define KDB_STACK_DIRECTION	-1	/* Stack grows down */
+
+	/*
+	 * Support for ia32 debug registers 
+	 */
+typedef struct _kdbhard_bp {
+	kdb_machreg_t	bph_reg;	/* Register this breakpoint uses */
+
+	unsigned int	bph_free:1;	/* Register available for use */
+	unsigned int	bph_data:1;	/* Data Access breakpoint */
+
+	unsigned int	bph_write:1;	/* Write Data breakpoint */
+	unsigned int	bph_mode:2;	/* 0=inst, 1=write, 2=io, 3=read */
+	unsigned int	bph_length:2;	/* 0=1, 1=2, 2=BAD, 3=4 (bytes) */
+} kdbhard_bp_t;
+
+extern kdbhard_bp_t	kdb_hardbreaks[/* KDB_MAXHARDBPT */];
+
+#define KDB_HAVE_LONGJMP 
+#ifdef KDB_HAVE_LONGJMP
+typedef struct __kdb_jmp_buf {
+	unsigned int regs[100];
+} kdb_jmp_buf;
+extern int kdb_setjmp(kdb_jmp_buf *);
+extern void kdba_longjmp(kdb_jmp_buf *, int);
+extern kdb_jmp_buf  kdbjmpbuf[];
+#endif	/* KDB_HAVE_LONGJMP */
+
+
+/*
+ A traceback table typically follows each function.
+ The find_tb_table() func will fill in this struct.  Note that the struct
+ is not an exact match with the encoded table defined by the ABI.  It is
+ defined here more for programming convenience.
+ */
+typedef struct {
+    unsigned long	flags;		/* flags: */
+#define KDBTBTAB_FLAGSGLOBALLINK	(1L<<47)
+#define KDBTBTAB_FLAGSISEPROL		(1L<<46)
+#define KDBTBTAB_FLAGSHASTBOFF		(1L<<45)
+#define KDBTBTAB_FLAGSINTPROC		(1L<<44)
+#define KDBTBTAB_FLAGSHASCTL		(1L<<43)
+#define KDBTBTAB_FLAGSTOCLESS		(1L<<42)
+#define KDBTBTAB_FLAGSFPPRESENT		(1L<<41)
+#define KDBTBTAB_FLAGSNAMEPRESENT	(1L<<38)
+#define KDBTBTAB_FLAGSUSESALLOCA	(1L<<37)
+#define KDBTBTAB_FLAGSSAVESCR		(1L<<33)
+#define KDBTBTAB_FLAGSSAVESLR		(1L<<32)
+#define KDBTBTAB_FLAGSSTORESBC		(1L<<31)
+#define KDBTBTAB_FLAGSFIXUP		(1L<<30)
+#define KDBTBTAB_FLAGSPARMSONSTK	(1L<<0)
+    unsigned char	fp_saved;	/* num fp regs saved f(32-n)..f31 */
+    unsigned char	gpr_saved;	/* num gpr's saved */
+    unsigned char	fixedparms;	/* num fixed point parms */
+    unsigned char	floatparms;	/* num float parms */
+    unsigned char	parminfo[32];	/* types of args.  null terminated */
+#define KDBTBTAB_PARMFIXED 1
+#define KDBTBTAB_PARMSFLOAT 2
+#define KDBTBTAB_PARMDFLOAT 3
+    unsigned int	tb_offset;	/* offset from start of func */
+    unsigned long	funcstart;	/* addr of start of function */
+    char		name[64];	/* name of function (null terminated)*/
+    kdb_symtab_t	symtab;		/* fake symtab entry */
+} kdbtbtable_t;
+int kdba_find_tb_table(kdb_machreg_t eip, kdbtbtable_t *tab);
+
+#endif	/* !_ASM_KDBPRIVATE_H */
diff -urN linux-2.4.21-pre3/include/asm-ppc64/lmb.h linux-2.4.21-pre4/include/asm-ppc64/lmb.h
--- linux-2.4.21-pre3/include/asm-ppc64/lmb.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-ppc64/lmb.h	Tue Jan 28 19:44:31 2003
@@ -13,6 +13,7 @@
  * 2 of the License, or (at your option) any later version.
  */
 
+#include <linux/config.h>
 #include <asm/prom.h>
 
 extern unsigned long reloc_offset(void);
diff -urN linux-2.4.21-pre3/include/asm-ppc64/memory.h linux-2.4.21-pre4/include/asm-ppc64/memory.h
--- linux-2.4.21-pre3/include/asm-ppc64/memory.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.21-pre4/include/asm-ppc64/memory.h	Tue Jan 28 19:44:31 2003
@@ -41,4 +41,24 @@
 #define isync_on_smp()	__asm__ __volatile__("": : :"memory")
 #endif
 
+/* Macros for adjusting thread priority (hardware multi-threading) */
+
+#if defined(CONFIG_PPC_ISERIES) || defined(CONFIG_HMT)
+#define HMT_low()	asm volatile("or 1,1,1		# low priority")
+#define HMT_medium()	asm volatile("or 2,2,2		# medium priority")
+#define HMT_high()	asm volatile("or 3,3,3		# high priority")
+
+#define HMT_LOW		"\tor	1,1,1		# low priority\n"
+#define HMT_MEDIUM	"\tor	2,2,2		# medium priority\n"
+#define HMT_HIGH	"\tor	3,3,3		# high priority\n"
+#else
+#define HMT_low()	do { } while(0)
+#define HMT_medium()	do { } while(0)
+#define HMT_high()	do { } while(0)
+
+#define HMT_LOW
+#define HMT_MEDIUM
+#define HMT_LOW
+#endif
+
 #endif
diff -urN linux-2.4.21-pre3/include/asm-ppc64/mmu.h linux-2.4.21-pre4/include/asm-ppc64/mmu.h
--- linux-2.4.21-pre3/include/asm-ppc64/mmu.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-ppc64/mmu.h	Tue Jan 28 19:44:31 2003
@@ -168,17 +168,23 @@
 #define PP_RWRW 2	/* Supervisor read/write, User read/write */
 #define PP_RXRX 3	/* Supervisor read,       User read */
 
-
 typedef struct {
 	HPTE *		htab;
 	unsigned long	htab_num_ptegs;
 	unsigned long	htab_hash_mask;
 	unsigned long	next_round_robin;
 	unsigned long   last_kernel_address;
+	unsigned long   htab_lock_shift;
 } HTAB;
 
 extern HTAB htab_data;
 
+#include <linux/cache.h>
+#include <asm/spinlock.h>
+typedef struct {
+	spinlock_t lock;
+} ____cacheline_aligned hash_table_lock_t;
+
 void invalidate_hpte( unsigned long slot );
 long select_hpte_slot( unsigned long vpn );
 void create_valid_hpte( unsigned long slot, unsigned long vpn,
@@ -227,12 +233,18 @@
 		asm volatile("clrldi	%0,%0,16\n\
 			      tlbie	%0,0" : : "r"(va) : "memory");
 	}
-
 	asm volatile("eieio; tlbsync; ptesync": : :"memory");
 }
  
 #endif /* __ASSEMBLY__ */
 
+/*
+ * Location of cpu0's segment table
+ */
+#define STAB0_PAGE	0x9
+#define STAB0_PHYS_ADDR	(STAB0_PAGE<<PAGE_SHIFT)
+#define STAB0_VIRT_ADDR	(KERNELBASE+STAB0_PHYS_ADDR)
+
 /* Block size masks */
 #define BL_128K	0x000
 #define BL_256K 0x001
diff -urN linux-2.4.21-pre3/include/asm-ppc64/mmu_context.h linux-2.4.21-pre4/include/asm-ppc64/mmu_context.h
--- linux-2.4.21-pre3/include/asm-ppc64/mmu_context.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.21-pre4/include/asm-ppc64/mmu_context.h	Tue Jan 28 19:44:31 2003
@@ -67,11 +67,12 @@
 init_new_context(struct task_struct *tsk, struct mm_struct *mm)
 {
 	long head, size;
+	unsigned long flags;
 
-	spin_lock( &mmu_context_queue.lock );
+	spin_lock_irqsave(&mmu_context_queue.lock, flags);
 
 	if ( (size = mmu_context_queue.size) <= 0 ) {
-		spin_unlock( &mmu_context_queue.lock );
+		spin_unlock_irqrestore(&mmu_context_queue.lock, flags);
 		return -ENOMEM;
 	}
 
@@ -82,7 +83,7 @@
 	mmu_context_queue.head = head;
 	mmu_context_queue.size = size-1;
 
-	spin_unlock( &mmu_context_queue.lock );
+	spin_unlock_irqrestore(&mmu_context_queue.lock, flags);
 
 	return 0;
 }
@@ -94,11 +95,12 @@
 destroy_context(struct mm_struct *mm)
 {
 	long index, size = mmu_context_queue.size;
+	unsigned long flags;
 
-	spin_lock( &mmu_context_queue.lock );
+	spin_lock_irqsave(&mmu_context_queue.lock, flags);
 
 	if ( (size = mmu_context_queue.size) >= NUM_USER_CONTEXT ) {
-		spin_unlock( &mmu_context_queue.lock );
+		spin_unlock_irqrestore(&mmu_context_queue.lock, flags);
 		mmu_context_underflow();
 	}
 
@@ -115,9 +117,10 @@
 	mmu_context_queue.size = size+1;
 	mmu_context_queue.elements[index] = mm->context;
 
-	spin_unlock( &mmu_context_queue.lock );
+	spin_unlock_irqrestore(&mmu_context_queue.lock, flags);
 }
 
+extern void flush_stab(void);
 
 /*
  * switch_mm is the entry point called from the architecture independent
@@ -127,8 +130,6 @@
 switch_mm(struct mm_struct *prev, struct mm_struct *next,
 	  struct task_struct *tsk, int cpu)
 {
-	tsk->thread.pgdir = next->pgd;	/* cache the pgdir in the thread 
-					   maybe not needed any more */
 	flush_stab();
 }
 
@@ -136,13 +137,8 @@
  * After we have set current->mm to a new value, this activates
  * the context for the new mm so we see the new mappings.
  */
-static inline void
-activate_mm(struct mm_struct *active_mm, struct mm_struct *mm)
-{
-	current->thread.pgdir = mm->pgd;
-	flush_stab();
-}
-
+#define activate_mm(active_mm, mm) \
+	switch_mm(active_mm, mm, current, smp_processor_id());
 
 #define VSID_RANDOMIZER 42470972311
 #define VSID_MASK	0xfffffffff
diff -urN linux-2.4.21-pre3/include/asm-ppc64/naca.h linux-2.4.21-pre4/include/asm-ppc64/naca.h
--- linux-2.4.21-pre3/include/asm-ppc64/naca.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-ppc64/naca.h	Tue Jan 28 19:44:31 2003
@@ -11,6 +11,7 @@
  */
 
 #include <asm/types.h>
+#include <asm/systemcfg.h>
 
 struct naca_struct {
 	/*==================================================================
@@ -29,47 +30,14 @@
 	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 */
+	void *systemcfg;		/* Pointer to systemcfg data 0x58 */
+	u32 dCacheL1LogLineSize;	/* L1 d-cache line size Log2 0x60 */
+	u32 dCacheL1LinesPerPage;	/* L1 d-cache lines / page   0x64 */
+	u32 iCacheL1LogLineSize;	/* L1 i-cache line size Log2 0x68 */
+	u32 iCacheL1LinesPerPage;	/* L1 i-cache lines / page   0x6c */
+	u64 resv0[2];                   /* Reserved           0x70 - 0x7F */
 };
 
-
 extern struct naca_struct *naca;
 
 #endif /* _NACA_H */
diff -urN linux-2.4.21-pre3/include/asm-ppc64/paca.h linux-2.4.21-pre4/include/asm-ppc64/paca.h
--- linux-2.4.21-pre3/include/asm-ppc64/paca.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-ppc64/paca.h	Tue Jan 28 19:44:31 2003
@@ -131,9 +131,8 @@
  * CACHE_LINE_19 - 20 Profile Data
  *=====================================================================================
  */
-	u32 pmc[12];                    /* Default pmc value		*/	
+	u64 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 */
@@ -144,7 +143,7 @@
 	u8  prof_mode;                  /* */
 	u8  rsvv5b[3];
 	u64 prof_counter;		/*					 */
-	u8  rsvd5c[128-8*6];
+	u8  rsvd5c[256-8*26];
 
 /*=====================================================================================
  * CACHE_LINE_20-30
diff -urN linux-2.4.21-pre3/include/asm-ppc64/page.h linux-2.4.21-pre4/include/asm-ppc64/page.h
--- linux-2.4.21-pre3/include/asm-ppc64/page.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-ppc64/page.h	Tue Jan 28 19:44:31 2003
@@ -14,7 +14,11 @@
 
 /* PAGE_SHIFT determines the page size */
 #define PAGE_SHIFT	12
+#ifndef __ASSEMBLY__
 #define PAGE_SIZE	(1UL << PAGE_SHIFT)
+#else
+# define PAGE_SIZE	(1 << PAGE_SHIFT)
+#endif
 #define PAGE_MASK	(~(PAGE_SIZE-1))
 #define PAGE_OFFSET_MASK (PAGE_SIZE-1)
 
@@ -32,6 +36,7 @@
 #ifdef __KERNEL__
 #ifndef __ASSEMBLY__
 #include <asm/naca.h>
+#include <asm/systemcfg.h>
 
 #define STRICT_MM_TYPECHECKS
 
@@ -57,7 +62,7 @@
 {
 	unsigned long lines, line_size;
 
-	line_size = naca->dCacheL1LineSize; 
+	line_size = systemcfg->dCacheL1LineSize; 
 	lines = naca->dCacheL1LinesPerPage;
 
 	__asm__ __volatile__(
@@ -129,7 +134,7 @@
 /* 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); \
+      kdb(KDB_REASON_CALL, 0, (kdb_eframe_t) 0); \
 } while (0)
 #else
 #define BUG() do { \
@@ -189,9 +194,11 @@
 #define KERNELBASE      PAGE_OFFSET
 #define VMALLOCBASE     0xD000000000000000
 #define IOREGIONBASE    0xE000000000000000
+#define EEHREGIONBASE   0xA000000000000000
 #define BOLTEDBASE      0xB000000000000000
 
 #define IO_REGION_ID       (IOREGIONBASE>>REGION_SHIFT)
+#define EEH_REGION_ID      (EEHREGIONBASE>>REGION_SHIFT)
 #define VMALLOC_REGION_ID  (VMALLOCBASE>>REGION_SHIFT)
 #define KERNEL_REGION_ID   (KERNELBASE>>REGION_SHIFT)
 #define BOLTED_REGION_ID   (BOLTEDBASE>>REGION_SHIFT)
diff -urN linux-2.4.21-pre3/include/asm-ppc64/perfmon.h linux-2.4.21-pre4/include/asm-ppc64/perfmon.h
--- linux-2.4.21-pre3/include/asm-ppc64/perfmon.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-ppc64/perfmon.h	Tue Jan 28 19:44:31 2003
@@ -29,17 +29,23 @@
 	u64 trace_buffer;
 	u64 trace_length;
 	u64 trace_end;
+	u64 timeslice_buffer;
+	u64 timeslice_length;
 	u64 state;
 };
 
 struct pmc_header {
-	int type;
-	int pid;
+	int subcmd;
+	union {
+		int type;
+		int pid;	/* PID to trace */
+		int slice; 	/* Timeslice ID */
+	} vdata;
 	int resv[30];
 };
 
 struct pmc_struct {
-        int pmc[11];
+        unsigned long pmc[11];
 };
 
 struct pmc_info_struct {
@@ -59,29 +65,51 @@
 };
 
 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
+	PMC_CMD_BUFFER       = 1,
+	PMC_CMD_DUMP         = 2,
+	PMC_CMD_DECR_PROFILE = 3,
+	PMC_CMD_PROFILE      = 4,
+	PMC_CMD_TRACE        = 5,
+	PMC_CMD_TIMESLICE    = 6
 };
 
+enum {
+	PMC_SUBCMD_BUFFER_ALLOC         = 1,
+	PMC_SUBCMD_BUFFER_FREE          = 2,
+	PMC_SUBCMD_BUFFER_CLEAR         = 3 
+};
 
-#define	PMC_TRACE_CMD 0xFF
+enum {
+	PMC_SUBCMD_DUMP_COUNTERS        = 1,
+	PMC_SUBCMD_DUMP_HARDWARE        = 2
+};
 
 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
+	PMC_SUBCMD_PROFILE_CYCLE        = 1,
+};
+
+enum {
+	PMC_SUBCMD_TIMESLICE_ENABLE     = 1,
+	PMC_SUBCMD_TIMESLICE_DISABLE    = 2,
+	PMC_SUBCMD_TIMESLICE_SET        = 3
+};
+
+#define	PMC_TRACE_CMD 0xFF
+
+/*
+ * The following types are not used by the kernel; they are put into the
+ * trace as flag records for the user space tools to interpret.
+ */
+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_TIMESLICE      = 7,
+        PMC_TYPE_TIMESLICE_DUMP = 8,
+	PMC_TYPE_END            = 8
 };
 #endif
 
@@ -91,4 +119,5 @@
 #define	PMC_STATE_PROFILE_KERN    0x11
 #define	PMC_STATE_TRACE_KERN      0x20
 #define	PMC_STATE_TRACE_USER      0x21
+#define	PMC_STATE_TIMESLICE       0x40
 
diff -urN linux-2.4.21-pre3/include/asm-ppc64/pgtable.h linux-2.4.21-pre4/include/asm-ppc64/pgtable.h
--- linux-2.4.21-pre3/include/asm-ppc64/pgtable.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-ppc64/pgtable.h	Tue Jan 28 19:44:31 2003
@@ -415,7 +415,11 @@
  */
 #define kern_addr_valid(addr)	(1)
 
-#define io_remap_page_range remap_page_range 
+#ifdef CONFIG_PPC_ISERIES
+#define io_remap_page_range remap_page_range
+#else
+extern int io_remap_page_range(unsigned long from, unsigned long to, unsigned long size, pgprot_t prot);
+#endif
 
 /*
  * No page table caches to initialise
diff -urN linux-2.4.21-pre3/include/asm-ppc64/posix_types.h linux-2.4.21-pre4/include/asm-ppc64/posix_types.h
--- linux-2.4.21-pre3/include/asm-ppc64/posix_types.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.21-pre4/include/asm-ppc64/posix_types.h	Tue Jan 28 19:44:31 2003
@@ -11,19 +11,10 @@
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  */
-#if 0
-# define DRENG_TYPES
-#endif
 
-#ifdef DRENG_TYPES
 typedef unsigned long	__kernel_dev_t;
 typedef unsigned long	__kernel_ino_t;
 typedef unsigned long  	__kernel_nlink_t;
-#else
-typedef unsigned int	__kernel_dev_t;
-typedef unsigned int	__kernel_ino_t;
-typedef unsigned int  	__kernel_nlink_t;
-#endif
 typedef unsigned int	__kernel_mode_t;
 typedef long		__kernel_off_t;
 typedef long long	__kernel_loff_t;
diff -urN linux-2.4.21-pre3/include/asm-ppc64/ppc32.h linux-2.4.21-pre4/include/asm-ppc64/ppc32.h
--- linux-2.4.21-pre3/include/asm-ppc64/ppc32.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.21-pre4/include/asm-ppc64/ppc32.h	Tue Jan 28 19:44:31 2003
@@ -43,25 +43,25 @@
 })
 
 /* These are here to support 32-bit syscalls on a 64-bit kernel. */
-typedef unsigned int           __kernel_size_t32;
-typedef int                    __kernel_ssize_t32;
-typedef int                    __kernel_ptrdiff_t32;
-typedef int                    __kernel_time_t32;
-typedef int                    __kernel_clock_t32;
-typedef int                    __kernel_pid_t32;
-typedef unsigned short         __kernel_ipc_pid_t32;
-typedef unsigned int           __kernel_uid_t32;
-typedef unsigned int           __kernel_gid_t32;
-typedef unsigned int           __kernel_dev_t32;
-typedef unsigned int           __kernel_ino_t32;
-typedef unsigned int           __kernel_mode_t32;
-typedef unsigned int           __kernel_umode_t32;
-typedef short                  __kernel_nlink_t32;
-typedef int                    __kernel_daddr_t32;
-typedef int                    __kernel_off_t32;
-typedef unsigned int           __kernel_caddr_t32;
-typedef int 		       __kernel_loff_t32;
-/* typedef __kernel_fsid_t        __kernel_fsid_t32; */
+typedef unsigned int	__kernel_size_t32;
+typedef int		__kernel_ssize_t32;
+typedef int		__kernel_ptrdiff_t32;
+typedef int		__kernel_time_t32;
+typedef int		__kernel_clock_t32;
+typedef int		__kernel_pid_t32;
+typedef unsigned short	__kernel_ipc_pid_t32;
+typedef unsigned int	__kernel_uid_t32;
+typedef unsigned int	__kernel_gid_t32;
+typedef unsigned int	__kernel_dev_t32;
+typedef unsigned int	__kernel_ino_t32;
+typedef unsigned int	__kernel_mode_t32;
+typedef unsigned int	__kernel_umode_t32;
+typedef short		__kernel_nlink_t32;
+typedef int		__kernel_daddr_t32;
+typedef int		__kernel_off_t32;
+typedef unsigned int	__kernel_caddr_t32;
+typedef int		__kernel_loff_t32;
+typedef int		__kernel_key_t32;
 
 struct statfs32 {
 	int f_type;
@@ -87,12 +87,12 @@
 	int si_code;
 
 	union {
-		int _pad[SI_PAD_SIZE];
+		int _pad[SI_PAD_SIZE32];
 
 		/* kill() */
 		struct {
 			__kernel_pid_t32 _pid;		/* sender's pid */
-			unsigned int _uid;		/* sender's uid */
+			__kernel_uid_t32 _uid;		/* sender's uid */
 		} _kill;
 
 		/* POSIX.1b timers */
@@ -104,14 +104,14 @@
 		/* POSIX.1b signals */
 		struct {
 			__kernel_pid_t32 _pid;		/* sender's pid */
-			unsigned int _uid;		/* sender's uid */
+			__kernel_uid_t32 _uid;		/* sender's uid */
 			sigval_t32 _sigval;
 		} _rt;
 
 		/* SIGCHLD */
 		struct {
 			__kernel_pid_t32 _pid;		/* which child */
-			unsigned int _uid;		/* sender's uid */
+			__kernel_uid_t32 _uid;		/* sender's uid */
 			int _status;			/* exit code */
 			__kernel_clock_t32 _utime;
 			__kernel_clock_t32 _stime;
@@ -119,8 +119,7 @@
 
 		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGEMT */
 		struct {
-			u32 _addr; /* faulting insn/memory ref. */
-			int _trapno;
+			unsigned int _addr; /* faulting insn/memory ref. */
 		} _sigfault;
 
 		/* SIGPOLL */
@@ -136,10 +135,10 @@
 
 typedef unsigned int __old_sigset_t32;
 struct __old_sigaction32 {
-	unsigned		sa_handler;
+	unsigned int		sa_handler;
 	__old_sigset_t32  	sa_mask;
 	unsigned int    	sa_flags;
-	unsigned		sa_restorer;     /* not used by Linux/SPARC yet */
+	unsigned int		sa_restorer;     /* not used by Linux/SPARC yet */
 };
 
 
@@ -153,8 +152,7 @@
 } sigset32_t;
 
 struct sigaction32 {
-       unsigned int  sa_handler;	/* Really a pointer, but need to deal 
-					     with 32 bits */
+       unsigned int  sa_handler;	/* Really a pointer, but need to deal with 32 bits */
        unsigned int sa_flags;
        unsigned int sa_restorer;	/* Another 32 bit pointer */
        sigset32_t sa_mask;		/* A 32 bit mask */
@@ -212,7 +210,7 @@
 	unsigned int   st_ctime;
 };
 
-struct sigcontext32_struct {
+struct sigcontext32 {
 	unsigned int	_unused[4];
 	int		signal;
 	unsigned int	handler;
@@ -224,9 +222,36 @@
 	unsigned int	  uc_flags;
 	unsigned int 	  uc_link;
 	stack_32_t	  uc_stack;
-	struct sigcontext32_struct uc_mcontext;
+	struct sigcontext32 uc_mcontext;
 	sigset_t	  uc_sigmask;	/* mask last for extensibility */
 };
 
+struct ipc_kludge_32 {
+	unsigned int msgp;
+	int msgtyp;
+};
+
+struct ipc_perm32 {
+        __kernel_key_t32  key;
+        __kernel_uid_t32  uid;
+        __kernel_gid_t32  gid;
+        __kernel_uid_t32  cuid;
+        __kernel_gid_t32  cgid;
+        __kernel_mode_t32 mode; 
+        unsigned short  seq;
+};
+
+struct ipc64_perm32 {
+	__kernel_key_t32 key;
+	__kernel_uid_t32 uid;
+	__kernel_gid_t32 gid;
+	__kernel_uid_t32 cuid;
+	__kernel_gid_t32 cgid;
+	__kernel_mode_t32 mode;
+	unsigned int	seq;
+	unsigned int	__pad1;
+	unsigned long	__unused1;
+	unsigned long	__unused2;
+};
 
 #endif  /* _PPC64_PPC32_H */
diff -urN linux-2.4.21-pre3/include/asm-ppc64/ppcdebug.h linux-2.4.21-pre4/include/asm-ppc64/ppcdebug.h
--- linux-2.4.21-pre3/include/asm-ppc64/ppcdebug.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-ppc64/ppcdebug.h	Tue Jan 28 19:44:31 2003
@@ -29,41 +29,45 @@
  * code.  They must be set statically, any attempt to change them dynamically
  * would be a very bad idea.
  */
-#define PPCDBG_MMINIT        PPCDBG_BITVAL(0)
-#define PPCDBG_MM            PPCDBG_BITVAL(1)
-#define PPCDBG_SYS32         PPCDBG_BITVAL(2)
-#define PPCDBG_SYS32NI       PPCDBG_BITVAL(3)
-#define PPCDBG_SYS32X	     PPCDBG_BITVAL(4)
-#define PPCDBG_SYS32M	     PPCDBG_BITVAL(5)
-#define PPCDBG_SYS64         PPCDBG_BITVAL(6)
-#define PPCDBG_SYS64NI       PPCDBG_BITVAL(7)
-#define PPCDBG_SYS64X	     PPCDBG_BITVAL(8)
-#define PPCDBG_SIGNAL        PPCDBG_BITVAL(9)
-#define PPCDBG_SIGNALXMON    PPCDBG_BITVAL(10)
-#define PPCDBG_BINFMT32      PPCDBG_BITVAL(11)
-#define PPCDBG_BINFMT64      PPCDBG_BITVAL(12)
-#define PPCDBG_BINFMTXMON    PPCDBG_BITVAL(13)
-#define PPCDBG_BINFMT_32ADDR PPCDBG_BITVAL(14)
-#define PPCDBG_ALIGNFIXUP    PPCDBG_BITVAL(15)
-#define PPCDBG_TCEINIT       PPCDBG_BITVAL(16)
-#define PPCDBG_TCE           PPCDBG_BITVAL(17)
-#define PPCDBG_PHBINIT       PPCDBG_BITVAL(18)
-#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)
-#define PPCDBG_ALL           (0xffffffffUL)
-
-/* The default initial value for the debug switch */
-#define PPC_DEBUG_DEFAULT    0 
-/* #define PPC_DEBUG_DEFAULT    PPCDBG_ALL        */
+#define PPCDBG_MMINIT		PPCDBG_BITVAL(0)
+#define PPCDBG_MM		PPCDBG_BITVAL(1)
+#define PPCDBG_SYS32		PPCDBG_BITVAL(2)
+#define PPCDBG_SYS32NI		PPCDBG_BITVAL(3)
+#define PPCDBG_SYS32X		PPCDBG_BITVAL(4)
+#define PPCDBG_SYS32M		PPCDBG_BITVAL(5)
+#define PPCDBG_SYS64		PPCDBG_BITVAL(6)
+#define PPCDBG_SYS64NI		PPCDBG_BITVAL(7)
+#define PPCDBG_SYS64X		PPCDBG_BITVAL(8)
+#define PPCDBG_SIGNAL		PPCDBG_BITVAL(9)
+#define PPCDBG_SIGNAL64		PPCDBG_BITVAL(10)
+#define PPCDBG_SIGNALXMON	PPCDBG_BITVAL(11)
+#define PPCDBG_BINFMT32		PPCDBG_BITVAL(12)
+#define PPCDBG_BINFMT64		PPCDBG_BITVAL(13)
+#define PPCDBG_BINFMTXMON	PPCDBG_BITVAL(14)
+#define PPCDBG_BINFMT_32ADDR	PPCDBG_BITVAL(15)
+#define PPCDBG_ALIGNFIXUP	PPCDBG_BITVAL(16)
+#define PPCDBG_TCEINIT		PPCDBG_BITVAL(17)
+#define PPCDBG_TCE		PPCDBG_BITVAL(18)
+#define PPCDBG_PHBINIT		PPCDBG_BITVAL(19)
+#define PPCDBG_SMP		PPCDBG_BITVAL(20)
+#define PPCDBG_BOOT		PPCDBG_BITVAL(21)
+#define PPCDBG_BUSWALK		PPCDBG_BITVAL(22)
+#define PPCDBG_PROM		PPCDBG_BITVAL(23)
+#define PPCDBG_RTAS		PPCDBG_BITVAL(24)
+#define PPCDBG_HTABSTRESS	PPCDBG_BITVAL(62)
+#define PPCDBG_HTABSIZE		PPCDBG_BITVAL(63)
+#define PPCDBG_NONE		(0UL)
+#define PPCDBG_ALL		(0xffffffffUL)
 
 #define PPCDBG_NUM_FLAGS     64
 
+/* The default initial value for the debug switch */
+#if 0
+# define PPC_DEBUG_DEFAULT	PPCDBG_ALL
+#else
+# define PPC_DEBUG_DEFAULT	PPCDBG_NONE 
+#endif
+
 #ifdef WANT_PPCDBG_TAB
 /* A table of debug switch names to allow name lookup in xmon 
  * (and whoever else wants it.
@@ -73,7 +77,7 @@
 	"mminit", 	"mm",
 	"syscall32", 	"syscall32_ni", "syscall32x",	"syscall32m",
 	"syscall64", 	"syscall64_ni", "syscall64x",
-	"signal",	"signal_xmon",
+	"signal",	"signal64",	"signal_xmon",
 	"binfmt32",	"binfmt64",	"binfmt_xmon",	"binfmt_32addr",
 	"alignfixup",   "tceinit",      "tce",          "phb_init",     
 	"smp",          "boot",         "buswalk",	"prom",
@@ -102,6 +106,7 @@
 #ifdef CONFIG_KDB
 #include <linux/kdb.h>
 #define PPCDBG_ENTER_DEBUGGER() kdb(KDB_REASON_CALL, 0, 0)
+#define PPCDBG_ENTER_DEBUGGER_REGS(X) kdb(KDB_REASON_CALL, 0, X)
 #endif
 
 #else
diff -urN linux-2.4.21-pre3/include/asm-ppc64/processor.h linux-2.4.21-pre4/include/asm-ppc64/processor.h
--- linux-2.4.21-pre3/include/asm-ppc64/processor.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-ppc64/processor.h	Tue Jan 28 19:44:31 2003
@@ -473,8 +473,6 @@
 #define	  IOCR_SPC	0x00000001
 
 
-/* Processor Version Register */
-
 /* Processor Version Register (PVR) field extraction */
 
 #define	PVR_VER(pvr)  (((pvr) >>  16) & 0xFFFF)	/* Version field */
@@ -588,11 +586,6 @@
 #define RUNLATCH	0x0001
 #define RUN_FLAG	0x0002
 
-/* Macros for adjusting thread priority (hardware multi-threading) */
-#define HMT_low()	asm volatile("or 1,1,1")
-#define HMT_medium()	asm volatile("or 2,2,2")
-#define HMT_high()	asm volatile("or 3,3,3")
-
 /* Size of an exception stack frame contained in the paca. */
 #define EXC_FRAME_SIZE 64
 
@@ -625,7 +618,8 @@
 
 #ifdef __KERNEL__
 /* 64-bit user address space is 41-bits (2TBs user VM) */
-#define TASK_SIZE_USER64 (0x0000020000000000UL)
+/* Subtract PGDIR_SIZE to work around a bug in free_pgtables */ 
+#define TASK_SIZE_USER64 (0x0000020000000000UL - PGDIR_SIZE)
 
 /* 
  * 32-bit user address space is 4GB - 1 page 
@@ -659,8 +653,10 @@
 	signed long     last_syscall;
 	unsigned long	flags;
 	double		fpr[32];	/* Complete floating point set */
-	unsigned long	fpscr_pad;	/* fpr ... fpscr must be contiguous */
-	unsigned long	fpscr;		/* Floating point status */
+	unsigned long	fpscr;		/* Floating point status (plus pad) */
+	unsigned long	fpexc_mode;	/* Floating-point exception mode */
+	unsigned long	saved_msr;	/* Save MSR across signal handlers */
+	unsigned long	saved_softe;	/* Ditto for Soft Enable/Disable */
 };
 
 #define PPC_FLAG_32BIT		0x01
@@ -705,6 +701,24 @@
 #define KSTK_EIP(tsk)  ((tsk)->thread.regs? (tsk)->thread.regs->nip: 0)
 #define KSTK_ESP(tsk)  ((tsk)->thread.regs? (tsk)->thread.regs->gpr[1]: 0)
 
+/* Get/set floating-point exception mode */
+#define GET_FPEXC_CTL(tsk, adr)	get_fpexc_mode((tsk), (adr))
+#define SET_FPEXC_CTL(tsk, val)	set_fpexc_mode((tsk), (val))
+
+extern int get_fpexc_mode(struct task_struct *tsk, unsigned long adr);
+extern int set_fpexc_mode(struct task_struct *tsk, unsigned int val);
+
+static inline unsigned int __unpack_fe01(unsigned long msr_bits)
+{
+	return ((msr_bits & MSR_FE0) >> 10) | ((msr_bits & MSR_FE1) >> 8);
+}
+
+static inline unsigned long __pack_fe01(unsigned int fpmode)
+{
+	return ((fpmode << 10) & MSR_FE0) | ((fpmode << 8) & MSR_FE1);
+}
+
+
 /*
  * NOTE! The task struct and the stack go together
  */
diff -urN linux-2.4.21-pre3/include/asm-ppc64/prom.h linux-2.4.21-pre4/include/asm-ppc64/prom.h
--- linux-2.4.21-pre3/include/asm-ppc64/prom.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-ppc64/prom.h	Tue Jan 28 19:44:31 2003
@@ -125,11 +125,17 @@
 	int	n_intrs;
 	struct	interrupt_info *intrs;
 	char	*full_name;
+
+	/* PCI stuff probably doesn't belong here */
 	int	busno;			/* for pci devices */
 	int	devfn;			/* for pci devices */
+#define DN_STATUS_BIST_FAILED (1<<0)
+	int	status;			/* Current device status (non-zero is bad) */
+	int	eeh_mode;		/* See eeh.h for possible EEH_MODEs */
+	int	eeh_config_addr;
 	struct  pci_controller *phb;	/* for pci devices */
 	struct	TceTable *tce_table;	/* for phb's or bridges */
-#define DN_STATUS_BIST_FAILED (1<<0)
+
 	struct	property *properties;
 	struct	device_node *parent;
 	struct	device_node *child;
@@ -170,6 +176,7 @@
 };
 
 extern struct prom_t prom;
+extern char *of_stdout_device;
 
 /* Prototypes */
 extern void abort(void);
@@ -194,5 +201,6 @@
 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_add_property(struct device_node* np, struct property* prop);
 
 #endif /* _PPC64_PROM_H */
diff -urN linux-2.4.21-pre3/include/asm-ppc64/ptrace.h linux-2.4.21-pre4/include/asm-ppc64/ptrace.h
--- linux-2.4.21-pre3/include/asm-ppc64/ptrace.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.21-pre4/include/asm-ppc64/ptrace.h	Tue Jan 28 19:44:31 2003
@@ -66,9 +66,8 @@
 
 #define STACK_FRAME_OVERHEAD	112	/* size of minimum stack frame */
 
-/* Size of stack frame allocated when calling signal handler. */
-/* FIXME: What should this be on 64-bit kernel (64 for 32-bit) */
-#define __SIGNAL_FRAMESIZE	64
+/* Size of dummy stack frame allocated when calling signal handler. */
+#define __SIGNAL_FRAMESIZE	128
 #define __SIGNAL_FRAMESIZE32	64
 
 #define instruction_pointer(regs) ((regs)->nip)
diff -urN linux-2.4.21-pre3/include/asm-ppc64/rtas.h linux-2.4.21-pre4/include/asm-ppc64/rtas.h
--- linux-2.4.21-pre3/include/asm-ppc64/rtas.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-ppc64/rtas.h	Tue Jan 28 19:44:31 2003
@@ -168,5 +168,13 @@
 
 extern struct proc_dir_entry *rtas_proc_dir;
 
+/* Some RTAS ops require a data buffer and that buffer must be < 4G.
+ * Rather than having a memory allocator, just use this buffer
+ * (get the lock first), make the RTAS call.  Copy the data instead
+ * of holding the buffer for long.
+ */
+#define RTAS_DATA_BUF_SIZE 1024
+extern spinlock_t rtas_data_buf_lock;
+extern char rtas_data_buf[RTAS_DATA_BUF_SIZE];
 
 #endif /* _PPC64_RTAS_H */
diff -urN linux-2.4.21-pre3/include/asm-ppc64/rwsem.h linux-2.4.21-pre4/include/asm-ppc64/rwsem.h
--- linux-2.4.21-pre3/include/asm-ppc64/rwsem.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.21-pre4/include/asm-ppc64/rwsem.h	Tue Jan 28 19:44:31 2003
@@ -79,6 +79,20 @@
 		rwsem_down_read_failed(sem);
 }
 
+static inline int __down_read_trylock(struct rw_semaphore *sem)
+{
+	int tmp;
+
+	while ((tmp = sem->count) >= 0) {
+		if (tmp == cmpxchg(&sem->count, tmp,
+				   tmp + RWSEM_ACTIVE_READ_BIAS)) {
+			smp_wmb();
+			return 1;
+		}
+	}
+	return 0;
+}
+
 /*
  * lock for writing
  */
@@ -94,6 +108,16 @@
 		rwsem_down_write_failed(sem);
 }
 
+static inline int __down_write_trylock(struct rw_semaphore *sem)
+{
+	int tmp;
+
+	tmp = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE,
+		      RWSEM_ACTIVE_WRITE_BIAS);
+	smp_wmb();
+	return tmp == RWSEM_UNLOCKED_VALUE;
+}
+
 /*
  * unlock after reading
  */
diff -urN linux-2.4.21-pre3/include/asm-ppc64/sigcontext.h linux-2.4.21-pre4/include/asm-ppc64/sigcontext.h
--- linux-2.4.21-pre3/include/asm-ppc64/sigcontext.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.21-pre4/include/asm-ppc64/sigcontext.h	Tue Jan 28 19:44:31 2003
@@ -9,13 +9,18 @@
  */
 
 #include <asm/ptrace.h>
+#include <asm/elf.h>
 
-struct sigcontext_struct {
+
+struct sigcontext {
 	unsigned long	_unused[4];
 	int		signal;
+	int		_pad0;
 	unsigned long	handler;
 	unsigned long	oldmask;
-	struct pt_regs 	*regs;
+	struct pt_regs	*regs;
+	elf_gregset_t	gp_regs;
+	elf_fpregset_t	fp_regs;
 };
 
 #endif /* _ASM_PPC64_SIGCONTEXT_H */
diff -urN linux-2.4.21-pre3/include/asm-ppc64/siginfo.h linux-2.4.21-pre4/include/asm-ppc64/siginfo.h
--- linux-2.4.21-pre3/include/asm-ppc64/siginfo.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-ppc64/siginfo.h	Tue Jan 28 19:44:31 2003
@@ -17,7 +17,8 @@
 } sigval_t;
 
 #define SI_MAX_SIZE	128
-#define SI_PAD_SIZE	((SI_MAX_SIZE/sizeof(int)) - 3)
+#define SI_PAD_SIZE	((SI_MAX_SIZE/sizeof(int)) - 4)
+#define SI_PAD_SIZE32	((SI_MAX_SIZE/sizeof(int)) - 3)
 
 typedef struct siginfo {
 	int si_signo;
diff -urN linux-2.4.21-pre3/include/asm-ppc64/signal.h linux-2.4.21-pre4/include/asm-ppc64/signal.h
--- linux-2.4.21-pre3/include/asm-ppc64/signal.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.21-pre4/include/asm-ppc64/signal.h	Tue Jan 28 19:44:31 2003
@@ -10,7 +10,7 @@
 #define _NSIG_BPW	64
 #define _NSIG_WORDS	(_NSIG / _NSIG_BPW)
 
-typedef unsigned long old_sigset_t;		/* at least 32 bits */
+typedef unsigned long old_sigset_t;
 
 typedef struct {
 	unsigned long sig[_NSIG_WORDS];
diff -urN linux-2.4.21-pre3/include/asm-ppc64/smp.h linux-2.4.21-pre4/include/asm-ppc64/smp.h
--- linux-2.4.21-pre3/include/asm-ppc64/smp.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.21-pre4/include/asm-ppc64/smp.h	Tue Jan 28 19:44:31 2003
@@ -19,6 +19,7 @@
 
 #include <linux/config.h>
 #include <linux/kernel.h>
+#include <linux/threads.h>	/* for NR_CPUS */
 
 #ifdef CONFIG_SMP
 
diff -urN linux-2.4.21-pre3/include/asm-ppc64/smplock.h linux-2.4.21-pre4/include/asm-ppc64/smplock.h
--- linux-2.4.21-pre3/include/asm-ppc64/smplock.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-ppc64/smplock.h	Tue Jan 28 19:44:31 2003
@@ -10,6 +10,7 @@
  */
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
+#include <asm/current.h>
 
 extern spinlock_t kernel_flag;
 
diff -urN linux-2.4.21-pre3/include/asm-ppc64/stat.h linux-2.4.21-pre4/include/asm-ppc64/stat.h
--- linux-2.4.21-pre3/include/asm-ppc64/stat.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.21-pre4/include/asm-ppc64/stat.h	Tue Jan 28 19:44:31 2003
@@ -27,8 +27,8 @@
 struct stat {
 	dev_t		st_dev;
 	ino_t		st_ino;
-	mode_t		st_mode;
 	nlink_t		st_nlink;
+	mode_t		st_mode;
 	uid_t 		st_uid;
 	gid_t 		st_gid;
 	dev_t		st_rdev;
@@ -43,6 +43,7 @@
 	unsigned long  	__unused3;
 	unsigned long  	__unused4;
 	unsigned long  	__unused5;
+	unsigned long  	__unused6;
 };
 
 /* This matches struct stat64 in glibc2.1. */
diff -urN linux-2.4.21-pre3/include/asm-ppc64/syscall.h linux-2.4.21-pre4/include/asm-ppc64/syscall.h
--- linux-2.4.21-pre3/include/asm-ppc64/syscall.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/include/asm-ppc64/syscall.h	Tue Jan 28 19:44:31 2003
@@ -0,0 +1,8 @@
+#ifndef _ASM_SYSCALL_H
+#define _ASM_SYSCALL_H
+
+/*
+ * Prototypes for architecture-specific Linux syscalls.
+ */
+
+#endif /* _ASM_SYSCALL_H */
diff -urN linux-2.4.21-pre3/include/asm-ppc64/systemcfg.h linux-2.4.21-pre4/include/asm-ppc64/systemcfg.h
--- linux-2.4.21-pre3/include/asm-ppc64/systemcfg.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/include/asm-ppc64/systemcfg.h	Tue Jan 28 19:44:31 2003
@@ -0,0 +1,101 @@
+#ifndef _SYSTEMCFG_H
+#define _SYSTEMCFG_H
+
+/* 
+ * Copyright (C) 2002 Peter Bergner <bergner@vnet.ibm.com>, IBM
+ *
+ * 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.
+ */
+
+/* Change Activity:
+ * 2002/09/30 : bergner  : Created
+ * End Change Activity 
+ */
+
+
+#ifndef __KERNEL__
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <linux/types.h>
+#endif
+
+/*
+ * If the major version changes we are incompatible.
+ * Minor version changes are a hint.
+ */
+#define SYSTEMCFG_MAJOR 1
+#define SYSTEMCFG_MINOR 0
+
+struct systemcfg {
+	__u8  eye_catcher[16];		/* Eyecatcher: SYSTEMCFG:PPC64	0x00 */
+	struct {			/* Systemcfg version numbers	     */
+		__u32 major;		/* Major number			0x10 */
+		__u32 minor;		/* Minor number			0x14 */
+	} version;
+
+	__u32 platform;			/* Platform flags		0x18 */
+	__u32 processor;		/* Processor type		0x1C */
+	__u64 processorCount;		/* # of physical processors	0x20 */
+	__u64 physicalMemorySize;	/* Size of real memory(B)	0x28 */
+	__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 */
+	__u64 tb_update_count;		/* Timebase atomicity ctr	0x50 */
+	__u32 tz_minuteswest;		/* Minutes west of Greenwich	0x58 */
+	__u32 tz_dsttime;		/* Type of dst correction	0x5C */
+	__u32 dCacheL1Size;		/* L1 d-cache size		0x60 */
+	__u32 dCacheL1LineSize;		/* L1 d-cache line size		0x64 */
+	__u32 iCacheL1Size;		/* L1 i-cache size		0x68 */
+	__u32 iCacheL1LineSize;		/* L1 i-cache line size		0x6C */
+	__u8  reserved0[3984];		/* Reserve rest of page		0x70 */
+};
+
+#ifdef __KERNEL__
+extern struct systemcfg *systemcfg;
+#else
+
+/* Processor Version Register (PVR) field extraction */
+#define PVR_VER(pvr)  (((pvr) >>  16) & 0xFFFF) /* Version field */
+#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
+
+/* Platforms supported by PPC64 */
+#define PLATFORM_PSERIES      0x0100
+#define PLATFORM_PSERIES_LPAR 0x0101
+#define PLATFORM_ISERIES_LPAR 0x0201
+
+
+static inline volatile struct systemcfg *systemcfg_init(void)
+{
+	int fd = open("/proc/ppc64/systemcfg", O_RDONLY);
+	volatile struct systemcfg *ret;
+
+	if (fd == -1)
+		return 0;
+	ret = mmap(0, sizeof(struct systemcfg), PROT_READ, MAP_SHARED, fd, 0);
+	close(fd);
+	if (!ret)
+		return 0;
+	if (ret->version.major != SYSTEMCFG_MAJOR || ret->version.minor < SYSTEMCFG_MINOR) {
+		munmap((void *)ret, sizeof(struct systemcfg));
+		return 0;
+	}
+	return ret;
+}
+#endif /* __KERNEL__ */
+
+#endif /* _SYSTEMCFG_H */
diff -urN linux-2.4.21-pre3/include/asm-ppc64/termios.h linux-2.4.21-pre4/include/asm-ppc64/termios.h
--- linux-2.4.21-pre3/include/asm-ppc64/termios.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-ppc64/termios.h	Tue Jan 28 19:44:31 2003
@@ -192,8 +192,6 @@
 #define TIOCM_OUT2	0x4000
 #define TIOCM_LOOP	0x8000
 
-#define TIOCM_MODEM_BITS       TIOCM_OUT2      /* IRDA support */
-
 /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
 #define TIOCSER_TEMT    0x01	/* Transmitter physically empty */
 
diff -urN linux-2.4.21-pre3/include/asm-ppc64/timex.h linux-2.4.21-pre4/include/asm-ppc64/timex.h
--- linux-2.4.21-pre3/include/asm-ppc64/timex.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-ppc64/timex.h	Tue Jan 28 19:44:31 2003
@@ -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.21-pre3/include/asm-ppc64/types.h linux-2.4.21-pre4/include/asm-ppc64/types.h
--- linux-2.4.21-pre3/include/asm-ppc64/types.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-ppc64/types.h	Tue Jan 28 19:44:31 2003
@@ -64,6 +64,12 @@
 typedef u32 dma_addr_t;
 typedef u64 dma64_addr_t;
 
+typedef struct {
+	unsigned long entry;
+	unsigned long toc;
+	unsigned long env;
+} func_descr_t;
+
 #endif /* __KERNEL__ */
 #endif /* __ASSEMBLY__ */
 
diff -urN linux-2.4.21-pre3/include/asm-ppc64/uaccess.h linux-2.4.21-pre4/include/asm-ppc64/uaccess.h
--- linux-2.4.21-pre3/include/asm-ppc64/uaccess.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-ppc64/uaccess.h	Tue Jan 28 19:44:31 2003
@@ -11,6 +11,7 @@
 #ifndef __ASSEMBLY__
 #include <linux/sched.h>
 #include <linux/errno.h>
+#include <asm/pgtable.h>
 #include <asm/processor.h>
 
 #define VERIFY_READ	0
diff -urN linux-2.4.21-pre3/include/asm-ppc64/ucontext.h linux-2.4.21-pre4/include/asm-ppc64/ucontext.h
--- linux-2.4.21-pre3/include/asm-ppc64/ucontext.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.21-pre4/include/asm-ppc64/ucontext.h	Tue Jan 28 19:44:31 2003
@@ -1,10 +1,9 @@
-#ifndef _ASMPPC64_UCONTEXT_H
-#define _ASMPPC64_UCONTEXT_H
+#ifndef _ASM_PPC64_UCONTEXT_H
+#define _ASM_PPC64_UCONTEXT_H
 
 #include <asm/sigcontext.h>
 
-/* Copied from i386. 
- *
+/*
  * 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
@@ -15,8 +14,9 @@
 	unsigned long	  uc_flags;
 	struct ucontext  *uc_link;
 	stack_t		  uc_stack;
-	struct sigcontext_struct uc_mcontext;
-	sigset_t	  uc_sigmask;	/* mask last for extensibility */
+	sigset_t	  uc_sigmask;
+	sigset_t	  __unsued[15];	/* Allow for uc_sigmask growth */
+	struct sigcontext uc_mcontext;  /* last for extensibility */
 };
 
-#endif /* _ASMPPC64_UCONTEXT_H */
+#endif /* _ASM_PPC64_UCONTEXT_H */
diff -urN linux-2.4.21-pre3/include/asm-ppc64/unistd.h linux-2.4.21-pre4/include/asm-ppc64/unistd.h
--- linux-2.4.21-pre3/include/asm-ppc64/unistd.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.21-pre4/include/asm-ppc64/unistd.h	Tue Jan 28 19:44:31 2003
@@ -200,6 +200,7 @@
 #define __NR_putpmsg		188	/* some people actually want streams */
 #define __NR_vfork		189
 #define __NR_ugetrlimit		190	/* SuS compliant getrlimit */
+#define __NR_readahead		191
 #define __NR_mmap2		192
 #define __NR_truncate64		193
 #define __NR_ftruncate64	194
@@ -216,7 +217,6 @@
 #define __NR_madvise		205
 #define __NR_mincore		206
 #define __NR_gettid		207
-#if 0 /* Reserved syscalls */
 #define __NR_tkill		208
 #define __NR_setxattr		209
 #define __NR_lsetxattr		210
@@ -231,7 +231,19 @@
 #define __NR_lremovexattr	219
 #define __NR_fremovexattr	220
 #define __NR_futex		221
-#endif
+#define __NR_sched_setaffinity	222     
+#define __NR_sched_getaffinity	223
+#define __NR_security		224
+#define __NR_tuxcall		225
+#define __NR_sendfile64		226
+#define __NR_io_setup		227
+#define __NR_io_destroy		228
+#define __NR_io_getevents	229
+#define __NR_io_submit		230
+#define __NR_io_cancel		231
+#define __NR_alloc_hugepages	232
+#define __NR_free_hugepages	233
+#define __NR_exit_group		234
 
 #define __NR(n)	#n
 
diff -urN linux-2.4.21-pre3/include/asm-sparc/mman.h linux-2.4.21-pre4/include/asm-sparc/mman.h
--- linux-2.4.21-pre3/include/asm-sparc/mman.h	Wed Mar 15 00:37:50 2000
+++ linux-2.4.21-pre4/include/asm-sparc/mman.h	Tue Jan 28 19:44:31 2003
@@ -20,7 +20,7 @@
 #define MAP_LOCKED      0x100           /* lock the mapping */
 #define _MAP_NEW        0x80000000      /* Binary compatibility is fun... */
 
-#define MAP_GROWSDOWN	0x0100		/* stack-like segment */
+#define MAP_GROWSDOWN	0x0200		/* stack-like segment */
 #define MAP_DENYWRITE	0x0800		/* ETXTBSY */
 #define MAP_EXECUTABLE	0x1000		/* mark it as an executable */
 
diff -urN linux-2.4.21-pre3/include/asm-sparc64/elf.h linux-2.4.21-pre4/include/asm-sparc64/elf.h
--- linux-2.4.21-pre3/include/asm-sparc64/elf.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-sparc64/elf.h	Tue Jan 28 19:44:31 2003
@@ -109,8 +109,9 @@
 	if (flags != current->thread.flags) {		\
 		/* flush_thread will update pgd cache */\
 		current->thread.flags |= SPARC_FLAG_ABI_PENDING; \
+	} else {					\
+		current->thread.flags &= ~SPARC_FLAG_ABI_PENDING; \
 	}						\
-							\
 	if (ibcs2)					\
 		set_personality(PER_SVR4);		\
 	else if (current->personality != PER_LINUX32)	\
diff -urN linux-2.4.21-pre3/include/asm-sparc64/mman.h linux-2.4.21-pre4/include/asm-sparc64/mman.h
--- linux-2.4.21-pre3/include/asm-sparc64/mman.h	Wed Mar 15 00:37:50 2000
+++ linux-2.4.21-pre4/include/asm-sparc64/mman.h	Tue Jan 28 19:44:31 2003
@@ -20,7 +20,7 @@
 #define MAP_LOCKED      0x100           /* lock the mapping */
 #define _MAP_NEW        0x80000000      /* Binary compatibility is fun... */
 
-#define MAP_GROWSDOWN	0x0100		/* stack-like segment */
+#define MAP_GROWSDOWN	0x0200		/* stack-like segment */
 #define MAP_DENYWRITE	0x0800		/* ETXTBSY */
 #define MAP_EXECUTABLE	0x1000		/* mark it as an executable */
 
diff -urN linux-2.4.21-pre3/include/asm-x86_64/bitops.h linux-2.4.21-pre4/include/asm-x86_64/bitops.h
--- linux-2.4.21-pre3/include/asm-x86_64/bitops.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-x86_64/bitops.h	Tue Jan 28 19:44:31 2003
@@ -372,7 +372,7 @@
 	__asm__("bsfl %1,%0\n\t"
 		"jnz 1f\n\t"
 		"movl $-1,%0\n"
-		"1:" : "=r" (r) : "rm" (x));
+		"1:" : "=r" (r) : "g" (x));
 	return r+1;
 }
 
diff -urN linux-2.4.21-pre3/include/asm-x86_64/hw_irq.h linux-2.4.21-pre4/include/asm-x86_64/hw_irq.h
--- linux-2.4.21-pre3/include/asm-x86_64/hw_irq.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-x86_64/hw_irq.h	Tue Jan 28 19:44:31 2003
@@ -1,6 +1,7 @@
 #ifndef _ASM_HW_IRQ_H
 #define _ASM_HW_IRQ_H
 
+#ifndef __ASSEMBLY__
 /*
  *	linux/include/asm/hw_irq.h
  *
@@ -13,13 +14,16 @@
  *
  *	hacked by Andi Kleen for x86-64.
  * 
- *  $Id: hw_irq.h,v 1.29 2002/04/15 23:43:12 ak Exp $
+ *  $Id: hw_irq.h,v 1.30 2002/10/02 15:44:22 ak Exp $
  */
 
 #include <linux/config.h>
+#include <linux/stddef.h>
 #include <asm/atomic.h>
 #include <asm/irq.h>
 
+#endif
+
 /*
  * IDT vectors usable for external interrupt sources start
  * at 0x20:
@@ -66,6 +70,7 @@
 #define FIRST_DEVICE_VECTOR	0x31
 #define FIRST_SYSTEM_VECTOR	0xef
 
+#ifndef __ASSEMBLY__
 extern int irq_vector[NR_IRQS];
 #define IO_APIC_VECTOR(irq)	irq_vector[irq]
 
@@ -100,58 +105,18 @@
 
 #define IO_APIC_IRQ(x) (((x) >= 16) || ((1<<(x)) & io_apic_irqs))
 
-#define __STR(x) #x
-#define STR(x) __STR(x)
-
 #include <asm/ptrace.h>
-#ifndef ASM_OFFSET_H
-#include <asm/offset.h>
-#endif
 
-/* IF:off, stack contains irq number on origrax */ 
-#define IRQ_ENTER								\
-"	cld ;"									\
-"	pushq %rdi ;"								\
-"	pushq %rsi ;"								\
-"	pushq %rdx ;"								\
-"	pushq %rcx ;"								\
-"	pushq %rax ;"								\
-"	pushq %r8 ;"								\
-"	pushq %r9 ;"								\
-"	pushq %r10 ;"								\
-"	pushq %r11 ;"								\
-"	leaq -48(%rsp),%rdi	;"						\
-"	testl $3,136(%rdi)	;"						\
-"	je 1f ;"								\
-"	swapgs ;"								\
-"1:	addl $1,%gs: " STR(pda_irqcount) ";"					\
-"	movq %gs: " STR(pda_irqstackptr) ",%rax ;"				\
-"	cmoveq %rax,%rsp ;"							\
-"	pushq %rdi ;" 
+extern void reschedule_interrupt(void);
+extern void invalidate_interrupt(void);
+extern void call_function_interrupt(void);
+extern void apic_timer_interrupt(void);
+extern void spurious_interrupt(void);
+extern void error_interrupt(void);
 
 #define IRQ_NAME2(nr) nr##_interrupt(void)
 #define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr)
 
-/*
- *	SMP has a few special interrupts for IPI messages
- */
-
-	/* there is a second layer of macro just to get the symbolic
-	   name for the vector evaluated. This change is for RTLinux */
-#define BUILD_SMP_INTERRUPT(x,v) XBUILD_SMP_INTERRUPT(x,v)
-#define XBUILD_SMP_INTERRUPT(x,v)\
-asmlinkage void x(void); \
-asmlinkage void call_##x(void); \
-__asm__( \
-"\n"__ALIGN_STR"\n" \
-SYMBOL_NAME_STR(x) ":\n\t" \
-	"push $" #v "-256;" \
-	IRQ_ENTER \
-	"call " SYMBOL_NAME_STR(smp_##x) " ; " \
-	"jmp ret_from_intr")
-
-#define BUILD_COMMON_IRQ()
-
 #define BUILD_IRQ(nr) \
 asmlinkage void IRQ_NAME(nr); \
 __asm__( \
@@ -202,4 +167,6 @@
 static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) {}
 #endif
 
+#endif
+
 #endif /* _ASM_HW_IRQ_H */
diff -urN linux-2.4.21-pre3/include/asm-x86_64/ia32.h linux-2.4.21-pre4/include/asm-x86_64/ia32.h
--- linux-2.4.21-pre3/include/asm-x86_64/ia32.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-x86_64/ia32.h	Tue Jan 28 19:44:31 2003
@@ -234,12 +234,6 @@
 	int iov_len; 
 };
 
-
-#ifdef __KERNEL__
-struct iovec *get_iovec32(struct iovec32 *iov32, struct iovec *iov_buf, u32 count, int type);
-#endif
-
-
 #endif /* !CONFIG_IA32_SUPPORT */
  
 #endif 
diff -urN linux-2.4.21-pre3/include/asm-x86_64/ia32_unistd.h linux-2.4.21-pre4/include/asm-x86_64/ia32_unistd.h
--- linux-2.4.21-pre3/include/asm-x86_64/ia32_unistd.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-x86_64/ia32_unistd.h	Tue Jan 28 19:44:31 2003
@@ -232,22 +232,24 @@
 #define __NR_ia32_security		223
 #define __NR_ia32_gettid		224
 #define __NR_ia32_readahead		225
+#define __NR_ia32_setxattr		226
+#define __NR_ia32_lsetxattr		227
+#define __NR_ia32_fsetxattr		228
+#define __NR_ia32_getxattr		229
+#define __NR_ia32_lgetxattr		230
+#define __NR_ia32_fgetxattr		231
+#define __NR_ia32_listxattr		232
+#define __NR_ia32_llistxattr		233
+#define __NR_ia32_flistxattr		234
+#define __NR_ia32_removexattr	235
+#define __NR_ia32_lremovexattr	236
+#define __NR_ia32_fremovexattr	237
+#define __NR_ia32_tkill		238
 #define __NR_ia32_sendfile64		239
 #define __NR_ia32_futex		240
 #define __NR_ia32_sched_setaffinity	241
 #define __NR_ia32_sched_getaffinity	242
-#define __NR_ia32_set_thread_area	243
-#define __NR_ia32_get_thread_area	244
-#define __NR_ia32_io_setup		245
-#define __NR_ia32_io_destroy		246
-#define __NR_ia32_io_getevents	247
-#define __NR_ia32_io_submit		248
-#define __NR_ia32_io_cancel		249
-#define __NR_ia32_alloc_hugepages	250
-#define __NR_ia32_free_hugepages	251
-#define __NR_ia32_exit_group		252
 
-
-#define IA32_NR_syscalls 260
+#define IA32_NR_syscalls 245
 
 #endif /* _ASM_X86_64_IA32_UNISTD_H_ */
diff -urN linux-2.4.21-pre3/include/asm-x86_64/ide.h linux-2.4.21-pre4/include/asm-x86_64/ide.h
--- linux-2.4.21-pre3/include/asm-x86_64/ide.h	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/include/asm-x86_64/ide.h	Tue Jan 28 19:44:31 2003
@@ -77,6 +77,7 @@
 	int index;
 
 	for(index = 0; index < MAX_HWIFS; index++) {
+		memset(&hw, 0, sizeof hw);
 		ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL);
 		hw.irq = ide_default_irq(ide_default_io_base(index));
 		ide_register_hw(&hw, NULL);
diff -urN linux-2.4.21-pre3/include/asm-x86_64/io.h linux-2.4.21-pre4/include/asm-x86_64/io.h
--- linux-2.4.21-pre3/include/asm-x86_64/io.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-x86_64/io.h	Tue Jan 28 19:44:31 2003
@@ -182,16 +182,20 @@
 #define readb(addr) (*(volatile unsigned char *) __io_virt(addr))
 #define readw(addr) (*(volatile unsigned short *) __io_virt(addr))
 #define readl(addr) (*(volatile unsigned int *) __io_virt(addr))
+#define readq(addr) (*(volatile unsigned long *) __io_virt(addr))
 #define __raw_readb readb
 #define __raw_readw readw
 #define __raw_readl readl
+#define __raw_readq readq
 
 #define writeb(b,addr) (*(volatile unsigned char *) __io_virt(addr) = (b))
 #define writew(b,addr) (*(volatile unsigned short *) __io_virt(addr) = (b))
 #define writel(b,addr) (*(volatile unsigned int *) __io_virt(addr) = (b))
+#define writeq(b,addr) (*(volatile unsigned long *) __io_virt(addr) = (b))
 #define __raw_writeb writeb
 #define __raw_writew writew
 #define __raw_writel writel
+#define __raw_writeq writeq
 
 void *memcpy_fromio(void*,const void*,unsigned); 
 void *memcpy_toio(void*,const void*,unsigned); 
diff -urN linux-2.4.21-pre3/include/asm-x86_64/kmap_types.h linux-2.4.21-pre4/include/asm-x86_64/kmap_types.h
--- linux-2.4.21-pre3/include/asm-x86_64/kmap_types.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-x86_64/kmap_types.h	Tue Jan 28 19:44:31 2003
@@ -3,11 +3,10 @@
 
 enum km_type {
 	KM_BOUNCE_READ,
-	KM_SKB_SUNRPC_DATA,
+	KM_SKB_DATA,
 	KM_SKB_DATA_SOFTIRQ,
 	KM_USER0,
 	KM_USER1,
-	KM_BH_IRQ,
 	KM_TYPE_NR
 };
 
diff -urN linux-2.4.21-pre3/include/asm-x86_64/page.h linux-2.4.21-pre4/include/asm-x86_64/page.h
--- linux-2.4.21-pre3/include/asm-x86_64/page.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-x86_64/page.h	Tue Jan 28 19:44:31 2003
@@ -1,6 +1,8 @@
 #ifndef _X86_64_PAGE_H
 #define _X86_64_PAGE_H
 
+#include <linux/stringify.h>
+
 /* PAGE_SHIFT determines the page size */
 #define PAGE_SHIFT	12
 #ifdef __ASSEMBLY__
@@ -23,6 +25,8 @@
 
 /* Changing the next two defines should be enough to increase the kernel stack */
 /* We still hope 8K is enough, but ... */
+/* Currently it is actually ~6k. This would change when task_struct moves into
+   an own slab. */
 #define THREAD_ORDER    1
 #define THREAD_SIZE    (2*PAGE_SIZE)
 
@@ -45,7 +49,7 @@
 typedef struct { unsigned long pmd; } pmd_t;
 typedef struct { unsigned long pgd; } pgd_t;
 typedef struct { unsigned long pml4; } pml4_t;
-#define PTE_MASK	PAGE_MASK
+#define PTE_MASK	PHYSICAL_PAGE_MASK
 
 typedef struct { unsigned long pgprot; } pgprot_t;
 
@@ -74,8 +78,6 @@
 #ifndef __ASSEMBLY__
 
 #include <linux/config.h>
-#include <linux/stringify.h>
-
 
 /*
  * Tell the user there is some problem.  The exception handler decodes this frame.
diff -urN linux-2.4.21-pre3/include/asm-x86_64/pci.h linux-2.4.21-pre4/include/asm-x86_64/pci.h
--- linux-2.4.21-pre3/include/asm-x86_64/pci.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-x86_64/pci.h	Tue Jan 28 19:44:31 2003
@@ -66,10 +66,11 @@
  * Once the device is given the dma address, the device owns this memory
  * until either pci_unmap_single or pci_dma_sync_single is performed.
  */
-extern dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
-			  size_t size, int direction);
+extern dma_addr_t __pci_map_single(struct pci_dev *hwdev, void *ptr,
+			  size_t size, int direction, int flush);
 
-extern void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t addr,
+
+void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t addr,
 				   size_t size, int direction);
 
 /*
@@ -115,8 +116,8 @@
 
 
 #else
-static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
-					size_t size, int direction)
+static inline dma_addr_t __pci_map_single(struct pci_dev *hwdev, void *ptr,
+					size_t size, int direction, int flush)
 {
 	dma_addr_t addr; 
 
@@ -203,6 +204,11 @@
 extern void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
 			 int nents, int direction);
 
+static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
+			  size_t size, int direction)
+{
+	return __pci_map_single(hwdev,ptr,size,direction,1); 
+}
 
 #define pci_unmap_page pci_unmap_single
 
diff -urN linux-2.4.21-pre3/include/asm-x86_64/pda.h linux-2.4.21-pre4/include/asm-x86_64/pda.h
--- linux-2.4.21-pre3/include/asm-x86_64/pda.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-x86_64/pda.h	Tue Jan 28 19:44:31 2003
@@ -1,10 +1,6 @@
 #ifndef X86_64_PDA_H
 #define X86_64_PDA_H
 
-#include <linux/stddef.h>
-#ifndef ASM_OFFSET_H
-#include <asm/offset.h>
-#endif
 #include <linux/cache.h>
 
 /* Per processor datastructure. %gs points to it while the kernel runs */ 
@@ -38,18 +34,16 @@
  */ 
 #define sizeof_field(type,field)  (sizeof(((type *)0)->field))
 #define typeof_field(type,field)  typeof(((type *)0)->field)
-#ifndef __STR
-#define __STR(x) #x
-#endif
-#define __STR2(x) __STR(x) 
 
 extern void __bad_pda_field(void);
+/* Don't use offsetof because it requires too much infrastructure */
+#define pda_offset(field) ((unsigned long)&((struct x8664_pda *)0)->field)
 
 #define pda_to_op(op,field,val) do { \
        switch (sizeof_field(struct x8664_pda, field)) { 		\
-       case 2: asm volatile(op "w %0,%%gs:" __STR2(pda_ ## field) ::"r" (val):"memory"); break;	\
-       case 4: asm volatile(op "l %0,%%gs:" __STR2(pda_ ## field) ::"r" (val):"memory"); break;	\
-       case 8: asm volatile(op "q %0,%%gs:" __STR2(pda_ ## field) ::"r" (val):"memory"); break;	\
+       case 2: asm volatile(op "w %0,%%gs:%c1" :: "r" (val), "i"(pda_offset(field)):"memory"); break;	\
+       case 4: asm volatile(op "l %0,%%gs:%c1" :: "r" (val), "i"(pda_offset(field)):"memory"); break;	\
+       case 8: asm volatile(op "q %0,%%gs:%c1" :: "r" (val), "i"(pda_offset(field)):"memory"); break;	\
        default: __bad_pda_field(); 					\
        } \
        } while (0)
@@ -58,9 +52,9 @@
 #define pda_from_op(op,field) ({ \
        typedef typeof_field(struct x8664_pda, field) T__; T__ ret__; \
        switch (sizeof_field(struct x8664_pda, field)) { 		\
-       case 2: asm volatile(op "w %%gs:" __STR2(pda_ ## field) ",%0":"=r" (ret__)::"memory"); break;	\
-       case 4: asm volatile(op "l %%gs:" __STR2(pda_ ## field) ",%0":"=r" (ret__)::"memory"); break;	\
-       case 8: asm volatile(op "q %%gs:" __STR2(pda_ ## field) ",%0":"=r" (ret__)::"memory"); break;	\
+       case 2: asm volatile(op "w %%gs:%c1,%0":"=r" (ret__): "i" (pda_offset(field)):"memory"); break;	\
+       case 4: asm volatile(op "l %%gs:%c1,%0":"=r" (ret__): "i" (pda_offset(field)):"memory"); break;	\
+       case 8: asm volatile(op "q %%gs:%c1,%0":"=r" (ret__): "i" (pda_offset(field)):"memory"); break;	\
        default: __bad_pda_field(); 					\
        } \
        ret__; })
diff -urN linux-2.4.21-pre3/include/asm-x86_64/pgtable.h linux-2.4.21-pre4/include/asm-x86_64/pgtable.h
--- linux-2.4.21-pre3/include/asm-x86_64/pgtable.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-x86_64/pgtable.h	Tue Jan 28 19:44:31 2003
@@ -156,12 +156,12 @@
 /* Find an entry in the second-level page table.. */
 #define pmd_offset(dir, address) ((pmd_t *) pgd_page(*(dir)) + \
 			__pmd_offset(address))
-#define __mk_pmd(address,prot) ((pmd_t) { (address) | pgprot_val(prot) })
+#define __mk_pmd(address,prot) ((pmd_t) { ((address) | pgprot_val(prot)) & __supported_pte_mask})
 
 #define ptep_get_and_clear(xp)	__pte(xchg(&(xp)->pte, 0))
 #define pte_same(a, b)		((a).pte == (b).pte)
-#define __mk_pte(page_nr,pgprot) __pte(((page_nr) << PAGE_SHIFT) | pgprot_val(pgprot))
-
+#define __mk_pte(page_nr,pgprot) \
+	__pte(((page_nr) << PAGE_SHIFT) | (pgprot_val(pgprot) & __supported_pte_mask))
 #define PML4_SIZE	(1UL << PML4_SHIFT)
 #define PML4_MASK	(~(PML4_SIZE-1))
 #define PMD_SIZE	(1UL << PMD_SHIFT)
@@ -230,13 +230,20 @@
 
 #define PAGE_NONE	__pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED)
 #define PAGE_SHARED	__pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED)
-#define PAGE_COPY	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
-#define PAGE_READONLY	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
+#define PAGE_SHARED_NOEXEC	__pgprot(_PAGE_NX | _PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED)
+#define PAGE_COPY	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_NX)
+
+#define PAGE_COPY_EXEC  \
+	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
+#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_NX)
+#define PAGE_READONLY_EXEC \
+	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
+#define PAGE_EXECONLY PAGE_READONLY_EXEC
 
 #define PAGE_LARGE (_PAGE_PSE|_PAGE_PRESENT) 
 
 #define __PAGE_KERNEL \
-	(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
+	(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_NX)
 #define __PAGE_KERNEL_NOCACHE   (__PAGE_KERNEL | _PAGE_PCD)
 #define __PAGE_KERNEL_RO        (__PAGE_KERNEL & ~_PAGE_RW)
 #define __PAGE_KERNEL_VSYSCALL	(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
@@ -249,32 +256,34 @@
 extern unsigned long __supported_pte_mask; 
 #define __PTE_SUPP(x) __pgprot((x) & __supported_pte_mask)
 
-#define PAGE_KERNEL __PTE_SUPP((__PAGE_KERNEL|_PAGE_GLOBAL) )
-#define PAGE_KERNEL_RO __PTE_SUPP(__PAGE_KERNEL_RO|_PAGE_GLOBAL)
-#define PAGE_KERNEL_NOCACHE __PTE_SUPP(__PAGE_KERNEL_NOCACHE|_PAGE_GLOBAL)
-#define PAGE_KERNEL_VSYSCALL __PTE_SUPP(__PAGE_KERNEL_VSYSCALL|_PAGE_GLOBAL)
-#define PAGE_KERNEL_LARGE __PTE_SUPP(__PAGE_KERNEL_LARGE|_PAGE_GLOBAL)
-#define PAGE_KERNEL_LARGE_NOCACHE __PTE_SUPP(__PAGE_KERNEL_LARGE_NOCACHE|_PAGE_GLOBAL)
-#define PAGE_USER_NOCACHE_RO __PTE_SUPP(__PAGE_USER_NOCACHE_RO|_PAGE_GLOBAL)
-#define PAGE_KERNEL_EXECUTABLE __PTE_SUPP(__PAGE_KERNEL_EXECUTABLE|_PAGE_GLOBAL)
+/* _NX is masked away in mk_pmd/pte */
+
+#define PAGE_KERNEL __PTE_SUPP(__PAGE_KERNEL|_PAGE_GLOBAL)
+#define PAGE_KERNEL_RO __pgprot(__PAGE_KERNEL_RO|_PAGE_GLOBAL)
+#define PAGE_KERNEL_NOCACHE __pgprot(__PAGE_KERNEL_NOCACHE|_PAGE_GLOBAL)
+#define PAGE_KERNEL_VSYSCALL __pgprot(__PAGE_KERNEL_VSYSCALL|_PAGE_GLOBAL)
+#define PAGE_KERNEL_LARGE __pgprot(__PAGE_KERNEL_LARGE|_PAGE_GLOBAL)
+#define PAGE_KERNEL_LARGE_NOCACHE __pgprot(__PAGE_KERNEL_LARGE_NOCACHE|_PAGE_GLOBAL)
+#define PAGE_USER_NOCACHE_RO __pgprot(__PAGE_USER_NOCACHE_RO|_PAGE_GLOBAL)
+#define PAGE_KERNEL_EXECUTABLE __pgprot(__PAGE_KERNEL_EXECUTABLE|_PAGE_GLOBAL)
 
 /*         xwr */
 #define __P000	PAGE_NONE
 #define __P001	PAGE_READONLY
 #define __P010	PAGE_COPY
 #define __P011	PAGE_COPY
-#define __P100	PAGE_READONLY
-#define __P101	PAGE_READONLY
-#define __P110	PAGE_COPY
-#define __P111	PAGE_COPY
+#define __P100	PAGE_EXECONLY
+#define __P101	PAGE_READONLY_EXEC
+#define __P110	PAGE_COPY_EXEC
+#define __P111	PAGE_COPY_EXEC
 
 /*         xwr */
 #define __S000	PAGE_NONE
 #define __S001	PAGE_READONLY
-#define __S010	PAGE_SHARED
-#define __S011	PAGE_SHARED
-#define __S100	PAGE_READONLY
-#define __S101	PAGE_READONLY
+#define __S010	PAGE_SHARED_NOEXEC
+#define __S011	PAGE_SHARED_NOEXEC
+#define __S100	PAGE_EXECONLY
+#define __S101	PAGE_READONLY_EXEC
 #define __S110	PAGE_SHARED
 #define __S111	PAGE_SHARED
 
@@ -342,6 +351,7 @@
 	pte_t __pte; 								 \
 	unsigned long __val = page_to_phys(page);  			 \
 	__val |= pgprot_val(pgprot);						 \
+	__val &= __supported_pte_mask;						\
  	set_pte(&__pte, __pte(__val));						 \
  	__pte;									 \
 }) 
@@ -350,13 +360,15 @@
 static inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
 { 
 	pte_t __pte; 
-	set_pte(&__pte, __pte(physpage + pgprot_val(pgprot))); 
+	set_pte(&__pte, __pte(physpage + (pgprot_val(pgprot) & __supported_pte_mask))); 
 	return __pte;
 }
 
 extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 { 
-	set_pte(&pte, __pte((pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot))); 
+	set_pte(&pte, 
+		__pte(((pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot))  &
+		      __supported_pte_mask));
 	return pte; 
 }
 
@@ -376,7 +388,7 @@
    Other CPUs get synced lazily via the page fault handler. */
 #define pgd_offset_k(address) \
 	__pgd_offset_k( \
-       (pgd_t *)__va(pml4_val(init_level4_pgt[pml4_index(address)]) & PAGE_MASK), address)
+       (pgd_t *)__va(pml4_val(init_level4_pgt[pml4_index(address)]) & PHYSICAL_PAGE_MASK), address)
 
 #define __pmd_offset(address) \
 		(((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1))
@@ -388,7 +400,7 @@
 			__pte_offset(address))
 
 /* never use these in the common code */
-#define pml4_page(level4) ((unsigned long) __va(pml4_val(level4) & PAGE_MASK))
+#define pml4_page(level4) ((unsigned long) __va(pml4_val(level4) & PHYSICAL_PAGE_MASK))
 #define pml4_index(address) (((address) >> PML4_SHIFT) & (PTRS_PER_PML4-1))
 #define pml4_offset_k(address) ((pml4_t *)read_pda(level4_pgt) + pml4_index(address))
 #define level3_offset_k(dir, address) ((pgd_t *) pml4_page(*(dir)) + pgd_index(address))
diff -urN linux-2.4.21-pre3/include/asm-x86_64/processor.h linux-2.4.21-pre4/include/asm-x86_64/processor.h
--- linux-2.4.21-pre3/include/asm-x86_64/processor.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-x86_64/processor.h	Tue Jan 28 19:44:31 2003
@@ -256,7 +256,7 @@
 /* This decides where the kernel will search for a free chunk of vm
  * space during mmap's.
  */
-#define TASK_UNMAPPED_32 0x40000000
+#define TASK_UNMAPPED_32 0xa0000000
 #define TASK_UNMAPPED_64 (TASK_SIZE/3) 
 #define TASK_UNMAPPED_BASE	\
 	((current->thread.flags & THREAD_IA32) ? TASK_UNMAPPED_32 : TASK_UNMAPPED_64)  
@@ -336,9 +336,11 @@
 #define N_EXCEPTION_STACKS 3  /* hw limit: 7 */
 #define EXCEPTION_STKSZ 1024
 
+extern void load_gs_index(unsigned);
+
 #define start_thread(regs,new_rip,new_rsp) do { \
-	__asm__("movl %0,%%fs; movl %0,%%es; movl %0,%%ds": :"r" (0));		 \
-	wrmsrl(MSR_KERNEL_GS_BASE, 0);						 \
+	asm volatile("movl %0,%%fs; movl %0,%%es; movl %0,%%ds": :"r" (0));	 \
+	load_gs_index(0);							\
 	(regs)->rip = (new_rip);						 \
 	(regs)->rsp = (new_rsp);						 \
 	write_pda(oldrsp, (new_rsp));						 \
diff -urN linux-2.4.21-pre3/include/asm-x86_64/proto.h linux-2.4.21-pre4/include/asm-x86_64/proto.h
--- linux-2.4.21-pre3/include/asm-x86_64/proto.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-x86_64/proto.h	Tue Jan 28 19:44:31 2003
@@ -34,7 +34,7 @@
 extern void reserve_bootmem_generic(unsigned long phys, unsigned len);
 extern void free_bootmem_generic(unsigned long phys, unsigned len);
 
-extern unsigned long start_pfn, end_pfn; 
+extern unsigned long start_pfn, end_pfn, end_pfn_map; 
 
 extern void show_stack(unsigned long * rsp);
 
diff -urN linux-2.4.21-pre3/include/asm-x86_64/rwsem.h linux-2.4.21-pre4/include/asm-x86_64/rwsem.h
--- linux-2.4.21-pre3/include/asm-x86_64/rwsem.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-x86_64/rwsem.h	Tue Jan 28 19:44:31 2003
@@ -5,7 +5,6 @@
  *
  * Derived from asm-i386/semaphore.h and asm-i386/rwsem.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
@@ -114,30 +113,6 @@
 		: "memory", "cc");
 }
 
-
-/*
- * 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
  */
@@ -164,19 +139,6 @@
 }
 
 /*
- * 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.21-pre3/include/asm-x86_64/scatterlist.h linux-2.4.21-pre4/include/asm-x86_64/scatterlist.h
--- linux-2.4.21-pre3/include/asm-x86_64/scatterlist.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-x86_64/scatterlist.h	Tue Jan 28 19:44:31 2003
@@ -1,24 +1,6 @@
 #ifndef _X8664_SCATTERLIST_H
 #define _X8664_SCATTERLIST_H
 
-/*
- * Drivers must set either ->address or (preferred) ->page and ->offset
- * to indicate where data must be transferred to/from.
- *
- * Using ->page is recommended since it handles highmem data as well as
- * low mem. ->address is restricted to data which has a virtual mapping, and
- * it will go away in the future. Updating to ->page can be automated very
- * easily -- something like
- *
- * sg->address = some_ptr;
- *
- * can be rewritten as
- *
- * sg->page = virt_to_page(some_ptr);
- * sg->offset = (unsigned long) some_ptr & ~PAGE_MASK;
- *
- * and that's it. There's no excuse for not highmem enabling YOUR driver. /jens
- */
 struct scatterlist {
     char *  address;    /* Location data is to be transferred to, NULL for
 			 * highmem page */
diff -urN linux-2.4.21-pre3/include/asm-x86_64/segment.h linux-2.4.21-pre4/include/asm-x86_64/segment.h
--- linux-2.4.21-pre3/include/asm-x86_64/segment.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-x86_64/segment.h	Tue Jan 28 19:44:31 2003
@@ -9,7 +9,6 @@
 /* 
  * we cannot use the same code segment descriptor for user and kernel
  * even not in the long flat model, because of different DPL /kkeil 
- * The segment offset needs to contain a RPL. Grr. -AK
  * GDT layout to get 64bit syscall right (sysret hardcodes gdt offsets) 
  */
 
diff -urN linux-2.4.21-pre3/include/asm-x86_64/semaphore.h linux-2.4.21-pre4/include/asm-x86_64/semaphore.h
--- linux-2.4.21-pre3/include/asm-x86_64/semaphore.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-x86_64/semaphore.h	Tue Jan 28 19:44:31 2003
@@ -124,13 +124,10 @@
 		LOCK "decl %0\n\t"     /* --sem->count */
 		"js 2f\n"
 		"1:\n"
-                ".subsection 1\n" \
-                ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" \
-                "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" \
-                ".endif\n" \
+		LOCK_SECTION_START("")
 		"2:\tcall __down_failed\n\t"
 		"jmp 1b\n"
-		".subsection 0"
+		LOCK_SECTION_END
 		:"=m" (sem->count)
 		:"D" (sem)
 		:"memory");
@@ -154,13 +151,10 @@
 		"js 2f\n\t"
 		"xorl %0,%0\n"
 		"1:\n"
-                ".subsection 1\n" \
-               ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" \
-                "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" \
-                ".endif\n" \
+		LOCK_SECTION_START("")
 		"2:\tcall __down_failed_interruptible\n\t"
 		"jmp 1b\n"
-		".subsection 0"
+		LOCK_SECTION_END
 		:"=a" (result), "=m" (sem->count)
 		:"D" (sem)
 		:"memory");
@@ -185,13 +179,10 @@
 		"js 2f\n\t"
 		"xorl %0,%0\n"
 		"1:\n"
-                ".subsection 1\n" \
-                ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" \
-                "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" \
-                ".endif\n" \
+		LOCK_SECTION_START("")
 		"2:\tcall __down_failed_trylock\n\t"
 		"jmp 1b\n"
-		".subsection 0"
+		LOCK_SECTION_END
 		:"=a" (result), "=m" (sem->count)
 		:"D" (sem)
 		:"memory","cc");
@@ -214,22 +205,13 @@
 		LOCK "incl %0\n\t"     /* ++sem->count */
 		"jle 2f\n"
 		"1:\n"
-                ".subsection 1\n" \
-                ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" \
-                "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" \
-                ".endif\n" \
+		LOCK_SECTION_START("")
 		"2:\tcall __up_wakeup\n\t"
 		"jmp 1b\n"
-		".subsection 0"
+		LOCK_SECTION_END
 		:"=m" (sem->count)
 		:"D" (sem)
 		:"memory");
 }
-
-static inline int sem_getcount(struct semaphore *sem)
-{
-       return atomic_read(&sem->count);
-}
-
 #endif /* __KERNEL__ */
 #endif
diff -urN linux-2.4.21-pre3/include/asm-x86_64/softirq.h linux-2.4.21-pre4/include/asm-x86_64/softirq.h
--- linux-2.4.21-pre3/include/asm-x86_64/softirq.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-x86_64/softirq.h	Tue Jan 28 19:44:31 2003
@@ -32,17 +32,12 @@
 			"cmpl $0, -8(%0);"				\
 			"jnz 2f;"					\
 			"1:;"						\
-									\
-                   ".subsection 1\n" \
-                   ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" \
-                   "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" \
-                   ".endif\n" \
+			LOCK_SECTION_START("") 		\
 			"2:"	\
 			"call do_softirq_thunk;"		\
 			""		\
 			"jmp 1b;"					\
-			".subsection 0;"				\
-									\
+			LOCK_SECTION_END			\
 		: /* no output */					\
 		: "r" (ptr)				\
 		/* no registers clobbered */ );				\
diff -urN linux-2.4.21-pre3/include/asm-x86_64/spinlock.h linux-2.4.21-pre4/include/asm-x86_64/spinlock.h
--- linux-2.4.21-pre3/include/asm-x86_64/spinlock.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-x86_64/spinlock.h	Tue Jan 28 19:44:31 2003
@@ -57,13 +57,13 @@
 	"\n1:\t" \
 	"lock ; decb %0\n\t" \
 	"js 2f\n" \
-	".section .text.lock,\"ax\"\n" \
+	LOCK_SECTION_START("") \
 	"2:\t" \
 	"cmpb $0,%0\n\t" \
 	"rep;nop\n\t" \
 	"jle 2b\n\t" \
 	"jmp 1b\n" \
-	".previous"
+	LOCK_SECTION_END
 
 /*
  * This works. Despite all the confusion.
diff -urN linux-2.4.21-pre3/include/asm-x86_64/system.h linux-2.4.21-pre4/include/asm-x86_64/system.h
--- linux-2.4.21-pre3/include/asm-x86_64/system.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-x86_64/system.h	Tue Jan 28 19:44:31 2003
@@ -246,8 +246,12 @@
 /* used in the idle loop; sti takes one instruction cycle to complete */
 #define safe_halt()		__asm__ __volatile__("sti; hlt": : :"memory")
 
+#define __save_and_cli(x)      do { __save_flags(x); __cli(); } while(0);
+#define __save_and_sti(x)      do { __save_flags(x); __sti(); } while(0);
+
 /* For spinlocks etc */
 #define local_irq_save(x) 	do { warn_if_not_ulong(x); __asm__ __volatile__("# local_irq_save \n\t pushfq ; popq %0 ; cli":"=g" (x): /* no input */ :"memory"); } while (0)
+#define local_irq_set(x) 	do { warn_if_not_ulong(x); __asm__ __volatile__("# local_irq_set \n\t pushfq ; popq %0 ; sti":"=g" (x): /* no input */ :"memory"); } while (0)
 #define local_irq_restore(x)	__asm__ __volatile__("# local_irq_restore \n\t pushq %0 ; popfq": /* no output */ :"g" (x):"memory")
 #define local_irq_disable()	__cli()
 #define local_irq_enable()	__sti()
@@ -262,6 +266,8 @@
 #define sti() __global_sti()
 #define save_flags(x) ((x)=__global_save_flags())
 #define restore_flags(x) __global_restore_flags(x)
+#define save_and_cli(x) do { save_flags(x); cli(); } while(0);
+#define save_and_sti(x) do { save_flags(x); sti(); } while(0);
 
 #else
 
@@ -269,6 +275,8 @@
 #define sti() __sti()
 #define save_flags(x) __save_flags(x)
 #define restore_flags(x) __restore_flags(x)
+#define save_and_cli(x) __save_and_cli(x)
+#define save_and_sti(x) __save_and_sti(x)
 
 #endif
 
diff -urN linux-2.4.21-pre3/include/asm-x86_64/timex.h linux-2.4.21-pre4/include/asm-x86_64/timex.h
--- linux-2.4.21-pre3/include/asm-x86_64/timex.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-x86_64/timex.h	Tue Jan 28 19:44:31 2003
@@ -10,7 +10,7 @@
 #include <asm/msr.h>
 #include <asm/vsyscall.h>
 
-#define CLOCK_TICK_RATE (hpet.address ? hpet.hz : 1193182L)
+#define CLOCK_TICK_RATE (vxtime_hz)
 #define FINETUNE	((((((long)LATCH * HZ - CLOCK_TICK_RATE) << SHIFT_HZ) * \
 			1000000 / CLOCK_TICK_RATE) << (SHIFT_SCALE - SHIFT_HZ)) / HZ)
 
@@ -61,6 +61,8 @@
 #define HPET_T0_SETVAL		0x040
 #define HPET_T0_32BIT		0x100
 
-extern struct hpet_data hpet;
+extern struct vxtime_data vxtime;
+extern unsigned long vxtime_hz;
+extern unsigned long hpet_address;
 
 #endif
diff -urN linux-2.4.21-pre3/include/asm-x86_64/unistd.h linux-2.4.21-pre4/include/asm-x86_64/unistd.h
--- linux-2.4.21-pre3/include/asm-x86_64/unistd.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-x86_64/unistd.h	Tue Jan 28 19:44:31 2003
@@ -483,8 +483,20 @@
 __SYSCALL(__NR_io_cancel, sys_ni_syscall)
 #define __NR_get_thread_area	211
 __SYSCALL(__NR_get_thread_area, sys_ni_syscall)
+#define __NR_lookup_dcookie     212
+__SYSCALL(__NR_lookup_dcookie, sys_ni_syscall)
+#define __NR_epoll_create       213
+__SYSCALL(__NR_epoll_create, sys_ni_syscall)
+#define __NR_epoll_ctl  214
+__SYSCALL(__NR_epoll_ctl, sys_ni_syscall)
+#define __NR_epoll_wait 215
+__SYSCALL(__NR_epoll_wait, sys_ni_syscall)
+#define __NR_remap_file_pages   216
+__SYSCALL(__NR_remap_file_pages, sys_ni_syscall)
+#define __NR_getdents64 217
+__SYSCALL(__NR_getdents64, sys_getdents64)
 
-#define __NR_syscall_max __NR_get_thread_area
+#define __NR_syscall_max __NR_getdents64
 
 #ifndef __NO_STUBS
 
@@ -549,10 +561,10 @@
 type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
 { \
 long __res; \
-__asm__ volatile ("movq %5,%%r10 ;" __syscall \
+__asm__ volatile ("movq %[a3],%%r10 ;" __syscall \
 	: "=a" (__res) \
 	: "0" (__NR_##name),"D" ((long)(arg1)),"S" ((long)(arg2)), \
-	  "d" ((long)(arg3)),"g" ((long)(arg4)) : __syscall_clobber,"r10" ); \
+	  "d" ((long)(arg3)), [a3] "g" ((long)(arg4)) : __syscall_clobber,"r10" ); \
 __syscall_return(type,__res); \
 } 
 
@@ -561,10 +573,10 @@
 type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
 { \
 long __res; \
-__asm__ volatile ("movq %5,%%r10 ; movq %6,%%r8 ; " __syscall \
+__asm__ volatile ("movq %[a3],%%r10 ; movq %[a4],%%r8 ; " __syscall \
 	: "=a" (__res) \
 	: "0" (__NR_##name),"D" ((long)(arg1)),"S" ((long)(arg2)), \
-	  "d" ((long)(arg3)),"g" ((long)(arg4)),"g" ((long)(arg5)) : \
+	  "d" ((long)(arg3)), [a3] "g" ((long)(arg4)), [a4] "g" ((long)(arg5)) : \
 	__syscall_clobber,"r8","r10" ); \
 __syscall_return(type,__res); \
 }
@@ -574,11 +586,11 @@
 type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \
 { \
 long __res; \
-__asm__ volatile ("movq %5,%%r10 ; movq %6,%%r8 ; movq %7,%%r9" __syscall \
+__asm__ volatile ("movq %[a3],%%r10 ; movq %[a4],%%r8 ; movq %[a5],%%r9" __syscall \
 	: "=a" (__res) \
 	: "0" (__NR_##name),"D" ((long)(arg1)),"S" ((long)(arg2)), \
-	  "d" ((long)(arg3)),"g" ((long)(arg4)),"g" ((long)(arg5), \
-	  "g" ((long)(arg6),) : \
+	  "d" ((long)(arg3)), [a3] "g" ((long)(arg4)), [a4] "g" ((long)(arg5), \
+	  [a5] "g" ((long)(arg6),) : \
 	__syscall_clobber,"r8","r10","r9" ); \
 __syscall_return(type,__res); \
 }
diff -urN linux-2.4.21-pre3/include/asm-x86_64/vsyscall.h linux-2.4.21-pre4/include/asm-x86_64/vsyscall.h
--- linux-2.4.21-pre3/include/asm-x86_64/vsyscall.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/asm-x86_64/vsyscall.h	Tue Jan 28 19:44:31 2003
@@ -15,29 +15,31 @@
 
 #ifdef __KERNEL__
 
-#define __section_hpet __attribute__ ((unused, __section__ (".hpet"), aligned(16)))
+#define __section_vxtime __attribute__ ((unused, __section__ (".vxtime"), aligned(16)))
 #define __section_wall_jiffies __attribute__ ((unused, __section__ (".wall_jiffies"), aligned(16)))
 #define __section_jiffies __attribute__ ((unused, __section__ (".jiffies"), aligned(16)))
 #define __section_sys_tz __attribute__ ((unused, __section__ (".sys_tz"), aligned(16)))
 #define __section_xtime __attribute__ ((unused, __section__ (".xtime"), aligned(16)))
 #define __section_vxtime_sequence __attribute__ ((unused, __section__ (".vxtime_sequence"), aligned(16)))
 
-struct hpet_data {
-	long address;		/* base address */
-	unsigned long hz;	/* HPET clocks / sec */
-	int trigger;		/* value at last interrupt */
+struct vxtime_data {
+	long last_tsc;
+	long tsc_quot;
+	long quot;
 	int last;
-	int offset;
-	unsigned long last_tsc;
-	long ticks;
+	int mode;
 };
 
+#define VXTIME_TSC_SAFE	0
+#define VXTIME_TSC	1
+#define	VXTIME_HPET	2
+
 #define hpet_readl(a)           readl(fix_to_virt(FIX_HPET_BASE) + a)
 #define hpet_writel(d,a)        writel(d, fix_to_virt(FIX_HPET_BASE) + a)
 
 /* vsyscall space (readonly) */
 extern long __vxtime_sequence[2];
-extern struct hpet_data __hpet;
+extern struct vxtime_data __vxtime;
 extern struct timeval __xtime;
 extern volatile unsigned long __jiffies;
 extern unsigned long __wall_jiffies;
@@ -45,7 +47,7 @@
 
 /* kernel space (writeable) */
 extern long vxtime_sequence[2];
-extern struct hpet_data hpet;
+extern struct vxtime_data vxtime;
 extern unsigned long wall_jiffies;
 extern struct timezone sys_tz;
 
diff -urN linux-2.4.21-pre3/include/linux/auto_fs.h linux-2.4.21-pre4/include/linux/auto_fs.h
--- linux-2.4.21-pre3/include/linux/auto_fs.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/linux/auto_fs.h	Tue Jan 28 19:44:31 2003
@@ -45,7 +45,7 @@
  * If so, 32-bit user-space code should be backwards compatible.
  */
 
-#if defined(__sparc__) || defined(__mips__) || defined(__s390__) || defined(__x86_64__)
+#if !defined(__alpha__) && !defined(__ia64__)   
 typedef unsigned int autofs_wqt_t;
 #else
 typedef unsigned long autofs_wqt_t;
diff -urN linux-2.4.21-pre3/include/linux/ipmi.h linux-2.4.21-pre4/include/linux/ipmi.h
--- linux-2.4.21-pre3/include/linux/ipmi.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/include/linux/ipmi.h	Tue Jan 28 19:44:31 2003
@@ -0,0 +1,516 @@
+/*
+ * ipmi.h
+ *
+ * MontaVista IPMI interface
+ *
+ * Author: MontaVista Software, Inc.
+ *         Corey Minyard <minyard@mvista.com>
+ *         source@mvista.com
+ *
+ * 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.
+ *
+ *
+ *  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.
+ */
+
+#ifndef __LINUX_IPMI_H
+#define __LINUX_IPMI_H
+
+#include <linux/ipmi_msgdefs.h>
+
+/*
+ * This file describes an interface to an IPMI driver.  You have to
+ * have a fairly good understanding of IPMI to use this, so go read
+ * the specs first before actually trying to do anything.
+ *
+ * With that said, this driver provides a multi-user interface to the
+ * IPMI driver, and it allows multiple IPMI physical interfaces below
+ * the driver.  The physical interfaces bind as a lower layer on the
+ * driver.  They appear as interfaces to the application using this
+ * interface.
+ *
+ * Multi-user means that multiple applications may use the driver,
+ * send commands, receive responses, etc.  The driver keeps track of
+ * commands the user sends and tracks the responses.  The responses
+ * will go back to the application that send the command.  If the
+ * response doesn't come back in time, the driver will return a
+ * timeout error response to the application.  Asynchronous events
+ * from the BMC event queue will go to all users bound to the driver.
+ * The incoming event queue in the BMC will automatically be flushed
+ * if it becomes full and it is queried once a second to see if
+ * anything is in it.  Incoming commands to the driver will get
+ * delivered as commands.
+ *
+ * This driver provides two main interfaces: one for in-kernel
+ * applications and another for userland applications.  The
+ * capabilities are basically the same for both interface, although
+ * the interfaces are somewhat different.  The stuff in the
+ * #ifdef KERNEL below is the in-kernel interface.  The userland
+ * interface is defined later in the file.  */
+
+
+
+/*
+ * This is an overlay for all the address types, so it's easy to
+ * determine the actual address type.  This is kind of like addresses
+ * work for sockets.
+ */
+#define IPMI_MAX_ADDR_SIZE 32
+struct ipmi_addr
+{
+	 /* Try to take these from the "Channel Medium Type" table
+	    in section 6.5 of the IPMI 1.5 manual. */
+	int   addr_type;
+	short channel;
+	char  data[IPMI_MAX_ADDR_SIZE];
+};
+
+/*
+ * When the address is not used, the type will be set to this value.
+ * The channel is the BMC's channel number for the channel (usually
+ * 0), or IPMC_BMC_CHANNEL if communicating directly with the BMC.
+ */
+#define IPMI_SYSTEM_INTERFACE_ADDR_TYPE	0x0c
+struct ipmi_system_interface_addr
+{
+	int           addr_type;
+	short         channel;
+	unsigned char lun;
+};
+
+/* An IPMB Address. */
+#define IPMI_IPMB_ADDR_TYPE		0x01
+/* Used for broadcast get device id as described in section 17.9 of the
+   IPMI 1.5 manual. */ 
+#define IPMI_IPMB_BROADCAST_ADDR_TYPE	0x41
+struct ipmi_ipmb_addr
+{
+	int           addr_type;
+	short         channel;
+	unsigned char slave_addr;
+	unsigned char lun;
+};
+
+
+/*
+ * Channel for talking directly with the BMC.  When using this
+ * channel, This is for the system interface address type only.  FIXME
+ * - is this right, or should we use -1?
+ */
+#define IPMI_BMC_CHANNEL  0xf
+#define IPMI_NUM_CHANNELS 0x10
+
+
+/*
+ * A raw IPMI message without any addressing.  This covers both
+ * commands and responses.  The completion code is always the first
+ * byte of data in the response (as the spec shows the messages laid
+ * out).
+ */
+struct ipmi_msg
+{
+	unsigned char  netfn;
+	unsigned char  cmd;
+	unsigned short data_len;
+	unsigned char  *data;
+};
+
+/*
+ * Various defines that are useful for IPMI applications.
+ */
+#define IPMI_INVALID_CMD_COMPLETION_CODE	0xC1
+#define IPMI_TIMEOUT_COMPLETION_CODE		0xC3
+#define IPMI_UNKNOWN_ERR_COMPLETION_CODE	0xff
+
+
+/*
+ * Receive types for messages coming from the receive interface.  This
+ * is used for the receive in-kernel interface and in the receive
+ * IOCTL.
+ */
+#define IPMI_RESPONSE_RECV_TYPE		1 /* A response to a command */
+#define IPMI_ASYNC_EVENT_RECV_TYPE	2 /* Something from the event queue */
+#define IPMI_CMD_RECV_TYPE		3 /* A command from somewhere else */
+/* Note that async events and received commands do not have a completion
+   code as the first byte of the incoming data, unlike a response. */
+
+
+
+#ifdef __KERNEL__
+
+/*
+ * The in-kernel interface.
+ */
+#include <linux/list.h>
+
+/* Opaque type for a IPMI message user.  One of these is needed to
+   send and receive messages. */
+typedef struct ipmi_user *ipmi_user_t;
+
+/*
+ * Stuff coming from the recieve interface comes as one of these.
+ * They are allocated, the receiver must free them with
+ * ipmi_free_recv_msg() when done with the message.  The link is not
+ * used after the message is delivered, so the upper layer may use the
+ * link to build a linked list, if it likes.
+ */
+struct ipmi_recv_msg
+{
+	struct list_head link;
+
+	/* The type of message as defined in the "Receive Types"
+           defines above. */
+	int              recv_type;
+
+	ipmi_user_t      user;
+	struct ipmi_addr addr;
+	long             msgid;
+	struct ipmi_msg  msg;
+
+	/* Call this when done with the message.  It will presumably free
+	   the message and do any other necessary cleanup. */
+	void (*done)(struct ipmi_recv_msg *msg);
+
+	/* Place-holder for the data, don't make any assumptions about
+	   the size or existance of this, since it may change. */
+	unsigned char   msg_data[IPMI_MAX_MSG_LENGTH];
+};
+
+/* Allocate and free the receive message. */
+static inline void ipmi_free_recv_msg(struct ipmi_recv_msg *msg)
+{
+	msg->done(msg);
+}
+struct ipmi_recv_msg *ipmi_alloc_recv_msg(void);
+
+struct ipmi_user_hndl
+{
+        /* Routine type to call when a message needs to be routed to
+	   the upper layer.  This will be called with some locks held,
+	   the only IPMI routines that can be called are ipmi_request
+	   and the alloc/free operations. */
+	void (*ipmi_recv_hndl)(struct ipmi_recv_msg *msg,
+			       void                 *handler_data);
+
+	/* Called when the interface detects a watchdog pre-timeout.  If
+	   this is NULL, it will be ignored for the user. */
+	void (*ipmi_watchdog_pretimeout)(void *handler_data);
+};
+
+/* Create a new user of the IPMI layer on the given interface number. */
+int ipmi_create_user(unsigned int          if_num,
+		     struct ipmi_user_hndl *handler,
+		     void                  *handler_data,
+		     ipmi_user_t           *user);
+
+/* Destroy the given user of the IPMI layer. */
+int ipmi_destroy_user(ipmi_user_t user);
+
+/* Get the IPMI version of the BMC we are talking to. */
+void ipmi_get_version(ipmi_user_t   user,
+		      unsigned char *major,
+		      unsigned char *minor);
+
+/* Set and get the slave address and LUN that we will use for our
+   source messages.  Note that this affects the interface, not just
+   this user, so it will affect all users of this interface.  This is
+   so some initialization code can come in and do the OEM-specific
+   things it takes to determine your address (if not the BMC) and set
+   it for everyone else. */
+void ipmi_set_my_address(ipmi_user_t   user,
+			 unsigned char address);
+unsigned char ipmi_get_my_address(ipmi_user_t user);
+void ipmi_set_my_LUN(ipmi_user_t   user,
+		     unsigned char LUN);
+unsigned char ipmi_get_my_LUN(ipmi_user_t user);
+
+/*
+ * Send a command request from the given user.  The address is the
+ * proper address for the channel type.  If this is a command, then
+ * the message response comes back, the receive handler for this user
+ * will be called with the given msgid value in the recv msg.  If this
+ * is a response to a command, then the msgid will be used as the
+ * sequence number for the response (truncated if necessary), so when
+ * sending a response you should use the sequence number you received
+ * in the msgid field of the received command.  If the priority is >
+ * 0, the message will go into a high-priority queue and be sent
+ * first.  Otherwise, it goes into a normal-priority queue.
+ */
+int ipmi_request(ipmi_user_t      user,
+		 struct ipmi_addr *addr,
+		 long             msgid,
+		 struct ipmi_msg  *msg,
+		 int              priority);
+
+/*
+ * Like ipmi_request, but lets you specify the slave return address.
+ */
+int ipmi_request_with_source(ipmi_user_t      user,
+			     struct ipmi_addr *addr,
+			     long             msgid,
+			     struct ipmi_msg  *msg,
+			     int              priority,
+			     unsigned char    source_address,
+			     unsigned char    source_lun);
+
+/*
+ * Like ipmi_request, but with messages supplied.  This will not
+ * allocate any memory, and the messages may be statically allocated
+ * (just make sure to do the "done" handling on them).  Note that this
+ * is primarily for the watchdog timer, since it should be able to
+ * send messages even if no memory is available.  This is subject to
+ * change as the system changes, so don't use it unless you REALLY
+ * have to.
+ */
+int ipmi_request_supply_msgs(ipmi_user_t          user,
+			     struct ipmi_addr     *addr,
+			     long                 msgid,
+			     struct ipmi_msg      *msg,
+			     void                 *supplied_smi,
+			     struct ipmi_recv_msg *supplied_recv,
+			     int                  priority);
+
+/*
+ * When commands come in to the SMS, the user can register to receive
+ * them.  Only one user can be listening on a specific netfn/cmd pair
+ * at a time, you will get an EBUSY error if the command is already
+ * registered.  If a command is received that does not have a user
+ * registered, the driver will automatically return the proper
+ * error.
+ */
+int ipmi_register_for_cmd(ipmi_user_t   user,
+			  unsigned char netfn,
+			  unsigned char cmd);
+int ipmi_unregister_for_cmd(ipmi_user_t   user,
+			    unsigned char netfn,
+			    unsigned char cmd);
+
+/*
+ * When the user is created, it will not receive IPMI events by
+ * default.  The user must set this to TRUE to get incoming events.
+ * The first user that sets this to TRUE will receive all events that
+ * have been queued while no one was waiting for events.
+ */
+int ipmi_set_gets_events(ipmi_user_t user, int val);
+
+/*
+ * Register the given user to handle all received IPMI commands.  This
+ * will fail if anyone is registered as a command receiver or if
+ * another is already registered to receive all commands.  NOTE THAT
+ * THIS IS FOR EMULATION USERS ONLY, DO NOT USER THIS FOR NORMAL
+ * STUFF.
+ */
+int ipmi_register_all_cmd_rcvr(ipmi_user_t user);
+int ipmi_unregister_all_cmd_rcvr(ipmi_user_t user);
+
+
+/*
+ * Called when a new SMI is registered.  This will also be called on
+ * every existing interface when a new watcher is registered with
+ * ipmi_smi_watcher_register().
+ */
+struct ipmi_smi_watcher
+{
+	struct list_head link;
+
+	/* These two are called with read locks held for the interface
+	   the watcher list.  So you can add and remove users from the
+	   IPMI interface, send messages, etc., but you cannot add
+	   or remove SMI watchers or SMI interfaces. */
+	void (*new_smi)(int if_num);
+	void (*smi_gone)(int if_num);
+};
+
+int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher);
+int ipmi_smi_watcher_unregister(struct ipmi_smi_watcher *watcher);
+
+/* The following are various helper functions for dealing with IPMI
+   addresses. */
+
+/* Return the maximum length of an IPMI address given it's type. */
+unsigned int ipmi_addr_length(int addr_type);
+
+/* Validate that the given IPMI address is valid. */
+int ipmi_validate_addr(struct ipmi_addr *addr, int len);
+
+/* Return 1 if the given addresses are equal, 0 if not. */
+int ipmi_addr_equal(struct ipmi_addr *addr1, struct ipmi_addr *addr2);
+
+#endif /* __KERNEL__ */
+
+
+/*
+ * The userland interface
+ */
+
+/*
+ * The userland interface for the IPMI driver is a standard character
+ * device, with each instance of an interface registered as a minor
+ * number under the major character device.
+ *
+ * The read and write calls do not work, to get messages in and out
+ * requires ioctl calls because of the complexity of the data.  select
+ * and poll do work, so you can wait for input using the file
+ * descriptor, you just can use read to get it.
+ *
+ * In general, you send a command down to the interface and receive
+ * responses back.  You can use the msgid value to correlate commands
+ * and responses, the driver will take care of figuring out which
+ * incoming messages are for which command and find the proper msgid
+ * value to report.  You will only receive reponses for commands you
+ * send.  Asynchronous events, however, go to all open users, so you
+ * must be ready to handle these (or ignore them if you don't care).
+ *
+ * The address type depends upon the channel type.  When talking
+ * directly to the BMC (IPMC_BMC_CHANNEL), the address is ignored
+ * (IPMI_UNUSED_ADDR_TYPE).  When talking to an IPMB channel, you must
+ * supply a valid IPMB address with the addr_type set properly.
+ *
+ * When talking to normal channels, the driver takes care of the
+ * details of formatting and sending messages on that channel.  You do
+ * not, for instance, have to format a send command, you just send
+ * whatever command you want to the channel, the driver will create
+ * the send command, automatically issue receive command and get even
+ * commands, and pass those up to the proper user.
+ */
+
+
+/* The magic IOCTL value for this interface. */
+#define IPMI_IOC_MAGIC 'i'
+
+
+/* Messages sent to the interface are this format. */
+struct ipmi_req
+{
+	unsigned char *addr; /* Address to send the message to. */
+	unsigned int  addr_len;
+
+	long    msgid; /* The sequence number for the message.  This
+			  exact value will be reported back in the
+			  response to this request if it is a command.
+			  If it is a response, this will be used as
+			  the sequence value for the response.  */
+
+	struct ipmi_msg msg;
+};
+/*
+ * Send a message to the interfaces.  error values are:
+ *   - EFAULT - an address supplied was invalid.
+ *   - EINVAL - The address supplied was not valid, or the command
+ *              was not allowed.
+ *   - EMSGSIZE - The message to was too large.
+ *   - ENOMEM - Buffers could not be allocated for the command.
+ */
+#define IPMICTL_SEND_COMMAND		_IOR(IPMI_IOC_MAGIC, 13,	\
+					     struct ipmi_req)
+
+/* Messages received from the interface are this format. */
+struct ipmi_recv
+{
+	int     recv_type; /* Is this a command, response or an
+			      asyncronous event. */
+
+	unsigned char *addr;    /* Address the message was from is put
+				   here.  The caller must supply the
+				   memory. */
+	unsigned int  addr_len; /* The size of the address buffer.
+				   The caller supplies the full buffer
+				   length, this value is updated to
+				   the actual message length when the
+				   message is received. */
+
+	long    msgid; /* The sequence number specified in the request
+			  if this is a response.  If this is a command,
+			  this will be the sequence number from the
+			  command. */
+
+	struct ipmi_msg msg; /* The data field must point to a buffer.
+				The data_size field must be set to the
+				size of the message buffer.  The
+				caller supplies the full buffer
+				length, this value is updated to the
+				actual message length when the message
+				is received. */
+};
+
+/*
+ * Receive a message.  error values:
+ *  - EAGAIN - no messages in the queue.
+ *  - EFAULT - an address supplied was invalid.
+ *  - EINVAL - The address supplied was not valid.
+ *  - EMSGSIZE - The message to was too large to fit into the message buffer,
+ *               the message will be left in the buffer. */
+#define IPMICTL_RECEIVE_MSG		_IOWR(IPMI_IOC_MAGIC, 12,	\
+					      struct ipmi_recv)
+
+/*
+ * Like RECEIVE_MSG, but if the message won't fit in the buffer, it
+ * will truncate the contents instead of leaving the data in the
+ * buffer.
+ */
+#define IPMICTL_RECEIVE_MSG_TRUNC	_IOWR(IPMI_IOC_MAGIC, 11,	\
+					      struct ipmi_recv)
+
+/* Register to get commands from other entities on this interface. */
+struct ipmi_cmdspec
+{
+	unsigned char netfn;
+	unsigned char cmd;
+};
+
+/* 
+ * Register to receive a specific command.  error values:
+ *   - EFAULT - an address supplied was invalid.
+ *   - EBUSY - The netfn/cmd supplied was already in use.
+ *   - ENOMEM - could not allocate memory for the entry.
+ */
+#define IPMICTL_REGISTER_FOR_CMD	_IOR(IPMI_IOC_MAGIC, 14,	\
+					     struct ipmi_cmdspec)
+/*
+ * Unregister a regsitered command.  error values:
+ *  - EFAULT - an address supplied was invalid.
+ *  - ENOENT - The netfn/cmd was not found registered for this user.
+ */
+#define IPMICTL_UNREGISTER_FOR_CMD	_IOR(IPMI_IOC_MAGIC, 15,	\
+					     struct ipmi_cmdspec)
+
+/* 
+ * Set whether this interface receives events.  Note that the first
+ * user registered for events will get all pending events for the
+ * interface.  error values:
+ *  - EFAULT - an address supplied was invalid.
+ */
+#define IPMICTL_SET_GETS_EVENTS_CMD	_IOR(IPMI_IOC_MAGIC, 16, int)
+
+/*
+ * Set and get the slave address and LUN that we will use for our
+ * source messages.  Note that this affects the interface, not just
+ * this user, so it will affect all users of this interface.  This is
+ * so some initialization code can come in and do the OEM-specific
+ * things it takes to determine your address (if not the BMC) and set
+ * it for everyone else.  You should probably leave the LUN alone.
+ */
+#define IPMICTL_SET_MY_ADDRESS_CMD	_IOR(IPMI_IOC_MAGIC, 17, unsigned int)
+#define IPMICTL_GET_MY_ADDRESS_CMD	_IOR(IPMI_IOC_MAGIC, 18, unsigned int)
+#define IPMICTL_SET_MY_LUN_CMD		_IOR(IPMI_IOC_MAGIC, 19, unsigned int)
+#define IPMICTL_GET_MY_LUN_CMD		_IOR(IPMI_IOC_MAGIC, 20, unsigned int)
+
+#endif /* __LINUX_IPMI_H */
diff -urN linux-2.4.21-pre3/include/linux/ipmi_msgdefs.h linux-2.4.21-pre4/include/linux/ipmi_msgdefs.h
--- linux-2.4.21-pre3/include/linux/ipmi_msgdefs.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/include/linux/ipmi_msgdefs.h	Tue Jan 28 19:44:31 2003
@@ -0,0 +1,58 @@
+/*
+ * ipmi_smi.h
+ *
+ * MontaVista IPMI system management interface
+ *
+ * Author: MontaVista Software, Inc.
+ *         Corey Minyard <minyard@mvista.com>
+ *         source@mvista.com
+ *
+ * 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.
+ *
+ *
+ *  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.
+ */
+
+#ifndef __LINUX_IPMI_MSGDEFS_H
+#define __LINUX_IPMI_MSGDEFS_H
+
+/* Various definitions for IPMI messages used by almost everything in
+   the IPMI stack. */
+
+#define IPMI_NETFN_APP_REQUEST	0x06
+#define IPMI_NETFN_APP_RESPONSE	0x07
+
+#define IPMI_BMC_SLAVE_ADDR	0x20
+
+#define IPMI_GET_DEVICE_ID_CMD		0x01
+
+#define IPMI_CLEAR_MSG_FLAGS_CMD	0x30
+#define IPMI_GET_MSG_FLAGS_CMD		0x31
+#define IPMI_SEND_MSG_CMD		0x34
+#define IPMI_GET_MSG_CMD		0x33
+
+#define IPMI_SET_BMC_GLOBAL_ENABLES_CMD	0x2e
+#define IPMI_GET_BMC_GLOBAL_ENABLES_CMD	0x2f
+#define IPMI_READ_EVENT_MSG_BUFFER_CMD	0x35
+
+#define IPMI_MAX_MSG_LENGTH	80
+
+#endif /* __LINUX_IPMI_MSGDEFS_H */
diff -urN linux-2.4.21-pre3/include/linux/ipmi_smi.h linux-2.4.21-pre4/include/linux/ipmi_smi.h
--- linux-2.4.21-pre3/include/linux/ipmi_smi.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/include/linux/ipmi_smi.h	Tue Jan 28 19:44:31 2003
@@ -0,0 +1,144 @@
+/*
+ * ipmi_smi.h
+ *
+ * MontaVista IPMI system management interface
+ *
+ * Author: MontaVista Software, Inc.
+ *         Corey Minyard <minyard@mvista.com>
+ *         source@mvista.com
+ *
+ * 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.
+ *
+ *
+ *  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.
+ */
+
+#ifndef __LINUX_IPMI_SMI_H
+#define __LINUX_IPMI_SMI_H
+
+#include <linux/ipmi_msgdefs.h>
+
+/* This files describes the interface for IPMI system management interface
+   drivers to bind into the IPMI message handler. */
+
+/* Structure for the low-level drivers. */
+typedef struct ipmi_smi *ipmi_smi_t;
+
+/*
+ * Messages to/from the lower layer.  The smi interface will take one
+ * of these to send. After the send has occurred and a response has
+ * been received, it will report this same data structure back up to
+ * the upper layer.  If an error occurs, it should fill in the
+ * response with an error code in the completion code location. When
+ * asyncronous data is received, one of these is allocated, the
+ * data_size is set to zero and the response holds the data from the
+ * get message or get event command that the interface initiated.
+ * Note that it is the interfaces responsibility to detect
+ * asynchronous data and messages and request them from the
+ * interface.
+ */
+struct ipmi_smi_msg
+{
+	struct list_head link;
+
+	long    msgid;
+	void    *user_data;
+
+	/* If 0, add to the end of the queue.  If 1, add to the beginning. */
+	int     prio;
+
+	int           data_size;
+	unsigned char data[IPMI_MAX_MSG_LENGTH];
+
+	int           rsp_size;
+	unsigned char rsp[IPMI_MAX_MSG_LENGTH];
+
+	/* Will be called when the system is done with the message
+           (presumably to free it). */
+	void (*done)(struct ipmi_smi_msg *msg);
+};
+
+struct ipmi_smi_handlers
+{
+	/* Called to enqueue an SMI message to be sent.  This
+	   operation is not allowed to fail.  If an error occurs, it
+	   should report back the error in a received message.  It may
+	   do this in the current call context, since no write locks
+	   are held when this is run.  If the priority is > 0, the
+	   message will go into a high-priority queue and be sent
+	   first.  Otherwise, it goes into a normal-priority queue. */
+	void (*sender)(void                *send_info,
+		       struct ipmi_smi_msg *msg,
+		       int                 priority);
+
+	/* Called by the upper layer to request that we try to get
+	   events from the BMC we are attached to. */
+	void (*request_events)(void *send_info);
+
+	/* Called when someone is using the interface, so the module can
+	   adjust it's use count.  Return zero if successful, or an
+	   errno if not. */
+	int (*new_user)(void *send_info);
+
+	/* Called when someone is no longer using the interface, so the
+	   module can adjust it's use count. */
+	void (*user_left)(void *send_info);
+
+	/* Called when the interface should go into "run to
+	   completion" mode.  If this call sets the value to true, the
+	   interface should make sure that all messages are flushed
+	   out and that none are pending, and any new requests are run
+	   to completion immediately. */
+	void (*set_run_to_completion)(void *send_info, int run_to_completion);
+};
+
+/* Add a low-level interface to the IPMI driver. */
+int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
+		      void                     *send_info,
+		      unsigned char            version_major,
+		      unsigned char            version_minor,
+		      ipmi_smi_t               *intf);
+
+/*
+ * Remove a low-level interface from the IPMI driver.  This will
+ * return an error if the interface is still in use by a user.
+ */
+int ipmi_unregister_smi(ipmi_smi_t intf);
+
+/*
+ * The lower layer reports received messages through this interface.
+ * The data_size should be zero if this is an asyncronous message.  If
+ * the lower layer gets an error sending a message, it should format
+ * an error response in the message response.
+ */
+void ipmi_smi_msg_received(ipmi_smi_t          intf,
+			   struct ipmi_smi_msg *msg);
+
+/* The lower layer received a watchdog pre-timeout on interface. */
+void ipmi_smi_watchdog_pretimeout(ipmi_smi_t intf);
+
+struct ipmi_smi_msg *ipmi_alloc_smi_msg(void);
+static inline void ipmi_free_smi_msg(struct ipmi_smi_msg *msg)
+{
+	msg->done(msg);
+}
+
+#endif /* __LINUX_IPMI_SMI_H */
diff -urN linux-2.4.21-pre3/include/linux/msdos_fs.h linux-2.4.21-pre4/include/linux/msdos_fs.h
--- linux-2.4.21-pre3/include/linux/msdos_fs.h	Fri Oct 12 13:48:42 2001
+++ linux-2.4.21-pre4/include/linux/msdos_fs.h	Tue Jan 28 19:44:31 2003
@@ -70,9 +70,9 @@
 
 #define MSDOS_FAT12 4084 /* maximum number of clusters in a 12 bit FAT */
 
-#define EOF_FAT12 0xFF8		/* standard EOF */
-#define EOF_FAT16 0xFFF8
-#define EOF_FAT32 0xFFFFFF8
+#define EOF_FAT12 0xFFF		/* standard EOF */
+#define EOF_FAT16 0xFFFF
+#define EOF_FAT32 0xFFFFFFF
 #define EOF_FAT(s) (MSDOS_SB(s)->fat_bits == 32 ? EOF_FAT32 : \
 	MSDOS_SB(s)->fat_bits == 16 ? EOF_FAT16 : EOF_FAT12)
 
diff -urN linux-2.4.21-pre3/include/linux/mtd/cfi.h linux-2.4.21-pre4/include/linux/mtd/cfi.h
--- linux-2.4.21-pre3/include/linux/mtd/cfi.h	Thu Oct  4 15:13:18 2001
+++ linux-2.4.21-pre4/include/linux/mtd/cfi.h	Tue Jan 28 19:44:31 2003
@@ -1,7 +1,7 @@
 
 /* Common Flash Interface structures 
  * See http://support.intel.com/design/flash/technote/index.htm
- * $Id: cfi.h,v 1.25 2001/09/04 07:06:21 dwmw2 Exp $
+ * $Id: cfi.h,v 1.32 2002/09/05 05:15:32 acurtis Exp $
  */
 
 #ifndef __MTD_CFI_H__
@@ -18,13 +18,16 @@
  * You can optimize the code size and performance by defining only 
  * the geometry(ies) available on your hardware.
  * CFIDEV_INTERLEAVE_n, where  represents the interleave (number of chips to fill the bus width)
- * CFIDEV_BUSWIDTH_n, where n is the bus width in bytes (1, 2 or 4 bytes)
+ * CFIDEV_BUSWIDTH_n, where n is the bus width in bytes (1, 2, 4 or 8 bytes)
  *
  * By default, all (known) geometries are supported.
  */
 
 #ifndef CONFIG_MTD_CFI_GEOMETRY
 
+/* The default case - support all but 64-bit, which has
+   a performance penalty */
+
 #define CFIDEV_INTERLEAVE_1 (1)
 #define CFIDEV_INTERLEAVE_2 (2)
 #define CFIDEV_INTERLEAVE_4 (4)
@@ -33,8 +36,12 @@
 #define CFIDEV_BUSWIDTH_2 (2)
 #define CFIDEV_BUSWIDTH_4 (4)
 
+typedef __u32 cfi_word;
+
 #else
 
+/* Explicitly configured buswidth/interleave support */
+
 #ifdef CONFIG_MTD_CFI_I1
 #define CFIDEV_INTERLEAVE_1 (1)
 #endif
@@ -44,6 +51,9 @@
 #ifdef CONFIG_MTD_CFI_I4
 #define CFIDEV_INTERLEAVE_4 (4)
 #endif
+#ifdef CONFIG_MTD_CFI_I8
+#define CFIDEV_INTERLEAVE_8 (8)
+#endif
 
 #ifdef CONFIG_MTD_CFI_B1
 #define CFIDEV_BUSWIDTH_1 (1)
@@ -54,6 +64,27 @@
 #ifdef CONFIG_MTD_CFI_B4
 #define CFIDEV_BUSWIDTH_4 (4)
 #endif
+#ifdef CONFIG_MTD_CFI_B8
+#define CFIDEV_BUSWIDTH_8 (8)
+#endif
+
+/* pick the largest necessary */
+#ifdef CONFIG_MTD_CFI_B8
+typedef __u64 cfi_word;
+
+/* This only works if asm/io.h is included first */
+#ifndef __raw_readll
+#define __raw_readll(addr)	(*(volatile __u64 *)(addr))
+#endif
+#ifndef __raw_writell
+#define __raw_writell(v, addr)	(*(volatile __u64 *)(addr) = (v))
+#endif
+#define CFI_WORD_64
+#else  /* CONFIG_MTD_CFI_B8 */
+/* All others can use 32-bits. It's probably more efficient than
+   the smaller types anyway */
+typedef __u32 cfi_word;
+#endif /* CONFIG_MTD_CFI_B8 */
 
 #endif
 
@@ -61,12 +92,15 @@
  * The following macros are used to select the code to execute:
  *   cfi_buswidth_is_*()
  *   cfi_interleave_is_*()
- *   [where * is either 1, 2 or 4]
+ *   [where * is either 1, 2, 4, or 8]
  * Those macros should be used with 'if' statements.  If only one of few
  * geometry arrangements are selected, they expand to constants thus allowing
  * the compiler (most of them being 0) to optimize away all the unneeded code,
  * while still validating the syntax (which is not possible with embedded 
  * #if ... #endif constructs).
+ * The exception to this is the 64-bit versions, which need an extension
+ * to the cfi_word type, and cause compiler warnings about shifts being
+ * out of range.
  */
 
 #ifdef CFIDEV_INTERLEAVE_1
@@ -105,6 +139,18 @@
 # define cfi_interleave_is_4() (0)
 #endif
 
+#ifdef CFIDEV_INTERLEAVE_8
+# ifdef CFIDEV_INTERLEAVE
+#  undef CFIDEV_INTERLEAVE
+#  define CFIDEV_INTERLEAVE (cfi->interleave)
+# else
+#  define CFIDEV_INTERLEAVE CFIDEV_INTERLEAVE_8
+# endif
+# define cfi_interleave_is_8() (CFIDEV_INTERLEAVE == CFIDEV_INTERLEAVE_8)
+#else
+# define cfi_interleave_is_8() (0)
+#endif
+
 #ifndef CFIDEV_INTERLEAVE
 #error You must define at least one interleave to support!
 #endif
@@ -145,6 +191,18 @@
 # define cfi_buswidth_is_4() (0)
 #endif
 
+#ifdef CFIDEV_BUSWIDTH_8
+# ifdef CFIDEV_BUSWIDTH
+#  undef CFIDEV_BUSWIDTH
+#  define CFIDEV_BUSWIDTH (map->buswidth)
+# else
+#  define CFIDEV_BUSWIDTH CFIDEV_BUSWIDTH_8
+# endif
+# define cfi_buswidth_is_8() (CFIDEV_BUSWIDTH == CFIDEV_BUSWIDTH_8)
+#else
+# define cfi_buswidth_is_8() (0)
+#endif
+
 #ifndef CFIDEV_BUSWIDTH
 #error You must define at least one bus width to support!
 #endif
@@ -156,6 +214,7 @@
 #define CFI_DEVICETYPE_X8  (8 / 8)
 #define CFI_DEVICETYPE_X16 (16 / 8)
 #define CFI_DEVICETYPE_X32 (32 / 8)
+#define CFI_DEVICETYPE_X64 (64 / 8)
 
 /* NB: We keep these structures in memory in HOST byteorder, except
  * where individually noted.
@@ -206,6 +265,10 @@
   __u16 BlkStatusRegMask;
   __u8  VccOptimal;
   __u8  VppOptimal;
+  __u8  NumProtectionFields;
+  __u16 ProtRegAddr;
+  __u8  FactProtRegSize;
+  __u8  UserProtRegSize;
 } __attribute__((packed));
 
 struct cfi_pri_query {
@@ -229,8 +292,8 @@
 #define P_ID_RESERVED 65535
 
 
-#define CFI_MODE_CFI	0
-#define CFI_MODE_JEDEC	1
+#define CFI_MODE_CFI	1
+#define CFI_MODE_JEDEC	0
 
 struct cfi_private {
 	__u16 cmdset;
@@ -264,9 +327,9 @@
 /*
  * Transforms the CFI command for the given geometry (bus width & interleave.
  */
-static inline __u32 cfi_build_cmd(u_char cmd, struct map_info *map, struct cfi_private *cfi)
+static inline cfi_word cfi_build_cmd(u_char cmd, struct map_info *map, struct cfi_private *cfi)
 {
-	__u32 val = 0;
+	cfi_word val = 0;
 
 	if (cfi_buswidth_is_1()) {
 		/* 1 x8 device */
@@ -291,6 +354,27 @@
 			val = (cmd << 16) | cmd;
 			val = cpu_to_cfi32((val << 8) | val);
 		}
+#ifdef CFI_WORD_64
+	} else if (cfi_buswidth_is_8()) {
+		if (cfi_interleave_is_1()) {
+			/* 1 x64 device in x64 mode */
+			val = cpu_to_cfi64(cmd);
+		} else if (cfi_interleave_is_2()) {
+			/* 2 x32 device in x32 mode */
+			val = cmd;
+			val = cpu_to_cfi64((val << 32) | val);
+		} else if (cfi_interleave_is_4()) {
+			/* 4 (x16, x32 or x64) devices in x16 mode */
+			val = (cmd << 16) | cmd;
+			val = cpu_to_cfi64((val << 32) | val);
+		} else if (cfi_interleave_is_8()) {
+			/* 8 (x8, x16 or x32) devices in x8 mode */
+			val = (cmd << 8) | cmd;
+			val = (val << 16) | val;
+			val = (val << 32) | val;
+			val = cpu_to_cfi64(val);
+		}
+#endif /* CFI_WORD_64 */
 	}
 	return val;
 }
@@ -300,7 +384,7 @@
  * Read a value according to the bus width.
  */
 
-static inline __u32 cfi_read(struct map_info *map, __u32 addr)
+static inline cfi_word cfi_read(struct map_info *map, __u32 addr)
 {
 	if (cfi_buswidth_is_1()) {
 		return map->read8(map, addr);
@@ -308,6 +392,8 @@
 		return map->read16(map, addr);
 	} else if (cfi_buswidth_is_4()) {
 		return map->read32(map, addr);
+	} else if (cfi_buswidth_is_8()) {
+		return map->read64(map, addr);
 	} else {
 		return 0;
 	}
@@ -317,7 +403,7 @@
  * Write a value according to the bus width.
  */
 
-static inline void cfi_write(struct map_info *map, __u32 val, __u32 addr)
+static inline void cfi_write(struct map_info *map, cfi_word val, __u32 addr)
 {
 	if (cfi_buswidth_is_1()) {
 		map->write8(map, val, addr);
@@ -325,6 +411,8 @@
 		map->write16(map, val, addr);
 	} else if (cfi_buswidth_is_4()) {
 		map->write32(map, val, addr);
+	} else if (cfi_buswidth_is_8()) {
+		map->write64(map, val, addr);
 	}
 }
 
@@ -337,9 +425,9 @@
  */
 static inline __u32 cfi_send_gen_cmd(u_char cmd, __u32 cmd_addr, __u32 base,
 				struct map_info *map, struct cfi_private *cfi,
-				int type, __u32 *prev_val)
+				int type, cfi_word *prev_val)
 {
-	__u32 val;
+	cfi_word val;
 	__u32 addr = base + cfi_build_cmd_addr(cmd_addr, CFIDEV_INTERLEAVE, type);
 
 	val = cfi_build_cmd(cmd, map, cfi);
@@ -360,6 +448,8 @@
 		return cfi16_to_cpu(map->read16(map, addr));
 	} else if (cfi_buswidth_is_4()) {
 		return cfi32_to_cpu(map->read32(map, addr));
+	} else if (cfi_buswidth_is_8()) {
+		return cfi64_to_cpu(map->read64(map, addr));
 	} else {
 		return 0;
 	}
@@ -368,17 +458,17 @@
 static inline void cfi_udelay(int us)
 {
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-	if (current->need_resched) {
-		unsigned long t = us * HZ / 1000000;
-		if (t < 1)
-			t = 1;
+	unsigned long t = us * HZ / 1000000;
+	if (t) {
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		schedule_timeout(t);
+		return;
 	}
-	else
 #endif
-		udelay(us);
+	udelay(us);
+	cond_resched();
 }
+
 static inline void cfi_spin_lock(spinlock_t *mutex)
 {
 	spin_lock_bh(mutex);
diff -urN linux-2.4.21-pre3/include/linux/mtd/cfi_endian.h linux-2.4.21-pre4/include/linux/mtd/cfi_endian.h
--- linux-2.4.21-pre3/include/linux/mtd/cfi_endian.h	Thu Oct  4 15:13:18 2001
+++ linux-2.4.21-pre4/include/linux/mtd/cfi_endian.h	Tue Jan 28 19:44:31 2003
@@ -1,5 +1,5 @@
 /*
- * $Id: cfi_endian.h,v 1.10 2001/06/18 11:00:46 abz Exp $
+ * $Id: cfi_endian.h,v 1.11 2002/01/30 23:20:48 awozniak Exp $
  *
  */
 
@@ -30,22 +30,28 @@
 #define cfi8_to_cpu(x) (x)
 #define cpu_to_cfi16(x) cpu_to_le16(x)
 #define cpu_to_cfi32(x) cpu_to_le32(x)
+#define cpu_to_cfi64(x) cpu_to_le64(x)
 #define cfi16_to_cpu(x) le16_to_cpu(x)
 #define cfi32_to_cpu(x) le32_to_cpu(x)
+#define cfi64_to_cpu(x) le64_to_cpu(x)
 #elif defined (CFI_BIG_ENDIAN)
 #define cpu_to_cfi8(x) (x)
 #define cfi8_to_cpu(x) (x)
 #define cpu_to_cfi16(x) cpu_to_be16(x)
 #define cpu_to_cfi32(x) cpu_to_be32(x)
+#define cpu_to_cfi64(x) cpu_to_be64(x)
 #define cfi16_to_cpu(x) be16_to_cpu(x)
 #define cfi32_to_cpu(x) be32_to_cpu(x)
+#define cfi64_to_cpu(x) be64_to_cpu(x)
 #elif defined (CFI_HOST_ENDIAN)
 #define cpu_to_cfi8(x) (x)
 #define cfi8_to_cpu(x) (x)
 #define cpu_to_cfi16(x) (x)
 #define cpu_to_cfi32(x) (x)
+#define cpu_to_cfi64(x) (x)
 #define cfi16_to_cpu(x) (x)
 #define cfi32_to_cpu(x) (x)
+#define cfi64_to_cpu(x) (x)
 #else
 #error No CFI endianness defined
 #endif
diff -urN linux-2.4.21-pre3/include/linux/mtd/compatmac.h linux-2.4.21-pre4/include/linux/mtd/compatmac.h
--- linux-2.4.21-pre3/include/linux/mtd/compatmac.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.21-pre4/include/linux/mtd/compatmac.h	Tue Jan 28 19:44:31 2003
@@ -2,7 +2,7 @@
 /*
  * mtd/include/compatmac.h
  *
- * $Id: compatmac.h,v 1.4 2000/07/03 10:01:38 dwmw2 Exp $
+ * $Id: compatmac.h,v 1.45 2003/01/24 15:50:57 dwmw2 Exp $
  *
  * Extensions and omissions from the normal 'linux/compatmac.h'
  * files. hopefully this will end up empty as the 'real' one 
@@ -17,21 +17,158 @@
 #ifndef __LINUX_MTD_COMPATMAC_H__
 #define __LINUX_MTD_COMPATMAC_H__
 
-#include <linux/compatmac.h>
-#include <linux/types.h> /* used later in this header */
+#include <linux/config.h>
 #include <linux/module.h>
 #ifndef LINUX_VERSION_CODE
 #include <linux/version.h>
 #endif
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
-#include <linux/vmalloc.h>
+#ifndef VERSION_CODE
+#  define VERSION_CODE(vers,rel,seq) ( ((vers)<<16) | ((rel)<<8) | (seq) )
+#endif
+#ifndef KERNEL_VERSION
+#  define KERNEL_VERSION(a,b,c) VERSION_CODE(a,b,c)
 #endif
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,0,0)
 #  error "This kernel is too old: not supported by this file"
 #endif
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)
+#include <linux/types.h> /* used later in this header */
+
+#define memcpy_fromio(a,b,c)    memcpy((a),(void *)(b),(c))
+#define memcpy_toio(a,b,c)      memcpy((void *)(a),(b),(c))
+
+typedef struct wait_queue * wait_queue_head_t;
+
+#define DECLARE_WAITQUEUE(x,y) struct wait_queue x = {y,NULL}
+#define DECLARE_WAIT_QUEUE_HEAD(x) struct wait_queue *x = NULL
+#define init_waitqueue_head init_waitqueue
+#define DECLARE_MUTEX(x) struct semaphore x = MUTEX
+#define DECLARE_MUTEX_LOCKED(x) struct semaphore x = MUTEX_LOCKED
+
+/* from sysdep-2.1.h */
+#  include <asm/segment.h>
+#  define access_ok(t,a,sz)           (verify_area((t),(a),(sz)) ? 0 : 1)
+#  define verify_area_20              verify_area
+#  define copy_to_user(t,f,n)         (memcpy_tofs(t,f,n), 0)
+#  define __copy_to_user(t,f,n)       copy_to_user((t),(f),(n))
+#  define copy_to_user_ret(t,f,n,r)   copy_to_user((t),(f),(n))
+#  define copy_from_user(t,f,n)       (memcpy_fromfs((t),(f),(n)), 0)
+#  define __copy_from_user(t,f,n)     copy_from_user((t),(f),(n))
+#  define copy_from_user_ret(t,f,n,r) copy_from_user((t),(f),(n))
+//xxx #  define PUT_USER(val,add)           (put_user((val),(add)), 0)
+#  define Put_user(val,add)           (put_user((val),(add)), 0)
+#  define __PUT_USER(val,add)         PUT_USER((val),(add))
+#  define PUT_USER_RET(val,add,ret)   PUT_USER((val),(add))
+#  define GET_USER(dest,add)          ((dest)=get_user((add)), 0)
+#  define __GET_USER(dest,add)        GET_USER((dest),(add))
+#  define GET_USER_RET(dest,add,ret)  GET_USER((dest),(add))
+
+#define ioremap(offset,size) vremap(offset,size)
+#define iounmap(adr)	/* */
+
+#define EXPORT_SYMBOL(s) /* */
+#define EXPORT_SYMBOL_NOVERS(s) /* */
+
+/* 2.1.10 and 2.1.43 introduced new functions. They are worth using */
+
+#if LINUX_VERSION_CODE < VERSION_CODE(2,1,10)
+
+#  include <asm/byteorder.h>
+#  ifdef __LITTLE_ENDIAN
+#    define cpu_to_le16(x) (x)
+#    define cpu_to_le32(x) (x)
+#    define cpu_to_be16(x) htons((x))
+#    define cpu_to_be32(x) htonl((x))
+#  else
+#    define cpu_to_be16(x) (x)
+#    define cpu_to_be32(x) (x)
+     extern inline __u16 cpu_to_le16(__u16 x) { return (x<<8) | (x>>8);}
+     extern inline __u32 cpu_to_le32(__u32 x) { return((x>>24) |
+             ((x>>8)&0xff00) | ((x<<8)&0xff0000) | (x<<24));}
+#  endif
+
+#  define le16_to_cpu(x)  cpu_to_le16(x)
+#  define le32_to_cpu(x)  cpu_to_le32(x)
+#  define be16_to_cpu(x)  cpu_to_be16(x)
+#  define be32_to_cpu(x)  cpu_to_be32(x)
+
+#endif
+
+#if LINUX_VERSION_CODE < VERSION_CODE(2,1,43)
+#  define cpu_to_le16p(addr) (cpu_to_le16(*(addr)))
+#  define cpu_to_le32p(addr) (cpu_to_le32(*(addr)))
+#  define cpu_to_be16p(addr) (cpu_to_be16(*(addr)))
+#  define cpu_to_be32p(addr) (cpu_to_be32(*(addr)))
+
+   extern inline void cpu_to_le16s(__u16 *a) {*a = cpu_to_le16(*a);}
+   extern inline void cpu_to_le32s(__u16 *a) {*a = cpu_to_le32(*a);}
+   extern inline void cpu_to_be16s(__u16 *a) {*a = cpu_to_be16(*a);}
+   extern inline void cpu_to_be32s(__u16 *a) {*a = cpu_to_be32(*a);}
+
+#  define le16_to_cpup(x) cpu_to_le16p(x)
+#  define le32_to_cpup(x) cpu_to_le32p(x)
+#  define be16_to_cpup(x) cpu_to_be16p(x)
+#  define be32_to_cpup(x) cpu_to_be32p(x)
+
+#  define le16_to_cpus(x) cpu_to_le16s(x)
+#  define le32_to_cpus(x) cpu_to_le32s(x)
+#  define be16_to_cpus(x) cpu_to_be16s(x)
+#  define be32_to_cpus(x) cpu_to_be32s(x)
+#endif
+
+// from 2.2, linux/types.h
+#ifndef __BIT_TYPES_DEFINED__
+#define __BIT_TYPES_DEFINED__
+
+typedef         __u8            u_int8_t;
+typedef         __s8            int8_t;
+typedef         __u16           u_int16_t;
+typedef         __s16           int16_t;
+typedef         __u32           u_int32_t;
+typedef         __s32           int32_t;
+
+#endif /* !(__BIT_TYPES_DEFINED__) */
+
+#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)
+  typedef struct { } spinlock_t;
+  #define SPIN_LOCK_UNLOCKED (spinlock_t) { }
+#else
+  typedef struct { int gcc_is_buggy; } spinlock_t;
+  #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
+#endif
+
+#define spin_lock_init(lock)    do { } while(0)
+#define spin_lock(lock)         (void)(lock) /* Not "unused variable". */
+#define spin_trylock(lock)      (1)
+#define spin_unlock_wait(lock)  do { } while(0)
+#define spin_unlock(lock)       do { } while(0)
+#define spin_lock_irq(lock)     cli()
+#define spin_unlock_irq(lock)   sti()
+
+#define spin_lock_irqsave(lock, flags) \
+        do { save_flags(flags); cli(); } while (0)
+#define spin_unlock_irqrestore(lock, flags) \
+        restore_flags(flags)
+
+// Doesn't work when tqueue.h is included. 
+// #define queue_task                   queue_task_irq_off
+#define tty_flip_buffer_push(tty)    queue_task_irq_off(&tty->flip.tqueue, &tq_timer)
+#define signal_pending(current)      (current->signal & ~current->blocked)
+#define schedule_timeout(to)         do {current->timeout = jiffies + (to);schedule ();} while (0)
+#define time_after(t1,t2)            (((long)t1-t2) > 0)
+
+#else
+  #include <linux/compatmac.h>
+#endif  // LINUX_VERSION_CODE < 0x020100
+
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
+#include <linux/vmalloc.h>
+#endif
+
 /* Modularization issues */
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,18)
 #  define __USE_OLD_SYMTAB__
@@ -97,32 +234,60 @@
 #include <linux/init.h>
 #endif
 
-#if LINUX_VERSION_CODE < 0x20300
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)
 #define init_MUTEX(x) do {*(x) = MUTEX;} while (0)
+#define init_MUTEX_LOCKED(x) do {*(x) = MUTEX_LOCKED;} while (0)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
 #define RQFUNC_ARG void
 #define blkdev_dequeue_request(req) do {CURRENT = req->next;} while (0)
 #else
 #define RQFUNC_ARG request_queue_t *q
 #endif
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,32)
+#define blk_cleanup_queue(nr) do {blk_dev[nr].request_fn = 0;} while(0)
+#define BLK_DEFAULT_QUEUE(nr) (blk_dev[nr].request_fn)
+#define blk_init_queue(q, rq) do {q = rq;} while(0)
+#endif
+
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,0)
+#ifdef CONFIG_MODULES
 #define __MOD_INC_USE_COUNT(mod)                                        \
         (atomic_inc(&(mod)->uc.usecount), (mod)->flags |= MOD_VISITED|MOD_USED_ONCE)
 #define __MOD_DEC_USE_COUNT(mod)                                        \
         (atomic_dec(&(mod)->uc.usecount), (mod)->flags |= MOD_VISITED)
+#else
+#define __MOD_INC_USE_COUNT(mod)
+#define __MOD_DEC_USE_COUNT(mod)
+#endif
 #endif
 
 
+#ifndef HAVE_INTER_MODULE
+static inline void *inter_module_get(char *x) {return NULL;}
+static inline void *inter_module_get_request(char *x, char *y) {return NULL;}
+static inline void inter_module_put(const char *x) {}
+static inline void inter_module_register(const char *x, struct module *y, const void *z) {}
+static inline void inter_module_unregister(const char *x) {}
+#endif
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)
 
 #define DECLARE_WAIT_QUEUE_HEAD(x) struct wait_queue *x = NULL
 #define init_waitqueue_head init_waitqueue
 
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+
 static inline int try_inc_mod_count(struct module *mod)
 {
+#ifdef CONFIG_MODULES
 	if (mod)
 		__MOD_INC_USE_COUNT(mod);
+#endif
 	return 1;
 }
 #endif
@@ -190,13 +355,229 @@
 
 #if LINUX_VERSION_CODE < 0x20300
 #include <linux/interrupt.h>
-#define spin_lock_bh(lock) do {start_bh_atomic();spin_lock(lock);} while(0)
-#define spin_unlock_bh(lock) do {spin_unlock(lock);end_bh_atomic();} while(0)
+#define spin_lock_bh(lock) do {start_bh_atomic();spin_lock(lock);}while(0)
+#define spin_unlock_bh(lock) do {spin_unlock(lock);end_bh_atomic();}while(0)
 #else
 #include <asm/softirq.h>
 #include <linux/spinlock.h>
 #endif
 
-#endif /* __LINUX_MTD_COMPATMAC_H__ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)
+#define set_current_state(state_value)                        \
+        do { current->state = (state_value); } while (0)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,0) 
+static inline int invalidate_device(kdev_t dev, int do_sync) {
+
+	if (do_sync)
+		fsync_dev(dev);
+	
+	invalidate_buffers(dev);
+	return 0;
+}
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,4,5)
+static inline int invalidate_device(kdev_t dev, int do_sync) {
+	struct super_block *sb = get_super(dev);
+	int res = 0;
+
+	if (do_sync)
+		fsync_dev(dev);
+	
+	if (sb)
+		res = invalidate_inodes(sb);
+
+	invalidate_buffers(dev);
+	return res;
+}
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10)
+#undef min
+#undef max
+#undef min_t
+#undef max_t
+/*
+ * min()/max() macros that also do
+ * strict type-checking.. See the
+ * "unnecessary" pointer comparison.
+ */
+#define min(x,y) ({ \
+        const typeof(x) _x = (x);       \
+        const typeof(y) _y = (y);       \
+        (void) (&_x == &_y);            \
+        _x < _y ? _x : _y; })
+
+#define max(x,y) ({ \
+        const typeof(x) _x = (x);       \
+        const typeof(y) _y = (y);       \
+        (void) (&_x == &_y);            \
+        _x > _y ? _x : _y; })
+
+/*
+ * ..and if you can't take the strict
+ * types, you can specify one yourself.
+ *
+ * Or not use min/max at all, of course.
+ */
+#define min_t(type,x,y) \
+        ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
+#define max_t(type,x,y) \
+        ({ type __x = (x); type __y = (y); __x > __y ? __x: __y; })
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,7)
+struct completion {
+	struct semaphore s;
+};
+
+#define complete(c) up(&(c)->s)
+#define wait_for_completion(c) down(&(c)->s)
+#define init_completion(c) init_MUTEX_LOCKED(&(c)->s);
+
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,9)
+/* This came later */
+#define complete_and_exit(c, r) do { complete(c); do_exit(r); } while(0)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,9) || \
+    (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10) && !defined(__rh_config_h__))
+
+#include <linux/genhd.h>
 
+static inline void add_gendisk(struct gendisk *gp)
+{
+	gp->next = gendisk_head;
+	gendisk_head = gp;
+}
+
+static inline void del_gendisk(struct gendisk *gp)
+{
+	struct gendisk *gd, **gdp;
+
+	for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next))
+		if (*gdp == gp) {
+			gd = *gdp; *gdp = gd->next;
+			break;
+		}
+}
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18) && defined(MODULE)
+
+#define module_init(func)		\
+mod_init_t init_module(void) {		\
+	return func();			\
+}
+
+#define module_exit(func)		\
+mod_exit_t cleanup_module(void) {	\
+	return func();			\
+}
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,9) || \
+    (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10) && !defined(__rh_config_h__))
+#define MODULE_LICENSE(x) /* */
+#endif
 
+/* Removed for 2.4.21 kernel. This really should have been renamed
+   when it was changed -- this is a PITA */
+#if 0 && LINUX_VERSION_CODE < KERNEL_VERSION(2,5,5)
+#include <linux/sched.h>
+static inline void __recalc_sigpending(void)
+{
+	recalc_sigpending(current);
+}
+#undef recalc_sigpending
+#define recalc_sigpending() __recalc_sigpending ()
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,5)
+#define parent_ino(d) ((d)->d_parent->d_inode->i_ino)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,3)
+#define need_resched() (current->need_resched)
+#define cond_resched() do { if need_resched() schedule(); } while(0)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19)
+#ifndef yield
+#define yield() do { set_current_state(TASK_RUNNING); schedule(); } while(0)
+#endif
+#ifndef minor
+#define major(d) (MAJOR(to_kdev_t(d)))
+#define minor(d) (MINOR(to_kdev_t(d)))
+#endif
+#ifndef mk_kdev
+#define mk_kdev(ma,mi) MKDEV(ma,mi)
+#define kdev_t_to_nr(x)	(x)
+#endif
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
+	/* Is this right? */
+#define set_user_nice(tsk, n) do { (tsk)->priority = 20-(n); } while(0) 
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,4,21) && !defined(RED_HAT_LINUX_KERNEL)
+#define set_user_nice(tsk, n) do { (tsk)->nice = n; } while(0)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,21)
+#define rq_data_dir(x)	((x)->cmd)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+
+#define IS_REQ_CMD(req) (1)
+
+#define QUEUE_LOCK(q) (&io_request_lock)
+
+#define BLK_INIT_QUEUE(q, req, lock) blk_init_queue((q), (req)) 
+
+#else /* > 2.5.0 */
+
+#define IS_REQ_CMD(req) ((req)->flags & REQ_CMD)
+
+#define QUEUE_LOCK(q) ((q)->queue_lock)
+
+#define BLK_INIT_QUEUE(q, req, lock) blk_init_queue((q), (req), (lock)) 
+
+#endif
+
+/* Removed cos it broke stuff. Where is this required anyway? 
+ * #ifndef QUEUE_EMPTY
+ * #define QUEUE_EMPTY  (!CURRENT)
+ * #endif
+ */
+#if LINUX_VERSION_CODE < 0x20300
+#define QUEUE_PLUGGED (blk_dev[MAJOR_NR].plug_tq.sync)
+#elif LINUX_VERSION_CODE < 0x20500 //FIXME (Si)
+#define QUEUE_PLUGGED (blk_dev[MAJOR_NR].request_queue.plugged)
+#else
+#define QUEUE_PLUGGED (blk_queue_plugged(QUEUE))
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14)
+#define BLK_INC_USE_COUNT MOD_INC_USE_COUNT
+#define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT
+#else
+#define BLK_INC_USE_COUNT do {} while(0)
+#define BLK_DEC_USE_COUNT do {} while(0)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,12)
+#define PageUptodate(x) Page_Uptodate(x)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,48)
+#define get_seconds() CURRENT_TIME
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,53)
+#define generic_file_readonly_mmap generic_file_mmap
+#endif
+
+#endif /* __LINUX_MTD_COMPATMAC_H__ */
diff -urN linux-2.4.21-pre3/include/linux/mtd/flashchip.h linux-2.4.21-pre4/include/linux/mtd/flashchip.h
--- linux-2.4.21-pre3/include/linux/mtd/flashchip.h	Tue Jun 12 10:30:27 2001
+++ linux-2.4.21-pre4/include/linux/mtd/flashchip.h	Tue Jan 28 19:44:31 2003
@@ -6,7 +6,7 @@
  *
  * (C) 2000 Red Hat. GPLd.
  *
- * $Id: flashchip.h,v 1.7 2001/01/18 03:52:36 nico Exp $
+ * $Id: flashchip.h,v 1.8 2002/10/21 13:20:52 jocke Exp $
  *
  */
 
@@ -36,6 +36,7 @@
 	FL_UNLOADING,
 	FL_LOCKING,
 	FL_UNLOCKING,
+	FL_POINT,
 	FL_UNKNOWN
 } flstate_t;
 
@@ -54,6 +55,7 @@
 	   a given offset, and we'll want to add the per-chip length field
 	   back in.
 	*/
+	int ref_point_counter;
 	flstate_t state;
 	flstate_t oldstate;
 	spinlock_t *mutex;
diff -urN linux-2.4.21-pre3/include/linux/mtd/ftl.h linux-2.4.21-pre4/include/linux/mtd/ftl.h
--- linux-2.4.21-pre3/include/linux/mtd/ftl.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/linux/mtd/ftl.h	Tue Jan 28 19:44:31 2003
@@ -1,5 +1,5 @@
 /*
- * $Id: ftl.h,v 1.5 2001/06/02 20:35:51 dwmw2 Exp $
+ * $Id: ftl.h,v 1.6 2003/01/24 13:20:04 dwmw2 Exp $
  * 
  * Derived from (and probably identical to):
  * ftl.h 1.7 1999/10/25 20:23:17
diff -urN linux-2.4.21-pre3/include/linux/mtd/map.h linux-2.4.21-pre4/include/linux/mtd/map.h
--- linux-2.4.21-pre3/include/linux/mtd/map.h	Thu Oct  4 15:13:18 2001
+++ linux-2.4.21-pre4/include/linux/mtd/map.h	Tue Jan 28 19:44:31 2003
@@ -1,6 +1,6 @@
 
 /* Overhauled routines for dealing with different mmap regions of flash */
-/* $Id: map.h,v 1.25 2001/09/09 15:04:17 dwmw2 Exp $ */
+/* $Id: map.h,v 1.29 2002/10/21 13:20:52 jocke Exp $ */
 
 #ifndef __LINUX_MTD_MAP_H__
 #define __LINUX_MTD_MAP_H__
@@ -33,6 +33,7 @@
 	__u8 (*read8)(struct map_info *, unsigned long);
 	__u16 (*read16)(struct map_info *, unsigned long);
 	__u32 (*read32)(struct map_info *, unsigned long);  
+	__u64 (*read64)(struct map_info *, unsigned long);  
 	/* If it returned a 'long' I'd call it readl.
 	 * It doesn't.
 	 * I won't.
@@ -42,8 +43,12 @@
 	void (*write8)(struct map_info *, __u8, unsigned long);
 	void (*write16)(struct map_info *, __u16, unsigned long);
 	void (*write32)(struct map_info *, __u32, unsigned long);
+	void (*write64)(struct map_info *, __u64, unsigned long);
 	void (*copy_to)(struct map_info *, unsigned long, const void *, ssize_t);
 
+	u_char * (*point) (struct map_info *, loff_t, size_t);
+	void (*unpoint) (struct map_info *, u_char *, loff_t, size_t);
+
 	void (*set_vpp)(struct map_info *, int);
 	/* We put these two here rather than a single void *map_priv, 
 	   because we want mappers to be able to have quickly-accessible
@@ -68,7 +73,7 @@
 void register_mtd_chip_driver(struct mtd_chip_driver *);
 void unregister_mtd_chip_driver(struct mtd_chip_driver *);
 
-struct mtd_info *do_map_probe(char *name, struct map_info *map);
+struct mtd_info *do_map_probe(const char *name, struct map_info *map);
 
 
 /*
diff -urN linux-2.4.21-pre3/include/linux/mtd/mtd.h linux-2.4.21-pre4/include/linux/mtd/mtd.h
--- linux-2.4.21-pre3/include/linux/mtd/mtd.h	Tue Jun 12 10:30:27 2001
+++ linux-2.4.21-pre4/include/linux/mtd/mtd.h	Tue Jan 28 19:44:31 2003
@@ -1,5 +1,5 @@
 
-/* $Id: mtd.h,v 1.33 2001/06/09 00:08:59 dwmw2 Exp $ */
+/* $Id: mtd.h,v 1.38 2003/01/12 16:30:19 spse Exp $ */
 
 #ifndef __MTD_MTD_H__
 #define __MTD_MTD_H__
@@ -93,6 +93,8 @@
 #define MEMUNLOCK               _IOW('M', 6, struct erase_info_user)
 #define MEMGETREGIONCOUNT	_IOR('M', 7, int)
 #define MEMGETREGIONINFO	_IOWR('M', 8, struct region_info_user)
+#define	MEMREADDATA             _IOWR('M', 9, struct mtd_oob_buf)
+#define	MEMWRITEDATA            _IOWR('M', 10, struct mtd_oob_buf)
 
 #ifndef __KERNEL__
 
@@ -168,25 +170,41 @@
 	int (*point) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf);
 
 	/* We probably shouldn't allow XIP if the unpoint isn't a NULL */
-	void (*unpoint) (struct mtd_info *mtd, u_char * addr);
+	void (*unpoint) (struct mtd_info *mtd, u_char * addr, loff_t from, size_t len);
 
 
 	int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
 	int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
 
-	int (*read_ecc) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, u_char *eccbuf);
-	int (*write_ecc) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf);
+	int (*read_ecc) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, u_char *eccbuf, int oobsel);
+	int (*write_ecc) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf, int oobsel);
 
 	int (*read_oob) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
 	int (*write_oob) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
 
+	/* 
+	 * Methods to access the protection register area, present in some 
+	 * flash devices. The user data is one time programmable but the
+	 * factory data is read only. 
+	 */
+	int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
+
+	int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
+
+	/* This function is not yet implemented */
+	int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
+
 	/* iovec-based read/write methods. We need these especially for NAND flash,
 	   with its limited number of write cycles per erase.
 	   NB: The 'count' parameter is the number of _vectors_, each of 
 	   which contains an (ofs, len) tuple.
 	*/
 	int (*readv) (struct mtd_info *mtd, struct iovec *vecs, unsigned long count, loff_t from, size_t *retlen);
+	int (*readv_ecc) (struct mtd_info *mtd, struct iovec *vecs, unsigned long count, loff_t from, 
+		size_t *retlen, u_char *eccbuf, int oobsel);
 	int (*writev) (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to, size_t *retlen);
+	int (*writev_ecc) (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to, 
+		size_t *retlen, u_char *eccbuf, int oobsel);
 
 	/* Sync */
 	void (*sync) (struct mtd_info *mtd);
@@ -239,6 +257,11 @@
 extern void register_mtd_user (struct mtd_notifier *new);
 extern int unregister_mtd_user (struct mtd_notifier *old);
 
+int default_mtd_writev(struct mtd_info *mtd, const struct iovec *vecs,
+		       unsigned long count, loff_t to, size_t *retlen);
+
+int default_mtd_readv(struct mtd_info *mtd, struct iovec *vecs,
+		      unsigned long count, loff_t from, size_t *retlen);
 
 #ifndef MTDC
 #define MTD_ERASE(mtd, args...) (*(mtd->erase))(mtd, args)
diff -urN linux-2.4.21-pre3/include/linux/mtd/nand.h linux-2.4.21-pre4/include/linux/mtd/nand.h
--- linux-2.4.21-pre3/include/linux/mtd/nand.h	Mon Dec 11 14:57:58 2000
+++ linux-2.4.21-pre4/include/linux/mtd/nand.h	Tue Jan 28 19:44:31 2003
@@ -3,8 +3,9 @@
  *
  *  Copyright (c) 2000 David Woodhouse <dwmw2@mvhi.com>
  *                     Steven J. Hill <sjhill@cotw.com>
+ *		       Thomas Gleixner <tglx@linutronix.de>
  *
- * $Id: nand.h,v 1.8 2000/10/30 17:16:17 sjhill Exp $
+ * $Id: nand.h,v 1.19 2002/12/02 21:48:17 gleixner Exp $
  *
  * 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
@@ -23,6 +24,26 @@
  *			bat later if I did something naughty.
  *   10-11-2000 SJH     Added private NAND flash structure for driver
  *   10-24-2000 SJH     Added prototype for 'nand_scan' function
+ *   10-29-2001 TG	changed nand_chip structure to support 
+ *			hardwarespecific function for accessing control lines
+ *   02-21-2002 TG	added support for different read/write adress and
+ *			ready/busy line access function
+ *   02-26-2002 TG	added chip_delay to nand_chip structure to optimize
+ *			command delay times for different chips
+ *   04-28-2002 TG	OOB config defines moved from nand.c to avoid duplicate
+ *			defines in jffs2/wbuf.c
+ *   08-07-2002 TG	forced bad block location to byte 5 of OOB, even if
+ *			CONFIG_MTD_NAND_ECC_JFFS2 is not set
+ *   08-10-2002 TG	extensions to nand_chip structure to support HW-ECC
+ *
+ *   08-29-2002 tglx 	nand_chip structure: data_poi for selecting 
+ *			internal / fs-driver buffer
+ *			support for 6byte/512byte hardware ECC
+ *			read_ecc, write_ecc extended for different oob-layout
+ *			oob layout selections: NAND_NONE_OOB, NAND_JFFS2_OOB,
+ *			NAND_YAFFS_OOB
+ *  11-25-2002 tglx	Added Manufacturer code FUJITSU, NATIONAL
+ *			Split manufacturer and device ID structures 
  */
 #ifndef __LINUX_MTD_NAND_H
 #define __LINUX_MTD_NAND_H
@@ -36,6 +57,16 @@
 extern int nand_scan (struct mtd_info *mtd);
 
 /*
+ * Constants for hardware specific CLE/ALE/NCE function
+*/
+#define NAND_CTL_SETNCE 	1
+#define NAND_CTL_CLRNCE		2
+#define NAND_CTL_SETCLE		3
+#define NAND_CTL_CLRCLE		4
+#define NAND_CTL_SETALE		5
+#define NAND_CTL_CLRALE		6
+
+/*
  * Standard NAND flash commands
  */
 #define NAND_CMD_READ0		0
@@ -49,6 +80,29 @@
 #define NAND_CMD_ERASE2		0xd0
 #define NAND_CMD_RESET		0xff
 
+/* 
+ * Constants for ECC_MODES
+ *
+ * NONE:	No ECC
+ * SOFT:	Software ECC 3 byte ECC per 256 Byte data
+ * HW3_256:	Hardware ECC 3 byte ECC per 256 Byte data
+ * HW3_512:	Hardware ECC 3 byte ECC per 512 Byte data
+ *
+ *
+*/
+#define NAND_ECC_NONE		0
+#define NAND_ECC_SOFT		1
+#define NAND_ECC_HW3_256	2
+#define NAND_ECC_HW3_512	3
+#define NAND_ECC_HW6_512	4
+#define NAND_ECC_DISKONCHIP	5
+
+/*
+ * Constants for Hardware ECC
+*/
+#define NAND_ECC_READ		0
+#define NAND_ECC_WRITE		1
+	
 /*
  * Enumeration for NAND flash chip state
  */
@@ -60,20 +114,33 @@
 	FL_SYNCING
 } nand_state_t;
 
+
 /*
  * NAND Private Flash Chip Data
  *
  * Structure overview:
  *
- *  IO_ADDR - address to access the 8 I/O lines to the flash device
+ *  IO_ADDR_R - address to read the 8 I/O lines of the flash device 
+ *
+ *  IO_ADDR_W - address to write the 8 I/O lines of the flash device 
+ *
+ *  hwcontrol - hardwarespecific function for accesing control-lines
  *
- *  CTRL_ADDR - address where ALE, CLE and CE control bits are accessed
+ *  dev_ready - hardwarespecific function for accesing device ready/busy line
  *
- *  CLE - location in control word for Command Latch Enable bit
+ *  waitfunc - hardwarespecific function for wait on ready
  *
- *  ALE - location in control word for Address Latch Enable bit
+ *  calculate_ecc - function for ecc calculation or readback from ecc hardware
  *
- *  NCE - location in control word for nChip Enable bit
+ *  correct_data - function for ecc correction, matching to ecc generator (sw/hw)
+ *
+ *  enable_hwecc - function to enable (reset) hardware ecc generator
+ *
+ *  eccmod - mode of ecc: see constants
+ *
+ *  eccsize - databytes used per ecc-calculation
+ *
+ *  chip_delay - chip dependent delay for transfering data from array to read regs (tR)
  *
  *  chip_lock - spinlock used to protect access to this structure
  *
@@ -85,27 +152,32 @@
  *
  *  data_buf - data buffer passed to/from MTD user modules
  *
- *  ecc_code_buf - used only for holding calculated or read ECCs for
- *                 a page read or written when ECC is in use
+ *  data_cache - data cache for redundant page access and shadow for
+ *		 ECC failure
  *
- *  reserved - padding to make structure fall on word boundary if
- *             when ECC is in use
+ *  cache_page - number of last valid page in page_cache 
  */
 struct nand_chip {
-	unsigned long IO_ADDR;
-	unsigned long CTRL_ADDR;
-	unsigned int CLE;
-	unsigned int ALE;
-	unsigned int NCE;
-	spinlock_t chip_lock;
+	unsigned long 	IO_ADDR_R;
+	unsigned long 	IO_ADDR_W;
+	void 		(*hwcontrol)(int cmd);
+	int  		(*dev_ready)(void);
+	void 		(*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr);
+	int 		(*waitfunc)(struct mtd_info *mtd, struct nand_chip *this, int state);
+	void		(*calculate_ecc)(const u_char *dat, u_char *ecc_code);
+	int 		(*correct_data)(u_char *dat, u_char *read_ecc, u_char *calc_ecc);
+	void		(*enable_hwecc)(int mode);
+	int		eccmode;
+	int		eccsize;
+	int 		chip_delay;
+	spinlock_t 	chip_lock;
 	wait_queue_head_t wq;
-	nand_state_t state;
-	int page_shift;
-	u_char *data_buf;
-#ifdef CONFIG_MTD_NAND_ECC
-	u_char ecc_code_buf[6];
-	u_char reserved[2];
-#endif
+	nand_state_t 	state;
+	int 		page_shift;
+	u_char 		*data_buf;
+	u_char		*data_poi;
+	u_char 		*data_cache;
+	int		cache_page;
 };
 
 /*
@@ -113,17 +185,17 @@
  */
 #define NAND_MFR_TOSHIBA	0x98
 #define NAND_MFR_SAMSUNG	0xec
+#define NAND_MFR_FUJITSU	0x04
+#define NAND_MFR_NATIONAL	0x8f
 
 /*
  * NAND Flash Device ID Structure
  *
  * Structure overview:
  *
- *  name - Complete name of device
+ *  name - Identify the device type
  *
- *  manufacture_id - manufacturer ID code of device.
- *
- *  model_id - model ID code of device.
+ *  id -  device ID code
  *
  *  chipshift - total number of address bits for the device which
  *              is used to calculate address offsets and the total
@@ -143,12 +215,60 @@
  */
 struct nand_flash_dev {
 	char * name;
-	int manufacture_id;
-	int model_id;
+	int id;
 	int chipshift;
-	char page256;
-	char pageadrlen;
 	unsigned long erasesize;
+	char page256;
 };
 
+/*
+ * NAND Flash Manufacturer ID Structure
+ *
+ *  name - Manufacturer name
+ *
+ *  id - manufacturer ID code of device.
+*/
+struct nand_manufacturers {
+	int id;
+	char * name;
+};
+
+extern struct nand_flash_dev nand_flash_ids[];
+extern struct nand_manufacturers nand_manuf_ids[];
+
+/*
+* Constants for oob configuration
+*/
+#define NAND_BADBLOCK_POS		5
+
+#define NAND_NONE_OOB			0
+#define NAND_JFFS2_OOB			1
+#define NAND_YAFFS_OOB			2
+
+#define NAND_NOOB_ECCPOS0		0
+#define NAND_NOOB_ECCPOS1		1
+#define NAND_NOOB_ECCPOS2		2
+#define NAND_NOOB_ECCPOS3		3
+#define NAND_NOOB_ECCPOS4		6
+#define NAND_NOOB_ECCPOS5		7
+
+#define NAND_JFFS2_OOB_ECCPOS0		0
+#define NAND_JFFS2_OOB_ECCPOS1		1
+#define NAND_JFFS2_OOB_ECCPOS2		2
+#define NAND_JFFS2_OOB_ECCPOS3		3
+#define NAND_JFFS2_OOB_ECCPOS4		6
+#define NAND_JFFS2_OOB_ECCPOS5		7
+
+#define NAND_YAFFS_OOB_ECCPOS0		8
+#define NAND_YAFFS_OOB_ECCPOS1		9
+#define NAND_YAFFS_OOB_ECCPOS2		10
+#define NAND_YAFFS_OOB_ECCPOS3		13
+#define NAND_YAFFS_OOB_ECCPOS4		14
+#define NAND_YAFFS_OOB_ECCPOS5		15
+
+#define NAND_JFFS2_OOB8_FSDAPOS		6
+#define NAND_JFFS2_OOB16_FSDAPOS	8
+#define NAND_JFFS2_OOB8_FSDALEN		2
+#define NAND_JFFS2_OOB16_FSDALEN	8
+
 #endif /* __LINUX_MTD_NAND_H */
diff -urN linux-2.4.21-pre3/include/linux/mtd/nftl.h linux-2.4.21-pre4/include/linux/mtd/nftl.h
--- linux-2.4.21-pre3/include/linux/mtd/nftl.h	Tue Jun 12 10:30:27 2001
+++ linux-2.4.21-pre4/include/linux/mtd/nftl.h	Tue Jan 28 19:44:31 2003
@@ -2,7 +2,7 @@
 /* Defines for NAND Flash Translation Layer  */
 /* (c) 1999 Machine Vision Holdings, Inc.    */
 /* Author: David Woodhouse <dwmw2@mvhi.com>  */
-/* $Id: nftl.h,v 1.10 2000/12/29 00:25:38 dwmw2 Exp $ */
+/* $Id: nftl.h,v 1.11 2002/06/18 13:54:24 dwmw2 Exp $ */
 
 #ifndef __MTD_NFTL_H__
 #define __MTD_NFTL_H__
@@ -97,7 +97,7 @@
 	__u16 lastEUN;                  /* should be suppressed */
 	__u16 numfreeEUNs;
 	__u16 LastFreeEUN; 		/* To speed up finding a free EUN */
-	__u32 long nr_sects;
+	__u32 nr_sects;
 	int head,sect,cyl;
 	__u16 *EUNtable; 		/* [numvunits]: First EUN for each virtual unit  */
 	__u16 *ReplUnitTable; 		/* [numEUNs]: ReplUnitNumber for each */
diff -urN linux-2.4.21-pre3/include/linux/mtd/pmc551.h linux-2.4.21-pre4/include/linux/mtd/pmc551.h
--- linux-2.4.21-pre3/include/linux/mtd/pmc551.h	Thu Oct  4 15:13:18 2001
+++ linux-2.4.21-pre4/include/linux/mtd/pmc551.h	Tue Jan 28 19:44:31 2003
@@ -1,5 +1,5 @@
 /*
- * $Id: pmc551.h,v 1.4 2001/06/12 16:19:38 major Exp $
+ * $Id: pmc551.h,v 1.5 2003/01/24 16:49:53 dwmw2 Exp $
  *
  * PMC551 PCI Mezzanine Ram Device
  *
@@ -17,7 +17,7 @@
 
 #include <linux/mtd/mtd.h>
 
-#define PMC551_VERSION "$Id: pmc551.h,v 1.4 2001/06/12 16:19:38 major Exp $\n"\
+#define PMC551_VERSION "$Id: pmc551.h,v 1.5 2003/01/24 16:49:53 dwmw2 Exp $\n"\
        "Ramix PMC551 PCI Mezzanine Ram Driver. (C) 1999,2000 Nortel Networks.\n"
 
 /*
@@ -36,7 +36,7 @@
  * Function Prototypes
  */
 static int pmc551_erase(struct mtd_info *, struct erase_info *);
-static void pmc551_unpoint(struct mtd_info *, u_char *);
+static void pmc551_unpoint(struct mtd_info *, u_char *, loff_t, size_t);
 static int pmc551_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf);
 static int pmc551_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *);
 static int pmc551_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);        
diff -urN linux-2.4.21-pre3/include/linux/netfilter_ipv4/ip_nat_helper.h linux-2.4.21-pre4/include/linux/netfilter_ipv4/ip_nat_helper.h
--- linux-2.4.21-pre3/include/linux/netfilter_ipv4/ip_nat_helper.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/linux/netfilter_ipv4/ip_nat_helper.h	Tue Jan 28 19:44:31 2003
@@ -50,6 +50,13 @@
 				unsigned int match_len,
 				char *rep_buffer,
 				unsigned int rep_len);
+extern int ip_nat_mangle_udp_packet(struct sk_buff **skb,
+				struct ip_conntrack *ct,
+				enum ip_conntrack_info ctinfo,
+				unsigned int match_offset,
+				unsigned int match_len,
+				char *rep_buffer,
+				unsigned int rep_len);
 extern int ip_nat_seq_adjust(struct sk_buff *skb,
 				struct ip_conntrack *ct,
 				enum ip_conntrack_info ctinfo);
diff -urN linux-2.4.21-pre3/include/linux/nubus.h linux-2.4.21-pre4/include/linux/nubus.h
--- linux-2.4.21-pre3/include/linux/nubus.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/linux/nubus.h	Tue Jan 28 19:44:31 2003
@@ -28,18 +28,18 @@
 };
 
 enum nubus_type_network {
-	NUBUS_TYPE_ETHERNET = 0x0001,
-	NUBUS_TYPE_RS232    = 0x0002
+	NUBUS_TYPE_ETHERNET 	 = 0x0001,
+	NUBUS_TYPE_RS232    	 = 0x0002
 };
 
 enum nubus_type_display {
-	NUBUS_TYPE_VIDEO = 0x0001
+	NUBUS_TYPE_VIDEO 	 = 0x0001
 };
 
 enum nubus_type_cpu {
-	NUBUS_TYPE_68020 = 0x0003,
-	NUBUS_TYPE_68030 = 0x0004,
-	NUBUS_TYPE_68040 = 0x0005
+	NUBUS_TYPE_68020 	 = 0x0003,
+	NUBUS_TYPE_68030 	 = 0x0004,
+	NUBUS_TYPE_68040 	 = 0x0005
 };
 
 /* Known <Cat,Type,SW,HW> tuples: (according to TattleTech and Slots)
@@ -80,22 +80,24 @@
 /* Add known DrSW values here */
 enum nubus_drsw {
 	/* NUBUS_CAT_DISPLAY */
-	NUBUS_DRSW_APPLE       = 0x0001,
-	NUBUS_DRSW_APPLE_HIRES = 0x0013, /* MacII HiRes card driver */
+	NUBUS_DRSW_APPLE       	= 0x0001,
+	NUBUS_DRSW_APPLE_HIRES 	= 0x0013, /* MacII HiRes card driver */
 	
 	/* NUBUS_CAT_NETWORK */
-	NUBUS_DRSW_CABLETRON        = 0x0001,
-	NUBUS_DRSW_SONIC_LC         = 0x0001,
-	NUBUS_DRSW_KINETICS         = 0x0103,
-	NUBUS_DRSW_ASANTE           = 0x0104,
-	NUBUS_DRSW_DAYNA            = 0x010b,
-	NUBUS_DRSW_FARALLON         = 0x010c,
-	NUBUS_DRSW_APPLE_SN         = 0x010f,
-	NUBUS_DRSW_FOCUS            = 0x011a,
-	NUBUS_DRSW_ASANTE_CS        = 0x011d, /* use asante SMC9194 driver */
+	NUBUS_DRSW_CABLETRON   	= 0x0001,
+	NUBUS_DRSW_SONIC_LC    	= 0x0001,
+	NUBUS_DRSW_KINETICS    	= 0x0103,
+	NUBUS_DRSW_ASANTE      	= 0x0104,
+	NUBUS_DRSW_DAYNA       	= 0x010b,
+	NUBUS_DRSW_FARALLON    	= 0x010c,
+	NUBUS_DRSW_APPLE_SN    	= 0x010f,
+	NUBUS_DRSW_DAYNA2	= 0x0115,
+	NUBUS_DRSW_FOCUS        = 0x011a,
+	NUBUS_DRSW_ASANTE_CS    = 0x011d, /* use asante SMC9194 driver */
+	NUBUS_DRSW_DAYNA_LC	= 0x011e,
 
 	/* NUBUS_CAT_CPU */
-	NUBUS_DRSW_NONE        = 0x0000,
+	NUBUS_DRSW_NONE        	= 0x0000,
 };
 
 /* DrHW: Uniquely identifies the hardware interface to a board (or at
@@ -106,11 +108,13 @@
 enum nubus_drhw {
 	/* NUBUS_CAT_DISPLAY */
 	NUBUS_DRHW_APPLE_TFB	= 0x0001, /* Toby frame buffer card */
+	NUBUS_DRHW_APPLE_HRVC	= 0x0013, /* Mac II High Res Video card */
 	NUBUS_DRHW_APPLE_RBV1   = 0x0018, /* IIci RBV video */
 	NUBUS_DRHW_APPLE_MDC    = 0x0019, /* Macintosh Display Card */
 	NUBUS_DRHW_APPLE_SONORA = 0x0022, /* Sonora built-in video */
+	NUBUS_DRHW_APPLE_JET 	= 0x0029, /* Jet framebuffer (DuoDock) */
 	NUBUS_DRHW_APPLE_VALKYRIE = 0x002e,
-	NUBUS_DRHW_APPLE_JET =    0x0029, /* Jet framebuffer (DuoDock) */
+	NUBUS_DRHW_THUNDER24	= 0x02cb, /* SuperMac Thunder/24 */
 	
 	/* NUBUS_CAT_NETWORK */
 	NUBUS_DRHW_INTERLAN     = 0x0100,
@@ -119,6 +123,11 @@
 	NUBUS_DRHW_CABLETRON    = 0x0109,
 	NUBUS_DRHW_ASANTE_LC    = 0x010f,
 	NUBUS_DRHW_SONIC        = 0x0110,
+	NUBUS_DRHW_SONIC_NB	= 0x0118,
+	NUBUS_DRHW_SONIC_LC	= 0x0119,
+	
+	/* NUBUS_CAT_COMMUNICATIONS */
+	NUBUS_DRHW_DOVEFAX	= 0x0100,
 };
 
 /* Resource IDs: These are the identifiers for the various weird and
@@ -153,8 +162,8 @@
 	NUBUS_RESID_SECONDINIT	 = 0x0026,
 
 	/* Not sure why Apple put these next two in here */
-	NUBUS_RESID_VIDNAMES = 0x0041,
-	NUBUS_RESID_VIDMODES = 0x007e
+	NUBUS_RESID_VIDNAMES 	 = 0x0041,
+	NUBUS_RESID_VIDMODES 	 = 0x007e
 };
 
 /* Fields within the vendor info directory */
diff -urN linux-2.4.21-pre3/include/linux/pci_ids.h linux-2.4.21-pre4/include/linux/pci_ids.h
--- linux-2.4.21-pre3/include/linux/pci_ids.h	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/include/linux/pci_ids.h	Tue Jan 28 19:44:31 2003
@@ -900,6 +900,7 @@
 #define PCI_DEVICE_ID_NVIDIA_UTNT2		0x0029
 #define PCI_DEVICE_ID_NVIDIA_VTNT2		0x002C
 #define PCI_DEVICE_ID_NVIDIA_UVTNT2		0x002D
+#define PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE	0x0065
 #define PCI_DEVICE_ID_NVIDIA_ITNT2		0x00A0
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE_SDR	0x0100
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE_DDR	0x0101
diff -urN linux-2.4.21-pre3/include/linux/prctl.h linux-2.4.21-pre4/include/linux/prctl.h
--- linux-2.4.21-pre3/include/linux/prctl.h	Mon Feb 25 11:38:13 2002
+++ linux-2.4.21-pre4/include/linux/prctl.h	Tue Jan 28 19:44:31 2003
@@ -26,4 +26,12 @@
 # define PR_FPEMU_NOPRINT	1	/* silently emulate fp operations accesses */
 # define PR_FPEMU_SIGFPE	2	/* don't emulate fp operations, send SIGFPE instead */
 
+/* Get/set floating-point exception mode (if meaningful) */
+#define PR_GET_FPEXC	11
+#define PR_SET_FPEXC	12
+# define PR_FP_EXC_DISABLED	0	/* FP exceptions disabled */
+# define PR_FP_EXC_NONRECOV	1	/* async non-recoverable exc. mode */
+# define PR_FP_EXC_ASYNC	2	/* async recoverable exception mode */
+# define PR_FP_EXC_PRECISE	3	/* precise exception mode */
+
 #endif /* _LINUX_PRCTL_H */
diff -urN linux-2.4.21-pre3/include/linux/reiserfs_fs.h linux-2.4.21-pre4/include/linux/reiserfs_fs.h
--- linux-2.4.21-pre3/include/linux/reiserfs_fs.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/include/linux/reiserfs_fs.h	Tue Jan 28 19:44:31 2003
@@ -1748,11 +1748,12 @@
 struct inode * reiserfs_iget (struct super_block * s, 
 			      const struct cpu_key * key);
 
-
-struct inode * reiserfs_new_inode (struct reiserfs_transaction_handle *th, 
-				   struct inode * dir, int mode, 
-				   const char * symname, int item_len,
-				   struct dentry *dentry, struct inode *inode, int * err);
+int reiserfs_new_inode (struct reiserfs_transaction_handle *th,
+                               struct inode * dir, int mode,
+                               const char * symname,
+                               int i_size,
+                               struct dentry *dentry,
+                               struct inode *inode);
 int reiserfs_sync_inode (struct reiserfs_transaction_handle *th, struct inode * inode);
 void reiserfs_update_sd (struct reiserfs_transaction_handle *th, struct inode * inode);
 
diff -urN linux-2.4.21-pre3/include/linux/sonypi.h linux-2.4.21-pre4/include/linux/sonypi.h
--- linux-2.4.21-pre3/include/linux/sonypi.h	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/include/linux/sonypi.h	Tue Jan 28 19:44:31 2003
@@ -43,9 +43,9 @@
 #define SONYPI_EVENT_JOGDIAL_DOWN_PRESSED	 3
 #define SONYPI_EVENT_JOGDIAL_UP_PRESSED		 4
 #define SONYPI_EVENT_JOGDIAL_PRESSED		 5
-#define SONYPI_EVENT_JOGDIAL_RELEASED		 6
+#define SONYPI_EVENT_JOGDIAL_RELEASED		 6	/* obsolete */
 #define SONYPI_EVENT_CAPTURE_PRESSED		 7
-#define SONYPI_EVENT_CAPTURE_RELEASED		 8
+#define SONYPI_EVENT_CAPTURE_RELEASED		 8	/* obsolete */
 #define SONYPI_EVENT_CAPTURE_PARTIALPRESSED	 9
 #define SONYPI_EVENT_CAPTURE_PARTIALRELEASED	10
 #define SONYPI_EVENT_FNKEY_ESC			11
@@ -93,6 +93,7 @@
 #define SONYPI_EVENT_MEYE_OPPOSITE		53
 #define SONYPI_EVENT_MEMORYSTICK_INSERT		54
 #define SONYPI_EVENT_MEMORYSTICK_EJECT		55
+#define SONYPI_EVENT_ANYBUTTON_RELEASED		56
 
 /* get/set brightness */
 #define SONYPI_IOCGBRT		_IOR('v', 0, __u8)
diff -urN linux-2.4.21-pre3/include/linux/sysctl.h linux-2.4.21-pre4/include/linux/sysctl.h
--- linux-2.4.21-pre3/include/linux/sysctl.h	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/include/linux/sysctl.h	Tue Jan 28 19:44:31 2003
@@ -294,7 +294,8 @@
 	NET_IPV4_ICMP_RATELIMIT=89,
 	NET_IPV4_ICMP_RATEMASK=90,
 	NET_TCP_TW_REUSE=91,
-	NET_TCP_FRTO=92
+	NET_TCP_FRTO=92,
+	NET_TCP_LOW_LATENCY=93
 };
 
 enum {
diff -urN linux-2.4.21-pre3/include/linux/usb_scanner_ioctl.h linux-2.4.21-pre4/include/linux/usb_scanner_ioctl.h
--- linux-2.4.21-pre3/include/linux/usb_scanner_ioctl.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre4/include/linux/usb_scanner_ioctl.h	Tue Jan 28 19:44:31 2003
@@ -0,0 +1,9 @@
+/* USB Scanner IOCTLS */
+
+/* read vendor and product IDs from the scanner */
+#define SCANNER_IOCTL_VENDOR _IOR('U', 0x20, int)
+#define SCANNER_IOCTL_PRODUCT _IOR('U', 0x21, int)
+/* send/recv a control message to the scanner */
+#define SCANNER_IOCTL_CTRLMSG _IOWR('U', 0x22, struct usb_ctrlrequest )
+
+
diff -urN linux-2.4.21-pre3/include/net/tcp.h linux-2.4.21-pre4/include/net/tcp.h
--- linux-2.4.21-pre3/include/net/tcp.h	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/include/net/tcp.h	Tue Jan 28 19:44:31 2003
@@ -461,6 +461,7 @@
 extern int sysctl_tcp_adv_win_scale;
 extern int sysctl_tcp_tw_reuse;
 extern int sysctl_tcp_frto;
+extern int sysctl_tcp_low_latency;
 
 extern atomic_t tcp_memory_allocated;
 extern atomic_t tcp_sockets_allocated;
@@ -1327,7 +1328,7 @@
 {
 	struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
 
-	if (tp->ucopy.task) {
+	if (!sysctl_tcp_low_latency && tp->ucopy.task) {
 		__skb_queue_tail(&tp->ucopy.prequeue, skb);
 		tp->ucopy.memory += skb->truesize;
 		if (tp->ucopy.memory > sk->rcvbuf) {
diff -urN linux-2.4.21-pre3/init/do_mounts.c linux-2.4.21-pre4/init/do_mounts.c
--- linux-2.4.21-pre3/init/do_mounts.c	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/init/do_mounts.c	Tue Jan 28 19:44:31 2003
@@ -593,7 +593,7 @@
 		rd_blocks >>= 1;
 
 	if (nblocks > rd_blocks) {
-		printk("RAMDISK: image too big! (%d/%d blocks)\n",
+		printk("RAMDISK: image too big! (%d/%lu blocks)\n",
 		       nblocks, rd_blocks);
 		goto done;
 	}
@@ -620,11 +620,11 @@
 		goto done;
 	}
 
-	printk(KERN_NOTICE "RAMDISK: Loading %d blocks [%d disk%s] into ram disk... ", 
+	printk(KERN_NOTICE "RAMDISK: Loading %d blocks [%ld disk%s] into ram disk... ", 
 		nblocks, ((nblocks-1)/devblocks)+1, nblocks>devblocks ? "s" : "");
 	for (i=0; i < nblocks; i++) {
 		if (i && (i % devblocks == 0)) {
-			printk("done disk #%d.\n", i/devblocks);
+			printk("done disk #%ld.\n", i/devblocks);
 			rotate = 0;
 			if (close(in_fd)) {
 				printk("Error closing the disk.\n");
@@ -636,7 +636,7 @@
 				printk("Error opening disk.\n");
 				goto noclose_input;
 			}
-			printk("Loading disk #%d... ", i/devblocks+1);
+			printk("Loading disk #%ld... ", i/devblocks+1);
 		}
 		read(in_fd, buf, BLOCK_SIZE);
 		write(out_fd, buf, BLOCK_SIZE);
diff -urN linux-2.4.21-pre3/kernel/printk.c linux-2.4.21-pre4/kernel/printk.c
--- linux-2.4.21-pre3/kernel/printk.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.21-pre4/kernel/printk.c	Tue Jan 28 19:44:31 2003
@@ -629,7 +629,7 @@
 	}
 	if (console->flags & CON_PRINTBUFFER) {
 		/*
-		 * release_cosole_sem() will print out the buffered messages for us.
+		 * release_console_sem() will print out the buffered messages for us.
 		 */
 		spin_lock_irqsave(&logbuf_lock, flags);
 		con_start = log_start;
diff -urN linux-2.4.21-pre3/kernel/sys.c linux-2.4.21-pre4/kernel/sys.c
--- linux-2.4.21-pre3/kernel/sys.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.21-pre4/kernel/sys.c	Tue Jan 28 19:44:31 2003
@@ -18,6 +18,25 @@
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
+#ifndef SET_UNALIGN_CTL
+# define SET_UNALIGN_CTL(a,b)	(-EINVAL)
+#endif
+#ifndef GET_UNALIGN_CTL
+# define GET_UNALIGN_CTL(a,b)	(-EINVAL)
+#endif
+#ifndef SET_FPEMU_CTL
+# define SET_FPEMU_CTL(a,b)	(-EINVAL)
+#endif
+#ifndef GET_FPEMU_CTL
+# define GET_FPEMU_CTL(a,b)	(-EINVAL)
+#endif
+#ifndef SET_FPEXC_CTL
+# define SET_FPEXC_CTL(a,b)	(-EINVAL)
+#endif
+#ifndef GET_FPEXC_CTL
+# define GET_FPEXC_CTL(a,b)	(-EINVAL)
+#endif
+
 /*
  * this is where the system-wide overflow UID and GID are defined, for
  * architectures that now have 32-bit UID/GID but didn't in the past
@@ -1229,36 +1248,24 @@
 			}
 			current->mm->dumpable = arg2;
 			break;
+
 	        case PR_SET_UNALIGN:
-#ifdef SET_UNALIGN_CTL
 			error = SET_UNALIGN_CTL(current, arg2);
-#else
-			error = -EINVAL;
-#endif
 			break;
-
 	        case PR_GET_UNALIGN:
-#ifdef GET_UNALIGN_CTL
 			error = GET_UNALIGN_CTL(current, arg2);
-#else
-			error = -EINVAL;
-#endif
 			break;
-
 	        case PR_SET_FPEMU:
-#ifdef SET_FPEMU_CTL
 			error = SET_FPEMU_CTL(current, arg2);
-#else
-			error = -EINVAL;
-#endif
 			break;
-
 	        case PR_GET_FPEMU:
-#ifdef GET_FPEMU_CTL
 			error = GET_FPEMU_CTL(current, arg2);
-#else
-			error = -EINVAL;
-#endif
+			break;
+		case PR_SET_FPEXC:
+			error = SET_FPEXC_CTL(current, arg2);
+			break;
+		case PR_GET_FPEXC:
+			error = GET_FPEXC_CTL(current, arg2);
 			break;
 
 		case PR_GET_KEEPCAPS:
diff -urN linux-2.4.21-pre3/mm/filemap.c linux-2.4.21-pre4/mm/filemap.c
--- linux-2.4.21-pre3/mm/filemap.c	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/mm/filemap.c	Tue Jan 28 19:44:31 2003
@@ -1572,7 +1572,7 @@
 	chunk_size = KIO_MAX_ATOMIC_IO << 10;
 
 	retval = -EINVAL;
-	if ((offset & blocksize_mask) || (count & blocksize_mask))
+	if ((offset & blocksize_mask) || (count & blocksize_mask) || ((unsigned long) buf & blocksize_mask))
 		goto out_free;
 	if (!mapping->a_ops->direct_IO)
 		goto out_free;
diff -urN linux-2.4.21-pre3/mm/slab.c linux-2.4.21-pre4/mm/slab.c
--- linux-2.4.21-pre3/mm/slab.c	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/mm/slab.c	Tue Jan 28 19:44:31 2003
@@ -1949,8 +1949,12 @@
 	name = cachep->name; 
 	{
 	char tmp; 
+	mm_segment_t	old_fs;
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
 	if (__get_user(tmp, name)) 
 		name = "broken"; 
+	set_fs(old_fs);
 	}       
 
 	seq_printf(m, "%-17s %6lu %6lu %6u %4lu %4lu %4u",
diff -urN linux-2.4.21-pre3/net/bluetooth/hci_sock.c linux-2.4.21-pre4/net/bluetooth/hci_sock.c
--- linux-2.4.21-pre3/net/bluetooth/hci_sock.c	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/net/bluetooth/hci_sock.c	Tue Jan 28 19:44:31 2003
@@ -73,7 +73,7 @@
 		/* OGF_LINK_POLICY */
 		{ 0x1200, 0x0, 0x0, 0x0     },
 		/* OGF_HOST_CTL */
-		{ 0x80100000, 0xa, 0x0, 0x0 },
+		{ 0x80100000, 0x2a, 0x0, 0x0 },
 		/* OGF_INFO_PARAM */
 		{ 0x22a, 0x0, 0x0, 0x0      }
 	}
diff -urN linux-2.4.21-pre3/net/bluetooth/rfcomm/tty.c linux-2.4.21-pre4/net/bluetooth/rfcomm/tty.c
--- linux-2.4.21-pre3/net/bluetooth/rfcomm/tty.c	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/net/bluetooth/rfcomm/tty.c	Tue Jan 28 19:44:31 2003
@@ -257,7 +257,7 @@
 
 static struct sk_buff *rfcomm_wmalloc(struct rfcomm_dev *dev, unsigned long size, int priority)
 {
-	if (size || atomic_read(&dev->wmem_alloc) < dev->sndbuf) {
+	if (atomic_read(&dev->wmem_alloc) < dev->sndbuf) {
 		struct sk_buff *skb = alloc_skb(size, priority);
 		if (skb) {
 			rfcomm_set_owner_w(skb, dev);
diff -urN linux-2.4.21-pre3/net/bluetooth/sco.c linux-2.4.21-pre4/net/bluetooth/sco.c
--- linux-2.4.21-pre3/net/bluetooth/sco.c	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/net/bluetooth/sco.c	Tue Jan 28 19:44:31 2003
@@ -678,7 +678,7 @@
 		
 		opts.mtu = sco_pi(sk)->conn->mtu;
 
-		BT_INFO("mtu %d", opts.mtu);
+		BT_DBG("mtu %d", opts.mtu);
 
 		len = MIN(len, sizeof(opts));
 		if (copy_to_user(optval, (char *)&opts, len))
diff -urN linux-2.4.21-pre3/net/ipv4/netfilter/ip_conntrack_core.c linux-2.4.21-pre4/net/ipv4/netfilter/ip_conntrack_core.c
--- linux-2.4.21-pre3/net/ipv4/netfilter/ip_conntrack_core.c	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/net/ipv4/netfilter/ip_conntrack_core.c	Tue Jan 28 19:44:31 2003
@@ -966,23 +966,28 @@
 		   related_to->expecting >= related_to->helper->max_expected) {
 		struct list_head *cur_item;
 		/* old == NULL */
-	    	if (net_ratelimit())
-		    	printk(KERN_WARNING 
-		    	       "ip_conntrack: max number of expected "
-			       "connections %i of %s reached for "
-			       "%u.%u.%u.%u->%u.%u.%u.%u%s\n",
-		    	       related_to->helper->max_expected, 
-		    	       related_to->helper->name,
-		    	       NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip),
-		    	       NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip),
-		    	       related_to->helper->flags & IP_CT_HELPER_F_REUSE_EXPECT ?
-		    	       ", reusing" : "");
 		if (!(related_to->helper->flags & 
 		      IP_CT_HELPER_F_REUSE_EXPECT)) {
 			WRITE_UNLOCK(&ip_conntrack_lock);
+ 		    	if (net_ratelimit())
+ 			    	printk(KERN_WARNING
+				       "ip_conntrack: max number of expected "
+				       "connections %i of %s reached for "
+				       "%u.%u.%u.%u->%u.%u.%u.%u\n",
+				       related_to->helper->max_expected,
+				       related_to->helper->name,
+ 		    	       	       NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip),
+ 		    	       	       NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip));
 			return -EPERM;
 		}
-
+		DEBUGP("ip_conntrack: max number of expected "
+		       "connections %i of %s reached for "
+		       "%u.%u.%u.%u->%u.%u.%u.%u, reusing\n",
+ 		       related_to->helper->max_expected,
+		       related_to->helper->name,
+		       NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip),
+		       NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip));
+ 
 		/* choose the the oldest expectation to evict */
 		list_for_each(cur_item, &related_to->sibling_list) { 
 			struct ip_conntrack_expect *cur;
diff -urN linux-2.4.21-pre3/net/ipv4/netfilter/ip_conntrack_ftp.c linux-2.4.21-pre4/net/ipv4/netfilter/ip_conntrack_ftp.c
--- linux-2.4.21-pre3/net/ipv4/netfilter/ip_conntrack_ftp.c	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/net/ipv4/netfilter/ip_conntrack_ftp.c	Tue Jan 28 19:44:31 2003
@@ -200,9 +200,9 @@
 
 		DEBUGP("ftp: string mismatch\n");
 		for (i = 0; i < plen; i++) {
-			DEBUGFTP("ftp:char %u `%c'(%u) vs `%c'(%u)\n",
-				 i, data[i], data[i],
-				 pattern[i], pattern[i]);
+			DEBUGP("ftp:char %u `%c'(%u) vs `%c'(%u)\n",
+				i, data[i], data[i],
+				pattern[i], pattern[i]);
 		}
 #endif
 		return 0;
diff -urN linux-2.4.21-pre3/net/ipv4/netfilter/ip_conntrack_proto_tcp.c linux-2.4.21-pre4/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
--- linux-2.4.21-pre3/net/ipv4/netfilter/ip_conntrack_proto_tcp.c	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/net/ipv4/netfilter/ip_conntrack_proto_tcp.c	Tue Jan 28 19:44:31 2003
@@ -186,13 +186,13 @@
 	    && tcph->syn && tcph->ack)
 		conntrack->proto.tcp.handshake_ack
 			= htonl(ntohl(tcph->seq) + 1);
-	WRITE_UNLOCK(&tcp_lock);
 
 	/* If only reply is a RST, we can consider ourselves not to
 	   have an established connection: this is a fairly common
 	   problem case, so we can delete the conntrack
 	   immediately.  --RR */
 	if (!(conntrack->status & IPS_SEEN_REPLY) && tcph->rst) {
+		WRITE_UNLOCK(&tcp_lock);
 		if (del_timer(&conntrack->timeout))
 			conntrack->timeout.function((unsigned long)conntrack);
 	} else {
@@ -203,6 +203,7 @@
 		    && tcph->ack_seq == conntrack->proto.tcp.handshake_ack)
 			set_bit(IPS_ASSURED_BIT, &conntrack->status);
 
+		WRITE_UNLOCK(&tcp_lock);
 		ip_ct_refresh(conntrack, tcp_timeouts[newconntrack]);
 	}
 
diff -urN linux-2.4.21-pre3/net/ipv4/netfilter/ip_nat_helper.c linux-2.4.21-pre4/net/ipv4/netfilter/ip_nat_helper.c
--- linux-2.4.21-pre3/net/ipv4/netfilter/ip_nat_helper.c	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/net/ipv4/netfilter/ip_nat_helper.c	Tue Jan 28 19:44:31 2003
@@ -8,6 +8,9 @@
  *		- add support for SACK adjustment 
  *	14 Mar 2002 Harald Welte <laforge@gnumonks.org>:
  *		- merge SACK support into newnat API
+ *	16 Aug 2002 Brian J. Murrell <netfilter@interlinx.bc.ca>:
+ *		- make ip_nat_resize_packet more generic (TCP and UDP)
+ *		- add ip_nat_mangle_udp_packet
  */
 #include <linux/version.h>
 #include <linux/config.h>
@@ -22,6 +25,7 @@
 #include <net/icmp.h>
 #include <net/ip.h>
 #include <net/tcp.h>
+#include <net/udp.h>
 
 #define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_nat_lock)
 #define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_nat_lock)
@@ -51,18 +55,12 @@
 		     int new_size)
 {
 	struct iphdr *iph;
-	struct tcphdr *tcph;
-	void *data;
 	int dir;
 	struct ip_nat_seq *this_way, *other_way;
 
 	DEBUGP("ip_nat_resize_packet: old_size = %u, new_size = %u\n",
 		(*skb)->len, new_size);
 
-	iph = (*skb)->nh.iph;
-	tcph = (void *)iph + iph->ihl*4;
-	data = (void *)tcph + tcph->doff*4;
-
 	dir = CTINFO2DIR(ctinfo);
 
 	this_way = &ct->nat.info.seq[dir];
@@ -84,37 +82,41 @@
 	}
 
 	iph = (*skb)->nh.iph;
-	tcph = (void *)iph + iph->ihl*4;
-	data = (void *)tcph + tcph->doff*4;
-
-	DEBUGP("ip_nat_resize_packet: Seq_offset before: ");
-	DUMP_OFFSET(this_way);
+	if (iph->protocol == IPPROTO_TCP) {
+		struct tcphdr *tcph = (void *)iph + iph->ihl*4;
+		void *data = (void *)tcph + tcph->doff*4;
+
+		DEBUGP("ip_nat_resize_packet: Seq_offset before: ");
+		DUMP_OFFSET(this_way);
+
+		LOCK_BH(&ip_nat_seqofs_lock);
+
+		/* SYN adjust. If it's uninitialized, of this is after last 
+		 * correction, record it: we don't handle more than one 
+		 * adjustment in the window, but do deal with common case of a 
+		 * retransmit */
+		if (this_way->offset_before == this_way->offset_after
+		    || before(this_way->correction_pos, ntohl(tcph->seq))) {
+			this_way->correction_pos = ntohl(tcph->seq);
+			this_way->offset_before = this_way->offset_after;
+			this_way->offset_after = (int32_t)
+				this_way->offset_before + new_size -
+				(*skb)->len;
+		}
 
-	LOCK_BH(&ip_nat_seqofs_lock);
+		UNLOCK_BH(&ip_nat_seqofs_lock);
 
-	/* SYN adjust. If it's uninitialized, of this is after last 
-	 * correction, record it: we don't handle more than one 
-	 * adjustment in the window, but do deal with common case of a 
-	 * retransmit */
-	if (this_way->offset_before == this_way->offset_after
-	    || before(this_way->correction_pos, ntohl(tcph->seq))) {
-		this_way->correction_pos = ntohl(tcph->seq);
-		this_way->offset_before = this_way->offset_after;
-		this_way->offset_after = (int32_t)
-			this_way->offset_before + new_size - (*skb)->len;
+		DEBUGP("ip_nat_resize_packet: Seq_offset after: ");
+		DUMP_OFFSET(this_way);
 	}
-
-	UNLOCK_BH(&ip_nat_seqofs_lock);
-
-	DEBUGP("ip_nat_resize_packet: Seq_offset after: ");
-	DUMP_OFFSET(this_way);
 	
 	return 1;
 }
 
 
 /* Generic function for mangling variable-length address changes inside
- * NATed connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX command in FTP).
+ * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX
+ * command in FTP).
  *
  * Takes care about all the nasty sequence number changes, checksumming,
  * skb enlargement, ...
@@ -174,10 +176,11 @@
 	tcph = (void *)iph + iph->ihl*4;
 	data = (void *)tcph + tcph->doff*4;
 
-	/* move post-replacement */
-	memmove(data + match_offset + rep_len,
-		 data + match_offset + match_len,
-		 (*skb)->tail - (data + match_offset + match_len));
+	if (rep_len != match_len)
+		/* move post-replacement */
+		memmove(data + match_offset + rep_len,
+			data + match_offset + match_len,
+			(*skb)->tail - (data + match_offset + match_len));
 
 	/* insert data from buffer */
 	memcpy(data + match_offset, rep_buffer, rep_len);
@@ -206,6 +209,114 @@
 	ip_send_check(iph);
 
 	return 1;
+}
+			
+/* Generic function for mangling variable-length address changes inside
+ * NATed UDP connections (like the CONNECT DATA XXXXX MESG XXXXX INDEX XXXXX
+ * command in the Amanda protocol)
+ *
+ * Takes care about all the nasty sequence number changes, checksumming,
+ * skb enlargement, ...
+ *
+ * XXX - This function could be merged with ip_nat_mangle_tcp_packet which
+ *       should be fairly easy to do.
+ */
+int 
+ip_nat_mangle_udp_packet(struct sk_buff **skb,
+			 struct ip_conntrack *ct,
+			 enum ip_conntrack_info ctinfo,
+			 unsigned int match_offset,
+			 unsigned int match_len,
+			 char *rep_buffer,
+			 unsigned int rep_len)
+{
+	struct iphdr *iph = (*skb)->nh.iph;
+	struct udphdr *udph = (void *)iph + iph->ihl * 4;
+	unsigned char *data;
+	u_int32_t udplen, newlen, newudplen;
+
+	udplen = (*skb)->len - iph->ihl*4;
+	newudplen = udplen - match_len + rep_len;
+	newlen = iph->ihl*4 + newudplen;
+
+	if (newlen > 65535) {
+		if (net_ratelimit())
+			printk("ip_nat_mangle_udp_packet: nat'ed packet "
+				"exceeds maximum packet size\n");
+		return 0;
+	}
+
+	if ((*skb)->len != newlen) {
+		if (!ip_nat_resize_packet(skb, ct, ctinfo, newlen)) {
+			printk("resize_packet failed!!\n");
+			return 0;
+		}
+	}
+
+	/* Alexey says: if a hook changes _data_ ... it can break
+	   original packet sitting in tcp queue and this is fatal */
+	if (skb_cloned(*skb)) {
+		struct sk_buff *nskb = skb_copy(*skb, GFP_ATOMIC);
+		if (!nskb) {
+			if (net_ratelimit())
+				printk("Out of memory cloning TCP packet\n");
+			return 0;
+		}
+		/* Rest of kernel will get very unhappy if we pass it
+		   a suddenly-orphaned skbuff */
+		if ((*skb)->sk)
+			skb_set_owner_w(nskb, (*skb)->sk);
+		kfree_skb(*skb);
+		*skb = nskb;
+	}
+
+	/* skb may be copied !! */
+	iph = (*skb)->nh.iph;
+	udph = (void *)iph + iph->ihl*4;
+	data = (void *)udph + sizeof(struct udphdr);
+
+	if (rep_len != match_len)
+		/* move post-replacement */
+		memmove(data + match_offset + rep_len,
+			data + match_offset + match_len,
+			(*skb)->tail - (data + match_offset + match_len));
+
+	/* insert data from buffer */
+	memcpy(data + match_offset, rep_buffer, rep_len);
+
+	/* update skb info */
+	if (newlen > (*skb)->len) {
+		DEBUGP("ip_nat_mangle_udp_packet: Extending packet by "
+			"%u to %u bytes\n", newlen - (*skb)->len, newlen);
+		skb_put(*skb, newlen - (*skb)->len);
+	} else {
+		DEBUGP("ip_nat_mangle_udp_packet: Shrinking packet from "
+			"%u to %u bytes\n", (*skb)->len, newlen);
+		skb_trim(*skb, newlen);
+	}
+
+	/* update the length of the UDP and IP packets to the new values*/
+	udph->len = htons((*skb)->len - iph->ihl*4);
+	iph->tot_len = htons(newlen);
+
+	/* fix udp checksum if udp checksum was previously calculated */
+	if ((*skb)->csum != 0) {
+		(*skb)->csum = csum_partial((char *)udph +
+					    sizeof(struct udphdr),
+					    newudplen - sizeof(struct udphdr),
+					    0);
+
+		udph->check = 0;
+		udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr,
+						newudplen, IPPROTO_UDP,
+						csum_partial((char *)udph,
+							 sizeof(struct udphdr),
+							(*skb)->csum));
+	}
+
+	ip_send_check(iph);
+
+	return 1;
 }
 
 /* Adjust one found SACK option including checksum correction */
diff -urN linux-2.4.21-pre3/net/ipv4/netfilter/ip_nat_standalone.c linux-2.4.21-pre4/net/ipv4/netfilter/ip_nat_standalone.c
--- linux-2.4.21-pre3/net/ipv4/netfilter/ip_nat_standalone.c	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/net/ipv4/netfilter/ip_nat_standalone.c	Tue Jan 28 19:44:31 2003
@@ -358,5 +358,6 @@
 EXPORT_SYMBOL(ip_nat_helper_unregister);
 EXPORT_SYMBOL(ip_nat_cheat_check);
 EXPORT_SYMBOL(ip_nat_mangle_tcp_packet);
+EXPORT_SYMBOL(ip_nat_mangle_udp_packet);
 EXPORT_SYMBOL(ip_nat_used_tuple);
 MODULE_LICENSE("GPL");
diff -urN linux-2.4.21-pre3/net/ipv4/netfilter/ipt_ECN.c linux-2.4.21-pre4/net/ipv4/netfilter/ipt_ECN.c
--- linux-2.4.21-pre3/net/ipv4/netfilter/ipt_ECN.c	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/net/ipv4/netfilter/ipt_ECN.c	Tue Jan 28 19:44:31 2003
@@ -87,8 +87,8 @@
 	}
 	
 	if (diffs[0] != *tcpflags) {
-		diffs[0] = htons(diffs[0]) ^ 0xFFFF;
-		diffs[1] = htons(*tcpflags);
+		diffs[0] = diffs[0] ^ 0xFFFF;
+		diffs[1] = *tcpflags;
 		tcph->check = csum_fold(csum_partial((char *)diffs,
 		                                    sizeof(diffs),
 		                                    tcph->check^0xFFFF));
diff -urN linux-2.4.21-pre3/net/ipv4/netfilter/ipt_REJECT.c linux-2.4.21-pre4/net/ipv4/netfilter/ipt_REJECT.c
--- linux-2.4.21-pre3/net/ipv4/netfilter/ipt_REJECT.c	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/net/ipv4/netfilter/ipt_REJECT.c	Tue Jan 28 19:44:31 2003
@@ -6,6 +6,8 @@
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/ip.h>
+#include <linux/udp.h>
+#include <linux/icmp.h>
 #include <net/icmp.h>
 #include <net/ip.h>
 #include <net/tcp.h>
@@ -157,6 +159,7 @@
 static void send_unreach(struct sk_buff *skb_in, int code)
 {
 	struct iphdr *iph;
+	struct udphdr *udph;
 	struct icmphdr *icmph;
 	struct sk_buff *nskb;
 	u32 saddr;
@@ -186,6 +189,19 @@
 	if (iph->frag_off&htons(IP_OFFSET))
 		return;
 
+	/* if UDP checksum is set, verify it's correct */
+	if (iph->protocol == IPPROTO_UDP
+	    && skb_in->tail-(u8*)iph >= sizeof(struct udphdr)) {
+		int datalen = skb_in->len - (iph->ihl<<2);
+		udph = (struct udphdr *)((char *)iph + (iph->ihl<<2));
+		if (udph->check
+		    && csum_tcpudp_magic(iph->saddr, iph->daddr,
+		                         datalen, IPPROTO_UDP,
+		                         csum_partial((char *)udph, datalen,
+		                                      0)) != 0)
+			return;
+	}
+		    
 	/* If we send an ICMP error to an ICMP error a mess would result.. */
 	if (iph->protocol == IPPROTO_ICMP
 	    && skb_in->tail-(u8*)iph >= sizeof(struct icmphdr)) {
diff -urN linux-2.4.21-pre3/net/ipv4/netfilter/ipt_ULOG.c linux-2.4.21-pre4/net/ipv4/netfilter/ipt_ULOG.c
--- linux-2.4.21-pre3/net/ipv4/netfilter/ipt_ULOG.c	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre4/net/ipv4/netfilter/ipt_ULOG.c	Tue Jan 28 19:44:31 2003
@@ -12,6 +12,7 @@
  * 	      module loadtime -HW
  * 2002/07/07 remove broken nflog_rcv() function -HW
  * 2002/08/29 fix shifted/unshifted nlgroup bug -HW
+ * 2002/10/30 fix uninitialized mac_len field - <Anders K. Pedersen>
  *
  * Released under the terms of the GPL
  *
@@ -31,7 +32,7 @@
  *   Specify, after how many clock ticks (intel: 100 per second) the queue
  * should be flushed even if it is not full yet.
  *
- * ipt_ULOG.c,v 1.21 2002/08/29 10:54:34 laforge Exp
+ * ipt_ULOG.c,v 1.22 2002/10/30 09:07:31 laforge Exp
  */
 
 #include <linux/module.h>
@@ -224,7 +225,8 @@
 	    && in->hard_header_len <= ULOG_MAC_LEN) {
 		memcpy(pm->mac, (*pskb)->mac.raw, in->hard_header_len);
 		pm->mac_len = in->hard_header_len;
-	}
+	} else
+		pm->mac_len = 0;
 
 	if (in)
 		strncpy(pm->indev_name, in->name, sizeof(pm->indev_name));
diff -urN linux-2.4.21-pre3/net/ipv4/netfilter/ipt_multiport.c linux-2.4.21-pre4/net/ipv4/netfilter/ipt_multiport.c
--- linux-2.4.21-pre3/net/ipv4/netfilter/ipt_multiport.c	Sun Sep 30 12:26:08 2001
+++ linux-2.4.21-pre4/net/ipv4/netfilter/ipt_multiport.c	Tue Jan 28 19:44:31 2003
@@ -78,7 +78,7 @@
 
 	/* Must specify proto == TCP/UDP, no unknown flags or bad count */
 	return (ip->proto == IPPROTO_TCP || ip->proto == IPPROTO_UDP)
-		&& !(ip->flags & IPT_INV_PROTO)
+		&& !(ip->invflags & IPT_INV_PROTO)
 		&& matchsize == IPT_ALIGN(sizeof(struct ipt_multiport))
 		&& (multiinfo->flags == IPT_MULTIPORT_SOURCE
 		    || multiinfo->flags == IPT_MULTIPORT_DESTINATION
diff -urN linux-2.4.21-pre3/net/ipv4/sysctl_net_ipv4.c linux-2.4.21-pre4/net/ipv4/sysctl_net_ipv4.c
--- linux-2.4.21-pre3/net/ipv4/sysctl_net_ipv4.c	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/net/ipv4/sysctl_net_ipv4.c	Tue Jan 28 19:44:31 2003
@@ -223,6 +223,8 @@
 	 &sysctl_tcp_tw_reuse, sizeof(int), 0644, NULL, &proc_dointvec},
 	{NET_TCP_FRTO, "tcp_frto",
 	 &sysctl_tcp_frto, sizeof(int), 0644, NULL, &proc_dointvec},
+	{NET_TCP_LOW_LATENCY, "tcp_low_latency",
+	 &sysctl_tcp_low_latency, sizeof(int), 0644, NULL, &proc_dointvec},
 	{0}
 };
 
diff -urN linux-2.4.21-pre3/net/ipv4/tcp_ipv4.c linux-2.4.21-pre4/net/ipv4/tcp_ipv4.c
--- linux-2.4.21-pre3/net/ipv4/tcp_ipv4.c	Tue Jan 28 19:44:26 2003
+++ linux-2.4.21-pre4/net/ipv4/tcp_ipv4.c	Tue Jan 28 19:44:31 2003
@@ -70,6 +70,7 @@
 extern int sysctl_ip_dynaddr;
 extern int sysctl_ip_default_ttl;
 int sysctl_tcp_tw_reuse = 0;
+int sysctl_tcp_low_latency = 0;
 
 /* Check TCP sequence numbers in ICMP packets. */
 #define ICMP_MIN_LENGTH 8
diff -urN linux-2.4.21-pre3/net/netsyms.c linux-2.4.21-pre4/net/netsyms.c
--- linux-2.4.21-pre3/net/netsyms.c	Thu Nov 28 15:53:16 2002
+++ linux-2.4.21-pre4/net/netsyms.c	Tue Jan 28 19:44:31 2003
@@ -389,6 +389,7 @@
 EXPORT_SYMBOL(sysctl_tcp_ecn);
 EXPORT_SYMBOL(tcp_cwnd_application_limited);
 EXPORT_SYMBOL(tcp_sendpage);
+EXPORT_SYMBOL(sysctl_tcp_low_latency);
 
 EXPORT_SYMBOL(tcp_write_xmit);
 
