## Automatically generated incremental diff
## From:   linux-2.4.28-bk7
## To:     linux-2.4.29
## Robot:  $Id: make-incremental-diff,v 1.12 2004/01/06 07:19:36 hpa Exp $

diff -urN linux-2.4.28-bk7/Documentation/Changes linux-2.4.29/Documentation/Changes
--- linux-2.4.28-bk7/Documentation/Changes	2004-02-18 05:36:30.000000000 -0800
+++ linux-2.4.29/Documentation/Changes	2005-01-19 07:07:49.166603157 -0800
@@ -52,7 +52,7 @@
 o  Gnu make               3.77                    # make --version
 o  binutils               2.9.1.0.25              # ld -v
 o  util-linux             2.10o                   # fdformat --version
-o  modutils               2.4.2                   # insmod -V
+o  modutils               2.4.10                   # insmod -V
 o  e2fsprogs              1.25                    # tune2fs
 o  jfsutils               1.0.12                  # fsck.jfs -V
 o  reiserfsprogs          3.6.3                   # reiserfsck -V 2>&1|grep reiserfsprogs
@@ -159,8 +159,8 @@
 Upgrade to recent modutils to fix various outstanding bugs which are
 seen more frequently under 2.4.x, and to enable auto-loading of USB
 modules.  In addition, the layout of modules under
-/lib/modules/`uname -r`/ has been made more sane.  This change also
-requires that you upgrade to a recent modutils.
+/lib/modules/`uname -r`/ has been made more sane, and EXPORT_SYMBOL_GPL 
+also requires that you upgrade to a recent modutils.
 
 Mkinitrd
 --------
diff -urN linux-2.4.28-bk7/Documentation/Configure.help linux-2.4.29/Documentation/Configure.help
--- linux-2.4.28-bk7/Documentation/Configure.help	2005-01-19 07:07:27.149649541 -0800
+++ linux-2.4.29/Documentation/Configure.help	2005-01-19 07:07:51.551706460 -0800
@@ -617,6 +617,8 @@
 
   This is required for the full functionality of sar(8) and interesting
   if you want to do performance tuning, by tweaking the elevator, e.g.
+  On the other hand, it will cause random and mysterious failures for
+  fdisk, mount and other programs reading /proc/partitions.
 
   If unsure, say N.
 
@@ -1317,21 +1319,6 @@
 
   Please read the comments at the top of <file:drivers/ide/pci/piix.c>.
 
-  If you say Y here, you should also say Y to "PIIXn Tuning support",
-  below.
-
-  If unsure, say N.
-
-PIIXn Tuning support
-CONFIG_PIIX_TUNING
-  This driver extension adds DMA mode setting and tuning for all PIIX
-  IDE controllers by Intel. Since the BIOS can sometimes improperly
-  set up the device/adapter combination and speed limits, it has
-  become a necessity to back/forward speed devices as needed.
-
-  Case 430HX/440FX PIIX3 need speed limits to reduce UDMA to DMA mode
-  2 if the BIOS can not perform this task at initialization.
-
   If unsure, say N.
 
 Promise PDC202{46|62|65|67} support
@@ -3055,19 +3042,6 @@
   If you want to compile it as a module, say M here and read
   <file:Documentation/modules.txt>.  If unsure, say `N'.
 
-Local NAT support
-CONFIG_IP_NF_NAT_LOCAL
-  This option enables support for NAT of locally originated connections. 
-  Enable this if you need to use destination NAT on connections
-  originating from local processes on the nat box itself.
-
-  Please note that you will need a recent version (>= 1.2.6a)
-  of the iptables userspace program in order to use this feature.
-  See <http://www.iptables.org/> for download instructions.
-
-  If unsure, say 'N'.
-
-
 Full NAT (Network Address Translation)
 CONFIG_IP_NF_NAT
   The Full NAT option allows masquerading, port forwarding and other
@@ -7759,7 +7733,7 @@
   of MPT adapters via system ioctl calls.  Use of ioctl calls to
   the MPT driver requires that you create and use a misc device
   node ala:
-    mknod /dev/mptctl c 10 240
+    mknod /dev/mptctl c 10 220
 
   One use of this ioctl interface is to perform an upgrade (reflash)
   of the MPT adapter firmware.  Refer to readme file(s) distributed
@@ -9345,6 +9319,11 @@
 
   If unsure, say N.
 
+CONFIG_SCSI_SATA_AHCI
+  This option enables support for AHCI Serial ATA.
+
+  If unsure, say N.
+
 CONFIG_SCSI_SATA_SVW
   This option enables support for Broadcom/Serverworks/Apple K2
   SATA support.
diff -urN linux-2.4.28-bk7/Documentation/DocBook/libata.tmpl linux-2.4.29/Documentation/DocBook/libata.tmpl
--- linux-2.4.28-bk7/Documentation/DocBook/libata.tmpl	2004-08-07 16:26:04.000000000 -0700
+++ linux-2.4.29/Documentation/DocBook/libata.tmpl	2005-01-19 07:07:51.592708236 -0800
@@ -61,6 +61,196 @@
   </para>
   </chapter>
 
+  <chapter id="libataDriverApi">
+     <title>libata Driver API</title>
+     <sect1>
+        <title>struct ata_port_operations</title>
+
+	<programlisting>
+void (*port_disable) (struct ata_port *);
+	</programlisting>
+
+	<para>
+	Called from ata_bus_probe() and ata_bus_reset() error paths,
+	as well as when unregistering from the SCSI module (rmmod, hot
+	unplug).
+	</para>
+
+	<programlisting>
+void (*dev_config) (struct ata_port *, struct ata_device *);
+	</programlisting>
+
+	<para>
+	Called after IDENTIFY [PACKET] DEVICE is issued to each device
+	found.  Typically used to apply device-specific fixups prior to
+	issue of SET FEATURES - XFER MODE, and prior to operation.
+	</para>
+
+	<programlisting>
+void (*set_piomode) (struct ata_port *, struct ata_device *);
+void (*set_dmamode) (struct ata_port *, struct ata_device *);
+void (*post_set_mode) (struct ata_port *ap);
+	</programlisting>
+
+	<para>
+	Hooks called prior to the issue of SET FEATURES - XFER MODE
+	command.  dev->pio_mode is guaranteed to be valid when
+	->set_piomode() is called, and dev->dma_mode is guaranteed to be
+	valid when ->set_dmamode() is called.  ->post_set_mode() is
+	called unconditionally, after the SET FEATURES - XFER MODE
+	command completes successfully.
+	</para>
+
+	<para>
+	->set_piomode() is always called (if present), but
+	->set_dma_mode() is only called if DMA is possible.
+	</para>
+
+	<programlisting>
+void (*tf_load) (struct ata_port *ap, struct ata_taskfile *tf);
+void (*tf_read) (struct ata_port *ap, struct ata_taskfile *tf);
+	</programlisting>
+
+	<para>
+	->tf_load() is called to load the given taskfile into hardware
+	registers / DMA buffers.  ->tf_read() is called to read the
+	hardware registers / DMA buffers, to obtain the current set of
+	taskfile register values.
+	</para>
+
+	<programlisting>
+void (*exec_command)(struct ata_port *ap, struct ata_taskfile *tf);
+	</programlisting>
+
+	<para>
+	causes an ATA command, previously loaded with
+	->tf_load(), to be initiated in hardware.
+	</para>
+
+	<programlisting>
+u8   (*check_status)(struct ata_port *ap);
+void (*dev_select)(struct ata_port *ap, unsigned int device);
+	</programlisting>
+
+	<para>
+	Reads the Status ATA shadow register from hardware.  On some
+	hardware, this has the side effect of clearing the interrupt
+	condition.
+	</para>
+
+	<programlisting>
+void (*dev_select)(struct ata_port *ap, unsigned int device);
+	</programlisting>
+
+	<para>
+	Issues the low-level hardware command(s) that causes one of N
+	hardware devices to be considered 'selected' (active and
+	available for use) on the ATA bus.
+	</para>
+
+	<programlisting>
+void (*phy_reset) (struct ata_port *ap);
+	</programlisting>
+
+	<para>
+	The very first step in the probe phase.  Actions vary depending
+	on the bus type, typically.  After waking up the device and probing
+	for device presence (PATA and SATA), typically a soft reset
+	(SRST) will be performed.  Drivers typically use the helper
+	functions ata_bus_reset() or sata_phy_reset() for this hook.
+	</para>
+
+	<programlisting>
+void (*bmdma_setup) (struct ata_queued_cmd *qc);
+void (*bmdma_start) (struct ata_queued_cmd *qc);
+	</programlisting>
+
+	<para>
+	When setting up an IDE BMDMA transaction, these hooks arm
+	(->bmdma_setup) and fire (->bmdma_start) the hardware's DMA
+	engine.
+	</para>
+
+	<programlisting>
+void (*qc_prep) (struct ata_queued_cmd *qc);
+int (*qc_issue) (struct ata_queued_cmd *qc);
+	</programlisting>
+
+	<para>
+	Higher-level hooks, these two hooks can potentially supercede
+	several of the above taskfile/DMA engine hooks.  ->qc_prep is
+	called after the buffers have been DMA-mapped, and is typically
+	used to populate the hardware's DMA scatter-gather table.
+	Most drivers use the standard ata_qc_prep() helper function, but
+	more advanced drivers roll their own.
+	</para>
+	<para>
+	->qc_issue is used to make a command active, once the hardware
+	and S/G tables have been prepared.  IDE BMDMA drivers use the
+	helper function ata_qc_issue_prot() for taskfile protocol-based
+	dispatch.  More advanced drivers roll their own ->qc_issue
+	implementation, using this as the "issue new ATA command to
+	hardware" hook.
+	</para>
+
+	<programlisting>
+void (*eng_timeout) (struct ata_port *ap);
+	</programlisting>
+
+	<para>
+	This is a high level error handling function, called from the
+	error handling thread, when a command times out.
+	</para>
+
+	<programlisting>
+irqreturn_t (*irq_handler)(int, void *, struct pt_regs *);
+void (*irq_clear) (struct ata_port *);
+	</programlisting>
+
+	<para>
+	->irq_handler is the interrupt handling routine registered with
+	the system, by libata.  ->irq_clear is called during probe just
+	before the interrupt handler is registered, to be sure hardware
+	is quiet.
+	</para>
+
+	<programlisting>
+u32 (*scr_read) (struct ata_port *ap, unsigned int sc_reg);
+void (*scr_write) (struct ata_port *ap, unsigned int sc_reg,
+                   u32 val);
+	</programlisting>
+
+	<para>
+	Read and write standard SATA phy registers.  Currently only used
+	if ->phy_reset hook called the sata_phy_reset() helper function.
+	</para>
+
+	<programlisting>
+int (*port_start) (struct ata_port *ap);
+void (*port_stop) (struct ata_port *ap);
+void (*host_stop) (struct ata_host_set *host_set);
+	</programlisting>
+
+	<para>
+	->port_start() is called just after the data structures for each
+	port are initialized.  Typically this is used to alloc per-port
+	DMA buffers / tables / rings, enable DMA engines, and similar
+	tasks.  
+	</para>
+	<para>
+	->host_stop() is called when the rmmod or hot unplug process
+	begins.  The hook must stop all hardware interrupts, DMA
+	engines, etc.
+	</para>
+	<para>
+	->port_stop() is called after ->host_stop().  It's sole function
+	is to release DMA/memory resources, now that they are no longer
+	actively being used.
+	</para>
+
+     </sect1>
+  </chapter>
+
   <chapter id="libataExt">
      <title>libata Library</title>
 !Edrivers/scsi/libata-core.c
@@ -78,7 +268,7 @@
   </chapter>
 
   <chapter id="SILInt">
-     <title>ata_sil Internals</title>
+     <title>sata_sil Internals</title>
 !Idrivers/scsi/sata_sil.c
   </chapter>
 
diff -urN linux-2.4.28-bk7/Documentation/computone.txt linux-2.4.29/Documentation/computone.txt
--- linux-2.4.28-bk7/Documentation/computone.txt	2001-11-02 17:26:17.000000000 -0800
+++ linux-2.4.29/Documentation/computone.txt	2005-01-19 07:07:51.651710791 -0800
@@ -6,11 +6,11 @@
 These notes are for the drivers which have already been integrated into the
 kernel and have been tested on Linux kernels 2.0, 2.2, 2.3, and 2.4.
 
-Version: 1.2.14
-Date: 11/01/2001
+Version: 1.2.18
+Date: 12/22/2004
 Historical Author: Andrew Manison <amanison@america.net>
 Primary Author: Doug McNash
-Support: support@computone.com
+Support: mhw@wittsend.com
 Fixes and Updates: Mike Warfield <mhw@wittsend.com>
 
 This file assumes that you are using the Computone drivers which are
@@ -26,7 +26,7 @@
 products previous to the Intelliport II.
 
 This driver was developed on the v2.0.x Linux tree and has been tested up
-to v2.4.14; it will probably not work with earlier v1.X kernels,.
+to v2.4.28; it will probably not work with earlier v1.X kernels,.
 
 
 2. QUICK INSTALLATION
diff -urN linux-2.4.28-bk7/Documentation/networking/e1000.txt linux-2.4.29/Documentation/networking/e1000.txt
--- linux-2.4.28-bk7/Documentation/networking/e1000.txt	2005-01-19 07:07:27.543666608 -0800
+++ linux-2.4.29/Documentation/networking/e1000.txt	2005-01-19 07:07:53.563793606 -0800
@@ -1,14 +1,14 @@
 Linux* Base Driver for the Intel(R) PRO/1000 Family of Adapters
 ===============================================================
 
-September 13, 2004
+November 17, 2004
 
 
 Contents
 ========
 
 - In This Release
-- Supported Adapters
+- Identifying Your Adapter
 - Command Line Parameters
 - Speed and Duplex Configuration
 - Additional Configurations
@@ -20,8 +20,7 @@
 ===============
 
 This file describes the Linux* Base Driver for the Intel(R) PRO/1000 Family
-of Adapters, version 5.x.x.  This driver includes support for Itanium(TM)2 
-and EM64T systems.
+of Adapters, version 5.x.x.  
 
 For questions related to hardware requirements, refer to the documentation 
 supplied with your Intel PRO/1000 adapter. All hardware requirements listed 
@@ -145,9 +144,11 @@
 Default Value: 256
     This value is the number of receive descriptors allocated by the driver. 
     Increasing this value allows the driver to buffer more incoming packets. 
-    Each descriptor is 16 bytes.  A receive buffer is also allocated for each
-    descriptor and can be either 2048, 4096, 8192, or 16384 bytes, depending 
-    on the MTU setting. The maximum MTU size is 16110.
+    Each descriptor is 16 bytes.  A receive buffer is allocated for each
+    descriptor and can either be 2048 or 4096 bytes long, depending on the MTU 
+
+    setting. An incoming packet can span one or more receive descriptors. 
+    The maximum MTU size is 16110.
 
     NOTE: MTU designates the frame size. It only needs to be set for Jumbo 
           Frames.
@@ -251,17 +252,18 @@
   also be forced.
 
 The AutoNeg parameter is used when more control is required over the auto-
-negotiation process.  When this parameter is used, Speed and Duplex must not 
-be specified.  This parameter is a bitmap that specifies which speed and 
-duplex settings are advertised to the link partner.
-
-Bit            7      6      5       4       3      2      1       0
-Speed (Mbps)   N/A    N/A    1000    N/A     100    100    10      10
-Duplex                       Full            Full   Half   Full    Half
-
-For example to limit the negotiated speed/duplex on the interface to 10 Mbps 
-Half or Full duplex, set AutoNeg to 0x02: 
-    insmod e1000 AutoNeg=0x02
+negotiation process. When this parameter is used, Speed and Duplex parameters 
+must not be specified. The following table describes supported values for the 
+AutoNeg parameter:
+
+
+Speed (Mbps)             1000    100    100    10      10
+Duplex                   Full    Full   Half   Full    Half
+Value (in base 16)       0x20    0x08   0x04   0x02    0x01
+
+
+Example: insmod e1000 AutoNeg=0x03, loads e1000 and specifies (10 full duplex, 
+10 half duplex) for negotiation with the peer.
 
 Note that setting AutoNeg does not guarantee that the board will link at the 
 highest specified speed or duplex mode, but the board will link at the 
@@ -333,11 +335,7 @@
   version 1.6 or later is required for this functionality.
 
   The latest release of ethtool can be found from
-  http://sf.net/projects/gkernel.  After ethtool is installed,
-  ethtool-copy.h must be copied and renamed to ethtool.h in your kernel
-  source tree at <linux_kernel_src>/include/linux.  Backup the original
-  ethtool.h as needed before copying.  The driver then must be recompiled
-  in order to take advantage of the latest ethtool features.
+  http://sf.net/projects/gkernel.  
 
   NOTE: Ethtool 1.6 only supports a limited set of ethtool options. Support 
   for a more complete ethtool feature set can be enabled by upgrading 
diff -urN linux-2.4.28-bk7/Documentation/parport.txt linux-2.4.29/Documentation/parport.txt
--- linux-2.4.28-bk7/Documentation/parport.txt	2001-11-09 14:30:55.000000000 -0800
+++ linux-2.4.29/Documentation/parport.txt	2005-01-19 07:07:53.632796595 -0800
@@ -264,5 +264,5 @@
     io=0x378 irq=7 dma=none (for PIO)
     io=0x378 irq=7 dma=3 (for DMA)
 --
-Philip.Blundell@pobox.com
+philb@gnu.org
 tim@cyberelk.net
diff -urN linux-2.4.28-bk7/Documentation/sysctl/vm.txt linux-2.4.29/Documentation/sysctl/vm.txt
--- linux-2.4.28-bk7/Documentation/sysctl/vm.txt	2005-01-19 07:07:27.613669640 -0800
+++ linux-2.4.29/Documentation/sysctl/vm.txt	2005-01-19 07:07:53.705799756 -0800
@@ -307,7 +307,7 @@
 Low ram machines that swaps all the time want to turn
 this on (i.e. set to 1).
 
-The default value is 1.
+The default value is 0.
 =============================================================
 
 
diff -urN linux-2.4.28-bk7/Documentation/tty.txt linux-2.4.29/Documentation/tty.txt
--- linux-2.4.28-bk7/Documentation/tty.txt	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.29/Documentation/tty.txt	2005-01-19 07:07:53.706799800 -0800
@@ -0,0 +1,194 @@
+
+			The Lockronomicon
+
+Your guide to the ancient and twisted locking policies of the tty layer and
+the warped logic behind them. Beware all ye who read on.
+
+FIXME: still need to work out the full set of BKL assumptions and document
+them so they can eventually be killed off.
+
+
+Line Discipline
+---------------
+
+Line disciplines are registered with tty_register_ldisc() passing the
+discipline number and the ldisc structure. At the point of registration the 
+discipline must be ready to use and it is possible it will get used before
+the call returns success. If the call returns an error then it won't get
+called. Do not re-use ldisc numbers as they are part of the userspace ABI
+and writing over an existing ldisc will cause demons to eat your computer.
+After the return the ldisc data has been copied so you may free your own 
+copy of the structure. You must not re-register over the top of the line
+discipline even with the same data or your computer again will be eaten by
+demons.
+
+In order to remove a line discipline call tty_register_ldisc passing NULL.
+In ancient times this always worked. In modern times the function will
+return -EBUSY if the ldisc is currently in use. Since the ldisc referencing
+code manages the module counts this should not usually be a concern.
+
+Heed this warning: the reference count field of the registered copies of the
+tty_ldisc structure in the ldisc table counts the number of lines using this
+discipline. The reference count of the tty_ldisc structure within a tty 
+counts the number of active users of the ldisc at this instant. In effect it
+counts the number of threads of execution within an ldisc method (plus those
+about to enter and exit although this detail matters not).
+
+Line Discipline Methods
+-----------------------
+
+TTY side interfaces:
+
+close()		-	This is called on a terminal when the line
+			discipline is being unplugged. At the point of
+			execution no further users will enter the
+			ldisc code for this tty. Can sleep.
+
+open()		-	Called when the line discipline is attached to
+			the terminal. No other call into the line
+			discipline for this tty will occur until it
+			completes successfully. Can sleep.
+
+write()		-	A process is writing data from user space
+			through the line discipline. Multiple write calls
+			are serialized by the tty layer for the ldisc. May
+			sleep.
+
+flush_buffer()	-	May be called at any point between open and close.
+
+chars_in_buffer() -	Report the number of bytes in the buffer.
+
+set_termios()	-	Called on termios structure changes. The caller
+			passes the old termios data and the current data
+			is in the tty. Currently can be parallel entered
+			and ordering isn't predictable - FIXME
+
+read()		-	Move data from the line discipline to the user.
+			Multiple read calls may occur in parallel and the
+			ldisc must deal with serialization issues. May 
+			sleep.
+
+poll()		-	Check the status for the poll/select calls. Multiple
+			poll calls may occur in parallel. May sleep.
+
+ioctl()		-	Called when an ioctl is handed to the tty layer
+			that might be for the ldisc. Multiple ioctl calls
+			may occur in parallel. May sleep. 
+
+Driver Side Interfaces:
+
+receive_buf()	-	Hand buffers of bytes from the driver to the ldisc
+			for processing. Semantics currently rather
+			mysterious 8(
+
+receive_room()	-	Can be called by the driver layer at any time when
+			the ldisc is opened. The ldisc must be able to
+			handle the reported amount of data at that instant.
+			Synchronization between active receive_buf and
+			receive_room calls is down to the driver not the
+			ldisc. Must not sleep.
+
+write_wakeup()	-	May be called at any point between open and close.
+			The TTY_DO_WRITE_WAKEUP flag indicates if a call
+			is needed but always races versus calls. Thus the
+			ldisc must be careful about setting order and to
+			handle unexpected calls. Must not sleep.
+
+
+Locking
+
+Callers to the line discipline functions from the tty layer are required to
+take line discipline locks. The same is true of calls from the driver side
+but not yet enforced.
+
+Three calls are now provided
+
+	ldisc = tty_ldisc_ref(tty);
+
+takes a handle to the line discipline in the tty and returns it. If no ldisc
+is currently attached or the ldisc is being closed and re-opened at this
+point then NULL is returned. While this handle is held the ldisc will not
+change or go away.
+
+	tty_ldisc_deref(ldisc)
+
+Returns the ldisc reference and allows the ldisc to be closed. Returning the
+reference takes away your right to call the ldisc functions until you take
+a new reference.
+
+	ldisc = tty_ldisc_ref_wait(tty);
+
+Performs the same function as tty_ldisc_ref except that it will wait for an
+ldisc change to complete and then return a reference to the new ldisc. 
+
+While these functions are slightly slower than the old code they should have
+minimal impact as most receive logic uses the flip buffers and they only
+need to take a reference when they push bits up through the driver.
+
+A caution: The ldisc->open(), ldisc->close() and driver->set_ldisc 
+functions are called with the ldisc unavailable. Thus tty_ldisc_ref will
+fail in this situation if used within these functions. Ldisc and driver
+code calling its own functions must be careful in this case. 
+
+
+Driver Interface
+----------------
+
+open()		-	Called when a device is opened. May sleep
+
+close()		-	Called when a device is closed. At the point of
+			return from this call the driver must make no 
+			further ldisc calls of any kind. May sleep
+
+write()		-	Called to write bytes to the device. May not
+			sleep. May occur in parallel in special cases. 
+			Because this includes panic paths drivers generally
+			shouldn't try and do clever locking here.
+
+put_char()	-	Stuff a single character onto the queue. The
+			driver is guaranteed following up calls to
+			flush_chars.
+
+flush_chars()	-	Ask the kernel to write put_char queue
+
+write_room()	-	Return the number of characters tht can be stuffed
+			into the port buffers without overflow (or less).
+			The ldisc is responsible for being intelligent
+ 			about multi-threading of write_room/write calls
+
+ioctl()		-	Called when an ioctl may be for the driver
+
+set_termios()	-	Called on termios change, serialized against
+			itself by a semaphore. May sleep.
+
+set_ldisc()	-	Notifier for discipline change. At the point this 
+			is done the discipline is not yet usable. Can now
+			sleep (I think)
+
+throttle()	-	Called by the ldisc to ask the driver to do flow
+			control.  Serialization including with unthrottle
+			is the job of the ldisc layer.
+
+unthrottle()	-	Called by the ldisc to ask the driver to stop flow
+			control.
+
+stop()		-	Ldisc notifier to the driver to stop output. As with
+			throttle the serializations with start() are down
+			to the ldisc layer.
+
+start()		-	Ldisc notifier to the driver to start output.
+
+hangup()	-	Ask the tty driver to cause a hangup initiated
+			from the host side. [Can sleep ??]
+
+break_ctl()	-	Send RS232 break. Can sleep. Can get called in
+			parallel, driver must serialize (for now), and
+			with write calls.
+
+wait_until_sent() -	Wait for characters to exit the hardware queue
+			of the driver. Can sleep
+
+send_xchar()	  -	Send XON/XOFF and if possible jump the queue with
+			it in order to get fast flow control responses.
+			Cannot sleep ??
+
diff -urN linux-2.4.28-bk7/MAINTAINERS linux-2.4.29/MAINTAINERS
--- linux-2.4.28-bk7/MAINTAINERS	2005-01-19 07:07:27.615669726 -0800
+++ linux-2.4.29/MAINTAINERS	2005-01-19 07:07:53.707799843 -0800
@@ -80,7 +80,7 @@
 
 3C505 NETWORK DRIVER
 P:	Philip Blundell
-M:	Philip.Blundell@pobox.com
+M:	philb@gnu.org
 L:	linux-net@vger.kernel.org
 S:	Maintained
 
@@ -699,7 +699,7 @@
 
 ETHEREXPRESS-16 NETWORK DRIVER
 P:	Philip Blundell
-M:	Philip.Blundell@pobox.com
+M:	philb@gnu.org
 L:	linux-net@vger.kernel.org
 S:	Maintained
 
@@ -841,7 +841,7 @@
 
 i386 SETUP CODE / CPU ERRATA WORKAROUNDS
 P:	Dave Jones
-M:	davej@suse.de
+M:	davej@redhat.com
 P:	H. Peter Anvin
 M:	hpa@zytor.com
 S:	Maintained
@@ -1421,13 +1421,13 @@
 
 PARALLEL PORT SUPPORT
 P:	Phil Blundell
-M:	Philip.Blundell@pobox.com
+M:	philb@gnu.org
 P:	Tim Waugh
 M:	tim@cyberelk.net
 P:	David Campbell
 M:	campbell@torque.net
 P:	Andrea Arcangeli
-M:	andrea@e-mind.com
+M:	andrea@suse.de
 L:	linux-parport@torque.net
 W:	http://people.redhat.com/twaugh/parport/
 S:	Maintained
diff -urN linux-2.4.28-bk7/Makefile linux-2.4.29/Makefile
--- linux-2.4.28-bk7/Makefile	2005-01-19 07:07:27.615669726 -0800
+++ linux-2.4.29/Makefile	2005-01-19 07:07:53.708799886 -0800
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
-SUBLEVEL = 28
-EXTRAVERSION = -bk7
+SUBLEVEL = 29
+EXTRAVERSION =
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -urN linux-2.4.28-bk7/arch/cris/drivers/serial.c linux-2.4.29/arch/cris/drivers/serial.c
--- linux-2.4.28-bk7/arch/cris/drivers/serial.c	2004-02-18 05:36:30.000000000 -0800
+++ linux-2.4.29/arch/cris/drivers/serial.c	2005-01-19 07:07:54.026813660 -0800
@@ -3324,10 +3324,7 @@
 		return;
 	
 	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
-		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-		    tty->ldisc.write_wakeup)
-			(tty->ldisc.write_wakeup)(tty);
-		wake_up_interruptible(&tty->write_wait);
+		tty_wakeup(tty);
 	}
 }
 
@@ -3952,11 +3949,7 @@
 	info->xmit.head = info->xmit.tail = 0;
 	restore_flags(flags);
 
-	wake_up_interruptible(&tty->write_wait);
-
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	    tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup)(tty);
+	tty_wakeup(tty);
 }
 
 /*
@@ -4578,8 +4571,7 @@
 	shutdown(info);
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
+	tty_ldisc_flush(tty);
 	tty->closing = 0;
 	info->event = 0;
 	info->tty = 0;
diff -urN linux-2.4.28-bk7/arch/i386/defconfig linux-2.4.29/arch/i386/defconfig
--- linux-2.4.28-bk7/arch/i386/defconfig	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/arch/i386/defconfig	2005-01-19 07:07:54.027813703 -0800
@@ -200,11 +200,6 @@
 #
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
-
-#
-# Appletalk devices
-#
-# CONFIG_DEV_APPLETALK is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 
@@ -240,10 +235,12 @@
 #
 # CONFIG_BLK_DEV_HD_IDE is not set
 # CONFIG_BLK_DEV_HD is not set
+# CONFIG_BLK_DEV_IDE_SATA is not set
 CONFIG_BLK_DEV_IDEDISK=y
 CONFIG_IDEDISK_MULTI_MODE=y
 # CONFIG_IDEDISK_STROKE is not set
 # CONFIG_BLK_DEV_IDECS is not set
+# CONFIG_BLK_DEV_DELKIN is not set
 CONFIG_BLK_DEV_IDECD=y
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
@@ -346,11 +343,15 @@
 # CONFIG_SCSI_MEGARAID is not set
 # CONFIG_SCSI_MEGARAID2 is not set
 # CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_SATA_AHCI is not set
 # CONFIG_SCSI_SATA_SVW is not set
+# CONFIG_SCSI_ATA_PIIX is not set
+# CONFIG_SCSI_SATA_NV is not set
 # CONFIG_SCSI_SATA_PROMISE is not set
 # CONFIG_SCSI_SATA_SX4 is not set
 # CONFIG_SCSI_SATA_SIL is not set
 # CONFIG_SCSI_SATA_SIS is not set
+# CONFIG_SCSI_SATA_ULI is not set
 # CONFIG_SCSI_SATA_VIA is not set
 # CONFIG_SCSI_SATA_VITESSE is not set
 # CONFIG_SCSI_BUSLOGIC is not set
diff -urN linux-2.4.28-bk7/arch/ia64/ia32/binfmt_elf32.c linux-2.4.29/arch/ia64/ia32/binfmt_elf32.c
--- linux-2.4.28-bk7/arch/ia64/ia32/binfmt_elf32.c	2004-08-07 16:26:04.000000000 -0700
+++ linux-2.4.29/arch/ia64/ia32/binfmt_elf32.c	2005-01-19 07:07:54.571837266 -0800
@@ -95,7 +95,11 @@
 		vma->vm_private_data = NULL;
 		down_write(&current->mm->mmap_sem);
 		{
-			insert_vm_struct(current->mm, vma);
+			if (insert_vm_struct(current->mm, vma)) {
+				kmem_cache_free(vm_area_cachep, vma);
+				up_write(&current->mm->mmap_sem);
+				return;
+			}
 		}
 		up_write(&current->mm->mmap_sem);
 	}
@@ -117,7 +121,11 @@
 		vma->vm_private_data = NULL;
 		down_write(&current->mm->mmap_sem);
 		{
-			insert_vm_struct(current->mm, vma);
+			if (insert_vm_struct(current->mm, vma)) {
+				kmem_cache_free(vm_area_cachep, vma);
+				up_write(&current->mm->mmap_sem);
+				return;
+			}
 		}
 		up_write(&current->mm->mmap_sem);
 	}
@@ -164,7 +172,7 @@
 {
 	unsigned long stack_base;
 	struct vm_area_struct *mpnt;
-	int i;
+	int i, ret;
 
 	stack_base = IA32_STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE;
 
@@ -188,7 +196,11 @@
 		mpnt->vm_pgoff = 0;
 		mpnt->vm_file = NULL;
 		mpnt->vm_private_data = 0;
-		insert_vm_struct(current->mm, mpnt);
+		if ((ret = insert_vm_struct(current->mm, mpnt))) {
+			up_write(&current->mm->mmap_sem);
+			kmem_cache_free(vm_area_cachep, mpnt);
+			return ret;
+		}
 		current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
 	}
 
diff -urN linux-2.4.28-bk7/arch/ia64/ia32/sys_ia32.c linux-2.4.29/arch/ia64/ia32/sys_ia32.c
--- linux-2.4.28-bk7/arch/ia64/ia32/sys_ia32.c	2005-01-19 07:07:28.620713259 -0800
+++ linux-2.4.29/arch/ia64/ia32/sys_ia32.c	2005-01-19 07:07:54.719843676 -0800
@@ -1369,6 +1369,11 @@
 #define __CMSG32_FIRSTHDR(ctl,len) \
 	((len) >= sizeof(struct cmsghdr32) ? (struct cmsghdr32 *)(ctl) : (struct cmsghdr32 *)NULL)
 #define CMSG32_FIRSTHDR(msg)	__CMSG32_FIRSTHDR((msg)->msg_control, (msg)->msg_controllen)
+#define CMSG32_OK(ucmlen, ucmsg, mhdr) \
+	((ucmlen) >= sizeof(struct cmsghdr32) && \
+	 (ucmlen) <= (unsigned long) \
+	 ((mhdr)->msg_controllen - \
+	  ((char *)(ucmsg) - (char *)(mhdr)->msg_control)))
 
 static inline struct cmsghdr32 *
 __cmsg32_nxthdr (void *ctl, __kernel_size_t size, struct cmsghdr32 *cmsg, int cmsg_len)
@@ -1429,10 +1434,7 @@
 			return -EFAULT;
 
 		/* Catch bogons. */
-		if (CMSG32_ALIGN(ucmlen) < CMSG32_ALIGN(sizeof(struct cmsghdr32)))
-			return -EINVAL;
-		if ((unsigned long)(((char *)ucmsg - (char *)kmsg->msg_control) + ucmlen)
-		    > kmsg->msg_controllen)
+		if (!CMSG32_OK(ucmlen, ucmsg, kmsg))
 			return -EINVAL;
 
 		tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) +
diff -urN linux-2.4.28-bk7/arch/ia64/mm/init.c linux-2.4.29/arch/ia64/mm/init.c
--- linux-2.4.28-bk7/arch/ia64/mm/init.c	2004-02-18 05:36:30.000000000 -0800
+++ linux-2.4.29/arch/ia64/mm/init.c	2005-01-19 07:07:54.871850259 -0800
@@ -105,7 +105,13 @@
 		vma->vm_pgoff = 0;
 		vma->vm_file = NULL;
 		vma->vm_private_data = NULL;
-		insert_vm_struct(current->mm, vma);
+		down_write(&current->mm->mmap_sem);
+		if (insert_vm_struct(current->mm, vma)) {
+			up_write(&current->mm->mmap_sem);
+			kmem_cache_free(vm_area_cachep, vma);
+			return;
+		}
+		up_write(&current->mm->mmap_sem);
 	}
 
 	/* map NaT-page at address zero to speed up speculative dereferencing of NULL: */
@@ -117,7 +123,13 @@
 			vma->vm_end = PAGE_SIZE;
 			vma->vm_page_prot = __pgprot(pgprot_val(PAGE_READONLY) | _PAGE_MA_NAT);
 			vma->vm_flags = VM_READ | VM_MAYREAD | VM_IO | VM_RESERVED;
-			insert_vm_struct(current->mm, vma);
+			down_write(&current->mm->mmap_sem);
+			if (insert_vm_struct(current->mm, vma)) {
+				up_write(&current->mm->mmap_sem);
+				kmem_cache_free(vm_area_cachep, vma);
+				return;
+			}
+			up_write(&current->mm->mmap_sem);
 		}
 	}
 }
diff -urN linux-2.4.28-bk7/arch/m68k/kernel/setup.c linux-2.4.29/arch/m68k/kernel/setup.c
--- linux-2.4.28-bk7/arch/m68k/kernel/setup.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/arch/m68k/kernel/setup.c	2005-01-19 07:07:54.906851775 -0800
@@ -597,7 +597,5 @@
 		printk( KERN_EMERG "(see http://no-fpu.linux-m68k.org)\n" );
 		panic( "no FPU" );
 	}
-
-#endif /* CONFIG_SUN3 */
-
+#endif /* !CONFIG_M68KFPU_EMU */
 }
diff -urN linux-2.4.28-bk7/arch/mips/defconfig-bosporus linux-2.4.29/arch/mips/defconfig-bosporus
--- linux-2.4.28-bk7/arch/mips/defconfig-bosporus	2005-01-19 07:07:31.385833026 -0800
+++ linux-2.4.29/arch/mips/defconfig-bosporus	2005-01-19 07:07:56.902938228 -0800
@@ -341,7 +341,6 @@
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
-CONFIG_IP_NF_NAT_LOCAL=y
 CONFIG_IP_NF_NAT_SNMP_BASIC=m
 CONFIG_IP_NF_MANGLE=m
 # CONFIG_IP_NF_TARGET_TOS is not set
diff -urN linux-2.4.28-bk7/arch/mips/defconfig-mtx-1 linux-2.4.29/arch/mips/defconfig-mtx-1
--- linux-2.4.28-bk7/arch/mips/defconfig-mtx-1	2005-01-19 07:07:33.023903977 -0800
+++ linux-2.4.29/arch/mips/defconfig-mtx-1	2005-01-19 07:07:57.418960577 -0800
@@ -335,7 +335,6 @@
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
-# CONFIG_IP_NF_NAT_LOCAL is not set
 # CONFIG_IP_NF_NAT_SNMP_BASIC is not set
 CONFIG_IP_NF_NAT_IRC=m
 CONFIG_IP_NF_NAT_FTP=m
diff -urN linux-2.4.28-bk7/arch/mips/kernel/irixelf.c linux-2.4.29/arch/mips/kernel/irixelf.c
--- linux-2.4.28-bk7/arch/mips/kernel/irixelf.c	2003-08-25 04:44:40.000000000 -0700
+++ linux-2.4.29/arch/mips/kernel/irixelf.c	2005-01-19 07:07:57.998985699 -0800
@@ -130,7 +130,10 @@
 	end = PAGE_ALIGN(end);
 	if (end <= start)
 		return;
+
+	down_write(&current->mm->mmap_sem);
 	do_brk(start, end - start);
+	up_write(&current->mm->mmap_sem);
 }
 
 
@@ -379,7 +382,9 @@
 
 	/* Map the last of the bss segment */
 	if (last_bss > len) {
+		down_write(&current->mm->mmap_sem);
 		do_brk(len, (last_bss - len));
+		up_write(&current->mm->mmap_sem);
 	}
 	kfree(elf_phdata);
 
@@ -567,7 +572,9 @@
 	unsigned long v;
 	struct prda *pp;
 
+	down_write(&current->mm->mmap_sem);
 	v =  do_brk (PRDA_ADDRESS, PAGE_SIZE);
+	up_write(&current->mm->mmap_sem);
 
 	if (v < 0)
 		return;
@@ -858,8 +865,11 @@
 
 	len = (elf_phdata->p_filesz + elf_phdata->p_vaddr+ 0xfff) & 0xfffff000;
 	bss = elf_phdata->p_memsz + elf_phdata->p_vaddr;
-	if (bss > len)
-	  do_brk(len, bss-len);
+	if (bss > len) {
+		down_write(&current->mm->mmap_sem);
+		do_brk(len, bss-len);
+		up_write(&current->mm->mmap_sem);
+	}
 	kfree(elf_phdata);
 	return 0;
 }
diff -urN linux-2.4.28-bk7/arch/mips64/defconfig linux-2.4.29/arch/mips64/defconfig
--- linux-2.4.28-bk7/arch/mips64/defconfig	2005-01-19 07:07:37.425094606 -0800
+++ linux-2.4.29/arch/mips64/defconfig	2005-01-19 07:08:01.120120877 -0800
@@ -265,7 +265,6 @@
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
 CONFIG_IP_NF_NAT_AMANDA=m
-CONFIG_IP_NF_NAT_LOCAL=y
 # CONFIG_IP_NF_NAT_SNMP_BASIC is not set
 CONFIG_IP_NF_NAT_IRC=m
 CONFIG_IP_NF_NAT_FTP=m
diff -urN linux-2.4.28-bk7/arch/mips64/defconfig-ip27 linux-2.4.29/arch/mips64/defconfig-ip27
--- linux-2.4.28-bk7/arch/mips64/defconfig-ip27	2005-01-19 07:07:38.469139826 -0800
+++ linux-2.4.29/arch/mips64/defconfig-ip27	2005-01-19 07:08:01.725147081 -0800
@@ -265,7 +265,6 @@
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
 CONFIG_IP_NF_NAT_AMANDA=m
-CONFIG_IP_NF_NAT_LOCAL=y
 # CONFIG_IP_NF_NAT_SNMP_BASIC is not set
 CONFIG_IP_NF_NAT_IRC=m
 CONFIG_IP_NF_NAT_FTP=m
diff -urN linux-2.4.28-bk7/arch/mips64/kernel/ioctl32.c linux-2.4.29/arch/mips64/kernel/ioctl32.c
--- linux-2.4.28-bk7/arch/mips64/kernel/ioctl32.c	2005-01-19 07:07:39.059165382 -0800
+++ linux-2.4.29/arch/mips64/kernel/ioctl32.c	2005-01-19 07:08:02.479179738 -0800
@@ -2352,6 +2352,10 @@
 	IOCTL32_HANDLER(AUTOFS_IOC_SETTIMEOUT32, ioc_settimeout),
 	IOCTL32_DEFAULT(AUTOFS_IOC_EXPIRE),
 	IOCTL32_DEFAULT(AUTOFS_IOC_EXPIRE_MULTI),
+	IOCTL32_DEFAULT(AUTOFS_IOC_PROTSUBVER),
+	IOCTL32_DEFAULT(AUTOFS_IOC_ASKREGHOST),
+	IOCTL32_DEFAULT(AUTOFS_IOC_TOGGLEREGHOST),
+	IOCTL32_DEFAULT(AUTOFS_IOC_ASKUMOUNT),
 
 	/* DEVFS */
 	IOCTL32_DEFAULT(DEVFSDIOC_GET_PROTO_REV),
diff -urN linux-2.4.28-bk7/arch/mips64/kernel/linux32.c linux-2.4.29/arch/mips64/kernel/linux32.c
--- linux-2.4.28-bk7/arch/mips64/kernel/linux32.c	2005-01-19 07:07:39.249173612 -0800
+++ linux-2.4.29/arch/mips64/kernel/linux32.c	2005-01-19 07:08:02.542182467 -0800
@@ -2483,6 +2483,12 @@
 				    (struct cmsghdr32 *)(ctl) : \
 				    (struct cmsghdr32 *)NULL)
 #define CMSG32_FIRSTHDR(msg)	__CMSG32_FIRSTHDR((msg)->msg_control, (msg)->msg_controllen)
+#define CMSG32_OK(ucmlen, ucmsg, mhdr) \
+	((ucmlen) >= sizeof(struct cmsghdr32) && \
+	 (ucmlen) <= (unsigned long) \
+	 ((mhdr)->msg_controllen - \
+	  ((char *)(ucmsg) - (char *)(mhdr)->msg_control)))
+
 
 __inline__ struct cmsghdr32 *__cmsg32_nxthdr(void *__ctl, __kernel_size_t __size,
 					      struct cmsghdr32 *__cmsg, int __cmsg_len)
@@ -2623,11 +2629,7 @@
 			return -EFAULT;
 
 		/* Catch bogons. */
-		if(CMSG32_ALIGN(ucmlen) <
-		   CMSG32_ALIGN(sizeof(struct cmsghdr32)))
-			return -ENOBUFS;
-		if((unsigned long)(((char *)ucmsg - (char *)kmsg->msg_control)
-				   + ucmlen) > kmsg->msg_controllen)
+		if (!CMSG32_OK(ucmlen, ucmsg, kmsg))
 			return -EINVAL;
 
 		tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) +
diff -urN linux-2.4.28-bk7/arch/parisc/kernel/ioctl32.c linux-2.4.29/arch/parisc/kernel/ioctl32.c
--- linux-2.4.28-bk7/arch/parisc/kernel/ioctl32.c	2003-08-25 04:44:40.000000000 -0700
+++ linux-2.4.29/arch/parisc/kernel/ioctl32.c	2005-01-19 07:08:03.889240808 -0800
@@ -3375,6 +3375,12 @@
 COMPATIBLE_IOCTL(AUTOFS_IOC_CATATONIC)
 COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOVER)
 COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE)
+COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE_MULTI)
+COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOSUBVER)
+COMPATIBLE_IOCTL(AUTOFS_IOC_ASKREGHOST)
+COMPATIBLE_IOCTL(AUTOFS_IOC_TOGGLEREGHOST)
+COMPATIBLE_IOCTL(AUTOFS_IOC_ASKUMOUNT)
+
 /* DEVFS */
 COMPATIBLE_IOCTL(DEVFSDIOC_GET_PROTO_REV)
 COMPATIBLE_IOCTL(DEVFSDIOC_SET_EVENT_MASK)
diff -urN linux-2.4.28-bk7/arch/parisc/kernel/sys_parisc32.c linux-2.4.29/arch/parisc/kernel/sys_parisc32.c
--- linux-2.4.28-bk7/arch/parisc/kernel/sys_parisc32.c	2003-06-13 07:51:31.000000000 -0700
+++ linux-2.4.29/arch/parisc/kernel/sys_parisc32.c	2005-01-19 07:08:03.960243884 -0800
@@ -1814,6 +1814,11 @@
 				    (struct cmsghdr32 *)(ctl) : \
 				    (struct cmsghdr32 *)NULL)
 #define CMSG32_FIRSTHDR(msg)	__CMSG32_FIRSTHDR((msg)->msg_control, (msg)->msg_controllen)
+#define CMSG32_OK(ucmlen, ucmsg, mhdr) \
+	((ucmlen) >= sizeof(struct cmsghdr32) && \
+	 (ucmlen) <= (unsigned long) \
+	 ((mhdr)->msg_controllen - \
+	  ((char *)(ucmsg) - (char *)(mhdr)->msg_control)))
 
 __inline__ struct cmsghdr32 *__cmsg32_nxthdr(void *__ctl, __kernel_size_t __size,
 					      struct cmsghdr32 *__cmsg, int __cmsg_len)
@@ -1940,11 +1945,7 @@
 			return -EFAULT;
 
 		/* Catch bogons. */
-		if(CMSG32_ALIGN(ucmlen) <
-		   CMSG32_ALIGN(sizeof(struct cmsghdr32)))
-			return -EINVAL;
-		if((unsigned long)(((char *)ucmsg - (char *)kmsg->msg_control)
-				   + ucmlen) > kmsg->msg_controllen)
+		if (!CMSG32_OK(ucmlen, ucmsg, kmsg))
 			return -EINVAL;
 
 		tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) +
diff -urN linux-2.4.28-bk7/arch/ppc/8xx_io/uart.c linux-2.4.29/arch/ppc/8xx_io/uart.c
--- linux-2.4.28-bk7/arch/ppc/8xx_io/uart.c	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.29/arch/ppc/8xx_io/uart.c	2005-01-19 07:08:04.057248085 -0800
@@ -738,10 +738,7 @@
 		return;
 
 	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
-		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-		    tty->ldisc.write_wakeup)
-			(tty->ldisc.write_wakeup)(tty);
-		wake_up_interruptible(&tty->write_wait);
+		tty_wakeup(tty);
 	}
 }
 
@@ -1209,10 +1206,7 @@
 	/* There is nothing to "flush", whatever we gave the CPM
 	 * is on its way out.
 	 */
-	wake_up_interruptible(&tty->write_wait);
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	    tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup)(tty);
+	tty_wakeup(tty);
 	info->flags &= ~TX_WAKEUP;
 }
 
@@ -1760,8 +1754,8 @@
 	 * the line discipline to only process XON/XOFF characters.
 	 */
 	tty->closing = 1;
-	if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-		tty_wait_until_sent(tty, info->closing_wait);
+	if (state->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+		tty_wait_until_sent(tty, state->closing_wait);
 	/*
 	 * At this point we stop accepting input.  To do this, we
 	 * disable the receive line status interrupts, and tell the
@@ -1791,15 +1785,14 @@
 	shutdown(info);
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
+	tty_ldisc_flush(tty);
 	tty->closing = 0;
 	info->event = 0;
 	info->tty = 0;
 	if (info->blocked_open) {
-		if (info->close_delay) {
+		if (state->close_delay) {
 			current->state = TASK_INTERRUPTIBLE;
-			schedule_timeout(info->close_delay);
+			schedule_timeout(state->close_delay);
 		}
 		wake_up_interruptible(&info->open_wait);
 	}
diff -urN linux-2.4.28-bk7/arch/ppc/configs/apus_defconfig linux-2.4.29/arch/ppc/configs/apus_defconfig
--- linux-2.4.28-bk7/arch/ppc/configs/apus_defconfig	2004-02-18 05:36:30.000000000 -0800
+++ linux-2.4.29/arch/ppc/configs/apus_defconfig	2005-01-19 07:08:04.136251506 -0800
@@ -199,7 +199,6 @@
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
 CONFIG_IP_NF_NAT_AMANDA=m
-# CONFIG_IP_NF_NAT_LOCAL is not set
 CONFIG_IP_NF_NAT_SNMP_BASIC=m
 CONFIG_IP_NF_NAT_IRC=m
 CONFIG_IP_NF_NAT_FTP=m
diff -urN linux-2.4.28-bk7/arch/ppc/configs/briq_defconfig linux-2.4.29/arch/ppc/configs/briq_defconfig
--- linux-2.4.28-bk7/arch/ppc/configs/briq_defconfig	2004-02-18 05:36:30.000000000 -0800
+++ linux-2.4.29/arch/ppc/configs/briq_defconfig	2005-01-19 07:08:04.187253715 -0800
@@ -175,7 +175,6 @@
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
 CONFIG_IP_NF_NAT_AMANDA=m
-# CONFIG_IP_NF_NAT_LOCAL is not set
 CONFIG_IP_NF_NAT_SNMP_BASIC=m
 CONFIG_IP_NF_NAT_IRC=m
 CONFIG_IP_NF_NAT_FTP=m
diff -urN linux-2.4.28-bk7/arch/ppc/configs/common_defconfig linux-2.4.29/arch/ppc/configs/common_defconfig
--- linux-2.4.28-bk7/arch/ppc/configs/common_defconfig	2004-02-18 05:36:30.000000000 -0800
+++ linux-2.4.29/arch/ppc/configs/common_defconfig	2005-01-19 07:08:04.188253759 -0800
@@ -180,7 +180,6 @@
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
 CONFIG_IP_NF_NAT_AMANDA=m
-# CONFIG_IP_NF_NAT_LOCAL is not set
 CONFIG_IP_NF_NAT_SNMP_BASIC=m
 CONFIG_IP_NF_NAT_IRC=m
 CONFIG_IP_NF_NAT_FTP=m
diff -urN linux-2.4.28-bk7/arch/ppc/configs/ibmchrp_defconfig linux-2.4.29/arch/ppc/configs/ibmchrp_defconfig
--- linux-2.4.28-bk7/arch/ppc/configs/ibmchrp_defconfig	2004-02-18 05:36:30.000000000 -0800
+++ linux-2.4.29/arch/ppc/configs/ibmchrp_defconfig	2005-01-19 07:08:04.238255924 -0800
@@ -173,7 +173,6 @@
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
 CONFIG_IP_NF_NAT_AMANDA=m
-# CONFIG_IP_NF_NAT_LOCAL is not set
 CONFIG_IP_NF_NAT_SNMP_BASIC=m
 CONFIG_IP_NF_NAT_IRC=m
 CONFIG_IP_NF_NAT_FTP=m
diff -urN linux-2.4.28-bk7/arch/ppc/configs/pal4_defconfig linux-2.4.29/arch/ppc/configs/pal4_defconfig
--- linux-2.4.28-bk7/arch/ppc/configs/pal4_defconfig	2004-02-18 05:36:30.000000000 -0800
+++ linux-2.4.29/arch/ppc/configs/pal4_defconfig	2005-01-19 07:08:04.306258870 -0800
@@ -172,7 +172,6 @@
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
 CONFIG_IP_NF_NAT_AMANDA=m
-# CONFIG_IP_NF_NAT_LOCAL is not set
 CONFIG_IP_NF_NAT_SNMP_BASIC=m
 CONFIG_IP_NF_NAT_IRC=m
 CONFIG_IP_NF_NAT_FTP=m
diff -urN linux-2.4.28-bk7/arch/ppc/configs/pmac_defconfig linux-2.4.29/arch/ppc/configs/pmac_defconfig
--- linux-2.4.28-bk7/arch/ppc/configs/pmac_defconfig	2004-02-18 05:36:30.000000000 -0800
+++ linux-2.4.29/arch/ppc/configs/pmac_defconfig	2005-01-19 07:08:04.307258913 -0800
@@ -183,7 +183,6 @@
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
 CONFIG_IP_NF_NAT_AMANDA=m
-# CONFIG_IP_NF_NAT_LOCAL is not set
 CONFIG_IP_NF_NAT_SNMP_BASIC=m
 CONFIG_IP_NF_NAT_IRC=m
 CONFIG_IP_NF_NAT_FTP=m
diff -urN linux-2.4.28-bk7/arch/ppc/configs/pplus_defconfig linux-2.4.29/arch/ppc/configs/pplus_defconfig
--- linux-2.4.28-bk7/arch/ppc/configs/pplus_defconfig	2004-02-18 05:36:30.000000000 -0800
+++ linux-2.4.29/arch/ppc/configs/pplus_defconfig	2005-01-19 07:08:04.333260039 -0800
@@ -175,7 +175,6 @@
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
 CONFIG_IP_NF_NAT_AMANDA=m
-# CONFIG_IP_NF_NAT_LOCAL is not set
 CONFIG_IP_NF_NAT_SNMP_BASIC=m
 CONFIG_IP_NF_NAT_IRC=m
 CONFIG_IP_NF_NAT_FTP=m
diff -urN linux-2.4.28-bk7/arch/ppc/configs/prpmc750_defconfig linux-2.4.29/arch/ppc/configs/prpmc750_defconfig
--- linux-2.4.28-bk7/arch/ppc/configs/prpmc750_defconfig	2004-02-18 05:36:30.000000000 -0800
+++ linux-2.4.29/arch/ppc/configs/prpmc750_defconfig	2005-01-19 07:08:04.334260082 -0800
@@ -183,7 +183,6 @@
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
-# CONFIG_IP_NF_NAT_LOCAL is not set
 # CONFIG_IP_NF_NAT_SNMP_BASIC is not set
 CONFIG_IP_NF_NAT_FTP=m
 # CONFIG_IP_NF_MANGLE is not set
diff -urN linux-2.4.28-bk7/arch/ppc/cpm2_io/uart.c linux-2.4.29/arch/ppc/cpm2_io/uart.c
--- linux-2.4.28-bk7/arch/ppc/cpm2_io/uart.c	2004-04-14 06:05:27.000000000 -0700
+++ linux-2.4.29/arch/ppc/cpm2_io/uart.c	2005-01-19 07:08:04.454265280 -0800
@@ -1754,8 +1754,8 @@
 	 * the line discipline to only process XON/XOFF characters.
 	 */
 	tty->closing = 1;
-	if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-		tty_wait_until_sent(tty, info->closing_wait);
+	if (state->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+		tty_wait_until_sent(tty, state->closing_wait);
 	/*
 	 * At this point we stop accepting input.  To do this, we
 	 * disable the receive line status interrupts, and tell the
@@ -1790,9 +1790,9 @@
 	info->event = 0;
 	info->tty = 0;
 	if (info->blocked_open) {
-		if (info->close_delay) {
+		if (state->close_delay) {
 			current->state = TASK_INTERRUPTIBLE;
-			schedule_timeout(info->close_delay);
+			schedule_timeout(state->close_delay);
 		}
 		wake_up_interruptible(&info->open_wait);
 	}
diff -urN linux-2.4.28-bk7/arch/ppc/defconfig linux-2.4.29/arch/ppc/defconfig
--- linux-2.4.28-bk7/arch/ppc/defconfig	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/arch/ppc/defconfig	2005-01-19 07:08:04.503267402 -0800
@@ -180,7 +180,6 @@
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
 CONFIG_IP_NF_NAT_AMANDA=m
-# CONFIG_IP_NF_NAT_LOCAL is not set
 CONFIG_IP_NF_NAT_SNMP_BASIC=m
 CONFIG_IP_NF_NAT_IRC=m
 CONFIG_IP_NF_NAT_FTP=m
diff -urN linux-2.4.28-bk7/arch/ppc/kernel/traps.c linux-2.4.29/arch/ppc/kernel/traps.c
--- linux-2.4.28-bk7/arch/ppc/kernel/traps.c	2004-04-14 06:05:27.000000000 -0700
+++ linux-2.4.29/arch/ppc/kernel/traps.c	2005-01-19 07:08:04.531268615 -0800
@@ -88,8 +88,10 @@
 	console_verbose();
 	spin_lock_irq(&die_lock);
 #ifdef CONFIG_PMAC_BACKLIGHT
-	set_backlight_enable(1);
-	set_backlight_level(BACKLIGHT_MAX);
+	if (_machine == _MACH_Pmac) {
+		set_backlight_enable(1);
+		set_backlight_level(BACKLIGHT_MAX);
+	}
 #endif
 	printk("Oops: %s, sig: %ld\n", str, err);
 	show_regs(fp);
diff -urN linux-2.4.28-bk7/arch/ppc64/kernel/ioctl32.c linux-2.4.29/arch/ppc64/kernel/ioctl32.c
--- linux-2.4.28-bk7/arch/ppc64/kernel/ioctl32.c	2004-02-18 05:36:30.000000000 -0800
+++ linux-2.4.29/arch/ppc64/kernel/ioctl32.c	2005-01-19 07:08:05.868326523 -0800
@@ -4278,6 +4278,11 @@
 COMPATIBLE_IOCTL(AUTOFS_IOC_CATATONIC),
 COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOVER),
 COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE),
+COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE_MULTI),
+COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOSUBVER),
+COMPATIBLE_IOCTL(AUTOFS_IOC_ASKREGHOST),
+COMPATIBLE_IOCTL(AUTOFS_IOC_TOGGLEREGHOST),
+COMPATIBLE_IOCTL(AUTOFS_IOC_ASKUMOUNT),
 /* DEVFS */
 COMPATIBLE_IOCTL(DEVFSDIOC_GET_PROTO_REV),
 COMPATIBLE_IOCTL(DEVFSDIOC_SET_EVENT_MASK),
diff -urN linux-2.4.28-bk7/arch/ppc64/kernel/signal.c linux-2.4.29/arch/ppc64/kernel/signal.c
--- linux-2.4.28-bk7/arch/ppc64/kernel/signal.c	2004-02-18 05:36:30.000000000 -0800
+++ linux-2.4.29/arch/ppc64/kernel/signal.c	2005-01-19 07:08:06.032333626 -0800
@@ -31,8 +31,8 @@
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
-#include <asm/ppcdebug.h>
 #include <asm/unistd.h>
+#include <asm/processor.h>
 
 #define DEBUG_SIG 0
 
@@ -138,7 +138,7 @@
 	regs->gpr[3] = EINTR;
 	regs->ccr |= 0x10000000;
 	while (1) {
-		current->state = TASK_INTERRUPTIBLE;
+		set_current_state(TASK_INTERRUPTIBLE);
 		schedule();
 		if (do_signal(&saveset, regs))
 			/*
@@ -236,22 +236,16 @@
 
 	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);
+	current->thread.fpscr = 0;
+
 	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;
-
 	return err;
 }
 
@@ -263,20 +257,33 @@
 restore_sigcontext(struct pt_regs *regs, sigset_t *set, struct sigcontext *sc)
 {
 	unsigned int err = 0;
+	int i;
+	elf_greg_t *gregs = (elf_greg_t *)regs;
+	unsigned long msr;
+
+	/* copy up to but not including MSR */
+	err |= __copy_from_user(regs, &sc->gp_regs,
+				PT_MSR * sizeof(elf_greg_t));
+	/* get the MSR value from the stack but don't put it in regs->msr */
+	err |= __get_user(msr, &sc->gp_regs[PT_MSR]);
+	/* copy from orig_r3 (the word after the MSR) to the end,
+	 * but don't copy softe */
+	for (i = PT_ORIG_R3; err == 0 && i <= PT_RESULT; ++i)
+		if (i != PT_SOFTE)
+			err |= __get_user(gregs[i], &sc->gp_regs[i]);
 
-	if (regs->msr & MSR_FP)
-		giveup_fpu(current);
-
-	err |= __copy_from_user(regs, &sc->gp_regs, GP_REGS_SIZE);
+	/* make the process reload FP regs if it executes an FP instr */
+	regs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1);
+#ifndef CONFIG_SMP
+	if (last_task_used_math == current)
+		last_task_used_math = NULL;
+#endif
 	err |= __copy_from_user(&current->thread.fpr, &sc->fp_regs, FP_REGS_SIZE);
-	current->thread.fpexc_mode = regs->msr & (MSR_FE0 | MSR_FE1);
+
+	/* restore the signal mask */
 	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;
 }
 
diff -urN linux-2.4.28-bk7/arch/ppc64/kernel/signal32.c linux-2.4.29/arch/ppc64/kernel/signal32.c
--- linux-2.4.28-bk7/arch/ppc64/kernel/signal32.c	2004-02-18 05:36:30.000000000 -0800
+++ linux-2.4.29/arch/ppc64/kernel/signal32.c	2005-01-19 07:08:06.274344107 -0800
@@ -48,7 +48,6 @@
 #include <asm/uaccess.h>
 #include <linux/elf.h>
 #include <asm/ppc32.h>
-#include <asm/ppcdebug.h>
 #include <asm/unistd.h>
 #include <asm/ucontext.h>
 
@@ -141,23 +140,22 @@
 {
 	struct k_sigaction new_ka, old_ka;
 	int ret;
+	u32 handler, restorer;
 	
-	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) {
 		old_sigset_t32 mask;
 
-		ret = get_user((long)new_ka.sa.sa_handler, &act->sa_handler);
-		ret |= __get_user((long)new_ka.sa.sa_restorer, &act->sa_restorer);
+		ret = get_user(handler, &act->sa_handler);
+		ret |= __get_user(restorer, &act->sa_restorer);
 		ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
 		ret |= __get_user(mask, &act->sa_mask);
 		if (ret)
 			return ret;
-		PPCDBG(PPCDBG_SIGNAL, "sys32_sigaction flags =%lx  \n", new_ka.sa.sa_flags);
-
+		new_ka.sa.sa_handler = (__sighandler_t)(long) handler;
+		new_ka.sa.sa_restorer = (void (*)(void))(long) restorer;
 		siginitset(&new_ka.sa.sa_mask, mask);
 	}
 
@@ -171,9 +169,6 @@
 		ret |= __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
 	}
 
-	
-	PPCDBG(PPCDBG_SYS32, "sys32_sigaction - exited - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
-
 	return ret;
 }
 
@@ -188,15 +183,11 @@
 	int ret;
 	mm_segment_t old_fs = get_fs();
 	
-	PPCDBG(PPCDBG_SYS32, "sys32_sigpending - entered - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
-		
 	set_fs (KERNEL_DS);
 	ret = sys_sigpending(&s);
 	set_fs (old_fs);
 	if (put_user (s, set)) return -EFAULT;
 	
-	PPCDBG(PPCDBG_SYS32, "sys32_sigpending - exited - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
-
 	return ret;
 }
 
@@ -216,16 +207,12 @@
 	int ret;
 	mm_segment_t old_fs = get_fs();
 	
-	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;
 	set_fs (KERNEL_DS);
 	ret = sys_sigprocmask((int)how, set ? &s : NULL, oset ? &s : NULL);
 	set_fs (old_fs);
 	
-	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))
@@ -256,14 +243,10 @@
 {
 	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 *)(regs->gpr[1] + __SIGNAL_FRAMESIZE32);
 	if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
 		goto badframe;
@@ -279,107 +262,67 @@
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
 
-	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*)(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
-		 */
-		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.
-		 */
-		saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE)
-			| (saved_regs[PT_MSR] & MSR_USERCHANGE);
-		/*
-		 * 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.)
-		 */
-		regs->msr = regs->msr | MSR_ISF;
-
-		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; 
-		regs->link = (u64)(saved_regs[PT_LNK]) & 0xFFFFFFFF; 
-		regs->xer = (u64)(saved_regs[PT_XER]) & 0xFFFFFFFF; 
-		regs->ccr = (u64)(saved_regs[PT_CCR]) & 0xFFFFFFFF;
-		/* regs->softe is left unchanged (like the MSR.EE bit) */
-		/******************************************************/
-		/* 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;
+	sr = (struct sigregs32*)(u64)sigctx.regs;
+	/*
+	 * 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;
 
-		if (copy_from_user(current->thread.fpr, &sr->fp_regs, sizeof(sr->fp_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.
+	 */
+	for (i = 0; i < 32; i++)
+		regs->gpr[i] = (u64)(saved_regs[i]) & 0xFFFFFFFF;
 
-		ret = regs->result;
-	} else {
-		/* More signals to go */
-		regs->gpr[1] = (unsigned long)sc - __SIGNAL_FRAMESIZE32;
-		if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
-			goto badframe;
-		sr = (struct sigregs32*)(u64)sigctx.regs;
-		regs->gpr[3] = ret = sigctx.signal;
-		regs->gpr[4] = (unsigned long) sc;
-		regs->link = (unsigned long) &sr->tramp;
-		regs->nip = sigctx.handler;
+	/*
+	 *  restore the non gpr registers 
+	 */
+	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; 
+	regs->link = (u64)(saved_regs[PT_LNK]) & 0xFFFFFFFF; 
+	regs->xer = (u64)(saved_regs[PT_XER]) & 0xFFFFFFFF; 
+	regs->ccr = (u64)(saved_regs[PT_CCR]) & 0xFFFFFFFF;
+	/* regs->softe is left unchanged (like the MSR.EE bit) */
+	regs->result = (u64)(saved_regs[PT_RESULT]) & 0xFFFFFFFF;
+
+	/* force the process to reload the FP registers from
+	   current->thread when it next does FP instructions */
+	regs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1);
+#ifndef CONFIG_SMP
+	if (last_task_used_math == current)
+		last_task_used_math = NULL;
+#endif
+	if (copy_from_user(current->thread.fpr, &sr->fp_regs,
+			   sizeof(sr->fp_regs)))
+		goto badframe;
 
-		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);
-	return ret;
+	return regs->result;
 
 badframe:
-	PPCDBG(PPCDBG_SYS32NI, "sys32_sigreturn - badframe - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-	do_exit(SIGSEGV);
+	force_sig(SIGSEGV, current);
+	return 0;
 }	
 
 /*
  * Set up a signal frame.
  */
 static void
-setup_frame32(struct pt_regs *regs, struct sigregs32 *frame,
-            unsigned int newsp)
+setup_frame32(struct pt_regs *regs, int sig, struct k_sigaction *ka,
+	      struct sigregs32 *frame, unsigned int newsp)
 {
-	struct sigcontext32 *sc = (struct sigcontext32 *)(u64)newsp;
 	int i;
 
 	if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
@@ -425,30 +368,32 @@
 			   (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)
-	    || get_user(regs->nip, &sc->handler)
-	    || get_user(regs->gpr[3], &sc->signal))
-		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
 	 */
-	regs->gpr[4] = (unsigned long) sc;
+	regs->gpr[3] = sig;
+	regs->gpr[4] = newsp;
+	regs->nip = (u64)ka->sa.sa_handler & 0xFFFFFFFF;
 	regs->link = (unsigned long) frame->tramp;
+
+	newsp -= __SIGNAL_FRAMESIZE32;
+	if (put_user(regs->gpr[1], (u32*)(u64)newsp))
+		goto badframe;
+	regs->gpr[1] = newsp;
+
 	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
 	printk("badframe in setup_frame32, regs=%p frame=%p newsp=%lx\n",
 	       regs, frame, newsp);
 #endif
-	do_exit(SIGSEGV);
+	if (sig == SIGSEGV)
+		ka->sa.sa_handler = SIG_DFL;
+	force_sig(SIGSEGV, current);
 }
 
 
@@ -485,14 +430,12 @@
 	struct sigcontext32 sigctx;
 	struct sigregs32 *signalregs;
  
-	int i, ret;
+	int i;
 	elf_gregset_t32 saved_regs;   /* an array of 32 bit register values */
 	sigset_t signal_set; 
 	stack_t stack;
-	unsigned int previous_stack;
 
-	ret = 0;
-	/* Adjust the inputted reg1 to point to the first rt signal frame */
+	/* Adjust the inputted reg1 to point to the rt signal frame */
 	rt_stack_frame = (struct rt_sigframe_32 *)(regs->gpr[1] + __SIGNAL_FRAMESIZE32);
 	/* Copy the information from the user stack  */
 	if (copy_from_user(&sigctx, &rt_stack_frame->uc.uc_mcontext,sizeof(sigctx))
@@ -514,100 +457,54 @@
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
 
-	/* Set to point to the next rt_sigframe - this is used to determine whether this 
-	 *   is the last signal to process
-	 */
-	rt_stack_frame ++;
-
-	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);
+	signalregs = (struct sigregs32 *) (u64)sigctx.regs;
 
-		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.
-		 */
-		saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE)
-			| (saved_regs[PT_MSR] & MSR_USERCHANGE);
-		/*
-		 * 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; 
-		regs->link = (u64)(saved_regs[PT_LNK]) & 0xFFFFFFFF; 
-		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.
-		 */
-		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  */
-	{
-		regs->gpr[1] = (u64)rt_stack_frame - __SIGNAL_FRAMESIZE32;
-		if (copy_from_user(&sigctx, &rt_stack_frame->uc.uc_mcontext,sizeof(sigctx)))
-		{
-			goto badframe;
-		}
-		signalregs = (struct sigregs32 *) (u64)sigctx.regs;
-		/* first parm to signal handler is the signal number */
-		regs->gpr[3] = ret = sigctx.signal;
-		/* second parm is a pointer to sig info */
-		get_user(regs->gpr[4], &rt_stack_frame->pinfo);
-		/* third parm is a pointer to the ucontext */
-		get_user(regs->gpr[5], &rt_stack_frame->puc);
-		/* fourth parm is the stack frame */
-		regs->gpr[6] = (u64)rt_stack_frame;
-		/* Set up link register to return to sigreturn when the */
-		/*  signal handler completes */
-		regs->link = (u64)&signalregs->tramp;
-		/* Set next instruction to the start fo the signal handler */
-		regs->nip = sigctx.handler;
-		/* Set the reg1 to look like a call to the signal handler */
-		if (get_user(previous_stack,&signalregs->gp_regs[PT_R1])
-		    || put_user(previous_stack, (unsigned long *)regs->gpr[1]))
-		{
-			goto badframe;
-		}
-		current->thread.fpscr = 0;
+	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.
+	 */
+	for (i = 0; i < 32; i++)
+		regs->gpr[i] = (u64)(saved_regs[i]) & 0xFFFFFFFF;
+	/*
+	 * restore the non gpr registers
+	 */
+	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; 
+	regs->link = (u64)(saved_regs[PT_LNK]) & 0xFFFFFFFF; 
+	regs->xer = (u64)(saved_regs[PT_XER]) & 0xFFFFFFFF; 
+	regs->ccr = (u64)(saved_regs[PT_CCR]) & 0xFFFFFFFF;
+	/* regs->softe is left unchanged (like MSR.EE) */
+	regs->result = (u64)(saved_regs[PT_RESULT]) & 0xFFFFFFFF;
+
+	/* force the process to reload the FP registers from
+	   current->thread when it next does FP instructions */
+	regs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1);
+#ifndef CONFIG_SMP
+	if (last_task_used_math == current)
+		last_task_used_math = NULL;
+#endif
+	if (copy_from_user(current->thread.fpr, &signalregs->fp_regs,
+			   sizeof(signalregs->fp_regs))) 
+		goto badframe;
 
-	return ret;
+	return regs->result;
 
  badframe:
-	do_exit(SIGSEGV);     
+	force_sig(SIGSEGV, current);
+	return 0;
 }
 
 
@@ -617,15 +514,14 @@
 	struct k_sigaction new_ka, old_ka;
 	int ret;
 	sigset32_t set32;
-
-	PPCDBG(PPCDBG_SIGNAL, "sys32_rt_sigaction - entered - sig=%x \n", sig);
+	u32 handler;
 
 	/* XXX: Don't preclude handling different sized sigset_t's.  */
 	if (sigsetsize != sizeof(sigset32_t))
 		return -EINVAL;
 
 	if (act) {
-		ret = get_user((long)new_ka.sa.sa_handler, &act->sa_handler);
+		ret = get_user(handler, &act->sa_handler);
 		ret |= __copy_from_user(&set32, &act->sa_mask,
 					sizeof(sigset32_t));
 		switch (_NSIG_WORDS) {
@@ -643,6 +539,7 @@
 		
 		if (ret)
 			return -EFAULT;
+		new_ka.sa.sa_handler = (__sighandler_t)(long) handler;
 	}
 
 	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
@@ -668,9 +565,7 @@
 		ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
 	}
 
-  
-	PPCDBG(PPCDBG_SIGNAL, "sys32_rt_sigaction - exiting - sig=%x \n", sig);
-	return ret;
+  	return ret;
 }
 
 
@@ -691,8 +586,6 @@
 	int ret;
 	mm_segment_t old_fs = get_fs();
 
-	PPCDBG(PPCDBG_SIGNAL, "sys32_rt_sigprocmask - entered how=%x \n", (int)how);
-	
 	if (set) {
 		if (copy_from_user (&s32, set, sizeof(sigset32_t)))
 			return -EFAULT;
@@ -779,7 +672,7 @@
 	case SIGBUS:
 	case SIGFPE:
 	case SIGILL:
-		d->si_addr = (unsigned int)(s->si_addr);
+		d->si_addr = (unsigned int)(u64)(s->si_addr);
         break;
 	case SIGPOLL:
 		d->si_band = s->si_band;
@@ -943,7 +836,7 @@
 	regs->gpr[3] = EINTR;
 	regs->ccr |= 0x10000000;
 	while (1) {
-		current->state = TASK_INTERRUPTIBLE;
+		set_current_state(TASK_INTERRUPTIBLE);
 		schedule();
 		if (do_signal(&saveset, regs))
 			/*
@@ -963,10 +856,9 @@
  * Set up a rt signal frame.
  */
 static void
-setup_rt_frame32(struct pt_regs *regs, struct sigregs32 *frame,
-            unsigned int newsp)
+setup_rt_frame32(struct pt_regs *regs, int sig, struct k_sigaction *ka,
+		 struct sigregs32 *frame, unsigned int newsp)
 {
-	unsigned int copyreg4,copyreg5;
 	struct rt_sigframe_32 * rt_sf = (struct rt_sigframe_32 *) (u64)newsp;
 	int i;
   
@@ -1013,34 +905,31 @@
 	current->thread.fpscr = 0;	/* turn off all fp exceptions */
   
 	/*
-	 * Retrieve rt_sigframe from stack and
-	 * set up registers for signal handler
-	*/
+	 * Set up registers for signal handler
+	 */
 	newsp -= __SIGNAL_FRAMESIZE32;
-      
-
-	if (put_user((u32)(regs->gpr[1]), (unsigned int *)(u64)newsp)
-	    || get_user(regs->nip, &rt_sf->uc.uc_mcontext.handler)
-	    || get_user(regs->gpr[3], &rt_sf->uc.uc_mcontext.signal)
-	    || get_user(copyreg4, &rt_sf->pinfo)
-	    || get_user(copyreg5, &rt_sf->puc))
-		goto badframe;
 
-	regs->gpr[4] = copyreg4;
-	regs->gpr[5] = copyreg5;
 	regs->gpr[1] = newsp;
+	regs->gpr[3] = sig;
+	regs->gpr[4] = (unsigned long) &rt_sf->info;
+	regs->gpr[5] = (unsigned long) &rt_sf->uc;
 	regs->gpr[6] = (unsigned long) rt_sf;
-	regs->link = (unsigned long) frame->tramp;
+	regs->nip    = (unsigned long) ka->sa.sa_handler;
+	regs->link   = (unsigned long) frame->tramp;
+
+	if (put_user((u32)(regs->gpr[1]), (unsigned int *)(u64)newsp))
+		goto badframe;
 
 	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
-	printk("badframe in setup_frame32, regs=%p frame=%p newsp=%lx\n",
+	printk("badframe in setup_rt_frame32, regs=%p frame=%p newsp=%lx\n",
 	       regs, frame, newsp);
 #endif
-	do_exit(SIGSEGV);
+	if (sig == SIGSEGV)
+		ka->sa.sa_handler = SIG_DFL;
+	force_sig(SIGSEGV, current);
 }
 
 
@@ -1131,7 +1020,9 @@
 	       regs, frame, *newspp);
 	printk("sc=%p sig=%d ka=%p info=%p oldset=%p\n", sc, sig, ka, info, oldset);
 #endif
-	do_exit(SIGSEGV);
+	if (sig == SIGSEGV)
+		ka->sa.sa_handler = SIG_DFL;
+	force_sig(SIGSEGV, current);
 }
 
 
@@ -1150,6 +1041,8 @@
 	int ret;
 	mm_segment_t old_fs;
 	unsigned long sp;
+	u32 sssp;
+	stack_32_t *ustack;
 
 	/*
 	 * set sp to the user stack on entry to the system call
@@ -1157,21 +1050,26 @@
 	 */
 	sp = regs->gpr[1];
 
-	/*  Put new stack info in local 64 bit stack struct                      */ 
-	if (newstack && (get_user((long)uss.ss_sp, &((stack_32_t *)(long)newstack)->ss_sp) ||
-			 __get_user(uss.ss_flags, &((stack_32_t *)(long)newstack)->ss_flags) ||
-			 __get_user(uss.ss_size, &((stack_32_t *)(long)newstack)->ss_size)))
+	/*  Put new stack info in local 64 bit stack struct */ 
+	ustack = (stack_32_t *)(long) newstack;
+	if (newstack && (get_user(sssp, &ustack->ss_sp) ||
+			 __get_user(uss.ss_flags, &ustack->ss_flags) ||
+			 __get_user(uss.ss_size, &ustack->ss_size)))
 		return -EFAULT; 
-
+	uss.ss_sp = (void *)(long) sssp;
    
 	old_fs = get_fs();
 	set_fs(KERNEL_DS);
 	ret = do_sigaltstack(newstack ? &uss : NULL, oldstack ? &uoss : NULL, sp);
 	set_fs(old_fs);
-	/* Copy the stack information to the user output buffer                  */
-	if (!ret && oldstack  && (put_user((long)uoss.ss_sp, &((stack_32_t *)(long)oldstack)->ss_sp) ||
-				  __put_user(uoss.ss_flags, &((stack_32_t *)(long)oldstack)->ss_flags) ||
-				  __put_user(uoss.ss_size, &((stack_32_t *)(long)oldstack)->ss_size)))
+	if (ret)
+		return ret;
+
+	/* Copy the stack information to the user output buffer */
+	ustack = (stack_32_t *)(long) oldstack;
+	if (oldstack && (put_user((long)uoss.ss_sp, &ustack->ss_sp) ||
+			 __put_user(uoss.ss_flags, &ustack->ss_flags) ||
+			 __put_user(uoss.ss_size, &ustack->ss_size)))
 		return -EFAULT;
 	return ret;
 }
@@ -1198,6 +1096,7 @@
 	siginfo_t info;
 	struct k_sigaction *ka;
 	unsigned int frame, newsp;
+	unsigned long signr = 0;
 
 	if (!oldset)
 		oldset = &current->blocked;
@@ -1205,15 +1104,9 @@
 	newsp = frame = 0;
 
 	for (;;) {
-		unsigned long signr;
-		
 		spin_lock_irq(&current->sigmask_lock);
 		signr = dequeue_signal(&current->blocked, &info);
 		spin_unlock_irq(&current->sigmask_lock);
-		ifppcdebug(PPCDBG_SYS32) {
-			if (signr)
-				udbg_printf("do_signal32 - processing signal=%2lx - pid=%ld, comm=%s \n", signr, current->pid, current->comm);
-		}
 
 		if (!signr)
 			break;
@@ -1298,14 +1191,6 @@
 			}
 		}
 
-		PPCDBG(PPCDBG_SIGNAL, " do signal :sigaction flags = %lx \n" ,ka->sa.sa_flags);
-		PPCDBG(PPCDBG_SIGNAL, " do signal :on sig stack  = %lx \n" ,on_sig_stack(regs->gpr[1]));
-		PPCDBG(PPCDBG_SIGNAL, " do signal :reg1  = %lx \n" ,regs->gpr[1]);
-		PPCDBG(PPCDBG_SIGNAL, " do signal :alt stack  = %lx \n" ,current->sas_ss_sp);
-		PPCDBG(PPCDBG_SIGNAL, " do signal :alt stack size  = %lx \n" ,current->sas_ss_size);
-
-
-
 		if ( (ka->sa.sa_flags & SA_ONSTACK)
 		     && (! on_sig_stack(regs->gpr[1])))
 			newsp = (current->sas_ss_sp + current->sas_ss_size);
@@ -1333,8 +1218,10 @@
 
 	/* Invoke correct stack setup routine */
 	if (ka->sa.sa_flags & SA_SIGINFO) 
-		setup_rt_frame32(regs, (struct sigregs32*)(u64)frame, newsp);
+		setup_rt_frame32(regs, signr, ka,
+				 (struct sigregs32*)(u64)frame, newsp);
 	else
-		setup_frame32(regs, (struct sigregs32*)(u64)frame, newsp);
+		setup_frame32(regs, signr, ka,
+			      (struct sigregs32*)(u64)frame, newsp);
 	return 1;
 }
diff -urN linux-2.4.28-bk7/arch/ppc64/kernel/sys_ppc32.c linux-2.4.29/arch/ppc64/kernel/sys_ppc32.c
--- linux-2.4.28-bk7/arch/ppc64/kernel/sys_ppc32.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/arch/ppc64/kernel/sys_ppc32.c	2005-01-19 07:08:06.386348958 -0800
@@ -3273,6 +3273,11 @@
 				    (struct cmsghdr32 *)(ctl) : \
 				    (struct cmsghdr32 *)NULL)
 #define CMSG32_FIRSTHDR(msg)	__CMSG32_FIRSTHDR((msg)->msg_control, (msg)->msg_controllen)
+#define CMSG32_OK(ucmlen, ucmsg, mhdr) \
+	((ucmlen) >= sizeof(struct cmsghdr32) && \
+	 (ucmlen) <= (unsigned long) \
+	 ((mhdr)->msg_controllen - \
+	  ((char *)(ucmsg) - (char *)(mhdr)->msg_control)))
 
 struct msghdr32
 {
@@ -3448,11 +3453,7 @@
 			return -EFAULT;
 
 		/* Catch bogons. */
-		if(CMSG32_ALIGN(ucmlen) <
-		   CMSG32_ALIGN(sizeof(struct cmsghdr32)))
-			return -EINVAL;
-		if((unsigned long)(((char *)ucmsg - (char *)kmsg->msg_control)
-				   + ucmlen) > kmsg->msg_controllen)
+		if (!CMSG32_OK(ucmlen, ucmsg, kmsg))
 			return -EINVAL;
 
 		tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) +
diff -urN linux-2.4.28-bk7/arch/s390/defconfig linux-2.4.29/arch/s390/defconfig
--- linux-2.4.28-bk7/arch/s390/defconfig	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/arch/s390/defconfig	2005-01-19 07:08:06.412350084 -0800
@@ -199,7 +199,6 @@
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
-CONFIG_IP_NF_NAT_LOCAL=y
 # CONFIG_IP_NF_NAT_SNMP_BASIC is not set
 CONFIG_IP_NF_NAT_IRC=m
 CONFIG_IP_NF_NAT_FTP=m
diff -urN linux-2.4.28-bk7/arch/s390x/kernel/exec32.c linux-2.4.29/arch/s390x/kernel/exec32.c
--- linux-2.4.28-bk7/arch/s390x/kernel/exec32.c	2001-04-11 19:02:29.000000000 -0700
+++ linux-2.4.29/arch/s390x/kernel/exec32.c	2005-01-19 07:08:06.417350301 -0800
@@ -41,7 +41,7 @@
 {
 	unsigned long stack_base;
 	struct vm_area_struct *mpnt;
-	int i;
+	int i, ret;
 
 	stack_base = STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE;
 
@@ -65,7 +65,11 @@
 		mpnt->vm_pgoff = 0;
 		mpnt->vm_file = NULL;
 		mpnt->vm_private_data = (void *) 0;
-		insert_vm_struct(current->mm, mpnt);
+		if ((ret = insert_vm_struct(current->mm, mpnt))) {
+			up_write(&current->mm->mmap_sem);
+			kmem_cache_free(vm_area_cachep, mpnt);
+			return ret;
+		}
 		current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
 	} 
 
diff -urN linux-2.4.28-bk7/arch/s390x/kernel/linux32.c linux-2.4.29/arch/s390x/kernel/linux32.c
--- linux-2.4.28-bk7/arch/s390x/kernel/linux32.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/arch/s390x/kernel/linux32.c	2005-01-19 07:08:06.579357317 -0800
@@ -2306,6 +2306,11 @@
 				    (struct cmsghdr32 *)(ctl) : \
 				    (struct cmsghdr32 *)NULL)
 #define CMSG32_FIRSTHDR(msg)	__CMSG32_FIRSTHDR((msg)->msg_control, (msg)->msg_controllen)
+#define CMSG32_OK(ucmlen, ucmsg, mhdr) \
+	((ucmlen) >= sizeof(struct cmsghdr32) && \
+	 (ucmlen) <= (unsigned long) \
+	 ((mhdr)->msg_controllen - \
+	  ((char *)(ucmsg) - (char *)(mhdr)->msg_control)))
 
 __inline__ struct cmsghdr32 *__cmsg32_nxthdr(void *__ctl, __kernel_size_t __size,
 					      struct cmsghdr32 *__cmsg, int __cmsg_len)
@@ -2432,11 +2437,7 @@
 			return -EFAULT;
 
 		/* Catch bogons. */
-		if(CMSG32_ALIGN(ucmlen) <
-		   CMSG32_ALIGN(sizeof(struct cmsghdr32)))
-			return -EINVAL;
-		if((unsigned long)(((char *)ucmsg - (char *)kmsg->msg_control)
-				   + ucmlen) > kmsg->msg_controllen)
+		if (!CMSG32_OK(ucmlen, ucmsg, kmsg))
 			return -EINVAL;
 
 		tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) +
diff -urN linux-2.4.28-bk7/arch/sparc64/defconfig linux-2.4.29/arch/sparc64/defconfig
--- linux-2.4.28-bk7/arch/sparc64/defconfig	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/arch/sparc64/defconfig	2005-01-19 07:08:06.668361172 -0800
@@ -253,7 +253,6 @@
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
 CONFIG_IP_NF_NAT_AMANDA=m
-# CONFIG_IP_NF_NAT_LOCAL is not set
 CONFIG_IP_NF_NAT_SNMP_BASIC=m
 CONFIG_IP_NF_NAT_IRC=m
 CONFIG_IP_NF_NAT_FTP=m
@@ -415,6 +414,7 @@
 # CONFIG_IDEDISK_MULTI_MODE is not set
 # CONFIG_IDEDISK_STROKE is not set
 # CONFIG_BLK_DEV_IDECS is not set
+# CONFIG_BLK_DEV_DELKIN is not set
 CONFIG_BLK_DEV_IDECD=y
 CONFIG_BLK_DEV_IDETAPE=m
 CONFIG_BLK_DEV_IDEFLOPPY=m
@@ -1128,6 +1128,7 @@
 CONFIG_CRYPTO_SHA1=y
 CONFIG_CRYPTO_SHA256=m
 CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_WP512=m
 CONFIG_CRYPTO_DES=y
 CONFIG_CRYPTO_BLOWFISH=m
 CONFIG_CRYPTO_TWOFISH=m
@@ -1137,6 +1138,7 @@
 CONFIG_CRYPTO_CAST6=m
 CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_ANUBIS=m
 CONFIG_CRYPTO_ARC4=m
 CONFIG_CRYPTO_DEFLATE=y
 CONFIG_CRYPTO_MICHAEL_MIC=m
diff -urN linux-2.4.28-bk7/arch/sparc64/kernel/binfmt_aout32.c linux-2.4.29/arch/sparc64/kernel/binfmt_aout32.c
--- linux-2.4.28-bk7/arch/sparc64/kernel/binfmt_aout32.c	2002-08-02 17:39:43.000000000 -0700
+++ linux-2.4.29/arch/sparc64/kernel/binfmt_aout32.c	2005-01-19 07:08:06.736364117 -0800
@@ -49,7 +49,9 @@
 	end = PAGE_ALIGN(end);
 	if (end <= start)
 		return;
+	down_write(&current->mm->mmap_sem);
 	do_brk(start, end - start);
+	up_write(&current->mm->mmap_sem);
 }
 
 /*
@@ -246,10 +248,14 @@
 	if (N_MAGIC(ex) == NMAGIC) {
 		loff_t pos = fd_offset;
 		/* Fuck me plenty... */
+		down_write(&current->mm->mmap_sem);
 		error = do_brk(N_TXTADDR(ex), ex.a_text);
+		up_write(&current->mm->mmap_sem);
 		bprm->file->f_op->read(bprm->file, (char *) N_TXTADDR(ex),
 			  ex.a_text, &pos);
+		down_write(&current->mm->mmap_sem);
 		error = do_brk(N_DATADDR(ex), ex.a_data);
+		up_write(&current->mm->mmap_sem);
 		bprm->file->f_op->read(bprm->file, (char *) N_DATADDR(ex),
 			  ex.a_data, &pos);
 		goto beyond_if;
@@ -257,8 +263,11 @@
 
 	if (N_MAGIC(ex) == OMAGIC) {
 		loff_t pos = fd_offset;
+		down_write(&current->mm->mmap_sem);
 		do_brk(N_TXTADDR(ex) & PAGE_MASK,
 			ex.a_text+ex.a_data + PAGE_SIZE - 1);
+		up_write(&current->mm->mmap_sem);
+		
 		bprm->file->f_op->read(bprm->file, (char *) N_TXTADDR(ex),
 			  ex.a_text+ex.a_data, &pos);
 	} else {
@@ -272,7 +281,9 @@
 
 		if (!bprm->file->f_op->mmap) {
 			loff_t pos = fd_offset;
+			down_write(&current->mm->mmap_sem);
 			do_brk(0, ex.a_text+ex.a_data);
+			up_write(&current->mm->mmap_sem);
 			bprm->file->f_op->read(bprm->file,(char *)N_TXTADDR(ex),
 				  ex.a_text+ex.a_data, &pos);
 			goto beyond_if;
@@ -388,7 +399,9 @@
 	len = PAGE_ALIGN(ex.a_text + ex.a_data);
 	bss = ex.a_text + ex.a_data + ex.a_bss;
 	if (bss > len) {
+		down_write(&current->mm->mmap_sem);
 		error = do_brk(start_addr + len, bss - len);
+		up_write(&current->mm->mmap_sem);
 		retval = error;
 		if (error != start_addr + len)
 			goto out;
diff -urN linux-2.4.28-bk7/arch/sparc64/kernel/binfmt_elf32.c linux-2.4.29/arch/sparc64/kernel/binfmt_elf32.c
--- linux-2.4.28-bk7/arch/sparc64/kernel/binfmt_elf32.c	2003-06-13 07:51:32.000000000 -0700
+++ linux-2.4.29/arch/sparc64/kernel/binfmt_elf32.c	2005-01-19 07:08:06.776365850 -0800
@@ -81,7 +81,7 @@
 
 #define elf_check_arch(x)	(((x)->e_machine == EM_SPARC) || ((x)->e_machine == EM_SPARC32PLUS))
 
-#define ELF_ET_DYN_BASE         0x08000000
+#define ELF_ET_DYN_BASE         0x70000000
 
 
 #include <asm/processor.h>
diff -urN linux-2.4.28-bk7/arch/sparc64/kernel/ioctl32.c linux-2.4.29/arch/sparc64/kernel/ioctl32.c
--- linux-2.4.28-bk7/arch/sparc64/kernel/ioctl32.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/arch/sparc64/kernel/ioctl32.c	2005-01-19 07:08:07.343390408 -0800
@@ -4918,6 +4918,10 @@
 COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOVER)
 COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE)
 COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE_MULTI)
+COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOSUBVER)
+COMPATIBLE_IOCTL(AUTOFS_IOC_ASKREGHOST)
+COMPATIBLE_IOCTL(AUTOFS_IOC_TOGGLEREGHOST)
+COMPATIBLE_IOCTL(AUTOFS_IOC_ASKUMOUNT)
 /* DEVFS */
 COMPATIBLE_IOCTL(DEVFSDIOC_GET_PROTO_REV)
 COMPATIBLE_IOCTL(DEVFSDIOC_SET_EVENT_MASK)
@@ -4928,6 +4932,7 @@
 COMPATIBLE_IOCTL(RAW_GETBIND)
 /* SMB ioctls which do not need any translations */
 COMPATIBLE_IOCTL(SMB_IOC_NEWCONN)
+COMPATIBLE_IOCTL(SMB_IOC_GETMOUNTUID32)
 /* NCP ioctls which do not need any translations */
 COMPATIBLE_IOCTL(NCP_IOC_CONN_LOGGED_IN)
 COMPATIBLE_IOCTL(NCP_IOC_SIGN_INIT)
diff -urN linux-2.4.28-bk7/arch/sparc64/kernel/smp.c linux-2.4.29/arch/sparc64/kernel/smp.c
--- linux-2.4.28-bk7/arch/sparc64/kernel/smp.c	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.29/arch/sparc64/kernel/smp.c	2005-01-19 07:08:07.422393829 -0800
@@ -137,15 +137,6 @@
 void __init smp_callin(void)
 {
 	int cpuid = hard_smp_processor_id();
-	extern int bigkernel;
-	extern unsigned long kern_locked_tte_data;
-
-	if (bigkernel) {
-		prom_dtlb_load(sparc64_highest_locked_tlbent()-1, 
-			kern_locked_tte_data + 0x400000, KERNBASE + 0x400000);
-		prom_itlb_load(sparc64_highest_locked_tlbent()-1, 
-			kern_locked_tte_data + 0x400000, KERNBASE + 0x400000);
-	}
 
 	inherit_locked_prom_mappings(0);
 
diff -urN linux-2.4.28-bk7/arch/sparc64/kernel/sys_sparc32.c linux-2.4.29/arch/sparc64/kernel/sys_sparc32.c
--- linux-2.4.28-bk7/arch/sparc64/kernel/sys_sparc32.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/arch/sparc64/kernel/sys_sparc32.c	2005-01-19 07:08:07.583400802 -0800
@@ -2354,6 +2354,11 @@
 				    (struct cmsghdr32 *)(ctl) : \
 				    (struct cmsghdr32 *)NULL)
 #define CMSG32_FIRSTHDR(msg)	__CMSG32_FIRSTHDR((msg)->msg_control, (msg)->msg_controllen)
+#define CMSG32_OK(ucmlen, ucmsg, mhdr) \
+	((ucmlen) >= sizeof(struct cmsghdr32) && \
+	 (ucmlen) <= (unsigned long) \
+	 ((mhdr)->msg_controllen - \
+	  ((char *)(ucmsg) - (char *)(mhdr)->msg_control)))
 
 __inline__ struct cmsghdr32 *__cmsg32_nxthdr(void *__ctl, __kernel_size_t __size,
 					      struct cmsghdr32 *__cmsg, int __cmsg_len)
@@ -2480,11 +2485,7 @@
 			return -EFAULT;
 
 		/* Catch bogons. */
-		if(CMSG32_ALIGN(ucmlen) <
-		   CMSG32_ALIGN(sizeof(struct cmsghdr32)))
-			return -EINVAL;
-		if((unsigned long)(((char *)ucmsg - (char *)kmsg->msg_control)
-				   + ucmlen) > kmsg->msg_controllen)
+		if (!CMSG32_OK(ucmlen, ucmsg, kmsg))
 			return -EINVAL;
 
 		tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) +
diff -urN linux-2.4.28-bk7/arch/sparc64/kernel/trampoline.S linux-2.4.29/arch/sparc64/kernel/trampoline.S
--- linux-2.4.28-bk7/arch/sparc64/kernel/trampoline.S	2003-06-13 07:51:32.000000000 -0700
+++ linux-2.4.29/arch/sparc64/kernel/trampoline.S	2005-01-19 07:08:07.635403055 -0800
@@ -90,7 +90,9 @@
 	sllx		%g2, 32, %g2
 	wr		%g2, 0, %tick_cmpr
 
-	/* Call OBP by hand to lock KERNBASE into i/d tlbs. */
+	/* Call OBP by hand to lock KERNBASE into i/d tlbs.
+	 * We lock 2 consequetive entries if we are 'bigkernel'.
+	 */
 	mov		%o0, %l0
 
 	sethi		%hi(prom_entry_lock), %g2
@@ -136,6 +138,46 @@
 	call		%o1
 	 add		%sp, (2047 + 128), %o0
 
+	sethi		%hi(bigkernel), %g2
+	lduw		[%g2 + %lo(bigkernel)], %g2
+	cmp		%g2, 0
+	be,pt		%icc, do_dtlb
+	 nop
+
+	sethi		%hi(call_method), %g2
+	or		%g2, %lo(call_method), %g2
+	stx		%g2, [%sp + 2047 + 128 + 0x00]
+	mov		5, %g2
+	stx		%g2, [%sp + 2047 + 128 + 0x08]
+	mov		1, %g2
+	stx		%g2, [%sp + 2047 + 128 + 0x10]
+	sethi		%hi(itlb_load), %g2
+	or		%g2, %lo(itlb_load), %g2
+	stx		%g2, [%sp + 2047 + 128 + 0x18]
+	sethi		%hi(mmu_ihandle_cache), %g2
+	lduw		[%g2 + %lo(mmu_ihandle_cache)], %g2
+	stx		%g2, [%sp + 2047 + 128 + 0x20]
+	sethi		%hi(KERNBASE + 0x400000), %g2
+	stx		%g2, [%sp + 2047 + 128 + 0x28]
+	sethi		%hi(kern_locked_tte_data), %g2
+	ldx		[%g2 + %lo(kern_locked_tte_data)], %g2
+	sethi		%hi(0x400000), %g1
+	add		%g2, %g1, %g2
+	stx		%g2, [%sp + 2047 + 128 + 0x30]
+
+	mov		14, %g2
+	BRANCH_IF_ANY_CHEETAH(g1,g5,1f)
+
+	mov		62, %g2
+1:
+	stx		%g2, [%sp + 2047 + 128 + 0x38]
+	sethi		%hi(p1275buf), %g2
+	or		%g2, %lo(p1275buf), %g2
+	ldx		[%g2 + 0x08], %o1
+	call		%o1
+	 add		%sp, (2047 + 128), %o0
+
+do_dtlb:
 	sethi		%hi(call_method), %g2
 	or		%g2, %lo(call_method), %g2
 	stx		%g2, [%sp + 2047 + 128 + 0x00]
@@ -168,6 +210,47 @@
 	call		%o1
 	 add		%sp, (2047 + 128), %o0
 
+	sethi		%hi(bigkernel), %g2
+	lduw		[%g2 + %lo(bigkernel)], %g2
+	cmp		%g2, 0
+	be,pt		%icc, do_unlock
+	 nop
+
+	sethi		%hi(call_method), %g2
+	or		%g2, %lo(call_method), %g2
+	stx		%g2, [%sp + 2047 + 128 + 0x00]
+	mov		5, %g2
+	stx		%g2, [%sp + 2047 + 128 + 0x08]
+	mov		1, %g2
+	stx		%g2, [%sp + 2047 + 128 + 0x10]
+	sethi		%hi(dtlb_load), %g2
+	or		%g2, %lo(dtlb_load), %g2
+	stx		%g2, [%sp + 2047 + 128 + 0x18]
+	sethi		%hi(mmu_ihandle_cache), %g2
+	lduw		[%g2 + %lo(mmu_ihandle_cache)], %g2
+	stx		%g2, [%sp + 2047 + 128 + 0x20]
+	sethi		%hi(KERNBASE + 0x400000), %g2
+	stx		%g2, [%sp + 2047 + 128 + 0x28]
+	sethi		%hi(kern_locked_tte_data), %g2
+	ldx		[%g2 + %lo(kern_locked_tte_data)], %g2
+	sethi		%hi(0x400000), %g1
+	add		%g2, %g1, %g2
+	stx		%g2, [%sp + 2047 + 128 + 0x30]
+
+	mov		14, %g2
+	BRANCH_IF_ANY_CHEETAH(g1,g5,1f)
+
+	mov		62, %g2
+1:
+
+	stx		%g2, [%sp + 2047 + 128 + 0x38]
+	sethi		%hi(p1275buf), %g2
+	or		%g2, %lo(p1275buf), %g2
+	ldx		[%g2 + 0x08], %o1
+	call		%o1
+	 add		%sp, (2047 + 128), %o0
+
+do_unlock:
 	sethi		%hi(prom_entry_lock), %g2
 	stb		%g0, [%g2 + %lo(prom_entry_lock)]
 	membar		#StoreStore | #StoreLoad
diff -urN linux-2.4.28-bk7/arch/x86_64/ia32/ia32_binfmt.c linux-2.4.29/arch/x86_64/ia32/ia32_binfmt.c
--- linux-2.4.28-bk7/arch/x86_64/ia32/ia32_binfmt.c	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.29/arch/x86_64/ia32/ia32_binfmt.c	2005-01-19 07:08:07.680405004 -0800
@@ -225,7 +225,7 @@
 {
 	unsigned long stack_base;
 	struct vm_area_struct *mpnt;
-	int i;
+	int i, ret;
 
 	stack_base = IA32_STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE;
 
@@ -250,7 +250,11 @@
 		mpnt->vm_pgoff = 0;
 		mpnt->vm_file = NULL;
 		mpnt->vm_private_data = (void *) 0;
-		insert_vm_struct(current->mm, mpnt);
+		if ((ret = insert_vm_struct(current->mm, mpnt))) {
+			up_write(&current->mm->mmap_sem);
+			kmem_cache_free(vm_area_cachep, mpnt);
+			return ret;
+		}
 		current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
 	} 
 
diff -urN linux-2.4.28-bk7/arch/x86_64/ia32/ia32_ioctl.c linux-2.4.29/arch/x86_64/ia32/ia32_ioctl.c
--- linux-2.4.28-bk7/arch/x86_64/ia32/ia32_ioctl.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/arch/x86_64/ia32/ia32_ioctl.c	2005-01-19 07:08:07.778409248 -0800
@@ -4099,6 +4099,10 @@
 COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOVER)
 COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE)
 COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE_MULTI)
+COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOSUBVER)
+COMPATIBLE_IOCTL(AUTOFS_IOC_ASKREGHOST)
+COMPATIBLE_IOCTL(AUTOFS_IOC_TOGGLEREGHOST)
+COMPATIBLE_IOCTL(AUTOFS_IOC_ASKUMOUNT)
 /* DEVFS */
 COMPATIBLE_IOCTL(DEVFSDIOC_GET_PROTO_REV)
 COMPATIBLE_IOCTL(DEVFSDIOC_SET_EVENT_MASK)
diff -urN linux-2.4.28-bk7/arch/x86_64/ia32/ia32entry.S linux-2.4.29/arch/x86_64/ia32/ia32entry.S
--- linux-2.4.28-bk7/arch/x86_64/ia32/ia32entry.S	2004-08-07 16:26:04.000000000 -0700
+++ linux-2.4.29/arch/x86_64/ia32/ia32entry.S	2005-01-19 07:08:07.831411544 -0800
@@ -52,6 +52,7 @@
 ENTRY(ia32_syscall)
 	swapgs	
 	sti
+	movl %eax,%eax	
 	pushq %rax
 	cld
 	SAVE_ARGS
diff -urN linux-2.4.28-bk7/arch/x86_64/ia32/ptrace32.c linux-2.4.29/arch/x86_64/ia32/ptrace32.c
--- linux-2.4.28-bk7/arch/x86_64/ia32/ptrace32.c	2004-04-14 06:05:28.000000000 -0700
+++ linux-2.4.29/arch/x86_64/ia32/ptrace32.c	2005-01-19 07:08:07.832411587 -0800
@@ -185,12 +185,12 @@
 			goto out;
 		*err = ptrace_check_attach(child, request == PTRACE_KILL); 
 		if (*err < 0) 
-				goto out;
+			goto out;
 		return child; 
-	} 
 
  out:
-	free_task_struct(child);
+		free_task_struct(child);
+	} 
 	return NULL; 
 	
 } 
diff -urN linux-2.4.28-bk7/arch/x86_64/ia32/socket32.c linux-2.4.29/arch/x86_64/ia32/socket32.c
--- linux-2.4.28-bk7/arch/x86_64/ia32/socket32.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/arch/x86_64/ia32/socket32.c	2005-01-19 07:08:08.052421116 -0800
@@ -136,12 +136,9 @@
 			return -EFAULT;
 
 		/* Catch bogons. */
-		if(CMSG32_ALIGN(ucmlen) <
-		   CMSG32_ALIGN(sizeof(struct cmsghdr32)))
-			return -EINVAL;
-		if((unsigned long)(((char *)ucmsg - (char *)kmsg->msg_control)
-				   + ucmlen) > kmsg->msg_controllen)
+		if (!CMSG32_OK(ucmlen, ucmsg, kmsg))
 			return -EINVAL;
+
 		if (kmsg->msg_controllen > 65536) 
 			return -EINVAL;
 
diff -urN linux-2.4.28-bk7/arch/x86_64/kernel/setup.c linux-2.4.29/arch/x86_64/kernel/setup.c
--- linux-2.4.28-bk7/arch/x86_64/kernel/setup.c	2004-08-07 16:26:04.000000000 -0700
+++ linux-2.4.29/arch/x86_64/kernel/setup.c	2005-01-19 07:08:08.316432550 -0800
@@ -52,6 +52,7 @@
 EXPORT_SYMBOL(acpi_disabled);
 
 int swiotlb;
+EXPORT_SYMBOL(swiotlb);
 
 extern	int phys_proc_id[NR_CPUS];
 
diff -urN linux-2.4.28-bk7/arch/x86_64/kernel/signal.c linux-2.4.29/arch/x86_64/kernel/signal.c
--- linux-2.4.28-bk7/arch/x86_64/kernel/signal.c	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.29/arch/x86_64/kernel/signal.c	2005-01-19 07:08:08.356434282 -0800
@@ -561,7 +561,7 @@
 	}
 
 	/* Did we come from a system call? */
-	if (regs->orig_rax >= 0) {
+	if ((long)regs->orig_rax >= 0) {
 		/* Restart the system call - no handlers present */
 		if (regs->rax == -ERESTARTNOHAND ||
 		    regs->rax == -ERESTARTSYS ||
diff -urN linux-2.4.28-bk7/drivers/acpi/bus.c linux-2.4.29/drivers/acpi/bus.c
--- linux-2.4.28-bk7/drivers/acpi/bus.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/drivers/acpi/bus.c	2005-01-19 07:08:08.665447666 -0800
@@ -1850,7 +1850,10 @@
 	acpi_status		status = AE_OK;
 	struct acpi_buffer	buffer = {sizeof(acpi_fadt), &acpi_fadt};
 
-	ACPI_FUNCTION_TRACE("acpi_bus_init");
+	ACPI_FUNCTION_TRACE("acpi_early_init");
+
+	if (acpi_disabled)
+		return_VOID;
 
 	status = acpi_initialize_subsystem();
 	if (ACPI_FAILURE(status)) {
@@ -1899,11 +1902,11 @@
 		goto error0;
 	}
 
-	return;
+	return_VOID;
 
 error0:
 	disable_acpi();
-	return;
+	return_VOID;
 }
 
 static int __init
diff -urN linux-2.4.28-bk7/drivers/block/floppy.c linux-2.4.29/drivers/block/floppy.c
--- linux-2.4.28-bk7/drivers/block/floppy.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.29/drivers/block/floppy.c	2005-01-19 07:08:08.702449268 -0800
@@ -4255,6 +4255,14 @@
 		max_buffer_sectors = 0;
 	}
 
+	/*
+	 * Small 10 msec delay to let through any interrupt that
+	 * initialization might have triggered, to not
+	 * confuse detection:
+	 */
+	current->state = TASK_UNINTERRUPTIBLE;
+	schedule_timeout(HZ/100 + 1);
+
 	for (i = 0; i < N_FDC; i++) {
 		fdc = i;
 		FDCS->driver_version = FD_DRIVER_VERSION;
diff -urN linux-2.4.28-bk7/drivers/block/sx8.c linux-2.4.29/drivers/block/sx8.c
--- linux-2.4.28-bk7/drivers/block/sx8.c	2004-08-07 16:26:04.000000000 -0700
+++ linux-2.4.29/drivers/block/sx8.c	2005-01-19 07:08:08.704449355 -0800
@@ -548,17 +548,6 @@
 	return -EOPNOTSUPP;
 }
 
-static inline unsigned long msecs_to_jiffies(unsigned long msecs)
-{
-	return ((HZ * msecs + 999) / 1000);
-}
-
-static void msleep(unsigned long msecs)
-{
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(msecs_to_jiffies(msecs) + 1);
-}
-
 static const u32 msg_sizes[] = { 32, 64, 128, CARM_MSG_SIZE };
 
 static inline int carm_lookup_bucket(u32 msg_size)
diff -urN linux-2.4.28-bk7/drivers/bluetooth/hci_ldisc.c linux-2.4.29/drivers/bluetooth/hci_ldisc.c
--- linux-2.4.28-bk7/drivers/bluetooth/hci_ldisc.c	2004-08-07 16:26:04.000000000 -0700
+++ linux-2.4.29/drivers/bluetooth/hci_ldisc.c	2005-01-19 07:08:08.743451044 -0800
@@ -188,9 +188,7 @@
 		kfree_skb(hu->tx_skb); hu->tx_skb = NULL;
 	}
 
-	/* Flush any pending characters in the driver and discipline. */
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
+	tty_ldisc_flush(tty);
 
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
@@ -283,9 +281,10 @@
 
 	spin_lock_init(&hu->rx_lock);
 
-	/* Flush any pending characters in the driver and line discipline */
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
+	/* Flush any pending characters in the driver and line discipline. */
+	/* FIXME: why is this needed. Note don't use ldisc_ref here as the
+	   open path is before the ldisc is referencable */
+	tty_ldisc_flush(tty);
 
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
diff -urN linux-2.4.28-bk7/drivers/char/amiserial.c linux-2.4.29/drivers/char/amiserial.c
--- linux-2.4.28-bk7/drivers/char/amiserial.c	2002-11-28 15:53:12.000000000 -0800
+++ linux-2.4.29/drivers/char/amiserial.c	2005-01-19 07:08:08.746451174 -0800
@@ -575,10 +575,7 @@
 		return;
 
 	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
-		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-		    tty->ldisc.write_wakeup)
-			(tty->ldisc.write_wakeup)(tty);
-		wake_up_interruptible(&tty->write_wait);
+		tty_wakeup(tty);
 	}
 }
 
@@ -1040,10 +1037,7 @@
 	save_flags(flags); cli();
 	info->xmit.head = info->xmit.tail = 0;
 	restore_flags(flags);
-	wake_up_interruptible(&tty->write_wait);
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	    tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup)(tty);
+	tty_wakeup(tty);
 }
 
 /*
@@ -1581,8 +1575,8 @@
 	 * the line discipline to only process XON/XOFF characters.
 	 */
 	tty->closing = 1;
-	if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-		tty_wait_until_sent(tty, info->closing_wait);
+	if (state->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+		tty_wait_until_sent(tty, state->closing_wait);
 	/*
 	 * At this point we stop accepting input.  To do this, we
 	 * disable the receive line status interrupts, and tell the
@@ -1608,15 +1602,14 @@
 	shutdown(info);
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
+	tty_ldisc_flush(tty);
 	tty->closing = 0;
 	info->event = 0;
 	info->tty = 0;
 	if (info->blocked_open) {
-		if (info->close_delay) {
+		if (state->close_delay) {
 			current->state = TASK_INTERRUPTIBLE;
-			schedule_timeout(info->close_delay);
+			schedule_timeout(state->close_delay);
 		}
 		wake_up_interruptible(&info->open_wait);
 	}
diff -urN linux-2.4.28-bk7/drivers/char/au1x00-serial.c linux-2.4.29/drivers/char/au1x00-serial.c
--- linux-2.4.28-bk7/drivers/char/au1x00-serial.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.29/drivers/char/au1x00-serial.c	2005-01-19 07:08:08.749451304 -0800
@@ -1948,8 +1948,8 @@
 	 * the line discipline to only process XON/XOFF characters.
 	 */
 	tty->closing = 1;
-	if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-		tty_wait_until_sent(tty, info->closing_wait);
+	if (state->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+		tty_wait_until_sent(tty, state->closing_wait);
 	/*
 	 * At this point we stop accepting input.  To do this, we
 	 * disable the receive line status interrupts, and tell the
@@ -1976,9 +1976,9 @@
 	info->event = 0;
 	info->tty = 0;
 	if (info->blocked_open) {
-		if (info->close_delay) {
+		if (state->close_delay) {
 			set_current_state(TASK_INTERRUPTIBLE);
-			schedule_timeout(info->close_delay);
+			schedule_timeout(state->close_delay);
 		}
 		wake_up_interruptible(&info->open_wait);
 	}
diff -urN linux-2.4.28-bk7/drivers/char/console.c linux-2.4.29/drivers/char/console.c
--- linux-2.4.28-bk7/drivers/char/console.c	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.29/drivers/char/console.c	2005-01-19 07:08:08.750451347 -0800
@@ -705,6 +705,9 @@
 	return 0;
 }
 
+#define VC_RESIZE_MAXCOL (32767)
+#define VC_RESIZE_MAXROW (32767)
+
 /*
  * Change # of rows and columns (0 means unchanged/the size of fg_console)
  * [this is to be used together with some user program
@@ -717,6 +720,9 @@
 	unsigned int currcons = fg_console, i;
 	unsigned short *newscreens[MAX_NR_CONSOLES];
 
+	if (cols > VC_RESIZE_MAXCOL || lines > VC_RESIZE_MAXROW)
+		return -EINVAL;
+
 	cc = (cols ? cols : video_num_columns);
 	ll = (lines ? lines : video_num_lines);
 	sr = cc << 1;
diff -urN linux-2.4.28-bk7/drivers/char/cyclades.c linux-2.4.29/drivers/char/cyclades.c
--- linux-2.4.28-bk7/drivers/char/cyclades.c	2003-06-13 07:51:32.000000000 -0700
+++ linux-2.4.29/drivers/char/cyclades.c	2005-01-19 07:08:08.755451564 -0800
@@ -1000,11 +1000,7 @@
 	wake_up_interruptible(&info->delta_msr_wait);
     }
     if (test_and_clear_bit(Cy_EVENT_WRITE_WAKEUP, &info->event)) {
-        if((tty->flags & (1<< TTY_DO_WRITE_WAKEUP))
-        && tty->ldisc.write_wakeup){
-            (tty->ldisc.write_wakeup)(tty);
-        }
-        wake_up_interruptible(&tty->write_wait);
+	tty_wakeup(tty);
     }
 #ifdef Z_WAKE
     if (test_and_clear_bit(Cy_EVENT_SHUTDOWN_WAKEUP, &info->event)) {
@@ -2918,8 +2914,7 @@
     shutdown(info);
     if (tty->driver.flush_buffer)
         tty->driver.flush_buffer(tty);
-    if (tty->ldisc.flush_buffer)
-        tty->ldisc.flush_buffer(tty);
+    tty_ldisc_flush(tty);
     CY_LOCK(info, flags);
 
     tty->closing = 0;
@@ -4689,10 +4684,7 @@
 	}
 	CY_UNLOCK(info, flags);
     }
-    wake_up_interruptible(&tty->write_wait);
-    if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP))
-	&& tty->ldisc.write_wakeup)
-	    (tty->ldisc.write_wakeup)(tty);
+    tty_wakeup(tty);
 } /* cy_flush_buffer */
 
 
diff -urN linux-2.4.28-bk7/drivers/char/dz.c linux-2.4.29/drivers/char/dz.c
--- linux-2.4.28-bk7/drivers/char/dz.c	2004-02-18 05:36:31.000000000 -0800
+++ linux-2.4.29/drivers/char/dz.c	2005-01-19 07:08:08.756451607 -0800
@@ -402,9 +402,7 @@
 		return;
 
 	if (test_and_clear_bit(DZ_EVENT_WRITE_WAKEUP, &info->event)) {
-		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
-			(tty->ldisc.write_wakeup) (tty);
-		wake_up_interruptible(&tty->write_wait);
+		tty_wakeup(tty);
 	}
 }
 
@@ -804,10 +802,7 @@
 	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
 	sti();
 
-	wake_up_interruptible(&tty->write_wait);
-
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup) (tty);
+	tty_wakeup(tty);
 }
 
 /*
@@ -1106,16 +1101,15 @@
 
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
+	tty_ldisc_flush(tty);
 	tty->closing = 0;
 	info->event = 0;
 	info->tty = 0;
 
-	if (tty->ldisc.num != ldiscs[N_TTY].num) {
+	if (tty->ldisc.num != N_TTY) {
 		if (tty->ldisc.close)
 			(tty->ldisc.close) (tty);
-		tty->ldisc = ldiscs[N_TTY];
+		tty->ldisc = *(tty_ldisc_get(N_TTY));
 		tty->termios->c_line = N_TTY;
 		if (tty->ldisc.open)
 			(tty->ldisc.open) (tty);
diff -urN linux-2.4.28-bk7/drivers/char/epca.c linux-2.4.29/drivers/char/epca.c
--- linux-2.4.28-bk7/drivers/char/epca.c	2003-06-13 07:51:33.000000000 -0700
+++ linux-2.4.29/drivers/char/epca.c	2005-01-19 07:08:08.759451737 -0800
@@ -585,9 +585,7 @@
 		if (tty->driver.flush_buffer)
 			tty->driver.flush_buffer(tty);
 
-		if (tty->ldisc.flush_buffer)
-			tty->ldisc.flush_buffer(tty);
-
+		tty_ldisc_flush(tty);
 		shutdown(ch);
 		tty->closing = 0;
 		ch->event = 0;
@@ -692,15 +690,13 @@
 		cli();
 		if (tty->driver.flush_buffer)
 			tty->driver.flush_buffer(tty);
-
-		if (tty->ldisc.flush_buffer)
-			tty->ldisc.flush_buffer(tty);
-
+		
+		tty_ldisc_flush(tty);
+		
 		shutdown(ch);
 
 		if (ch->count)
 			MOD_DEC_USE_COUNT;
-		
 
 		ch->tty   = NULL;
 		ch->event = 0;
@@ -1175,9 +1171,7 @@
 	memoff(ch);
 	restore_flags(flags);
 
-	wake_up_interruptible(&tty->write_wait);
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup)(tty);
+	tty_wakeup(tty);
 
 } /* End pc_flush_buffer */
 
@@ -2383,10 +2377,7 @@
 				{ /* Begin if LOWWAIT */
 
 					ch->statusflags &= ~LOWWAIT;
-					if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-						  tty->ldisc.write_wakeup)
-						(tty->ldisc.write_wakeup)(tty);
-					wake_up_interruptible(&tty->write_wait);
+					tty_wakeup(tty);
 
 				} /* End if LOWWAIT */
 
@@ -2402,11 +2393,7 @@
 				{ /* Begin if EMPTYWAIT */
 
 					ch->statusflags &= ~EMPTYWAIT;
-					if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-						  tty->ldisc.write_wakeup)
-						(tty->ldisc.write_wakeup)(tty);
-
-					wake_up_interruptible(&tty->write_wait);
+					tty_wakeup(tty);
 
 				} /* End if EMPTYWAIT */
 
@@ -3255,8 +3242,8 @@
 			}
 			else 
 			{
-				if (tty->ldisc.flush_buffer)
-					tty->ldisc.flush_buffer(tty);
+				/* ldisc lock already held in ioctl */
+				tty_ldisc_flush(tty);
 			}
 
 			/* Fall Thru */
diff -urN linux-2.4.28-bk7/drivers/char/esp.c linux-2.4.29/drivers/char/esp.c
--- linux-2.4.28-bk7/drivers/char/esp.c	2002-08-02 17:39:43.000000000 -0700
+++ linux-2.4.29/drivers/char/esp.c	2005-01-19 07:08:08.761451823 -0800
@@ -786,10 +786,7 @@
 		return;
 
 	if (test_and_clear_bit(ESP_EVENT_WRITE_WAKEUP, &info->event)) {
-		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-		    tty->ldisc.write_wakeup)
-			(tty->ldisc.write_wakeup)(tty);
-		wake_up_interruptible(&tty->write_wait);
+		tty_wakeup(tty);
 	}
 }
 
@@ -1395,10 +1392,7 @@
 	cli();
 	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
 	sti();
-	wake_up_interruptible(&tty->write_wait);
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	    tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup)(tty);
+	tty_wakeup(tty);
 }
 
 /*
@@ -2115,8 +2109,7 @@
 	shutdown(info);
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
+	tty_ldisc_flush(tty);
 	tty->closing = 0;
 	info->event = 0;
 	info->tty = 0;
diff -urN linux-2.4.28-bk7/drivers/char/generic_serial.c linux-2.4.29/drivers/char/generic_serial.c
--- linux-2.4.28-bk7/drivers/char/generic_serial.c	2002-11-28 15:53:12.000000000 -0800
+++ linux-2.4.29/drivers/char/generic_serial.c	2005-01-19 07:08:08.762451867 -0800
@@ -439,10 +439,7 @@
 	port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
 	restore_flags(flags);
 
-	wake_up_interruptible(&tty->write_wait);
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	    tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup)(tty);
+	tty_wakeup(tty);
 	func_exit ();
 }
 
@@ -582,10 +579,7 @@
 	if (!tty) return;
 
 	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) {
-		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-		    tty->ldisc.write_wakeup)
-			(tty->ldisc.write_wakeup)(tty);
-		wake_up_interruptible(&tty->write_wait);
+		tty_wakeup(tty);
 	}
 	func_exit ();
 }
@@ -729,8 +723,8 @@
 {
 	unsigned long flags;
 	struct gs_port *port;
-
-	func_enter ();
+	
+	func_enter();
 
 	if (!tty) return;
 
@@ -803,8 +797,7 @@
 
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
+	tty_ldisc_flush(tty);
 	tty->closing = 0;
 
 	port->event = 0;
diff -urN linux-2.4.28-bk7/drivers/char/hvc_console.c linux-2.4.29/drivers/char/hvc_console.c
--- linux-2.4.28-bk7/drivers/char/hvc_console.c	2004-02-18 05:36:31.000000000 -0800
+++ linux-2.4.29/drivers/char/hvc_console.c	2005-01-19 07:08:08.763451910 -0800
@@ -217,10 +217,7 @@
 
 		if (hp->do_wakeup) {
 			hp->do_wakeup = 0;
-			if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP))
-			    && tty->ldisc.write_wakeup)
-				(tty->ldisc.write_wakeup)(tty);
-			wake_up_interruptible(&tty->write_wait);
+			tty_wakeup(tty);
 		}
 	}
 
diff -urN linux-2.4.28-bk7/drivers/char/ip2/i2ellis.c linux-2.4.29/drivers/char/ip2/i2ellis.c
--- linux-2.4.28-bk7/drivers/char/ip2/i2ellis.c	2001-10-24 12:05:18.000000000 -0700
+++ linux-2.4.29/drivers/char/ip2/i2ellis.c	2005-01-19 07:08:08.764451953 -0800
@@ -605,7 +605,7 @@
 
 	set_current_state( TASK_INTERRUPTIBLE );
 
-	pDelayTimer->expires  = jiffies + ( mseconds + 9 ) / 10;
+	pDelayTimer->expires  = jiffies + ((HZ * mseconds + 999) / 1000);
 	pDelayTimer->function = ii2DelayWakeup;
 	pDelayTimer->data     = 0;
 
diff -urN linux-2.4.28-bk7/drivers/char/ip2/i2ellis.h linux-2.4.29/drivers/char/ip2/i2ellis.h
--- linux-2.4.28-bk7/drivers/char/ip2/i2ellis.h	2001-10-24 12:05:18.000000000 -0700
+++ linux-2.4.29/drivers/char/ip2/i2ellis.h	2005-01-19 07:08:08.764451953 -0800
@@ -403,7 +403,6 @@
 //	For queuing interupt bottom half handlers.	/\/\|=mhw=|\/\/
 	struct tq_struct	tqueue_interrupt;
 
-	struct timer_list  SendPendingTimer;   // Used by iiSendPending
 	unsigned int	SendPendingRetry;
 
 #ifdef	CONFIG_DEVFS_FS
diff -urN linux-2.4.28-bk7/drivers/char/ip2/i2lib.c linux-2.4.29/drivers/char/ip2/i2lib.c
--- linux-2.4.28-bk7/drivers/char/ip2/i2lib.c	2002-08-02 17:39:43.000000000 -0700
+++ linux-2.4.29/drivers/char/ip2/i2lib.c	2005-01-19 07:08:08.766452040 -0800
@@ -174,8 +174,12 @@
 			pB->i2eWaitingForEmptyFifo |=
 				(pB->i2eOutMailWaiting & MB_OUT_STUFFED);
 			pB->i2eOutMailWaiting = 0;
+			if( pB->SendPendingRetry ) {
+				printk( KERN_DEBUG "IP2: iiSendPendingMail: busy board pickup on %d\n", pB->SendPendingRetry );
+			}
 			pB->SendPendingRetry = 0;
 		} else {
+#ifdef	IP2_USE_TIMER_WAIT
 /*		The only time we hit this area is when "iiTrySendMail" has
 		failed.  That only occurs when the outbound mailbox is
 		still busy with the last message.  We take a short breather
@@ -193,6 +197,11 @@
 			} else {
 				printk( KERN_ERR "IP2: iiSendPendingMail unable to queue outbound mail\n" );
 			}
+#endif
+			pB->SendPendingRetry++;
+			if( 0 == ( pB->SendPendingRetry % 8 ) ) {
+				printk( KERN_ERR "IP2: iiSendPendingMail: board busy, retry %d\n", pB->SendPendingRetry );
+			}
 		}
 	}
 }
@@ -1329,8 +1338,9 @@
 	remove_wait_queue(&(pCh->pBookmarkWait), &wait);
 
 	// if expires == 0 then timer poped, then do not need to del_timer
+	// jiffy wrap per Tim Schmielau (tim@physik3.uni-rostock.de)
 	if ((timeout > 0) && pCh->BookmarkTimer.expires && 
-	                     time_before(jiffies, pCh->BookmarkTimer.expires)) {
+			time_before(jiffies, pCh->BookmarkTimer.expires)) {
 		del_timer( &(pCh->BookmarkTimer) );
 		pCh->BookmarkTimer.expires = 0;
 
@@ -1385,15 +1395,9 @@
 	ip2trace (CHANN, ITRC_SICMD, 10, 2, tp->flags,
 			(1 << TTY_DO_WRITE_WAKEUP) );
 
-	wake_up_interruptible ( &tp->write_wait );
-	if ( ( tp->flags & (1 << TTY_DO_WRITE_WAKEUP) ) 
-	  && tp->ldisc.write_wakeup )
-	{
-		(tp->ldisc.write_wakeup) ( tp );
-
-		ip2trace (CHANN, ITRC_SICMD, 11, 0 );
+	tty_wakeup(tp);
+	ip2trace (CHANN, ITRC_SICMD, 11, 0 );
 
-	}
 }
 
 static inline void
diff -urN linux-2.4.28-bk7/drivers/char/ip2/ip2types.h linux-2.4.29/drivers/char/ip2/ip2types.h
--- linux-2.4.28-bk7/drivers/char/ip2/ip2types.h	1999-08-23 10:23:23.000000000 -0700
+++ linux-2.4.29/drivers/char/ip2/ip2types.h	2005-01-19 07:08:08.767452083 -0800
@@ -49,6 +49,10 @@
 	short irq[IP2_MAX_BOARDS]; 
 	unsigned short addr[IP2_MAX_BOARDS];
 	int type[IP2_MAX_BOARDS];
+#ifdef CONFIG_PCI
+	struct pci_dev *pci_dev[IP2_MAX_BOARDS];
+#endif
+
 } ip2config_t;
 
 #endif
diff -urN linux-2.4.28-bk7/drivers/char/ip2main.c linux-2.4.29/drivers/char/ip2main.c
--- linux-2.4.28-bk7/drivers/char/ip2main.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/drivers/char/ip2main.c	2005-01-19 07:08:08.770452213 -0800
@@ -19,6 +19,26 @@
 //
 // Done:
 //
+// 1.2.18	/\/\|=mhw=|\/\/
+// Fixed jiffies math in ii2DelayTimer...
+//	How long has THIS been broken?  Delay was basically a noop...
+// Dumped some groady tracing code that hasn't been used (or tested) in
+//	years and was only a source of warning messages.
+//
+// 1.2.17	/\/\|=mhw=|\/\/
+// PCI fixes submitted by Bjorn Helgaas
+//	Added calls to Add pci_enable_device()/pci_disable_device() per
+//	submitted patches.  My thanks to Bjorn Helgaas <bjorn.helgaas@hp.com>.
+//
+// 1.2.16	/\/\|=mhw=|\/\/
+// Yet another shot at the busy board timing window (use the poll timer).
+// 	Because of this, the poll timer is always enabled...
+// Cleaned up some comments on immediate interrupt mode (ppp code elsewhere
+// 	has been fixed and the new busy board logic won't throw a hairball).
+//
+// 1.2.15	dmc
+// Fixed jiffy wrap, PCI card may now be set to poll.
+//
 // 1.2.14	/\/\|=mhw=|\/\/
 // Added bounds checking to ip2_ipl_ioctl to avoid potential terroristic acts.
 // Changed the definition of ip2trace to be more consistant with kernel style
@@ -227,7 +247,7 @@
 
 /* String constants to identify ourselves */
 static char *pcName    = "Computone IntelliPort Plus multiport driver";
-static char *pcVersion = "1.2.14";
+static char *pcVersion = "1.2.18";
 
 /* String constants for port names */
 static char *pcDriver_name   = "ip2";
@@ -437,7 +457,7 @@
 	}
 	return 0;
 }
-#endif
+#endif /* MODULE */
 
 static int __init
 have_requested_irq( char irq )
@@ -545,6 +565,12 @@
 	// free memory
 	for (i = 0; i < IP2_MAX_BOARDS; i++) {
 		void *pB;
+#ifdef CONFIG_PCI
+		if (ip2config.type[i] == PCI && ip2config.pci_dev[i]) {
+			pci_disable_device(ip2config.pci_dev[i]);
+			ip2config.pci_dev[i] = NULL;
+		}
+#endif
 		if ((pB = i2BoardPtrTable[i]) != 0 ) {
 			kfree ( pB );
 			i2BoardPtrTable[i] = NULL;
@@ -604,17 +630,12 @@
 		if (iop) {
 			ip2config.addr[i] = iop[i];
 			if (irqp) {
-				if( irqp[i] >= 0 ) {
-					ip2config.irq[i] = irqp[i];
-				} else {
-					ip2config.irq[i] = 0;
-				}
+				ip2config.irq[i] = irqp[i];
 	// This is a little bit of a hack.  If poll_only=1 on command
 	// line back in ip2.c OR all IRQs on all specified boards are
 	// explicitly set to 0, then drop to poll only mode and override
 	// PCI or EISA interrupts.  This superceeds the old hack of
 	// triggering if all interrupts were zero (like da default).
-	// Still a hack but less prone to random acts of terrorism.
 	//
 	// What we really should do, now that the IRQ default is set
 	// to -1, is to use 0 as a hard coded, do not probe.
@@ -700,17 +721,12 @@
 					} else {
 						printk( KERN_ERR "IP2: PCI I/O address error\n");
 					}
-					pcibios_read_config_byte(pci_bus, pci_devfn,
+					if (ip2config.irq[i] != 0) {
+						pcibios_read_config_byte(pci_bus, pci_devfn,
 								  PCI_INTERRUPT_LINE, &pci_irq);
 
-//		If the PCI BIOS assigned it, lets try and use it.  If we
-//		can't acquire it or it screws up, deal with it then.
-
-//					if (!is_valid_irq(pci_irq)) {
-//						printk( KERN_ERR "IP2: Bad PCI BIOS IRQ(%d)\n",pci_irq);
-//						pci_irq = 0;
-//					}
-					ip2config.irq[i] = pci_irq;
+						ip2config.irq[i] = pci_irq;
+					}
 				} else {	// ann error
 					ip2config.addr[i] = 0;
 					if (status == PCIBIOS_DEVICE_NOT_FOUND) {
@@ -727,9 +743,15 @@
 							  PCI_DEVICE_ID_COMPUTONE_IP2EX, pci_dev_i);
 				if (pci_dev_i != NULL) {
 					unsigned int addr;
-					unsigned char pci_irq;
+
+					if (pci_enable_device(pci_dev_i)) {
+						printk( KERN_ERR "IP2: can't enable PCI device at %s\n",
+						pci_name(pci_dev_i));
+						break;
+					}
 
 					ip2config.type[i] = PCI;
+					ip2config.pci_dev[i] = pci_dev_i;
 					status =
 					pci_read_config_dword(pci_dev_i, PCI_BASE_ADDRESS_1, &addr);
 					if ( addr & 1 ) {
@@ -737,18 +759,8 @@
 					} else {
 						printk( KERN_ERR "IP2: PCI I/O address error\n");
 					}
-					status =
-					pci_read_config_byte(pci_dev_i, PCI_INTERRUPT_LINE, &pci_irq);
-
-//		If the PCI BIOS assigned it, lets try and use it.  If we
-//		can't acquire it or it screws up, deal with it then.
-
-//					if (!is_valid_irq(pci_irq)) {
-//						printk( KERN_ERR "IP2: Bad PCI BIOS IRQ(%d)\n",pci_irq);
-//						pci_irq = 0;
-//					}
-					ip2config.irq[i] = pci_irq;
-				} else {	// ann error
+					ip2config.irq[i] = pci_dev_i->irq;
+				} else {	// an error
 					ip2config.addr[i] = 0;
 					if (status == PCIBIOS_DEVICE_NOT_FOUND) {
 						printk( KERN_ERR "IP2: PCI board %d not found\n", i );
@@ -964,6 +976,14 @@
 				/* Initialise the interrupt handler bottom half (aka slih). */
 			}
 		}
+
+		if (!TimerOn) {
+//			Kick the timer on for stuck board safeties...
+			PollTimer.expires = POLL_TIMEOUT;
+			add_timer ( &PollTimer );
+			TimerOn = 1;
+		}
+
 		for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
 			if ( i2BoardPtrTable[i] ) {
 				set_irq( i, ip2config.irq[i] ); /* set and enable board interrupt */
@@ -1375,8 +1395,10 @@
 
 //		Only process those boards which match our IRQ.
 //			IRQ = 0 for polled boards, we won't poll "IRQ" boards
+//		Add an additional "check" if the irq is zero for boards
+//		which are "stuck"
 
-		if ( pB && (pB->i2eUsingIrq == irq) ) {
+		if ( pB && ( pB->i2eUsingIrq == irq || ( 0 == irq && 0 != pB->SendPendingRetry ) ) ) {
 #ifdef USE_IQI
 
 		    if (NO_MAIL_HERE != ( pB->i2eStartMail = iiGetMail(pB))) {
@@ -1391,9 +1413,8 @@
 			mark_bh(IMMEDIATE_BH);
 		    }
 #else
-//		We are using immediate servicing here.  This sucks and can
-//		cause all sorts of havoc with ppp and others.  The failsafe
-//		check on iiSendPendingMail could also throw a hairball.
+//		We are using immediate servicing here.  Suboptimal
+//			to say the least...
 			i2ServiceBoard( pB );
 #endif /* USE_IQI */
 		}
@@ -1417,6 +1438,9 @@
 static void
 ip2_poll(unsigned long arg)
 {
+	int i;
+	i2eBordStrPtr  pB;
+
 	ip2trace (ITRC_NO_PORT, ITRC_INTR, 100, 0 );
 
 	TimerOn = 0; // it's the truth but not checked in service
@@ -1424,7 +1448,15 @@
 	// Just polled boards, IRQ = 0 will hit all non-interrupt boards.
 	// It will NOT poll boards handled by hard interrupts.
 	// The issue of queued BH interrups is handled in ip2_interrupt().
-	ip2_interrupt(0, NULL, NULL);
+
+	for( i = 0; i < i2nBoards; ++i ) {
+		pB = i2BoardPtrTable[i];
+	// Service the board if the irq indicates a polled board
+	// OR if the SendPendingRetry indicates a retry state in the board
+		if ( pB && ( 0 == pB->i2eUsingIrq || 0 != pB->SendPendingRetry ) ) {
+			i2ServiceBoard( pB );
+		}
+	}
 
 	PollTimer.expires = POLL_TIMEOUT;
 	add_timer( &PollTimer );
@@ -1462,8 +1494,7 @@
 	if (tty->pgrp > 0)
 		kill_pg(tty->pgrp, sig, 1);
 	if (flush || !L_NOFLSH(tty)) {
-		if ( tty->ldisc.flush_buffer )  
-			tty->ldisc.flush_buffer(tty);
+		tty_ldisc_flush(tty);
 		i2InputFlush( tty->driver_data );
 	}
 }
@@ -1853,8 +1884,7 @@
 
 	if ( tty->driver.flush_buffer ) 
 		tty->driver.flush_buffer(tty);
-	if ( tty->ldisc.flush_buffer )  
-		tty->ldisc.flush_buffer(tty);
+	tty_ldisc_flush(tty);
 	tty->closing = 0;
 	
 	pCh->pTTY = NULL;
@@ -3198,7 +3228,16 @@
 	case 2:	    // Ping device
 		rc = -EINVAL;
 		break;
+
+#ifdef IP2_TRACE_DEVICE
 	case 3:	    // Trace device
+/*
+	This may have been useful at one time during early development
+	but has not been used for years and is just a source of excess
+	baggage and unused code and warnings.  The client programs that
+	understood this returned "blob" don't even currently compile...
+	Disabled until needed in the future.  /\/\|=mhw=|\/\/  12/22/2004
+*/
 		if ( cmd == 1 ) {
 			PUT_USER(rc, iiSendPendingMail, pIndex++ );
 			PUT_USER(rc, i2InitChannels, pIndex++ );
@@ -3259,6 +3298,7 @@
 		}
 
 		break;
+#endif
 
 	default:
 		rc = -ENODEV;
diff -urN linux-2.4.28-bk7/drivers/char/isicom.c linux-2.4.29/drivers/char/isicom.c
--- linux-2.4.28-bk7/drivers/char/isicom.c	2003-06-13 07:51:33.000000000 -0700
+++ linux-2.4.29/drivers/char/isicom.c	2005-01-19 07:08:08.771452257 -0800
@@ -502,11 +502,8 @@
 	
 	if (!tty)
 		return;
-	
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	    tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup)(tty);
-	wake_up_interruptible(&tty->write_wait);
+
+	tty_wakeup(tty);	
 } 		
  		
 /* main interrupt handler routine */ 		
@@ -1199,8 +1196,8 @@
 	isicom_shutdown_port(port);
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
+	
+	tty_ldisc_flush(tty);
 	tty->closing = 0;
 	port->tty = 0;
 	if (port->blocked_open) {
@@ -1670,10 +1667,7 @@
 	port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
 	restore_flags(flags);
 	
-	wake_up_interruptible(&tty->write_wait);
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	    tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup)(tty);
+	tty_wakeup(tty);
 }
 
 
diff -urN linux-2.4.28-bk7/drivers/char/istallion.c linux-2.4.29/drivers/char/istallion.c
--- linux-2.4.28-bk7/drivers/char/istallion.c	2005-01-19 07:07:41.911288915 -0800
+++ linux-2.4.29/drivers/char/istallion.c	2005-01-19 07:08:08.775452430 -0800
@@ -1214,8 +1214,7 @@
 	clear_bit(ST_TXBUSY, &portp->state);
 	clear_bit(ST_RXSTOP, &portp->state);
 	set_bit(TTY_IO_ERROR, &tty->flags);
-	if (tty->ldisc.flush_buffer)
-		(tty->ldisc.flush_buffer)(tty);
+	tty_ldisc_flush(tty);
 	set_bit(ST_DOFLUSHRX, &portp->state);
 	stli_flushbuffer(tty);
 
@@ -2477,10 +2476,7 @@
 	}
 	restore_flags(flags);
 
-	wake_up_interruptible(&tty->write_wait);
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	    tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup)(tty);
+	tty_wakeup(tty);
 }
 
 /*****************************************************************************/
@@ -2915,6 +2911,7 @@
 	asynotify_t		nt;
 	unsigned long		oldsigs;
 	int			rc, donerx;
+	struct tty_ldisc	*ld;
 
 #if DEBUG
 	printk(KERN_DEBUG "stli_hostcmd(brdp=%x,channr=%d)\n",
@@ -3014,10 +3011,15 @@
 			clear_bit(ST_TXBUSY, &portp->state);
 		if (nt.data & (DT_TXEMPTY | DT_TXLOW)) {
 			if (tty != (struct tty_struct *) NULL) {
-				if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-				    tty->ldisc.write_wakeup) {
-					(tty->ldisc.write_wakeup)(tty);
-					EBRDENABLE(brdp);
+				if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP))) {
+					ld = tty_ldisc_ref(tty);
+					if(ld) {
+						if(ld->write_wakeup) {
+							ld->write_wakeup(tty);
+							EBRDENABLE(brdp);
+						}
+						tty_ldisc_deref(ld);
+					}
 				}
 				wake_up_interruptible(&tty->write_wait);
 			}
diff -urN linux-2.4.28-bk7/drivers/char/lp.c linux-2.4.29/drivers/char/lp.c
--- linux-2.4.28-bk7/drivers/char/lp.c	2002-08-02 17:39:43.000000000 -0700
+++ linux-2.4.29/drivers/char/lp.c	2005-01-19 07:08:08.777452516 -0800
@@ -12,7 +12,7 @@
  * "lp=" command line parameters added by Grant Guenther, grant@torque.net
  * lp_read (Status readback) support added by Carsten Gross,
  *                                             carsten@sol.wohnheim.uni-ulm.de
- * Support for parport by Philip Blundell <Philip.Blundell@pobox.com>
+ * Support for parport by Philip Blundell <philb@gnu.org>
  * Parport sharing hacking by Andrea Arcangeli
  * Fixed kernel_(to/from)_user memory copy to check for errors
  * 				by Riccardo Facchetti <fizban@tin.it>
diff -urN linux-2.4.28-bk7/drivers/char/moxa.c linux-2.4.29/drivers/char/moxa.c
--- linux-2.4.28-bk7/drivers/char/moxa.c	2001-10-25 13:53:47.000000000 -0700
+++ linux-2.4.29/drivers/char/moxa.c	2005-01-19 07:08:08.779452603 -0800
@@ -677,8 +677,8 @@
 
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
+	tty_ldisc_flush(tty);
+
 	tty->closing = 0;
 	ch->event = 0;
 	ch->tty = 0;
@@ -754,10 +754,7 @@
 	if (ch == NULL)
 		return;
 	MoxaPortFlushData(ch->port, 1);
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	    tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup) (tty);
-	wake_up_interruptible(&tty->write_wait);
+	tty_wakeup(tty);
 }
 
 static int moxa_chars_in_buffer(struct tty_struct *tty)
@@ -908,6 +905,8 @@
 	case TIOCSSERIAL:
 		return (moxa_set_serial_info(ch, (struct serial_struct *) arg));
 	default:
+		if(!capable(CAP_SYS_RAWIO))
+			return -EPERM;
 		retval = MoxaDriverIoctl(cmd, arg, port);
 	}
 	return (retval);
@@ -1011,10 +1010,7 @@
 				if (MoxaPortTxQueue(ch->port) <= WAKEUP_CHARS) {
 					if (!tp->stopped) {
 						ch->statusflags &= ~LOWWAIT;
-						if ((tp->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-						  tp->ldisc.write_wakeup)
-							(tp->ldisc.write_wakeup) (tp);
-						wake_up_interruptible(&tp->write_wait);
+						tty_wakeup(tp);
 					}
 				}
 			}
@@ -1203,10 +1199,7 @@
 	if (ch->tty && (ch->statusflags & EMPTYWAIT)) {
 		if (MoxaPortTxQueue(ch->port) == 0) {
 			ch->statusflags &= ~EMPTYWAIT;
-			if ((ch->tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-			    ch->tty->ldisc.write_wakeup)
-				(ch->tty->ldisc.write_wakeup) (ch->tty);
-			wake_up_interruptible(&ch->tty->write_wait);
+			tty_wakeup(ch->tty);
 			return;
 		}
 		moxaEmptyTimer[ch->port].expires = jiffies + HZ;
diff -urN linux-2.4.28-bk7/drivers/char/mux.c linux-2.4.29/drivers/char/mux.c
--- linux-2.4.28-bk7/drivers/char/mux.c	2003-06-13 07:51:33.000000000 -0700
+++ linux-2.4.29/drivers/char/mux.c	2005-01-19 07:08:08.780452646 -0800
@@ -429,8 +429,7 @@
 
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
+	tty_ldisc_flush(tty);
 	tty->closing = 0;
 	info->event = 0;
 	info->tty = 0;
diff -urN linux-2.4.28-bk7/drivers/char/mxser.c linux-2.4.29/drivers/char/mxser.c
--- linux-2.4.28-bk7/drivers/char/mxser.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/drivers/char/mxser.c	2005-01-19 07:08:08.782452733 -0800
@@ -725,10 +725,7 @@
 	tty = info->tty;
 	if (tty) {
 		if (test_and_clear_bit(MXSER_EVENT_TXLOW, &info->event)) {
-			if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-			    tty->ldisc.write_wakeup)
-				(tty->ldisc.write_wakeup) (tty);
-			wake_up_interruptible(&tty->write_wait);
+			tty_wakeup(tty);
 		}
 		if (test_and_clear_bit(MXSER_EVENT_HANGUP, &info->event)) {
 			tty_hangup(tty);	/* FIXME: module removal race here - AKPM */
@@ -890,8 +887,8 @@
 	mxser_shutdown(info);
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
+	tty_ldisc_flush(tty);
+
 	tty->closing = 0;
 	info->event = 0;
 	info->tty = 0;
@@ -1050,10 +1047,7 @@
 	cli();
 	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
 	restore_flags(flags);
-	wake_up_interruptible(&tty->write_wait);
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	    tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup) (tty);
+	tty_wakeup(tty);
 }
 
 static int mxser_ioctl(struct tty_struct *tty, struct file *file,
diff -urN linux-2.4.28-bk7/drivers/char/n_hdlc.c linux-2.4.29/drivers/char/n_hdlc.c
--- linux-2.4.28-bk7/drivers/char/n_hdlc.c	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.29/drivers/char/n_hdlc.c	2005-01-19 07:08:08.783452776 -0800
@@ -351,9 +351,8 @@
 #endif
 	
 	/* Flush any pending characters in the driver and discipline. */
-	
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer (tty);
+
+	tty_ldisc_flush(tty);	
 
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer (tty);
diff -urN linux-2.4.28-bk7/drivers/char/n_r3964.c linux-2.4.29/drivers/char/n_r3964.c
--- linux-2.4.28-bk7/drivers/char/n_r3964.c	2003-06-13 07:51:33.000000000 -0700
+++ linux-2.4.29/drivers/char/n_r3964.c	2005-01-19 07:08:08.784452820 -0800
@@ -158,7 +158,8 @@
         r3964_write,           /* write */
         r3964_ioctl,           /* ioctl */
         r3964_set_termios,     /* set_termios */
-        r3964_poll,            /* poll */            
+        r3964_poll,            /* poll */
+        NULL,                  /* hangup */
         r3964_receive_buf,     /* receive_buf */
         r3964_receive_room,    /* receive_room */
         0                      /* write_wakeup */
diff -urN linux-2.4.28-bk7/drivers/char/n_tty.c linux-2.4.29/drivers/char/n_tty.c
--- linux-2.4.28-bk7/drivers/char/n_tty.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.29/drivers/char/n_tty.c	2005-01-19 07:08:08.787452950 -0800
@@ -112,11 +112,18 @@
 	spin_unlock_irqrestore(&tty->read_lock, flags);
 }
 
-/* 
- * Check whether to call the driver.unthrottle function.
- * We test the TTY_THROTTLED bit first so that it always
- * indicates the current state.
+/**
+ *	check_unthrottle	-	allow new receive data
+ *	@tty; tty device
+ *
+ *	Check whether to call the driver.unthrottle function.
+ *	We test the TTY_THROTTLED bit first so that it always
+ *	indicates the current state. The decision about whether
+ *	it is worth allowing more input has been taken by the caller.
+ *	Can sleep, may be called under the atomic_read semaphore but
+ *	this is not guaranteed.
  */
+ 
 static void check_unthrottle(struct tty_struct * tty)
 {
 	if (tty->count &&
@@ -125,10 +132,13 @@
 		tty->driver.unthrottle(tty);
 }
 
-/*
- * Reset the read buffer counters, clear the flags, 
- * and make sure the driver is unthrottled. Called
- * from n_tty_open() and n_tty_flush_buffer().
+/**
+ *	reset_buffer_flags	-	reset buffer state
+ *	@tty: terminal to reset
+ *
+ *	Reset the read buffer counters, clear the flags, 
+ *	and make sure the driver is unthrottled. Called
+ *	from n_tty_open() and n_tty_flush_buffer().
  */
 static void reset_buffer_flags(struct tty_struct *tty)
 {
@@ -142,9 +152,19 @@
 	check_unthrottle(tty);
 }
 
-/*
- * Flush the input buffer
+/**
+ *	n_tty_flush_buffer	-	clean input queue
+ *	@tty:	terminal device
+ *
+ *	Flush the input buffer. Called when the line discipline is
+ *	being closed, when the tty layer wants the buffer flushed (eg
+ *	at hangup) or when the N_TTY line discipline internally has to
+ *	clean the pending queue (for example some signals).
+ *
+ *	FIXME: tty->ctrl_status is not spinlocked and relies on
+ *	lock_kernel() still.
  */
+ 
 void n_tty_flush_buffer(struct tty_struct * tty)
 {
 	/* clear everything and unthrottle the driver */
@@ -159,9 +179,14 @@
 	}
 }
 
-/*
- * Return number of characters buffered to be delivered to user
+/**
+ *	n_tty_chars_in_buffer	-	report available bytes
+ *	@tty: tty device
+ *
+ *	Report the number of characters buffered to be delivered to user
+ *	at this instant in time. 
  */
+ 
 ssize_t n_tty_chars_in_buffer(struct tty_struct *tty)
 {
 	unsigned long flags;
@@ -242,10 +267,20 @@
 	return 0;
 }
 
-/*
- * opost_block --- to speed up block console writes, among other
- * things.
+/**
+ *	opost_block		-	block postprocess
+ *	@tty: terminal device
+ *	@inbuf: user buffer
+ *	@nr: number of bytes
+ *
+ *	This path is used to speed up block console writes, among other
+ *	things when processing blocks of output data. It handles only
+ *	the simple cases normally found and helps to generate blocks of
+ *	symbols for the console driver and thus improve performance.
+ *
+ *	Called from write_chan under the tty layer write lock.
  */
+ 
 static ssize_t opost_block(struct tty_struct * tty,
 		       const unsigned char * inbuf, unsigned int nr)
 {
@@ -334,6 +369,16 @@
 	}
 }
 
+/**
+ *	eraser		-	handle erase function
+ *	@c: character input
+ *	@tty: terminal device
+ *
+ *	Perform erase and neccessary output when an erase character is
+ *	present in the stream from the driver layer. Handles the complexities
+ *	of UTF-8 multibyte symbols.
+ */
+ 
 static void eraser(unsigned char c, struct tty_struct *tty)
 {
 	enum { ERASE, WERASE, KILL } kill_type;
@@ -450,6 +495,18 @@
 		finish_erasing(tty);
 }
 
+/**
+ *	isig		-	handle the ISIG optio
+ *	@sig: signal
+ *	@tty: terminal
+ *	@flush: force flush
+ *
+ *	Called when a signal is being sent due to terminal input. This
+ *	may caus terminal flushing to take place according to the termios
+ *	settings and character used. Called from the driver receive_buf
+ *	path so serialized.
+ */
+ 
 static inline void isig(int sig, struct tty_struct *tty, int flush)
 {
 	if (tty->pgrp > 0)
@@ -461,6 +518,16 @@
 	}
 }
 
+/**
+ *	n_tty_receive_break	-	handle break
+ *	@tty: terminal
+ *
+ *	An RS232 break event has been hit in the incoming bitstream. This
+ *	can cause a variety of events depending upon the termios settings.
+ *
+ *	Called from the receive_buf path so single threaded.
+ */
+ 
 static inline void n_tty_receive_break(struct tty_struct *tty)
 {
 	if (I_IGNBRK(tty))
@@ -477,19 +544,40 @@
 	wake_up_interruptible(&tty->read_wait);
 }
 
+/**
+ *	n_tty_receive_overrun	-	handle overrun reporting
+ *	@tty: terminal
+ *
+ *	Data arrived faster than we could process it. While the tty
+ *	driver has flagged this the bits that were missed are gone
+ *	forever.
+ *
+ *	Called from the receive_buf path so single threaded. Does not
+ *	need locking as num_overrun and overrun_time are function
+ *	private.
+ */
+ 
 static inline void n_tty_receive_overrun(struct tty_struct *tty)
 {
 	char buf[64];
 
 	tty->num_overrun++;
 	if (time_before(tty->overrun_time, jiffies - HZ)) {
-		printk("%s: %d input overrun(s)\n", tty_name(tty, buf),
+		printk(KERN_WARNING "%s: %d input overrun(s)\n", tty_name(tty, buf),
 		       tty->num_overrun);
 		tty->overrun_time = jiffies;
 		tty->num_overrun = 0;
 	}
 }
 
+/**
+ *	n_tty_receive_parity_error	-	error notifier
+ *	@tty: terminal device
+ *	@c: character
+ *
+ *	Process a parity error and queue the right data to indicate
+ *	the error case if neccessary. Locking as per n_tty_receive_buf.
+ */
 static inline void n_tty_receive_parity_error(struct tty_struct *tty,
 					      unsigned char c)
 {
@@ -507,6 +595,16 @@
 	wake_up_interruptible(&tty->read_wait);
 }
 
+/**
+ *	n_tty_receive_char	-	perform processing
+ *	@tty: terminal device
+ *	@c: character
+ *
+ *	Process an individual character of input received from the driver.
+ *	This is serialized with respect to itself by the rules for the 
+ *	driver above.
+ */
+
 static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
 {
 	unsigned long flags;
@@ -698,6 +796,16 @@
 	put_tty_queue(c, tty);
 }	
 
+/**
+ *	n_tty_receive_room	-	receive space
+ *	@tty: terminal
+ *
+ *	Called by the driver to find out how much data it is
+ *	permitted to feed to the line discipline without any being lost
+ *	and thus to manage flow control. Not serialized. Answers for the
+ *	"instant".
+ */
+ 
 static int n_tty_receive_room(struct tty_struct *tty)
 {
 	int	left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
@@ -716,10 +824,13 @@
 	return 0;
 }
 
-/*
- * Required for the ptys, serial driver etc. since processes
- * that attach themselves to the master and rely on ASYNC
- * IO must be woken up
+/**
+ *	n_tty_write_wakeup	-	asynchronous I/O notifier
+ *	@tty: tty device
+ *
+ *	Required for the ptys, serial driver etc. since processes
+ *	that attach themselves to the master and rely on ASYNC
+ *	IO must be woken up
  */
 
 static void n_tty_write_wakeup(struct tty_struct *tty)
@@ -732,6 +843,19 @@
 	return;
 }
 
+/**
+ *	n_tty_receive_buf	-	data receive
+ *	@tty: terminal device
+ *	@cp: buffer
+ *	@fp: flag buffer
+ *	@count: characters
+ *
+ *	Called by the terminal driver when a block of characters has
+ *	been received. This function must be called from soft contexts
+ *	not from interrupt context. The driver is responsible for making
+ *	calls one at a time and in order (or using queue_ldisc)
+ */
+ 
 static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
 			      char *fp, int count)
 {
@@ -813,6 +937,18 @@
 	        current->sig->action[sig-1].sa.sa_handler == SIG_IGN);
 }
 
+/**
+ *	n_tty_set_termios	-	termios data changed
+ *	@tty: terminal
+ *	@old: previous data
+ *
+ *	Called by the tty layer when the user changes termios flags so
+ *	that the line discipline can plan ahead. This function cannot sleep
+ *	and is protected from re-entry by the tty layer. The user is 
+ *	guaranteed that this function will not be re-entered or in progress
+ *	when the ldisc is closed.
+ */
+ 
 static void n_tty_set_termios(struct tty_struct *tty, struct termios * old)
 {
 	if (!tty)
@@ -828,7 +964,6 @@
 	    I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) ||
 	    I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) ||
 	    I_PARMRK(tty)) {
-		cli();
 		memset(tty->process_char_map, 0, 256/8);
 
 		if (I_IGNCR(tty) || I_ICRNL(tty))
@@ -864,7 +999,6 @@
 			set_bit(SUSP_CHAR(tty), &tty->process_char_map);
 		}
 		clear_bit(__DISABLED_CHAR, &tty->process_char_map);
-		sti();
 		tty->raw = 0;
 		tty->real_raw = 0;
 	} else {
@@ -878,6 +1012,16 @@
 	}
 }
 
+/**
+ *	n_tty_close		-	close the ldisc for this tty
+ *	@tty: device
+ *
+ *	Called from the terminal layer when this line discipline is 
+ *	being shut down, either because of a close or becsuse of a 
+ *	discipline change. The function will not be called while other
+ *	ldisc methods are in progress.
+ */
+ 
 static void n_tty_close(struct tty_struct *tty)
 {
 	n_tty_flush_buffer(tty);
@@ -887,11 +1031,22 @@
 	}
 }
 
+/**
+ *	n_tty_open		-	open an ldisc
+ *	@tty: terminal to open
+ *
+ *	Called when this line discipline is being attached to the 
+ *	terminal device. Can sleep. Called serialized so that no
+ *	other events will occur in parallel. No further open will occur
+ *	until a close.
+ */
+
 static int n_tty_open(struct tty_struct *tty)
 {
 	if (!tty)
 		return -EINVAL;
 
+	/* This one is ugly. Currently a malloc failure here can panic */
 	if (!tty->read_buf) {
 		tty->read_buf = alloc_buf();
 		if (!tty->read_buf)
@@ -917,14 +1072,23 @@
 	return 0;
 }
 
-/*
- * Helper function to speed up read_chan.  It is only called when
- * ICANON is off; it copies characters straight from the tty queue to
- * user space directly.  It can be profitably called twice; once to
- * drain the space from the tail pointer to the (physical) end of the
- * buffer, and once to drain the space from the (physical) beginning of
- * the buffer to head pointer.
+/**
+ * 	copy_from_read_buf	-	copy read data directly
+ *	@tty: terminal device
+ *	@b: user data
+ *	@nr: size of data
+ *
+ *	Helper function to speed up read_chan.  It is only called when
+ *	ICANON is off; it copies characters straight from the tty queue to
+ *	user space directly.  It can be profitably called twice; once to
+ *	drain the space from the tail pointer to the (physical) end of the
+ *	buffer, and once to drain the space from the (physical) beginning of
+ *	the buffer to head pointer.
+ *
+ *	Called under the tty->atomic_read sem and with TTY_DONT_FLIP set
+ *
  */
+ 
 static inline int copy_from_read_buf(struct tty_struct *tty,
 				      unsigned char **b,
 				      size_t *nr)
@@ -952,25 +1116,18 @@
 	return retval;
 }
 
-static ssize_t read_chan(struct tty_struct *tty, struct file *file,
-			 unsigned char *buf, size_t nr)
-{
-	unsigned char *b = buf;
-	DECLARE_WAITQUEUE(wait, current);
-	int c;
-	int minimum, time;
-	ssize_t retval = 0;
-	ssize_t size;
-	long timeout;
-	unsigned long flags;
-
-do_it_again:
-
-	if (!tty->read_buf) {
-		printk("n_tty_read_chan: called with read_buf == NULL?!?\n");
-		return -EIO;
-	}
+/**
+ *     job_control             -       check job control
+ *     @tty: tty
+ *     @file: file handle
+ *
+ *     Perform job control management checks on this file/tty descriptor
+ *     and if appropriate send any needed signals and return a negative
+ *     error code if action should be taken.
+ */
 
+static int job_control(struct tty_struct *tty, struct file *file)
+{
 	/* Job control check -- must be done at start and after
 	   every sleep (POSIX.1 7.1.1.4). */
 	/* NOTE: not yet done after every sleep pending a thorough
@@ -989,7 +1146,48 @@
 			return -ERESTARTSYS;
 		}
 	}
+	return 0;
+}
+ 
 
+/**
+ *	read_chan		-	read function for tty
+ *	@tty: tty device
+ *	@file: file object
+ *	@buf: userspace buffer pointer
+ *	@nr: size of I/O
+ *
+ *	Perform reads for the line discipline. We are guaranteed that the
+ *	line discipline will not be closed under us but we may get multiple
+ *	parallel readers and must handle this ourselves. We may also get
+ *	a hangup. Always called in user context, may sleep.
+ *
+ *	This code must be sure never to sleep through a hangup.
+ */
+ 
+static ssize_t read_chan(struct tty_struct *tty, struct file *file,
+			 unsigned char __user *buf, size_t nr)
+{
+	unsigned char __user *b = buf;
+	DECLARE_WAITQUEUE(wait, current);
+	int c;
+	int minimum, time;
+	ssize_t retval = 0;
+	ssize_t size;
+	long timeout;
+	unsigned long flags;
+
+do_it_again:
+
+	if (!tty->read_buf) {
+		printk("n_tty_read_chan: called with read_buf == NULL?!?\n");
+		return -EIO;
+	}
+
+	c = job_control(tty, file);
+	if(c < 0)
+		return c;
+	
 	minimum = time = 0;
 	timeout = MAX_SCHEDULE_TIMEOUT;
 	if (!tty->icanon) {
@@ -1011,6 +1209,9 @@
 		}
 	}
 
+	/*
+	 *	Internal serialization of reads.
+	 */
 	if (file->f_flags & O_NONBLOCK) {
 		if (down_trylock(&tty->atomic_read))
 			return -EAGAIN;
@@ -1146,6 +1347,21 @@
 	return retval;
 }
 
+/**
+ *	write_chan		-	write function for tty
+ *	@tty: tty device
+ *	@file: file object
+ *	@buf: userspace buffer pointer
+ *	@nr: size of I/O
+ *
+ *	Write function of the terminal device. This is serialized with
+ *	respect to other write callers but not to termios changes, reads
+ *	and other such events. We must be careful with N_TTY as the receive
+ *	code will echo characters, thus calling driver write methods.
+ *
+ *	This code must be sure never to sleep through a hangup.
+ */
+ 
 static ssize_t write_chan(struct tty_struct * tty, struct file * file,
 			  const unsigned char * buf, size_t nr)
 {
@@ -1217,7 +1433,25 @@
 	return (b - buf) ? b - buf : retval;
 }
 
-/* Called without the kernel lock held - fine */
+/**
+ *	normal_poll		-	poll method for N_TTY
+ *	@tty: terminal device
+ *	@file: file accessing it
+ *	@wait: poll table
+ *
+ *	Called when the line discipline is asked to poll() for data or
+ *	for special events. This code is not serialized with respect to
+ *	other events save open/close.
+ *
+ *	This code must be sure never to sleep through a hangup.
+ *	Called without the kernel lock held - fine
+ *
+ *	FIXME: if someone changes the VMIN or discipline settings for the
+ *	terminal while another process is in poll() the poll does not
+ *	recompute the new limits. Possibly set_termios should issue
+ *	a read wakeup to fix this bug.
+ */
+ 
 static unsigned int normal_poll(struct tty_struct * tty, struct file * file, poll_table *wait)
 {
 	unsigned int mask = 0;
@@ -1258,6 +1492,7 @@
 	n_tty_ioctl,		/* ioctl */
 	n_tty_set_termios,	/* set_termios */
 	normal_poll,		/* poll */
+	NULL,			/* hangup */
 	n_tty_receive_buf,	/* receive_buf */
 	n_tty_receive_room,	/* receive_room */
 	n_tty_write_wakeup	/* write_wakeup */
diff -urN linux-2.4.28-bk7/drivers/char/pcmcia/synclink_cs.c linux-2.4.29/drivers/char/pcmcia/synclink_cs.c
--- linux-2.4.28-bk7/drivers/char/pcmcia/synclink_cs.c	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.29/drivers/char/pcmcia/synclink_cs.c	2005-01-19 07:08:08.815454162 -0800
@@ -553,6 +553,29 @@
 static void* mgslpc_get_text_ptr(void);
 static void* mgslpc_get_text_ptr() {return mgslpc_get_text_ptr;}
 
+/**
+ * line discipline callback wrappers
+ *
+ * The wrappers maintain line discipline references
+ * while calling into the line discipline.
+ *
+ * ldisc_receive_buf  - pass receive data to line discipline
+ */
+
+static void ldisc_receive_buf(struct tty_struct *tty,
+			      const __u8 *data, char *flags, int count)
+{
+	struct tty_ldisc *ld;
+	if (!tty)
+		return;
+	ld = tty_ldisc_ref(tty);
+	if (ld) {
+		if (ld->receive_buf)
+			ld->receive_buf(tty, data, flags, count);
+		tty_ldisc_deref(ld);
+	}
+}
+
 static dev_link_t *mgslpc_attach(void)
 {
     MGSLPC_INFO *info;
@@ -1027,13 +1050,7 @@
 		printk("bh_transmit() entry on %s\n", info->device_name);
 
 	if (tty) {
-		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-		    tty->ldisc.write_wakeup) {
-			if ( debug_level >= DEBUG_LEVEL_BH )
-				printk( "%s(%d):calling ldisc.write_wakeup on %s\n",
-					__FILE__,__LINE__,info->device_name);
-			(tty->ldisc.write_wakeup)(tty);
-		}
+		tty_wakeup(tty);
 		wake_up_interruptible(&tty->write_wait);
 	}
 }
@@ -1917,11 +1934,9 @@
 	info->tx_count = info->tx_put = info->tx_get = 0;
 	del_timer(&info->tx_timer);	
 	spin_unlock_irqrestore(&info->lock,flags);
-	
+
 	wake_up_interruptible(&tty->write_wait);
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	    tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup)(tty);
+	tty_wakeup(tty);
 }
 
 /* Send a high-priority XON/XOFF character
@@ -2685,9 +2700,8 @@
 
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
-		
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
+	
+	tty_ldisc_flush(tty);
 		
 	shutdown(info);
 	
@@ -4199,11 +4213,7 @@
 			} 
 			else
 #endif
-			{
-				/* Call the line discipline receive callback directly. */
-				if (tty && tty->ldisc.receive_buf)
-					tty->ldisc.receive_buf(tty, buf->data, info->flag_buf, framesize);
-			}
+				ldisc_receive_buf(tty, buf->data, info->flag_buf, framesize);
 		}
 	}
 
diff -urN linux-2.4.28-bk7/drivers/char/pcxx.c linux-2.4.29/drivers/char/pcxx.c
--- linux-2.4.28-bk7/drivers/char/pcxx.c	2002-11-28 15:53:12.000000000 -0800
+++ linux-2.4.29/drivers/char/pcxx.c	2005-01-19 07:08:08.816454206 -0800
@@ -619,28 +619,11 @@
 	
 		if(tty->driver.flush_buffer)
 			tty->driver.flush_buffer(tty);
-		if(tty->ldisc.flush_buffer)
-			tty->ldisc.flush_buffer(tty);
+		tty_ldisc_flush(tty);
 		shutdown(info);
 		tty->closing = 0;
 		info->event = 0;
 		info->tty = NULL;
-#ifndef MODULE
-/* ldiscs[] is not available in a MODULE
-** worth noting that while I'm not sure what this hunk of code is supposed
-** to do, it is not present in the serial.c driver.  Hmmm.  If you know,
-** please send me a note.  brian@ilinx.com
-** Don't know either what this is supposed to do christoph@lameter.com.
-*/
-		if(tty->ldisc.num != ldiscs[N_TTY].num) {
-			if(tty->ldisc.close)
-				(tty->ldisc.close)(tty);
-			tty->ldisc = ldiscs[N_TTY];
-			tty->termios->c_line = N_TTY;
-			if(tty->ldisc.open)
-				(tty->ldisc.open)(tty);
-		}
-#endif
 		if(info->blocked_open) {
 			if(info->close_delay) {
 				current->state = TASK_INTERRUPTIBLE;
@@ -883,9 +866,7 @@
 	memoff(ch);
 	restore_flags(flags);
 
-	wake_up_interruptible(&tty->write_wait);
-	if((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup)(tty);
+	tty_wakeup(tty);
 }
 
 static void pcxe_flush_chars(struct tty_struct *tty)
@@ -1793,10 +1774,7 @@
 			if (event & LOWTX_IND) {
 				if (ch->statusflags & LOWWAIT) {
 					ch->statusflags &= ~LOWWAIT;
-					if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-						tty->ldisc.write_wakeup)
-						(tty->ldisc.write_wakeup)(tty);
-					wake_up_interruptible(&tty->write_wait);
+					tty_wakeup(tty);
 				}
 			}
 
@@ -1804,10 +1782,7 @@
 				ch->statusflags &= ~TXBUSY;
 				if (ch->statusflags & EMPTYWAIT) {
 					ch->statusflags &= ~EMPTYWAIT;
-					if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-						tty->ldisc.write_wakeup)
-						(tty->ldisc.write_wakeup)(tty);
-					wake_up_interruptible(&tty->write_wait);
+					tty_wakeup(tty);
 				}
 			}
 		}
@@ -2254,8 +2229,7 @@
 				tty_wait_until_sent(tty, 0);
 			}
 			else {
-				if(tty->ldisc.flush_buffer)
-					tty->ldisc.flush_buffer(tty);
+				tty_ldisc_flush(tty);
 			}
 
 			/* Fall Thru */
diff -urN linux-2.4.28-bk7/drivers/char/pdc_console.c linux-2.4.29/drivers/char/pdc_console.c
--- linux-2.4.28-bk7/drivers/char/pdc_console.c	2003-06-13 07:51:33.000000000 -0700
+++ linux-2.4.29/drivers/char/pdc_console.c	2005-01-19 07:08:08.817454249 -0800
@@ -463,8 +463,7 @@
 
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
+	tty_ldisc_flush(tty);
 	tty->closing = 0;
 	info->event = 0;
 	info->tty = 0;
diff -urN linux-2.4.28-bk7/drivers/char/pty.c linux-2.4.29/drivers/char/pty.c
--- linux-2.4.28-bk7/drivers/char/pty.c	2002-08-02 17:39:43.000000000 -0700
+++ linux-2.4.29/drivers/char/pty.c	2005-01-19 07:08:08.818454292 -0800
@@ -85,9 +85,9 @@
 	if (!tty->link)
 		return;
 	tty->link->packet = 0;
+	set_bit(TTY_OTHER_CLOSED, &tty->link->flags);
 	wake_up_interruptible(&tty->link->read_wait);
 	wake_up_interruptible(&tty->link->write_wait);
-	set_bit(TTY_OTHER_CLOSED, &tty->link->flags);
 	if (tty->driver.subtype == PTY_TYPE_MASTER) {
 		set_bit(TTY_OTHER_CLOSED, &tty->flags);
 #ifdef CONFIG_UNIX98_PTYS
@@ -121,10 +121,7 @@
 	if (!o_tty)
 		return;
 
-	if ((o_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	    o_tty->ldisc.write_wakeup)
-		(o_tty->ldisc.write_wakeup)(o_tty);
-	wake_up_interruptible(&o_tty->write_wait);
+	tty_wakeup(o_tty);
 	set_bit(TTY_THROTTLED, &tty->flags);
 }
 
@@ -137,6 +134,10 @@
  *   (2) avoid redundant copying for cases where count >> receive_room
  * N.B. Calls from user space may now return an error code instead of
  * a count.
+ *
+ * FIXME: Our pty_write method is called with our ldisc lock held but
+ * not our partners. We can't just take the other one blindly without
+ * risking deadlocks.  There is also the small matter of TTY_DONT_FLIP
  */
 static int pty_write(struct tty_struct * tty, int from_user,
 		       const unsigned char *buf, int count)
@@ -299,9 +300,8 @@
 	
 	if (!to)
 		return;
-	
-	if (to->ldisc.flush_buffer)
-		to->ldisc.flush_buffer(to);
+
+	tty_ldisc_flush(to);	
 	
 	if (to->packet) {
 		tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
diff -urN linux-2.4.28-bk7/drivers/char/random.c linux-2.4.29/drivers/char/random.c
--- linux-2.4.28-bk7/drivers/char/random.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/drivers/char/random.c	2005-01-19 07:08:08.820454379 -0800
@@ -1771,7 +1771,7 @@
 static int proc_do_poolsize(ctl_table *table, int write, struct file *filp,
 			    void *buffer, size_t *lenp)
 {
-	int	ret;
+	unsigned int	ret;
 
 	sysctl_poolsize = random_state->poolinfo.POOLBYTES;
 
diff -urN linux-2.4.28-bk7/drivers/char/rio/riointr.c linux-2.4.29/drivers/char/rio/riointr.c
--- linux-2.4.28-bk7/drivers/char/rio/riointr.c	2001-09-10 09:04:53.000000000 -0700
+++ linux-2.4.29/drivers/char/rio/riointr.c	2005-01-19 07:08:08.821454422 -0800
@@ -248,12 +248,9 @@
     rio_dprintk (RIO_DEBUG_INTR, "Waking up.... ldisc:%d (%d/%d)....",
 		 (int)(PortP->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)),
 		 PortP->gs.wakeup_chars, PortP->gs.xmit_cnt); 
-    if ((PortP->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	PortP->gs.tty->ldisc.write_wakeup)
-      (PortP->gs.tty->ldisc.write_wakeup)(PortP->gs.tty);
+    tty_wakeup(PortP->gs.tty);
     rio_dprintk (RIO_DEBUG_INTR, "(%d/%d)\n",
 		PortP->gs.wakeup_chars, PortP->gs.xmit_cnt); 
-    wake_up_interruptible(&PortP->gs.tty->write_wait);
   }
 
 }
diff -urN linux-2.4.28-bk7/drivers/char/riscom8.c linux-2.4.29/drivers/char/riscom8.c
--- linux-2.4.28-bk7/drivers/char/riscom8.c	2001-09-13 15:21:32.000000000 -0700
+++ linux-2.4.29/drivers/char/riscom8.c	2005-01-19 07:08:08.822454465 -0800
@@ -1200,8 +1200,7 @@
 	rc_shutdown_port(bp, port);
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
+	tty_ldisc_flush(tty);
 	tty->closing = 0;
 	port->event = 0;
 	port->tty = 0;
@@ -1375,9 +1374,7 @@
 	restore_flags(flags);
 	
 	wake_up_interruptible(&tty->write_wait);
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	    tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup)(tty);
+	tty_wakeup(tty);
 }
 
 static int rc_get_modem_info(struct riscom_port * port, unsigned int *value)
@@ -1734,10 +1731,7 @@
 		return;
 
 	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) {
-		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-		    tty->ldisc.write_wakeup)
-			(tty->ldisc.write_wakeup)(tty);
-		wake_up_interruptible(&tty->write_wait);
+		tty_wakeup(tty);
 	}
 }
 
diff -urN linux-2.4.28-bk7/drivers/char/rocket.c linux-2.4.29/drivers/char/rocket.c
--- linux-2.4.28-bk7/drivers/char/rocket.c	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.29/drivers/char/rocket.c	2005-01-19 07:08:08.824454552 -0800
@@ -241,9 +241,12 @@
 				   CHANNEL_t *cp, unsigned int ChanStatus)
 {
 	unsigned int CharNStat;
-	int ToRecv, wRecv, space, count;
+	int ToRecv, wRecv, space = 0, count;
 	unsigned char	*cbuf;
 	char		*fbuf;
+	struct tty_ldisc *ld;
+
+	ld = tty_ldisc_ref(tty);
 	
 	ToRecv= sGetRxCnt(cp);
 	space = 2*TTY_FLIPBUF_SIZE;
@@ -348,8 +351,8 @@
 		fbuf += ToRecv;
 		count += ToRecv;
 	}
-	tty->ldisc.receive_buf(tty, tty->flip.char_buf,
-			       tty->flip.flag_buf, count);
+	ld->receive_buf(tty, tty->flip.char_buf, tty->flip.flag_buf, count);
+	tty_ldisc_deref(ld);
 }
 
 /*
@@ -400,10 +403,7 @@
 	if (info->xmit_cnt == 0)
 		xmit_flags[info->line >> 5] &= ~(1 << (info->line & 0x1f));
 	if (info->xmit_cnt < WAKEUP_CHARS) {
-		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-		    tty->ldisc.write_wakeup)
-			(tty->ldisc.write_wakeup)(tty);
-		wake_up_interruptible(&tty->write_wait);
+		tty_wakeup(tty);
 	}
 #ifdef ROCKET_DEBUG_INTR
 	printk("(%d,%d,%d,%d)...", info->xmit_cnt, info->xmit_head,
@@ -1128,8 +1128,7 @@
 	}
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
+	tty_ldisc_flush(tty);
 
 	xmit_flags[info->line >> 5] &= ~(1 << (info->line & 0x1f));
 	if (info->blocked_open) {
@@ -1806,10 +1805,7 @@
 	restore_flags(flags);
 end:
 	if (info->xmit_cnt < WAKEUP_CHARS) {
-		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-		    tty->ldisc.write_wakeup)
-			(tty->ldisc.write_wakeup)(tty);
-		wake_up_interruptible(&tty->write_wait);
+		tty_wakeup(tty);
 	}
 	return retval;
 }
@@ -1868,9 +1864,7 @@
 	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
 	sti();
 	wake_up_interruptible(&tty->write_wait);
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	    tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup)(tty);
+	tty_wakeup(tty);
 	
 	cp = &info->channel;
 	
diff -urN linux-2.4.28-bk7/drivers/char/selection.c linux-2.4.29/drivers/char/selection.c
--- linux-2.4.28-bk7/drivers/char/selection.c	2001-09-07 09:28:38.000000000 -0700
+++ linux-2.4.29/drivers/char/selection.c	2005-01-19 07:08:08.825454595 -0800
@@ -290,9 +290,11 @@
 {
 	struct vt_struct *vt = (struct vt_struct *) tty->driver_data;
 	int	pasted = 0, count;
+	struct  tty_ldisc *ld;
 	DECLARE_WAITQUEUE(wait, current);
 
 	poke_blanked_console();
+	ld = tty_ldisc_ref_wait(tty);
 	add_wait_queue(&vt->paste_wait, &wait);
 	while (sel_buffer && sel_buffer_lth > pasted) {
 		set_current_state(TASK_INTERRUPTIBLE);
@@ -301,12 +303,14 @@
 			continue;
 		}
 		count = sel_buffer_lth - pasted;
-		count = MIN(count, tty->ldisc.receive_room(tty));
-		tty->ldisc.receive_buf(tty, sel_buffer + pasted, 0, count);
+		count = MIN(count, ld->receive_room(tty));
+		ld->receive_buf(tty, sel_buffer + pasted, 0, count);
 		pasted += count;
 	}
 	remove_wait_queue(&vt->paste_wait, &wait);
 	current->state = TASK_RUNNING;
+
+	tty_ldisc_deref(ld);
 	return 0;
 }
 
diff -urN linux-2.4.28-bk7/drivers/char/ser_a2232.c linux-2.4.29/drivers/char/ser_a2232.c
--- linux-2.4.28-bk7/drivers/char/ser_a2232.c	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.29/drivers/char/ser_a2232.c	2005-01-19 07:08:08.826454639 -0800
@@ -633,10 +633,7 @@
 					
 				/* WakeUp if output buffer runs low */
 				if ((port->gs.xmit_cnt <= port->gs.wakeup_chars) && port->gs.tty) {
-					if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && port->gs.tty->ldisc.write_wakeup){
-						(port->gs.tty->ldisc.write_wakeup)(port->gs.tty);
-					}
-					wake_up_interruptible(&port->gs.tty->write_wait);
+					tty_wakeup(port->gs.tty);
 				}
 			} // if the port is used
 		} // for every port on the board
diff -urN linux-2.4.28-bk7/drivers/char/serial.c linux-2.4.29/drivers/char/serial.c
--- linux-2.4.28-bk7/drivers/char/serial.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/drivers/char/serial.c	2005-01-19 07:08:08.830454812 -0800
@@ -1068,17 +1068,15 @@
 static void do_softint(void *private_)
 {
 	struct async_struct	*info = (struct async_struct *) private_;
-	struct tty_struct	*tty;
-	
+	struct tty_struct       *tty;
+
 	tty = info->tty;
 	if (!tty)
 		return;
 
 	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
-		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-		    tty->ldisc.write_wakeup)
-			(tty->ldisc.write_wakeup)(tty);
-		wake_up_interruptible(&tty->write_wait);
+		tty_wakeup(tty);
+		
 #ifdef SERIAL_HAVE_POLL_WAIT
 		wake_up_interruptible(&tty->poll_wait);
 #endif
@@ -1976,13 +1974,10 @@
 	save_flags(flags); cli();
 	info->xmit.head = info->xmit.tail = 0;
 	restore_flags(flags);
-	wake_up_interruptible(&tty->write_wait);
 #ifdef SERIAL_HAVE_POLL_WAIT
 	wake_up_interruptible(&tty->poll_wait);
 #endif
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	    tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup)(tty);
+	tty_wakeup(tty);
 }
 
 /*
@@ -2845,8 +2840,8 @@
 	 * the line discipline to only process XON/XOFF characters.
 	 */
 	tty->closing = 1;
-	if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-		tty_wait_until_sent(tty, info->closing_wait);
+	if (state->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+		tty_wait_until_sent(tty, state->closing_wait);
 	/*
 	 * At this point we stop accepting input.  To do this, we
 	 * disable the receive line status interrupts, and tell the
@@ -2867,15 +2862,14 @@
 	shutdown(info);
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
+	tty_ldisc_flush(tty);
 	tty->closing = 0;
 	info->event = 0;
 	info->tty = 0;
 	if (info->blocked_open) {
-		if (info->close_delay) {
+		if (state->close_delay) {
 			set_current_state(TASK_INTERRUPTIBLE);
-			schedule_timeout(info->close_delay);
+			schedule_timeout(state->close_delay);
 		}
 		wake_up_interruptible(&info->open_wait);
 	}
diff -urN linux-2.4.28-bk7/drivers/char/serial167.c linux-2.4.29/drivers/char/serial167.c
--- linux-2.4.28-bk7/drivers/char/serial167.c	2002-11-28 15:53:12.000000000 -0800
+++ linux-2.4.29/drivers/char/serial167.c	2005-01-19 07:08:08.832454899 -0800
@@ -773,11 +773,7 @@
 	wake_up_interruptible(&info->open_wait);
     }
     if (test_and_clear_bit(Cy_EVENT_WRITE_WAKEUP, &info->event)) {
-	if((tty->flags & (1<< TTY_DO_WRITE_WAKEUP))
-	&& tty->ldisc.write_wakeup){
-	    (tty->ldisc.write_wakeup)(tty);
-	}
-	wake_up_interruptible(&tty->write_wait);
+	tty_wakeup(tty);
     }
 } /* do_softint */
 
@@ -1357,9 +1353,7 @@
 	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
     restore_flags(flags);
     wake_up_interruptible(&tty->write_wait);
-    if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP))
-    && tty->ldisc.write_wakeup)
-	(tty->ldisc.write_wakeup)(tty);
+    tty_wakeup(tty);
 } /* cy_flush_buffer */
 
 
@@ -1916,18 +1910,9 @@
     shutdown(info);
     if (tty->driver.flush_buffer)
 	tty->driver.flush_buffer(tty);
-    if (tty->ldisc.flush_buffer)
-	tty->ldisc.flush_buffer(tty);
+    tty_ldisc_flush(tty);
     info->event = 0;
     info->tty = 0;
-    if (tty->ldisc.num != ldiscs[N_TTY].num) {
-	if (tty->ldisc.close)
-	    (tty->ldisc.close)(tty);
-	tty->ldisc = ldiscs[N_TTY];
-	tty->termios->c_line = N_TTY;
-	if (tty->ldisc.open)
-	    (tty->ldisc.open)(tty);
-    }
     if (info->blocked_open) {
 	if (info->close_delay) {
 	    current->state = TASK_INTERRUPTIBLE;
diff -urN linux-2.4.28-bk7/drivers/char/serial_amba.c linux-2.4.29/drivers/char/serial_amba.c
--- linux-2.4.28-bk7/drivers/char/serial_amba.c	2002-08-02 17:39:43.000000000 -0700
+++ linux-2.4.29/drivers/char/serial_amba.c	2005-01-19 07:08:08.833454942 -0800
@@ -569,10 +569,7 @@
 	if (!tty || !test_and_clear_bit(EVT_WRITE_WAKEUP, &info->event))
 		return;
 
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	    tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup)(tty);
-	wake_up_interruptible(&tty->write_wait);
+	tty_wakeup(tty);
 }
 
 static int ambauart_startup(struct amba_info *info)
@@ -958,10 +955,7 @@
 	save_flags(flags); cli();
 	info->xmit.head = info->xmit.tail = 0;
 	restore_flags(flags);
-	wake_up_interruptible(&tty->write_wait);
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	    tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup)(tty);
+	tty_wakeup(tty);
 }
 
 /*
@@ -1459,8 +1453,7 @@
 	ambauart_shutdown(info);
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
+	tty_ldisc_flush(tty);
 	tty->closing = 0;
 	info->event = 0;
 	info->tty = NULL;
diff -urN linux-2.4.28-bk7/drivers/char/serial_tx3912.c linux-2.4.29/drivers/char/serial_tx3912.c
--- linux-2.4.28-bk7/drivers/char/serial_tx3912.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.29/drivers/char/serial_tx3912.c	2005-01-19 07:08:08.834454985 -0800
@@ -127,12 +127,9 @@
 	}
 	
         if (port->gs.xmit_cnt <= port->gs.wakeup_chars) {
-                if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-                    port->gs.tty->ldisc.write_wakeup)
-                        (port->gs.tty->ldisc.write_wakeup)(port->gs.tty);
+		tty_wakeup(port->gs.tty);
                 rs_dprintk(TX3912_UART_DEBUG_TRANSMIT, "Waking up.... ldisc (%d)....\n",
                             port->gs.wakeup_chars); 
-                wake_up_interruptible(&port->gs.tty->write_wait);
        	}	
 }
 
diff -urN linux-2.4.28-bk7/drivers/char/serial_txx927.c linux-2.4.29/drivers/char/serial_txx927.c
--- linux-2.4.28-bk7/drivers/char/serial_txx927.c	2002-08-02 17:39:43.000000000 -0700
+++ linux-2.4.29/drivers/char/serial_txx927.c	2005-01-19 07:08:08.836455072 -0800
@@ -535,10 +535,7 @@
 		return;
 
 	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
-		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-		    tty->ldisc.write_wakeup)
-			(tty->ldisc.write_wakeup)(tty);
-		wake_up_interruptible(&tty->write_wait);
+		tty_wakeup(tty);
 #ifdef SERIAL_HAVE_POLL_WAIT
 		wake_up_interruptible(&tty->poll_wait);
 #endif                                                    
@@ -1104,13 +1101,10 @@
 	save_flags(flags); cli();
 	info->xmit.head = info->xmit.tail = 0;
 	restore_flags(flags);
-	wake_up_interruptible(&tty->write_wait);
 #ifdef SERIAL_HAVE_POLL_WAIT
 	wake_up_interruptible(&tty->poll_wait);
 #endif
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	    tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup)(tty);
+	tty_wakeup(tty);
 }
 
 /*
@@ -1442,8 +1436,8 @@
 	 * the line discipline to only process XON/XOFF characters.
 	 */
 	tty->closing = 1;
-	if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-		tty_wait_until_sent(tty, info->closing_wait);
+	if (state->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+		tty_wait_until_sent(tty, state->closing_wait);
 	/*
 	 * At this point we stop accepting input.  To do this, we
 	 * disable the receive line status interrupts, and tell the
@@ -1465,15 +1459,14 @@
 	shutdown(info);
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
+	tty_ldisc_flush(tty);
 	tty->closing = 0;
 	info->event = 0;
 	info->tty = 0;
 	if (info->blocked_open) {
-		if (info->close_delay) {
+		if (state->close_delay) {
 			current->state = TASK_INTERRUPTIBLE;
-			schedule_timeout(info->close_delay);
+			schedule_timeout(state->close_delay);
 		}
 		wake_up_interruptible(&info->open_wait);
 	}
diff -urN linux-2.4.28-bk7/drivers/char/sgiserial.c linux-2.4.29/drivers/char/sgiserial.c
--- linux-2.4.28-bk7/drivers/char/sgiserial.c	2004-02-18 05:36:31.000000000 -0800
+++ linux-2.4.29/drivers/char/sgiserial.c	2005-01-19 07:08:08.837455115 -0800
@@ -1498,10 +1498,10 @@
 	tty->closing = 0;
 	info->event = 0;
 	info->tty = 0;
-	if (tty->ldisc.num != ldiscs[N_TTY].num) {
+	if (tty->ldisc.num != N_TTY) {
 		if (tty->ldisc.close)
 			(tty->ldisc.close)(tty);
-		tty->ldisc = ldiscs[N_TTY];
+		tty->ldisc = *(tty_ldisc_get(N_TTY));
 		tty->termios->c_line = N_TTY;
 		if (tty->ldisc.open)
 			(tty->ldisc.open)(tty);
diff -urN linux-2.4.28-bk7/drivers/char/sh-sci.c linux-2.4.29/drivers/char/sh-sci.c
--- linux-2.4.28-bk7/drivers/char/sh-sci.c	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.29/drivers/char/sh-sci.c	2005-01-19 07:08:08.842455332 -0800
@@ -1021,10 +1021,7 @@
 		return;
 
 	if (test_and_clear_bit(SCI_EVENT_WRITE_WAKEUP, &port->event)) {
-		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-		    tty->ldisc.write_wakeup)
-			(tty->ldisc.write_wakeup)(tty);
-		wake_up_interruptible(&tty->write_wait);
+		tty_wakeup(tty);
 	}
 }
 
diff -urN linux-2.4.28-bk7/drivers/char/specialix.c linux-2.4.29/drivers/char/specialix.c
--- linux-2.4.28-bk7/drivers/char/specialix.c	2002-08-02 17:39:43.000000000 -0700
+++ linux-2.4.29/drivers/char/specialix.c	2005-01-19 07:08:08.844455418 -0800
@@ -1579,8 +1579,7 @@
 	sx_shutdown_port(bp, port);
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
+	tty_ldisc_flush(tty);
 	tty->closing = 0;
 	port->event = 0;
 	port->tty = 0;
@@ -1758,10 +1757,7 @@
 	port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
 	restore_flags(flags);
 	
-	wake_up_interruptible(&tty->write_wait);
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	    tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup)(tty);
+	tty_wakeup(tty);
 }
 
 
@@ -2211,12 +2207,8 @@
 	if(!(tty = port->tty)) 
 		return;
 
-	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) {
-		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-		    tty->ldisc.write_wakeup)
-			(tty->ldisc.write_wakeup)(tty);
-		wake_up_interruptible(&tty->write_wait);
-	}
+	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) 
+		tty_wakeup(tty);
 }
 
 
diff -urN linux-2.4.28-bk7/drivers/char/stallion.c linux-2.4.29/drivers/char/stallion.c
--- linux-2.4.28-bk7/drivers/char/stallion.c	2005-01-19 07:07:41.924289478 -0800
+++ linux-2.4.29/drivers/char/stallion.c	2005-01-19 07:08:08.847455548 -0800
@@ -1238,8 +1238,7 @@
 		portp->tx.tail = (char *) NULL;
 	}
 	set_bit(TTY_IO_ERROR, &tty->flags);
-	if (tty->ldisc.flush_buffer)
-		(tty->ldisc.flush_buffer)(tty);
+	tty_ldisc_flush(tty);
 
 	tty->closing = 0;
 	portp->tty = (struct tty_struct *) NULL;
@@ -1850,10 +1849,7 @@
 		return;
 
 	stl_flush(portp);
-	wake_up_interruptible(&tty->write_wait);
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	    tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup)(tty);
+	tty_wakeup(tty);
 }
 
 /*****************************************************************************/
@@ -2224,10 +2220,7 @@
 
 	lock_kernel();
 	if (test_bit(ASYI_TXLOW, &portp->istate)) {
-		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-		    tty->ldisc.write_wakeup)
-			(tty->ldisc.write_wakeup)(tty);
-		wake_up_interruptible(&tty->write_wait);
+		tty_wakeup(tty);
 	}
 	if (test_bit(ASYI_DCDCHANGE, &portp->istate)) {
 		clear_bit(ASYI_DCDCHANGE, &portp->istate);
diff -urN linux-2.4.28-bk7/drivers/char/sx.c linux-2.4.29/drivers/char/sx.c
--- linux-2.4.28-bk7/drivers/char/sx.c	2003-06-13 07:51:33.000000000 -0700
+++ linux-2.4.29/drivers/char/sx.c	2005-01-19 07:08:08.849455635 -0800
@@ -1057,9 +1057,7 @@
 	}
 
 	if ((port->gs.xmit_cnt <= port->gs.wakeup_chars) && port->gs.tty) {
-		if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-		    port->gs.tty->ldisc.write_wakeup)
-			(port->gs.tty->ldisc.write_wakeup)(port->gs.tty);
+		tty_wakeup(port->gs.tty);
 		sx_dprintk (SX_DEBUG_TRANSMIT, "Waking up.... ldisc (%d)....\n",
 		            port->gs.wakeup_chars); 
 		wake_up_interruptible(&port->gs.tty->write_wait);
diff -urN linux-2.4.28-bk7/drivers/char/synclink.c linux-2.4.29/drivers/char/synclink.c
--- linux-2.4.28-bk7/drivers/char/synclink.c	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.29/drivers/char/synclink.c	2005-01-19 07:08:08.855455895 -0800
@@ -1011,6 +1011,29 @@
 	return 0;
 }
 
+/**
+ * line discipline callback wrappers
+ *
+ * The wrappers maintain line discipline references
+ * while calling into the line discipline.
+ *
+ * ldisc_receive_buf  - pass receive data to line discipline
+ */
+
+static void ldisc_receive_buf(struct tty_struct *tty,
+			      const __u8 *data, char *flags, int count)
+{
+	struct tty_ldisc *ld;
+	if (!tty)
+		return;
+	ld = tty_ldisc_ref(tty);
+	if (ld) {
+		if (ld->receive_buf)
+			ld->receive_buf(tty, data, flags, count);
+		tty_ldisc_deref(ld);
+	}
+}
+
 /* mgsl_stop()		throttle (stop) transmitter
  * 	
  * Arguments:		tty	pointer to tty info structure
@@ -1170,14 +1193,7 @@
 			__FILE__,__LINE__,info->device_name);
 
 	if (tty) {
-		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-		    tty->ldisc.write_wakeup) {
-			if ( debug_level >= DEBUG_LEVEL_BH )
-				printk( "%s(%d):calling ldisc.write_wakeup on %s\n",
-					__FILE__,__LINE__,info->device_name);
-			(tty->ldisc.write_wakeup)(tty);
-		}
-		wake_up_interruptible(&tty->write_wait);
+		tty_wakeup(tty);
 	}
 
 	/* if transmitter idle and loopmode_send_done_requested
@@ -2433,12 +2449,8 @@
 	del_timer(&info->tx_timer);	
 	spin_unlock_irqrestore(&info->irq_spinlock,flags);
 	
-	wake_up_interruptible(&tty->write_wait);
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	    tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup)(tty);
-		
-}	/* end of mgsl_flush_buffer() */
+	tty_wakeup(tty);
+}
 
 /* mgsl_send_xchar()
  *
@@ -3342,9 +3354,8 @@
 
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
-		
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
+	
+	tty_ldisc_flush(tty);
 		
 	shutdown(info);
 	
@@ -7007,11 +7018,7 @@
 			} 
 			else
 #endif
-			{
-				/* Call the line discipline receive callback directly. */
-				if ( tty && tty->ldisc.receive_buf )
-				tty->ldisc.receive_buf(tty, info->intermediate_rxbuffer, info->flag_buf, framesize);
-			}
+				ldisc_receive_buf(tty, info->intermediate_rxbuffer, info->flag_buf, framesize);
 		}
 	}
 	/* Free the buffers used by this frame. */
@@ -7183,9 +7190,7 @@
 			memcpy( info->intermediate_rxbuffer, pBufEntry->virt_addr, framesize);
 			info->icount.rxok++;
 
-			/* Call the line discipline receive callback directly. */
-			if ( tty && tty->ldisc.receive_buf )
-				tty->ldisc.receive_buf(tty, info->intermediate_rxbuffer, info->flag_buf, framesize);
+			ldisc_receive_buf(tty, info->intermediate_rxbuffer, info->flag_buf, framesize);
 		}
 
 		/* Free the buffers used by this frame. */
diff -urN linux-2.4.28-bk7/drivers/char/synclinkmp.c linux-2.4.29/drivers/char/synclinkmp.c
--- linux-2.4.28-bk7/drivers/char/synclinkmp.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/drivers/char/synclinkmp.c	2005-01-19 07:08:08.858456025 -0800
@@ -735,6 +735,29 @@
 	return 0;
 }
 
+/**
+ * line discipline callback wrappers
+ *
+ * The wrappers maintain line discipline references
+ * while calling into the line discipline.
+ *
+ * ldisc_receive_buf  - pass receive data to line discipline
+ */
+
+static void ldisc_receive_buf(struct tty_struct *tty,
+			      const __u8 *data, char *flags, int count)
+{
+	struct tty_ldisc *ld;
+	if (!tty)
+		return;
+	ld = tty_ldisc_ref(tty);
+	if (ld) {
+		if (ld->receive_buf)
+			ld->receive_buf(tty, data, flags, count);
+		tty_ldisc_deref(ld);
+	}
+}
+
 /* tty callbacks */
 
 /* Called when a port is opened.  Init and enable port.
@@ -906,8 +929,7 @@
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
 
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
+	tty_ldisc_flush(tty);
 
 	shutdown(info);
 
@@ -1315,9 +1337,7 @@
 	spin_unlock_irqrestore(&info->lock,flags);
 
 	wake_up_interruptible(&tty->write_wait);
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	    tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup)(tty);
+	tty_wakeup(tty);
 }
 
 /* throttle (stop) transmitter
@@ -1983,13 +2003,7 @@
 			__FILE__,__LINE__,info->device_name);
 
 	if (tty) {
-		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-		    tty->ldisc.write_wakeup) {
-			if ( debug_level >= DEBUG_LEVEL_BH )
-				printk( "%s(%d):%s calling ldisc.write_wakeup\n",
-					__FILE__,__LINE__,info->device_name);
-			(tty->ldisc.write_wakeup)(tty);
-		}
+		tty_wakeup(tty);
 		wake_up_interruptible(&tty->write_wait);
 	}
 }
@@ -4989,15 +5003,8 @@
 			}
 			else
 #endif
-			{
-				if ( tty && tty->ldisc.receive_buf ) {
-					/* Call the line discipline receive callback directly. */
-					tty->ldisc.receive_buf(tty,
-						info->tmp_rx_buf,
-						info->flag_buf,
-						framesize);
-				}
-			}
+				ldisc_receive_buf(tty,info->tmp_rx_buf,
+						  info->flag_buf, framesize);
 		}
 	}
 	/* Free the buffers used by this frame. */
diff -urN linux-2.4.28-bk7/drivers/char/tty_io.c linux-2.4.29/drivers/char/tty_io.c
--- linux-2.4.28-bk7/drivers/char/tty_io.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/drivers/char/tty_io.c	2005-01-19 07:08:08.864456285 -0800
@@ -120,7 +120,6 @@
 
 struct termios tty_std_termios;		/* for the benefit of tty drivers  */
 struct tty_driver *tty_drivers;		/* linked list of tty drivers */
-struct tty_ldisc ldiscs[NR_LDISCS];	/* line disc dispatch table	*/
 
 #ifdef CONFIG_UNIX98_PTYS
 extern struct tty_driver ptm_driver[];	/* Unix98 pty masters; for /dev/ptmx */
@@ -260,63 +259,314 @@
 	return 0;
 }
 
+/*
+ *     This is probably overkill for real world processors but
+ *     they are not on hot paths so a little discipline won't do
+ *     any harm.
+ */    
+
+static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
+{
+	down(&tty->termios_sem);
+	tty->termios->c_line = num;
+	up(&tty->termios_sem);
+}
+
+/*
+ *     This guards the refcounted line discipline lists. The lock
+ *     must be taken with irqs off because there are hangup path
+ *     callers who will do ldisc lookups and cannot sleep.
+ */
+
+spinlock_t tty_ldisc_lock = SPIN_LOCK_UNLOCKED;
+DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait);
+struct tty_ldisc tty_ldiscs[NR_LDISCS]; /* line disc dispatch table     */
+
 int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc)
 {
+
+	unsigned long flags;
+	int ret = 0;
+
 	if (disc < N_TTY || disc >= NR_LDISCS)
 		return -EINVAL;
-	
+
+	spin_lock_irqsave(&tty_ldisc_lock, flags);
 	if (new_ldisc) {
-		ldiscs[disc] = *new_ldisc;
-		ldiscs[disc].flags |= LDISC_FLAG_DEFINED;
-		ldiscs[disc].num = disc;
-	} else
-		memset(&ldiscs[disc], 0, sizeof(struct tty_ldisc));
+		tty_ldiscs[disc] = *new_ldisc;
+		tty_ldiscs[disc].num = disc;
+		tty_ldiscs[disc].flags |= LDISC_FLAG_DEFINED;
+		tty_ldiscs[disc].refcount = 0;
+	} else {
+		if(tty_ldiscs[disc].refcount)
+			ret = -EBUSY;
+		else
+			tty_ldiscs[disc].flags &= ~LDISC_FLAG_DEFINED;
+        }
+	spin_unlock_irqrestore(&tty_ldisc_lock, flags);
 	
-	return 0;
+	return ret;
+
 }
 
+
 EXPORT_SYMBOL(tty_register_ldisc);
 
-/* Set the discipline of a tty line. */
+struct tty_ldisc *tty_ldisc_get(int disc)
+{
+	unsigned long flags;
+	struct tty_ldisc *ld;
+
+	if (disc < N_TTY || disc >= NR_LDISCS)
+		return NULL;
+
+	spin_lock_irqsave(&tty_ldisc_lock, flags);
+
+	ld = &tty_ldiscs[disc];
+	/* Check the entry is defined */
+	if(ld->flags & LDISC_FLAG_DEFINED)
+		ld->refcount++;
+	else
+		ld = NULL;
+	spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+	return ld;
+}
+
+EXPORT_SYMBOL_GPL(tty_ldisc_get);
+
+void tty_ldisc_put(int disc)
+{
+	struct tty_ldisc *ld;
+	unsigned long flags;
+
+	if (disc < N_TTY || disc >= NR_LDISCS)
+		BUG();
+
+	spin_lock_irqsave(&tty_ldisc_lock, flags);
+	ld = &tty_ldiscs[disc];
+	if(ld->refcount <= 0)
+		BUG();
+	ld->refcount--;
+	spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+}
+      
+EXPORT_SYMBOL_GPL(tty_ldisc_put);
+
+void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld)
+{
+	tty->ldisc = *ld;
+	tty->ldisc.refcount = 0;
+}
+
+/**
+ *     tty_ldisc_try           -       internal helper
+ *     @tty: the tty
+ *
+ *     Make a single attempt to grab and bump the refcount on
+ *     the tty ldisc. Return 0 on failure or 1 on success. This is
+ *     used to implement both the waiting and non waiting versions
+ *     of tty_ldisc_ref
+ */
+
+static int tty_ldisc_try(struct tty_struct *tty)
+{
+	unsigned long flags;
+	struct tty_ldisc *ld;
+	int ret = 0;
+
+	spin_lock_irqsave(&tty_ldisc_lock, flags);
+	ld = &tty->ldisc;
+	if(test_bit(TTY_LDISC, &tty->flags))
+	{
+		ld->refcount++;
+		ret = 1;
+	}
+	spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+	return ret;
+}
+
+/**
+ *     tty_ldisc_ref_wait      -       wait for the tty ldisc
+ *     @tty: tty device
+ *
+ *     Dereference the line discipline for the terminal and take a
+ *     reference to it. If the line discipline is in flux then
+ *     wait patiently until it changes.
+ *
+ *     Note: Must not be called from an IRQ/timer context. The caller
+ *     must also be careful not to hold other locks that will deadlock
+ *     against a discipline change, such as an existing ldisc reference
+ *     (which we check for)
+ */
+
+struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty)
+{
+	/* wait_event is a macro */
+	wait_event(tty_ldisc_wait, tty_ldisc_try(tty));
+	return &tty->ldisc;
+}
+
+EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait);
+
+/**
+ *     tty_ldisc_ref           -       get the tty ldisc
+ *     @tty: tty device
+ *
+ *     Dereference the line discipline for the terminal and take a
+ *     reference to it. If the line discipline is in flux then
+ *     return NULL. Can be called from IRQ and timer functions.
+ */
+
+struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty)
+{
+	if(tty_ldisc_try(tty))
+		return &tty->ldisc;
+	return NULL;
+}
+
+EXPORT_SYMBOL_GPL(tty_ldisc_ref);
+
+
+void tty_ldisc_deref(struct tty_ldisc *ld)
+{
+
+	unsigned long flags;
+
+	if(ld == NULL)
+		BUG();
+
+	spin_lock_irqsave(&tty_ldisc_lock, flags);
+	if(ld->refcount == 0)
+		printk(KERN_EMERG "tty_ldisc_deref: no references.\n");
+	else
+		ld->refcount--;
+	if(ld->refcount == 0)
+		wake_up(&tty_ldisc_wait);
+	spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+}
+
+EXPORT_SYMBOL_GPL(tty_ldisc_deref);
+
+/**
+  *     tty_ldisc_enable        -       allow ldisc use
+  *     @tty: terminal to activate ldisc on
+  *
+  *     Set the TTY_LDISC flag when the line discipline can be called
+  *     again. Do neccessary wakeups for existing sleepers.
+  *
+  *     Note: nobody should set this bit except via this function. Clearing
+  *     directly is allowed.
+  */
+
+static void tty_ldisc_enable(struct tty_struct *tty)
+{
+	set_bit(TTY_LDISC, &tty->flags);
+	wake_up(&tty_ldisc_wait);
+}
+
+/**
+ *     tty_set_ldisc           -       set line discipline
+ *     @tty: the terminal to set
+ *     @ldisc: the line discipline
+ *
+ *     Set the discipline of a tty line. Must be called from a process
+ *     context.
+ */
+
 static int tty_set_ldisc(struct tty_struct *tty, int ldisc)
 {
 	int	retval = 0;
 	struct	tty_ldisc o_ldisc;
 	char buf[64];
+	unsigned long flags;
+	struct tty_ldisc *ld;
 
 	if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS))
 		return -EINVAL;
+
+restart:
+
+	if (tty->ldisc.num == ldisc)
+		return 0; /* We are already in the desired discipline */
+
+	ld = tty_ldisc_get(ldisc);
 	/* Eduardo Blanco <ejbs@cs.cs.com.uy> */
 	/* Cyrus Durgin <cider@speakeasy.org> */
-	if (!(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED)) {
+	if (ld == NULL)
+	{
 		char modname [20];
-		sprintf(modname, "tty-ldisc-%d", ldisc);
-		request_module (modname);
+                sprintf(modname, "tty-ldisc-%d", ldisc);
+                request_module (modname);
+		ld = tty_ldisc_get(ldisc);
 	}
-	if (!(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED))
+	
+	if (ld == NULL)
 		return -EINVAL;
 
-	if (tty->ldisc.num == ldisc)
-		return 0;	/* We are already in the desired discipline */
+	
 	o_ldisc = tty->ldisc;
-
 	tty_wait_until_sent(tty, 0);
+
+	/*
+	 *      Make sure we don't change while someone holds a
+	 *      reference to the line discipline. The TTY_LDISC bit
+	 *      prevents anyone taking a reference once it is clear.
+	 *      We need the lock to avoid racing reference takers.
+	 */
+
+	spin_lock_irqsave(&tty_ldisc_lock, flags);
+	if(tty->ldisc.refcount)
+	{
+		/* Free the new ldisc we grabbed. Must drop the lock
+		   first. */
+		spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+		tty_ldisc_put(ldisc);
+		/*
+		 * There are several reasons we may be busy, including
+		 * random momentary I/O traffic. We must therefore
+		 * retry. We could distinguish between blocking ops
+		 * and retries if we made tty_ldisc_wait() smarter. That
+		 * is up for discussion.
+		 */
+		if(wait_event_interruptible(tty_ldisc_wait, tty->ldisc.refcount == 0) < 0)
+			return -ERESTARTSYS;
+		goto restart;
+	}
+	clear_bit(TTY_LDISC, &tty->flags);
+	clear_bit(TTY_DONT_FLIP, &tty->flags);
+	spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+
+	/*
+	 *      From this point on we know nobody has an ldisc
+	 *      usage reference, nor can they obtain one until
+	 *      we say so later on.
+	 */
+
+	/*
+	 * Wait for ->hangup_work and ->flip.work handlers to terminate
+	 */
+	run_task_queue(&tq_timer);
+	flush_scheduled_tasks();
 	
 	/* Shutdown the current discipline. */
 	if (tty->ldisc.close)
 		(tty->ldisc.close)(tty);
 
 	/* Now set up the new line discipline. */
-	tty->ldisc = ldiscs[ldisc];
-	tty->termios->c_line = ldisc;
+	tty_ldisc_assign(tty, ld);
+	tty_set_termios_ldisc(tty, ldisc);
 	if (tty->ldisc.open)
 		retval = (tty->ldisc.open)(tty);
 	if (retval < 0) {
-		tty->ldisc = o_ldisc;
-		tty->termios->c_line = tty->ldisc.num;
+		tty_ldisc_put(ldisc);
+		/* There is an outstanding reference here so this is safe */
+		tty_ldisc_assign(tty, tty_ldisc_get(o_ldisc.num));
+		tty_set_termios_ldisc(tty, tty->ldisc.num);
 		if (tty->ldisc.open && (tty->ldisc.open(tty) < 0)) {
-			tty->ldisc = ldiscs[N_TTY];
-			tty->termios->c_line = N_TTY;
+			tty_ldisc_put(o_ldisc.num);
+			/* This driver is always present */
+			tty_ldisc_assign(tty, tty_ldisc_get(N_TTY));
+			tty_set_termios_ldisc(tty, N_TTY);
 			if (tty->ldisc.open) {
 				int r = tty->ldisc.open(tty);
 
@@ -327,8 +577,21 @@
 			}
 		}
 	}
+	/* At this point we hold a reference to the new ldisc and a
+	    reference to the old ldisc. If we ended up flipping back
+	    to the existing ldisc we have two references to it */
+
 	if (tty->ldisc.num != o_ldisc.num && tty->driver.set_ldisc)
 		tty->driver.set_ldisc(tty);
+
+	tty_ldisc_put(o_ldisc.num);
+
+	/*
+	 *      Allow ldisc referencing to occur as soon as the driver
+	 *      ldisc callback completes.
+	 */
+	tty_ldisc_enable(tty);
+
 	return retval;
 }
 
@@ -430,11 +693,55 @@
 
 static spinlock_t redirect_lock = SPIN_LOCK_UNLOCKED;
 static struct file *redirect;
+
+/**
+  *     tty_wakeup      -       request more data
+  *     @tty: terminal
+  *
+  *     Internal and external helper for wakeups of tty. This function
+  *     informs the line discipline if present that the driver is ready\
+  *     to receive more output data.
+  */
+
+void tty_wakeup(struct tty_struct *tty)
+{
+	struct tty_ldisc *ld;
+
+	if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) {
+		ld = tty_ldisc_ref(tty);
+		if(ld) {
+			if(ld->write_wakeup)
+				ld->write_wakeup(tty);
+			tty_ldisc_deref(ld);
+		}
+	}
+	wake_up_interruptible(&tty->write_wait);
+}
+
+/*
+ * tty_wakeup/tty_ldisc_flush are actually _GPL exports but we can't do 
+ * that in 2.4 for modutils compat reasons.
+ */
+EXPORT_SYMBOL(tty_wakeup);
+
+
+void tty_ldisc_flush(struct tty_struct *tty)
+{
+	struct tty_ldisc *ld = tty_ldisc_ref(tty);
+	if(ld) {
+		if(ld->flush_buffer)
+			ld->flush_buffer(tty);
+		tty_ldisc_deref(ld);
+	}
+}
+
+
 /*
- * This can be called by the "eventd" kernel thread.  That is process synchronous,
- * but doesn't hold any locks, so we need to make sure we have the appropriate
- * locks for what we're doing..
+ * tty_wakeup/tty_ldisc_flush are actually _GPL exports but we can't do 
+ * that in 2.4 for modutils compat reasons.
  */
+EXPORT_SYMBOL(tty_ldisc_flush);
+
 void do_tty_hangup(void *data)
 {
 	struct tty_struct *tty = (struct tty_struct *) data;
@@ -442,6 +749,7 @@
 	struct file *f = NULL;
 	struct task_struct *p;
 	struct list_head *l;
+	struct tty_ldisc *ld;
 	int    closecount = 0, n;
 
 	if (!tty)
@@ -475,20 +783,22 @@
 	file_list_unlock();
 	
 	/* FIXME! What are the locking issues here? This may me overdoing things.. */
+	ld = tty_ldisc_ref(tty);
+	if(ld != NULL)	
 	{
-		unsigned long flags;
-
-		save_flags(flags); cli();
-		if (tty->ldisc.flush_buffer)
-			tty->ldisc.flush_buffer(tty);
+		if (ld->flush_buffer)
+			ld->flush_buffer(tty);
 		if (tty->driver.flush_buffer)
 			tty->driver.flush_buffer(tty);
-		if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) &&
-		    tty->ldisc.write_wakeup)
-			(tty->ldisc.write_wakeup)(tty);
-		restore_flags(flags);
+		if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) && ld->write_wakeup)
+			ld->write_wakeup(tty);
+		if (ld->hangup)
+			ld->hangup(tty);
 	}
 
+	/* FIXME: Once we trust the LDISC code better we can wait here for
+	   ldisc completion and fix the driver call race */
+
 	wake_up_interruptible(&tty->write_wait);
 	wake_up_interruptible(&tty->read_wait);
 
@@ -496,21 +806,19 @@
 	 * Shutdown the current line discipline, and reset it to
 	 * N_TTY.
 	 */
+
 	if (tty->driver.flags & TTY_DRIVER_RESET_TERMIOS)
-		*tty->termios = tty->driver.init_termios;
-	if (tty->ldisc.num != ldiscs[N_TTY].num) {
-		if (tty->ldisc.close)
-			(tty->ldisc.close)(tty);
-		tty->ldisc = ldiscs[N_TTY];
-		tty->termios->c_line = N_TTY;
-		if (tty->ldisc.open) {
-			int i = (tty->ldisc.open)(tty);
-			if (i < 0)
-				printk(KERN_ERR "do_tty_hangup: N_TTY open: "
-						"error %d\n", -i);
-		}
+	{
+		down(&tty->termios_sem);
+                *tty->termios = tty->driver.init_termios;
+		up(&tty->termios_sem);
 	}
-	
+
+	/* Defer ldisc switch */
+	/* tty_deferred_ldisc_switch(N_TTY)
+	   This should get done automatically when the port closes and
+	   tty_release is called */
+
 	read_lock(&tasklist_lock);
  	for_each_task(p) {
 		if ((tty->session > 0) && (p->session == tty->session) &&
@@ -541,6 +849,17 @@
 				tty->driver.close(tty, cons_filp);
 	} else if (tty->driver.hangup)
 		(tty->driver.hangup)(tty);
+
+	/* We don't want to have driver/ldisc interactions beyond
+	   the ones we did here. The driver layer expects no
+	   calls after ->hangup() from the ldisc side. However we
+	   can't yet guarantee all that */
+
+	set_bit(TTY_HUPPED, &tty->flags);
+	if(ld) {
+		tty_ldisc_enable(tty);
+		tty_ldisc_deref(ld);
+	}
 	unlock_kernel();
 	if (f)
 		fput(f);
@@ -644,10 +963,8 @@
 	}
 	if (tty->driver.start)
 		(tty->driver.start)(tty);
-	if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) &&
-	    tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup)(tty);
-	wake_up_interruptible(&tty->write_wait);
+	/* If we have a running line discipline it may need kicking */
+	tty_wakeup(tty);
 }
 
 static ssize_t tty_read(struct file * file, char * buf, size_t count, 
@@ -656,6 +973,7 @@
 	int i;
 	struct tty_struct * tty;
 	struct inode *inode;
+	struct tty_ldisc *ld;
 
 	/* Can't seek (pread) on ttys.  */
 	if (ppos != &file->f_pos)
@@ -684,11 +1002,15 @@
 			return -ERESTARTSYS;
 		}
 #endif
+	/* We want to wait for the line discipline to sort out in this
+	   situation */
+	ld = tty_ldisc_ref_wait(tty);
 	lock_kernel();
-	if (tty->ldisc.read)
-		i = (tty->ldisc.read)(tty,file,buf,count);
+	if (ld->read)
+		i = (ld->read)(tty,file,buf,count);
 	else
 		i = -EIO;
+	tty_ldisc_deref(ld);
 	unlock_kernel();
 	if (i > 0)
 		inode->i_atime = CURRENT_TIME;
@@ -757,6 +1079,8 @@
 	int is_console;
 	struct tty_struct * tty;
 	struct inode *inode = file->f_dentry->d_inode;
+	ssize_t ret;
+	struct tty_ldisc *ld;
 
 	/* Can't seek (pwrite) on ttys.  */
 	if (ppos != &file->f_pos)
@@ -803,13 +1127,19 @@
 		}
 	}
 #endif
-	if (!tty->ldisc.write)
-		return -EIO;
-	return do_tty_write(tty->ldisc.write, tty, file,
-			    (const unsigned char *)buf, count);
+
+	ld = tty_ldisc_ref_wait(tty);
+	if (!ld->write)
+		ret = -EIO;
+	else
+		ret = do_tty_write(ld->write, tty, file,
+				(const unsigned char __user *)buf, count);
+	tty_ldisc_deref(ld);
+	return ret;
 }
 
-/* Semaphore to protect creating and releasing a tty */
+/* Semaphore to protect creating and releasing a tty. This is shared with
+   vt.c for deeply disgusting hack reasons */
 static DECLARE_MUTEX(tty_sem);
 
 static void down_tty_sem(int index)
@@ -971,7 +1301,10 @@
 				(tty->ldisc.close)(tty);
 			goto release_mem_out;
 		}
+		set_bit(TTY_LDISC, &o_tty->flags);
+		tty_ldisc_enable(o_tty);
 	}
+	tty_ldisc_enable(tty);
 	goto success;
 
 	/*
@@ -999,7 +1332,9 @@
 	}
 	tty->count++;
 	tty->driver = *driver; /* N.B. why do this every time?? */
-
+	/* FIXME */
+	if(!test_bit(TTY_LDISC, &tty->flags))
+		printk(KERN_ERR "init_dev but no ldisc\n");
 success:
 	*ret_tty = tty;
 	
@@ -1080,6 +1415,7 @@
 	int	pty_master, tty_closing, o_tty_closing, do_sleep;
 	int	idx;
 	char	buf[64];
+	unsigned long flags;
 	
 	tty = (struct tty_struct *)filp->private_data;
 	if (tty_paranoia_check(tty, filp->f_dentry->d_inode->i_rdev, "release_dev"))
@@ -1272,24 +1608,59 @@
 #endif
 
 	/*
+	 * Prevent flush_to_ldisc() from rescheduling the work for later.  Then
+	 * kill any delayed work. As this is the final close it does not
+	 * race with the set_ldisc code path.
+	 */
+	clear_bit(TTY_LDISC, &tty->flags);
+	clear_bit(TTY_DONT_FLIP, &tty->flags);
+
+	/*
+	 * Wait for ->hangup_work and ->flip.work handlers to terminate
+	 */
+
+	run_task_queue(&tq_timer);
+	flush_scheduled_tasks();
+
+	/*
+	 * Wait for any short term users (we know they are just driver
+         * side waiters as the file is closing so user count on the file
+         * side is zero.
+	 */
+
+	spin_lock_irqsave(&tty_ldisc_lock, flags);
+	while(tty->ldisc.refcount)
+	{
+		spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+		wait_event(tty_ldisc_wait, tty->ldisc.refcount == 0);
+		spin_lock_irqsave(&tty_ldisc_lock, flags);
+	}
+	spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+
+	/*
 	 * Shutdown the current line discipline, and reset it to N_TTY.
 	 * N.B. why reset ldisc when we're releasing the memory??
+	 * FIXME: this MUST get fixed for the new reflocking
 	 */
 	if (tty->ldisc.close)
 		(tty->ldisc.close)(tty);
-	tty->ldisc = ldiscs[N_TTY];
-	tty->termios->c_line = N_TTY;
+	tty_ldisc_put(tty->ldisc.num);
+
+	/*
+	 *      Switch the line discipline back
+	 */
+	tty_ldisc_assign(tty, tty_ldisc_get(N_TTY));
+	tty_set_termios_ldisc(tty,N_TTY); 
+
 	if (o_tty) {
+		/* FIXME: could o_tty be in setldisc here ? */
+		clear_bit(TTY_LDISC, &o_tty->flags);
 		if (o_tty->ldisc.close)
 			(o_tty->ldisc.close)(o_tty);
-		o_tty->ldisc = ldiscs[N_TTY];
+		tty_ldisc_put(o_tty->ldisc.num);
+		tty_ldisc_assign(o_tty, tty_ldisc_get(N_TTY));
+		tty_set_termios_ldisc(o_tty,N_TTY);
 	}
-	
-	/*
-	 * Make sure that the tty's task queue isn't activated. 
-	 */
-	run_task_queue(&tq_timer);
-	flush_scheduled_tasks();
 
 	/* 
 	 * The release_mem function takes care of the details of clearing
@@ -1464,14 +1835,18 @@
 static unsigned int tty_poll(struct file * filp, poll_table * wait)
 {
 	struct tty_struct * tty;
+	struct tty_ldisc *ld;
+	int ret = 0;
 
 	tty = (struct tty_struct *)filp->private_data;
 	if (tty_paranoia_check(tty, filp->f_dentry->d_inode->i_rdev, "tty_poll"))
 		return 0;
 
-	if (tty->ldisc.poll)
-		return (tty->ldisc.poll)(tty, filp, wait);
-	return 0;
+	ld = tty_ldisc_ref_wait(tty);
+	if (ld->poll)
+		ret = (ld->poll)(tty, filp, wait);
+	tty_ldisc_deref(ld);
+	return ret;
 }
 
 static int tty_fasync(int fd, struct file * filp, int on)
@@ -1505,12 +1880,15 @@
 static int tiocsti(struct tty_struct *tty, char * arg)
 {
 	char ch, mbz = 0;
+	struct tty_ldisc *ld;
 
 	if ((current->tty != tty) && !suser())
 		return -EPERM;
 	if (get_user(ch, arg))
 		return -EFAULT;
-	tty->ldisc.receive_buf(tty, &ch, &mbz, 1);
+	ld = tty_ldisc_ref_wait(tty);
+	ld->receive_buf(tty, &ch, &mbz, 1);
+	tty_ldisc_deref(ld);
 	return 0;
 }
 
@@ -1718,6 +2096,7 @@
 {
 	struct tty_struct *tty, *real_tty;
 	int retval;
+	struct tty_ldisc *ld;
 	
 	tty = (struct tty_struct *)file->private_data;
 	if (tty_paranoia_check(tty, inode->i_rdev, "tty_ioctl"))
@@ -1808,6 +2187,7 @@
 		case TIOCGSID:
 			return tiocgsid(tty, real_tty, (pid_t *) arg);
 		case TIOCGETD:
+			/* FIXME: check this is ok */
 			return put_user(tty->ldisc.num, (int *) arg);
 		case TIOCSETD:
 			return tiocsetd(tty, (int *) arg);
@@ -1841,16 +2221,19 @@
 			return send_break(tty, arg ? arg*(HZ/10) : HZ/4);
 	}
 	if (tty->driver.ioctl) {
-		int retval = (tty->driver.ioctl)(tty, file, cmd, arg);
+		retval = (tty->driver.ioctl)(tty, file, cmd, arg);
 		if (retval != -ENOIOCTLCMD)
 			return retval;
 	}
-	if (tty->ldisc.ioctl) {
-		int retval = (tty->ldisc.ioctl)(tty, file, cmd, arg);
-		if (retval != -ENOIOCTLCMD)
-			return retval;
+	ld = tty_ldisc_ref_wait(tty);
+	retval = -EINVAL;
+	if (ld->ioctl) {
+		retval = ld->ioctl(tty, file, cmd, arg);
+		if (retval == -ENOIOCTLCMD)
+			retval = -EINVAL;
 	}
-	return -EINVAL;
+	tty_ldisc_deref(ld);
+	return retval;
 }
 
 
@@ -1883,14 +2266,20 @@
 	int session;
 	int		i;
 	struct file	*filp;
+	struct tty_ldisc *disc;
 	
 	if (!tty)
 		return;
 	session  = tty->session;
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
+	/* We don't want an ldisc switch during this */
+	disc = tty_ldisc_ref(tty);
+	if (disc && disc->flush_buffer)
+		disc->flush_buffer(tty);
+	tty_ldisc_deref(disc);
+
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
+
 	read_lock(&tasklist_lock);
 	for_each_task(p) {
 		if ((p->tty == tty) ||
@@ -1942,11 +2331,16 @@
 	unsigned char	*cp;
 	char		*fp;
 	int		count;
-	unsigned long flags;
+	unsigned long 	flags;
+	struct tty_ldisc *disc;
+
+	disc = tty_ldisc_ref(tty);
+	if (disc == NULL)       /*  !TTY_LDISC */
+		return;
 
 	if (test_bit(TTY_DONT_FLIP, &tty->flags)) {
 		queue_task(&tty->flip.tqueue, &tq_timer);
-		return;
+		goto out;
 	}
 	if (tty->flip.buf_num) {
 		cp = tty->flip.char_buf + TTY_FLIPBUF_SIZE;
@@ -1969,7 +2363,31 @@
 	tty->flip.count = 0;
 	restore_flags(flags);
 	
-	tty->ldisc.receive_buf(tty, cp, fp, count);
+	disc->receive_buf(tty, cp, fp, count);
+out:
+	tty_ldisc_deref(disc);
+}
+
+/*
+ *     Call the ldisc flush directly from a driver. This function may
+ *     return an error and need retrying by the user.
+ */
+
+int tty_push_data(struct tty_struct *tty, unsigned char *cp, unsigned char *fp, int count)
+{
+	int ret = 0;
+	struct tty_ldisc *disc;
+	
+	disc = tty_ldisc_ref(tty);
+	if(test_bit(TTY_DONT_FLIP, &tty->flags))
+		ret = -EAGAIN;
+	else if(disc == NULL)
+		ret = -EIO;
+	else
+		disc->receive_buf(tty, cp, fp, count);
+	tty_ldisc_deref(disc);
+	return ret;
+
 }
 
 /*
@@ -2032,13 +2450,14 @@
 {
 	memset(tty, 0, sizeof(struct tty_struct));
 	tty->magic = TTY_MAGIC;
-	tty->ldisc = ldiscs[N_TTY];
+	tty_ldisc_assign(tty, tty_ldisc_get(N_TTY));
 	tty->pgrp = -1;
 	tty->flip.char_buf_ptr = tty->flip.char_buf;
 	tty->flip.flag_buf_ptr = tty->flip.flag_buf;
 	tty->flip.tqueue.routine = flush_to_ldisc;
 	tty->flip.tqueue.data = tty;
 	init_MUTEX(&tty->flip.pty_sem);
+	init_MUTEX(&tty->termios_sem);
 	init_waitqueue_head(&tty->write_wait);
 	init_waitqueue_head(&tty->read_wait);
 	tty->tq_hangup.routine = do_tty_hangup;
@@ -2217,7 +2636,7 @@
 void __init console_init(void)
 {
 	/* Setup the default TTY line discipline. */
-	memset(ldiscs, 0, sizeof(ldiscs));
+	memset(tty_ldiscs, 0, NR_LDISCS*sizeof(struct tty_ldisc));
 	(void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);
 
 	/*
diff -urN linux-2.4.28-bk7/drivers/char/tty_ioctl.c linux-2.4.29/drivers/char/tty_ioctl.c
--- linux-2.4.28-bk7/drivers/char/tty_ioctl.c	2002-11-28 15:53:12.000000000 -0800
+++ linux-2.4.29/drivers/char/tty_ioctl.c	2005-01-19 07:08:08.865456328 -0800
@@ -96,8 +96,16 @@
 {
 	int canon_change;
 	struct termios old_termios = *tty->termios;
+	struct tty_ldisc *ld;
+
+	/*
+	 *      Perform the actual termios internal changes under lock.
+	 */
+
+	/* FIXME: we need to decide on some locking/ordering semantics
+	   for the set_termios notification eventually */
+	down(&tty->termios_sem);
 
-	cli();
 	*tty->termios = *new_termios;
 	unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
 	canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON;
@@ -107,7 +115,6 @@
 		tty->canon_data = 0;
 		tty->erasing = 0;
 	}
-	sti();
 	if (canon_change && !L_ICANON(tty) && tty->read_cnt)
 		/* Get characters left over from canonical mode. */
 		wake_up_interruptible(&tty->read_wait);
@@ -134,13 +141,19 @@
 	if (tty->driver.set_termios)
 		(*tty->driver.set_termios)(tty, &old_termios);
 
-	if (tty->ldisc.set_termios)
-		(*tty->ldisc.set_termios)(tty, &old_termios);
+	ld = tty_ldisc_ref(tty);
+	if (ld != NULL) {
+		if (ld->set_termios)
+			(ld->set_termios)(tty, &old_termios);
+		tty_ldisc_deref(ld);
+	}
+	up(&tty->termios_sem);
 }
 
 static int set_termios(struct tty_struct * tty, unsigned long arg, int opt)
 {
 	struct termios tmp_termios;
+	struct tty_ldisc *ld;
 	int retval = tty_check_change(tty);
 
 	if (retval)
@@ -157,8 +170,13 @@
 			return -EFAULT;
 	}
 
-	if ((opt & TERMIOS_FLUSH) && tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
+	ld = tty_ldisc_ref(tty);
+
+	if (ld != NULL) {
+		if ((opt & TERMIOS_FLUSH) && ld->flush_buffer)
+			ld->flush_buffer(tty);
+		tty_ldisc_deref(ld);
+	}
 
 	if (opt & TERMIOS_WAIT) {
 		tty_wait_until_sent(tty, 0);
@@ -223,12 +241,16 @@
 static int get_sgttyb(struct tty_struct * tty, struct sgttyb * sgttyb)
 {
 	struct sgttyb tmp;
+	unsigned long flags;
 
+	down(&tty->termios_sem);
 	tmp.sg_ispeed = 0;
 	tmp.sg_ospeed = 0;
 	tmp.sg_erase = tty->termios->c_cc[VERASE];
 	tmp.sg_kill = tty->termios->c_cc[VKILL];
 	tmp.sg_flags = get_sgflags(tty);
+	up(&tty->termios_sem);
+
 	return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
 }
 
@@ -267,12 +289,14 @@
 	retval = tty_check_change(tty);
 	if (retval)
 		return retval;
-	termios =  *tty->termios;
 	if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))
 		return -EFAULT;
+	down(&tty->termios_sem);
+	termios =  *tty->termios;
 	termios.c_cc[VERASE] = tmp.sg_erase;
 	termios.c_cc[VKILL] = tmp.sg_kill;
 	set_sgflags(&termios, tmp.sg_flags);
+	up(&tty->termios_sem);
 	change_termios(tty, &termios);
 	return 0;
 }
@@ -362,6 +386,7 @@
 {
 	struct tty_struct * real_tty;
 	int retval;
+	struct tty_ldisc *ld;
 
 	if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
 	    tty->driver.subtype == PTY_TYPE_MASTER)
@@ -440,22 +465,26 @@
 			retval = tty_check_change(tty);
 			if (retval)
 				return retval;
+
+			ld = tty_ldisc_ref(tty);
 			switch (arg) {
 			case TCIFLUSH:
-				if (tty->ldisc.flush_buffer)
-					tty->ldisc.flush_buffer(tty);
+				if (ld->flush_buffer)
+					ld->flush_buffer(tty);
 				break;
 			case TCIOFLUSH:
-				if (tty->ldisc.flush_buffer)
-					tty->ldisc.flush_buffer(tty);
+				if (ld->flush_buffer)
+					ld->flush_buffer(tty);
 				/* fall through */
 			case TCOFLUSH:
 				if (tty->driver.flush_buffer)
 					tty->driver.flush_buffer(tty);
 				break;
 			default:
+				tty_ldisc_deref(ld);
 				return -EINVAL;
 			}
+			tty_ldisc_deref(ld);
 			return 0;
 		case TIOCOUTQ:
 			return put_user(tty->driver.chars_in_buffer ?
@@ -501,9 +530,11 @@
 		case TIOCSSOFTCAR:
 			if (get_user(arg, (unsigned int *) arg))
 				return -EFAULT;
+			down(&tty->termios_sem);
 			tty->termios->c_cflag =
 				((tty->termios->c_cflag & ~CLOCAL) |
 				 (arg ? CLOCAL : 0));
+			up(&tty->termios_sem);
 			return 0;
 		default:
 			return -ENOIOCTLCMD;
diff -urN linux-2.4.28-bk7/drivers/char/vac-serial.c linux-2.4.29/drivers/char/vac-serial.c
--- linux-2.4.28-bk7/drivers/char/vac-serial.c	2004-02-18 05:36:31.000000000 -0800
+++ linux-2.4.29/drivers/char/vac-serial.c	2005-01-19 07:08:08.867456414 -0800
@@ -1699,8 +1699,8 @@
 	 * the line discipline to only process XON/XOFF characters.
 	 */
 	tty->closing = 1;
-	if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-		tty_wait_until_sent(tty, info->closing_wait);
+	if (state->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+		tty_wait_until_sent(tty, state->closing_wait);
 	/*
 	 * At this point we stop accepting input.  To do this, we
 	 * disable the receive line status interrupts, and tell the
@@ -1727,9 +1727,9 @@
 	info->event = 0;
 	info->tty = 0;
 	if (info->blocked_open) {
-		if (info->close_delay) {
+		if (state->close_delay) {
 			current->state = TASK_INTERRUPTIBLE;
-			schedule_timeout(info->close_delay);
+			schedule_timeout(state->close_delay);
 		}
 		wake_up_interruptible(&info->open_wait);
 	}
diff -urN linux-2.4.28-bk7/drivers/char/vme_scc.c linux-2.4.29/drivers/char/vme_scc.c
--- linux-2.4.28-bk7/drivers/char/vme_scc.c	2002-08-02 17:39:43.000000000 -0700
+++ linux-2.4.29/drivers/char/vme_scc.c	2005-01-19 07:08:08.868456458 -0800
@@ -569,12 +569,8 @@
 		SCCwrite(COMMAND_REG, CR_TX_PENDING_RESET);   /* disable tx_int on next tx underrun? */
 		port->gs.flags &= ~GS_TX_INTEN;
 	}
-	if (port->gs.tty && port->gs.xmit_cnt <= port->gs.wakeup_chars) {
-		if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-				port->gs.tty->ldisc.write_wakeup)
-			(port->gs.tty->ldisc.write_wakeup)(port->gs.tty);
-		wake_up_interruptible(&port->gs.tty->write_wait);
-	}
+	if (port->gs.tty && port->gs.xmit_cnt <= port->gs.wakeup_chars) 
+		tty_wakeup(port->gs.tty);
 
 	SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
 }
diff -urN linux-2.4.28-bk7/drivers/char/vt.c linux-2.4.29/drivers/char/vt.c
--- linux-2.4.28-bk7/drivers/char/vt.c	2002-11-28 15:53:12.000000000 -0800
+++ linux-2.4.29/drivers/char/vt.c	2005-01-19 07:08:08.869456501 -0800
@@ -588,8 +588,7 @@
 		  default:
 			return -EINVAL;
 		}
-		if (tty->ldisc.flush_buffer)
-			tty->ldisc.flush_buffer(tty);
+		tty_ldisc_flush(tty);
 		return 0;
 
 	case KDGKBMODE:
diff -urN linux-2.4.28-bk7/drivers/isdn/isdn_tty.c linux-2.4.29/drivers/isdn/isdn_tty.c
--- linux-2.4.28-bk7/drivers/isdn/isdn_tty.c	2001-12-21 09:41:54.000000000 -0800
+++ linux-2.4.29/drivers/isdn/isdn_tty.c	2005-01-19 07:08:08.998462088 -0800
@@ -321,10 +321,7 @@
 		info->send_outstanding++;
 		info->msr &= ~UART_MSR_CTS;
 		info->lsr &= ~UART_LSR_TEMT;
-		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-		    tty->ldisc.write_wakeup)
-			(tty->ldisc.write_wakeup) (tty);
-		wake_up_interruptible(&tty->write_wait);
+		tty_wakeup(tty);
 		return;
 	}
 	if (slen < 0) {
@@ -1214,10 +1211,7 @@
 						/* If DLE decoding results in zero-transmit, but
 						 * c originally was non-zero, do a wakeup.
 						 */
-						if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-						 tty->ldisc.write_wakeup)
-							(tty->ldisc.write_wakeup) (tty);
-						wake_up_interruptible(&tty->write_wait);
+						tty_wakeup(tty);
 						info->msr |= UART_MSR_CTS;
 						info->lsr |= UART_LSR_TEMT;
 					}
@@ -1335,10 +1329,7 @@
 	isdn_tty_cleanup_xmit(info);
 	info->xmit_count = 0;
 	restore_flags(flags);
-	wake_up_interruptible(&tty->write_wait);
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	    tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup) (tty);
+	tty_wakeup(tty);
 }
 
 static void
@@ -1867,8 +1858,7 @@
 	isdn_tty_shutdown(info);
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
+	tty_ldisc_flush(tty);
 	info->tty = 0;
 	info->ncarrier = 0;
 	tty->closing = 0;
@@ -2791,8 +2781,7 @@
 			restore_flags(flags);
 			return;
 		}
-		if (info->tty->ldisc.flush_buffer)
-			info->tty->ldisc.flush_buffer(info->tty);
+		tty_ldisc_flush(info->tty);
 		if ((info->flags & ISDN_ASYNC_CHECK_CD) &&
 		    (!((info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) &&
 		       (info->flags & ISDN_ASYNC_CALLOUT_NOHUP)))) {
diff -urN linux-2.4.28-bk7/drivers/macintosh/macserial.c linux-2.4.29/drivers/macintosh/macserial.c
--- linux-2.4.28-bk7/drivers/macintosh/macserial.c	2002-08-02 17:39:44.000000000 -0700
+++ linux-2.4.29/drivers/macintosh/macserial.c	2005-01-19 07:08:09.017462911 -0800
@@ -735,12 +735,8 @@
 	if (!tty)
 		return;
 
-	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
-		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-		    tty->ldisc.write_wakeup)
-			(tty->ldisc.write_wakeup)(tty);
-		wake_up_interruptible(&tty->write_wait);
-	}
+	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) 
+		tty_wakeup(tty);
 }
 
 static int startup(struct mac_serial * info)
@@ -1595,10 +1591,7 @@
 	save_flags(flags); cli();
 	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
 	restore_flags(flags);
-	wake_up_interruptible(&tty->write_wait);
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	    tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup)(tty);
+	tty_wakeup(tty);
 }
 
 /*
@@ -2029,8 +2022,7 @@
 
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
+	tty_ldisc_flush(tty);
 	tty->closing = 0;
 	info->event = 0;
 	info->tty = 0;
diff -urN linux-2.4.28-bk7/drivers/media/video/bttv-if.c linux-2.4.29/drivers/media/video/bttv-if.c
--- linux-2.4.28-bk7/drivers/media/video/bttv-if.c	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.29/drivers/media/video/bttv-if.c	2005-01-19 07:08:09.088465986 -0800
@@ -190,7 +190,6 @@
 	return state;
 }
 
-#ifndef I2C_PEC
 static void bttv_inc_use(struct i2c_adapter *adap)
 {
 	MOD_INC_USE_COUNT;
@@ -200,7 +199,6 @@
 {
 	MOD_DEC_USE_COUNT;
 }
-#endif
 
 static int attach_inform(struct i2c_client *client)
 {
@@ -243,12 +241,8 @@
 };
 
 static struct i2c_adapter bttv_i2c_adap_template = {
-#ifdef I2C_PEC
-	.owner             = THIS_MODULE,
-#else
 	.inc_use           = bttv_inc_use,
 	.dec_use           = bttv_dec_use,
-#endif
 #ifdef I2C_ADAP_CLASS_TV_ANALOG
 	.class             = I2C_ADAP_CLASS_TV_ANALOG,
 #endif
diff -urN linux-2.4.28-bk7/drivers/media/video/tvmixer.c linux-2.4.29/drivers/media/video/tvmixer.c
--- linux-2.4.28-bk7/drivers/media/video/tvmixer.c	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.29/drivers/media/video/tvmixer.c	2005-01-19 07:08:09.144468412 -0800
@@ -193,10 +193,8 @@
 
 	/* lock bttv in memory while the mixer is in use  */
 	file->private_data = mix;
-#ifndef I2C_PEC
 	if (client->adapter->inc_use)
 		client->adapter->inc_use(client->adapter);
-#endif
         return 0;
 }
 
@@ -210,17 +208,12 @@
 		return -ENODEV;
 	}
 
-#ifndef I2C_PEC
 	if (client->adapter->dec_use)
 		client->adapter->dec_use(client->adapter);
-#endif
 	return 0;
 }
 
 static struct i2c_driver driver = {
-#ifdef I2C_PEC
-	.owner           = THIS_MODULE,
-#endif
 	.name            = "tv card mixer driver",
         .id              = I2C_DRIVERID_TVMIXER,
 #ifdef I2C_DF_DUMMY
diff -urN linux-2.4.28-bk7/drivers/net/3c505.c linux-2.4.29/drivers/net/3c505.c
--- linux-2.4.28-bk7/drivers/net/3c505.c	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.29/drivers/net/3c505.c	2005-01-19 07:08:09.146468498 -0800
@@ -32,7 +32,7 @@
  *              Linux 1.3.0 changes by
  *                      Alan Cox <Alan.Cox@linux.org>
  *              More debugging, DMA support, currently maintained by
- *                      Philip Blundell <Philip.Blundell@pobox.com>
+ *                      Philip Blundell <philb@gnu.org>
  *              Multicard/soft configurable dma channel/rev 2 hardware support
  *                      by Christopher Collins <ccollins@pcug.org.au>
  *		Ethtool support (jgarzik), 11/17/2001
diff -urN linux-2.4.28-bk7/drivers/net/8139cp.c linux-2.4.29/drivers/net/8139cp.c
--- linux-2.4.28-bk7/drivers/net/8139cp.c	2004-08-07 16:26:04.000000000 -0700
+++ linux-2.4.29/drivers/net/8139cp.c	2005-01-19 07:08:09.153468802 -0800
@@ -398,6 +398,8 @@
 static struct pci_device_id cp_pci_tbl[] = {
 	{ PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{ PCI_VENDOR_ID_TTTECH, PCI_DEVICE_ID_TTTECH_MC322,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
 	{ },
 };
 MODULE_DEVICE_TABLE(pci, cp_pci_tbl);
diff -urN linux-2.4.28-bk7/drivers/net/8390.c linux-2.4.29/drivers/net/8390.c
--- linux-2.4.28-bk7/drivers/net/8390.c	2004-08-07 16:26:04.000000000 -0700
+++ linux-2.4.29/drivers/net/8390.c	2005-01-19 07:08:09.154468845 -0800
@@ -1143,7 +1143,7 @@
    
 	outb_p(E8390_NODMA+E8390_PAGE0, e8390_base+E8390_CMD);
     
-	if (inb_p(e8390_base) & E8390_TRANS) 
+	if (inb_p(e8390_base+E8390_CMD) & E8390_TRANS) 
 	{
 		printk(KERN_WARNING "%s: trigger_send() called with the transmitter busy.\n",
 			dev->name);
diff -urN linux-2.4.28-bk7/drivers/net/Config.in linux-2.4.29/drivers/net/Config.in
--- linux-2.4.28-bk7/drivers/net/Config.in	2004-08-07 16:26:04.000000000 -0700
+++ linux-2.4.29/drivers/net/Config.in	2005-01-19 07:08:09.155468888 -0800
@@ -71,9 +71,6 @@
          bool '   Broadcom 5222 Dual Phy Support' CONFIG_BCM5222_DUAL_PHY
       fi
    fi
-   if [ "$CONFIG_SIBYTE_SB1xxx_SOC" = "y" ]; then
-      tristate '  SB1250 Ethernet support' CONFIG_NET_SB1250_MAC
-   fi
    if [ "$CONFIG_SGI_IP27" = "y" ]; then
       bool '  SGI IOC3 Ethernet' CONFIG_SGI_IOC3_ETH
    fi
@@ -272,6 +269,9 @@
 dep_tristate 'Packet Engines Hamachi GNIC-II support' CONFIG_HAMACHI $CONFIG_PCI
 dep_tristate 'Packet Engines Yellowfin Gigabit-NIC support (EXPERIMENTAL)' CONFIG_YELLOWFIN $CONFIG_PCI $CONFIG_EXPERIMENTAL
 dep_tristate 'Realtek 8169 Gigabit Ethernet support' CONFIG_R8169 $CONFIG_PCI
+if [ "$CONFIG_SIBYTE_SB1xxx_SOC" = "y" ]; then
+   tristate 'SB1250 Ethernet support' CONFIG_NET_SB1250_MAC
+fi
 dep_tristate 'Marvell Yukon Chipset / SysKonnect SK-98xx Support' CONFIG_SK98LIN $CONFIG_PCI
 dep_tristate 'Broadcom Tigon3 support' CONFIG_TIGON3 $CONFIG_PCI
 
@@ -281,6 +281,13 @@
    dep_bool '    MV-64340 Port 1' CONFIG_MV64340_ETH_1 $CONFIG_MV64340_ETH
    dep_bool '    MV-64340 Port 2' CONFIG_MV64340_ETH_2 $CONFIG_MV64340_ETH
 fi
+
+if [ "$CONFIG_PMC_BIG_SUR" = "y" ]; then
+   tristate 'PMC-Sierra Big Sur Fast Ethernet Adapter' CONFIG_BIG_SUR_FE
+fi
+if [ "$CONFIG_PMC_YOSEMITE" = "y" ]; then
+   tristate 'PMC-Sierra TITAN Gigabit Ethernet Support' CONFIG_TITAN_GE
+fi
 endmenu
 
 if [ "$CONFIG_PPC_ISERIES" = "y" ]; then
@@ -293,8 +300,8 @@
 
 bool 'FDDI driver support' CONFIG_FDDI
 if [ "$CONFIG_FDDI" = "y" ]; then
-   if [ "$CONFIG_PCI" = "y" -o "$CONFIG_EISA" = "y" ]; then
-      tristate '  Digital DEFEA and DEFPA adapter support' CONFIG_DEFXX
+   if [ "$CONFIG_TC" = "y" -o "$CONFIG_EISA" = "y" -o "$CONFIG_PCI" = "y" ]; then
+      tristate '  Digital DEFTA/DEFEA/DEFPA adapter support' CONFIG_DEFXX
    fi
    dep_tristate '  SysKonnect FDDI PCI support' CONFIG_SKFP $CONFIG_PCI
 fi
diff -urN linux-2.4.28-bk7/drivers/net/Makefile linux-2.4.29/drivers/net/Makefile
--- linux-2.4.28-bk7/drivers/net/Makefile	2004-08-07 16:26:04.000000000 -0700
+++ linux-2.4.29/drivers/net/Makefile	2005-01-19 07:08:09.155468888 -0800
@@ -117,6 +117,8 @@
 
 obj-$(CONFIG_GALILEO_64240_ETH) += gt64240eth.o
 obj-$(CONFIG_MV64340_ETH)	+= mv64340_eth.o
+obj-$(CONFIG_BIG_SUR_FE)	+= big_sur_ge.o
+obj-$(CONFIG_TITAN_GE)		+= titan_mdio.o titan_ge.o
 obj-$(CONFIG_AIRONET4500) 	+= aironet4500_core.o
 obj-$(CONFIG_AIRONET4500_CS) 	+= aironet4500_core.o
 obj-$(CONFIG_AIRONET4500_NONCS)  += aironet4500_card.o
diff -urN linux-2.4.28-bk7/drivers/net/au1000_eth.c linux-2.4.29/drivers/net/au1000_eth.c
--- linux-2.4.28-bk7/drivers/net/au1000_eth.c	2004-02-18 05:36:31.000000000 -0800
+++ linux-2.4.29/drivers/net/au1000_eth.c	2005-01-19 07:08:09.157468975 -0800
@@ -241,7 +241,11 @@
 	mdelay(1);
 
 	/* set up LEDs to correct display */
+#ifdef CONFIG_MIPS_MTX1
+	mdio_write(dev, phy_addr, 17, 0xff80);
+#else
 	mdio_write(dev, phy_addr, 17, 0xffc0);
+#endif
 
 	if (au1000_debug > 4)
 		dump_mii(dev, phy_addr);
@@ -1077,6 +1081,7 @@
 static struct {
 	int port;
 	u32 base_addr;
+	u32 macen_addr;
 	int irq;
 	struct net_device *dev;
 } iflist[2];
@@ -1095,23 +1100,48 @@
 	struct net_device *dev;
 	int i, found_one = 0;
 
-	iflist[0].irq = AU1000_ETH0_IRQ;
-	iflist[1].irq = AU1000_ETH1_IRQ;
 	switch (c->cputype) {
+#ifdef CONFIG_SOC_AU1000
 	case CPU_AU1000:
 		num_ifs = 2 - ni;
 		iflist[0].base_addr = AU1000_ETH0_BASE;
 		iflist[1].base_addr = AU1000_ETH1_BASE;
+		iflist[0].macen_addr = AU1000_MAC0_ENABLE;
+		iflist[1].macen_addr = AU1000_MAC1_ENABLE;
+		iflist[0].irq = AU1000_MAC0_DMA_INT;
+		iflist[1].irq = AU1000_MAC1_DMA_INT;
 		break;
+#endif
+#ifdef CONFIG_SOC_AU1100
 	case CPU_AU1100:
 		num_ifs = 1 - ni;
-		iflist[0].base_addr = AU1000_ETH0_BASE;
+		iflist[0].base_addr = AU1100_ETH0_BASE;
+		iflist[0].macen_addr = AU1100_MAC0_ENABLE;
+		iflist[0].irq = AU1100_MAC0_DMA_INT;
 		break;
+#endif
+#ifdef CONFIG_SOC_AU1500
 	case CPU_AU1500:
 		num_ifs = 2 - ni;
 		iflist[0].base_addr = AU1500_ETH0_BASE;
 		iflist[1].base_addr = AU1500_ETH1_BASE;
+		iflist[0].macen_addr = AU1500_MAC0_ENABLE;
+		iflist[1].macen_addr = AU1500_MAC1_ENABLE;
+		iflist[0].irq = AU1500_MAC0_DMA_INT;
+		iflist[1].irq = AU1500_MAC1_DMA_INT;
+		break;
+#endif
+#ifdef CONFIG_SOC_AU1550
+	case CPU_AU1550:
+		num_ifs = 2 - ni;
+		iflist[0].base_addr = AU1550_ETH0_BASE;
+		iflist[1].base_addr = AU1550_ETH1_BASE;
+		iflist[0].macen_addr = AU1550_MAC0_ENABLE;
+		iflist[1].macen_addr = AU1550_MAC1_ENABLE;
+		iflist[0].irq = AU1550_MAC0_DMA_INT;
+		iflist[1].irq = AU1550_MAC1_DMA_INT;
 		break;
+#endif
 	default:
 		num_ifs = 0;
 	}
@@ -1173,9 +1203,8 @@
 	/* aup->mac is the base address of the MAC's registers */
 	aup->mac = (volatile mac_reg_t *)((unsigned long)ioaddr);
 	/* Setup some variables for quick register address access */
-	switch (ioaddr) {
-	case AU1000_ETH0_BASE:
-	case AU1500_ETH0_BASE:
+	if (ioaddr == iflist[0].base_addr)
+	{
 		/* check env variables first */
 		if (!get_ethernet_addr(ethaddr)) { 
 			memcpy(au1000_mac_addr, ethaddr, sizeof(dev->dev_addr));
@@ -1192,37 +1221,27 @@
 						sizeof(dev->dev_addr));
 			}
 		}
-		if (ioaddr == AU1000_ETH0_BASE)
 			aup->enable = (volatile u32 *) 
-				((unsigned long)AU1000_MAC0_ENABLE);
-		else
-			aup->enable = (volatile u32 *) 
-				((unsigned long)AU1500_MAC0_ENABLE);
+				((unsigned long)iflist[0].macen_addr);
 		memcpy(dev->dev_addr, au1000_mac_addr, sizeof(dev->dev_addr));
 		setup_hw_rings(aup, MAC0_RX_DMA_ADDR, MAC0_TX_DMA_ADDR);
 		aup->mac_id = 0;
 		au_macs[0] = aup;
-			break;
-
-	case AU1000_ETH1_BASE:
-	case AU1500_ETH1_BASE:
-		if (ioaddr == AU1000_ETH1_BASE)
-			aup->enable = (volatile u32 *) 
-				((unsigned long)AU1000_MAC1_ENABLE);
+	}
 		else
+	if (ioaddr == iflist[1].base_addr)
+	{
 			aup->enable = (volatile u32 *) 
-				((unsigned long)AU1500_MAC1_ENABLE);
+				((unsigned long)iflist[1].macen_addr);
 		memcpy(dev->dev_addr, au1000_mac_addr, sizeof(dev->dev_addr));
 		dev->dev_addr[4] += 0x10;
 		setup_hw_rings(aup, MAC1_RX_DMA_ADDR, MAC1_TX_DMA_ADDR);
 		aup->mac_id = 1;
 		au_macs[1] = aup;
-			break;
-
-	default:
+	}
+	else
+	{
 		printk(KERN_ERR "%s: bad ioaddr\n", dev->name);
-		break;
-
 	}
 
 	/* bring the device out of reset, otherwise probing the mii
@@ -1370,6 +1389,7 @@
 		control |= MAC_FULL_DUPLEX;
 	}
 	aup->mac->control = control;
+	aup->mac->vlan1_tag = 0x8100; /* activate vlan support */
 	au_sync();
 
 	spin_unlock_irqrestore(&aup->lock, flags);
diff -urN linux-2.4.28-bk7/drivers/net/big_sur_ge.c linux-2.4.29/drivers/net/big_sur_ge.c
--- linux-2.4.28-bk7/drivers/net/big_sur_ge.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.29/drivers/net/big_sur_ge.c	2005-01-19 07:08:09.160469105 -0800
@@ -0,0 +1,1613 @@
+/*
+ * drivers/net/big_sur_ge.c - Driver for PMC-Sierra Big Sur
+ * ethernet ports
+ *
+ * Copyright (C) 2003, 2004 PMC-Sierra Inc.
+ * Author : Manish Lachwani (lachwani@pmc-sierra.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
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+/*
+ * This driver also includes the PHY related stuff. The device
+ * is a fast ethernet device. But, there is a Gigabit unit
+ * in the works. When that is ready, this driver will support
+ * it. 
+ *
+ * Basic Operation
+ * ================
+ * The device operates in following modes:
+ * -> Polled mode, no DMA (FIFO)
+ * -> Polled mode, Simple DMA
+ * -> Interrupt mode, Simple DMA
+ * -> Interrupt mode, Scatter Gather DMA
+ *
+ * Scatter Gather DMA does not work. So, we make use of Simple DMA
+ * mode here. There is no implementation of ring descriptors here
+ * since it is not working as yet. Note that there could be an enhancement
+ * whereby the driver can support FIFO mode or Simple DMA. However,
+ * this version only supports Simple DMA.
+ *
+ * Receive Operation
+ * ==================
+ * The device DMA's sends an interrupt to the processor. The driver 
+ * is invoked and it determines if the packet is to be received. If 
+ * yes, it allocates a new skb and has the DMA controller transfer the 
+ * data into the newly allocated skb. The receive side handles one 
+ * packet at a time. The Rx FIFO on the device is 2000 bytes.
+ *
+ * Send Operation
+ * ===============
+ * The device Transmit FIFO is 2000 bytes long, i.e. one packet. When
+ * sending, the driver makes sure that the packet is aligned. Once
+ * done, it asks the device to do a DMA transfer from memory to the 
+ * onboard FIFO. The device is stopped till the transfer completes since
+ * it can DMA only one packet at a time.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/mii.h>
+#include <linux/interrupt.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "big_sur_ge.h"
+
+MODULE_AUTHOR("Manish Lachwani <lachwani@pmc-sierra.com>");
+MODULE_DESCRIPTION("PMC-Sierra Big Sur Ethernet MAC Driver");
+MODULE_LICENSE("GPL");
+
+#define TX_TIMEOUT (60 * HZ)      /* Transmit timeout */
+
+typedef enum DUPLEX { UNKNOWN, HALF_DUPLEX, FULL_DUPLEX } DUPLEX;
+
+/* Big Sur Ethernet MAC structure */
+struct big_sur_ge_enet {
+        struct net_device_stats *stats;	/* Statistics for this device */
+        struct timer_list phy_timer;    /* PHY monitoring timer */
+        u32 index;             		/* Which interface is this */
+        u32 save_base_address; 		/* Saved physical base address */
+        struct sk_buff *saved_skb;      /* skb being transmitted */
+        spinlock_t lock;            	/* For atomic access to saved_skb */
+        u8 mii_addr;        		/* The MII address of the PHY */
+        big_sur_ge *emac;               /* GE driver structure */
+	struct tasklet_struct big_sur_tasklet;	/* Tasklet structure */
+};
+
+extern unsigned char big_sur_mac_addr_base[6];
+
+/*
+ * Function Prototypes 
+ */
+unsigned long big_sur_ge_dma_control(xdma_channel *);
+void big_sur_ge_dma_reset(xdma_channel *);
+static void handle_intr(struct net_device *, big_sur_ge *);
+void big_sur_ge_check_fifo_recv_error(struct net_device *, big_sur_ge *);
+void big_sur_ge_check_fifo_send_error(struct net_device *, big_sur_ge *);
+static int big_sur_ge_config_fifo(big_sur_ge *);
+static int big_sur_ge_config_dma(big_sur_ge *);
+void big_sur_ge_enet_reset(big_sur_ge *);
+void big_sur_ge_check_mac_error(big_sur_ge *, unsigned long);
+static void big_sur_receive(struct net_device *);
+static void big_sur_tx_free_skb(struct net_device *);
+big_sur_ge_config *big_sur_ge_get_config(int);
+static void big_sur_ge_reset(struct net_device *,DUPLEX);
+
+/*
+ * DMA Channel Initialization. In case of Simple DMA,
+ * not much to do here. However, in case of SG DMA, we
+ * need to intialize the descriptor pointers 
+ */
+int big_sur_ge_dma_init(xdma_channel *dma, unsigned long base_address) 
+{
+	dma->reg_base_address = base_address;
+	dma->ready = 1; 
+
+	big_sur_ge_dma_reset(dma);
+	return 0;
+}
+
+/*
+ * Perform the self test on the DMA channel 
+ */
+#define BIG_SUR_GE_CONTROL_REG_RESET_MASK	0x98000000
+
+int big_sur_ge_dma_self_test(xdma_channel *dma)
+{
+	unsigned long	reg_data;
+
+	big_sur_ge_dma_reset(dma);
+	
+	reg_data = big_sur_ge_dma_control(dma);
+	if (reg_data != BIG_SUR_GE_CONTROL_REG_RESET_MASK) {
+		printk(KERN_ERR "DMA Channel Self Test Failed \n");
+		return -1;
+	}
+	
+	return 0;
+}
+
+/*
+ * Reset the DMA channel
+ */
+void big_sur_ge_dma_reset(xdma_channel *dma)
+{
+	BIG_SUR_GE_WRITE(dma->reg_base_address + BIG_SUR_GE_RST_REG_OFFSET,
+						BIG_SUR_GE_RESET_MASK);
+}
+
+/*
+ * Get control register from the DMA channel
+ */
+unsigned long big_sur_ge_dma_control(xdma_channel *dma)
+{
+	return BIG_SUR_GE_READ(dma->reg_base_address + BIG_SUR_GE_DMAC_REG_OFFSET);
+}
+
+/*
+ * Set control register of the DMA channel
+ */
+void big_sur_ge_set_dma_control(xdma_channel *dma, unsigned long control)
+{
+	BIG_SUR_GE_WRITE(dma->reg_base_address + BIG_SUR_GE_DMAC_REG_OFFSET, control);
+}
+
+/*
+ * Get the status of the DMA channel 
+ */
+unsigned long big_sur_ge_dma_status(xdma_channel *dma)
+{
+	return BIG_SUR_GE_READ(dma->reg_base_address + BIG_SUR_GE_DMAS_REG_OFFSET);
+}
+
+/*
+ * Transfer the data over the DMA channel
+ */
+void big_sur_ge_dma_transfer(xdma_channel *dma, unsigned long *source,
+				unsigned long *dest, unsigned long length)
+{
+	/* Source Address */
+	BIG_SUR_GE_WRITE(dma->reg_base_address + BIG_SUR_GE_SA_REG_OFFSET, 
+				(unsigned long)source);
+
+	/* Destination Address */
+	BIG_SUR_GE_WRITE(dma->reg_base_address + BIG_SUR_GE_DA_REG_OFFSET,
+				(unsigned long)dest);
+
+	/* Length of the data */
+	BIG_SUR_GE_WRITE(dma->reg_base_address + BIG_SUR_GE_LEN_REG_OFFSET,
+				length);
+}
+
+/*
+ * Init the packet fifo only in the FIFO mode
+ */
+int packet_fifo_init(packet_fifo *fifo, u32 reg, u32 data)
+{
+	fifo->reg_base_addr = reg;
+	fifo->data_base_address = data;
+	fifo->ready_status = 1;
+
+	BIG_SUR_GE_FIFO_RESET(fifo);
+
+	return 0;
+}
+
+/*
+ * Write to the packet FIFO, 32-bit at a time. 
+ */
+static int packet_fifo_write(packet_fifo * fifo, int *buffer, int len)
+{
+	unsigned long fifo_count, word_count, extra_byte;
+	unsigned long *buffer_data = (unsigned long *) buffer;
+
+	fifo_count =
+	    BIG_SUR_GE_READ(fifo->reg_base_addr +
+			    BIG_SUR_GE_FIFO_WIDTH_BYTE_COUNT);
+	fifo_count &= BIG_SUR_GE_COUNT_MASK;
+
+	word_count = len / BIG_SUR_GE_FIFO_WIDTH_BYTE_COUNT;
+	extra_byte = len % BIG_SUR_GE_FIFO_WIDTH_BYTE_COUNT;
+
+	if (extra_byte > 0)
+		if (fifo_count > (word_count + 1)) {
+			printk(KERN_ERR
+			       "No room in the packet send fifo \n");
+			return -1;
+		}
+
+	for (fifo_count = 0; fifo_count < word_count; fifo_count++)
+		BIG_SUR_GE_WRITE(fifo->data_base_address,
+				 buffer_data[fifo_count]);
+
+	if (extra_byte > 0) {
+		unsigned long last_word = 0;
+		int *extra_buffer_data =
+		    (int *) (buffer_data + word_count);
+
+		if (extra_byte == 1)
+			last_word = extra_buffer_data[0] << 24;
+		else if (extra_byte == 2)
+			last_word = (extra_buffer_data[0] << 24 |
+				     extra_buffer_data[1] << 16);
+
+		else if (extra_byte == 3)
+			last_word = (extra_buffer_data[0] << 24 |
+				     extra_buffer_data[1] << 16 |
+				     extra_buffer_data[2] << 8);
+
+
+		BIG_SUR_GE_WRITE(fifo->data_base_address, last_word);
+	}
+
+	return 0;
+}
+
+/*
+ * Start transmitting the packet 
+ */
+int big_sur_tx(big_sur_ge *emac, u8 *buffer, unsigned long byte_cnt)
+{
+	unsigned long int_status, reg_data, status_reg;
+
+	if ( (!emac->started) && (emac->polled) &&
+		(emac->dma_sg) ) 
+		return -1;
+
+	/* There is space in the FIFO */
+	int_status = BIG_SUR_GE_READ(emac->base_address + XIIF_V123B_IISR_OFFSET);
+	if (int_status & BIG_SUR_GE_EIR_XMIT_LFIFO_FULL_MASK) {
+		printk(KERN_ERR "Tx FIFO error: Queue is Full \n");
+		return -1;
+	}
+
+	/*
+	 * Check if there is enough space for this packet
+	 */
+	if ((BIG_SUR_GE_GET_COUNT(&emac->send_fifo) * sizeof(unsigned long)) < byte_cnt) {
+		printk(KERN_ERR "Send FIFO on chip is full \n");
+		return -1;
+	}
+
+	if (emac->has_dma == 0) {
+		/* Write to the Send FIFO */
+		if (packet_fifo_write(&emac->send_fifo, buffer, byte_cnt) == -1) {
+			printk(KERN_ERR "Error : Could not write to FIFO \n");
+			return -1;
+		}
+
+		/* Write the MSB of the length */
+		BIG_SUR_GE_WRITE(emac->base_address + 0x1FF4, (byte_cnt & 0xff00));
+
+		/* Write the LSB of the length */
+		BIG_SUR_GE_WRITE(emac->base_address + 0x1FF8, (byte_cnt & 0x00ff));
+
+		/* Write the Status bit */
+		BIG_SUR_GE_WRITE(emac->base_address + 0x1FFC, 0x80000000);
+	
+		/* Make sure MAC has done transmitting */	
+		status_reg = BIG_SUR_GE_READ(emac->base_address + 0x1FFC);
+		while (!(status_reg & 0x80000000)) {
+			status_reg = BIG_SUR_GE_READ(emac->base_address + 0x1FFC);
+			if (!(status_reg & 0x80000000))
+				break;
+		}
+
+	}
+	else {
+		/* DMA Engine is not buzy */
+		if (big_sur_ge_dma_status(&emac->send_channel) & BIG_SUR_GE_DMASR_BUSY_MASK) {
+			printk(KERN_ERR "Send channel FIFO engine busy \n");
+			return -1;
+		}
+
+		/* Get ready to transfer the data */
+		big_sur_ge_set_dma_control(&emac->send_channel, 
+					BIG_SUR_GE_DMACR_SOURCE_INCR_MASK |
+					BIG_SUR_GE_DMACR_DEST_LOCAL_MASK  |
+					BIG_SUR_GE_DMACR_SG_DISABLE_MASK);
+
+		big_sur_ge_dma_transfer(&emac->send_channel, (unsigned long *)buffer, 
+					(unsigned long *)(emac->base_address + 
+					BIG_SUR_GE_PFIFO_TXDATA_OFFSET), byte_cnt);
+
+		/* Check the DMA Engine status */	
+		reg_data = big_sur_ge_dma_status(&emac->send_channel);
+		while (reg_data & BIG_SUR_GE_DMASR_BUSY_MASK) {
+                	reg_data = big_sur_ge_dma_status(&emac->recv_channel);
+	                if (!(reg_data & BIG_SUR_GE_DMASR_BUSY_MASK))
+        	                break;
+        	}
+
+		/* Check for any DMA errors */
+		if ( (reg_data & BIG_SUR_GE_DMASR_BUS_ERROR_MASK) || 
+			(reg_data & BIG_SUR_GE_DMASR_BUS_TIMEOUT_MASK)) {
+				printk(KERN_ERR "Send side DMA error \n");
+				return -1;
+		}
+
+		/* Write the packet length */
+		BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_TPLR_OFFSET, byte_cnt);
+	}
+
+	/* Good Send */
+	return 0;
+}
+
+/*
+ * Read the packet FIFO
+ */
+static int packet_fifo_read(packet_fifo * fifo, u8 * buffer, unsigned int len)
+{
+	unsigned long fifo_count, word_count, extra_byte;
+	unsigned long *buffer_data = (unsigned long *) buffer;
+
+	fifo_count =
+	    BIG_SUR_GE_READ(fifo->reg_base_addr +
+			    BIG_SUR_GE_FIFO_WIDTH_BYTE_COUNT);
+	fifo_count &= BIG_SUR_GE_COUNT_MASK;
+
+	if ((fifo_count * BIG_SUR_GE_FIFO_WIDTH_BYTE_COUNT) < len)
+		return -1;
+
+	word_count = len / BIG_SUR_GE_FIFO_WIDTH_BYTE_COUNT;
+	extra_byte = len % BIG_SUR_GE_FIFO_WIDTH_BYTE_COUNT;
+
+	for (fifo_count = 0; fifo_count < word_count; fifo_count++)
+		buffer_data[fifo_count] =
+		    BIG_SUR_GE_READ(fifo->reg_base_addr);
+
+	if (extra_byte > 0) {
+		unsigned long last_word;
+		int *extra_buffer_data =
+		    (int *) (buffer_data + word_count);
+
+		last_word = BIG_SUR_GE_READ(fifo->data_base_address);
+		if (extra_byte == 1)
+			extra_buffer_data[0] = (int) (last_word << 24);
+		else if (extra_byte == 2) {
+			extra_buffer_data[0] = (int) (last_word << 24);
+			extra_buffer_data[1] = (int) (last_word << 16);
+		} else if (extra_byte == 3) {
+			extra_buffer_data[0] = (int) (last_word << 24);
+			extra_buffer_data[1] = (int) (last_word << 16);
+			extra_buffer_data[2] = (int) (last_word << 8);
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * FIFO receive for Simple DMA case
+ */
+int big_sur_rx(big_sur_ge *emac, u8 *buffer, unsigned long *byte_cnt)
+{
+	unsigned long int_status, reg_data, packet_length;
+
+        if ( (!emac->started) && (emac->polled) &&
+		(emac->dma_sg) ) {
+                return -1;
+	}
+
+	/* Not enough space in the current buffer */	
+	if (*byte_cnt < BIG_SUR_GE_MAX_FRAME_SIZE)
+		return -1;
+
+	int_status = BIG_SUR_GE_READ(emac->base_address + XIIF_V123B_IISR_OFFSET);
+
+	/* FIFO is empty */
+	if (int_status & BIG_SUR_GE_EIR_RECV_LFIFO_EMPTY_MASK) {
+		BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_IISR_OFFSET, 
+					BIG_SUR_GE_EIR_RECV_LFIFO_EMPTY_MASK);
+		return -1;
+	}
+
+	packet_length = BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_RPLR_OFFSET);
+
+	if (emac->has_dma == 0) {
+		reg_data = BIG_SUR_GE_READ(emac->base_address + 0x3FFC);
+		if (reg_data & 0x80000000) {
+			if (packet_fifo_read(&emac->recv_fifo, buffer, packet_length) == -1) {
+				printk(KERN_ERR "Could not read the packet fifo \n");
+				return -1;
+			}
+
+			BIG_SUR_GE_WRITE(emac->base_address + 0x3FFC, 0x0);
+		}
+	}
+	else {	
+		/* Rx side DMA engine */
+		if (big_sur_ge_dma_status(&emac->recv_channel) & BIG_SUR_GE_DMASR_BUSY_MASK) {
+			printk(KERN_ERR "Rx side DMA Engine busy \n");
+			return -1;
+		}
+
+		if (packet_length == 0) {
+			printk(KERN_ERR "MAC has the FIFO packet length 0 \n");
+			return -1;
+		}
+
+		/* For the simple DMA case only */
+		big_sur_ge_set_dma_control(&emac->recv_channel, 
+							BIG_SUR_GE_DMACR_DEST_INCR_MASK |
+							BIG_SUR_GE_DMACR_SOURCE_LOCAL_MASK |
+							BIG_SUR_GE_DMACR_SG_DISABLE_MASK);
+
+		big_sur_ge_dma_transfer(&emac->recv_channel, (unsigned long *)
+					(emac->base_address + 
+					BIG_SUR_GE_PFIFO_RXDATA_OFFSET), (unsigned long *)
+					buffer, packet_length);
+
+		reg_data = big_sur_ge_dma_status(&emac->recv_channel);
+		while (reg_data & BIG_SUR_GE_DMASR_BUSY_MASK) {
+			reg_data = big_sur_ge_dma_status(&emac->recv_channel);
+			if (!(reg_data & BIG_SUR_GE_DMASR_BUSY_MASK))
+					break;
+		}	
+
+		if ( (reg_data & BIG_SUR_GE_DMASR_BUS_ERROR_MASK) || 
+			(reg_data & BIG_SUR_GE_DMASR_BUS_TIMEOUT_MASK)) {
+				printk(KERN_ERR "DMA Bus Error \n");
+				return -1;
+		}
+	}
+
+	*byte_cnt = packet_length;
+	
+	return 0;
+}
+
+/*
+ * Main FIFO Interrupt Handler
+ */
+void big_sur_ge_fifo_intr(unsigned long data)
+{
+	struct net_device *netdev = (struct net_device *)data;
+	struct big_sur_ge_enet *lp = (struct big_sur_ge_enet *)netdev->priv;
+	big_sur_ge *emac = (big_sur_ge *)lp->emac;
+
+	/* Read the interrupt status */
+	unsigned long int_status = BIG_SUR_GE_READ(emac->base_address +
+							XIIF_V123B_DIPR_OFFSET);
+
+	/* Handle Rx and Tx */
+	if (int_status & BIG_SUR_GE_IPIF_EMAC_MASK)
+		handle_intr(netdev, emac);
+
+	/* Handle Receive Error */
+	if (int_status & BIG_SUR_GE_IPIF_RECV_FIFO_MASK)
+		big_sur_ge_check_fifo_recv_error(netdev, emac);
+
+	/* Handle Transmit Error */
+	if (int_status & BIG_SUR_GE_IPIF_SEND_FIFO_MASK)
+		big_sur_ge_check_fifo_send_error(netdev, emac);
+
+	/* Clear the errors */
+	if (int_status & XIIF_V123B_ERROR_MASK)
+		BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_DISR_OFFSET, 
+							XIIF_V123B_ERROR_MASK);
+}
+
+/*
+ * Tasklet function to invoke interrupt
+ */
+void big_sur_tasklet_schedule(void *data)
+{
+	struct net_device *netdev = (struct net_device *)data;
+	struct big_sur_ge_enet *lp = (struct big_sur_ge_enet *)netdev->priv;
+
+	tasklet_schedule(&lp->big_sur_tasklet);
+	
+	return;
+}
+
+/*
+ * Main intr handler 
+ */
+static void handle_intr(struct net_device *netdev, big_sur_ge *emac)
+{
+	unsigned long int_status = BIG_SUR_GE_READ(emac->base_address + 
+						XIIF_V123B_IISR_OFFSET);
+
+	/* Process the Rx side */
+	if (int_status & BIG_SUR_GE_EIR_RECV_DONE_MASK) {
+		big_sur_receive(netdev);
+		BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_IISR_OFFSET, 
+						BIG_SUR_GE_EIR_RECV_DONE_MASK);
+	}
+
+	/* Process the Tx side */
+	if (int_status & BIG_SUR_GE_EIR_XMIT_DONE_MASK) {
+		big_sur_tx_free_skb(netdev);
+		BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_IISR_OFFSET,
+                                                BIG_SUR_GE_EIR_XMIT_DONE_MASK);
+	}
+
+	big_sur_ge_check_mac_error(emac, int_status);
+}
+/*
+ * For now, the MAC address errors dont trigger a update of the 
+ * stats. There is no stats framework in place. Hence, we just
+ * check for the errors below and do a reset if needed. 
+ */
+void big_sur_ge_check_mac_error(big_sur_ge *emac, unsigned long int_status)
+{
+	if (int_status & (BIG_SUR_GE_EIR_RECV_DFIFO_OVER_MASK | 
+				BIG_SUR_GE_EIR_RECV_LFIFO_OVER_MASK |
+				BIG_SUR_GE_EIR_RECV_LFIFO_UNDER_MASK |
+				BIG_SUR_GE_EIR_RECV_ERROR_MASK |
+				BIG_SUR_GE_EIR_RECV_MISSED_FRAME_MASK |
+				BIG_SUR_GE_EIR_RECV_COLLISION_MASK |
+				BIG_SUR_GE_EIR_RECV_FCS_ERROR_MASK |
+				BIG_SUR_GE_EIR_RECV_LEN_ERROR_MASK |
+				BIG_SUR_GE_EIR_RECV_SHORT_ERROR_MASK |
+				BIG_SUR_GE_EIR_RECV_LONG_ERROR_MASK |
+				BIG_SUR_GE_EIR_RECV_ALIGN_ERROR_MASK |
+				BIG_SUR_GE_EIR_XMIT_SFIFO_OVER_MASK |
+				BIG_SUR_GE_EIR_XMIT_LFIFO_OVER_MASK |
+				BIG_SUR_GE_EIR_XMIT_SFIFO_UNDER_MASK |
+				BIG_SUR_GE_EIR_XMIT_LFIFO_UNDER_MASK) ) {
+
+		BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_IIER_OFFSET, 0);
+		big_sur_ge_enet_reset(emac);
+	}
+}
+
+/*
+ * Check for FIFO Recv errors
+ */
+void big_sur_ge_check_fifo_recv_error(struct net_device *netdev, big_sur_ge *emac)
+{
+	if (BIG_SUR_GE_IS_DEADLOCKED(&emac->recv_fifo)) {
+		unsigned long intr_enable;
+
+		/*
+		 * The only way to ack this interrupt is to reset the 
+		 * device. However, before we reset, we make sure this
+		 * interrupt is disabled
+		 */
+		intr_enable = BIG_SUR_GE_READ(emac->base_address + XIIF_V123B_DIER_OFFSET);
+		BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_DIER_OFFSET,
+					(intr_enable & ~(BIG_SUR_GE_IPIF_RECV_FIFO_MASK)));
+
+		/* Reset the device */
+		big_sur_ge_reset(netdev, UNKNOWN);
+
+		/* Turn the interrupts back on */
+		BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_DIER_OFFSET,
+					(intr_enable | BIG_SUR_GE_IPIF_RECV_FIFO_MASK));
+
+	}
+}
+
+/*
+ * Check for FIFO Send errors
+ */
+void big_sur_ge_check_fifo_send_error(struct net_device *netdev, big_sur_ge *emac)
+{
+        if (BIG_SUR_GE_IS_DEADLOCKED(&emac->send_fifo)) {
+		unsigned long intr_enable;
+
+		/* Disable the interrupt first */
+		intr_enable = BIG_SUR_GE_READ(emac->base_address + XIIF_V123B_DIER_OFFSET);
+		BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_DIER_OFFSET,
+                                        (intr_enable & ~(BIG_SUR_GE_IPIF_SEND_FIFO_MASK)));
+
+		/* Reset the device */
+		big_sur_ge_reset(netdev, UNKNOWN);
+
+		/* Turn the interrupts back on */
+		BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_DIER_OFFSET,
+					(intr_enable | BIG_SUR_GE_IPIF_SEND_FIFO_MASK));
+	}
+}
+
+/*
+ * GE unit init
+ */
+int big_sur_ge_enet_init(big_sur_ge *emac, unsigned int device_id)
+{
+	big_sur_ge_config *config;
+	int err;
+	
+	/* Assume that the device has been stopped */
+	config = big_sur_ge_get_config(device_id);
+	if (config == NULL)
+		return -1;
+
+	emac->ready = 0;
+	emac->started = 0;
+	emac->dma_sg = 0; 
+	emac->has_mii = config->has_mii;
+	emac->has_mcast_hash_table = 0;
+	emac->dma_config = config->dma_config;
+	emac->base_address = config->base_address;
+
+	if (big_sur_ge_config_dma(emac) == -1)
+		return -1;
+
+	if (emac->has_dma == 0) {
+		err = big_sur_ge_config_fifo(emac);
+		if (err == -1)
+			return err;
+	}
+
+	/* Now, we know that the FIFO initialized successfully. So, set the ready flag */
+	emac->ready = 1;
+
+	/* Do we need a PHY reset here also. It did cause problems on some boards */	
+	big_sur_ge_enet_reset(emac);
+
+	/* PHY reset code. Remove if causes a problem on the board */
+	big_sur_ge_reset_phy(emac->base_address);
+
+	return 0;
+}
+
+/*
+ * Start the GE unit for Tx, Rx and Interrupts
+ */
+int big_sur_ge_start(big_sur_ge *emac)
+{
+	unsigned long		reg_data;
+	
+	/*
+	 * Basic mode of operation is polled and interrupt mode. 
+	 * We disable the polled mode for good. We may use the 
+	 * polled mode for Rx NAPI but that does not require all 
+	 * the interrupts to be disabled
+	 */
+	emac->polled = 0;
+
+	/*
+ 	 * DMA: Three modes of operation - simple, FIFO, SG. 
+	 * SG is surely not working and so is kept off using the 
+	 * dma_sg flag. Simple and FIFO work. But, we may not use FIFO 
+	 * at all. So, we enable the interrupts below
+	 */
+	BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_DIER_OFFSET, 
+				BIG_SUR_GE_IPIF_FIFO_DFT_MASK | XIIF_V123B_ERROR_MASK);
+
+	BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_IIER_OFFSET,
+				BIG_SUR_GE_EIR_DFT_FIFO_MASK);
+
+	/* Toggle the started flag */
+	emac->started = 1;
+
+	/* Start the Tx and Rx units respectively */
+	reg_data = BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_ECR_OFFSET);
+	reg_data &= ~(BIG_SUR_GE_ECR_XMIT_RESET_MASK | BIG_SUR_GE_ECR_RECV_RESET_MASK);
+	reg_data |= (BIG_SUR_GE_ECR_XMIT_ENABLE_MASK | BIG_SUR_GE_ECR_RECV_ENABLE_MASK);
+	
+	BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_ECR_OFFSET, reg_data);
+
+	return 0;
+}
+
+/*
+ * Stop the GE unit
+ */
+int big_sur_ge_stop(big_sur_ge *emac)
+{
+	unsigned long	reg_data;
+
+	/* We assume that the device is not already stopped */
+	if (!emac->started)
+		return 0;
+
+	/* Disable the Tx and Rx unit respectively */
+	reg_data = BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_ECR_OFFSET);
+	reg_data &= ~(BIG_SUR_GE_ECR_XMIT_ENABLE_MASK | BIG_SUR_GE_ECR_RECV_ENABLE_MASK);
+	BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_ECR_OFFSET, reg_data);
+
+	/* Disable the interrupts */
+	BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_DGIER_OFFSET, 0);
+
+	/* Toggle the started flag */
+	emac->started = 0;
+
+	return 0;
+}
+
+/*
+ * Reset the GE MAC unit 
+ */
+void big_sur_ge_enet_reset(big_sur_ge *emac)
+{
+	unsigned long reg_data;
+
+	(void) big_sur_ge_stop(emac);
+
+	BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_RESETR_OFFSET, 
+			XIIF_V123B_RESET_MASK);
+	
+	/*
+         * For now, configure the receiver to not strip off 
+	 * FCS and padding since this is not currently supported. 
+	 * In the future, just take the default and provide the option 
+	 * for the user to change this behavior.
+         */
+	reg_data = BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_ECR_OFFSET);
+	reg_data &= ~(BIG_SUR_GE_ECR_RECV_PAD_ENABLE_MASK | BIG_SUR_GE_ECR_RECV_FCS_ENABLE_MASK);
+	reg_data &= ~(BIG_SUR_GE_ECR_RECV_STRIP_ENABLE_MASK);
+	BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_ECR_OFFSET, reg_data);
+}
+
+/*
+ * Set the MAC address of the GE mac unit 
+ */
+int big_sur_ge_set_mac_address(big_sur_ge *emac, unsigned char *addr)
+{
+	unsigned long	mac_addr = 0;
+
+	/* Device is started and so mac address must be set */
+	if (emac->started == 1)
+		return 0;
+
+	/* Address High */
+	mac_addr = ( (addr[0] << 8) | addr[1]);
+	BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_SAH_OFFSET, mac_addr);
+
+	/* Address Low */
+	mac_addr |= ( (addr[2] << 24) | (addr[3] << 16) | 
+			(addr[4] << 8) | addr[5]);
+	BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_SAL_OFFSET, mac_addr);
+	
+	return 0;
+}
+
+/*
+ * Get the MAC address of the GE MAC unit
+ */
+void big_sur_ge_get_mac_unit(big_sur_ge *emac, unsigned int *addr)
+{
+	unsigned long	mac_addr_hi, mac_addr_lo;
+
+	mac_addr_hi = BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_SAH_OFFSET);
+	mac_addr_lo = BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_SAL_OFFSET);
+
+	addr[0] = (mac_addr_hi >> 8);
+	addr[1] = mac_addr_hi;
+
+	addr[2] = (mac_addr_lo >> 24);
+	addr[3] = (mac_addr_lo >> 16);
+	addr[4] = (mac_addr_lo >> 8);
+	addr[5] = mac_addr_lo;
+}
+
+/*
+ * Configure the GE MAC for DMA capabilities, only Simple
+ */
+static int big_sur_ge_config_dma(big_sur_ge *emac)
+{
+	/* Supports Simple DMA */
+	emac->has_dma = 1;
+
+	if (big_sur_ge_dma_init(&emac->recv_channel, emac->base_address +
+				BIG_SUR_GE_DMA_RECV_OFFSET) == -1) {
+		printk(KERN_ERR "Could not initialize the DMA unit  \n");
+		return -1;
+	}
+
+	if (big_sur_ge_dma_init(&emac->send_channel, emac->base_address +
+                                BIG_SUR_GE_DMA_SEND_OFFSET) == -1) {
+		printk(KERN_ERR "Could not initialize the DMA unit  \n");
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * Configure the FIFO for simple DMA
+ */
+static int big_sur_ge_config_fifo(big_sur_ge *emac)
+{
+	int err = 0;
+
+	/* Receive side packet FIFO */
+	err = packet_fifo_init(&emac->recv_fifo, emac->base_address + 
+				BIG_SUR_GE_PFIFO_RXREG_OFFSET, emac->base_address +
+				BIG_SUR_GE_PFIFO_RXDATA_OFFSET);
+
+	if (err == -1) {
+		printk(KERN_ERR "Could not initialize Rx packet FIFO for Simple DMA \n");
+		return err;
+	}
+
+	/* Send side Packet FIFO */
+	err = packet_fifo_init(&emac->send_fifo, emac->base_address +
+				BIG_SUR_GE_PFIFO_TXREG_OFFSET, emac->base_address +
+				BIG_SUR_GE_PFIFO_TXDATA_OFFSET);
+
+	if (err == -1) {
+		printk(KERN_ERR "Could not initialize Tx packet FIFO for Simple DMA \n");
+	}
+
+	return err;
+}
+
+typedef struct {
+        unsigned long   option;
+        unsigned long   mask;
+} option_map;
+
+static option_map option_table[] = {
+        {BIG_SUR_GE_UNICAST_OPTION, BIG_SUR_GE_ECR_UNICAST_ENABLE_MASK},
+        {BIG_SUR_GE_BROADCAST_OPTION, BIG_SUR_GE_ECR_BROAD_ENABLE_MASK},
+        {BIG_SUR_GE_PROMISC_OPTION, BIG_SUR_GE_ECR_PROMISC_ENABLE_MASK},
+        {BIG_SUR_GE_FDUPLEX_OPTION, BIG_SUR_GE_ECR_FULL_DUPLEX_MASK},
+        {BIG_SUR_GE_LOOPBACK_OPTION, BIG_SUR_GE_ECR_LOOPBACK_MASK},
+        {BIG_SUR_GE_MULTICAST_OPTION, BIG_SUR_GE_ECR_MULTI_ENABLE_MASK},
+        {BIG_SUR_GE_FLOW_CONTROL_OPTION, BIG_SUR_GE_ECR_PAUSE_FRAME_MASK},
+        {BIG_SUR_GE_INSERT_PAD_OPTION, BIG_SUR_GE_ECR_XMIT_PAD_ENABLE_MASK},
+        {BIG_SUR_GE_INSERT_FCS_OPTION, BIG_SUR_GE_ECR_XMIT_FCS_ENABLE_MASK},
+        {BIG_SUR_GE_INSERT_ADDR_OPTION, BIG_SUR_GE_ECR_XMIT_ADDR_INSERT_MASK},
+        {BIG_SUR_GE_OVWRT_ADDR_OPTION, BIG_SUR_GE_ECR_XMIT_ADDR_OVWRT_MASK},
+        {BIG_SUR_GE_STRIP_PAD_OPTION, BIG_SUR_GE_ECR_RECV_PAD_ENABLE_MASK},
+        {BIG_SUR_GE_STRIP_FCS_OPTION, BIG_SUR_GE_ECR_RECV_FCS_ENABLE_MASK},
+        {BIG_SUR_GE_STRIP_PAD_FCS_OPTION, BIG_SUR_GE_ECR_RECV_STRIP_ENABLE_MASK}
+};
+
+#define BIG_SUR_GE_NUM_OPTIONS          (sizeof(option_table) / sizeof(option_map))
+
+/*
+ * Set the options for the GE
+ */
+int big_sur_ge_set_options(big_sur_ge *emac, unsigned long option_flag)
+{
+        unsigned long reg_data;
+        unsigned int index;
+
+        /* Assume that the device is stopped before calling this function */
+
+        reg_data = BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_ECR_OFFSET);
+        for (index = 0; index < BIG_SUR_GE_NUM_OPTIONS; index++) {
+                if (option_flag & option_table[index].option)
+                        reg_data |= option_table[index].mask;
+                else
+                        reg_data &= ~(option_table[index].mask);
+
+        }
+
+        BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_ECR_OFFSET, reg_data);
+
+        /* No polled option */
+        emac->polled = 0;
+        return 0;
+}
+
+/*
+ * Get the options from the GE
+ */
+unsigned long big_sur_ge_get_options(big_sur_ge *emac)
+{
+        unsigned long option_flag = 0, reg_data;
+        unsigned int index;
+
+        reg_data = BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_ECR_OFFSET);
+
+        for (index = 0; index < BIG_SUR_GE_NUM_OPTIONS; index++) {
+                if (option_flag & option_table[index].option)
+                        reg_data |= option_table[index].mask;
+        }
+
+        return option_flag;
+}
+
+/*
+ * Set the Inter frame gap
+ */
+int big_sur_ge_set_frame_gap(big_sur_ge *emac, int part1, int part2)
+{
+        unsigned long config;
+
+        /* Assume that the device is stopped before calling this */
+
+        config = ( (part1 << BIG_SUR_GE_IFGP_PART1_SHIFT) |
+                        (part2 << BIG_SUR_GE_IFGP_PART2_SHIFT) );
+
+        BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_IFGP_OFFSET, config);
+
+        return 0;
+}
+
+/*
+ * Get the Inter frame gap
+ */
+void big_sur_ge_get_frame_gap(big_sur_ge *emac, int *part1, int *part2)
+{
+        unsigned long config;
+
+        config = BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_IFGP_OFFSET);
+        *part1 = ((config & BIG_SUR_GE_IFGP_PART1_SHIFT) >> BIG_SUR_GE_IFGP_PART1_SHIFT);
+        *part2 = ((config & BIG_SUR_GE_IFGP_PART2_SHIFT) >> BIG_SUR_GE_IFGP_PART2_SHIFT);
+}
+
+/*
+ * PHY specific functions for the MAC
+ */
+#define	BIG_SUR_GE_MAX_PHY_ADDR		32
+#define	BIG_SUR_GE_MAX_PHY_REG		32
+
+/*
+ * Read the PHY reg
+ */
+int big_sur_ge_phy_read(big_sur_ge *emac, unsigned long addr, 
+				unsigned long reg_num, unsigned int *data)
+{
+	unsigned long mii_control, mii_data;
+
+	if (!emac->has_mii)
+		return -1;
+
+	mii_control = BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_MGTCR_OFFSET);
+	if (mii_control & BIG_SUR_GE_MGTCR_START_MASK) {
+		printk(KERN_ERR "PHY busy \n");
+		return -1;
+	}
+
+	mii_control = (addr << BIG_SUR_GE_MGTCR_PHY_ADDR_SHIFT);
+	mii_control |= (reg_num << BIG_SUR_GE_MGTCR_REG_ADDR_SHIFT);
+	mii_control |= (BIG_SUR_GE_MGTCR_RW_NOT_MASK | BIG_SUR_GE_MGTCR_START_MASK |
+				BIG_SUR_GE_MGTCR_MII_ENABLE_MASK);
+
+	BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_MGTCR_OFFSET, mii_control);
+
+	while (mii_control & BIG_SUR_GE_MGTCR_START_MASK) 
+		if (!(mii_control & BIG_SUR_GE_MGTCR_START_MASK))
+			break;
+
+	mii_data = BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_MGTDR_OFFSET);
+	*data = (unsigned int) mii_data;
+
+	return 0;
+}
+
+/*
+ * Write to the PHY register
+ */
+int big_sur_ge_phy_write(big_sur_ge *emac, unsigned long addr,
+				unsigned long reg_num, unsigned int data)
+{
+	unsigned long		mii_control;
+
+	if (!emac->has_mii)
+                return -1;
+
+	mii_control = BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_MGTCR_OFFSET);
+	if (mii_control & BIG_SUR_GE_MGTCR_START_MASK) {
+                printk(KERN_ERR "PHY busy \n");
+                return -1;
+        }
+
+	BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_MGTDR_OFFSET, (unsigned long)data);
+	
+	mii_control = (addr << BIG_SUR_GE_MGTCR_PHY_ADDR_SHIFT);
+        mii_control |= (reg_num << BIG_SUR_GE_MGTCR_REG_ADDR_SHIFT);
+        mii_control |= (BIG_SUR_GE_MGTCR_START_MASK | BIG_SUR_GE_MGTCR_MII_ENABLE_MASK);
+
+	BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_MGTCR_OFFSET, mii_control);
+
+	while (mii_control & BIG_SUR_GE_MGTCR_START_MASK)
+                if (!(mii_control & BIG_SUR_GE_MGTCR_START_MASK))
+                        break;
+
+	return 0;
+}
+
+/*
+ * Reset the GE system
+ */
+static void big_sur_ge_reset(struct net_device *netdev, DUPLEX duplex)
+{
+	struct big_sur_ge_enet *lp = (struct big_sur_ge_enet *)netdev->priv;
+	struct sk_buff *skb;
+	unsigned long options;
+	int ifcfg1, ifcfg2;
+
+	/* Stop the queue */
+	netif_stop_queue(netdev);
+
+	big_sur_ge_get_frame_gap(lp->emac, &ifcfg1, &ifcfg2);
+	options = big_sur_ge_get_options(lp->emac);
+	switch (duplex) {
+		case HALF_DUPLEX:
+			options &= ~(BIG_SUR_GE_FDUPLEX_OPTION);
+			break;
+
+		case FULL_DUPLEX:
+			options |= BIG_SUR_GE_FDUPLEX_OPTION;
+			break;
+
+		case UNKNOWN:
+			break;
+	}
+
+	big_sur_ge_enet_reset(lp->emac);
+
+	/* Set the necessary options for the MAC unit */
+	big_sur_ge_set_mac_address(lp->emac, netdev->dev_addr);
+	big_sur_ge_set_frame_gap(lp->emac, ifcfg1, ifcfg2);
+	big_sur_ge_set_options(lp->emac, options);
+
+	(void) big_sur_ge_start(lp->emac);
+
+	spin_lock_irq(lp->lock);
+	skb = lp->saved_skb;
+	lp->saved_skb = NULL;
+	spin_unlock_irq(lp->lock);
+
+	if (skb) 
+		dev_kfree_skb(skb);
+
+	/* Start the queue, in case it was stopped */
+	netif_wake_queue(netdev);
+}
+
+/*
+ * Get the PHY status and then configure the 
+ * speed, duplex, link status etc.
+ */
+static int big_sur_ge_get_phy_status(struct net_device *netdev, 
+					DUPLEX *duplex, int *linkup)
+{
+	struct big_sur_ge_enet  *lp = netdev->priv;
+	unsigned int		reg_data;
+	int			err = 0;
+
+	err = big_sur_ge_phy_read(lp->emac, lp->mii_addr, MII_BMCR, &reg_data);
+	if (err == -1) {
+		printk(KERN_ERR "%s: Could not read PHY control register", netdev->name);
+		return err;
+	}
+
+	if (!(reg_data & BMCR_ANENABLE)) {
+		if (reg_data & BMCR_FULLDPLX) 
+			*duplex = FULL_DUPLEX;
+		else
+			*duplex = HALF_DUPLEX;
+	}
+	else {
+		unsigned int advertise, partner, neg;
+	
+		err = big_sur_ge_phy_read(lp->emac, lp->mii_addr, MII_ADVERTISE, &advertise);
+		if (err == -1) {
+	                printk(KERN_ERR "%s: Could not read PHY control register", netdev->name);
+        	        return err;
+		}
+
+		err = big_sur_ge_phy_read(lp->emac, lp->mii_addr, MII_LPA, &partner);
+		if (err == -1) {
+                        printk(KERN_ERR "%s: Could not read PHY control register", netdev->name);
+                        return err;
+                }
+
+		neg = advertise & partner & ADVERTISE_ALL;
+		if (neg & ADVERTISE_100FULL)
+                        *duplex = FULL_DUPLEX;
+                else if (neg & ADVERTISE_100HALF)
+                        *duplex = HALF_DUPLEX;
+                else if (neg & ADVERTISE_10FULL)
+                        *duplex = FULL_DUPLEX;
+                else
+                        *duplex = HALF_DUPLEX;
+
+		err = big_sur_ge_phy_read(lp->emac, lp->mii_addr, MII_BMSR, &reg_data);
+		if (err == -1) {
+                        printk(KERN_ERR "%s: Could not read PHY control register", netdev->name);
+                        return err;
+                }
+
+		*linkup = (reg_data & BMSR_LSTATUS) != 0;
+
+	}
+	return 0;
+}
+
+/*
+ * Poll the MII for duplex and link status 
+ */
+static void big_sur_ge_poll_mii(unsigned long data)
+{
+	struct net_device *netdev = (struct net_device *) data;	
+	struct big_sur_ge_enet* lp = netdev->priv;
+	unsigned long options;
+	DUPLEX mac_duplex, phy_duplex;
+	int phy_carrier, netif_carrier;
+
+	if (big_sur_ge_get_phy_status(netdev, &phy_duplex, &phy_carrier) == -1) {
+		printk(KERN_ERR "%s: Terminating link monitoring.\n", netdev->name);
+		return;
+	}
+
+	options = big_sur_ge_get_options(lp->emac);
+	if (options & BIG_SUR_GE_FDUPLEX_OPTION)
+		mac_duplex = FULL_DUPLEX;
+	else
+		mac_duplex = HALF_DUPLEX;
+
+	if (mac_duplex != phy_duplex) {
+		tasklet_disable(&lp->big_sur_tasklet);
+		big_sur_ge_reset(netdev, phy_duplex);
+		tasklet_enable(&lp->big_sur_tasklet);
+	}
+
+	netif_carrier = netif_carrier_ok(netdev) != 0;
+
+        if (phy_carrier != netif_carrier) {
+                if (phy_carrier) {
+                        printk(KERN_INFO "%s: Link carrier restored.\n",
+                               netdev->name);
+                        netif_carrier_on(netdev);
+                } else {
+                        printk(KERN_INFO "%s: Link carrier lost.\n", netdev->name);
+                        netif_carrier_off(netdev);
+                }
+        }
+
+        /* Set up the timer so we'll get called again in 2 seconds. */
+        lp->phy_timer.expires = jiffies + 2 * HZ;
+        add_timer(&lp->phy_timer);
+}
+
+/*
+ * Open the network interface
+ */
+static int big_sur_ge_open(struct net_device *netdev)
+{
+	struct big_sur_ge_enet *lp = netdev->priv;
+	unsigned long options;
+	DUPLEX phy_duplex, mac_duplex;
+	int phy_carrier;
+
+	(void) big_sur_ge_stop(lp->emac);
+
+	if (big_sur_ge_set_mac_address(lp->emac, netdev->dev_addr) == -1) {
+		printk(KERN_ERR "%s: Could not set MAC address.\n", netdev->name);
+		return -EIO;
+	}
+
+	options = big_sur_ge_get_options(lp->emac);
+
+	/*
+	 * This MAC unit has no support for Interrupts. So, we initialize
+	 * a tasklet here that will be scheduled from the timer
+	 * interrupt handler. Note that we cannot run the receive
+	 * and the transmit functions as part of an interrupt handler. Since,
+	 * this will be disastrous for the timer under load. Hence, tasklet
+	 * is the best way to go
+	 */
+	tasklet_init(&lp->big_sur_tasklet, big_sur_ge_fifo_intr, (unsigned long)netdev);
+
+	if (!(big_sur_ge_get_phy_status(netdev, &phy_duplex, &phy_carrier))) {
+		if (options & BIG_SUR_GE_FDUPLEX_OPTION)
+			mac_duplex = FULL_DUPLEX;
+		else
+			mac_duplex = HALF_DUPLEX;
+
+		if (mac_duplex != phy_duplex) {
+			switch (phy_duplex) {
+				case HALF_DUPLEX: 
+					options &= ~(BIG_SUR_GE_FDUPLEX_OPTION); 
+					break;
+				case FULL_DUPLEX:
+					options |= BIG_SUR_GE_FDUPLEX_OPTION;
+					break;
+				case UNKNOWN:
+					break;
+			}
+
+			big_sur_ge_set_options(lp->emac, options);
+		}
+	}
+
+	if (big_sur_ge_start(lp->emac) == -1) {
+		printk(KERN_ERR "%s: Could not start device.\n", netdev->name);
+		tasklet_kill(&lp->big_sur_tasklet);
+		return -EBUSY;
+	}
+
+	MOD_INC_USE_COUNT;
+	netif_start_queue(netdev);
+
+	lp->phy_timer.expires = jiffies + 2*HZ;
+        lp->phy_timer.data = (unsigned long)netdev;
+        lp->phy_timer.function = &big_sur_ge_poll_mii;
+	add_timer(&lp->phy_timer);
+
+	return 0;
+}
+
+/*
+ * Close the network device interface
+ */
+static int big_sur_ge_close(struct net_device *netdev)
+{
+	struct big_sur_ge_enet  *lp = netdev->priv;
+	
+	del_timer_sync(&lp->phy_timer);
+	netif_stop_queue(netdev);
+
+	if (big_sur_ge_stop(lp->emac) == -1) {
+		printk(KERN_ERR "%s: Could not stop device.\n", netdev->name);
+		return -EBUSY;
+        }
+
+	tasklet_kill(&lp->big_sur_tasklet);
+
+        MOD_DEC_USE_COUNT;
+        return 0;
+}
+
+/*	
+ * Get the network device stats. 
+ */
+static struct net_device_stats *big_sur_ge_get_stats(struct net_device *netdev)
+{
+	struct big_sur_ge_enet *lp = netdev->priv;
+	
+	return lp->stats;
+}
+
+/*
+ * FIFO send for a packet that needs to be transmitted
+ */
+static int big_sur_start_xmit(struct sk_buff *orig_skb, struct net_device *netdev)
+{
+	struct big_sur_ge_enet *lp = netdev->priv;
+	struct sk_buff *new_skb;
+	unsigned int len, align;
+	struct net_device_stats *stats = lp->stats;
+
+	/* 
+	 * The FIFO takes a single request at a time. Stop the queue to
+	 * accomplish this.  We'll wake the queue in the transmit
+	 * routine below or in the timeout routine
+	 */
+	netif_stop_queue(netdev);
+        len = orig_skb->len;
+
+	/*
+	 * Align the packet for the FIFO
+	 */
+	if (!(new_skb = dev_alloc_skb(len + 4))) {
+                dev_kfree_skb(orig_skb);
+                printk(KERN_ERR "%s: Could not allocate transmit buffer.\n",
+                       netdev->name);
+                netif_wake_queue(netdev);
+                return -EBUSY;
+        }
+
+	align = 4 - ((unsigned long) new_skb->data & 3);
+        if (align != 4)
+                skb_reserve(new_skb, align);
+
+	skb_put(new_skb, len);
+        memcpy(new_skb->data, orig_skb->data, len);
+
+	dev_kfree_skb(orig_skb);
+	lp->saved_skb = new_skb;
+
+	/* Do the actual transmit */
+	if (big_sur_tx(lp->emac, (u8 *) new_skb->data, len) == -1) {
+		spin_lock_irq(&lp->lock);
+                new_skb = lp->saved_skb;
+                lp->saved_skb = NULL;
+                spin_unlock_irq(&lp->lock);
+
+                dev_kfree_skb(new_skb);
+                printk(KERN_ERR "%s: Could not transmit buffer.\n", netdev->name);
+                netif_wake_queue(netdev);
+                return -EIO;
+        }
+
+	stats->tx_bytes += len;
+	stats->tx_packets++;
+
+        return 0;
+}
+
+/*
+ * Free the skb
+ */
+static void big_sur_tx_free_skb(struct net_device *netdev)
+{
+	struct big_sur_ge_enet *lp = netdev->priv;
+	struct sk_buff *skb;
+
+	spin_lock_irq(&lp->lock);
+	skb = lp->saved_skb;
+        lp->saved_skb = NULL;
+        spin_unlock_irq(&lp->lock);
+	
+	if (skb)
+		dev_kfree_skb(skb);
+
+	/* Start the queue since we know that packet has been transmitted */
+        netif_wake_queue(netdev);
+}
+
+/*
+ * Handle the timeout of the ethernet device 
+ */
+static void big_sur_ge_tx_timeout(struct net_device *netdev)
+{
+	struct big_sur_ge_enet *lp = (struct big_sur_ge_enet *)netdev;
+
+	printk("%s: Exceeded transmit timeout of %lu ms.  Resetting mac.\n",
+			netdev->name, TX_TIMEOUT * 1000UL / HZ);
+
+	tasklet_disable(&lp->big_sur_tasklet);
+	big_sur_ge_reset(netdev, UNKNOWN);
+	tasklet_enable(&lp->big_sur_tasklet);
+}
+
+/*
+ * Receive the packets
+ */
+static void big_sur_receive(struct net_device *netdev)
+{
+	struct big_sur_ge_enet *lp = (struct big_sur_ge_enet *)netdev->priv;
+	struct sk_buff *skb;
+	unsigned long len = BIG_SUR_GE_MAX_FRAME_SIZE;
+	unsigned int align;
+	struct net_device_stats *stats = lp->stats;
+	
+	if (!(skb = dev_alloc_skb(len + 4))) {
+		printk(KERN_ERR "%s: Could not allocate receive buffer.\n",
+			netdev->name);
+		return;
+	}
+
+	align = 4 - ((unsigned long) skb->data & 3);
+        if (align != 4)
+                skb_reserve(skb, align);
+
+	if (big_sur_rx(lp->emac, (u8 *)skb->data, &len) == -1) {
+		dev_kfree_skb(skb);
+		
+		printk(KERN_ERR "%s: Could not receive buffer \n", netdev->name);
+		netdev->tx_timeout = NULL;
+		big_sur_ge_reset(netdev, UNKNOWN);
+		netdev->tx_timeout = big_sur_ge_tx_timeout;
+	}
+
+	skb_put(skb, len);
+        skb->dev = netdev;
+        skb->protocol = eth_type_trans(skb, netdev);
+
+	stats->rx_packets++;
+	stats->rx_bytes += len;
+
+	/* Good Rx, send the packet upstream. */
+	netif_rx(skb);
+}
+
+/*
+ * Set the Multicast Hash list
+ */
+static void big_sur_ge_set_multi(struct net_device *netdev)
+{
+	struct big_sur_ge_enet *lp = (struct big_sur_ge_enet *)netdev->priv;
+	unsigned long options;
+
+	tasklet_disable(&lp->big_sur_tasklet);
+
+	(void) big_sur_ge_stop(lp->emac);
+	options = big_sur_ge_get_options(lp->emac);
+	options &= ~(BIG_SUR_GE_PROMISC_OPTION | BIG_SUR_GE_MULTICAST_OPTION);
+
+	if (netdev->flags & IFF_PROMISC) 
+		options |= BIG_SUR_GE_PROMISC_OPTION;
+	
+	(void) big_sur_ge_start(lp->emac);
+
+	tasklet_enable(&lp->big_sur_tasklet);
+}	
+
+/*
+ * IOCTL support
+ */
+static int big_sur_ge_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
+{
+	struct big_sur_ge_enet *lp = netdev->priv;
+	struct mii_ioctl_data *data = (struct mii_ioctl_data *) &rq->ifr_data;
+
+	switch(cmd) {
+		case SIOCGMIIPHY:       	/* Get address of MII PHY in use. */
+	        case SIOCDEVPRIVATE:    	/* for binary compat, remove in 2.5 */
+                	data->phy_id = lp->mii_addr;
+
+        	case SIOCGMIIREG:   	    	/* Read MII PHY register. */
+	        case SIOCDEVPRIVATE + 1: 	/* for binary compat, remove in 2.5 */
+                	if (data->phy_id > 31 || data->reg_num > 31)
+                        	return -ENXIO;
+
+                	del_timer_sync(&lp->phy_timer);
+
+			if (big_sur_ge_phy_read(lp->emac, data->phy_id, 
+						data->reg_num, &data->val_out) == -1) {
+				printk(KERN_ERR "%s: Could not read from PHY", netdev->name);
+				return -EBUSY;
+			}
+
+			lp->phy_timer.expires = jiffies + 2*HZ;
+	                add_timer(&lp->phy_timer);
+				
+			return 0;
+
+		case SIOCSMIIREG:       	/* Write MII PHY register. */
+	        case SIOCDEVPRIVATE + 2:        /* for binary compat, remove in 2.5 */
+			if (data->phy_id > 31 || data->reg_num > 31)
+				return -ENXIO;
+	
+			del_timer_sync(&lp->phy_timer);
+
+			if (big_sur_ge_phy_write(lp->emac, data->phy_id, data->reg_num,
+							data->val_in) == -1) {
+				printk(KERN_ERR "%s: Could not write to PHY", netdev->name);
+				return -EBUSY;
+			}
+
+			lp->phy_timer.expires = jiffies + 2*HZ;
+			add_timer(&lp->phy_timer);
+
+			return 0;
+
+		default:
+			return -EOPNOTSUPP;
+	}
+}
+
+/*
+ * Get the config from the config table 
+ */
+big_sur_ge_config *big_sur_ge_get_config(int index)
+{	
+	/* For port 0 only */
+	big_sur_ge_config *config;
+
+	config->device_id = 0;
+	config->base_address = BIG_SUR_GE_BASE; /* Base Address of the MAC */
+	config->has_counters = 0;
+	config->has_sg_dma = 0;
+	config->dma_config = 0;
+	config->has_mii = 1;
+
+	return (big_sur_ge_config *)config;
+}
+
+/*
+ * Release the network device structure
+ */
+static void big_sur_ge_remove_dev(struct net_device *netdev)
+{
+	struct big_sur_ge_enet  *lp = (struct big_sur_ge_enet *)netdev;
+	big_sur_ge_config	*config;
+
+	config = big_sur_ge_get_config(lp->index);
+	config->base_address = lp->save_base_address;
+	
+	if (lp->saved_skb)
+                dev_kfree_skb(lp->saved_skb);
+        kfree(lp);
+
+        unregister_netdev(netdev);
+        kfree(netdev);
+}
+
+/*
+ * Initial Function to probe the network interface 
+ */
+static int __init big_sur_ge_probe(int index)
+{
+	struct net_device *netdev;
+	struct big_sur_ge_enet *lp;
+	big_sur_ge_config *config;
+	unsigned long maddr;
+
+	config = big_sur_ge_get_config(index);
+	if (!config)
+		return -ENODEV;
+
+	netdev = alloc_etherdev(sizeof(struct big_sur_ge_enet));
+
+	if (!netdev) {
+		printk(KERN_ERR "Could not allocate Big Sur Ethernet device %d.\n",index);
+		return -ENOMEM;
+	}
+
+	SET_MODULE_OWNER(netdev);
+
+	lp = (struct big_sur_ge_enet *)netdev->priv;
+	memset(lp, 0, sizeof(struct big_sur_ge_enet));
+	spin_lock_init(&lp->lock);
+	
+	/* Use KSEG1 address */
+	lp->save_base_address = config->base_address;
+	
+	if (big_sur_ge_enet_init(lp->emac, config->device_id) == -1) {
+		printk(KERN_ERR "%s: Could not initialize device.\n", netdev->name);
+		big_sur_ge_remove_dev(netdev);
+		return -ENODEV;
+	}
+
+	memcpy(netdev->dev_addr, big_sur_mac_addr_base, 6);
+	if (big_sur_ge_set_mac_address(lp->emac, netdev->dev_addr) == -1) {
+		printk(KERN_ERR "%s: Could not set MAC address.\n", netdev->name);
+		big_sur_ge_remove_dev(netdev);
+                return -EIO;
+        }
+
+	/* Check the PHY */	
+	lp->mii_addr = 0xff;
+	for (maddr = 0; maddr < 31; maddr++) {
+		unsigned int	reg_data;
+
+		if (big_sur_ge_phy_read(lp->emac, maddr, MII_BMCR, &reg_data) == 0) {
+			lp->mii_addr = maddr;
+                        break;
+                }
+	}
+
+	if (lp->mii_addr == 0xff) {
+                lp->mii_addr = 0;
+                printk(KERN_WARNING
+                       "%s: No PHY detected.  Assuming a PHY at address %d.\n",
+					netdev->name, lp->mii_addr);
+	}
+
+	netdev->open = big_sur_ge_open;
+	netdev->stop = big_sur_ge_close;
+	netdev->get_stats = big_sur_ge_get_stats; 
+	netdev->do_ioctl = big_sur_ge_ioctl;
+	netdev->tx_timeout = big_sur_ge_tx_timeout;
+	netdev->watchdog_timeo = TX_TIMEOUT;
+	netdev->hard_start_xmit = big_sur_start_xmit;
+	netdev->set_multicast_list = big_sur_ge_set_multi;
+
+	printk(KERN_INFO
+               "%s: PMC-Sierra Big Sur Ethernet Device %d  at 0x%08X mapped to 0x%08X\n",
+		netdev->name, index,
+               lp->save_base_address, config->base_address);
+
+        return 0;
+}
+	
+static int __init big_sur_ge_init(void)
+{
+	int	index = 0;
+
+	while (big_sur_ge_probe(index++) == 0);
+
+	return (index > 1) ? 0 : -ENODEV;
+}
+
+static void __init big_sur_ge_cleanup_module(void)
+{
+	/* Nothing to do here */
+}
+
+module_init(big_sur_ge_init);
+module_exit(big_sur_ge_cleanup_module);
+
diff -urN linux-2.4.28-bk7/drivers/net/big_sur_ge.h linux-2.4.29/drivers/net/big_sur_ge.h
--- linux-2.4.28-bk7/drivers/net/big_sur_ge.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.29/drivers/net/big_sur_ge.h	2005-01-19 07:08:09.162469191 -0800
@@ -0,0 +1,449 @@
+/*
+ * drivers/net/big_sur_ge.h - Driver for PMC-Sierra Big Sur
+ * ethernet ports
+ *
+ * Copyright (C) 2003, 2004 PMC-Sierra Inc.
+ * Author : Manish Lachwani (lachwani@pmc-sierra.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
+ * 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	__BIG_SUR_GE_H__
+#define	__BIG_SUR_GE_H__
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/config.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#define	BIG_SUR_DEVICE_NAME	"big sur"
+#define	BIG_SUR_DEVICE_DESC	"Big Sur Ethernet 10/100 MAC"
+
+#define BIG_SUR_GE_BASE		(0x1b000000 | KSEG1)
+
+#define	BIG_SUR_GE_WRITE(ofs,data)			\
+	*(volatile u32 *)(BIG_SUR_GE_BASE+(ofs)) = data
+
+#define	BIG_SUR_GE_READ(ofs)				\
+	*(volatile u32 *)(BIG_SUR_GE_BASE+(ofs))
+
+#define	BIG_SUR_GE_READ_REG(base_addr, reg_offset)	\
+	BIG_SUR_GE_READ(base_addr + reg_offset)
+
+#define	BIG_SUR_GE_WRITE_REG(base_addr, reg_offset, data)	\
+	BIG_SUR_GE_WRITE(base_addr + reg_offset, data)
+
+#define	BIG_SUR_GE_CONTROL_REG(base_addr, mask)		\
+	BIG_SUR_GE_WRITE(base_addr + BIG_SUR_GE_ECR_OFFSET, mask)
+
+#define	BIG_SUR_GE_FIFO_WIDTH_BYTE_COUNT	4UL
+
+/* IPIF specific defines */
+#define XIIF_V123B_DISR_OFFSET     0UL  /* device interrupt status register */
+#define XIIF_V123B_DIPR_OFFSET     4UL  /* device interrupt pending register */
+#define XIIF_V123B_DIER_OFFSET     8UL  /* device interrupt enable register */
+#define XIIF_V123B_DIIR_OFFSET     24UL /* device interrupt ID register */
+#define XIIF_V123B_DGIER_OFFSET    28UL /* device global interrupt enable reg */
+#define XIIF_V123B_IISR_OFFSET     32UL /* IP interrupt status register */
+#define XIIF_V123B_IIER_OFFSET     40UL /* IP interrupt enable register */
+#define XIIF_V123B_RESETR_OFFSET   64UL /* reset register */
+#define XIIF_V123B_RESET_MASK	   0xAUL
+#define	XIIF_V123B_ERROR_MASK	   0x1UL
+
+/* Options for the MAC */
+#define BIG_SUR_GE_UNICAST_OPTION        	0x00000001
+#define BIG_SUR_GE_BROADCAST_OPTION      	0x00000002
+#define BIG_SUR_GE_PROMISC_OPTION        	0x00000004
+#define BIG_SUR_GE_FDUPLEX_OPTION        	0x00000008
+#define BIG_SUR_GE_POLLED_OPTION         	0x00000010
+#define BIG_SUR_GE_LOOPBACK_OPTION       	0x00000020
+#define BIG_SUR_GE_FLOW_CONTROL_OPTION   	0x00000080
+#define BIG_SUR_GE_INSERT_PAD_OPTION     	0x00000100
+#define BIG_SUR_GE_INSERT_FCS_OPTION     	0x00000200
+#define BIG_SUR_GE_INSERT_ADDR_OPTION    	0x00000400
+#define BIG_SUR_GE_OVWRT_ADDR_OPTION     	0x00000800
+#define BIG_SUR_GE_STRIP_PAD_FCS_OPTION  	0x00002000
+#define BIG_SUR_GE_MULTICAST_OPTION      	0x00000040
+#define BIG_SUR_GE_FLOW_CONTROL_OPTION   	0x00000080
+#define BIG_SUR_GE_INSERT_PAD_OPTION     	0x00000100
+#define BIG_SUR_GE_INSERT_FCS_OPTION     	0x00000200
+#define BIG_SUR_GE_INSERT_ADDR_OPTION    	0x00000400
+#define BIG_SUR_GE_OVWRT_ADDR_OPTION     	0x00000800
+#define BIG_SUR_GE_STRIP_PAD_OPTION      	0x00001000
+#define BIG_SUR_GE_STRIP_FCS_OPTION     	0x00002000
+
+#define BIG_SUR_GE_MTU             1500	/* max size of Ethernet frame */
+#define BIG_SUR_GE_HDR_SIZE        14	/* size of Ethernet header */
+#define BIG_SUR_GE_HDR_VLAN_SIZE   18	/* size of Ethernet header with VLAN */
+#define BIG_SUR_GE_TRL_SIZE        4 	/* size of Ethernet trailer (FCS) */
+#define BIG_SUR_GE_MAX_FRAME_SIZE  \
+		(BIG_SUR_GE_MTU + BIG_SUR_GE_HDR_SIZE + BIG_SUR_GE_TRL_SIZE)
+
+#define BIG_SUR_GE_MAX_VLAN_FRAME_SIZE  \
+		(BIG_SUR_GE_MTU + BIG_SUR_GE_HDR_VLAN_SIZE + BIG_SUR_GE_TRL_SIZE)
+
+/* FIFO Specific Defines */
+#define BIG_SUR_GE_RESET_REG_OFFSET            0UL
+#define BIG_SUR_GE_MODULE_INFO_REG_OFFSET      0UL
+#define BIG_SUR_GE_COUNT_STATUS_REG_OFFSET     4UL
+#define BIG_SUR_GE_RESET_FIFO_MASK             0x0000000A
+#define BIG_SUR_GE_COUNT_MASK                  0x0000FFFF
+#define BIG_SUR_GE_DEADLOCK_MASK               0x20000000
+#define BIG_SUR_GE_ALMOST_EMPTY_FULL_MASK      0x40000000
+#define BIG_SUR_GE_EMPTY_FULL_MASK             0x80000000
+
+#define BIG_SUR_GE_FIFO_RESET(fifo)				\
+		BIG_SUR_GE_WRITE((fifo)->reg_base_addr + 	\
+		BIG_SUR_GE_RESET_REG_OFFSET, BIG_SUR_GE_RESET_FIFO_MASK)
+
+#define	BIG_SUR_GE_GET_COUNT(fifo)			\
+	(BIG_SUR_GE_READ((fifo)->reg_base_addr + 	\
+	BIG_SUR_GE_COUNT_STATUS_REG_OFFSET) & BIG_SUR_GE_COUNT_MASK)
+
+#define	BIG_SUR_GE_IS_ALMOST_EMPTY(fifo)		\
+		(BIG_SUR_GE_READ(fifo->reg_base_addr + 	\
+		BIG_SUR_GE_COUNT_STATUS_REG_OFFSET) &	\
+		BIG_SUR_GE_ALMOST_EMPTY_FULL_MASK)
+
+#define	BIG_SUR_GE_IS_ALMOST_FULL(fifo)  		\
+		(BIG_SUR_GE_READ(fifo->reg_base_addr + 	\
+		BIG_SUR_GE_COUNT_STATUS_REG_OFFSET) &   \
+		BIG_SUR_GE_ALMOST_EMPTY_FULL_MASK)
+
+#define BIG_SUR_GE_IS_EMPTY(fifo)  			\
+		(BIG_SUR_GE_READ(fifo->reg_base_addr +	\
+		BIG_SUR_GE_COUNT_STATUS_REG_OFFSET) &   \
+		BIG_SUR_GE_EMPTY_FULL_MASK)
+
+#define BIG_SUR_GE_IS_FULL(fifo)  			\
+	(BIG_SUR_GE_READ(fifo->reg_base_addr + 		\
+	BIG_SUR_GE_COUNT_STATUS_REG_OFFSET) &   	\
+	BIG_SUR_GE_EMPTY_FULL_MASK)
+
+#define	BIG_SUR_GE_IS_DEADLOCKED(fifo)			\
+	(BIG_SUR_GE_READ((fifo)->reg_base_addr + 	\
+	BIG_SUR_GE_COUNT_STATUS_REG_OFFSET) &   	\
+	BIG_SUR_GE_DEADLOCK_MASK)
+
+/* Device Config */
+typedef struct _big_sur_ge_config {
+	u16 device_id;
+	u32 base_address;
+	u32 has_counters;
+	u32 has_sg_dma;
+	u8 dma_config;
+	u32 has_mii;
+} big_sur_ge_config;
+
+/* Send and Receive DMA channel */
+typedef struct _xdma_channel_tag {
+	u32 reg_base_address;
+        u32 base_address;
+        u32 ready;
+} xdma_channel;
+
+/* Send and Receive Packet FIFO */
+typedef struct _packet_fifo {
+        u32 reg_base_addr;
+        u32 ready_status;
+        u32 data_base_address;
+} packet_fifo;
+
+/* Big Sur GE driver structure */
+typedef struct _big_sur_ge {
+	u32 base_address;
+	u32 started;
+	u32 ready;
+	u32 polled;
+	u32 dma_sg;
+	u8 dma_config;
+	u32 has_mii;
+	u32 has_mcast_hash_table;
+	/* For the FIFO and simple DMA case only */
+	packet_fifo recv_fifo;
+	packet_fifo send_fifo;
+	xdma_channel	recv_channel;
+	xdma_channel	send_channel;
+
+	u8 has_dma;
+} big_sur_ge;
+
+/* Offset of the MAC registers from the IPIF base address */
+#define BIG_SUR_GE_REG_OFFSET     0x1100UL
+
+/*
+ * Register offsets for the Ethernet MAC. Each register is 32 bits.
+ */
+#define BIG_SUR_GE_EMIR_OFFSET   (BIG_SUR_GE_REG_OFFSET + 0x0) /* EMAC Module ID */
+#define BIG_SUR_GE_ECR_OFFSET    (BIG_SUR_GE_REG_OFFSET + 0x4) /* MAC Control */
+#define BIG_SUR_GE_IFGP_OFFSET   (BIG_SUR_GE_REG_OFFSET + 0x8) /* Interframe Gap */
+#define BIG_SUR_GE_SAH_OFFSET    (BIG_SUR_GE_REG_OFFSET + 0xC) /* Station addr, high */
+#define BIG_SUR_GE_SAL_OFFSET    (BIG_SUR_GE_REG_OFFSET + 0x10)/* Station addr, low */
+#define BIG_SUR_GE_MGTCR_OFFSET  (BIG_SUR_GE_REG_OFFSET + 0x14)/* MII mgmt control */
+#define BIG_SUR_GE_MGTDR_OFFSET  (BIG_SUR_GE_REG_OFFSET + 0x18)/* MII mgmt data */
+#define BIG_SUR_GE_RPLR_OFFSET   (BIG_SUR_GE_REG_OFFSET + 0x1C)/* Rx packet length */
+#define BIG_SUR_GE_TPLR_OFFSET   (BIG_SUR_GE_REG_OFFSET + 0x20)/* Tx packet length */
+#define BIG_SUR_GE_TSR_OFFSET    (BIG_SUR_GE_REG_OFFSET + 0x24)/* Tx status */
+#define BIG_SUR_GE_RMFC_OFFSET   (BIG_SUR_GE_REG_OFFSET + 0x28)/* Rx missed frames */
+#define BIG_SUR_GE_RCC_OFFSET    (BIG_SUR_GE_REG_OFFSET + 0x2C)/* Rx collisions */
+#define BIG_SUR_GE_RFCSEC_OFFSET (BIG_SUR_GE_REG_OFFSET + 0x30)/* Rx FCS errors */
+#define BIG_SUR_GE_RAEC_OFFSET   (BIG_SUR_GE_REG_OFFSET + 0x34)/* Rx alignment errors */
+
+/* Transmit excess deferral cnt */
+#define BIG_SUR_GE_TEDC_OFFSET   (BIG_SUR_GE_REG_OFFSET + 0x38)
+
+/* Interrupt Status Register */
+#define BIG_SUR_GE_ISR_OFFSET           0x20UL 
+
+/* Send and Receive DMA Channel */
+#define BIG_SUR_GE_DMA_OFFSET           0x2300UL
+#define BIG_SUR_GE_DMA_SEND_OFFSET      (BIG_SUR_GE_DMA_OFFSET + 0x0) 
+#define BIG_SUR_GE_DMA_RECV_OFFSET      (BIG_SUR_GE_DMA_OFFSET + 0x40)
+
+/* Packet FIFO */
+#define BIG_SUR_GE_PFIFO_OFFSET         0x2000UL
+#define BIG_SUR_GE_PFIFO_TXREG_OFFSET   (BIG_SUR_GE_PFIFO_OFFSET + 0x0) 
+#define BIG_SUR_GE_PFIFO_RXREG_OFFSET   (BIG_SUR_GE_PFIFO_OFFSET + 0x10)
+#define BIG_SUR_GE_PFIFO_TXDATA_OFFSET  (BIG_SUR_GE_PFIFO_OFFSET + 0x100) 
+#define BIG_SUR_GE_PFIFO_RXDATA_OFFSET  (BIG_SUR_GE_PFIFO_OFFSET + 0x200)
+
+/*
+ * EMAC Module Identification Register (EMIR)
+ */
+#define BIG_SUR_GE_EMIR_VERSION_MASK    0xFFFF0000UL   /* Device version */
+#define BIG_SUR_GE_EMIR_TYPE_MASK       0x0000FF00UL   /* Device type */
+
+/*
+ * EMAC Control Register (ECR)
+ */
+#define BIG_SUR_GE_ECR_FULL_DUPLEX_MASK         0x80000000   /* Full duplex mode */
+#define BIG_SUR_GE_ECR_XMIT_RESET_MASK          0x40000000   /* Reset transmitter */
+#define BIG_SUR_GE_ECR_XMIT_ENABLE_MASK         0x20000000   /* Enable transmitter */
+#define BIG_SUR_GE_ECR_RECV_RESET_MASK          0x10000000   /* Reset receiver */
+#define BIG_SUR_GE_ECR_RECV_ENABLE_MASK         0x08000000   /* Enable receiver */
+#define BIG_SUR_GE_ECR_PHY_ENABLE_MASK          0x04000000   /* Enable PHY */
+#define BIG_SUR_GE_ECR_XMIT_PAD_ENABLE_MASK     0x02000000   /* Enable xmit pad insert */
+#define BIG_SUR_GE_ECR_XMIT_FCS_ENABLE_MASK     0x01000000   /* Enable xmit FCS insert */
+#define BIG_SUR_GE_ECR_XMIT_ADDR_INSERT_MASK    0x00800000   /* Enable xmit source addr insertion */
+#define BIG_SUR_GE_ECR_XMIT_ERROR_INSERT_MASK   0x00400000   /* Insert xmit error */
+#define BIG_SUR_GE_ECR_XMIT_ADDR_OVWRT_MASK     0x00200000   /* Enable xmit source addr overwrite */
+#define BIG_SUR_GE_ECR_LOOPBACK_MASK            0x00100000   /* Enable internal loopback */
+#define BIG_SUR_GE_ECR_RECV_PAD_ENABLE_MASK     0x00080000   /* Enable recv pad strip */
+#define BIG_SUR_GE_ECR_RECV_FCS_ENABLE_MASK     0x00040000   /* Enable recv FCS strip */
+#define BIG_SUR_GE_ECR_RECV_STRIP_ENABLE_MASK   0x00080000   /* Enable recv pad/fcs strip */
+#define BIG_SUR_GE_ECR_UNICAST_ENABLE_MASK      0x00020000   /* Enable unicast addr */
+#define BIG_SUR_GE_ECR_MULTI_ENABLE_MASK        0x00010000   /* Enable multicast addr */
+#define BIG_SUR_GE_ECR_BROAD_ENABLE_MASK        0x00008000   /* Enable broadcast addr */
+#define BIG_SUR_GE_ECR_PROMISC_ENABLE_MASK      0x00004000   /* Enable promiscuous mode */
+#define BIG_SUR_GE_ECR_RECV_ALL_MASK            0x00002000   /* Receive all frames */
+#define BIG_SUR_GE_ECR_RESERVED2_MASK           0x00001000   /* Reserved */
+#define BIG_SUR_GE_ECR_MULTI_HASH_ENABLE_MASK   0x00000800   /* Enable multicast hash */
+#define BIG_SUR_GE_ECR_PAUSE_FRAME_MASK         0x00000400   /* Interpret pause frames */
+#define BIG_SUR_GE_ECR_CLEAR_HASH_MASK          0x00000200   /* Clear hash table */
+#define BIG_SUR_GE_ECR_ADD_HASH_ADDR_MASK       0x00000100  /* Add hash table address */
+
+/*
+ * Interframe Gap Register (IFGR)
+ */
+#define BIG_SUR_GE_IFGP_PART1_MASK         0xF8000000        /* Interframe Gap Part1 */
+#define BIG_SUR_GE_IFGP_PART1_SHIFT        27
+#define BIG_SUR_GE_IFGP_PART2_MASK         0x07C00000        /* Interframe Gap Part2 */
+#define BIG_SUR_GE_IFGP_PART2_SHIFT        22
+
+/*
+ * Station Address High Register (SAH)
+ */
+#define BIG_SUR_GE_SAH_ADDR_MASK           0x0000FFFF        /* Station address high bytes */
+
+/*
+ * Station Address Low Register (SAL)
+ */
+#define BIG_SUR_GE_SAL_ADDR_MASK           0xFFFFFFFF        /* Station address low bytes */
+
+/*
+ * MII Management Control Register (MGTCR)
+ */
+#define BIG_SUR_GE_MGTCR_START_MASK        0x80000000        /* Start/Busy */
+#define BIG_SUR_GE_MGTCR_RW_NOT_MASK       0x40000000        /* Read/Write Not (direction) */
+#define BIG_SUR_GE_MGTCR_PHY_ADDR_MASK     0x3E000000        /* PHY address */
+#define BIG_SUR_GE_MGTCR_PHY_ADDR_SHIFT    25  /* PHY address shift */
+#define BIG_SUR_GE_MGTCR_REG_ADDR_MASK     0x01F00000        /* Register address */
+#define BIG_SUR_GE_MGTCR_REG_ADDR_SHIFT    20  /* Register addr shift */
+#define BIG_SUR_GE_MGTCR_MII_ENABLE_MASK   0x00080000        /* Enable MII from EMAC */
+#define BIG_SUR_GE_MGTCR_RD_ERROR_MASK     0x00040000        /* MII mgmt read error */
+
+/*
+ * MII Management Data Register (MGTDR)
+ */
+#define BIG_SUR_GE_MGTDR_DATA_MASK         0x0000FFFF        /* MII data */
+
+/*
+ * Receive Packet Length Register (RPLR)
+ */
+#define BIG_SUR_GE_RPLR_LENGTH_MASK        0x0000FFFF        /* Receive packet length */
+
+/*
+ * Transmit Packet Length Register (TPLR)
+ */
+#define BIG_SUR_GE_TPLR_LENGTH_MASK        0x0000FFFF       /* Transmit packet length */
+
+/*
+ * Transmit Status Register (TSR)
+ */
+#define BIG_SUR_GE_TSR_EXCESS_DEFERRAL_MASK 0x80000000       /* Transmit excess deferral */
+#define BIG_SUR_GE_TSR_FIFO_UNDERRUN_MASK   0x40000000       /* Packet FIFO underrun */
+#define BIG_SUR_GE_TSR_ATTEMPTS_MASK        0x3E000000      /* Transmission attempts */
+#define BIG_SUR_GE_TSR_LATE_COLLISION_MASK  0x01000000      /* Transmit late collision */
+
+/* Receive Missed Frame Count (RMFC) */
+#define BIG_SUR_GE_RMFC_DATA_MASK          0x0000FFFF
+
+/* Receive Collision Count (RCC) */
+#define BIG_SUR_GE_RCC_DATA_MASK           0x0000FFFF
+
+/* Receive FCS Error Count (RFCSEC) */
+#define BIG_SUR_GE_RFCSEC_DATA_MASK        0x0000FFFF
+
+/* Receive Alignment Error Count (RALN) */
+#define BIG_SUR_GE_RAEC_DATA_MASK          0x0000FFFF
+
+/* Transmit Excess Deferral Count (TEDC) */
+#define BIG_SUR_GE_TEDC_DATA_MASK          0x0000FFFF
+
+/*
+ * EMAC Interrupt Registers (Status and Enable) masks. These registers are
+ * part of the IPIF IP Interrupt registers
+ */
+#define BIG_SUR_GE_EIR_XMIT_DONE_MASK         0x00000001     /* Xmit complete */
+#define BIG_SUR_GE_EIR_RECV_DONE_MASK         0x00000002     /* Recv complete */
+#define BIG_SUR_GE_EIR_XMIT_ERROR_MASK        0x00000004     /* Xmit error */
+#define BIG_SUR_GE_EIR_RECV_ERROR_MASK        0x00000008     /* Recv error */
+#define BIG_SUR_GE_EIR_XMIT_SFIFO_EMPTY_MASK  0x00000010     /* Xmit status fifo empty */
+#define BIG_SUR_GE_EIR_RECV_LFIFO_EMPTY_MASK  0x00000020     /* Recv length fifo empty */
+#define BIG_SUR_GE_EIR_XMIT_LFIFO_FULL_MASK   0x00000040     /* Xmit length fifo full */
+#define BIG_SUR_GE_EIR_RECV_LFIFO_OVER_MASK   0x00000080     /* Recv length fifo overrun */
+#define BIG_SUR_GE_EIR_RECV_LFIFO_UNDER_MASK  0x00000100     /* Recv length fifo underrun */
+#define BIG_SUR_GE_EIR_XMIT_SFIFO_OVER_MASK   0x00000200     /* Xmit status fifo overrun */
+#define BIG_SUR_GE_EIR_XMIT_SFIFO_UNDER_MASK  0x00000400     /* Transmit status fifo underrun */
+#define BIG_SUR_GE_EIR_XMIT_LFIFO_OVER_MASK   0x00000800     /* Transmit length fifo overrun */
+#define BIG_SUR_GE_EIR_XMIT_LFIFO_UNDER_MASK  0x00001000     /* Transmit length fifo underrun */
+#define BIG_SUR_GE_EIR_XMIT_PAUSE_MASK        0x00002000     /* Transmit pause pkt received */
+#define BIG_SUR_GE_EIR_RECV_DFIFO_OVER_MASK   0x00004000     /* Receive data fifo overrun */
+#define BIG_SUR_GE_EIR_RECV_MISSED_FRAME_MASK 0x00008000     /* Receive missed frame error */
+#define BIG_SUR_GE_EIR_RECV_COLLISION_MASK    0x00010000     /* Receive collision error */
+#define BIG_SUR_GE_EIR_RECV_FCS_ERROR_MASK    0x00020000     /* Receive FCS error */
+#define BIG_SUR_GE_EIR_RECV_LEN_ERROR_MASK    0x00040000     /* Receive length field error */
+#define BIG_SUR_GE_EIR_RECV_SHORT_ERROR_MASK  0x00080000     /* Receive short frame error */
+#define BIG_SUR_GE_EIR_RECV_LONG_ERROR_MASK   0x00100000     /* Receive long frame error */
+#define BIG_SUR_GE_EIR_RECV_ALIGN_ERROR_MASK  0x00200000     /* Receive alignment error */
+
+/* Enable the MAC unit */
+#define	big_sur_ge_mac_enable(base_address)			\
+{								\
+	u32	control;					\
+	control = BIG_SUR_GE_READ(base_address + 		\
+				BIG_SUR_GE_ECR_OFFSET);		\
+	control &= ~(BIG_SUR_GE_ECR_XMIT_RESET_MASK | 		\
+			BIG_SUR_GE_ECR_RECV_RESET_MASK);	\
+	control |= (BIG_SUR_GE_ECR_XMIT_ENABLE_MASK | 		\
+			BIG_SUR_GE_ECR_RECV_ENABLE_MASK);	\
+	BIG_SUR_GE_WRITE(base_address + BIG_SUR_GE_ECR_OFFSET, control);	\
+}
+
+/* Disable the MAC unit */
+#define	big_sur_ge_mac_disable(base_address)			\
+{								\
+	u32	control;					\
+	control = BIG_SUR_GE_READ(base_address + 		\
+				BIG_SUR_GE_ECR_OFFSET);		\
+	control &= ~(BIG_SUR_GE_ECR_XMIT_ENABLE_MASK | 		\
+			BIG_SUR_GE_ECR_RECV_ENABLE_MASK);	\
+	BIG_SUR_GE_WRITE(base_address + BIG_SUR_GE_ECR_OFFSET, control);	\
+}
+
+/* Check if the Tx is done */
+#define	big_sur_ge_tx_done(base_address)			\
+	(BIG_SUR_GE_READ(base_address + BIG_SUR_GE_ISR_OFFSET)	\
+			& BIG_SUR_GE_EIR_XMIT_DONE_MASK)
+
+
+/* Check if Rx FIFO is empty */
+#define	big_sur_ge_rx_empty(base_address)			\
+	(!(BIG_SUR_GE_READ(base_address + BIG_SUR_GE_ISR_OFFSET) \
+			& BIG_SUR_GE_EIR_RECV_DONE_MASK))
+
+/* Reset the MAC PHY */
+#define	big_sur_ge_reset_phy(base_address)				\
+{									\
+	u32 control;							\
+	control = BIG_SUR_GE_READ(base_address + BIG_SUR_GE_ECR_OFFSET);	\
+	control &= ~(BIG_SUR_GE_ECR_PHY_ENABLE_MASK);				\
+	BIG_SUR_GE_WRITE(base_address + BIG_SUR_GE_ECR_OFFSET, control);	\
+	control |= BIG_SUR_GE_ECR_PHY_ENABLE_MASK;				\
+	BIG_SUR_GE_WRITE(base_address + BIG_SUR_GE_ECR_OFFSET, control);	\
+}
+
+#define BIG_SUR_GE_RST_REG_OFFSET	0  /* reset register */
+#define BIG_SUR_GE_MI_REG_OFFSET	0  /* module information register */
+#define BIG_SUR_GE_DMAC_REG_OFFSET	4  /* DMA control register */
+#define BIG_SUR_GE_SA_REG_OFFSET	8  /* source address register */
+#define BIG_SUR_GE_DA_REG_OFFSET	12 /* destination address register */
+#define BIG_SUR_GE_LEN_REG_OFFSET	16 /* length register */
+#define BIG_SUR_GE_DMAS_REG_OFFSET	20 /* DMA status register */
+#define BIG_SUR_GE_BDA_REG_OFFSET	24 /* buffer descriptor address register */
+#define BIG_SUR_GE_SWCR_REG_OFFSET	28 /* software control register */
+#define BIG_SUR_GE_UPC_REG_OFFSET	32 /* unserviced packet count register */
+#define BIG_SUR_GE_PCT_REG_OFFSET	36 /* packet count threshold register */
+#define BIG_SUR_GE_PWB_REG_OFFSET	40 /* packet wait bound register */
+#define BIG_SUR_GE_IS_REG_OFFSET	44 /* interrupt status register */
+#define BIG_SUR_GE_IE_REG_OFFSET	48 /* interrupt enable register */
+
+#define BIG_SUR_GE_RESET_MASK		0x0000000A
+
+/* Simple DMA register support */
+#define BIG_SUR_GE_DMACR_SOURCE_INCR_MASK	0x80000000UL  /* increment source address */
+#define BIG_SUR_GE_DMACR_DEST_INCR_MASK		0x40000000UL  /* increment dest address */
+#define BIG_SUR_GE_DMACR_SOURCE_LOCAL_MASK	0x20000000UL  /* local source address */
+#define BIG_SUR_GE_DMACR_DEST_LOCAL_MASK	0x10000000UL  /* local dest address */
+#define BIG_SUR_GE_DMACR_SG_DISABLE_MASK	0x08000000UL   /* scatter gather disable */
+#define BIG_SUR_GE_DMASR_BUSY_MASK		0x80000000UL  /* channel is busy */
+#define BIG_SUR_GE_DMASR_BUS_ERROR_MASK		0x40000000UL   /* bus error occurred */
+#define BIG_SUR_GE_DMASR_BUS_TIMEOUT_MASK	0x20000000UL   /* bus timeout occurred */
+
+/* Interrupts */
+#define BIG_SUR_GE_IPIF_EMAC_MASK      0x00000004UL    /* MAC interrupt */
+#define BIG_SUR_GE_IPIF_SEND_DMA_MASK  0x00000008UL    /* Send DMA interrupt */
+#define BIG_SUR_GE_IPIF_RECV_DMA_MASK  0x00000010UL    /* Receive DMA interrupt */
+#define BIG_SUR_GE_IPIF_RECV_FIFO_MASK 0x00000020UL    /* Receive FIFO interrupt */
+#define BIG_SUR_GE_IPIF_SEND_FIFO_MASK 0x00000040UL    /* Send FIFO interrupt */
+
+#define BIG_SUR_GE_IPIF_FIFO_DFT_MASK  (BIG_SUR_GE_IPIF_EMAC_MASK |	\
+                                 BIG_SUR_GE_IPIF_SEND_FIFO_MASK |	\
+                                 BIG_SUR_GE_IPIF_RECV_FIFO_MASK)
+
+#define BIG_SUR_GE_IPIF_DMA_DEV_INTR_COUNT   7 /* Number of interrupt sources */
+#define BIG_SUR_GE_IPIF_FIFO_DEV_INTR_COUNT  5 /* Number of interrupt sources */
+#define BIG_SUR_GE_IPIF_DEVICE_INTR_COUNT  7   /* Number of interrupt sources */
+#define BIG_SUR_GE_IPIF_IP_INTR_COUNT      22  /* Number of MAC interrupts */
+
+/* A default interrupt mask for non-DMA operation (direct FIFOs) */
+#define BIG_SUR_GE_EIR_DFT_FIFO_MASK  (BIG_SUR_GE_EIR_XMIT_DONE_MASK |	\
+                                BIG_SUR_GE_EIR_RECV_DONE_MASK)
+
+#endif
diff -urN linux-2.4.28-bk7/drivers/net/declance.c linux-2.4.29/drivers/net/declance.c
--- linux-2.4.28-bk7/drivers/net/declance.c	2004-02-18 05:36:31.000000000 -0800
+++ linux-2.4.29/drivers/net/declance.c	2005-01-19 07:08:09.164469278 -0800
@@ -1205,9 +1205,6 @@
 		}
 	}
 
-	lp->next = root_lance_dev;
-	root_lance_dev = dev;
-
 	/* Copy the ethernet address to the device structure, later to the
 	 * lance initialization block so the lance gets it every time it's
 	 * (re)initialized.
@@ -1264,11 +1261,14 @@
 		goto err_out_free_dev;
 	}
 
+	lp->next = root_lance_dev;
+	root_lance_dev = dev;
+
 	printk("%s: registered as %s.\n", name, dev->name);
 	return 0;
 
 err_out_free_dev:
-	kfree(dev);
+	free_netdev(dev);
 
 err_out:
 	return ret;
@@ -1315,13 +1315,13 @@
 		struct net_device *dev = root_lance_dev;
 		struct lance_private *lp = (struct lance_private *)dev->priv;
 
+		unregister_netdev(dev);
 #ifdef CONFIG_TC
 		if (lp->slot >= 0)
 			release_tc_card(lp->slot);
 #endif
 		root_lance_dev = lp->next;
-		unregister_netdev(dev);
-		kfree(dev);
+		free_netdev(dev);
 	}
 }
 
diff -urN linux-2.4.28-bk7/drivers/net/e1000/e1000.h linux-2.4.29/drivers/net/e1000/e1000.h
--- linux-2.4.28-bk7/drivers/net/e1000/e1000.h	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/drivers/net/e1000/e1000.h	2005-01-19 07:08:09.168469451 -0800
@@ -86,7 +86,7 @@
 
 #include "e1000_hw.h"
 
-#if DBG
+#ifdef DBG
 #define E1000_DBG(args...) printk(KERN_DEBUG "e1000: " args)
 #else
 #define E1000_DBG(args...)
@@ -204,7 +204,7 @@
 	spinlock_t stats_lock;
 	atomic_t irq_sem;
 	struct tq_struct tx_timeout_task;
-     	uint8_t fc_autoneg;
+	uint8_t fc_autoneg;
 
 	struct timer_list blink_timer;
 	unsigned long led_status;
diff -urN linux-2.4.28-bk7/drivers/net/e1000/e1000_ethtool.c linux-2.4.29/drivers/net/e1000/e1000_ethtool.c
--- linux-2.4.28-bk7/drivers/net/e1000/e1000_ethtool.c	2005-01-19 07:07:42.025293853 -0800
+++ linux-2.4.29/drivers/net/e1000/e1000_ethtool.c	2005-01-19 07:08:09.170469538 -0800
@@ -776,7 +776,7 @@
 e1000_intr_test(struct e1000_adapter *adapter, uint64_t *data)
 {
 	struct net_device *netdev = adapter->netdev;
- 	uint32_t icr, mask, i=0, shared_int = TRUE;
+ 	uint32_t mask, i=0, shared_int = TRUE;
  	uint32_t irq = adapter->pdev->irq;
 
 	*data = 0;
@@ -784,7 +784,8 @@
 	/* Hook up test interrupt handler just for this test */
  	if(!request_irq(irq, &e1000_test_intr, 0, netdev->name, netdev)) {
  		shared_int = FALSE;
- 	} else if(request_irq(irq, &e1000_test_intr, SA_SHIRQ, netdev->name, netdev)){
+ 	} else if(request_irq(irq, &e1000_test_intr, SA_SHIRQ, 
+			netdev->name, netdev)){
 		*data = 1;
 		return -1;
 	}
@@ -793,21 +794,6 @@
 	E1000_WRITE_REG(&adapter->hw, IMC, 0xFFFFFFFF);
 	msec_delay(10);
 
-	/* Interrupts are disabled, so read interrupt cause
-	 * register (icr) twice to verify that there are no interrupts
-	 * pending.  icr is clear on read.
-	 */
-	icr = E1000_READ_REG(&adapter->hw, ICR);
-	icr = E1000_READ_REG(&adapter->hw, ICR);
-
-	if(icr != 0) {
-		/* if icr is non-zero, there is no point
-		 * running other interrupt tests.
-		 */
-		*data = 2;
-		i = 10;
-	}
-
 	/* Test each interrupt */
 	for(; i < 10; i++) {
 
@@ -856,8 +842,10 @@
 			 * test failed.
 			 */
 			adapter->test_icr = 0;
-			E1000_WRITE_REG(&adapter->hw, IMC, ~mask);
-			E1000_WRITE_REG(&adapter->hw, ICS, ~mask);
+			E1000_WRITE_REG(&adapter->hw, IMC, 
+					(~mask & 0x00007FFF));
+			E1000_WRITE_REG(&adapter->hw, ICS, 
+					(~mask & 0x00007FFF));
 			msec_delay(10);
 
 			if(adapter->test_icr) {
@@ -1335,10 +1323,17 @@
 
 	msec_delay(200);
 
-	pci_dma_sync_single(pdev, rxdr->buffer_info[0].dma,
-			    rxdr->buffer_info[0].length, PCI_DMA_FROMDEVICE);
+	i = 0;
+	do {
+		pci_dma_sync_single(pdev, rxdr->buffer_info[i].dma,
+					    rxdr->buffer_info[i].length,
+					    PCI_DMA_FROMDEVICE);
+
+		if (!e1000_check_lbtest_frame(rxdr->buffer_info[i++].skb, 1024))
+			return 0;
+	} while (i < 64);
 
-	return e1000_check_lbtest_frame(rxdr->buffer_info[0].skb, 1024);
+	return 13;
 }
 
 static int
@@ -1357,10 +1352,27 @@
 e1000_link_test(struct e1000_adapter *adapter, uint64_t *data)
 {
 	*data = 0;
-	e1000_check_for_link(&adapter->hw);
 
-	if(!(E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU)) {
-		*data = 1;
+	if (adapter->hw.media_type == e1000_media_type_internal_serdes) {
+		int i = 0;
+		adapter->hw.serdes_link_down = TRUE;
+
+		/* on some blade server designs link establishment */
+		/* could take as long as 2-3 minutes.              */
+		do {
+			e1000_check_for_link(&adapter->hw);
+			if (adapter->hw.serdes_link_down == FALSE)
+				return *data;
+			msec_delay(20);
+		} while (i++ < 3750);
+
+		*data = 1; 
+	} else {
+		e1000_check_for_link(&adapter->hw);
+
+		if(!(E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU)) {
+			*data = 1;
+		}
 	}
 	return *data;
 }
@@ -1489,6 +1501,8 @@
 	case E1000_DEV_ID_82543GC_COPPER:
 	case E1000_DEV_ID_82544EI_FIBER:
 	case E1000_DEV_ID_82546EB_QUAD_COPPER:
+	case E1000_DEV_ID_82545EM_FIBER:
+	case E1000_DEV_ID_82545EM_COPPER:
 		return wol->wolopts ? -EOPNOTSUPP : 0;
 
 	case E1000_DEV_ID_82546EB_FIBER:
diff -urN linux-2.4.28-bk7/drivers/net/e1000/e1000_hw.c linux-2.4.29/drivers/net/e1000/e1000_hw.c
--- linux-2.4.28-bk7/drivers/net/e1000/e1000_hw.c	2005-01-19 07:07:42.029294026 -0800
+++ linux-2.4.29/drivers/net/e1000/e1000_hw.c	2005-01-19 07:08:09.175469754 -0800
@@ -123,17 +123,31 @@
 static void
 e1000_phy_init_script(struct e1000_hw *hw)
 {
+    uint32_t ret_val;
+    uint16_t phy_saved_data;
+
     DEBUGFUNC("e1000_phy_init_script");
 
-    
+
     if(hw->phy_init_script) {
         msec_delay(20);
 
+        /* Save off the current value of register 0x2F5B to be restored at
+         * the end of this routine. */
+        ret_val = e1000_read_phy_reg(hw, 0x2F5B, &phy_saved_data);
+
+        /* Disabled the PHY transmitter */
+        e1000_write_phy_reg(hw, 0x2F5B, 0x0003);
+
+        msec_delay(20);
+
         e1000_write_phy_reg(hw,0x0000,0x0140);
 
         msec_delay(5);
 
-        if(hw->mac_type == e1000_82541 || hw->mac_type == e1000_82547) {
+        switch(hw->mac_type) {
+        case e1000_82541:
+        case e1000_82547:
             e1000_write_phy_reg(hw, 0x1F95, 0x0001);
 
             e1000_write_phy_reg(hw, 0x1F71, 0xBD21);
@@ -151,12 +165,23 @@
             e1000_write_phy_reg(hw, 0x1F96, 0x003F);
 
             e1000_write_phy_reg(hw, 0x2010, 0x0008);
-        } else {
+            break;
+
+        case e1000_82541_rev_2:
+        case e1000_82547_rev_2:
             e1000_write_phy_reg(hw, 0x1F73, 0x0099);
+            break;
+        default:
+            break;
         }
 
         e1000_write_phy_reg(hw, 0x0000, 0x3300);
 
+        msec_delay(20);
+
+        /* Now enable the transmitter */
+        e1000_write_phy_reg(hw, 0x2F5B, phy_saved_data);
+
         if(hw->mac_type == e1000_82547) {
             uint16_t fused, fine, coarse;
 
@@ -245,6 +270,7 @@
     case E1000_DEV_ID_82546GB_COPPER:
     case E1000_DEV_ID_82546GB_FIBER:
     case E1000_DEV_ID_82546GB_SERDES:
+    case E1000_DEV_ID_82546GB_PCIE:
         hw->mac_type = e1000_82546_rev_3;
         break;
     case E1000_DEV_ID_82541EI:
@@ -968,7 +994,7 @@
 
             if((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) {
                 hw->dsp_config_state = e1000_dsp_config_disabled;
-                /* Force MDI for IGP B-0 PHY */
+                /* Force MDI for earlier revs of the IGP PHY */
                 phy_data &= ~(IGP01E1000_PSCR_AUTO_MDIX |
                               IGP01E1000_PSCR_FORCE_MDI_MDIX);
                 hw->mdix = 1;
@@ -2113,7 +2139,7 @@
          * at gigabit speed, then TBI compatibility is not needed.  If we are
          * at gigabit speed, we turn on TBI compatibility.
          */
-	if(hw->tbi_compatibility_en) {
+        if(hw->tbi_compatibility_en) {
             uint16_t speed, duplex;
             e1000_get_speed_and_duplex(hw, &speed, &duplex);
             if(speed != SPEED_1000) {
@@ -2473,8 +2499,9 @@
        (reg_addr > MAX_PHY_MULTI_PAGE_REG)) {
         ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
                                          (uint16_t)reg_addr);
-        if(ret_val)
+        if(ret_val) {
             return ret_val;
+        }
     }
 
     ret_val = e1000_read_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT & reg_addr,
@@ -2578,8 +2605,9 @@
        (reg_addr > MAX_PHY_MULTI_PAGE_REG)) {
         ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
                                          (uint16_t)reg_addr);
-        if(ret_val)
+        if(ret_val) {
             return ret_val;
+        }
     }
 
     ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT & reg_addr,
@@ -3482,7 +3510,7 @@
     /* A check for invalid values:  offset too large, too many words, and not
      * enough words.
      */
-    if((offset > eeprom->word_size) || (words > eeprom->word_size - offset) ||
+    if((offset >= eeprom->word_size) || (words > eeprom->word_size - offset) ||
        (words == 0)) {
         DEBUGOUT("\"words\" parameter out of bounds\n");
         return -E1000_ERR_EEPROM;
@@ -3628,11 +3656,10 @@
 
     DEBUGFUNC("e1000_write_eeprom");
 
-
     /* A check for invalid values:  offset too large, too many words, and not
      * enough words.
      */
-    if((offset > eeprom->word_size) || (words > eeprom->word_size - offset) ||
+    if((offset >= eeprom->word_size) || (words > eeprom->word_size - offset) ||
        (words == 0)) {
         DEBUGOUT("\"words\" parameter out of bounds\n");
         return -E1000_ERR_EEPROM;
@@ -4924,7 +4951,7 @@
                                    boolean_t link_up)
 {
     int32_t ret_val;
-    uint16_t phy_data, speed, duplex, i;
+    uint16_t phy_data, phy_saved_data, speed, duplex, i;
     uint16_t dsp_reg_array[IGP01E1000_PHY_CHANNEL_NUM] =
                                         {IGP01E1000_PHY_AGC_PARAM_A,
                                         IGP01E1000_PHY_AGC_PARAM_B,
@@ -5005,6 +5032,21 @@
         }
     } else {
         if(hw->dsp_config_state == e1000_dsp_config_activated) {
+            /* Save off the current value of register 0x2F5B to be restored at
+             * the end of the routines. */
+            ret_val = e1000_read_phy_reg(hw, 0x2F5B, &phy_saved_data);
+
+            if(ret_val)
+                return ret_val;
+
+            /* Disable the PHY transmitter */
+            ret_val = e1000_write_phy_reg(hw, 0x2F5B, 0x0003);
+
+            if(ret_val)
+                return ret_val;
+
+            msec_delay(20);
+
             ret_val = e1000_write_phy_reg(hw, 0x0000,
                                           IGP01E1000_IEEE_FORCE_GIGA);
             if(ret_val)
@@ -5027,10 +5069,33 @@
             if(ret_val)
                 return ret_val;
 
+            msec_delay(20);
+
+            /* Now enable the transmitter */
+            ret_val = e1000_write_phy_reg(hw, 0x2F5B, phy_saved_data);
+
+            if(ret_val)
+                return ret_val;
+
             hw->dsp_config_state = e1000_dsp_config_enabled;
         }
 
         if(hw->ffe_config_state == e1000_ffe_config_active) {
+            /* Save off the current value of register 0x2F5B to be restored at
+             * the end of the routines. */
+            ret_val = e1000_read_phy_reg(hw, 0x2F5B, &phy_saved_data);
+
+            if(ret_val)
+                return ret_val;
+
+            /* Disable the PHY transmitter */
+            ret_val = e1000_write_phy_reg(hw, 0x2F5B, 0x0003);
+
+            if(ret_val)
+                return ret_val;
+
+            msec_delay(20);
+
             ret_val = e1000_write_phy_reg(hw, 0x0000,
                                           IGP01E1000_IEEE_FORCE_GIGA);
             if(ret_val)
@@ -5044,6 +5109,15 @@
                                           IGP01E1000_IEEE_RESTART_AUTONEG);
             if(ret_val)
                 return ret_val;
+
+            msec_delay(20);
+
+            /* Now enable the transmitter */
+            ret_val = e1000_write_phy_reg(hw, 0x2F5B, phy_saved_data);
+
+            if(ret_val)
+                return ret_val;
+
             hw->ffe_config_state = e1000_ffe_config_enabled;
         }
     }
@@ -5132,14 +5206,29 @@
          * Dx states where the power conservation is most important.  During
          * driver activity we should enable SmartSpeed, so performance is
          * maintained. */
-        ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, &phy_data);
-        if(ret_val)
-            return ret_val;
+        if (hw->smart_speed == e1000_smart_speed_on) {
+            ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+                                         &phy_data);
+            if(ret_val)
+                return ret_val;
 
-        phy_data |= IGP01E1000_PSCFR_SMART_SPEED;
-        ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, phy_data);
-        if(ret_val)
-            return ret_val;
+            phy_data |= IGP01E1000_PSCFR_SMART_SPEED;
+            ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+                                          phy_data);
+            if(ret_val)
+                return ret_val;
+        } else if (hw->smart_speed == e1000_smart_speed_off) {
+            ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+                                         &phy_data);
+	    if (ret_val)
+                return ret_val;
+
+            phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+            ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+                                          phy_data);
+            if(ret_val)
+                return ret_val;
+        }
 
     } else if((hw->autoneg_advertised == AUTONEG_ADVERTISE_SPEED_DEFAULT) ||
               (hw->autoneg_advertised == AUTONEG_ADVERTISE_10_ALL ) ||
diff -urN linux-2.4.28-bk7/drivers/net/e1000/e1000_hw.h linux-2.4.29/drivers/net/e1000/e1000_hw.h
--- linux-2.4.28-bk7/drivers/net/e1000/e1000_hw.h	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/drivers/net/e1000/e1000_hw.h	2005-01-19 07:08:09.177469841 -0800
@@ -169,6 +169,12 @@
 } e1000_downshift;
 
 typedef enum {
+    e1000_smart_speed_default = 0,
+    e1000_smart_speed_on,
+    e1000_smart_speed_off
+} e1000_smart_speed;
+
+typedef enum {
     e1000_polarity_reversal_enabled = 0,
     e1000_polarity_reversal_disabled,
     e1000_polarity_reversal_undefined = 0xFF
@@ -362,6 +368,7 @@
 #define E1000_DEV_ID_82546GB_COPPER      0x1079
 #define E1000_DEV_ID_82546GB_FIBER       0x107A
 #define E1000_DEV_ID_82546GB_SERDES      0x107B
+#define E1000_DEV_ID_82546GB_PCIE        0x108A
 #define E1000_DEV_ID_82547EI             0x1019
 #define NODE_ADDRESS_SIZE 6
 #define ETH_LENGTH_OF_ADDRESS 6
@@ -1027,6 +1034,7 @@
     uint8_t perm_mac_addr[NODE_ADDRESS_SIZE];
     boolean_t disable_polarity_correction;
     boolean_t speed_downgraded;
+    e1000_smart_speed smart_speed;
     e1000_dsp_config dsp_config_state;
     boolean_t get_link_status;
     boolean_t serdes_link_down;
diff -urN linux-2.4.28-bk7/drivers/net/e1000/e1000_main.c linux-2.4.29/drivers/net/e1000/e1000_main.c
--- linux-2.4.28-bk7/drivers/net/e1000/e1000_main.c	2005-01-19 07:07:42.031294112 -0800
+++ linux-2.4.29/drivers/net/e1000/e1000_main.c	2005-01-19 07:08:09.180469971 -0800
@@ -34,11 +34,15 @@
  * - if_mii support and associated kcompat for older kernels
  * - More errlogging support from Jon Mason <jonmason@us.ibm.com>
  * - Fix TSO issues on PPC64 machines -- Jon Mason <jonmason@us.ibm.com>
- *
- * 5.3.11	6/4/04
- * - ethtool register dump reads MANC register conditionally.
- *
- * 5.3.10	6/1/04
+ * 5.6.5 	11/01/04
+ * - Enabling NETIF_F_SG without checksum offload is illegal - 
+     John Mason <jdmason@us.ibm.com>
+ * 5.6.3        10/26/04
+ * - Remove redundant initialization - Jamal Hadi
+ * - Reset buffer_info->dma in tx resource cleanup logic
+ * 5.6.2	10/12/04
+ * - Sparse cleanup - shemminger@osdl.org
+ * - Fix tx resource cleanup logic
  */
 
 char e1000_driver_name[] = "e1000";
@@ -48,7 +52,7 @@
 #else
 #define DRIVERNAPI "-NAPI"
 #endif
-char e1000_driver_version[] = "5.5.4-k1"DRIVERNAPI;
+char e1000_driver_version[] = "5.6.10.1-k1"DRIVERNAPI;
 char e1000_copyright[] = "Copyright (c) 1999-2004 Intel Corporation.";
 
 /* e1000_pci_tbl - PCI Device ID Table
@@ -90,6 +94,7 @@
 	INTEL_E1000_ETHERNET_DEVICE(0x107A),
 	INTEL_E1000_ETHERNET_DEVICE(0x107B),
 	INTEL_E1000_ETHERNET_DEVICE(0x107C),
+	INTEL_E1000_ETHERNET_DEVICE(0x108A),
 	/* required last entry */
 	{0,}
 };
@@ -128,8 +133,6 @@
 static struct net_device_stats * e1000_get_stats(struct net_device *netdev);
 static int e1000_change_mtu(struct net_device *netdev, int new_mtu);
 static int e1000_set_mac(struct net_device *netdev, void *p);
-static void e1000_irq_disable(struct e1000_adapter *adapter);
-static void e1000_irq_enable(struct e1000_adapter *adapter);
 static irqreturn_t e1000_intr(int irq, void *data, struct pt_regs *regs);
 static boolean_t e1000_clean_tx_irq(struct e1000_adapter *adapter);
 #ifdef CONFIG_E1000_NAPI
@@ -146,9 +149,6 @@
 void set_ethtool_ops(struct net_device *netdev);
 static void e1000_enter_82542_rst(struct e1000_adapter *adapter);
 static void e1000_leave_82542_rst(struct e1000_adapter *adapter);
-static void e1000_rx_checksum(struct e1000_adapter *adapter,
-                              struct e1000_rx_desc *rx_desc,
-                              struct sk_buff *skb);
 static void e1000_tx_timeout(struct net_device *dev);
 static void e1000_tx_timeout_task(struct net_device *dev);
 static void e1000_smartspeed(struct e1000_adapter *adapter);
@@ -242,6 +242,33 @@
 
 module_exit(e1000_exit_module);
 
+/**
+ * e1000_irq_disable - Mask off interrupt generation on the NIC
+ * @adapter: board private structure
+ **/
+
+static inline void
+e1000_irq_disable(struct e1000_adapter *adapter)
+{
+	atomic_inc(&adapter->irq_sem);
+	E1000_WRITE_REG(&adapter->hw, IMC, ~0);
+	E1000_WRITE_FLUSH(&adapter->hw);
+	synchronize_irq();
+}
+
+/**
+ * e1000_irq_enable - Enable default interrupt generation settings
+ * @adapter: board private structure
+ **/
+
+static inline void
+e1000_irq_enable(struct e1000_adapter *adapter)
+{
+	if(likely(atomic_dec_and_test(&adapter->irq_sem))) {
+		E1000_WRITE_REG(&adapter->hw, IMS, IMS_ENABLE_MASK);
+		E1000_WRITE_FLUSH(&adapter->hw);
+	}
+}
 
 int
 e1000_up(struct e1000_adapter *adapter)
@@ -475,8 +502,6 @@
 				   NETIF_F_HW_VLAN_TX |
 				   NETIF_F_HW_VLAN_RX |
 				   NETIF_F_HW_VLAN_FILTER;
-	} else {
-		netdev->features = NETIF_F_SG;
 	}
 
 #ifdef NETIF_F_TSO
@@ -1056,6 +1081,24 @@
 	adapter->tx_ring.desc = NULL;
 }
 
+static inline void
+e1000_unmap_and_free_tx_resource(struct e1000_adapter *adapter,
+			struct e1000_buffer *buffer_info)
+{
+	struct pci_dev *pdev = adapter->pdev;
+	if(buffer_info->dma) {
+		pci_unmap_page(pdev,
+			       buffer_info->dma,
+			       buffer_info->length,
+			       PCI_DMA_TODEVICE);
+		buffer_info->dma = 0;
+	}
+	if(buffer_info->skb) {
+		dev_kfree_skb_any(buffer_info->skb);
+		buffer_info->skb = NULL;
+	}
+}
+
 /**
  * e1000_clean_tx_ring - Free Tx Buffers
  * @adapter: board private structure
@@ -1066,7 +1109,6 @@
 {
 	struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
 	struct e1000_buffer *buffer_info;
-	struct pci_dev *pdev = adapter->pdev;
 	unsigned long size;
 	unsigned int i;
 
@@ -1074,17 +1116,7 @@
 
 	for(i = 0; i < tx_ring->count; i++) {
 		buffer_info = &tx_ring->buffer_info[i];
-		if(buffer_info->skb) {
-
-			pci_unmap_page(pdev,
-				       buffer_info->dma,
-				       buffer_info->length,
-				       PCI_DMA_TODEVICE);
-
-			dev_kfree_skb(buffer_info->skb);
-
-			buffer_info->skb = NULL;
-		}
+		e1000_unmap_and_free_tx_resource(adapter, buffer_info);
 	}
 
 	size = sizeof(struct e1000_buffer) * tx_ring->count;
@@ -1262,9 +1294,12 @@
 	uint32_t rctl;
 	uint32_t hash_value;
 	int i;
+	unsigned long flags;
 
 	/* Check for Promiscuous and All Multicast modes */
 
+	spin_lock_irqsave(&adapter->tx_lock, flags);
+
 	rctl = E1000_READ_REG(hw, RCTL);
 
 	if(netdev->flags & IFF_PROMISC) {
@@ -1313,6 +1348,8 @@
 
 	if(hw->mac_type == e1000_82542_rev2_0)
 		e1000_leave_82542_rst(adapter);
+
+	spin_unlock_irqrestore(&adapter->tx_lock, flags);
 }
 
 /* Need to wait a few seconds after link up to get diagnostic information from
@@ -1752,7 +1789,6 @@
 	unsigned int mss = 0;
 	int count = 0;
 	unsigned int f;
-	nr_frags = skb_shinfo(skb)->nr_frags;
 	len -= skb->data_len;
 
 	if(unlikely(skb->len <= 0)) {
@@ -1796,22 +1832,22 @@
 
 	/* need: count + 2 desc gap to keep tail from touching
 	 * head, otherwise try next time */
-	if(E1000_DESC_UNUSED(&adapter->tx_ring) < count + 2) {
+	if(unlikely(E1000_DESC_UNUSED(&adapter->tx_ring) < count + 2)) {
 		netif_stop_queue(netdev);
 		spin_unlock_irqrestore(&adapter->tx_lock, flags);
 		return 1;
 	}
 
-	spin_unlock_irqrestore(&adapter->tx_lock, flags);
-
 	if(unlikely(adapter->hw.mac_type == e1000_82547)) {
 		if(unlikely(e1000_82547_fifo_workaround(adapter, skb))) {
 			netif_stop_queue(netdev);
 			mod_timer(&adapter->tx_fifo_stall_timer, jiffies);
 			return 1;
+			spin_unlock_irqrestore(&adapter->tx_lock, flags);
 		}
 	}
 
+	spin_unlock_irqrestore(&adapter->tx_lock, flags);
 	if(unlikely(adapter->vlgrp && vlan_tx_tag_present(skb))) {
 		tx_flags |= E1000_TX_FLAGS_VLAN;
 		tx_flags |= (vlan_tx_tag_get(skb) << E1000_TX_FLAGS_VLAN_SHIFT);
@@ -1889,9 +1925,9 @@
 	int max_frame = new_mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
 
 	if((max_frame < MINIMUM_ETHERNET_FRAME_SIZE) ||
-	   (max_frame > MAX_JUMBO_FRAME_SIZE)) {
-		DPRINTK(PROBE, ERR, "Invalid MTU setting\n");
-		return -EINVAL;
+		(max_frame > MAX_JUMBO_FRAME_SIZE)) {
+			DPRINTK(PROBE, ERR, "Invalid MTU setting\n");
+			return -EINVAL;
 	}
 
 	if(max_frame <= MAXIMUM_ETHERNET_FRAME_SIZE) {
@@ -2059,34 +2095,6 @@
 }
 
 /**
- * e1000_irq_disable - Mask off interrupt generation on the NIC
- * @adapter: board private structure
- **/
-
-static void
-e1000_irq_disable(struct e1000_adapter *adapter)
-{
-	atomic_inc(&adapter->irq_sem);
-	E1000_WRITE_REG(&adapter->hw, IMC, ~0);
-	E1000_WRITE_FLUSH(&adapter->hw);
-	synchronize_irq();
-}
-
-/**
- * e1000_irq_enable - Enable default interrupt generation settings
- * @adapter: board private structure
- **/
-
-static void
-e1000_irq_enable(struct e1000_adapter *adapter)
-{
-	if(likely(atomic_dec_and_test(&adapter->irq_sem))) {
-		E1000_WRITE_REG(&adapter->hw, IMS, IMS_ENABLE_MASK);
-		E1000_WRITE_FLUSH(&adapter->hw);
-	}
-}
-
-/**
  * e1000_intr - Interrupt Handler
  * @irq: interrupt number
  * @data: pointer to a network interface device structure
@@ -2147,6 +2155,9 @@
 	int tx_cleaned;
 	int work_done = 0;
 	
+	if (!netif_carrier_ok(netdev))
+		goto quit_polling;
+
 	tx_cleaned = e1000_clean_tx_irq(adapter);
 	e1000_clean_rx_irq(adapter, &work_done, work_to_do);
 
@@ -2156,7 +2167,7 @@
 	/* if no Rx and Tx cleanup work was done, exit the polling mode */
 	if(!tx_cleaned || (work_done < work_to_do) || 
 				!netif_running(netdev)) {
-		netif_rx_complete(netdev);
+quit_polling:	netif_rx_complete(netdev);
 		e1000_irq_enable(adapter);
 		return 0;
 	}
@@ -2175,7 +2186,6 @@
 {
 	struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
 	struct net_device *netdev = adapter->netdev;
-	struct pci_dev *pdev = adapter->pdev;
 	struct e1000_tx_desc *tx_desc, *eop_desc;
 	struct e1000_buffer *buffer_info;
 	unsigned int i, eop;
@@ -2190,20 +2200,7 @@
 			tx_desc = E1000_TX_DESC(*tx_ring, i);
 			buffer_info = &tx_ring->buffer_info[i];
 
-			if(likely(buffer_info->dma)) {
-				pci_unmap_page(pdev,
-					       buffer_info->dma,
-					       buffer_info->length,
-					       PCI_DMA_TODEVICE);
-
-				buffer_info->dma = 0;
-			}
-
-			if(buffer_info->skb) {
-				dev_kfree_skb_any(buffer_info->skb);
-				buffer_info->skb = NULL;
-			}
-
+			e1000_unmap_and_free_tx_resource(adapter, buffer_info);
 			tx_desc->buffer_addr = 0;
 			tx_desc->lower.data = 0;
 			tx_desc->upper.data = 0;
@@ -2230,6 +2227,41 @@
 }
 
 /**
+ * e1000_rx_checksum - Receive Checksum Offload for 82543
+ * @adapter: board private structure
+ * @rx_desc: receive descriptor
+ * @sk_buff: socket buffer with received data
+ **/
+
+static inline void
+e1000_rx_checksum(struct e1000_adapter *adapter,
+                  struct e1000_rx_desc *rx_desc,
+                  struct sk_buff *skb)
+{
+	/* 82543 or newer only */
+	if(unlikely((adapter->hw.mac_type < e1000_82543) ||
+	/* Ignore Checksum bit is set */
+	(rx_desc->status & E1000_RXD_STAT_IXSM) ||
+	/* TCP Checksum has not been calculated */
+	(!(rx_desc->status & E1000_RXD_STAT_TCPCS)))) {
+		skb->ip_summed = CHECKSUM_NONE;
+		return;
+	}
+
+	/* At this point we know the hardware did the TCP checksum */
+	/* now look at the TCP checksum error bit */
+	if(rx_desc->errors & E1000_RXD_ERR_TCPE) {
+		/* let the stack verify checksum errors */
+		skb->ip_summed = CHECKSUM_NONE;
+		adapter->hw_csum_err++;
+	} else {
+		/* TCP checksum is good */
+		skb->ip_summed = CHECKSUM_UNNECESSARY;
+		adapter->hw_csum_good++;
+	}
+}
+
+/**
  * e1000_clean_rx_irq - Send received data up the network stack
  * @adapter: board private structure
  **/
@@ -2277,7 +2309,7 @@
 		if(unlikely(!(rx_desc->status & E1000_RXD_STAT_EOP))) {
 			/* All receives must fit into a single buffer */
 			E1000_DBG("%s: Receive packet consumed multiple"
-				  " buffers\n", netdev->name);
+					" buffers\n", netdev->name);
 			dev_kfree_skb_irq(skb);
 			goto next_desc;
 		}
@@ -2575,41 +2607,6 @@
 	return E1000_SUCCESS;
 }
 
-/**
- * e1000_rx_checksum - Receive Checksum Offload for 82543
- * @adapter: board private structure
- * @rx_desc: receive descriptor
- * @sk_buff: socket buffer with received data
- **/
-
-static void
-e1000_rx_checksum(struct e1000_adapter *adapter,
-                  struct e1000_rx_desc *rx_desc,
-                  struct sk_buff *skb)
-{
-	/* 82543 or newer only */
-	if(unlikely((adapter->hw.mac_type < e1000_82543) ||
-	/* Ignore Checksum bit is set */
-	(rx_desc->status & E1000_RXD_STAT_IXSM) ||
-	/* TCP Checksum has not been calculated */
-	(!(rx_desc->status & E1000_RXD_STAT_TCPCS)))) {
-		skb->ip_summed = CHECKSUM_NONE;
-		return;
-	}
-
-	/* At this point we know the hardware did the TCP checksum */
-	/* now look at the TCP checksum error bit */
-	if(rx_desc->errors & E1000_RXD_ERR_TCPE) {
-		/* let the stack verify checksum errors */
-		skb->ip_summed = CHECKSUM_NONE;
-		adapter->hw_csum_err++;
-	} else {
-		/* TCP checksum is good */
-		skb->ip_summed = CHECKSUM_UNNECESSARY;
-		adapter->hw_csum_good++;
-	}
-}
-
 void
 e1000_pci_set_mwi(struct e1000_hw *hw)
 {
diff -urN linux-2.4.28-bk7/drivers/net/e1000/e1000_osdep.h linux-2.4.29/drivers/net/e1000/e1000_osdep.h
--- linux-2.4.28-bk7/drivers/net/e1000/e1000_osdep.h	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/drivers/net/e1000/e1000_osdep.h	2005-01-19 07:08:09.181470014 -0800
@@ -69,7 +69,7 @@
 
 #define MSGOUT(S, A, B)	printk(KERN_DEBUG S "\n", A, B)
 
-#if DBG
+#ifdef DBG
 #define DEBUGOUT(S)		printk(KERN_DEBUG S "\n")
 #define DEBUGOUT1(S, A...)	printk(KERN_DEBUG S "\n", A)
 #else
diff -urN linux-2.4.28-bk7/drivers/net/e1000/e1000_param.c linux-2.4.29/drivers/net/e1000/e1000_param.c
--- linux-2.4.28-bk7/drivers/net/e1000/e1000_param.c	2005-01-19 07:07:42.035294286 -0800
+++ linux-2.4.29/drivers/net/e1000/e1000_param.c	2005-01-19 07:08:09.181470014 -0800
@@ -447,9 +447,6 @@
 
 			adapter->itr = InterruptThrottleRate[bd];
 			switch(adapter->itr) {
-			case -1:
-				adapter->itr = 1;
-				break;
 			case 0:
 				DPRINTK(PROBE, INFO, "%s turned off\n", 
 					opt.name);
@@ -458,6 +455,7 @@
 				DPRINTK(PROBE, INFO, "%s set to dynamic mode\n", 
 					opt.name);
 				break;
+			case -1:
 			default:
 				e1000_validate_option(&adapter->itr, &opt, 
 					adapter);
diff -urN linux-2.4.28-bk7/drivers/net/eexpress.c linux-2.4.29/drivers/net/eexpress.c
--- linux-2.4.28-bk7/drivers/net/eexpress.c	2003-08-25 04:44:42.000000000 -0700
+++ linux-2.4.29/drivers/net/eexpress.c	2005-01-19 07:08:09.183470101 -0800
@@ -7,7 +7,7 @@
  * Support for 8-bit mode by Zoltan Szilagyi <zoltans@cs.arizona.edu>
  *
  * Many modifications, and currently maintained, by
- *  Philip Blundell <Philip.Blundell@pobox.com>
+ *  Philip Blundell <philb@gnu.org>
  * Added the Compaq LTE  Alan Cox <alan@redhat.com>
  * Added MCA support Adam Fritzler <mid@auk.cx>
  *
diff -urN linux-2.4.28-bk7/drivers/net/forcedeth.c linux-2.4.29/drivers/net/forcedeth.c
--- linux-2.4.28-bk7/drivers/net/forcedeth.c	2005-01-19 07:07:42.039294459 -0800
+++ linux-2.4.29/drivers/net/forcedeth.c	2005-01-19 07:08:09.190470404 -0800
@@ -575,12 +575,6 @@
 	return retval;
 }
 
-static void msleep(unsigned long msecs)
-{
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((HZ * msecs + 999) / 1000);
-}
-
 static int phy_reset(struct net_device *dev)
 {
 	struct fe_priv *np = get_nvpriv(dev);
diff -urN linux-2.4.28-bk7/drivers/net/gt64240eth.c linux-2.4.29/drivers/net/gt64240eth.c
--- linux-2.4.28-bk7/drivers/net/gt64240eth.c	2004-02-18 05:36:31.000000000 -0800
+++ linux-2.4.29/drivers/net/gt64240eth.c	2005-01-19 07:08:09.193470534 -0800
@@ -29,6 +29,9 @@
  *
  * Support for Rx NAPI, Rx checksum offload, IOCTL and ETHTOOL added
  * Manish Lachwani (lachwani@pmc-sierra.com) - 09/16/2003
+ *
+ * Modified for later version of Linux 2.4 kernel
+ * Manish Lachwani (lachwani@pmc-sierra.com) - 04/29/2004
  */
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -77,12 +80,20 @@
  *  > 3	lots of change-of-state messages.
  *  > 4	EXTENSIVE data/descriptor dumps.
  */
+
 #ifdef GT64240_DEBUG
 static int gt64240_debug = GT64240_DEBUG;
 #else
 static int gt64240_debug = 0;
 #endif
 
+static int debug = -1;
+
+#define GT64240_MSG_ENABLE	(NETIF_MSG_DRV          | \
+				NETIF_MSG_PROBE        | \
+				NETIF_MSG_LINK)
+
+
 /********************************************************/
 
 // prototypes
@@ -254,119 +265,84 @@
 	return (int) (smir & smirDataMask);
 }
 
-/* Ethtool support */
-static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+static void gp_get_drvinfo (struct net_device *dev, 
+				struct ethtool_drvinfo *info)
+{
+	strcpy(info->driver, "gt64260");
+	strcpy(info->version, version);
+}
+
+static int gp_get_settings(struct net_device *dev, 
+				struct ethtool_cmd *cmd)
 {
 	struct gt64240_private *gp = (struct gt64240_private *) dev->priv;
-	u32 ethcmd;
+	int rc;
 
-	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
-		return -EFAULT;
+	spin_lock_irq(&gp->lock);
+	rc = mii_ethtool_gset(&gp->mii_if, cmd);
+	spin_unlock_irq(&gp->lock);
+	return rc;
+}
 
-	switch (ethcmd) {
-
-		/* Get driver info */
-	case ETHTOOL_GDRVINFO:{
-			struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
-			strncpy(info.driver, "gt64260",
-				sizeof(info.driver) - 1);
-			strncpy(info.version, version,
-				sizeof(info.version) - 1);
-			if (copy_to_user(useraddr, &info, sizeof(info)))
-				return -EFAULT;
-			return 0;
-		}
-		/* get settings */
-	case ETHTOOL_GSET:{
-			struct ethtool_cmd ecmd = { ETHTOOL_GSET };
-			spin_lock_irq(&gp->lock);
-			mii_ethtool_gset(&gp->mii_if, &ecmd);
-			spin_unlock_irq(&gp->lock);
-			if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
-				return -EFAULT;
-			return 0;
-		}
-		/* set settings */
-	case ETHTOOL_SSET:{
-			int r;
-			struct ethtool_cmd ecmd;
-			if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
-				return -EFAULT;
-			spin_lock_irq(&gp->lock);
-			r = mii_ethtool_sset(&gp->mii_if, &ecmd);
-			spin_unlock_irq(&gp->lock);
-			return r;
-		}
-		/* restart autonegotiation */
-	case ETHTOOL_NWAY_RST:{
-			return mii_nway_restart(&gp->mii_if);
-		}
-		/* get link status */
-	case ETHTOOL_GLINK:{
-			struct ethtool_value edata = { ETHTOOL_GLINK };
-			edata.data = mii_link_ok(&gp->mii_if);
-			if (copy_to_user(useraddr, &edata, sizeof(edata)))
-				return -EFAULT;
-			return 0;
-		}
-		/* get message-level */
-	case ETHTOOL_GMSGLVL:{
-			struct ethtool_value edata = { ETHTOOL_GMSGLVL };
-			edata.data = 0;	/* XXX */
-			if (copy_to_user(useraddr, &edata, sizeof(edata)))
-				return -EFAULT;
-			return 0;
-		}
-		/* set message-level */
-	case ETHTOOL_SMSGLVL:{
-			struct ethtool_value edata;
-			if (copy_from_user
-			    (&edata, useraddr, sizeof(edata)))
-				return -EFAULT;
-			/* debug = edata.data; *//* XXX */
-			return 0;
-		}
-	}
-	return -EOPNOTSUPP;
+static int gp_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct gt64240_private *gp = (struct gt64240_private *) dev->priv;
+	int rc;
+
+	spin_lock_irq(&gp->lock);
+	rc = mii_ethtool_sset(&gp->mii_if, cmd);
+	spin_unlock_irq(&gp->lock);
+	return rc;
 }
 
+static int gp_nway_reset(struct net_device *dev)
+{
+	struct gt64240_private *gp = (struct gt64240_private *) dev->priv;
+	return mii_nway_restart(&gp->mii_if);
+}
+
+static u32 gp_get_link(struct net_device *dev)
+{
+	struct gt64240_private *gp = (struct gt64240_private *) dev->priv;
+	return mii_link_ok(&gp->mii_if);
+}
+
+static u32 gp_get_msglevel(struct net_device *dev)
+{
+	struct gt64240_private *gp = (struct gt64240_private *) dev->priv;
+	return gp->msg_enable;
+}
+
+static void gp_set_msglevel(struct net_device *dev, u32 value)
+{
+	struct gt64240_private *gp = (struct gt64240_private *) dev->priv;
+	gp->msg_enable = value;
+}
+
+static struct ethtool_ops gp_ethtool_ops = {
+	.get_drvinfo		= gp_get_drvinfo,
+	.get_settings		= gp_get_settings,
+	.set_settings		= gp_set_settings,
+	.nway_reset		= gp_nway_reset,
+	.get_link		= gp_get_link,
+	.get_msglevel		= gp_get_msglevel,
+	.set_msglevel		= gp_set_msglevel,
+};
+
 static int gt64240_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
+	struct gt64240_private *gp = (struct gt64240_private *) dev->priv;
 	struct mii_ioctl_data *data =
 	    (struct mii_ioctl_data *) &rq->ifr_data;
-	int phy = dev->base_addr & 0x1f;
 	int retval;
 
-	switch (cmd) {
-	case SIOCETHTOOL:
-		retval = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
-		break;
-
-	case SIOCGMIIPHY:	/* Get address of MII PHY in use. */
-	case SIOCDEVPRIVATE:	/* for binary compat, remove in 2.5 */
-		data->phy_id = phy;
-		/* Fall through */
-
-	case SIOCGMIIREG:	/* Read MII PHY register. */
-	case SIOCDEVPRIVATE + 1:	/* for binary compat, remove in 2.5 */
-		data->val_out = read_MII(dev, data->reg_num & 0x1f);
-		retval = 0;
-		break;
-
-	case SIOCSMIIREG:	/* Write MII PHY register. */
-	case SIOCDEVPRIVATE + 2:	/* for binary compat, remove in 2.5 */
-		if (!capable(CAP_NET_ADMIN)) {
-			retval = -EPERM;
-		} else {
-			write_MII(dev, data->reg_num & 0x1f, data->val_in);
-			retval = 0;
-		}
-		break;
+	if (!netif_running(dev))
+		return -EINVAL;
+
+	spin_lock_irq(&gp->lock);
+	retval = generic_mii_ioctl(&gp->mii_if, data, cmd, NULL);
+	spin_unlock_irq(&gp->lock);
 
-	default:
-		retval = -EOPNOTSUPP;
-		break;
-	}
 	return retval;
 }
 
@@ -714,17 +690,6 @@
 	GT64240ETH_WRITE(gp, GT64240_ETH_INT_MASK, 0);
 }
 
-#ifdef GT64240_NAPI
-static inline void __netif_rx_complete(struct net_device *dev)
-{
-	if (!test_bit(__LINK_STATE_RX_SCHED, &dev->state))
-		BUG();
-	list_del(&dev->poll_list);
-	clear_bit(__LINK_STATE_RX_SCHED, &dev->state);
-}
-#endif
-
-
 /*
  * Probe for a GT64240 ethernet controller.
  */
@@ -770,21 +735,12 @@
 	static unsigned version_printed = 0;
 	struct gt64240_private *gp = NULL;
 	int retval;
-	u16 vendor_id, device_id;
 	u32 cpuConfig;
 	unsigned char chip_rev;
 
-	// probe for GT64240 by reading PCI0 vendor/device ID register
-	pcibios_read_config_word(0, 0, PCI_VENDOR_ID, &vendor_id);
-	pcibios_read_config_word(0, 0, PCI_DEVICE_ID, &device_id);
-
-	dev = init_etherdev(NULL, sizeof(struct gt64240_private));
-
-	if (gt64240_debug > 2)
-		printk
-		    ("%s: gt64240_probe1 vendId=0x%08x, devId=0x%08x, addr=0x%08lx, irq=%d.,port=%d.\n",
-		     dev->name, vendor_id, device_id, ioaddr, irq,
-		     port_num);
+	dev = alloc_etherdev(sizeof(struct gt64240_private));
+	if (!dev)
+		return -ENOMEM;
 
 	if (irq < 0) {
 		printk
@@ -801,12 +757,8 @@
 	       (cpuConfig & (1 << 12)) ? "little" : "big");
 
 	printk
-	    ("%s: GT64240 found at ioaddr 0x%lx, irq %d., PCI devID=%x\n",
-	     dev->name, ioaddr, irq, device_id);
-
-	/* Allocate a new 'dev' if needed. */
-	if (dev == NULL)
-		dev = init_etherdev(0, sizeof(struct gt64240_private));
+	    ("%s: GT64240 found at ioaddr 0x%lx, irq %d.\n",
+	     dev->name, ioaddr, irq);
 
 	if (gt64240_debug && version_printed++ == 0)
 		printk("%s: %s", dev->name, version);
@@ -821,23 +773,9 @@
 	printk("%s: HW Address ", dev->name);
 	dump_hw_addr(dev->dev_addr);
 
-	/* Initialize our private structure. */
-	if (dev->priv == NULL) {
-
-		gp = (struct gt64240_private *) kmalloc(sizeof(*gp),
-							GFP_KERNEL);
-		if (gp == NULL) {
-			retval = -ENOMEM;
-			goto free_region;
-		}
-
-		dev->priv = gp;
-	}
-
 	gp = dev->priv;
 
-	memset(gp, 0, sizeof(*gp));	// clear it
-
+	gp->msg_enable = (debug < 0 ? GT64240_MSG_ENABLE : debug);
 	gp->port_num = port_num;
 	gp->io_size = GT64240_ETH_IO_SIZE;
 	gp->port_offset = port_num * GT64240_ETH_IO_SIZE;
@@ -927,12 +865,12 @@
 	dev->poll = gt64240_poll;
 	dev->weight = 64;
 #endif
+	dev->ethtool_ops = &gp_ethtool_ops;
 
 	/* Fill in the fields of the device structure with ethernet values. */
-	ether_setup(dev);
 	return 0;
 
-      free_region:
+free_region:
 	release_region(ioaddr, gp->io_size);
 	unregister_netdev(dev);
 	if (dev->priv != NULL)
@@ -1036,7 +974,6 @@
 static int gt64240_init(struct net_device *dev)
 {
 	struct gt64240_private *gp = (struct gt64240_private *) dev->priv;
-	u32 ciu;
 
 	if (gt64240_debug > 3) {
 		printk("%s: gt64240_init: dev=%p\n", dev->name, dev);
@@ -1292,7 +1229,7 @@
 	    (struct gt64240_private *) netdev->priv;
 	unsigned long flags;
 	int done = 1, orig_budget, work_done;
-	u32 intMask, status = GT64240ETH_READ(gp, GT64240_ETH_INT_CAUSE);
+	u32 status = GT64240ETH_READ(gp, GT64240_ETH_INT_CAUSE);
 
 	spin_lock_irqsave(&gp->lock, flags);
 	gt64240_tx_fill(netdev, status);
@@ -1315,6 +1252,8 @@
 	}
 
 	spin_unlock_irqrestore(&gp->lock, flags);
+
+	return (done ? 0 : 1);
 }
 #endif
 
diff -urN linux-2.4.28-bk7/drivers/net/gt64240eth.h linux-2.4.29/drivers/net/gt64240eth.h
--- linux-2.4.28-bk7/drivers/net/gt64240eth.h	2004-02-18 05:36:31.000000000 -0800
+++ linux-2.4.29/drivers/net/gt64240eth.h	2005-01-19 07:08:09.193470534 -0800
@@ -401,6 +401,8 @@
     int drv_flags;
     spinlock_t lock;	   /* Serialise access to device */
     struct mii_if_info mii_if;
+
+    u32	msg_enable;
 };
 
 #endif /* _GT64240ETH_H */
diff -urN linux-2.4.28-bk7/drivers/net/hamradio/6pack.c linux-2.4.29/drivers/net/hamradio/6pack.c
--- linux-2.4.28-bk7/drivers/net/hamradio/6pack.c	2004-08-07 16:26:05.000000000 -0700
+++ linux-2.4.29/drivers/net/hamradio/6pack.c	2005-01-19 07:08:09.194470577 -0800
@@ -571,8 +571,7 @@
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
 
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
+	tty_ldisc_flush(tty);
 
 	/* Restore default settings */
 	sp->dev->type = ARPHRD_AX25;
diff -urN linux-2.4.28-bk7/drivers/net/hamradio/mkiss.c linux-2.4.29/drivers/net/hamradio/mkiss.c
--- linux-2.4.28-bk7/drivers/net/hamradio/mkiss.c	2003-08-25 04:44:42.000000000 -0700
+++ linux-2.4.29/drivers/net/hamradio/mkiss.c	2005-01-19 07:08:09.195470621 -0800
@@ -654,8 +654,7 @@
 
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
+	tty_ldisc_flush(tty);
 
 	/* Restore default settings */
 	ax->dev->type = ARPHRD_AX25;
diff -urN linux-2.4.28-bk7/drivers/net/irda/irtty.c linux-2.4.29/drivers/net/irda/irtty.c
--- linux-2.4.28-bk7/drivers/net/irda/irtty.c	2003-06-13 07:51:35.000000000 -0700
+++ linux-2.4.29/drivers/net/irda/irtty.c	2005-01-19 07:08:09.196470664 -0800
@@ -179,9 +179,8 @@
 
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
-	
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
+
+	tty_ldisc_flush(tty);	
 	
 	self->magic = IRTTY_MAGIC;
 	self->mode = IRDA_IRLAP;
diff -urN linux-2.4.28-bk7/drivers/net/jazzsonic.c linux-2.4.29/drivers/net/jazzsonic.c
--- linux-2.4.28-bk7/drivers/net/jazzsonic.c	2001-09-09 10:43:01.000000000 -0700
+++ linux-2.4.29/drivers/net/jazzsonic.c	2005-01-19 07:08:09.197470707 -0800
@@ -14,6 +14,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/types.h>
 #include <linux/fcntl.h>
@@ -51,8 +52,8 @@
 
 #define SONIC_WRITE(reg,val)						\
 do {									\
-	*((volatile unsigned int *)base_addr+reg) = val;		\
-}
+	*((volatile unsigned int *)base_addr+(reg)) = (val);		\
+} while (0)
 
 
 /* use 0 for production, 1 for verification, >2 for debug */
@@ -84,7 +85,7 @@
 /* Index to functions, as function prototypes. */
 
 extern int sonic_probe(struct net_device *dev);
-static int sonic_probe1(struct net_device *dev, unsigned int base_addr,
+static int sonic_probe1(struct net_device *dev, unsigned long base_addr,
                         unsigned int irq);
 
 
@@ -94,7 +95,7 @@
  */
 int __init sonic_probe(struct net_device *dev)
 {
-	unsigned int base_addr = dev ? dev->base_addr : 0;
+	unsigned long base_addr = dev ? dev->base_addr : 0;
 	int i;
 
 	/*
@@ -117,7 +118,7 @@
 	return -ENODEV;
 }
 
-static int __init sonic_probe1(struct net_device *dev, unsigned int base_addr,
+static int __init sonic_probe1(struct net_device *dev, unsigned long base_addr,
                                unsigned int irq)
 {
 	static unsigned version_printed;
diff -urN linux-2.4.28-bk7/drivers/net/mv64340_eth.c linux-2.4.29/drivers/net/mv64340_eth.c
--- linux-2.4.28-bk7/drivers/net/mv64340_eth.c	2004-02-18 05:36:31.000000000 -0800
+++ linux-2.4.29/drivers/net/mv64340_eth.c	2005-01-19 07:08:09.199470794 -0800
@@ -94,13 +94,6 @@
  * Helper functions - used inside the driver only *
  **************************************************/
 
-static inline void __netif_rx_complete(struct net_device *dev)
-{
-        if (!test_bit(__LINK_STATE_RX_SCHED, &dev->state)) BUG();
-        list_del(&dev->poll_list);
-        clear_bit(__LINK_STATE_RX_SCHED, &dev->state);
-}
-
 static void *mv64340_eth_malloc_ring(unsigned int size)
 {
 	dma_addr_t dma_handle;
@@ -707,11 +700,11 @@
 	if (mv64340_eth_real_open(dev)) {
 		printk("%s: Error opening interface\n", dev->name);
 		free_irq(dev->irq, dev);
-		spin_unlock_irq(&ethernet_priv->lock);
+               spin_unlock_irq(&port_private->lock);
 		return -EBUSY;
 	}
 	MOD_INC_USE_COUNT;
-	spin_unlock_irq(&ethernet_priv->lock);
+       spin_unlock_irq(&port_private->lock);
 	return 0;
 }
 
@@ -723,7 +716,6 @@
 	unsigned int port_num;
 	u32 phy_reg_data;
 	unsigned int size;
-	int i;
 
 	ethernet_private = dev->priv;
 	port_private =
@@ -952,7 +944,7 @@
 
 	free_irq(dev->irq, dev);
 	MOD_DEC_USE_COUNT;
-	spin_unlock_irq(&ethernet_priv->lock);
+       spin_unlock_irq(&port_private->lock);
 	return 0;
 };
 
@@ -1232,7 +1224,7 @@
 	stats->tx_packets++;
 	dev->trans_start = jiffies;
 
-	spin_unlock_irqrestore(&ethernet_priv->lock, flags);
+       spin_unlock_irqrestore(&port_private->lock, flags);
 	return 0;		/* success */
 }
 
@@ -2874,6 +2866,8 @@
 	return ETH_OK;
 }
 
+#ifdef MV64340_COAL
+
 /*******************************************************************************
  * eth_port_set_rx_coal - Sets coalescing interrupt mechanism on RX path
  *
@@ -2910,6 +2904,7 @@
 		  & 0xffc000ff));
 	return coal;
 }
+#endif
 
 /*******************************************************************************
  * eth_port_set_tx_coal - Sets coalescing interrupt mechanism on TX path
diff -urN linux-2.4.28-bk7/drivers/net/ne.c linux-2.4.29/drivers/net/ne.c
--- linux-2.4.28-bk7/drivers/net/ne.c	2002-08-02 17:39:44.000000000 -0700
+++ linux-2.4.29/drivers/net/ne.c	2005-01-19 07:08:09.201470880 -0800
@@ -105,6 +105,9 @@
     {"PCM-4823", "PCM-4823", {0x00, 0xc0, 0x6c}}, /* Broken Advantech MoBo */
     {"REALTEK", "RTL8019", {0x00, 0x00, 0xe8}}, /* no-name with Realtek chip */
     {"LCS-8834", "LCS-8836", {0x04, 0x04, 0x37}}, /* ShinyNet (SET) */
+#ifdef CONFIG_TOSHIBA_RBTX4927
+    {"TX4927", "TX4927", {0x00, 0x60, 0x0a}}, /* Toshiba w/EEPROM, no probing */
+#endif
     {0,}
 };
 #endif
@@ -239,6 +242,13 @@
 	int reg0, ret;
 	static unsigned version_printed;
 
+#ifdef CONFIG_TOSHIBA_RBTX4927
+#include <asm/tx4927/toshiba_rbtx4927.h>
+	ioaddr = RBTX4927_RTL_8019_BASE;
+	dev->irq = RBTX4927_RTL_8019_IRQ;
+	wordlength = 1;
+#endif
+
 	if (!request_region(ioaddr, NE_IO_EXTENT, dev->name))
 		return -EBUSY;
 
@@ -342,8 +352,15 @@
 		start_page = NESM_START_PG;
 		stop_page = NESM_STOP_PG;
 	} else {
+#ifdef CONFIG_TOSHIBA_RBTX4927
+		start_page = NESM_START_PG;
+		stop_page = NESM_STOP_PG;
+		for (i = 0; i < 16; i++)
+			SA_prom[i] = SA_prom[i+i];
+#else
 		start_page = NE1SM_START_PG;
 		stop_page = NE1SM_STOP_PG;
+#endif
 	}
 
 	neX000 = (SA_prom[14] == 0x57  &&  SA_prom[15] == 0x57);
diff -urN linux-2.4.28-bk7/drivers/net/pcnet32.c linux-2.4.29/drivers/net/pcnet32.c
--- linux-2.4.28-bk7/drivers/net/pcnet32.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/drivers/net/pcnet32.c	2005-01-19 07:08:09.202470924 -0800
@@ -1007,7 +1007,11 @@
 	return -EBUSY;
     }
 
-    return pcnet32_probe1(ioaddr, 1, pdev);
+    err = pcnet32_probe1(ioaddr, 1, pdev);
+    if (err < 0) {
+	pci_disable_device(pdev);
+    }
+    return err;
 }
 
 
@@ -2241,6 +2245,7 @@
 	release_region(dev->base_addr, PCNET32_TOTAL_SIZE);
 	pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr);
 	free_netdev(dev);
+	pci_disable_device(pdev);
 	pci_set_drvdata(pdev, NULL);
     }
 }
diff -urN linux-2.4.28-bk7/drivers/net/ppp_async.c linux-2.4.29/drivers/net/ppp_async.c
--- linux-2.4.28-bk7/drivers/net/ppp_async.c	2002-08-02 17:39:44.000000000 -0700
+++ linux-2.4.29/drivers/net/ppp_async.c	2005-01-19 07:08:09.204471010 -0800
@@ -117,6 +117,9 @@
  * frees the memory that ppp_asynctty_receive is using.  The best
  * way to fix this is to use a rwlock in the tty struct, but for now
  * we use a single global rwlock for all ttys in ppp line discipline.
+ *
+ * FIXME: this is no longer true. The _close path for the ldisc is 
+ * now guaranteed to be sane. 
  */
 static rwlock_t disc_data_lock = RW_LOCK_UNLOCKED;
 
@@ -139,7 +142,8 @@
 }
 
 /*
- * Called when a tty is put into PPP line discipline.
+ * Called when a tty is put into PPP line discipline. Called in process
+ * context.
  */
 static int
 ppp_asynctty_open(struct tty_struct *tty)
@@ -227,6 +231,18 @@
 }
 
 /*
+ * Called on tty hangup in process context.
+ *
+ * Wait for I/O to driver to complete and unregister PPP channel.
+ * This is already done by the close routine, so just call that.
+ */
+static int ppp_asynctty_hangup(struct tty_struct *tty)
+{
+	ppp_asynctty_close(tty);
+	return 0;
+}
+
+/*
  * Read does nothing - no data is ever available this way.
  * Pppd reads and writes packets via /dev/ppp instead.
  */
@@ -248,6 +264,11 @@
 	return -EAGAIN;
 }
 
+/*
+ * Called in process context only. May be re-entered by multiple
+ * ioctl calling threads.
+ */
+ 
 static int
 ppp_asynctty_ioctl(struct tty_struct *tty, struct file *file,
 		   unsigned int cmd, unsigned long arg)
@@ -359,6 +380,7 @@
 	write:	ppp_asynctty_write,
 	ioctl:	ppp_asynctty_ioctl,
 	poll:	ppp_asynctty_poll,
+	hangup: ppp_asynctty_hangup,
 	receive_room: ppp_asynctty_room,
 	receive_buf: ppp_asynctty_receive,
 	write_wakeup: ppp_asynctty_wakeup,
@@ -714,7 +736,8 @@
 
 /*
  * Flush output from our internal buffers.
- * Called for the TCFLSH ioctl.
+ * Called for the TCFLSH ioctl. Can be entered in parallel
+ * but this is covered by the xmit_lock.
  */
 static void
 ppp_async_flush_output(struct asyncppp *ap)
@@ -819,7 +842,9 @@
 	ppp_input_error(&ap->chan, code);
 }
 
-/* called when the tty driver has data for us. */
+/* Called when the tty driver has data for us. Runs parallel with the
+   other ldisc functions but will not be re-entered */
+
 static void
 ppp_async_input(struct asyncppp *ap, const unsigned char *buf,
 		char *flags, int count)
diff -urN linux-2.4.28-bk7/drivers/net/ppp_synctty.c linux-2.4.29/drivers/net/ppp_synctty.c
--- linux-2.4.28-bk7/drivers/net/ppp_synctty.c	2002-08-02 17:39:44.000000000 -0700
+++ linux-2.4.29/drivers/net/ppp_synctty.c	2005-01-19 07:08:09.204471010 -0800
@@ -172,6 +172,8 @@
  * frees the memory that ppp_synctty_receive is using.  The best
  * way to fix this is to use a rwlock in the tty struct, but for now
  * we use a single global rwlock for all ttys in ppp line discipline.
+ *
+ * FIXME: Fixed in tty_io nowdays.
  */
 static rwlock_t disc_data_lock = RW_LOCK_UNLOCKED;
 
@@ -280,6 +282,18 @@
 }
 
 /*
+ * Called on tty hangup in process context.
+ *
+ * Wait for I/O to driver to complete and unregister PPP channel.
+ * This is already done by the close routine, so just call that.
+ */
+static int ppp_sync_hangup(struct tty_struct *tty)
+{
+	ppp_sync_close(tty);
+	return 0;
+}
+
+/*
  * Read does nothing - no data is ever available this way.
  * Pppd reads and writes packets via /dev/ppp instead.
  */
@@ -412,6 +426,7 @@
 	write:	ppp_sync_write,
 	ioctl:	ppp_synctty_ioctl,
 	poll:	ppp_sync_poll,
+	hangup: ppp_sync_hangup,
 	receive_room: ppp_sync_room,
 	receive_buf: ppp_sync_receive,
 	write_wakeup: ppp_sync_wakeup,
diff -urN linux-2.4.28-bk7/drivers/net/sb1250-mac.c linux-2.4.29/drivers/net/sb1250-mac.c
--- linux-2.4.28-bk7/drivers/net/sb1250-mac.c	2004-02-18 05:36:31.000000000 -0800
+++ linux-2.4.29/drivers/net/sb1250-mac.c	2005-01-19 07:08:09.209471227 -0800
@@ -468,14 +468,17 @@
 {
 	int cnt;
 	uint64_t bits;
+	int mac_mdio_genc;
+
+	mac_mdio_genc = SBMAC_READCSR(s->sbm_mdio) & M_MAC_GENC;
 	
 	bits = M_MAC_MDIO_DIR_OUTPUT | M_MAC_MDIO_OUT;
 	
-	SBMAC_WRITECSR(s->sbm_mdio,bits);
+	SBMAC_WRITECSR(s->sbm_mdio,bits | mac_mdio_genc);
 	
 	for (cnt = 0; cnt < 32; cnt++) {
-		SBMAC_WRITECSR(s->sbm_mdio,bits | M_MAC_MDC);
-		SBMAC_WRITECSR(s->sbm_mdio,bits);
+		SBMAC_WRITECSR(s->sbm_mdio,bits | M_MAC_MDC | mac_mdio_genc);
+		SBMAC_WRITECSR(s->sbm_mdio,bits | mac_mdio_genc);
 	}
 }
 
@@ -496,9 +499,12 @@
 	int i;
 	uint64_t bits;
 	unsigned int curmask;
+	int mac_mdio_genc;
+
+	mac_mdio_genc = SBMAC_READCSR(s->sbm_mdio) & M_MAC_GENC;
 	
 	bits = M_MAC_MDIO_DIR_OUTPUT;
-	SBMAC_WRITECSR(s->sbm_mdio,bits);
+	SBMAC_WRITECSR(s->sbm_mdio,bits | mac_mdio_genc);
 	
 	curmask = 1 << (bitcnt - 1);
 	
@@ -506,9 +512,9 @@
 		if (data & curmask)
 			bits |= M_MAC_MDIO_OUT;
 		else bits &= ~M_MAC_MDIO_OUT;
-		SBMAC_WRITECSR(s->sbm_mdio,bits);
-		SBMAC_WRITECSR(s->sbm_mdio,bits | M_MAC_MDC);
-		SBMAC_WRITECSR(s->sbm_mdio,bits);
+		SBMAC_WRITECSR(s->sbm_mdio,bits | mac_mdio_genc);
+		SBMAC_WRITECSR(s->sbm_mdio,bits | M_MAC_MDC | mac_mdio_genc);
+		SBMAC_WRITECSR(s->sbm_mdio,bits | mac_mdio_genc);
 		curmask >>= 1;
 	}
 }
@@ -534,7 +540,8 @@
 	int idx;
 	int error;
 	int regval;
-	
+	int mac_mdio_genc;
+
 	/*
 	 * Synchronize ourselves so that the PHY knows the next
 	 * thing coming down is a command
@@ -555,17 +562,20 @@
 	sbmac_mii_senddata(s,phyaddr, 5);
 	sbmac_mii_senddata(s,regidx, 5);
 	
+	mac_mdio_genc = SBMAC_READCSR(s->sbm_mdio) & M_MAC_GENC;
+	
 	/* 
 	 * Switch the port around without a clock transition.
 	 */
-	SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT);
+	SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | mac_mdio_genc);
 	
 	/*
 	 * Send out a clock pulse to signal we want the status
 	 */
 	
-	SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | M_MAC_MDC);
-	SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT);
+	SBMAC_WRITECSR(s->sbm_mdio,
+		       M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc);
+	SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | mac_mdio_genc);
 	
 	/* 
 	 * If an error occurred, the PHY will signal '1' back
@@ -576,8 +586,9 @@
 	 * Issue an 'idle' clock pulse, but keep the direction
 	 * the same.
 	 */
-	SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | M_MAC_MDC);
-	SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT);
+	SBMAC_WRITECSR(s->sbm_mdio,
+		       M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc);
+	SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | mac_mdio_genc);
 	
 	regval = 0;
 	
@@ -589,12 +600,14 @@
 				regval |= 1;
 		}
 		
-		SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | M_MAC_MDC);
-		SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT);
+		SBMAC_WRITECSR(s->sbm_mdio,
+			       M_MAC_MDIO_DIR_INPUT|M_MAC_MDC | mac_mdio_genc);
+		SBMAC_WRITECSR(s->sbm_mdio,
+			       M_MAC_MDIO_DIR_INPUT | mac_mdio_genc);
 	}
 	
 	/* Switch back to output */
-	SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_OUTPUT);
+	SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc);
 	
 	if (error == 0)
 		return regval;
@@ -620,7 +633,8 @@
 static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx,
 			    unsigned int regval)
 {
-	
+	int mac_mdio_genc;
+
 	sbmac_mii_sync(s);
 	
 	sbmac_mii_senddata(s,MII_COMMAND_START,2);
@@ -629,8 +643,10 @@
 	sbmac_mii_senddata(s,regidx, 5);
 	sbmac_mii_senddata(s,MII_COMMAND_ACK,2);
 	sbmac_mii_senddata(s,regval,16);
-	
-	SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_OUTPUT);
+
+	mac_mdio_genc = SBMAC_READCSR(s->sbm_mdio) & M_MAC_GENC;
+
+	SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc);
 }
 
 
@@ -2788,7 +2804,7 @@
 	struct net_device *dev;
 	sbmac_port_t port;
 	int chip_max_units;
-	
+
 	/*
 	 * For bringup when not using the firmware, we can pre-fill
 	 * the MAC addresses using the environment variables
diff -urN linux-2.4.28-bk7/drivers/net/sgiseeq.c linux-2.4.29/drivers/net/sgiseeq.c
--- linux-2.4.28-bk7/drivers/net/sgiseeq.c	2004-02-18 05:36:31.000000000 -0800
+++ linux-2.4.29/drivers/net/sgiseeq.c	2005-01-19 07:08:09.210471270 -0800
@@ -162,12 +162,6 @@
 
 	seeq_load_eaddr(dev, sp->sregs);
 
-	/* XXX for now just accept packets directly to us
-	 * XXX and ether-broadcast.  Will do multicast and
-	 * XXX promiscuous mode later. -davem
-	 */
-	sp->mode = SEEQ_RCMD_RBCAST;
-
 	/* Setup tx ring. */
 	for(i = 0; i < SEEQ_TX_BUFFERS; i++) {
 		if (!ib->tx_desc[i].tdma.pbuf) {
@@ -332,10 +326,17 @@
 				/* Copy out of kseg1 to avoid silly cache flush. */
 				eth_copy_and_sum(skb, pkt_pointer + 2, len, 0);
 				skb->protocol = eth_type_trans(skb, dev);
-				netif_rx(skb);
-				dev->last_rx = jiffies;
-				sp->stats.rx_packets++;
-				sp->stats.rx_bytes += len;
+
+				/* We don't want to receive our own packets */
+				if (memcmp(skb->mac.ethernet->h_source, dev->dev_addr, 6)) {
+					netif_rx(skb);
+					dev->last_rx = jiffies;
+					sp->stats.rx_packets++;
+					sp->stats.rx_bytes += len;
+				} else {
+					/* Silently drop my own packets */
+					dev_kfree_skb_irq(skb);
+				}
 			} else {
 				printk (KERN_NOTICE "%s: Memory squeeze, deferring packet.\n",
 					dev->name);
@@ -570,6 +571,22 @@
 
 static void sgiseeq_set_multicast(struct net_device *dev)
 {
+	struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv;
+	unsigned char oldmode = sp->mode;
+
+	if(dev->flags & IFF_PROMISC)
+		sp->mode = SEEQ_RCMD_RANY;
+	else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count)
+		sp->mode = SEEQ_RCMD_RBMCAST;
+	else
+		sp->mode = SEEQ_RCMD_RBCAST;
+
+	/* XXX I know this sucks, but is there a better way to reprogram
+	 * XXX the receiver? At least, this shouldn't happen too often.
+	 */
+
+	if (oldmode != sp->mode)
+		sgiseeq_reset(dev);
 }
 
 static inline void setup_tx_ring(struct sgiseeq_tx_desc *buf, int nbufs)
@@ -640,6 +657,7 @@
 	sp->sregs = (struct sgiseeq_regs *) &hpc3c0->eth_ext[0];
 	sp->hregs = &hpc3c0->ethregs;
 	sp->name = sgiseeqstr;
+	sp->mode = SEEQ_RCMD_RBCAST;
 
 	sp->srings.rx_desc = (struct sgiseeq_rx_desc *)
 	                     KSEG1ADDR(ALIGNED(&sp->srings.rxvector[0]));
diff -urN linux-2.4.28-bk7/drivers/net/slip.c linux-2.4.29/drivers/net/slip.c
--- linux-2.4.28-bk7/drivers/net/slip.c	2002-11-28 15:53:14.000000000 -0800
+++ linux-2.4.29/drivers/net/slip.c	2005-01-19 07:08:09.212471357 -0800
@@ -670,7 +670,9 @@
  * Handle the 'receiver data ready' interrupt.
  * This function is called by the 'tty_io' module in the kernel when
  * a block of SLIP data has been received, which can now be decapsulated
- * and sent on to some IP layer for further processing.
+ * and sent on to some IP layer for further processing. This will not
+ * be re-entered while running but other ldisc functions may be called
+ * in parallel
  */
  
 static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
@@ -826,9 +828,11 @@
  * SLIP line discipline is called for.  Because we are
  * sure the tty line exists, we only have to link it to
  * a free SLIP channel...
+ *
+ * Called in process context serialized from other ldisc calls.
  */
-static int
-slip_open(struct tty_struct *tty)
+
+static int slip_open(struct tty_struct *tty)
 {
 	struct slip *sl;
 	int err;
@@ -865,8 +869,6 @@
 	sl->pid = current->pid;
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
 
 	if (!test_bit(SLF_INUSE, &sl->flags)) {
 		/* Perform the low-level SLIP initialization. */
@@ -910,6 +912,9 @@
 }
 
 /*
+
+  FIXME: 1,2 are fixed 3 was never true anyway.
+  
    Let me to blame a bit.
    1. TTY module calls this funstion on soft interrupt.
    2. TTY module calls this function WITH MASKED INTERRUPTS!
@@ -928,9 +933,8 @@
 
 /*
  * Close down a SLIP channel.
- * This means flushing out any pending queues, and then restoring the
- * TTY line discipline to what it was before it got hooked to SLIP
- * (which usually is TTY again).
+ * This means flushing out any pending queues, and then returning. This
+ * call is serialized against other ldisc functions.
  */
 static void
 slip_close(struct tty_struct *tty)
diff -urN linux-2.4.28-bk7/drivers/net/strip.c linux-2.4.29/drivers/net/strip.c
--- linux-2.4.28-bk7/drivers/net/strip.c	2001-11-09 14:02:24.000000000 -0800
+++ linux-2.4.29/drivers/net/strip.c	2005-01-19 07:08:09.214471444 -0800
@@ -2706,8 +2706,7 @@
     tty->disc_data = strip_info;
     if (tty->driver.flush_buffer)
         tty->driver.flush_buffer(tty);
-    if (tty->ldisc.flush_buffer)
-        tty->ldisc.flush_buffer(tty);
+    tty_ldisc_flush(tty);
 
     /*
      * Restore default settings
diff -urN linux-2.4.28-bk7/drivers/net/sungem.c linux-2.4.29/drivers/net/sungem.c
--- linux-2.4.28-bk7/drivers/net/sungem.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/drivers/net/sungem.c	2005-01-19 07:08:09.216471530 -0800
@@ -119,6 +119,8 @@
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
 	{ PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_GMACP,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_GMAC2,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
 	{0, }
 };
 
diff -urN linux-2.4.28-bk7/drivers/net/tg3.c linux-2.4.29/drivers/net/tg3.c
--- linux-2.4.28-bk7/drivers/net/tg3.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/drivers/net/tg3.c	2005-01-19 07:08:09.223471833 -0800
@@ -59,8 +59,8 @@
 
 #define DRV_MODULE_NAME		"tg3"
 #define PFX DRV_MODULE_NAME	": "
-#define DRV_MODULE_VERSION	"3.14"
-#define DRV_MODULE_RELDATE	"November 15, 2004"
+#define DRV_MODULE_VERSION	"3.15"
+#define DRV_MODULE_RELDATE	"January 6, 2005"
 
 #define TG3_DEF_MAC_MODE	0
 #define TG3_DEF_RX_MODE		0
@@ -477,7 +477,8 @@
 static int tg3_readphy(struct tg3 *tp, int reg, u32 *val)
 {
 	u32 frame_val;
-	int loops, ret;
+	unsigned int loops;
+	int ret;
 
 	if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) {
 		tw32_f(MAC_MI_MODE,
@@ -485,7 +486,7 @@
 		udelay(80);
 	}
 
-	*val = 0xffffffff;
+	*val = 0x0;
 
 	frame_val  = ((PHY_ADDR << MI_COM_PHY_ADDR_SHIFT) &
 		      MI_COM_PHY_ADDR_MASK);
@@ -496,7 +497,7 @@
 	tw32_f(MAC_MI_COM, frame_val);
 
 	loops = PHY_BUSY_LOOPS;
-	while (loops-- > 0) {
+	while (loops != 0) {
 		udelay(10);
 		frame_val = tr32(MAC_MI_COM);
 
@@ -505,10 +506,11 @@
 			frame_val = tr32(MAC_MI_COM);
 			break;
 		}
+		loops -= 1;
 	}
 
 	ret = -EBUSY;
-	if (loops > 0) {
+	if (loops != 0) {
 		*val = frame_val & MI_COM_DATA_MASK;
 		ret = 0;
 	}
@@ -524,7 +526,8 @@
 static int tg3_writephy(struct tg3 *tp, int reg, u32 val)
 {
 	u32 frame_val;
-	int loops, ret;
+	unsigned int loops;
+	int ret;
 
 	if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) {
 		tw32_f(MAC_MI_MODE,
@@ -542,7 +545,7 @@
 	tw32_f(MAC_MI_COM, frame_val);
 
 	loops = PHY_BUSY_LOOPS;
-	while (loops-- > 0) {
+	while (loops != 0) {
 		udelay(10);
 		frame_val = tr32(MAC_MI_COM);
 		if ((frame_val & MI_COM_BUSY) == 0) {
@@ -550,10 +553,11 @@
 			frame_val = tr32(MAC_MI_COM);
 			break;
 		}
+		loops -= 1;
 	}
 
 	ret = -EBUSY;
-	if (loops > 0)
+	if (loops != 0)
 		ret = 0;
 
 	if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) {
diff -urN linux-2.4.28-bk7/drivers/net/titan_ge.c linux-2.4.29/drivers/net/titan_ge.c
--- linux-2.4.28-bk7/drivers/net/titan_ge.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.29/drivers/net/titan_ge.c	2005-01-19 07:08:09.228472050 -0800
@@ -0,0 +1,2305 @@
+/*
+ * drivers/net/titan_ge.c - Driver for Titan ethernet ports
+ *
+ * Copyright (C) 2003 PMC-Sierra Inc.
+ * Author : Manish Lachwani (lachwani@pmc-sierra.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
+ * 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 MAC unit of the Titan consists of the following:
+ *
+ * -> XDMA Engine to move data to from the memory to the MAC packet FIFO
+ * -> FIFO is where the incoming and outgoing data is placed
+ * -> TRTG is the unit that pulls the data from the FIFO for Tx and pushes
+ *    the data into the FIFO for Rx
+ * -> TMAC is the outgoing MAC interface and RMAC is the incoming. 
+ * -> AFX is the address filtering block
+ * -> GMII block to communicate with the PHY
+ *
+ * Rx will look like the following:
+ * GMII --> RMAC --> AFX --> TRTG --> Rx FIFO --> XDMA --> CPU memory
+ *
+ * Tx will look like the following:
+ * CPU memory --> XDMA --> Tx FIFO --> TRTG --> TMAC --> GMII
+ *
+ * The Titan driver has support for the following performance features:
+ * -> Rx side checksumming 
+ * -> Jumbo Frames
+ * -> Interrupt Coalscing
+ * -> Rx NAPI 
+ * -> SKB Recycling
+ * -> Transmit/Receive descriptors in SRAM
+ * -> Fast routing for IP forwarding
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/fcntl.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ip.h>
+#include <linux/init.h>
+#include <linux/in.h>
+#include <linux/pci.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/mii.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+#include <linux/prefetch.h>
+
+/* For MII specifc registers, titan_mdio.h should be included */
+#include <net/ip.h>
+
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/types.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+
+#include "titan_ge.h"
+#include "titan_mdio.h"
+
+/* Static Function Declarations	 */
+static int titan_ge_eth_open(struct net_device *);
+static int titan_ge_eth_stop(struct net_device *);
+static int titan_ge_change_mtu(struct net_device *, int);
+static struct net_device_stats *titan_ge_get_stats(struct net_device *);
+static int titan_ge_init_rx_desc_ring(titan_ge_port_info *, int, int,
+				      unsigned long, unsigned long,
+				      unsigned long);
+static int titan_ge_init_tx_desc_ring(titan_ge_port_info *, int,
+				      unsigned long, unsigned long);
+
+static int titan_ge_open(struct net_device *);
+static int titan_ge_start_xmit(struct sk_buff *, struct net_device *);
+static int titan_ge_stop(struct net_device *);
+static int titan_ge_set_mac_address(struct net_device *, void *);
+
+static unsigned long titan_ge_tx_coal(unsigned long, int);
+static unsigned long titan_ge_rx_coal(unsigned long, int);
+
+static void titan_ge_port_reset(unsigned int);
+static int titan_ge_free_tx_queue(titan_ge_port_info *);
+static int titan_ge_rx_task(struct net_device *, titan_ge_port_info *);
+static int titan_ge_port_start(struct net_device *, titan_ge_port_info *);
+
+static int titan_ge_init(int);
+static int titan_ge_return_tx_desc(titan_ge_port_info *, int);
+
+/*
+ * Some configuration for the FIFO and the XDMA channel needs
+ * to be done only once for all the ports. This flag controls
+ * that
+ */
+unsigned long config_done = 0;
+
+/*
+ * One time out of memory flag
+ */
+unsigned int oom_flag = 0;
+
+#ifdef TITAN_RX_NAPI
+static int titan_ge_poll(struct net_device *netdev, int *budget);
+#endif
+
+int titan_ge_receive_queue(struct net_device *, unsigned int);
+
+/* MAC Address */
+extern unsigned char titan_ge_mac_addr_base[6];
+
+/* Support for Rx NAPI */
+#ifdef TITAN_RX_NAPI
+static inline void __netif_rx_complete(struct net_device *dev)
+{
+        if (!test_bit(__LINK_STATE_RX_SCHED, &dev->state)) 
+		BUG();
+        list_del(&dev->poll_list);
+	mb();
+        clear_bit(__LINK_STATE_RX_SCHED, &dev->state);
+}
+#endif
+
+/* 
+ * The Titan GE has two alignment requirements:
+ * -> skb->data to be cacheline aligned (32 byte)
+ * -> IP header alignment to 16 bytes
+ *
+ * The latter is not implemented. So, that results in an extra copy on
+ * the Rx. This is a big performance hog. For the former case, the 
+ * dev_alloc_skb() has been replaced with titan_ge_alloc_skb(). The size
+ * requested is calculated:
+ * 
+ * Ethernet Frame Size : 1518
+ * Ethernet Header     : 14
+ * Future Titan change for IP header alignment : 2
+ *
+ * Hence, we allocate (1518 + 14 + 2+ 64) = 1580 bytes. For the future 
+ * revisions of the chip that do support IP header alignment, we will use
+ * skb_reserve().
+ */
+
+#define ALIGNED_RX_SKB_ADDR(addr) \
+        ((((unsigned long)(addr) + (64UL - 1UL)) \
+	& ~(64UL - 1UL)) - (unsigned long)(addr))
+
+#define titan_ge_alloc_skb(__length, __gfp_flags) \
+({      struct sk_buff *__skb; \
+        __skb = alloc_skb((__length) + 64, (__gfp_flags)); \
+        if(__skb) { \
+                int __offset = (int) ALIGNED_RX_SKB_ADDR(__skb->data); \
+                if(__offset) \
+                        skb_reserve(__skb, __offset); \
+        } \
+        __skb; \
+})
+
+/*
+ * Configure the GMII block of the Titan based 
+ * on what the PHY tells us
+ */
+static void titan_ge_gmii_config(int port_num)
+{
+	volatile unsigned int reg_data = 0, phy_reg;
+	int err;
+
+	err = titan_ge_mdio_read(port_num,
+                               TITAN_GE_MDIO_PHY_STATUS, &phy_reg);
+
+	if (err == TITAN_GE_MDIO_ERROR) {
+                printk(KERN_ERR
+                       "Could not read PHY control register 0x11 \n");
+		printk(KERN_ERR
+			"Setting speed to 1000 Mbps and Duplex to Full \n");
+
+		return TITAN_ERROR;
+        }
+
+	err = titan_ge_mdio_write(port_num,
+			TITAN_GE_MDIO_PHY_IE, 0);
+
+	if (phy_reg & 0x8000) {
+		if (phy_reg & 0x2000) {
+			/* Full Duplex and 1000 Mbps */
+			TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE + 
+					(port_num << 12)), 0x201);
+		}  else {
+			/* Half Duplex and 1000 Mbps */
+			TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE +
+					(port_num << 12)), 0x2201);
+			}
+	}
+	if (phy_reg & 0x4000) {
+		if (phy_reg & 0x2000) {
+			/* Full Duplex and 100 Mbps */
+			TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE +
+					(port_num << 12)), 0x100);
+		} else {
+			/* Half Duplex and 100 Mbps */
+			TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE +
+					(port_num << 12)), 0x2100);
+		}
+	}
+	reg_data = TITAN_GE_READ(TITAN_GE_GMII_CONFIG_GENERAL +
+				(port_num << 12));
+	reg_data |= 0x3;
+	TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_GENERAL +
+			(port_num << 12)), reg_data);
+}
+
+/*
+ * Enable the TMAC if it is not
+ */
+static void titan_ge_enable_tx(unsigned int port_num)
+{
+	unsigned long reg_data;
+
+	reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 +
+				(port_num << 12));
+	if (!(reg_data & 0x8000)) {
+		printk("TMAC disabled for port %d!! \n", port_num);
+
+		reg_data |= 0x0001;	/* Enable TMAC */
+		reg_data |= 0x4000;	/* CRC Check Enable */
+		reg_data |= 0x2000;	/* Padding enable */
+		reg_data |= 0x0800;	/* CRC Add enable */
+		reg_data |= 0x0080;	/* PAUSE frame */
+
+		TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 +
+				(port_num << 12)), reg_data);
+	}
+}
+
+/*
+ * Tx Timeout function
+ */
+static void titan_ge_tx_timeout(struct net_device *netdev)
+{
+	titan_ge_port_info *titan_ge_eth = netdev->priv;
+
+	printk(KERN_INFO "%s: TX timeout  ", netdev->name);
+	printk(KERN_INFO "Resetting card \n");
+
+	/* Do the reset outside of interrupt context */
+	schedule_task(&titan_ge_eth->tx_timeout_task);
+}
+
+/*
+ * Update the AFX tables for UC and MC for slice 0 only
+ */
+static void titan_ge_update_afx(titan_ge_port_info * titan_ge_eth)
+{
+	unsigned int i;
+	volatile unsigned long reg_data = 0;
+	u8 p_addr[6];
+	int port = titan_ge_eth->port_num;
+
+	memcpy(p_addr, titan_ge_eth->port_mac_addr, 6);
+
+	/* Set the MAC address here for TMAC and RMAC */
+        TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_HI + (port << 12)),
+                       ((p_addr[5] << 8) | p_addr[4]));
+        TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_MID + (port << 12)),
+                       ((p_addr[3] << 8) | p_addr[2]));
+        TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_LOW + (port << 12)), 
+                       ((p_addr[1] << 8) | p_addr[0]));
+
+        TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_HI + (port << 12)),
+                       ((p_addr[5] << 8) | p_addr[4]));
+        TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_MID + (port << 12)),
+                       ((p_addr[3] << 8) | p_addr[2]));
+        TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_LOW + (port << 12)),
+                       ((p_addr[1] << 8) | p_addr[0]));
+
+	TITAN_GE_WRITE((0x112c | (port << 12)), 0x1);
+	/* Configure the eight address filters */
+	for (i = 0; i < 8; i++) {
+		/* Select each of the eight filters */
+		TITAN_GE_WRITE((TITAN_GE_AFX_ADDRS_FILTER_CTRL_2 +
+				(port << 12)), i);
+
+		/* Configure the match */
+		reg_data = 0x9;	/* Forward Enable Bit */
+		TITAN_GE_WRITE((TITAN_GE_AFX_ADDRS_FILTER_CTRL_0 +
+				(port << 12)), reg_data);
+
+		/* Finally, AFX Exact Match Address Registers */
+		TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_LOW + (port << 12)),
+			       ((p_addr[1] << 8) | p_addr[0]));
+		TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_MID + (port << 12)),
+			       ((p_addr[3] << 8) | p_addr[2]));
+		TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_HIGH + (port << 12)),
+			       ((p_addr[5] << 8) | p_addr[4]));
+
+		/* VLAN id set to 0 */
+		TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_VID + 
+				(port << 12)), 0);
+	}
+}
+
+/*
+ * Actual Routine to reset the adapter when the timeout occurred
+ */
+static void titan_ge_tx_timeout_task(struct net_device *netdev)
+{
+	titan_ge_port_info *titan_ge_eth = netdev->priv;
+	int port = titan_ge_eth->port_num;
+
+	printk("Titan GE: Transmit timed out. Resetting ... \n");
+
+	/* Dump debug info */
+	printk(KERN_ERR "TRTG cause : %x \n",
+			(unsigned long)TITAN_GE_READ(0x100c + (port << 12)));
+
+	/* Fix this for the other ports */
+	printk(KERN_ERR "FIFO cause : %x \n",
+			(unsigned long)TITAN_GE_READ(0x482c));
+	printk(KERN_ERR "IE cause : %x \n",
+			(unsigned long)TITAN_GE_READ(0x0040));
+	printk(KERN_ERR "XDMA GDI ERROR : %x \n",
+			(unsigned long)TITAN_GE_READ(0x5008 + (port << 8)));
+	printk(KERN_ERR "CHANNEL ERROR: %x \n",
+			(unsigned long)TITAN_GE_READ(TITAN_GE_CHANNEL0_INTERRUPT
+						+ (port << 8)));	
+
+	netif_device_detach(netdev);
+	titan_ge_port_reset(titan_ge_eth->port_num);
+	titan_ge_port_start(netdev, titan_ge_eth);
+	netif_device_attach(netdev);
+}
+
+/*
+ * Change the MTU of the Ethernet Device
+ */
+static int titan_ge_change_mtu(struct net_device *netdev, int new_mtu)
+{
+	titan_ge_port_info *titan_ge_eth;
+	unsigned int port_num;
+	unsigned long flags;
+
+	titan_ge_eth = netdev->priv;
+	port_num = titan_ge_eth->port_num;
+
+	spin_lock_irqsave(&titan_ge_eth->lock, flags);
+
+	if ((new_mtu > 9500) || (new_mtu < 64)) {
+		spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
+		return -EINVAL;
+	}
+
+	netdev->mtu = new_mtu;
+
+	/* Now we have to reopen the interface so that SKBs with the new
+	 * size will be allocated */
+
+	if (netif_running(netdev)) {
+		if (titan_ge_eth_stop(netdev) != TITAN_OK) {
+			printk(KERN_ERR
+			       "%s: Fatal error on stopping device\n",
+			       netdev->name);
+			spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
+			return -1;
+		}
+
+		if (titan_ge_eth_open(netdev) != TITAN_OK) {
+			printk(KERN_ERR
+			       "%s: Fatal error on opening device\n",
+			       netdev->name);
+			spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
+			return -1;
+		}
+	}
+
+	spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
+	return 0;
+}
+
+/*
+ * Reset the XDMA unit due to errors
+ */
+static void titan_ge_xdma_reset(void)
+{
+       unsigned long   reg_data;
+
+       reg_data = TITAN_GE_READ(TITAN_GE_XDMA_CONFIG);
+       reg_data |= 0x80000000;
+       TITAN_GE_WRITE(TITAN_GE_XDMA_CONFIG, reg_data);
+
+       mdelay(2);
+
+       reg_data = TITAN_GE_READ(TITAN_GE_XDMA_CONFIG);
+       reg_data &= ~(0x80000000);
+       TITAN_GE_WRITE(TITAN_GE_XDMA_CONFIG, reg_data);
+}
+
+/*
+ * Titan Gbe Interrupt Handler. All the three ports send interrupt to one line
+ * only. Once an interrupt is triggered, figure out the port and then check
+ * the channel.
+ */
+static irqreturn_t titan_ge_int_handler(int irq, void *dev_id,
+	struct pt_regs *regs)
+{
+	struct net_device *netdev = (struct net_device *) dev_id;
+	titan_ge_port_info *titan_ge_eth;
+	unsigned int port_num, reg_data;
+	unsigned long eth_int_cause_error = 0, is;
+	unsigned long eth_int_cause1;
+	int err = 0;
+#ifdef CONFIG_SMP
+	unsigned long eth_int_cause2;
+#endif
+
+	titan_ge_eth = netdev->priv;
+	port_num = titan_ge_eth->port_num;
+
+	/* Ack the CPU interrupt */
+	if (port_num == 1) {
+#ifdef CONFIG_MIPS64
+		is = *(volatile u_int32_t *)(0xfffffffffb001b00);
+		*(volatile u_int32_t *)(0xfffffffffb001b0c) = is;
+#else
+                is = *(volatile u_int32_t *)(0xfb001b00);
+                *(volatile u_int32_t *)(0xfb001b0c) = is;
+#endif
+
+#ifdef CONFIG_SMP
+#ifdef CONFIG_MIPS64
+		is = *(volatile u_int32_t *)(0xfffffffffb002b00);
+		*(volatile u_int32_t *)(0xfffffffffb002b0c) = is;
+#else
+		is = *(volatile u_int32_t *)(0xfb002b00);
+		*(volatile u_int32_t *)(0xfb002b0c) = is;
+#endif
+#endif
+        }
+
+        if (port_num == 0) {
+#ifdef CONFIG_MIPS64
+		is = *(volatile u_int32_t *)(0xfffffffffb001b10);
+		*(volatile u_int32_t *)(0xfffffffffb001b1c) = is;
+#else
+                is = *(volatile u_int32_t *)(0xfb001b10);
+                *(volatile u_int32_t *)(0xfb001b1c) = is;
+#endif
+
+#ifdef CONFIG_SMP
+#ifdef CONFIG_MIPS64
+		is = *(volatile u_int32_t *)(0xfffffffffb002b10);
+		*(volatile u_int32_t *)(0xfffffffffb002b1c) = is;
+#else
+		is = *(volatile u_int32_t *)(0xfb002b10);
+		*(volatile u_int32_t *)(0xfb002b1c) = is;
+#endif
+#endif
+        }
+
+	eth_int_cause1 = TITAN_GE_READ(TITAN_GE_INTR_XDMA_CORE_A);
+#ifdef CONFIG_SMP
+	eth_int_cause2 = TITAN_GE_READ(TITAN_GE_INTR_XDMA_CORE_B);
+#endif
+
+	/* Spurious interrupt */
+#ifdef CONFIG_SMP
+	if ( (eth_int_cause1 == 0) && (eth_int_cause2 == 0)) {
+#else
+	if (eth_int_cause1 == 0) {
+#endif
+		eth_int_cause_error = TITAN_GE_READ(TITAN_GE_CHANNEL0_INTERRUPT +
+					(port_num << 8));
+
+		if (eth_int_cause_error == 0)
+			return IRQ_NONE;
+	}
+
+	/* Handle Tx first. No need to ack interrupts */
+#ifdef CONFIG_SMP
+	if ( (eth_int_cause1 & 0x20202) || 
+		(eth_int_cause2 & 0x20202) )
+#else
+	if (eth_int_cause1 & 0x20202) 
+#endif
+		titan_ge_free_tx_queue(titan_ge_eth);
+		
+#ifdef TITAN_RX_NAPI
+	/* Handle the Rx next */
+#ifdef CONFIG_SMP
+	if ( (eth_int_cause1 & 0x10101) ||
+		(eth_int_cause2 & 0x10101)) {
+#else
+	if (eth_int_cause1 & 0x10101) {
+#endif
+		if (netif_rx_schedule_prep(netdev)) {
+			unsigned int ack;
+	
+			ack = TITAN_GE_READ(TITAN_GE_INTR_XDMA_IE);
+			/* Disable Tx and Rx both */
+			if (port_num == 0) 
+				ack &= ~(0x3);
+			if (port_num == 1) 
+				ack &= ~(0x300);
+
+			if (port_num == 2)
+				ack &= ~(0x30000);
+
+			/* Interrupts have been disabled */
+			TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, ack);
+
+			__netif_rx_schedule(netdev);
+		}
+	}
+#else
+	titan_ge_free_tx_queue(titan_ge_eth);
+	count = titan_ge_receive_queue(netdev, 0);
+
+#endif
+	/* Handle error interrupts */
+        if (eth_int_cause_error && 
+		(eth_int_cause_error != 0x2)) {
+		printk(KERN_ERR
+			"XDMA Channel Error : %x  on port %d\n",
+			eth_int_cause_error, port_num);
+
+		printk(KERN_ERR
+			"XDMA GDI Hardware error : %x  on port %d\n",
+			TITAN_GE_READ(0x5008 + (port_num << 8)), port_num);
+
+		printk(KERN_ERR
+			"XDMA currently has %d Rx descriptors \n",
+			TITAN_GE_READ(0x5048 + (port_num << 8)));
+
+		printk(KERN_ERR
+			"XDMA currently has prefetcted %d Rx descriptors \n",
+			TITAN_GE_READ(0x505c + (port_num << 8)));
+	
+                TITAN_GE_WRITE((TITAN_GE_CHANNEL0_INTERRUPT +
+                               (port_num << 8)), eth_int_cause_error);
+        }
+
+	/*
+	 * PHY interrupt to inform abt the changes. Reading the 
+	 * PHY Status register will clear the interrupt
+	 */
+	if ((!(eth_int_cause1 & 0x30303)) && 
+		(eth_int_cause_error == 0)) {
+		err =
+		    titan_ge_mdio_read(port_num,
+			       TITAN_GE_MDIO_PHY_IS, &reg_data);
+
+		if (reg_data & 0x0400) {
+			/* Link status change */
+			titan_ge_mdio_read(port_num,
+				   TITAN_GE_MDIO_PHY_STATUS, &reg_data);
+			if (!(reg_data & 0x0400)) {
+				/* Link is down */
+				netif_carrier_off(netdev);
+				netif_stop_queue(netdev);
+			} else {
+				/* Link is up */
+				netif_carrier_on(netdev);
+				netif_wake_queue(netdev);
+
+				/* Enable the queue */
+				titan_ge_enable_tx(port_num);
+			}
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * Multicast and Promiscuous mode set. The 
+ * set_multi entry point is called whenever the 
+ * multicast address list or the network interface 
+ * flags are updated.
+ */
+static void titan_ge_set_multi(struct net_device *netdev)
+{
+	unsigned long reg_data;
+	unsigned int port_num;
+	titan_ge_port_info *titan_ge_eth;
+
+	titan_ge_eth = netdev->priv;
+	port_num = titan_ge_eth->port_num;
+
+	reg_data = TITAN_GE_READ(TITAN_GE_AFX_ADDRS_FILTER_CTRL_1 + 
+				(port_num << 12));
+
+	if (netdev->flags & IFF_PROMISC) {
+		reg_data |= 0x2;
+	}
+	else if (netdev->flags & IFF_ALLMULTI) {
+		reg_data |= 0x01;
+		reg_data |= 0x400; /* Use the 64-bit Multicast Hash bin */
+	}
+	else {
+		reg_data = 0x2;
+	}
+
+	TITAN_GE_WRITE((TITAN_GE_AFX_ADDRS_FILTER_CTRL_1 + 
+			(port_num << 12)), reg_data);
+	if (reg_data & 0x01) {
+		TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_LOW +
+				(port_num << 12)), 0xffff);
+		TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_MIDLOW +
+				(port_num << 12)), 0xffff);
+		TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_MIDHI +
+				(port_num << 12)), 0xffff);
+		TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_HI +
+				(port_num << 12)), 0xffff);
+	}
+}
+
+/*
+ * Open the network device
+ */
+static int titan_ge_open(struct net_device *netdev)
+{
+	int retval;
+	titan_ge_port_info *titan_ge_eth;
+	unsigned int port_num;
+
+	titan_ge_eth = netdev->priv;
+	port_num = titan_ge_eth->port_num;
+
+	retval = request_irq(TITAN_ETH_PORT_IRQ - port_num, titan_ge_int_handler,
+		     SA_INTERRUPT | SA_SAMPLE_RANDOM , netdev->name, netdev);
+
+	if (retval != 0) {
+		printk(KERN_ERR "Cannot assign IRQ number to TITAN GE \n");
+		return -1;
+	} else {
+		netdev->irq = TITAN_ETH_PORT_IRQ - port_num;
+		printk(KERN_INFO "Assigned IRQ %d to port %d\n", 
+				netdev->irq, port_num);
+	}
+
+	spin_lock_irq(&(titan_ge_eth->lock));
+
+	if (titan_ge_eth_open(netdev) != TITAN_OK) {
+		printk("%s: Error opening interface \n", netdev->name);
+		spin_unlock_irq(&(titan_ge_eth->lock));
+		free_irq(netdev->irq, netdev);
+		return -EBUSY;
+	}
+
+	SET_MODULE_OWNER(netdev);
+	spin_unlock_irq(&(titan_ge_eth->lock));
+	return 0;
+}
+
+/*
+ * Return the Rx buffer back to the Rx ring
+ */
+static int titan_ge_rx_return_buff(titan_ge_port_info * titan_ge_port,
+					struct sk_buff *skb)
+{
+	int rx_used_desc;
+	volatile titan_ge_rx_desc *rx_desc;
+
+	rx_used_desc = titan_ge_port->rx_used_desc_q;
+	rx_desc = &(titan_ge_port->rx_desc_area[rx_used_desc]);
+
+#ifdef TITAN_GE_JUMBO_FRAMES
+	rx_desc->buffer_addr =
+               pci_map_single(0, skb->data, TITAN_GE_JUMBO_BUFSIZE - 2,
+                                            PCI_DMA_FROMDEVICE);
+#else
+	rx_desc->buffer_addr = 
+                pci_map_single(0, skb->data, TITAN_GE_STD_BUFSIZE - 2,
+                                            PCI_DMA_FROMDEVICE);
+#endif
+
+	titan_ge_port->rx_skb[rx_used_desc] = skb;
+	rx_desc->cmd_sts = TITAN_GE_RX_BUFFER_OWNED;
+
+	titan_ge_port->rx_used_desc_q =
+    	(rx_used_desc + 1) % TITAN_GE_RX_QUEUE;
+
+	return TITAN_OK;
+}
+
+/*
+ * Allocate the SKBs for the Rx ring. Also used 
+ * for refilling the queue
+ */
+static int titan_ge_rx_task(struct net_device *netdev, 
+				titan_ge_port_info *titan_ge_eth)
+{
+	struct sk_buff *skb;
+	int count = 0;
+
+	while (titan_ge_eth->rx_ring_skbs < titan_ge_eth->rx_ring_size) {
+
+	/* First try to get the skb from the recycler */
+#ifdef TITAN_GE_JUMBO_FRAMES
+		skb = titan_ge_alloc_skb(TITAN_GE_JUMBO_BUFSIZE, GFP_ATOMIC);
+#else	
+		skb = titan_ge_alloc_skb(TITAN_GE_STD_BUFSIZE, GFP_ATOMIC);
+#endif
+		if (!skb) {	
+			/* OOM, set the flag */
+			printk("OOM \n");
+			oom_flag = 1;
+			break;
+		}
+		count++;
+		skb->dev = netdev;
+
+		titan_ge_eth->rx_ring_skbs++;
+
+		if (titan_ge_rx_return_buff(titan_ge_eth, skb) !=
+		    TITAN_OK) {
+			printk(KERN_ERR "%s: Error allocating RX Ring\n",
+		       		netdev->name);
+			break;
+		}
+	}
+
+	return count;
+}
+
+/*
+ * Actual init of the Tital GE port. There is one register for 
+ * the channel configuration
+ */
+static void titan_port_init(struct net_device *netdev,
+			    titan_ge_port_info * titan_ge_eth)
+{
+	unsigned long reg_data;
+	
+	titan_ge_port_reset(titan_ge_eth->port_num);
+
+	/* First reset the TMAC */
+	reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG);
+	reg_data |= 0x80000000;
+	TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data);
+
+	udelay(30);
+
+	reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG);
+	reg_data &= ~(0xc0000000);
+	TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data);
+
+	/* Now reset the RMAC */
+	reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG);
+	reg_data |= 0x00080000;
+	TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data);
+
+	udelay(30);
+
+	reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG);
+	reg_data &= ~(0x000c0000);
+	TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data);
+}
+
+/*
+ * Start the port. All the hardware specific configuration
+ * for the XDMA, Tx FIFO, Rx FIFO, TMAC, RMAC, TRTG and AFX
+ * go here
+ */
+static int titan_ge_port_start(struct net_device *netdev,
+				titan_ge_port_info * titan_port)
+{
+	volatile unsigned long reg_data, reg_data1;
+	int count = 0;
+	int port_num = titan_port->port_num;
+	unsigned long reg_data_1;
+
+	if (config_done == 0) {
+		reg_data = TITAN_GE_READ(0x0004);
+		reg_data |= 0x100;
+		TITAN_GE_WRITE(0x0004, reg_data);
+
+		reg_data &= ~(0x100);
+		TITAN_GE_WRITE(0x0004, reg_data);
+
+		/* Turn on GMII/MII mode and turn off TBI mode */
+		reg_data = TITAN_GE_READ(TITAN_GE_TSB_CTRL_1);
+        	reg_data |= 0x00000700;
+		reg_data &= ~(0x00800000); /* Fencing */
+#ifdef TITAN_RX_NAPI
+		TITAN_GE_WRITE(0x000c, 0x00001100);
+#else
+		TITAN_GE_WRITE(0x000c, 0x00000100); /* No WCIMODE */
+#endif
+	        TITAN_GE_WRITE(TITAN_GE_TSB_CTRL_1, reg_data);
+
+		/* Set the CPU Resource Limit register */
+		TITAN_GE_WRITE(0x00f8, 0x8); 
+
+		/* Be conservative when using the BIU buffers */
+		TITAN_GE_WRITE(0x0068, 0x4);
+	}
+
+#ifdef TITAN_RX_NAPI
+	titan_port->tx_threshold = 0;
+	titan_port->rx_threshold = 0;
+#endif
+
+	/* We need to write the descriptors for Tx and Rx */
+        TITAN_GE_WRITE((TITAN_GE_CHANNEL0_TX_DESC + (port_num << 8)),
+                       (unsigned long) titan_port->tx_dma);
+        TITAN_GE_WRITE((TITAN_GE_CHANNEL0_RX_DESC + (port_num << 8)),
+                       (unsigned long) titan_port->rx_dma);
+
+	if (config_done == 0) {
+		/* Step 1:  XDMA config	*/
+	        reg_data = TITAN_GE_READ(TITAN_GE_XDMA_CONFIG);
+		reg_data &= ~(0x80000000);      /* clear reset */
+       		reg_data |= 0x1 << 29;	/* sparse tx descriptor spacing */
+		reg_data |= 0x1 << 28;	/* sparse rx descriptor spacing */
+		reg_data |= (0x1 << 23) | (0x1 << 24);  /* Descriptor Coherency */ 
+		reg_data |= (0x1 << 21) | (0x1 << 22);  /* Data Coherency */
+		TITAN_GE_WRITE(TITAN_GE_XDMA_CONFIG, reg_data);
+	}
+
+	/* IR register for the XDMA */
+	reg_data = TITAN_GE_READ(TITAN_GE_GDI_INTERRUPT_ENABLE + (port_num << 8));
+       	reg_data |= 0x80068000; /* No Rx_OOD */
+       	TITAN_GE_WRITE((TITAN_GE_GDI_INTERRUPT_ENABLE + (port_num << 8)), reg_data);
+
+	/* Start the Tx and Rx XDMA controller */
+	reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG + (port_num << 8));
+	reg_data &= 0x4fffffff;     /* Clear tx reset */
+	reg_data &= 0xfff4ffff;     /* Clear rx reset */
+
+#ifdef TITAN_GE_JUMBO_FRAMES
+	reg_data |= 0xa0 | 0x30030000;
+#else
+	reg_data |= 0x40 | 0x20030000;
+#endif
+
+#ifndef CONFIG_SMP
+	reg_data &= ~(0x10);
+	reg_data |= 0x0f; /* All of the packet */
+#endif
+
+        TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG + (port_num << 8)), reg_data);
+
+	/* Rx desc count */
+	count = titan_ge_rx_task(netdev, titan_port);
+	TITAN_GE_WRITE((0x5048 + (port_num << 8)), count);
+	count = TITAN_GE_READ(0x5048 + (port_num << 8));
+
+	udelay(30);
+
+	/* 
+	 * Step 2:  Configure the SDQPF, i.e. FIFO 
+	 */
+	if (config_done == 0) {
+		reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_RXFIFO_CTL);
+		reg_data = 0x1;
+		TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_CTL, reg_data);
+		reg_data &= ~(0x1);
+		TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_CTL, reg_data);
+		reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_RXFIFO_CTL);
+		TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_CTL, reg_data);
+
+		reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_TXFIFO_CTL);
+		reg_data = 0x1;
+		TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_CTL, reg_data);
+		reg_data &= ~(0x1);
+        	TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_CTL, reg_data);
+		reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_TXFIFO_CTL);
+        	TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_CTL, reg_data);
+	}
+	/* 
+	 * Enable RX FIFO 0, 4 and 8 
+	 */
+	if (port_num == 0) {
+		reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_RXFIFO_0);
+	
+		reg_data |= 0x100000;
+		reg_data |= (0xff << 10);
+
+		TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_0, reg_data);
+		/* 
+		 * BAV2,BAV and DAV settings for the Rx FIFO 
+		 */
+        	reg_data1 = TITAN_GE_READ(0x4844);
+	       	reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1);
+        	TITAN_GE_WRITE(0x4844, reg_data1);
+
+		reg_data &= ~(0x00100000);
+		reg_data |= 0x200000;
+
+		TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_0, reg_data);
+
+		reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_TXFIFO_0);
+		reg_data |= 0x100000;
+
+		TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_0, reg_data);
+
+		reg_data |= (0xff << 10);
+
+		TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_0, reg_data);
+	
+		/* 
+		 * BAV2, BAV and DAV settings for the Tx FIFO 
+		 */
+	        reg_data1 = TITAN_GE_READ(0x4944);
+		reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10);
+
+	        TITAN_GE_WRITE(0x4944, reg_data1);
+	
+		reg_data &= ~(0x00100000);
+		reg_data |= 0x200000;
+
+		TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_0, reg_data);
+
+	}
+
+	if (port_num == 1) {
+		reg_data = TITAN_GE_READ(0x4870);
+
+		reg_data |= 0x100000;
+		reg_data |= (0xff << 10) | (0xff + 1);
+
+		TITAN_GE_WRITE(0x4870, reg_data);
+		/*
+		 * BAV2,BAV and DAV settings for the Rx FIFO
+		 */
+		reg_data1 = TITAN_GE_READ(0x4874);
+		reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1);
+		TITAN_GE_WRITE(0x4874, reg_data1);
+
+		reg_data &= ~(0x00100000);
+		reg_data |= 0x200000;
+
+		TITAN_GE_WRITE(0x4870, reg_data);
+
+		reg_data = TITAN_GE_READ(0x494c);
+		reg_data |= 0x100000;
+
+		TITAN_GE_WRITE(0x494c, reg_data);
+		reg_data |= (0xff << 10) | (0xff + 1);
+		TITAN_GE_WRITE(0x494c, reg_data);
+
+		/*
+		 * BAV2, BAV and DAV settings for the Tx FIFO
+		 */
+		reg_data1 = TITAN_GE_READ(0x4950);
+		reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10);
+
+		TITAN_GE_WRITE(0x4950, reg_data1);
+
+		reg_data &= ~(0x00100000);
+		reg_data |= 0x200000;
+
+		TITAN_GE_WRITE(0x494c, reg_data);
+	}
+
+	/*
+	 * Titan 1.2 revision does support port #2
+	 */
+	if (port_num == 2) {
+		/*
+		 * Put the descriptors in the SRAM
+		 */
+		reg_data = TITAN_GE_READ(0x48a0);
+
+		reg_data |= 0x100000;
+		reg_data |= (0xff << 10) | (2*(0xff + 1));
+
+		TITAN_GE_WRITE(0x48a0, reg_data);
+		/*
+		 * BAV2,BAV and DAV settings for the Rx FIFO
+		 */
+		reg_data1 = TITAN_GE_READ(0x48a4);
+		reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1);
+		TITAN_GE_WRITE(0x48a4, reg_data1);
+
+		reg_data &= ~(0x00100000);
+		reg_data |= 0x200000;
+
+		TITAN_GE_WRITE(0x48a0, reg_data);
+		
+		reg_data = TITAN_GE_READ(0x4958);
+		reg_data |= 0x100000;
+
+		TITAN_GE_WRITE(0x4958, reg_data);
+		reg_data |= (0xff << 10) | (2*(0xff + 1));
+		TITAN_GE_WRITE(0x4958, reg_data);
+
+		/*
+		 * BAV2, BAV and DAV settings for the Tx FIFO
+		 */
+		reg_data1 = TITAN_GE_READ(0x495c);
+		reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10);
+
+		TITAN_GE_WRITE(0x495c, reg_data1);
+
+		reg_data &= ~(0x00100000);
+		reg_data |= 0x200000;
+
+		TITAN_GE_WRITE(0x4958, reg_data);
+	}
+
+	if (port_num == 2) {
+		reg_data = TITAN_GE_READ(0x48a0);
+
+		reg_data |= 0x100000;
+		reg_data |= (0xff << 10) | (2*(0xff + 1));
+
+		TITAN_GE_WRITE(0x48a0, reg_data);
+		/*
+		 * BAV2,BAV and DAV settings for the Rx FIFO
+		 */
+		reg_data1 = TITAN_GE_READ(0x48a4);
+		reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1);
+		TITAN_GE_WRITE(0x48a4, reg_data1);
+
+		reg_data &= ~(0x00100000);
+		reg_data |= 0x200000;
+
+		TITAN_GE_WRITE(0x48a0, reg_data);
+
+		reg_data = TITAN_GE_READ(0x4958);
+		reg_data |= 0x100000;
+
+		TITAN_GE_WRITE(0x4958, reg_data);
+		reg_data |= (0xff << 10) | (2*(0xff + 1));
+		TITAN_GE_WRITE(0x4958, reg_data);
+
+		/*
+		 * BAV2, BAV and DAV settings for the Tx FIFO
+		 */
+		reg_data1 = TITAN_GE_READ(0x495c);
+		reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10);
+
+		TITAN_GE_WRITE(0x495c, reg_data1);
+
+		reg_data &= ~(0x00100000);
+		reg_data |= 0x200000;
+
+		TITAN_GE_WRITE(0x4958, reg_data);
+	}
+
+	/* 
+	 * Step 3:  TRTG block enable 
+	 */
+	reg_data = TITAN_GE_READ(TITAN_GE_TRTG_CONFIG + (port_num << 12));
+	/*
+	 * This is the 1.2 revision of the chip. It has fix for the
+	 * IP header alignment. Now, the IP header begins at an
+	 * aligned address and this wont need an extra copy in the
+	 * driver. This performance drawback existed in the previous
+	 * versions of the silicon
+	 */
+	reg_data_1 = TITAN_GE_READ(0x103c + (port_num << 12));
+	reg_data_1 |= 0x40000000;
+	TITAN_GE_WRITE((0x103c + (port_num << 12)), reg_data_1);
+
+	reg_data_1 |= 0x04000000;
+	TITAN_GE_WRITE((0x103c + (port_num << 12)), reg_data_1);
+
+	mdelay(5);
+
+	reg_data_1 &= ~(0x04000000);
+	TITAN_GE_WRITE((0x103c + (port_num << 12)), reg_data_1);
+
+	mdelay(5);
+
+	reg_data |= 0x0001; 
+	TITAN_GE_WRITE((TITAN_GE_TRTG_CONFIG + (port_num << 12)), reg_data);
+
+	/* 
+	 * Step 4:  Start the Tx activity 
+	 */
+	TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_2 + (port_num << 12)), 0xe197);
+#ifdef TITAN_GE_JUMBO_FRAMES
+	TITAN_GE_WRITE((0x1258 + (port_num << 12)), 0x4000);
+#endif
+	reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 + (port_num << 12));
+	reg_data |= 0x0001;	/* Enable TMAC */
+	reg_data |= 0x6c70;	/* PAUSE also set */
+
+	TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 + (port_num << 12)), reg_data);
+
+	udelay(30);
+
+	/* Destination Address drop bit */
+        reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_2 + (port_num << 12));
+        reg_data |= 0x218;        /* DA_DROP bit and pause */
+        TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_2 + (port_num << 12)), reg_data);
+
+	TITAN_GE_WRITE((0x1218 + (port_num << 12)), 0x3);
+
+#ifdef TITAN_GE_JUMBO_FRAMES
+	TITAN_GE_WRITE((0x1208 + (port_num << 12)), 0x4000);
+#endif
+	/* Start the Rx activity */
+	reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 + (port_num << 12));
+	reg_data |= 0x0001;	/* RMAC Enable */
+	reg_data |= 0x0010;	/* CRC Check enable */
+	reg_data |= 0x0040;	/* Min Frame check enable */
+	reg_data |= 0x4400;	/* Max Frame check enable */
+
+	TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 + (port_num << 12)), reg_data);
+
+	udelay(30);
+
+	/* 
+	 * Enable the Interrupts for Tx and Rx 
+	 */
+	reg_data1 = TITAN_GE_READ(TITAN_GE_INTR_XDMA_IE);
+
+	if (port_num == 0) {
+		reg_data1 |= 0x3;
+#ifdef CONFIG_SMP
+		TITAN_GE_WRITE(0x0038, 0x003);
+#else
+		TITAN_GE_WRITE(0x0038, 0x303);
+#endif
+	}
+
+	if (port_num == 1) {
+		reg_data1 |= 0x300;
+	}
+
+	if (port_num == 2)
+		reg_data1 |= 0x30000;
+
+	TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, reg_data1);
+	TITAN_GE_WRITE(0x003c, 0x300);
+	
+	if (config_done == 0) {
+		TITAN_GE_WRITE(0x0024, 0x04000024);	/* IRQ vector */
+		TITAN_GE_WRITE(0x0020, 0x000fb000);	/* INTMSG base */
+	}
+
+	/* Priority */
+	reg_data = TITAN_GE_READ(0x1038 + (port_num << 12));
+	reg_data &= ~(0x00f00000);
+	TITAN_GE_WRITE((0x1038 + (port_num << 12)), reg_data);
+
+	/* Step 5:  GMII config */
+	titan_ge_gmii_config(port_num);
+
+	if (config_done == 0) {
+		TITAN_GE_WRITE(0x1a80, 0);
+		config_done = 1;
+	}
+
+	return TITAN_OK;
+}
+
+/*
+ * Function to queue the packet for the Ethernet device
+ */
+static void titan_ge_tx_queue(titan_ge_port_info * titan_ge_eth,
+				struct sk_buff * skb)
+{
+	volatile titan_ge_tx_desc *tx_curr;
+	int port_num = titan_ge_eth->port_num;
+	unsigned int curr_desc =
+			titan_ge_eth->tx_curr_desc_q;
+
+	tx_curr = &(titan_ge_eth->tx_desc_area[curr_desc]);
+	tx_curr->buffer_addr = 
+		pci_map_single(0, skb->data, skb->len - skb->data_len,
+					PCI_DMA_TODEVICE);
+
+	titan_ge_eth->tx_skb[curr_desc] = (struct sk_buff *) skb;
+	tx_curr->buffer_len = skb->len - skb->data_len;
+
+	/* Last descriptor enables interrupt and changes ownership */
+	tx_curr->cmd_sts = 0x1 | (1 << 15) | (1 << 5);
+
+	/* Kick the XDMA to start the transfer from memory to the FIFO */
+        TITAN_GE_WRITE((0x5044 + (port_num << 8)), 0x1);
+
+	/* Current descriptor updated */
+	titan_ge_eth->tx_curr_desc_q = (curr_desc + 1) % TITAN_GE_TX_QUEUE;
+
+	/* Prefetch the next descriptor */
+#ifdef CONFIG_CPU_HAS_PREFETCH
+	rm9000_prefetch(&(titan_ge_eth->tx_desc_area[
+				titan_ge_eth->tx_curr_desc_q]));
+#endif
+}
+
+/*
+ * Actually does the open of the Ethernet device
+ */
+static int titan_ge_eth_open(struct net_device *netdev)
+{
+	titan_ge_port_info *titan_ge_eth;
+	unsigned int port_num, size, phy_reg;
+	unsigned long reg_data;
+	int err = 0;
+
+	titan_ge_eth = netdev->priv;
+	port_num = titan_ge_eth->port_num;
+
+	/* Stop the Rx activity */
+	reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 +
+				(port_num << 12));
+	reg_data &= ~(0x00000001);
+	TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 +
+			(port_num << 12)), reg_data);
+
+	/* Clear the port interrupts */
+	TITAN_GE_WRITE((TITAN_GE_CHANNEL0_INTERRUPT +
+			(port_num << 8)), 0x0);
+
+	if (config_done == 0) {
+		TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0);
+		TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_B, 0);
+	}
+
+	/* Set the MAC Address */
+	memcpy(titan_ge_eth->port_mac_addr, netdev->dev_addr, 6);
+	
+	if (config_done == 0)
+		titan_port_init(netdev, titan_ge_eth);
+
+	titan_ge_update_afx(titan_ge_eth);
+
+	/* Allocate the Tx ring now */
+	titan_ge_eth->tx_ring_skbs = 0;
+	titan_ge_eth->tx_ring_size = TITAN_GE_TX_QUEUE;
+	size = titan_ge_eth->tx_ring_size * sizeof(titan_ge_tx_desc);
+
+	/* Allocate space in the SRAM for the descriptors */
+        if (port_num == 0) {
+                titan_ge_eth->tx_desc_area =
+                    (titan_ge_tx_desc *) (TITAN_GE_SRAM_BASE_VIRTUAL);
+
+                titan_ge_eth->tx_dma = (TITAN_GE_SRAM_BASE_PHYSICAL);
+        }
+
+	if (port_num == 1) {
+		titan_ge_eth->tx_desc_area =
+		    (titan_ge_tx_desc *) (TITAN_GE_SRAM_BASE_VIRTUAL + 0x100);
+		
+		titan_ge_eth->tx_dma = (TITAN_GE_SRAM_BASE_PHYSICAL + 0x100);
+	}
+
+	if (!titan_ge_eth->tx_desc_area) {
+		printk(KERN_ERR
+		       "%s: Cannot allocate Tx Ring (size %d bytes) for port %d\n",
+		       netdev->name, size, port_num);
+		return -ENOMEM;
+	}
+
+	memset((void *) titan_ge_eth->tx_desc_area, 0,
+	       titan_ge_eth->tx_desc_area_size);
+
+	/* Now initialize the Tx descriptor ring */
+	titan_ge_init_tx_desc_ring(titan_ge_eth,
+				   titan_ge_eth->tx_ring_size,
+				   (unsigned long) titan_ge_eth->
+				   tx_desc_area,
+				   (unsigned long) titan_ge_eth->tx_dma);
+
+	/* Allocate the Rx ring now */
+	titan_ge_eth->rx_ring_size = TITAN_GE_RX_QUEUE;
+	titan_ge_eth->rx_ring_skbs = 0;
+	size = titan_ge_eth->rx_ring_size * sizeof(titan_ge_rx_desc);
+
+	if (port_num == 0) {
+		titan_ge_eth->rx_desc_area =
+			(titan_ge_rx_desc *)(TITAN_GE_SRAM_BASE_VIRTUAL + 0x1000);
+
+		titan_ge_eth->rx_dma = (TITAN_GE_SRAM_BASE_PHYSICAL + 0x1000);
+	}
+
+	if (port_num == 1) {
+		titan_ge_eth->rx_desc_area =
+			(titan_ge_rx_desc *)(TITAN_GE_SRAM_BASE_VIRTUAL + 0x1100);
+		titan_ge_eth->rx_dma = (TITAN_GE_SRAM_BASE_PHYSICAL + 0x1100);
+	}
+
+	if (!titan_ge_eth->rx_desc_area) {
+		printk(KERN_ERR
+		       "%s: Cannot allocate Rx Ring (size %d bytes)\n",
+		       netdev->name, size);
+
+		printk(KERN_ERR
+		       "%s: Freeing previously allocated TX queues...",
+		       netdev->name);
+
+		pci_free_consistent(0, titan_ge_eth->tx_desc_area_size,
+				    (void *) titan_ge_eth->tx_desc_area,
+				    titan_ge_eth->tx_dma);
+
+		return -ENOMEM;
+	}
+
+	memset((void *) titan_ge_eth->rx_desc_area, 0,
+	       titan_ge_eth->tx_desc_area_size);
+
+	/* Now initialize the Rx ring */
+#ifdef TITAN_GE_JUMBO_FRAMES
+	if ((titan_ge_init_rx_desc_ring
+	    (titan_ge_eth, titan_ge_eth->rx_ring_size, TITAN_GE_JUMBO_BUFSIZE,
+	     (unsigned long) titan_ge_eth->rx_desc_area, 0,
+	      (unsigned long) titan_ge_eth->rx_dma)) == 0)
+#else
+	if ((titan_ge_init_rx_desc_ring
+	     (titan_ge_eth, titan_ge_eth->rx_ring_size, TITAN_GE_STD_BUFSIZE,
+	      (unsigned long) titan_ge_eth->rx_desc_area, 0,
+	      (unsigned long) titan_ge_eth->rx_dma)) == 0)
+#endif
+		panic("%s: Error initializing RX Ring\n", netdev->name);
+
+	/* Fill the Rx ring with the SKBs */
+	titan_ge_port_start(netdev, titan_ge_eth);
+
+	/* 
+	 * Check if Interrupt Coalscing needs to be turned on. The
+	 * values specified in the register is multiplied by 
+	 * (8 x 64 nanoseconds) to determine when an interrupt should
+	 * be sent to the CPU. 
+	 */
+#ifndef TITAN_RX_NAPI
+	/* 
+	 * If NAPI is turned on, we disable Rx interrupts
+	 * completely. So, we dont need coalescing then. Tx side
+	 * coalescing set to very high value. Maybe, disable
+	 * Tx side interrupts completely
+	 */
+	if (TITAN_GE_RX_COAL) {
+		titan_ge_eth->rx_int_coal =
+		    titan_ge_rx_coal(TITAN_GE_RX_COAL, port_num);
+	} 
+
+#endif
+	if (TITAN_GE_TX_COAL) {
+		titan_ge_eth->tx_int_coal =
+		    titan_ge_tx_coal(TITAN_GE_TX_COAL, port_num);
+	}
+
+	err =
+	    titan_ge_mdio_read(port_num,
+			       TITAN_GE_MDIO_PHY_STATUS, &phy_reg);
+	if (err == TITAN_GE_MDIO_ERROR) {
+		printk(KERN_ERR
+		       "Could not read PHY control register 0x11 \n");
+		return TITAN_ERROR;
+	}
+	if (!(phy_reg & 0x0400)) {
+		netif_carrier_off(netdev);
+		netif_stop_queue(netdev);
+		return TITAN_ERROR;
+	} else {
+		netif_carrier_on(netdev);
+		netif_start_queue(netdev);
+	}
+
+	return TITAN_OK;
+}
+
+/*
+ * Queue the packet for Tx. Currently no support for zero copy, 
+ * checksum offload and Scatter Gather. The chip does support 
+ * Scatter Gather only. But, that wont help here since zero copy 
+ * requires support for Tx checksumming also. 
+ */
+int titan_ge_start_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+	titan_ge_port_info *titan_ge_eth;
+	unsigned long flags;
+	struct net_device_stats *stats;
+	titan_ge_eth = netdev->priv;
+
+	stats = &titan_ge_eth->stats;
+#ifdef CONFIG_SMP
+	spin_lock_irqsave(&titan_ge_eth->lock, flags);
+#else
+	local_irq_save(flags);
+#endif
+
+	if ((TITAN_GE_TX_QUEUE - titan_ge_eth->tx_ring_skbs) <=
+	    (skb_shinfo(skb)->nr_frags + 1)) {
+		netif_stop_queue(netdev);
+#ifdef CONFIG_SMP
+		spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
+#else
+		local_irq_restore(flags);
+#endif
+		printk(KERN_ERR "Tx OOD \n");
+		return 1;
+	}
+
+	titan_ge_tx_queue(titan_ge_eth, skb);
+	titan_ge_eth->tx_ring_skbs++;
+
+	if (TITAN_GE_TX_QUEUE <= (titan_ge_eth->tx_ring_skbs + 4)) {
+#ifdef CONFIG_SMP
+		spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
+#else
+		local_irq_restore(flags);
+#endif
+		titan_ge_free_tx_queue(titan_ge_eth);
+#ifdef CONFIG_SMP
+		spin_lock_irqsave(&titan_ge_eth->lock, flags);
+#else
+		local_irq_save(flags);
+#endif
+	}
+
+	stats->tx_bytes += skb->len;
+	stats->tx_packets++;
+
+#ifdef CONFIG_SMP
+	spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
+#else
+	local_irq_restore(flags);
+#endif
+
+	netdev->trans_start = jiffies;
+
+	return 0;
+}
+
+#ifdef CONFIG_NET_FASTROUTE
+/*
+ * Fast forward function for the fast routing. Helps
+ * in IP forwarding. No semi fast forward since we
+ * have to do that extra copy on the Rx for the IP
+ * header alignment
+ */
+static int titan_ge_fast_forward(struct net_device *dev, 
+			struct sk_buff *skb, int len)
+{
+	titan_ge_port_info *titan_ge_eth = 
+			(titan_ge_port_info *)dev->priv;
+	struct ethhdr *eth = (void*)skb->data;
+
+	if (eth->h_proto == __constant_htons(ETH_P_IP)) {
+		struct rtable *rt;
+		struct iphdr *iph;
+		unsigned h;
+
+		iph = (struct iphdr*)(skb->data + ETH_HLEN);
+		h=(*(u8*)&iph->daddr^*(u8*)&iph->saddr)&NETDEV_FASTROUTE_HMASK;
+		rt = (struct rtable*)(dev->fastpath[h]);
+		if (rt &&
+			((u16*)&iph->daddr)[0] == ((u16*)&rt->key.dst)[0] &&
+			((u16*)&iph->daddr)[1] == ((u16*)&rt->key.dst)[1] &&
+			((u16*)&iph->saddr)[0] == ((u16*)&rt->key.src)[0] &&
+			((u16*)&iph->saddr)[1] == ((u16*)&rt->key.src)[1] &&
+			rt->u.dst.obsolete == 0) {
+				struct net_device *odev = rt->u.dst.dev;
+
+				if (*(u8*)iph != 0x45 ||
+					(eth->h_dest[0]&1) ||
+					!neigh_is_valid(rt->u.dst.neighbour) ||
+					iph->ttl <= 1) {
+						return 1;		
+				}
+				ip_decrease_ttl(iph);
+				skb_put(skb, len);
+
+				memcpy(eth->h_source, odev->dev_addr, 6);
+				memcpy(eth->h_dest, rt->u.dst.neighbour->ha, 6);
+				skb->dev = odev;
+				skb->pkt_type = PACKET_FASTROUTE;
+
+				if (netif_running(odev) &&
+				   (spin_trylock(&odev->xmit_lock))) {
+					if(odev->xmit_lock_owner != 0) {
+						odev->xmit_lock_owner=0;
+					}
+					if (odev->hard_start_xmit(skb,odev) == 0) {
+						odev->xmit_lock_owner=-1;
+						spin_unlock(&odev->xmit_lock);
+						return 0;
+					} 
+				}
+				skb->nh.raw = skb->data + ETH_HLEN;
+				skb->protocol = __constant_htons(ETH_P_IP);
+				return 1;
+			}
+	}
+	return 1;
+}
+
+#endif
+
+/*
+ * Actually does the Rx. Rx side checksumming supported.
+ */
+static int titan_ge_rx(struct net_device *netdev, int port_num,
+			titan_ge_port_info * titan_ge_port,
+		       titan_ge_packet * packet)
+{
+	int rx_curr_desc, rx_used_desc;
+	volatile titan_ge_rx_desc *rx_desc;
+
+	rx_curr_desc = titan_ge_port->rx_curr_desc_q;
+	rx_used_desc = titan_ge_port->rx_used_desc_q;
+
+	if (((rx_curr_desc + 1) % TITAN_GE_RX_QUEUE) == rx_used_desc) 
+		return TITAN_ERROR;
+
+	rx_desc = &(titan_ge_port->rx_desc_area[rx_curr_desc]);
+
+	if (rx_desc->cmd_sts & TITAN_GE_RX_BUFFER_OWNED) 
+		return TITAN_ERROR;
+
+	packet->skb = titan_ge_port->rx_skb[rx_curr_desc];
+	packet->len = (rx_desc->cmd_sts & 0x7fff);
+
+	/* 
+	 * At this point, we dont know if the checksumming 
+	 * actually helps relieve CPU. So, keep it for 
+	 * port 0 only
+	 */
+	packet->checksum = ntohs((rx_desc->buffer & 0xffff0000) >> 16);
+
+	titan_ge_port->rx_curr_desc_q =
+	    (rx_curr_desc + 1) % TITAN_GE_RX_QUEUE;
+	
+	/* Prefetch the next descriptor */
+#ifdef CONFIG_CPU_HAS_PREFETCH
+	rm9000_prefetch(&(titan_ge_port->rx_desc_area[
+			titan_ge_port->rx_curr_desc_q + 1]));
+#endif
+
+	return TITAN_OK;
+}
+
+/*
+ * Free the Tx queue of the used SKBs
+ */
+static int titan_ge_free_tx_queue(titan_ge_port_info *titan_ge_eth)
+{
+	unsigned long flags;
+
+	/* Take the lock */
+#ifdef CONFIG_SMP
+	spin_lock_irqsave(&(titan_ge_eth->lock), flags);
+#else
+	local_irq_save(flags);
+#endif
+
+	while (titan_ge_return_tx_desc(titan_ge_eth, titan_ge_eth->port_num) == 0) 
+		if (titan_ge_eth->tx_ring_skbs != 1)
+			titan_ge_eth->tx_ring_skbs--;
+
+#ifdef CONFIG_SMP
+	spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
+#else
+	local_irq_restore(flags);
+#endif
+
+	return TITAN_OK;
+}
+
+/*
+ * Threshold beyond which we do the cleaning of
+ * Tx queue and new allocation for the Rx 
+ * queue
+ */
+#define	TX_THRESHOLD	4
+#define	RX_THRESHOLD	10
+
+/*
+ * Receive the packets and send it to the kernel. 
+ */
+int titan_ge_receive_queue(struct net_device *netdev, unsigned int max)
+{
+	titan_ge_port_info *titan_ge_eth;
+	unsigned int port_num;
+	titan_ge_packet packet;
+	struct net_device_stats *stats;
+	struct sk_buff *skb;
+	unsigned long received_packets = 0;
+	unsigned int ack;
+
+	titan_ge_eth = netdev->priv;
+	port_num = titan_ge_eth->port_num;
+	stats = &titan_ge_eth->stats;
+
+	while ((--max)
+	       && (titan_ge_rx(netdev, port_num, titan_ge_eth, &packet) == TITAN_OK)) {
+
+		titan_ge_eth->rx_ring_skbs--;
+
+#ifdef TITAN_RX_NAPI
+		if (--titan_ge_eth->rx_work_limit < 0)
+			break;
+		received_packets++;
+#endif
+		stats->rx_packets++;
+		stats->rx_bytes += packet.len;
+
+		if ((packet.cmd_sts & TITAN_GE_RX_PERR) ||
+			(packet.cmd_sts & TITAN_GE_RX_OVERFLOW_ERROR) ||
+			(packet.cmd_sts & TITAN_GE_RX_TRUNC) ||
+			(packet.cmd_sts & TITAN_GE_RX_CRC_ERROR)) {
+				stats->rx_dropped++;
+				dev_kfree_skb_any(skb);
+	
+				continue;
+		}
+		/* 
+		 * Either support fast path or slow path. Decision
+		 * making can really slow down the performance. The
+		 * idea is to cut down the number of checks and improve
+		 * the fastpath.
+		 */
+#ifdef CONFIG_NET_FASTROUTE
+		switch (titan_ge_fast_forward(netdev, 
+				packet.skb, packet.len)) {
+			case 0:
+				goto gone;
+			case 1:
+				break;
+		}
+#endif
+		skb = (struct sk_buff *) packet.skb;
+		/*
+		 * This chip is wierd. Does not have a byte level offset
+		 * to fix the IP header alignment issue. Now, do an extra
+		 * copy only if the custom pattern is not present
+		 */
+		skb_put(skb, packet.len - 2);
+
+		/*
+		 * Increment data pointer by two since thats where
+		 * the MAC starts
+		 */
+		skb_reserve(skb, 2);
+		skb->protocol = eth_type_trans(skb, netdev);
+		netif_receive_skb(skb);
+
+#ifdef CONFIG_NET_FASTROUTE
+gone:
+#endif
+
+#ifdef TITAN_RX_NAPI
+		if (titan_ge_eth->rx_threshold > RX_THRESHOLD) {
+			ack = titan_ge_rx_task(netdev, titan_ge_eth);
+        	        TITAN_GE_WRITE((0x5048 + (port_num << 8)), ack);
+			titan_ge_eth->rx_threshold = 0;
+		} else
+			titan_ge_eth->rx_threshold++;
+#else
+		ack = titan_ge_rx_task(netdev, titan_ge_eth);
+		TITAN_GE_WRITE((0x5048 + (port_num << 8)), ack);
+#endif
+
+#ifdef TITAN_RX_NAPI
+		if (titan_ge_eth->tx_threshold > TX_THRESHOLD) {
+			titan_ge_eth->tx_threshold = 0;
+			titan_ge_free_tx_queue(titan_ge_eth);
+		}
+		else
+			titan_ge_eth->tx_threshold++;
+#endif
+
+	}
+	return received_packets;
+}
+
+
+#ifdef TITAN_RX_NAPI
+
+/*
+ * Enable the Rx side interrupts 
+ */
+static void titan_ge_enable_int(unsigned int port_num,
+			titan_ge_port_info *titan_ge_eth,
+			struct net_device *netdev)
+{
+	unsigned long reg_data = 
+		TITAN_GE_READ(TITAN_GE_INTR_XDMA_IE);
+
+	if (port_num == 0)
+		reg_data |= 0x3;
+	if (port_num == 1)
+		reg_data |= 0x300;
+	if (port_num == 2)
+		reg_data |= 0x30000;
+
+	/* Re-enable interrupts */
+	TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, reg_data);
+}
+
+/*
+ * Main function to handle the polling for Rx side NAPI.
+ * Receive interrupts have been disabled at this point. 
+ * The poll schedules the transmit followed by receive.
+ */	
+static int titan_ge_poll(struct net_device *netdev, int *budget)
+{
+        titan_ge_port_info *titan_ge_eth = netdev->priv;
+        int port_num = titan_ge_eth->port_num; 
+	int work_done = 0; 
+	unsigned long flags, status;
+
+	titan_ge_eth->rx_work_limit = *budget;
+        if (titan_ge_eth->rx_work_limit > netdev->quota)
+                titan_ge_eth->rx_work_limit = netdev->quota;
+
+	do {
+		/* Do the transmit cleaning work here */
+		titan_ge_free_tx_queue(titan_ge_eth);
+
+		/* Ack the Rx interrupts */
+		if (port_num == 0) 
+			TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0x3);
+                if (port_num == 1)
+                        TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0x300);
+                if (port_num == 2)
+                        TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0x30000);
+
+	        work_done += titan_ge_receive_queue(netdev, 0);
+
+		/* Out of quota and there is work to be done */	
+		if (titan_ge_eth->rx_work_limit < 0)
+			goto not_done;			
+
+		/* Receive alloc_skb could lead to OOM */	
+		if (oom_flag == 1) {
+			oom_flag = 0;
+			goto oom;
+		}
+
+		status = TITAN_GE_READ(TITAN_GE_INTR_XDMA_CORE_A);
+	} while (status & 0x30300);
+
+	/* If we are here, then no more interrupts to process */
+	goto done;
+
+not_done:
+	*budget -= work_done;
+	netdev->quota -= work_done;
+	return 1;
+
+oom:
+	printk(KERN_ERR "OOM \n");
+	netif_rx_complete(netdev);
+	return 0;
+
+done:
+	/*
+	 * No more packets on the poll list. Turn the interrupts 
+	 * back on and we should be able to catch the new
+	 * packets in the interrupt handler
+	 */
+	if (!work_done)
+		work_done = 1;
+
+	*budget -= work_done;
+        netdev->quota -= work_done;
+
+#ifdef CONFIG_SMP
+	spin_lock_irqsave(&titan_ge_eth->lock, flags);
+#else
+	local_irq_save(flags);
+#endif
+
+	/* Remove us from the poll list */
+	netif_rx_complete(netdev);
+
+	/* Re-enable interrupts */
+	titan_ge_enable_int(port_num, titan_ge_eth, netdev);
+
+#ifdef CONFIG_SMP
+	spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
+#else
+	local_irq_restore(flags);
+#endif
+
+	return 0;
+}
+#endif
+
+/*
+ * Close the network device
+ */
+int titan_ge_stop(struct net_device *netdev)
+{
+	titan_ge_port_info *titan_ge_eth;
+	unsigned int port_num;
+
+	titan_ge_eth = netdev->priv;
+	port_num = titan_ge_eth->port_num;
+
+	spin_lock_irq(&(titan_ge_eth->lock));
+	titan_ge_eth_stop(netdev);
+	free_irq(netdev->irq, netdev);
+	MOD_DEC_USE_COUNT;
+	spin_unlock_irq(&titan_ge_eth->lock);
+
+	return TITAN_OK;
+}
+
+/*
+ * Free the Tx ring
+ */
+static void titan_ge_free_tx_rings(struct net_device *netdev)
+{
+	titan_ge_port_info *titan_ge_eth;
+	unsigned int port_num, curr;
+	unsigned long reg_data;
+
+	titan_ge_eth = netdev->priv;
+	port_num = titan_ge_eth->port_num;
+
+	/* Stop the Tx DMA */
+	reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG +
+				(port_num << 8));
+	reg_data |= 0xc0000000;
+	TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG +
+			(port_num << 8)), reg_data);
+
+	/* Disable the TMAC */
+	reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 +
+				(port_num << 12));
+	reg_data &= ~(0x00000001);
+	TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 +
+			(port_num << 12)), reg_data);
+
+	for (curr = 0;
+	     (titan_ge_eth->tx_ring_skbs) && (curr < TITAN_GE_TX_QUEUE);
+	     curr++) {
+		if (titan_ge_eth->tx_skb[curr]) {
+			dev_kfree_skb(titan_ge_eth->tx_skb[curr]);
+			titan_ge_eth->tx_ring_skbs--;
+		}
+	}
+
+	if (titan_ge_eth->tx_ring_skbs != 0)
+		printk
+		    ("%s: Error on Tx descriptor free - could not free %d"
+		     " descriptors\n", netdev->name,
+		     titan_ge_eth->tx_ring_skbs);
+
+	pci_free_consistent(0, titan_ge_eth->tx_desc_area_size,
+			    (void *) titan_ge_eth->tx_desc_area,
+			    titan_ge_eth->tx_dma);
+}
+
+/*
+ * Free the Rx ring
+ */
+static void titan_ge_free_rx_rings(struct net_device *netdev)
+{
+	titan_ge_port_info *titan_ge_eth;
+	unsigned int port_num, curr;
+	unsigned long reg_data;
+
+	titan_ge_eth = netdev->priv;
+	port_num = titan_ge_eth->port_num;
+
+	/* Stop the Rx DMA */
+	reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG + 
+				(port_num << 8));
+	reg_data |= 0x000c0000;
+	TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG +
+			(port_num << 8)), reg_data);
+
+	/* Disable the RMAC */
+	reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 +
+				(port_num << 12));
+	reg_data &= ~(0x00000001);
+	TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 +
+			(port_num << 12)), reg_data);
+
+	for (curr = 0;
+	     titan_ge_eth->rx_ring_skbs && (curr < TITAN_GE_RX_QUEUE);
+	     curr++) {
+		if (titan_ge_eth->rx_skb[curr]) {
+			dev_kfree_skb(titan_ge_eth->rx_skb[curr]);
+			titan_ge_eth->rx_ring_skbs--;
+		}
+	}
+
+	if (titan_ge_eth->rx_ring_skbs != 0)
+		printk(KERN_ERR
+		       "%s: Error in freeing Rx Ring. %d skb's still"
+		       " stuck in RX Ring - ignoring them\n", netdev->name,
+		       titan_ge_eth->rx_ring_skbs);
+
+	pci_free_consistent(0, titan_ge_eth->rx_desc_area_size,
+			    (void *) titan_ge_eth->rx_desc_area,
+			    titan_ge_eth->rx_dma);
+}
+
+/*
+ * Actually does the stop of the Ethernet device
+ */
+static int titan_ge_eth_stop(struct net_device *netdev)
+{
+	titan_ge_port_info *titan_ge_eth;
+	unsigned int port_num;
+
+	titan_ge_eth = netdev->priv;
+	port_num = titan_ge_eth->port_num;
+
+	netif_stop_queue(netdev);
+
+	titan_ge_port_reset(titan_ge_eth->port_num);
+
+	titan_ge_free_tx_rings(netdev);
+	titan_ge_free_rx_rings(netdev);
+
+	/* Disable the Tx and Rx Interrupts for all channels */
+	TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, 0x0);
+
+	return TITAN_OK;
+}
+
+/*
+ * Update the MAC address. Note that we have to write the 
+ * address in three station registers, 16 bits each. And this 
+ * has to be done for TMAC and RMAC
+ */
+static void titan_ge_update_mac_address(struct net_device *netdev)
+{
+	titan_ge_port_info *titan_ge_eth = netdev->priv;
+	unsigned int port_num = titan_ge_eth->port_num;
+	u8 p_addr[6];
+
+	memcpy(titan_ge_eth->port_mac_addr, netdev->dev_addr, 6);
+	memcpy(p_addr, netdev->dev_addr, 6);
+
+	/* Update the Address Filtering Match tables */
+	titan_ge_update_afx(titan_ge_eth);
+
+	printk("Station MAC : %d %d %d %d %d %d  \n", 
+		p_addr[5], p_addr[4], p_addr[3], 
+		p_addr[2], p_addr[1], p_addr[0]);
+
+	/* Set the MAC address here for TMAC and RMAC */
+	TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_HI + (port_num << 12)),
+		       ((p_addr[5] << 8) | p_addr[4]));
+	TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_MID + (port_num << 12)),
+		       ((p_addr[3] << 8) | p_addr[2]));
+	TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_LOW + (port_num << 12)),
+		       ((p_addr[1] << 8) | p_addr[0]));
+
+	TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_HI + (port_num << 12)),
+		       ((p_addr[5] << 8) | p_addr[4]));
+	TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_MID + (port_num << 12)),
+		       ((p_addr[3] << 8) | p_addr[2]));
+	TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_LOW + (port_num << 12)),
+		       ((p_addr[1] << 8) | p_addr[0]));
+
+	return;
+}
+
+/*
+ * Set the MAC address of the Ethernet device
+ */
+int titan_ge_set_mac_address(struct net_device *netdev, void *addr)
+{
+	int i;
+
+	for (i = 0; i < 6; i++)
+		netdev->dev_addr[i] = ((unsigned char *) addr)[i + 2];
+
+	titan_ge_update_mac_address(netdev);
+	return 0;
+}
+
+/*
+ * Get the Ethernet device stats
+ */
+static struct net_device_stats *titan_ge_get_stats(struct net_device
+						   *netdev)
+{
+	titan_ge_port_info *titan_ge_eth;
+	unsigned int port_num;
+
+	titan_ge_eth = netdev->priv;
+	port_num = titan_ge_eth->port_num;
+
+	return &titan_ge_eth->stats;
+}
+
+/*
+ * Register the Titan GE with the kernel
+ */
+static int __init titan_ge_init_module(void)
+{
+	unsigned long version, device;
+
+	printk(KERN_NOTICE
+	       "PMC-Sierra TITAN 10/100/1000 Ethernet Driver \n");
+	device = TITAN_GE_READ(TITAN_GE_DEVICE_ID);
+	version = (device & 0x000f0000) >> 16;
+	device &= 0x0000ffff;
+
+	printk(KERN_NOTICE "Device Id : %x,  Version : %x \n", device,
+	       version);
+
+	/* Register only one port */ 
+	if (titan_ge_init(0)) 
+		printk(KERN_ERR
+		       "Error registering the TITAN Ethernet driver"
+			"for port 0 \n");
+	
+	if (titan_ge_init(1)) 
+		printk(KERN_ERR "Error registering the TITAN Ethernet" 
+				"driver for port 1\n");
+
+	return 0;
+}
+
+/*
+ * Unregister the Titan GE from the kernel
+ */
+static void __init titan_ge_cleanup_module(void)
+{
+	/* Nothing to do here */
+}
+
+module_init(titan_ge_init_module);
+module_exit(titan_ge_cleanup_module);
+
+/*
+ * Initialize the Rx descriptor ring for the Titan Ge
+ */
+static int titan_ge_init_rx_desc_ring(titan_ge_port_info * titan_eth_port,
+				      int rx_desc_num,
+				      int rx_buff_size,
+				      unsigned long rx_desc_base_addr,
+				      unsigned long rx_buff_base_addr,
+				      unsigned long rx_dma)
+{
+	volatile titan_ge_rx_desc *rx_desc;
+	unsigned long buffer_addr;
+	int index;
+	unsigned long titan_ge_rx_desc_bus = rx_dma;
+
+	buffer_addr = rx_buff_base_addr;
+	rx_desc = (titan_ge_rx_desc *) rx_desc_base_addr;
+
+	/* Check alignment */
+	if (rx_buff_base_addr & 0xF)
+		return 0;
+
+	/* Check Rx buffer size */
+	if ((rx_buff_size < 8) || (rx_buff_size > TITAN_GE_MAX_RX_BUFFER))
+		return 0;
+
+	/* 64-bit alignment 
+	if ((rx_buff_base_addr + rx_buff_size) & 0x7)
+		return 0; */
+
+	/* Initialize the Rx desc ring */
+	for (index = 0; index < rx_desc_num; index++) {
+		titan_ge_rx_desc_bus += sizeof(titan_ge_rx_desc);
+		rx_desc[index].cmd_sts = 0;
+		rx_desc[index].buffer_addr = buffer_addr;
+		titan_eth_port->rx_skb[index] = NULL;
+		buffer_addr += rx_buff_size;
+	}
+
+	titan_eth_port->rx_curr_desc_q = 0;
+	titan_eth_port->rx_used_desc_q = 0;
+
+	titan_eth_port->rx_desc_area =
+	    (titan_ge_rx_desc *) rx_desc_base_addr;
+	titan_eth_port->rx_desc_area_size =
+	    rx_desc_num * sizeof(titan_ge_rx_desc);
+	
+	titan_eth_port->rx_dma = rx_dma;
+
+	return TITAN_OK;
+}
+
+/*
+ * Initialize the Tx descriptor ring. Descriptors in the SRAM
+ */
+static int titan_ge_init_tx_desc_ring(titan_ge_port_info * titan_ge_port,
+				      int tx_desc_num,
+				      unsigned long tx_desc_base_addr,
+				      unsigned long tx_dma)
+{
+	titan_ge_tx_desc *tx_desc;
+	int index;
+	unsigned long titan_ge_tx_desc_bus = tx_dma;
+
+	if (tx_desc_base_addr & 0xF)
+		return 0;
+
+	tx_desc = (titan_ge_tx_desc *) tx_desc_base_addr;
+
+	for (index = 0; index < tx_desc_num; index++) {
+		titan_ge_port->tx_dma_array[index] =
+		    (dma_addr_t) titan_ge_tx_desc_bus;
+		titan_ge_tx_desc_bus += sizeof(titan_ge_tx_desc);
+		tx_desc[index].cmd_sts = 0x0000;
+		tx_desc[index].buffer_len = 0;
+		tx_desc[index].buffer_addr = 0x00000000;
+		titan_ge_port->tx_skb[index] = NULL;
+	}
+
+	titan_ge_port->tx_curr_desc_q = 0;
+	titan_ge_port->tx_used_desc_q = 0;
+
+	titan_ge_port->tx_desc_area =
+	    (titan_ge_tx_desc *) tx_desc_base_addr;
+	titan_ge_port->tx_desc_area_size =
+	    tx_desc_num * sizeof(titan_ge_tx_desc);
+
+	titan_ge_port->tx_dma = tx_dma;
+	return TITAN_OK;
+}
+
+/*
+ * Initialize the device as an Ethernet device
+ */
+static int titan_ge_init(int port)
+{
+	titan_ge_port_info *titan_ge_eth;
+	struct net_device *netdev;
+	int err;
+
+	netdev = alloc_etherdev(sizeof(titan_ge_port_info));
+	if (!netdev) {
+		err = -ENODEV;
+		goto out;
+	}
+
+	netdev->open = titan_ge_open;
+	netdev->stop = titan_ge_stop;
+	netdev->hard_start_xmit = titan_ge_start_xmit;
+	netdev->get_stats = titan_ge_get_stats;
+	netdev->set_multicast_list = titan_ge_set_multi;
+	netdev->set_mac_address = titan_ge_set_mac_address;
+
+	/* Tx timeout */
+	netdev->tx_timeout = titan_ge_tx_timeout;
+	netdev->watchdog_timeo = 2 * HZ;
+
+#ifdef TITAN_RX_NAPI
+	/* Set these to very high values */
+	netdev->poll = titan_ge_poll;
+	netdev->weight = 64;
+#endif
+	netdev->tx_queue_len = TITAN_GE_TX_QUEUE;
+	netif_carrier_off(netdev);
+	netdev->base_addr = 0;
+
+#ifdef CONFIG_NET_FASTROUTE
+	netdev->accept_fastpath = titan_accept_fastpath;
+#endif
+
+	netdev->change_mtu = titan_ge_change_mtu;
+
+	titan_ge_eth = netdev->priv;
+	/* Allocation of memory for the driver structures */
+
+	titan_ge_eth->port_num = port;
+
+	memset(&titan_ge_eth->stats, 0, sizeof(struct net_device_stats));
+
+	/* Configure the Tx timeout handler */
+	INIT_TQUEUE(&titan_ge_eth->tx_timeout_task,
+		    (void (*)(void *)) titan_ge_tx_timeout_task, netdev);
+
+	spin_lock_init(&titan_ge_eth->lock);
+
+	/* set MAC addresses */
+	memcpy(netdev->dev_addr, titan_ge_mac_addr_base, 6);
+	netdev->dev_addr[5] += port;
+
+	err = register_netdev(netdev);
+
+        if (err)
+                goto out_free_private;
+
+	printk(KERN_NOTICE
+	       "%s: port %d with MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",
+	       netdev->name, port, netdev->dev_addr[0],
+	       netdev->dev_addr[1], netdev->dev_addr[2],
+	       netdev->dev_addr[3], netdev->dev_addr[4],
+	       netdev->dev_addr[5]);
+
+#ifdef TITAN_RX_NAPI
+	printk(KERN_NOTICE "Rx NAPI supported, Tx Coalescing ON \n");
+#else
+	printk(KERN_NOTICE "Rx and Tx Coalescing ON \n");
+#endif
+
+	/*
+	 * Titan 1.2 does support port #2
+	 */
+	if (titan_ge_init(2))
+		printk(KERN_ERR "Error registering the TITAN Ethernet"
+				"driver for port 2\n");
+
+	return 0;
+
+out_free_private:
+
+out_free_netdev:
+	kfree(netdev);
+
+out:
+	return err;
+}
+
+/*
+ * Reset the Ethernet port
+ */
+static void titan_ge_port_reset(unsigned int port_num)
+{
+	unsigned int reg_data;
+
+	/* Stop the Tx port activity */
+	reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 + 
+				(port_num << 12));
+	reg_data &= ~(0x0001);
+	TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 + 
+			(port_num << 12)), reg_data);
+
+	/* Stop the Rx port activity */
+	reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 + 
+				(port_num << 12));
+	reg_data &= ~(0x0001);
+	TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 + 
+			(port_num << 12)), reg_data);
+
+	return;
+}
+
+/*
+ * Return the Tx desc after use by the XDMA
+ */
+static int titan_ge_return_tx_desc(titan_ge_port_info * titan_ge_eth, int port)
+{
+	int tx_desc_used;
+	struct sk_buff *skb;
+
+	tx_desc_used = titan_ge_eth->tx_used_desc_q;
+
+	/* return right away */
+	if (tx_desc_used == titan_ge_eth->tx_curr_desc_q)
+		return TITAN_ERROR;
+
+	/* Now the critical stuff */
+	skb = titan_ge_eth->tx_skb[tx_desc_used];
+
+	dev_kfree_skb_any(skb);
+
+	titan_ge_eth->tx_skb[tx_desc_used] = NULL;
+	titan_ge_eth->tx_used_desc_q =
+	    (tx_desc_used + 1) % TITAN_GE_TX_QUEUE;
+
+	return 0;
+}
+
+#ifndef TITAN_RX_NAPI
+/*
+ * Coalescing for the Rx path
+ */
+static unsigned long titan_ge_rx_coal(unsigned long delay, int port)
+{
+	TITAN_GE_WRITE(TITAN_GE_INT_COALESCING, delay);
+	TITAN_GE_WRITE(0x5038, delay);
+
+	return delay;
+}
+#endif
+
+/*
+ * Coalescing for the Tx path
+ */
+static unsigned long titan_ge_tx_coal(unsigned long delay, int port)
+{
+	unsigned long rx_delay;
+
+	rx_delay = TITAN_GE_READ(TITAN_GE_INT_COALESCING);
+	delay = (delay << 16) | rx_delay;
+
+	TITAN_GE_WRITE(TITAN_GE_INT_COALESCING, delay);
+	TITAN_GE_WRITE(0x5038, delay);
+
+	return delay;
+}
diff -urN linux-2.4.28-bk7/drivers/net/titan_ge.h linux-2.4.29/drivers/net/titan_ge.h
--- linux-2.4.28-bk7/drivers/net/titan_ge.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.29/drivers/net/titan_ge.h	2005-01-19 07:08:09.229472093 -0800
@@ -0,0 +1,436 @@
+#ifndef _TITAN_GE_H_
+#define _TITAN_GE_H_
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/config.h>
+#include <linux/spinlock.h>
+#include <asm/addrspace.h> /* For KSEG1ADDR() */
+
+/*
+ * These functions should be later moved to a more generic location since there
+ * will be others accessing it also
+ */
+
+/* 
+ * This is the way it works: LKB5 Base is at 0x0128. TITAN_BASE is defined in
+ * include/asm/titan_dep.h. TITAN_GE_BASE is the value in the TITAN_GE_LKB5 
+ * register.
+ */
+
+#ifdef CONFIG_MIPS64
+#define	TITAN_GE_BASE	0xfffffffffe000000
+#else
+#define	TITAN_GE_BASE	0xfe000000
+#endif
+
+#define	TITAN_GE_WRITE(offset, data) \
+		*(volatile u32 *)(TITAN_GE_BASE + offset) = data	
+
+#define TITAN_GE_READ(offset) *(volatile u32 *)(TITAN_GE_BASE + offset)
+
+#ifndef msec_delay
+#define msec_delay(x)   do { if(in_interrupt()) { \
+                                /* Don't mdelay in interrupt context! */ \
+                                BUG(); \
+                        } else { \
+                                set_current_state(TASK_UNINTERRUPTIBLE); \
+                                schedule_timeout((x * HZ)/1000); \
+                        } } while(0)
+#endif
+
+#define TITAN_GE_PORT_0
+
+#define	TITAN_GE_SRAM_BASE_VIRTUAL	0xf4000000
+#define	TITAN_GE_SRAM_BASE_PHYSICAL	0xf4000000
+
+#ifdef CONFIG_NET_FASTROUTE
+
+#include <linux/if_arp.h>
+#include <net/ip.h>
+
+static int titan_accept_fastpath(struct net_device *dev, struct dst_entry *dst)
+{
+	struct net_device *odev = dst->dev;
+
+	if (dst->ops->protocol != __constant_htons(ETH_P_IP))
+		return -1;
+	if (odev->type != ARPHRD_ETHER || odev->accept_fastpath == NULL)
+		return -1;
+
+	return 0;
+}
+#endif
+
+
+/*
+ * We may need these constants
+ */
+#define TITAN_BIT0    0x00000001
+#define TITAN_BIT1    0x00000002
+#define TITAN_BIT2    0x00000004
+#define TITAN_BIT3    0x00000008
+#define TITAN_BIT4    0x00000010
+#define TITAN_BIT5    0x00000020
+#define TITAN_BIT6    0x00000040
+#define TITAN_BIT7    0x00000080
+#define TITAN_BIT8    0x00000100
+#define TITAN_BIT9    0x00000200
+#define TITAN_BIT10   0x00000400
+#define TITAN_BIT11   0x00000800
+#define TITAN_BIT12   0x00001000
+#define TITAN_BIT13   0x00002000
+#define TITAN_BIT14   0x00004000
+#define TITAN_BIT15   0x00008000
+#define TITAN_BIT16   0x00010000
+#define TITAN_BIT17   0x00020000
+#define TITAN_BIT18   0x00040000
+#define TITAN_BIT19   0x00080000
+#define TITAN_BIT20   0x00100000
+#define TITAN_BIT21   0x00200000
+#define TITAN_BIT22   0x00400000
+#define TITAN_BIT23   0x00800000
+#define TITAN_BIT24   0x01000000
+#define TITAN_BIT25   0x02000000
+#define TITAN_BIT26   0x04000000
+#define TITAN_BIT27   0x08000000
+#define TITAN_BIT28   0x10000000
+#define TITAN_BIT29   0x20000000
+#define TITAN_BIT30   0x40000000
+#define TITAN_BIT31   0x80000000
+
+/* Flow Control */
+#define	TITAN_GE_FC_NONE	0x0
+#define	TITAN_GE_FC_FULL	0x1
+#define	TITAN_GE_FC_TX_PAUSE	0x2
+#define	TITAN_GE_FC_RX_PAUSE	0x3
+
+/* Duplex Settings */
+#define	TITAN_GE_FULL_DUPLEX	0x1
+#define	TITAN_GE_HALF_DUPLEX	0x2
+
+/* Speed settings */
+#define	TITAN_GE_SPEED_1000	0x1
+#define	TITAN_GE_SPEED_100	0x2
+#define	TITAN_GE_SPEED_10	0x3
+
+/* Debugging info only */
+#undef TITAN_DEBUG
+
+/* Support for Rx side NAPI */
+#define TITAN_RX_NAPI
+
+#ifdef CONFIG_MIPS64
+#define	TITAN_GE_IE_MASK	0xfffffffffb001b64
+#define	TITAN_GE_IE_STATUS	0xfffffffffb001b60
+#else
+#define	TITAN_GE_IE_MASK	0xfb001b64
+#define	TITAN_GE_IE_STATUS	0xfb001b60
+#endif
+
+/* Support for Jumbo Frames */
+#undef TITAN_GE_JUMBO_FRAMES
+
+/* Rx buffer size */
+#ifdef TITAN_GE_JUMBO_FRAMES
+#define	TITAN_GE_JUMBO_BUFSIZE	9080
+#else
+#define	TITAN_GE_STD_BUFSIZE	1580
+#endif
+
+/* Default Tx Queue Size */
+#define	TITAN_GE_TX_QUEUE	128
+
+/* Default Rx Queue Size */
+#define	TITAN_GE_RX_QUEUE	64
+
+/* 
+ * Tx and Rx Interrupt Coalescing parameter. These values are 
+ * for 1 Ghz processor. Rx coalescing can be taken care of
+ * by NAPI. NAPI is adaptive and hence useful. Tx coalescing
+ * is not adaptive. Hence, these values need to be adjusted
+ * based on load, CPU speed etc.
+ */
+#define	TITAN_GE_RX_COAL	150
+#define	TITAN_GE_TX_COAL	300
+
+#if defined(__BIG_ENDIAN)
+
+/* Define the Rx descriptor */
+typedef struct _eth_rx_desc {
+        u32     reserved;	/* Unused 		*/
+        u32     buffer_addr;	/* CPU buffer address 	*/
+	u32	cmd_sts;	/* Command and Status	*/
+	u32	buffer;		/* XDMA buffer address	*/
+} titan_ge_rx_desc;
+
+/* Define the Tx descriptor */
+typedef struct _eth_tx_desc {
+        u16     cmd_sts;	/* Command, Status and Buffer count */
+	u16	buffer_len;	/* Length of the buffer	*/
+        u32     buffer_addr;	/* Physical address of the buffer */
+} titan_ge_tx_desc;
+
+#elif defined(__LITTLE_ENDIAN)
+
+/* Define the Rx descriptor */
+typedef struct _eth_rx_desc {
+	u32	buffer_addr;	/* Buffer address inclusive of checksum */
+        u32     cmd_sts;	/* Command and Status info */
+} titan_ge_rx_desc;
+
+/* Define the Tx descriptor */
+typedef struct _eth_tx_desc {
+	u32     buffer_addr;	/* Physical address of the buffer */
+	u16     buffer_len;     /* Length of the buffer */
+	u16     cmd_sts;        /* Command, Status and Buffer count */
+} titan_ge_tx_desc;
+#else
+#error One of __BIG_ENDIAN or __LITTLE_ENDIAN must be defined
+#endif
+
+/* Packet Structure */
+typedef struct _pkt_info {
+        unsigned int           len;
+        unsigned int            cmd_sts;
+        unsigned int            buffer;
+        struct sk_buff          *skb;
+	unsigned int		checksum;
+} titan_ge_packet;
+
+
+#define	PHYS_CNT	2
+
+/* Titan Port specific data structure */
+typedef struct _eth_port_ctrl {
+	unsigned int		port_num;
+	u8			port_mac_addr[6];
+
+	/* Rx descriptor pointers */
+	int 			rx_curr_desc_q, rx_used_desc_q;
+
+	/* Tx descriptor pointers */
+	int 			tx_curr_desc_q, tx_used_desc_q;
+
+	/* Rx descriptor area */
+	volatile titan_ge_rx_desc	*rx_desc_area;
+	unsigned int			rx_desc_area_size;
+	struct sk_buff*			rx_skb[TITAN_GE_RX_QUEUE];
+
+	/* Tx Descriptor area */
+	volatile titan_ge_tx_desc	*tx_desc_area;
+	unsigned int                    tx_desc_area_size;
+	struct sk_buff*                 tx_skb[TITAN_GE_TX_QUEUE];
+
+	/* Timeout task */
+	struct tq_struct		tx_timeout_task;
+
+	/* DMA structures and handles */
+	dma_addr_t			tx_dma;
+	dma_addr_t			rx_dma;
+	dma_addr_t			tx_dma_array[TITAN_GE_TX_QUEUE];
+
+	/* Device lock */
+	spinlock_t			lock;
+
+	unsigned int			tx_ring_skbs;
+	unsigned int			rx_ring_size;
+	unsigned int			tx_ring_size;
+	unsigned int			rx_ring_skbs;
+
+	struct net_device_stats		stats;
+
+	/* Tx and Rx coalescing */
+	unsigned long			rx_int_coal;
+	unsigned long			tx_int_coal;
+
+	/* Threshold for replenishing the Rx and Tx rings */
+	unsigned int			tx_threshold;
+	unsigned int			rx_threshold;
+
+	/* NAPI work limit */
+	unsigned int			rx_work_limit;
+} titan_ge_port_info;
+
+/* Titan specific constants */
+#define	TITAN_ETH_PORT_IRQ		4
+
+/* Max Rx buffer */
+#define	TITAN_GE_MAX_RX_BUFFER		65536
+
+/* Tx and Rx Error */
+#define	TITAN_GE_ERROR
+
+/* Rx Descriptor Command and Status */
+
+#define	TITAN_GE_RX_CRC_ERROR		TITAN_BIT27	/* crc error */
+#define	TITAN_GE_RX_OVERFLOW_ERROR	TITAN_BIT15	/* overflow */
+#define TITAN_GE_RX_BUFFER_OWNED	TITAN_BIT21	/* buffer ownership */
+#define	TITAN_GE_RX_STP			TITAN_BIT31	/* start of packet */
+#define	TITAN_GE_RX_BAM			TITAN_BIT30	/* broadcast address match */
+#define TITAN_GE_RX_PAM			TITAN_BIT28	/* physical address match */
+#define TITAN_GE_RX_LAFM		TITAN_BIT29	/* logical address filter match */
+#define TITAN_GE_RX_VLAN		TITAN_BIT26	/* virtual lans */
+#define TITAN_GE_RX_PERR		TITAN_BIT19	/* packet error */
+#define TITAN_GE_RX_TRUNC		TITAN_BIT20	/* packet size greater than 32 buffers */
+
+/* Tx Descriptor Command */
+#define	TITAN_GE_TX_BUFFER_OWNED	TITAN_BIT5	/* buffer ownership */	
+#define	TITAN_GE_TX_ENABLE_INTERRUPT	TITAN_BIT15	/* Interrupt Enable */
+
+/* Return Status */
+#define	TITAN_OK	0x1	/* Good Status */
+#define	TITAN_ERROR	0x2	/* Error Status */
+
+/* MIB specific register offset */
+#define TITAN_GE_MSTATX_STATS_BASE_LOW       0x0800  /* MSTATX COUNTL[15:0] */
+#define TITAN_GE_MSTATX_STATS_BASE_MID       0x0804  /* MSTATX COUNTM[15:0] */
+#define TITAN_GE_MSTATX_STATS_BASE_HI        0x0808  /* MSTATX COUNTH[7:0] */
+#define TITAN_GE_MSTATX_CONTROL              0x0828  /* MSTATX Control */
+#define TITAN_GE_MSTATX_VARIABLE_SELECT      0x082C  /* MSTATX Variable Select */
+
+/* MIB counter offsets, add to the TITAN_GE_MSTATX_STATS_BASE_XXX */
+#define TITAN_GE_MSTATX_RXFRAMESOK                   0x0040
+#define TITAN_GE_MSTATX_RXOCTETSOK                   0x0050
+#define TITAN_GE_MSTATX_RXFRAMES                     0x0060
+#define TITAN_GE_MSTATX_RXOCTETS                     0x0070
+#define TITAN_GE_MSTATX_RXUNICASTFRAMESOK            0x0080
+#define TITAN_GE_MSTATX_RXBROADCASTFRAMESOK          0x0090
+#define TITAN_GE_MSTATX_RXMULTICASTFRAMESOK          0x00A0
+#define TITAN_GE_MSTATX_RXTAGGEDFRAMESOK             0x00B0
+#define TITAN_GE_MSTATX_RXMACPAUSECONTROLFRAMESOK    0x00C0
+#define TITAN_GE_MSTATX_RXMACCONTROLFRAMESOK         0x00D0
+#define TITAN_GE_MSTATX_RXFCSERROR                   0x00E0
+#define TITAN_GE_MSTATX_RXALIGNMENTERROR             0x00F0
+#define TITAN_GE_MSTATX_RXSYMBOLERROR                0x0100
+#define TITAN_GE_MSTATX_RXLAYER1ERROR                0x0110
+#define TITAN_GE_MSTATX_RXINRANGELENGTHERROR         0x0120
+#define TITAN_GE_MSTATX_RXLONGLENGTHERROR            0x0130
+#define TITAN_GE_MSTATX_RXLONGLENGTHCRCERROR         0x0140
+#define TITAN_GE_MSTATX_RXSHORTLENGTHERROR           0x0150
+#define TITAN_GE_MSTATX_RXSHORTLLENGTHCRCERROR       0x0160
+#define TITAN_GE_MSTATX_RXFRAMES64OCTETS             0x0170
+#define TITAN_GE_MSTATX_RXFRAMES65TO127OCTETS        0x0180
+#define TITAN_GE_MSTATX_RXFRAMES128TO255OCTETS       0x0190
+#define TITAN_GE_MSTATX_RXFRAMES256TO511OCTETS       0x01A0
+#define TITAN_GE_MSTATX_RXFRAMES512TO1023OCTETS      0x01B0
+#define TITAN_GE_MSTATX_RXFRAMES1024TO1518OCTETS     0x01C0
+#define TITAN_GE_MSTATX_RXFRAMES1519TOMAXSIZE        0x01D0
+#define TITAN_GE_MSTATX_RXSTATIONADDRESSFILTERED     0x01E0
+#define TITAN_GE_MSTATX_RXVARIABLE                   0x01F0
+#define TITAN_GE_MSTATX_GENERICADDRESSFILTERED       0x0200
+#define TITAN_GE_MSTATX_UNICASTFILTERED              0x0210
+#define TITAN_GE_MSTATX_MULTICASTFILTERED            0x0220
+#define TITAN_GE_MSTATX_BROADCASTFILTERED            0x0230
+#define TITAN_GE_MSTATX_HASHFILTERED                 0x0240
+#define TITAN_GE_MSTATX_TXFRAMESOK                   0x0250
+#define TITAN_GE_MSTATX_TXOCTETSOK                   0x0260
+#define TITAN_GE_MSTATX_TXOCTETS                     0x0270
+#define TITAN_GE_MSTATX_TXTAGGEDFRAMESOK             0x0280
+#define TITAN_GE_MSTATX_TXMACPAUSECONTROLFRAMESOK    0x0290
+#define TITAN_GE_MSTATX_TXFCSERROR                   0x02A0
+#define TITAN_GE_MSTATX_TXSHORTLENGTHERROR           0x02B0
+#define TITAN_GE_MSTATX_TXLONGLENGTHERROR            0x02C0
+#define TITAN_GE_MSTATX_TXSYSTEMERROR                0x02D0
+#define TITAN_GE_MSTATX_TXMACERROR                   0x02E0
+#define TITAN_GE_MSTATX_TXCARRIERSENSEERROR          0x02F0
+#define TITAN_GE_MSTATX_TXSQETESTERROR               0x0300
+#define TITAN_GE_MSTATX_TXUNICASTFRAMESOK            0x0310
+#define TITAN_GE_MSTATX_TXBROADCASTFRAMESOK          0x0320
+#define TITAN_GE_MSTATX_TXMULTICASTFRAMESOK          0x0330
+#define TITAN_GE_MSTATX_TXUNICASTFRAMESATTEMPTED     0x0340
+#define TITAN_GE_MSTATX_TXBROADCASTFRAMESATTEMPTED   0x0350
+#define TITAN_GE_MSTATX_TXMULTICASTFRAMESATTEMPTED   0x0360
+#define TITAN_GE_MSTATX_TXFRAMES64OCTETS             0x0370
+#define TITAN_GE_MSTATX_TXFRAMES65TO127OCTETS        0x0380
+#define TITAN_GE_MSTATX_TXFRAMES128TO255OCTETS       0x0390
+#define TITAN_GE_MSTATX_TXFRAMES256TO511OCTETS       0x03A0
+#define TITAN_GE_MSTATX_TXFRAMES512TO1023OCTETS      0x03B0
+#define TITAN_GE_MSTATX_TXFRAMES1024TO1518OCTETS     0x03C0
+#define TITAN_GE_MSTATX_TXFRAMES1519TOMAXSIZE        0x03D0
+#define TITAN_GE_MSTATX_TXVARIABLE                   0x03E0
+#define TITAN_GE_MSTATX_RXSYSTEMERROR                0x03F0
+#define TITAN_GE_MSTATX_SINGLECOLLISION              0x0400
+#define TITAN_GE_MSTATX_MULTIPLECOLLISION            0x0410
+#define TITAN_GE_MSTATX_DEFERREDXMISSIONS            0x0420
+#define TITAN_GE_MSTATX_LATECOLLISIONS               0x0430
+#define TITAN_GE_MSTATX_ABORTEDDUETOXSCOLLS          0x0440
+
+/* Interrupt specific defines */
+#define TITAN_GE_DEVICE_ID         0x0000  /* Device ID */
+#define TITAN_GE_RESET             0x0004  /* Reset reg */
+#define TITAN_GE_TSB_CTRL_0        0x000C  /* TSB Control reg 0 */
+#define TITAN_GE_TSB_CTRL_1        0x0010  /* TSB Control reg 1 */
+#define TITAN_GE_INTR_GRP0_STATUS  0x0040  /* General Interrupt Group 0 Status */
+#define TITAN_GE_INTR_XDMA_CORE_A  0x0048  /* XDMA Channel Interrupt Status, Core A*/
+#define TITAN_GE_INTR_XDMA_CORE_B  0x004C  /* XDMA Channel Interrupt Status, Core B*/
+#define	TITAN_GE_INTR_XDMA_IE	   0x0058  /* XDMA Channel Interrupt Enable */
+#define TITAN_GE_SDQPF_ECC_INTR    0x480C  /* SDQPF ECC Interrupt Status */
+#define TITAN_GE_SDQPF_RXFIFO_CTL  0x4828  /* SDQPF RxFifo Control and Interrupt Enb*/
+#define TITAN_GE_SDQPF_RXFIFO_INTR 0x482C  /* SDQPF RxFifo Interrupt Status */
+#define TITAN_GE_SDQPF_TXFIFO_CTL  0x4928  /* SDQPF TxFifo Control and Interrupt Enb*/
+#define TITAN_GE_SDQPF_TXFIFO_INTR 0x492C  /* SDQPF TxFifo Interrupt Status */
+#define	TITAN_GE_SDQPF_RXFIFO_0	   0x4840  /* SDQPF RxFIFO Enable */
+#define	TITAN_GE_SDQPF_TXFIFO_0	   0x4940  /* SDQPF TxFIFO Enable */
+#define TITAN_GE_XDMA_CONFIG       0x5000  /* XDMA Global Configuration */
+#define TITAN_GE_XDMA_INTR_SUMMARY 0x5010  /* XDMA Interrupt Summary */
+#define TITAN_GE_XDMA_BUFADDRPRE   0x5018  /* XDMA Buffer Address Prefix */
+#define TITAN_GE_XDMA_DESCADDRPRE  0x501C  /* XDMA Descriptor Address Prefix */
+#define TITAN_GE_XDMA_PORTWEIGHT   0x502C  /* XDMA Port Weight Configuration */
+
+/* Rx MAC defines */
+#define TITAN_GE_RMAC_CONFIG_1               0x1200  /* RMAC Configuration 1 */
+#define TITAN_GE_RMAC_CONFIG_2               0x1204  /* RMAC Configuration 2 */
+#define TITAN_GE_RMAC_MAX_FRAME_LEN          0x1208  /* RMAC Max Frame Length */
+#define TITAN_GE_RMAC_STATION_HI             0x120C  /* Rx Station Address High */
+#define TITAN_GE_RMAC_STATION_MID            0x1210  /* Rx Station Address Middle */
+#define TITAN_GE_RMAC_STATION_LOW            0x1214  /* Rx Station Address Low */
+#define TITAN_GE_RMAC_LINK_CONFIG            0x1218  /* RMAC Link Configuration */
+
+/* Tx MAC defines */
+#define TITAN_GE_TMAC_CONFIG_1               0x1240  /* TMAC Configuration 1 */
+#define TITAN_GE_TMAC_CONFIG_2               0x1244  /* TMAC Configuration 2 */
+#define TITAN_GE_TMAC_IPG                    0x1248  /* TMAC Inter-Packet Gap */
+#define TITAN_GE_TMAC_STATION_HI             0x124C  /* Tx Station Address High */
+#define TITAN_GE_TMAC_STATION_MID            0x1250  /* Tx Station Address Middle */
+#define TITAN_GE_TMAC_STATION_LOW            0x1254  /* Tx Station Address Low */
+#define TITAN_GE_TMAC_MAX_FRAME_LEN          0x1258  /* TMAC Max Frame Length */
+#define TITAN_GE_TMAC_MIN_FRAME_LEN          0x125C  /* TMAC Min Frame Length */
+#define TITAN_GE_TMAC_PAUSE_FRAME_TIME       0x1260  /* TMAC Pause Frame Time */
+#define TITAN_GE_TMAC_PAUSE_FRAME_INTERVAL   0x1264  /* TMAC Pause Frame Interval */
+
+/* GMII register */
+#define TITAN_GE_GMII_INTERRUPT_STATUS       0x1348  /* GMII Interrupt Status */
+#define TITAN_GE_GMII_CONFIG_GENERAL         0x134C  /* GMII Configuration General */
+#define TITAN_GE_GMII_CONFIG_MODE            0x1350  /* GMII Configuration Mode */
+
+/* Tx and Rx XDMA defines */
+#define	TITAN_GE_INT_COALESCING		     0x5030 /* Interrupt Coalescing */
+#define	TITAN_GE_CHANNEL0_CONFIG	     0x5040 /* Channel 0 XDMA config */
+#define	TITAN_GE_CHANNEL0_INTERRUPT	     0x504c /* Channel 0 Interrupt Status */
+#define	TITAN_GE_GDI_INTERRUPT_ENABLE        0x5050 /* IE for the GDI Errors */
+#define	TITAN_GE_CHANNEL0_PACKET	     0x5060 /* Channel 0 Packet count */
+#define	TITAN_GE_CHANNEL0_BYTE		     0x5064 /* Channel 0 Byte count */
+#define	TITAN_GE_CHANNEL0_TX_DESC	     0x5054 /* Channel 0 Tx first desc */
+#define	TITAN_GE_CHANNEL0_RX_DESC	     0x5058 /* Channel 0 Rx first desc */
+
+/* AFX (Address Filter Exact) register offsets for Slice 0 */
+#define TITAN_GE_AFX_EXACT_MATCH_LOW         0x1100  /* AFX Exact Match Address Low*/
+#define TITAN_GE_AFX_EXACT_MATCH_MID         0x1104  /* AFX Exact Match Address Mid*/
+#define TITAN_GE_AFX_EXACT_MATCH_HIGH        0x1108  /* AFX Exact Match Address Hi */
+#define TITAN_GE_AFX_EXACT_MATCH_VID         0x110C  /* AFX Exact Match VID */
+#define TITAN_GE_AFX_MULTICAST_HASH_LOW      0x1110  /* AFX Multicast HASH Low */
+#define TITAN_GE_AFX_MULTICAST_HASH_MIDLOW   0x1114  /* AFX Multicast HASH MidLow */
+#define TITAN_GE_AFX_MULTICAST_HASH_MIDHI    0x1118  /* AFX Multicast HASH MidHi */
+#define TITAN_GE_AFX_MULTICAST_HASH_HI       0x111C  /* AFX Multicast HASH Hi */
+#define TITAN_GE_AFX_ADDRS_FILTER_CTRL_0     0x1120  /* AFX Address Filter Ctrl 0 */
+#define TITAN_GE_AFX_ADDRS_FILTER_CTRL_1     0x1124  /* AFX Address Filter Ctrl 1 */
+#define TITAN_GE_AFX_ADDRS_FILTER_CTRL_2     0x1128  /* AFX Address Filter Ctrl 2 */
+
+/* Traffic Groomer block */
+#define        TITAN_GE_TRTG_CONFIG	     0x1000  /* TRTG Config */
+
+#endif 				/* _TITAN_GE_H_ */
+
diff -urN linux-2.4.28-bk7/drivers/net/titan_mdio.c linux-2.4.29/drivers/net/titan_mdio.c
--- linux-2.4.28-bk7/drivers/net/titan_mdio.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.29/drivers/net/titan_mdio.c	2005-01-19 07:08:09.230472137 -0800
@@ -0,0 +1,217 @@
+/*
+ * drivers/net/titan_mdio.c - Driver for Titan ethernet ports
+ *
+ * Copyright (C) 2003 PMC-Sierra Inc.
+ * Author : Manish Lachwani (lachwani@pmc-sierra.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
+ * 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.
+ *
+ * Management Data IO (MDIO) driver for the Titan GMII. Interacts with the Marvel PHY
+ * on the Titan. No support for the TBI as yet. 
+ *
+ */
+
+#include	"titan_mdio.h"
+
+#define MDIO_DEBUG
+
+/*
+ * Local constants
+ */
+#define MAX_CLKA            1023
+#define MAX_PHY_DEV         31
+#define MAX_PHY_REG         31
+#define WRITEADDRS_OPCODE   0x0
+#define	READ_OPCODE	    0x2
+#define WRITE_OPCODE        0x1
+#define MAX_MDIO_POLL       100
+
+/* 
+ * Titan MDIO and SCMB registers
+ */
+#define TITAN_GE_SCMB_CONTROL                0x01c0  /* SCMB Control */
+#define TITAN_GE_SCMB_CLKA	             0x01c4  /* SCMB Clock A */
+#define TITAN_GE_MDIO_COMMAND                0x01d0  /* MDIO Command */
+#define TITAN_GE_MDIO_DEVICE_PORT_ADDRESS    0x01d4  /* MDIO Device and Port addrs */
+#define TITAN_GE_MDIO_DATA                   0x01d8  /* MDIO Data */
+#define TITAN_GE_MDIO_INTERRUPTS             0x01dC  /* MDIO Interrupts */
+
+/*
+ * Function to poll the MDIO 
+ */
+static int titan_ge_mdio_poll()
+{
+	int	i, val;
+
+	for (i = 0; i < MAX_MDIO_POLL; i++) {
+		val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND);
+
+		if (!(val & 0x8000))
+			return TITAN_GE_MDIO_GOOD;
+	}
+
+	return TITAN_GE_MDIO_ERROR;
+}
+
+
+/*
+ * Initialize and configure the MDIO 
+ */
+int titan_ge_mdio_setup(titan_ge_mdio_config *titan_mdio)
+{
+	unsigned long	val;
+
+	/* Reset the SCMB and program into MDIO mode*/
+	TITAN_GE_MDIO_WRITE(TITAN_GE_SCMB_CONTROL, 0x9000);
+	TITAN_GE_MDIO_WRITE(TITAN_GE_SCMB_CONTROL, 0x1000);
+
+	/* CLK A */
+	val = TITAN_GE_MDIO_READ(TITAN_GE_SCMB_CLKA);
+	val = ( (val & ~(0x03ff)) | (titan_mdio->clka & 0x03ff));
+	TITAN_GE_MDIO_WRITE(TITAN_GE_SCMB_CLKA, val);
+
+	/* Preamble Suppresion */
+	val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND);
+	val = ( (val & ~(0x0001)) | (titan_mdio->mdio_spre & 0x0001));
+	TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val);
+
+	/* MDIO mode */
+	val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS);
+	val = ( (val & ~(0x4000)) | (titan_mdio->mdio_mode & 0x4000));
+	TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val);
+
+	return TITAN_GE_MDIO_GOOD;
+}
+
+/*
+ * Set the PHY address in indirect mode
+ */
+int titan_ge_mdio_inaddrs(int dev_addr, int reg_addr)
+{
+	volatile unsigned long	val;
+
+	/* Setup the PHY device */
+	val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS);
+	val = ( (val & ~(0x1f00)) | ( (dev_addr << 8) & 0x1f00));
+	val = ( (val & ~(0x001f)) | ( reg_addr & 0x001f));
+	TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val);
+
+	/* Write the new address */
+	val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND);
+	val = ( (val & ~(0x0300)) | ( (WRITEADDRS_OPCODE << 8) & 0x0300));
+	TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val);
+
+	return TITAN_GE_MDIO_GOOD;
+}
+
+/*
+ * Read the MDIO register. This is what the individual parametes mean:
+ *
+ * dev_addr : PHY ID
+ * reg_addr : register offset
+ *
+ * See the spec for the Titan MAC. We operate in the Direct Mode. 
+ */
+
+#define MAX_RETRIES	2
+
+int titan_ge_mdio_read(int dev_addr, int reg_addr, unsigned int *pdata)
+{
+	volatile unsigned long	val;
+	int retries = 0;
+
+	/* Setup the PHY device */
+
+again:
+	val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS);
+	val = ( (val & ~(0x1f00)) | ( (dev_addr << 8) & 0x1f00));
+	val = ( (val & ~(0x001f)) | ( reg_addr & 0x001f));
+	val |= 0x4000;
+	TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val);
+	
+	udelay(30);
+
+	/* Issue the read command */
+	val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND);
+	val = ( (val & ~(0x0300)) | ( (READ_OPCODE << 8) & 0x0300));
+	TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val);
+
+	udelay(30);
+
+	if (titan_ge_mdio_poll() != TITAN_GE_MDIO_GOOD)
+		return TITAN_GE_MDIO_ERROR;
+
+	*pdata = (unsigned int)TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DATA);
+	val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_INTERRUPTS);
+
+	udelay(30);
+
+	if (val & 0x2) {
+		if (retries == MAX_RETRIES)
+			return TITAN_GE_MDIO_ERROR;
+		else {
+			retries++;
+			goto again;
+		}
+	}
+
+	return TITAN_GE_MDIO_GOOD;
+}
+
+/*
+ * Write to the MDIO register 
+ *
+ * dev_addr : PHY ID
+ * reg_addr : register that needs to be written to
+ *
+ */
+int titan_ge_mdio_write(int dev_addr, int reg_addr, unsigned int data)
+{
+	volatile unsigned long	val;
+
+	if (titan_ge_mdio_poll() != TITAN_GE_MDIO_GOOD)
+		return TITAN_GE_MDIO_ERROR;
+
+	/* Setup the PHY device */
+        val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS);
+        val = ( (val & ~(0x1f00)) | ( (dev_addr << 8) & 0x1f00));
+        val = ( (val & ~(0x001f)) | ( reg_addr & 0x001f));
+	val |= 0x4000;
+        TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val);
+
+	udelay(30);
+
+	/* Setup the data to write */
+	TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DATA, data);
+
+	udelay(30);
+
+	/* Issue the write command */
+	val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND);
+	val = ( (val & ~(0x0300)) | ( (WRITE_OPCODE << 8) & 0x0300));
+	TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val);
+
+	udelay(30);
+
+	if (titan_ge_mdio_poll() != TITAN_GE_MDIO_GOOD) 
+                return TITAN_GE_MDIO_ERROR;
+
+	val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_INTERRUPTS);	
+	if (val & 0x2)
+		return TITAN_GE_MDIO_ERROR;
+
+	return TITAN_GE_MDIO_GOOD;
+}
+
diff -urN linux-2.4.28-bk7/drivers/net/titan_mdio.h linux-2.4.29/drivers/net/titan_mdio.h
--- linux-2.4.28-bk7/drivers/net/titan_mdio.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.29/drivers/net/titan_mdio.h	2005-01-19 07:08:09.231472180 -0800
@@ -0,0 +1,59 @@
+/*
+ * MDIO used to interact with the PHY when using GMII/MII
+ */
+#ifndef _TITAN_MDIO_H
+#define _TITAN_MDIO_H
+
+#include <linux/netdevice.h>
+#include <linux/tqueue.h>
+#include <linux/delay.h>
+#include "titan_ge.h"
+
+
+#define	TITAN_GE_MDIO_ERROR	(-9000)
+#define	TITAN_GE_MDIO_GOOD	0
+
+#define	TITAN_GE_MDIO_BASE		TITAN_GE_BASE
+
+#define	TITAN_GE_MDIO_READ(offset)	*(volatile u32 *)(TITAN_GE_MDIO_BASE + offset)
+
+#define	TITAN_GE_MDIO_WRITE(offset, data)	\
+					*(volatile u32 *)(TITAN_GE_MDIO_BASE + offset) = data
+
+
+/* GMII specific registers */
+#define	TITAN_GE_MARVEL_PHY_ID		0x00
+#define	TITAN_PHY_AUTONEG_ADV		0x04
+#define	TITAN_PHY_LP_ABILITY		0x05
+#define	TITAN_GE_MDIO_MII_CTRL		0x09
+#define	TITAN_GE_MDIO_MII_EXTENDED	0x0f
+#define	TITAN_GE_MDIO_PHY_CTRL		0x10
+#define	TITAN_GE_MDIO_PHY_STATUS	0x11
+#define	TITAN_GE_MDIO_PHY_IE		0x12
+#define	TITAN_GE_MDIO_PHY_IS		0x13
+#define	TITAN_GE_MDIO_PHY_LED		0x18
+#define	TITAN_GE_MDIO_PHY_LED_OVER	0x19
+#define	PHY_ANEG_TIME_WAIT		45	/* 45 seconds wait time */
+
+/*
+ * MDIO Config Structure 
+ */
+typedef struct 
+{
+	unsigned int		clka;
+	int			mdio_spre;
+	int			mdio_mode;
+} titan_ge_mdio_config;
+
+/*
+ * Function Prototypes 
+ */
+int titan_ge_mdio_setup(titan_ge_mdio_config *);
+int titan_ge_mdio_inaddrs(int, int);
+int titan_ge_mdio_read(int, int, unsigned int *);
+int titan_ge_mdio_write(int, int, unsigned int);
+
+#endif /* _TITAN_MDIO_H */
+		
+
+
diff -urN linux-2.4.28-bk7/drivers/net/wan/8253x/8253xsyn.c linux-2.4.29/drivers/net/wan/8253x/8253xsyn.c
--- linux-2.4.28-bk7/drivers/net/wan/8253x/8253xsyn.c	2002-08-02 17:39:44.000000000 -0700
+++ linux-2.4.29/drivers/net/wan/8253x/8253xsyn.c	2005-01-19 07:08:09.233472266 -0800
@@ -1108,10 +1108,7 @@
 	{
 		tty->driver.flush_buffer(tty);
 	}
-	if (tty->ldisc.flush_buffer)
-	{
-		tty->ldisc.flush_buffer(tty);
-	}
+	tty_ldisc_flush(tty);
 	tty->closing = 0;
 	port->event = 0;
 	port->tty = 0;
diff -urN linux-2.4.28-bk7/drivers/net/wan/8253x/8253xtty.c linux-2.4.29/drivers/net/wan/8253x/8253xtty.c
--- linux-2.4.28-bk7/drivers/net/wan/8253x/8253xtty.c	2003-06-13 07:51:35.000000000 -0700
+++ linux-2.4.29/drivers/net/wan/8253x/8253xtty.c	2005-01-19 07:08:09.235472353 -0800
@@ -691,10 +691,7 @@
 	port->DoingInterrupt = 1;
 	if (test_and_clear_bit(SAB8253X_EVENT_WRITE_WAKEUP, &port->event)) 
 	{
-		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-		    tty->ldisc.write_wakeup)
-			(tty->ldisc.write_wakeup)(tty);
-		wake_up_interruptible(&tty->write_wait); /* in case tty driver waiting on write */
+		tty_wakeup(tty);
 	}
 	port->DoingInterrupt = 0;
 }
@@ -2001,10 +1998,7 @@
 	{
 		tty->driver.flush_buffer(tty);
 	}
-	if (tty->ldisc.flush_buffer)
-	{
-		tty->ldisc.flush_buffer(tty);
-	}
+	tty_ldisc_flush(tty);
 	tty->closing = 0;
 	port->event = 0;
 	port->tty = 0;
diff -urN linux-2.4.28-bk7/drivers/net/wan/8253x/8253xutl.c linux-2.4.29/drivers/net/wan/8253x/8253xutl.c
--- linux-2.4.28-bk7/drivers/net/wan/8253x/8253xutl.c	2002-08-02 17:39:44.000000000 -0700
+++ linux-2.4.29/drivers/net/wan/8253x/8253xutl.c	2005-01-19 07:08:09.236472396 -0800
@@ -1412,11 +1412,6 @@
 	WRITEB(port,cmdr,SAB82532_CMDR_XRES);
 	restore_flags(flags);
 	
-	wake_up_interruptible(&tty->write_wait); /* wake up tty driver */
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	    tty->ldisc.write_wakeup)
-	{
-		(*tty->ldisc.write_wakeup)(tty);
-	}
+	tty_wakeup(tty);
 }
 
diff -urN linux-2.4.28-bk7/drivers/net/wan/pc300_tty.c linux-2.4.29/drivers/net/wan/pc300_tty.c
--- linux-2.4.28-bk7/drivers/net/wan/pc300_tty.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/drivers/net/wan/pc300_tty.c	2005-01-19 07:08:09.237472440 -0800
@@ -627,14 +627,8 @@
 	}
 
 	CPC_TTY_DBG("%s: call wake_up_interruptible\n",cpc_tty->name);
-	
-	wake_up_interruptible(&tty->write_wait); 
-
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup){
-		CPC_TTY_DBG("%s: call line disc. wake up\n",cpc_tty->name);
-		tty->ldisc.write_wakeup(tty); 
-	} 
 
+	tty_wakeup(tty);	
 	return; 
 } 
 
@@ -699,12 +693,19 @@
 			cpc_tty = &cpc_tty_area[port];
 		
 			if ((buf=cpc_tty->buf_rx.first) != 0) {
-															
-				if (cpc_tty->tty && (cpc_tty->tty->ldisc.receive_buf)) { 
-					CPC_TTY_DBG("%s: call line disc. receive_buf\n",cpc_tty->name);
-					cpc_tty->tty->ldisc.receive_buf(cpc_tty->tty, (const unsigned char *)buf->data, 
-													&flags, buf->size);
-				}	
+				
+				if(cpc_tty->tty) 
+				{
+					struct tty_ldisc *ld = tty_ldisc_ref(cpc_tty->tty);
+					if(ld)
+					{
+						if (ld->receive_buf) {
+							CPC_TTY_DBG("%s: call line disc. receive_buf\n",cpc_tty->name);
+							ld->receive_buf(cpc_tty->tty, (char *)(buf->data), &flags, buf->size);
+						}
+						tty_ldisc_deref(ld);
+					}
+				}											
 				cpc_tty->buf_rx.first = cpc_tty->buf_rx.first->next;
 				kfree((unsigned char *)buf);
 				buf = cpc_tty->buf_rx.first;
@@ -908,12 +909,7 @@
 		return; 
 	}
 
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup){
-		CPC_TTY_DBG("%s:call line disc. wakeup\n",cpc_tty->name);
-		tty->ldisc.write_wakeup (tty); 
-	}
-
-	wake_up_interruptible(&tty->write_wait); 
+	tty_wakeup(tty);
 }
 
 /*
diff -urN linux-2.4.28-bk7/drivers/net/wan/sdla.c linux-2.4.29/drivers/net/wan/sdla.c
--- linux-2.4.28-bk7/drivers/net/wan/sdla.c	2002-11-28 15:53:14.000000000 -0800
+++ linux-2.4.29/drivers/net/wan/sdla.c	2005-01-19 07:08:09.238472483 -0800
@@ -1300,6 +1300,8 @@
 
 		case SDLA_WRITEMEM:
 		case SDLA_READMEM:
+			if(!capable(CAP_SYS_RAWIO))
+				return -EPERM;
 			return(sdla_xfer(dev, (struct sdla_mem *)ifr->ifr_data, cmd == SDLA_READMEM));
 
 		case SDLA_START:
diff -urN linux-2.4.28-bk7/drivers/net/wan/sdla_chdlc.c linux-2.4.29/drivers/net/wan/sdla_chdlc.c
--- linux-2.4.28-bk7/drivers/net/wan/sdla_chdlc.c	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.29/drivers/net/wan/sdla_chdlc.c	2005-01-19 07:08:09.241472613 -0800
@@ -3868,11 +3868,7 @@
 	if ((tty=card->tty)==NULL)
 		return;
 	
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	    tty->ldisc.write_wakeup){
-		(tty->ldisc.write_wakeup)(tty);
-	}
-	wake_up_interruptible(&tty->write_wait);
+	tty_wakeup(tty);
 #if defined(SERIAL_HAVE_POLL_WAIT) || \
          (defined LINUX_2_1 && LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,15))
 	wake_up_interruptible(&tty->poll_wait);
@@ -4098,6 +4094,7 @@
 	char fp=0;
 	struct tty_struct *tty;
 	int i;
+	struct tty_ldisc *ld;
 	
 	if (!card->tty_open){
 		dbg_printk(KERN_INFO "%s: TTY not open during receive\n",
@@ -4185,8 +4182,11 @@
 			len -= offset;
 		}
 		sdla_peek(&card->hw, addr, card->tty_rx+offset, len);
-		if (tty->ldisc.receive_buf){
-			tty->ldisc.receive_buf(tty,card->tty_rx,&fp,olen);
+		ld = tty_ldisc_ref(tty);
+		if (ld) {
+			if (ld->receive_buf)
+				ld->receive_buf(tty,card->tty_rx,&fp,olen);
+			tty_ldisc_deref(ld);
 		}else{
 			if (net_ratelimit()){
 				printk(KERN_INFO 
@@ -4493,14 +4493,11 @@
 	if (!tty)
 		return;
 	
-	wake_up_interruptible(&tty->write_wait);
 #if defined(SERIAL_HAVE_POLL_WAIT) || \
          (defined LINUX_2_1 && LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,15))
 	wake_up_interruptible(&tty->poll_wait);
 #endif
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	    tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup)(tty);
+	tty_wakeup(tty);
 
 	return;
 }
diff -urN linux-2.4.28-bk7/drivers/net/wan/x25_asy.c linux-2.4.29/drivers/net/wan/x25_asy.c
--- linux-2.4.28-bk7/drivers/net/wan/x25_asy.c	2001-09-13 16:04:43.000000000 -0700
+++ linux-2.4.29/drivers/net/wan/x25_asy.c	2005-01-19 07:08:09.243472700 -0800
@@ -619,9 +619,7 @@
 	if (tty->driver.flush_buffer)  {
 		tty->driver.flush_buffer(tty);
 	}
-	if (tty->ldisc.flush_buffer)  {
-		tty->ldisc.flush_buffer(tty);
-	}
+	tty_ldisc_flush(tty);
 
 	/* Restore default settings */
 	sl->dev->type = ARPHRD_X25;
diff -urN linux-2.4.28-bk7/drivers/net/wireless/prism54/isl_38xx.c linux-2.4.29/drivers/net/wireless/prism54/isl_38xx.c
--- linux-2.4.28-bk7/drivers/net/wireless/prism54/isl_38xx.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/drivers/net/wireless/prism54/isl_38xx.c	2005-01-19 07:08:09.244472743 -0800
@@ -44,7 +44,7 @@
  *  register located at offset %ISL38XX_INT_IDENT_REG.
  */
 void
-isl38xx_disable_interrupts(void *device)
+isl38xx_disable_interrupts(void __iomem *device)
 {
 	isl38xx_w32_flush(device, 0x00000000, ISL38XX_INT_EN_REG);
 	udelay(ISL38XX_WRITEIO_DELAY);
@@ -52,7 +52,7 @@
 
 void
 isl38xx_handle_sleep_request(isl38xx_control_block *control_block,
-			     int *powerstate, void *device_base)
+			     int *powerstate, void __iomem *device_base)
 {
 	/* device requests to go into sleep mode
 	 * check whether the transmit queues for data and management are empty */
@@ -88,7 +88,7 @@
 
 void
 isl38xx_handle_wakeup(isl38xx_control_block *control_block,
-		      int *powerstate, void *device_base)
+		      int *powerstate, void __iomem *device_base)
 {
 	/* device is in active state, update the powerstate flag */
 	*powerstate = ISL38XX_PSM_ACTIVE_STATE;
@@ -110,7 +110,7 @@
 }
 
 void
-isl38xx_trigger_device(int asleep, void *device_base)
+isl38xx_trigger_device(int asleep, void __iomem *device_base)
 {
 	struct timeval current_time;
 	u32 reg, counter = 0;
@@ -190,7 +190,7 @@
 }
 
 void
-isl38xx_interface_reset(void *device_base, dma_addr_t host_address)
+isl38xx_interface_reset(void __iomem *device_base, dma_addr_t host_address)
 {
 #if VERBOSE > SHOW_ERROR_MESSAGES
 	DEBUG(SHOW_FUNCTION_CALLS, "isl38xx_interface_reset\n");
@@ -214,7 +214,7 @@
 }
 
 void
-isl38xx_enable_common_interrupts(void *device_base) {
+isl38xx_enable_common_interrupts(void __iomem *device_base) {
 	u32 reg;
 	reg = ( ISL38XX_INT_IDENT_UPDATE | 
 			ISL38XX_INT_IDENT_SLEEP | ISL38XX_INT_IDENT_WAKEUP);
diff -urN linux-2.4.28-bk7/drivers/net/wireless/prism54/isl_38xx.h linux-2.4.29/drivers/net/wireless/prism54/isl_38xx.h
--- linux-2.4.28-bk7/drivers/net/wireless/prism54/isl_38xx.h	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/drivers/net/wireless/prism54/isl_38xx.h	2005-01-19 07:08:09.245472786 -0800
@@ -75,7 +75,7 @@
  *  from the %ISL38XX_PCI_POSTING_FLUSH offset.
  */
 static inline void
-isl38xx_w32_flush(void *base, u32 val, unsigned long offset)
+isl38xx_w32_flush(void __iomem *base, u32 val, unsigned long offset)
 {
 	writel(val, base + offset);
 	(void) readl(base + ISL38XX_PCI_POSTING_FLUSH);
@@ -161,13 +161,13 @@
 /* determine number of entries currently in queue */
 int isl38xx_in_queue(isl38xx_control_block *cb, int queue);
 
-void isl38xx_disable_interrupts(void *);
-void isl38xx_enable_common_interrupts(void *);
+void isl38xx_disable_interrupts(void __iomem *);
+void isl38xx_enable_common_interrupts(void __iomem *);
 
 void isl38xx_handle_sleep_request(isl38xx_control_block *, int *,
-				  void *);
-void isl38xx_handle_wakeup(isl38xx_control_block *, int *, void *);
-void isl38xx_trigger_device(int, void *);
-void isl38xx_interface_reset(void *, dma_addr_t);
+				  void __iomem *);
+void isl38xx_handle_wakeup(isl38xx_control_block *, int *, void __iomem *);
+void isl38xx_trigger_device(int, void __iomem *);
+void isl38xx_interface_reset(void __iomem *, dma_addr_t);
 
 #endif				/* _ISL_38XX_H */
diff -urN linux-2.4.28-bk7/drivers/net/wireless/prism54/isl_ioctl.c linux-2.4.29/drivers/net/wireless/prism54/isl_ioctl.c
--- linux-2.4.28-bk7/drivers/net/wireless/prism54/isl_ioctl.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/drivers/net/wireless/prism54/isl_ioctl.c	2005-01-19 07:08:09.247472873 -0800
@@ -1524,31 +1524,35 @@
 		     const struct obj_mlme *mlme, int error)
 {
 	union iwreq_data wrqu;
+	char *memptr;
 
-	wrqu.data.pointer = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL);
-	if (!wrqu.data.pointer)
+	memptr = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL);
+	if (!memptr)
 		return;
+	wrqu.data.pointer = memptr;
 	wrqu.data.length = 0;
-	format_event(priv, wrqu.data.pointer, str, mlme, &wrqu.data.length,
+	format_event(priv, memptr, str, mlme, &wrqu.data.length,
 		     error);
-	wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, wrqu.data.pointer);
-	kfree(wrqu.data.pointer);
+	wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, memptr);
+	kfree(memptr);
 }
 
 static void
 send_simple_event(islpci_private *priv, const char *str)
 {
 	union iwreq_data wrqu;
+	char *memptr;
 	int n = strlen(str);
 
-	wrqu.data.pointer = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL);
-	if (!wrqu.data.pointer)
+	memptr = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL);
+	if (!memptr)
 		return;
 	BUG_ON(n > IW_CUSTOM_MAX);
+	wrqu.data.pointer = memptr;
 	wrqu.data.length = n;
-	strcpy(wrqu.data.pointer, str);
-	wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, wrqu.data.pointer);
-	kfree(wrqu.data.pointer);
+	strcpy(memptr, str);
+	wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, memptr);
+	kfree(memptr);
 }
 
 static void
diff -urN linux-2.4.28-bk7/drivers/net/wireless/prism54/islpci_dev.c linux-2.4.29/drivers/net/wireless/prism54/islpci_dev.c
--- linux-2.4.28-bk7/drivers/net/wireless/prism54/islpci_dev.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/drivers/net/wireless/prism54/islpci_dev.c	2005-01-19 07:08:09.248472916 -0800
@@ -58,7 +58,7 @@
 isl_upload_firmware(islpci_private *priv)
 {
 	u32 reg, rc;
-	void *device_base = priv->device_base;
+	void __iomem *device_base = priv->device_base;
 
 	/* clear the RAMBoot and the Reset bit */
 	reg = readl(device_base + ISL38XX_CTRL_STAT_REG);
@@ -113,7 +113,7 @@
 			    (fw_len >
 			     ISL38XX_MEMORY_WINDOW_SIZE) ?
 			    ISL38XX_MEMORY_WINDOW_SIZE : fw_len;
-			u32 *dev_fw_ptr = device_base + ISL38XX_DIRECT_MEM_WIN;
+			u32 __iomem *dev_fw_ptr = device_base + ISL38XX_DIRECT_MEM_WIN;
 
 			/* set the cards base address for writting the data */
 			isl38xx_w32_flush(device_base, reg,
@@ -187,7 +187,7 @@
 	u32 reg;
 	islpci_private *priv = config;
 	struct net_device *ndev = priv->ndev;
-	void *device = priv->device_base;
+	void __iomem *device = priv->device_base;
 	int powerstate = ISL38XX_PSM_POWERSAVE_STATE;
 
 	/* lock the interrupt handler */
@@ -407,7 +407,7 @@
 static int
 prism54_bring_down(islpci_private *priv)
 {
-	void *device_base = priv->device_base;
+	void __iomem *device_base = priv->device_base;
 	u32 reg;
 	/* we are going to shutdown the device */
 	islpci_set_state(priv, PRV_STATE_PREBOOT);
diff -urN linux-2.4.28-bk7/drivers/net/wireless/prism54/islpci_dev.h linux-2.4.29/drivers/net/wireless/prism54/islpci_dev.h
--- linux-2.4.28-bk7/drivers/net/wireless/prism54/islpci_dev.h	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/drivers/net/wireless/prism54/islpci_dev.h	2005-01-19 07:08:09.248472916 -0800
@@ -113,7 +113,7 @@
 	u32 pci_state[16];	/* used for suspend/resume */
 	char firmware[33];
 
-	void *device_base;	/* ioremapped device base address */
+	void __iomem *device_base;	/* ioremapped device base address */
 
 	/* consistent DMA region */
 	void *driver_mem_address;	/* base DMA address */
diff -urN linux-2.4.28-bk7/drivers/net/wireless/prism54/islpci_hotplug.c linux-2.4.29/drivers/net/wireless/prism54/islpci_hotplug.c
--- linux-2.4.28-bk7/drivers/net/wireless/prism54/islpci_hotplug.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/drivers/net/wireless/prism54/islpci_hotplug.c	2005-01-19 07:08:09.249472959 -0800
@@ -292,6 +292,8 @@
 	islpci_private *priv = ndev ? netdev_priv(ndev) : NULL;
 	BUG_ON(!priv);
 
+	pci_enable_device(pdev);
+
 	printk(KERN_NOTICE "%s: got resume request\n", ndev->name);
 
 	pci_restore_state(pdev, priv->pci_state);
diff -urN linux-2.4.28-bk7/drivers/net/wireless/prism54/prismcompat.h linux-2.4.29/drivers/net/wireless/prism54/prismcompat.h
--- linux-2.4.28-bk7/drivers/net/wireless/prism54/prismcompat.h	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/drivers/net/wireless/prism54/prismcompat.h	2005-01-19 07:08:09.249472959 -0800
@@ -38,6 +38,10 @@
 #error Firmware Loading is not configured in the kernel !
 #endif
 
+#ifndef __iomem
+#define __iomem
+#endif
+
 #define prism54_synchronize_irq(irq) synchronize_irq(irq)
 
 #define PRISM_FW_PDEV		&priv->pdev->dev
diff -urN linux-2.4.28-bk7/drivers/net/wireless/prism54/prismcompat24.h linux-2.4.29/drivers/net/wireless/prism54/prismcompat24.h
--- linux-2.4.28-bk7/drivers/net/wireless/prism54/prismcompat24.h	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/drivers/net/wireless/prism54/prismcompat24.h	2005-01-19 07:08:09.250473003 -0800
@@ -51,6 +51,10 @@
 #define INIT_WORK		INIT_TQUEUE
 #define schedule_work		schedule_task
 
+#ifndef __iomem
+#define __iomem
+#endif
+
 #if !defined(HAVE_NETDEV_PRIV)
 #define netdev_priv(x)		(x)->priv
 #endif
diff -urN linux-2.4.28-bk7/drivers/parport/ieee1284.c linux-2.4.29/drivers/parport/ieee1284.c
--- linux-2.4.28-bk7/drivers/parport/ieee1284.c	2001-10-25 00:07:39.000000000 -0700
+++ linux-2.4.29/drivers/parport/ieee1284.c	2005-01-19 07:08:09.250473003 -0800
@@ -1,7 +1,7 @@
 /* $Id: parport_ieee1284.c,v 1.4 1997/10/19 21:37:21 philip Exp $
  * IEEE-1284 implementation for parport.
  *
- * Authors: Phil Blundell <Philip.Blundell@pobox.com>
+ * Authors: Phil Blundell <philb@gnu.org>
  *          Carsten Gross <carsten@sol.wohnheim.uni-ulm.de>
  *	    Jose Renau <renau@acm.org>
  *          Tim Waugh <tim@cyberelk.demon.co.uk> (largely rewritten)
diff -urN linux-2.4.28-bk7/drivers/parport/parport_arc.c linux-2.4.29/drivers/parport/parport_arc.c
--- linux-2.4.28-bk7/drivers/parport/parport_arc.c	2001-02-09 11:30:23.000000000 -0800
+++ linux-2.4.29/drivers/parport/parport_arc.c	2005-01-19 07:08:09.251473046 -0800
@@ -1,6 +1,6 @@
 /* Low-level parallel port routines for Archimedes onboard hardware
  *
- * Author: Phil Blundell <Philip.Blundell@pobox.com>
+ * Author: Phil Blundell <philb@gnu.org>
  */
 
 /* This driver is for the parallel port hardware found on Acorn's old
diff -urN linux-2.4.28-bk7/drivers/parport/parport_gsc.c linux-2.4.29/drivers/parport/parport_gsc.c
--- linux-2.4.28-bk7/drivers/parport/parport_gsc.c	2002-11-28 15:53:14.000000000 -0800
+++ linux-2.4.29/drivers/parport/parport_gsc.c	2005-01-19 07:08:09.252473089 -0800
@@ -12,7 +12,7 @@
  * 
  * based on parport_pc.c by 
  * 	    Grant Guenther <grant@torque.net>
- * 	    Phil Blundell <Philip.Blundell@pobox.com>
+ * 	    Phil Blundell <philb@gnu.org>
  *          Tim Waugh <tim@cyberelk.demon.co.uk>
  *	    Jose Renau <renau@acm.org>
  *          David Campbell <campbell@torque.net>
diff -urN linux-2.4.28-bk7/drivers/parport/parport_pc.c linux-2.4.29/drivers/parport/parport_pc.c
--- linux-2.4.28-bk7/drivers/parport/parport_pc.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/drivers/parport/parport_pc.c	2005-01-19 07:08:09.254473176 -0800
@@ -1,6 +1,6 @@
 /* Low-level parallel-port routines for 8255-based PC-style hardware.
  * 
- * Authors: Phil Blundell <Philip.Blundell@pobox.com>
+ * Authors: Phil Blundell <philb@gnu.org>
  *          Tim Waugh <tim@cyberelk.demon.co.uk>
  *	    Jose Renau <renau@acm.org>
  *          David Campbell <campbell@torque.net>
diff -urN linux-2.4.28-bk7/drivers/parport/parport_sunbpp.c linux-2.4.29/drivers/parport/parport_sunbpp.c
--- linux-2.4.28-bk7/drivers/parport/parport_sunbpp.c	2001-06-11 19:15:27.000000000 -0700
+++ linux-2.4.29/drivers/parport/parport_sunbpp.c	2005-01-19 07:08:09.254473176 -0800
@@ -4,7 +4,7 @@
  * Author: Derrick J. Brashear <shadow@dementia.org>
  *
  * based on work by:
- *          Phil Blundell <Philip.Blundell@pobox.com>
+ *          Phil Blundell <philb@gnu.org>
  *          Tim Waugh <tim@cyberelk.demon.co.uk>
  *	    Jose Renau <renau@acm.org>
  *          David Campbell <campbell@tirian.che.curtin.edu.au>
diff -urN linux-2.4.28-bk7/drivers/parport/probe.c linux-2.4.29/drivers/parport/probe.c
--- linux-2.4.28-bk7/drivers/parport/probe.c	2001-05-22 19:54:04.000000000 -0700
+++ linux-2.4.29/drivers/parport/probe.c	2005-01-19 07:08:09.255473219 -0800
@@ -2,7 +2,7 @@
  * Parallel port device probing code
  *
  * Authors:    Carsten Gross, carsten@sol.wohnheim.uni-ulm.de
- *             Philip Blundell <Philip.Blundell@pobox.com>
+ *             Philip Blundell <philb@gnu.org>
  */
 
 #include <linux/parport.h>
diff -urN linux-2.4.28-bk7/drivers/s390/char/con3215.c linux-2.4.29/drivers/s390/char/con3215.c
--- linux-2.4.28-bk7/drivers/s390/char/con3215.c	2003-08-25 04:44:42.000000000 -0700
+++ linux-2.4.29/drivers/s390/char/con3215.c	2005-01-19 07:08:09.873499986 -0800
@@ -363,10 +363,7 @@
 	tty = raw->tty;
 	if (tty != NULL &&
 	    RAW3215_BUFFER_SIZE - raw->count >= RAW3215_MIN_SPACE) {
-		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-		    tty->ldisc.write_wakeup)
-			(tty->ldisc.write_wakeup)(tty);
-		wake_up_interruptible(&tty->write_wait);
+		tty_wakeup(tty);
 	}
 }
 
@@ -978,10 +975,7 @@
 
 	raw = (raw3215_info *) tty->driver_data;
 	raw3215_flush_buffer(raw);
-	wake_up_interruptible(&tty->write_wait);
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	    tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup)(tty);
+	tty_wakeup(tty);
 }
 
 /*
diff -urN linux-2.4.28-bk7/drivers/s390/char/tubtty.c linux-2.4.29/drivers/s390/char/tubtty.c
--- linux-2.4.28-bk7/drivers/s390/char/tubtty.c	2002-11-28 15:53:14.000000000 -0800
+++ linux-2.4.29/drivers/s390/char/tubtty.c	2005-01-19 07:08:10.026506612 -0800
@@ -445,10 +445,7 @@
 		ob->bc_cnt = 0;
 		TUBUNLOCK(tubp->irq, flags);
 	}
-	wake_up_interruptible(&tty->write_wait);
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	    tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup)(tty);
+	tty_wakeup(tty);
 }
 
 static int
@@ -646,10 +643,7 @@
 	}
 
 	if (tty != NULL) {
-		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-		    tty->ldisc.write_wakeup != NULL)
-			(tty->ldisc.write_wakeup)(tty);
-		wake_up_interruptible(&tty->write_wait);
+		tty_wakeup(tty);
 	}
 do_unlock:
 	TUBUNLOCK(tubp->irq, flags);
diff -urN linux-2.4.28-bk7/drivers/s390/net/ctctty.c linux-2.4.29/drivers/s390/net/ctctty.c
--- linux-2.4.28-bk7/drivers/s390/net/ctctty.c	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.29/drivers/s390/net/ctctty.c	2005-01-19 07:08:10.124510857 -0800
@@ -362,9 +362,8 @@
 
 		info->flags &= ~CTC_ASYNC_TX_LINESTAT;
 		if (tty) {
-			if (wake && (tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-			    tty->ldisc.write_wakeup)
-				(tty->ldisc.write_wakeup)(tty);
+			if (wake)
+				tty_wakeup(tty);
 			wake_up_interruptible(&tty->write_wait);
 		}
 	}
@@ -655,10 +654,7 @@
 	skb_queue_purge(&info->tx_queue);
 	info->lsr |= UART_LSR_TEMT;
 	restore_flags(flags);
-	wake_up_interruptible(&tty->write_wait);
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	    tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup) (tty);
+	tty_wakeup(tty);
 }
 
 static void
@@ -1168,8 +1164,7 @@
 	ctc_tty_shutdown(info);
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
+	tty_ldisc_flush(tty);
 	spin_lock_irqsave(&ctc_tty_lock, saveflags);
 	info->tty = 0;
 	spin_unlock_irqrestore(&ctc_tty_lock, saveflags);
diff -urN linux-2.4.28-bk7/drivers/sbus/char/aurora.c linux-2.4.29/drivers/sbus/char/aurora.c
--- linux-2.4.28-bk7/drivers/sbus/char/aurora.c	2002-11-28 15:53:14.000000000 -0800
+++ linux-2.4.29/drivers/sbus/char/aurora.c	2005-01-19 07:08:10.229515405 -0800
@@ -1573,8 +1573,7 @@
 	aurora_shutdown_port(bp, port);
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
+	tty_ldisc_flush(tty);
 	tty->closing = 0;
 	port->event = 0;
 	port->tty = 0;
@@ -1785,11 +1784,8 @@
 	save_flags(flags); cli();
 	port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
 	restore_flags(flags);
-	
-	wake_up_interruptible(&tty->write_wait);
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	    tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup)(tty);
+
+	tty_wakeup(tty);	
 #ifdef AURORA_DEBUG
 	printk("aurora_flush_buffer: end\n");
 #endif
@@ -2286,10 +2282,7 @@
 		return;
 
 	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) {
-		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-		    tty->ldisc.write_wakeup)
-			(tty->ldisc.write_wakeup)(tty);
-		wake_up_interruptible(&tty->write_wait);
+		tty_wakeup(tty);
 	}
 #ifdef AURORA_DEBUG
 	printk("do_softint: end\n");
diff -urN linux-2.4.28-bk7/drivers/sbus/char/sab82532.c linux-2.4.29/drivers/sbus/char/sab82532.c
--- linux-2.4.28-bk7/drivers/sbus/char/sab82532.c	2002-08-02 17:39:44.000000000 -0700
+++ linux-2.4.29/drivers/sbus/char/sab82532.c	2005-01-19 07:08:10.231515491 -0800
@@ -669,10 +669,7 @@
 		return;
 
 	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
-		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-		    tty->ldisc.write_wakeup)
-			(tty->ldisc.write_wakeup)(tty);
-		wake_up_interruptible(&tty->write_wait);
+		tty_wakeup(tty);
 	}
 }
 
@@ -1206,10 +1203,7 @@
 	info->xmit.head = info->xmit.tail = 0;
 	restore_flags(flags);
 
-	wake_up_interruptible(&tty->write_wait);
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	    tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup)(tty);
+	tty_wakeup(tty);
 }
 
 /*
@@ -1667,8 +1661,7 @@
 	shutdown(info);
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
+	tty_ldisc_flush(tty);
 	tty->closing = 0;
 	info->event = 0;
 	info->tty = 0;
diff -urN linux-2.4.28-bk7/drivers/sbus/char/su.c linux-2.4.29/drivers/sbus/char/su.c
--- linux-2.4.28-bk7/drivers/sbus/char/su.c	2002-08-02 17:39:44.000000000 -0700
+++ linux-2.4.29/drivers/sbus/char/su.c	2005-01-19 07:08:10.233515578 -0800
@@ -698,10 +698,7 @@
 		return;
 
 	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
-		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-		    tty->ldisc.write_wakeup)
-			(tty->ldisc.write_wakeup)(tty);
-		wake_up_interruptible(&tty->write_wait);
+		tty_wakeup(tty);
 	}
 }
 
@@ -1313,10 +1310,7 @@
 	save_flags(flags); cli();
 	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
 	restore_flags(flags);
-	wake_up_interruptible(&tty->write_wait);
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	    tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup)(tty);
+	tty_wakeup(tty);
 }
 
 /*
@@ -1815,8 +1809,7 @@
 	shutdown(info);
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
+	tty_ldisc_flush(tty);
 	tty->closing = 0;
 	info->event = 0;
 	info->tty = 0;
diff -urN linux-2.4.28-bk7/drivers/sbus/char/zs.c linux-2.4.29/drivers/sbus/char/zs.c
--- linux-2.4.28-bk7/drivers/sbus/char/zs.c	2002-08-02 17:39:44.000000000 -0700
+++ linux-2.4.29/drivers/sbus/char/zs.c	2005-01-19 07:08:10.236515708 -0800
@@ -746,10 +746,7 @@
 		return;
 
 	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
-		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-		    tty->ldisc.write_wakeup)
-			(tty->ldisc.write_wakeup)(tty);
-		wake_up_interruptible(&tty->write_wait);
+		tty_wakeup(tty);
 	}
 }
 
@@ -1199,10 +1196,7 @@
 	cli();
 	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
 	sti();
-	wake_up_interruptible(&tty->write_wait);
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	    tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup)(tty);
+	tty_wakeup(tty);
 }
 
 /*
@@ -1600,15 +1594,14 @@
 	shutdown(info);
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
+	tty_ldisc_flush(tty);
 	tty->closing = 0;
 	info->event = 0;
 	info->tty = 0;
-	if (tty->ldisc.num != ldiscs[N_TTY].num) {
+	if (tty->ldisc.num != N_TTY) {
 		if (tty->ldisc.close)
 			(tty->ldisc.close)(tty);
-		tty->ldisc = ldiscs[N_TTY];
+		tty->ldisc = *(tty_ldisc_get(N_TTY));
 		tty->termios->c_line = N_TTY;
 		if (tty->ldisc.open)
 			(tty->ldisc.open)(tty);
diff -urN linux-2.4.28-bk7/drivers/scsi/Config.in linux-2.4.29/drivers/scsi/Config.in
--- linux-2.4.28-bk7/drivers/scsi/Config.in	2005-01-19 07:07:42.140298834 -0800
+++ linux-2.4.29/drivers/scsi/Config.in	2005-01-19 07:08:10.237515751 -0800
@@ -72,7 +72,7 @@
 dep_tristate '  AHCI SATA support (EXPERIMENTAL)' CONFIG_SCSI_SATA_AHCI $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL
 dep_tristate '  ServerWorks Frodo / Apple K2 SATA support (EXPERIMENTAL)' CONFIG_SCSI_SATA_SVW $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL
 dep_tristate '  Intel PIIX/ICH SATA support' CONFIG_SCSI_ATA_PIIX $CONFIG_SCSI_SATA $CONFIG_PCI
-dep_tristate '  NVIDIA SATA support (EXPERIMENTAL)' CONFIG_SCSI_SATA_NV $CONFIG_SCSI_SATA $CONFIG_PCI
+dep_tristate '  NVIDIA SATA support (EXPERIMENTAL)' CONFIG_SCSI_SATA_NV $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL
 dep_tristate '  Promise SATA TX2/TX4 support (EXPERIMENTAL)' CONFIG_SCSI_SATA_PROMISE $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL
 dep_tristate '  Promise SATA SX4 support (EXPERIMENTAL)' CONFIG_SCSI_SATA_SX4 $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL
 dep_tristate '  Silicon Image SATA support (EXPERIMENTAL)' CONFIG_SCSI_SATA_SIL $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL
diff -urN linux-2.4.28-bk7/drivers/scsi/aacraid/README linux-2.4.29/drivers/scsi/aacraid/README
--- linux-2.4.28-bk7/drivers/scsi/aacraid/README	2003-08-25 04:44:42.000000000 -0700
+++ linux-2.4.29/drivers/scsi/aacraid/README	2005-01-19 07:08:10.238515794 -0800
@@ -30,7 +30,7 @@
 Alan Cox <alan@redhat.com>
 Christoph Hellwig <hch@infradead.org>	(small cleanups/fixes)
 Matt Domsch <matt_domsch@dell.com>	(revision ioctl, adapter messages)
-Deanna Bonds <deanna_bonds@adaptec.com> (non-DASD support, PAE fibs and 64 bit, added new adaptec controllers
+Deanna Bonds                            (non-DASD support, PAE fibs and 64 bit, added new adaptec controllers
 					 added new ioctls, changed scsi interface to use new error handler,
 					 increased the number of fibs and outstanding commands to a container)
 
diff -urN linux-2.4.28-bk7/drivers/scsi/advansys.c linux-2.4.29/drivers/scsi/advansys.c
--- linux-2.4.28-bk7/drivers/scsi/advansys.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/drivers/scsi/advansys.c	2005-01-19 07:08:10.728537017 -0800
@@ -713,7 +713,7 @@
      Tom Rini <trini@kernel.crashing.org> provided the CONFIG_ISA
      patch and helped with PowerPC wide and narrow board support.
 
-     Philip Blundell <philip.blundell@pobox.com> provided an
+     Philip Blundell <philb@gnu.org> provided an
      advansys_interrupts_enabled patch.
 
      Dave Jones <dave@denial.force9.co.uk> reported the compiler
diff -urN linux-2.4.28-bk7/drivers/scsi/ahci.c linux-2.4.29/drivers/scsi/ahci.c
--- linux-2.4.28-bk7/drivers/scsi/ahci.c	2005-01-19 07:07:42.142298920 -0800
+++ linux-2.4.29/drivers/scsi/ahci.c	2005-01-19 07:08:10.730537104 -0800
@@ -231,7 +231,8 @@
 	{
 		.sht		= &ahci_sht,
 		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-				  ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO,
+				  ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO |
+				  ATA_FLAG_PIO_DMA,
 		.pio_mask	= 0x03, /* pio3-4 */
 		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
 		.port_ops	= &ahci_ops,
@@ -240,9 +241,13 @@
 
 static struct pci_device_id ahci_pci_tbl[] = {
 	{ PCI_VENDOR_ID_INTEL, 0x2652, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_ahci },
+	  board_ahci }, /* ICH6 */
 	{ PCI_VENDOR_ID_INTEL, 0x2653, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_ahci },
+	  board_ahci }, /* ICH6M */
+	{ PCI_VENDOR_ID_INTEL, 0x27c1, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	  board_ahci }, /* ICH7 */
+	{ PCI_VENDOR_ID_INTEL, 0x27c5, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	  board_ahci }, /* ICH7M */
 	{ }	/* terminate list */
 };
 
diff -urN linux-2.4.28-bk7/drivers/scsi/ata_piix.c linux-2.4.29/drivers/scsi/ata_piix.c
--- linux-2.4.28-bk7/drivers/scsi/ata_piix.c	2005-01-19 07:07:42.143298964 -0800
+++ linux-2.4.29/drivers/scsi/ata_piix.c	2005-01-19 07:08:10.732537190 -0800
@@ -60,6 +60,7 @@
 	piix4_pata		= 2,
 	ich6_sata		= 3,
 	ich6_sata_rm		= 4,
+	ich7_sata		= 5,
 };
 
 static int piix_init_one (struct pci_dev *pdev,
@@ -90,6 +91,8 @@
 	{ 0x8086, 0x2651, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata },
 	{ 0x8086, 0x2652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_rm },
 	{ 0x8086, 0x2653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_rm },
+	{ 0x8086, 0x27c0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich7_sata },
+	{ 0x8086, 0x27c4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich7_sata },
 
 	{ }	/* terminate list */
 };
@@ -237,6 +240,18 @@
 		.udma_mask	= 0x7f,	/* udma0-6 */
 		.port_ops	= &piix_sata_ops,
 	},
+
+	/* ich7_sata */
+	{
+		.sht		= &piix_sht,
+		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_SRST |
+				  PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR |
+				  ATA_FLAG_SLAVE_POSS | PIIX_FLAG_AHCI,
+		.pio_mask	= 0x1f,	/* pio0-4 */
+		.mwdma_mask	= 0x07, /* mwdma0-2 */
+		.udma_mask	= 0x7f,	/* udma0-6 */
+		.port_ops	= &piix_sata_ops,
+	},
 };
 
 static struct pci_bits piix_enable_bits[] = {
diff -urN linux-2.4.28-bk7/drivers/scsi/dpt/dpti_ioctl.h linux-2.4.29/drivers/scsi/dpt/dpti_ioctl.h
--- linux-2.4.28-bk7/drivers/scsi/dpt/dpti_ioctl.h	2001-09-07 09:28:38.000000000 -0700
+++ linux-2.4.29/drivers/scsi/dpt/dpti_ioctl.h	2005-01-19 07:08:10.732537190 -0800
@@ -3,7 +3,7 @@
                              -------------------
     begin                : Thu Sep 7 2000
     copyright            : (C) 2001 by Adaptec
-    email                : deanna_bonds@adaptec.com
+    email                : aacraid@adaptec.com
 
     See README.dpti for history, notes, license info, and credits
  ***************************************************************************/
diff -urN linux-2.4.28-bk7/drivers/scsi/dpt_i2o.c linux-2.4.29/drivers/scsi/dpt_i2o.c
--- linux-2.4.28-bk7/drivers/scsi/dpt_i2o.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/drivers/scsi/dpt_i2o.c	2005-01-19 07:08:10.734537277 -0800
@@ -3,7 +3,7 @@
                              -------------------
     begin                : Thu Sep 7 2000
     copyright            : (C) 2000 by Adaptec
-    email                : deanna_bonds@adaptec.com
+    email                : aacraid@adaptec.com
 
     			   July 30, 2001 First version being submitted
 			   for inclusion in the kernel.  V2.4
diff -urN linux-2.4.28-bk7/drivers/scsi/dpti.h linux-2.4.29/drivers/scsi/dpti.h
--- linux-2.4.28-bk7/drivers/scsi/dpti.h	2001-09-07 09:28:38.000000000 -0700
+++ linux-2.4.29/drivers/scsi/dpti.h	2005-01-19 07:08:10.735537320 -0800
@@ -3,7 +3,7 @@
                              -------------------
     begin                : Thu Sep 7 2000
     copyright            : (C) 2001 by Adaptec
-    email                : deanna_bonds@adaptec.com
+    email                : aacraid@adaptec.com
 
     See README.dpti for history, notes, license info, and credits
  ***************************************************************************/
diff -urN linux-2.4.28-bk7/drivers/scsi/libata-core.c linux-2.4.29/drivers/scsi/libata-core.c
--- linux-2.4.28-bk7/drivers/scsi/libata-core.c	2005-01-19 07:07:42.148299180 -0800
+++ linux-2.4.29/drivers/scsi/libata-core.c	2005-01-19 07:08:10.740537537 -0800
@@ -28,6 +28,7 @@
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/list.h>
+#include <linux/mm.h>
 #include <linux/highmem.h>
 #include <linux/spinlock.h>
 #include <linux/blkdev.h>
@@ -1918,7 +1919,24 @@
 	if (idx)
 		ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
 }
+/**
+ *	ata_check_atapi_dma - Check whether ATAPI DMA can be supported
+ *	@qc: Metadata associated with taskfile to check
+ *
+ *	LOCKING:
+ *	RETURNS: 0 when ATAPI DMA can be used
+ *               nonzero otherwise
+ */
+int ata_check_atapi_dma(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	int rc = 0; /* Assume ATAPI DMA is OK by default */
 
+	if (ap->ops->check_atapi_dma)
+		rc = ap->ops->check_atapi_dma(qc);
+
+	return rc;
+}
 /**
  *	ata_qc_prep - Prepare taskfile for submission
  *	@qc: Metadata associated with taskfile to be prepared
@@ -1949,8 +1967,6 @@
 	sg->page = virt_to_page(buf);
 	sg->offset = (unsigned long) buf & ~PAGE_MASK;
 	sg_dma_len(sg) = buflen;
-
-	WARN_ON(buflen > PAGE_SIZE);
 }
 
 void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg,
@@ -2370,6 +2386,9 @@
 	unsigned long timeout = 0;
 
 	switch (ap->pio_task_state) {
+	case PIO_ST_IDLE:
+		return;
+
 	case PIO_ST:
 		ata_pio_block(ap);
 		break;
@@ -2386,7 +2405,7 @@
 	case PIO_ST_TMOUT:
 	case PIO_ST_ERR:
 		ata_pio_error(ap);
-		break;
+		return;
 	}
 
 	if (timeout) {
@@ -2394,11 +2413,7 @@
 		schedule_timeout(timeout);
 	}
 
-	if ((ap->pio_task_state != PIO_ST_IDLE) &&
-	    (ap->pio_task_state != PIO_ST_TMOUT) &&
-	    (ap->pio_task_state != PIO_ST_ERR)) {
-		schedule_task(&ap->pio_task);
-	}
+	schedule_task(&ap->pio_task);
 }
 
 static void atapi_request_sense(struct ata_port *ap, struct ata_device *dev,
@@ -2407,7 +2422,6 @@
 	DECLARE_COMPLETION(wait);
 	struct ata_queued_cmd *qc;
 	unsigned long flags;
-	int using_pio = dev->flags & ATA_DFLAG_PIO;
 	int rc;
 
 	DPRINTK("ATAPI request sense\n");
@@ -2428,16 +2442,10 @@
 	qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
 	qc->tf.command = ATA_CMD_PACKET;
 
-	if (using_pio) {
-		qc->tf.protocol = ATA_PROT_ATAPI;
-		qc->tf.lbam = (8 * 1024) & 0xff;
-		qc->tf.lbah = (8 * 1024) >> 8;
-
-		qc->nbytes = SCSI_SENSE_BUFFERSIZE;
-	} else {
-		qc->tf.protocol = ATA_PROT_ATAPI_DMA;
-		qc->tf.feature |= ATAPI_PKT_DMA;
-	}
+	qc->tf.protocol = ATA_PROT_ATAPI;
+	qc->tf.lbam = (8 * 1024) & 0xff;
+	qc->tf.lbah = (8 * 1024) >> 8;
+	qc->nbytes = SCSI_SENSE_BUFFERSIZE;
 
 	qc->waiting = &wait;
 	qc->complete_fn = ata_qc_complete_noop;
@@ -2693,6 +2701,30 @@
 	VPRINTK("EXIT\n");
 }
 
+static inline int ata_should_dma_map(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+
+	switch (qc->tf.protocol) {
+	case ATA_PROT_DMA:
+	case ATA_PROT_ATAPI_DMA:
+		return 1;
+
+	case ATA_PROT_ATAPI:
+	case ATA_PROT_PIO:
+	case ATA_PROT_PIO_MULT:
+		if (ap->flags & ATA_FLAG_PIO_DMA)
+			return 1;
+
+		/* fall through */
+
+	default:
+		return 0;
+	}
+
+	/* never reached */
+}
+
 /**
  *	ata_qc_issue - issue taskfile to device
  *	@qc: command to issue to device
@@ -2713,12 +2745,16 @@
 {
 	struct ata_port *ap = qc->ap;
 
-	if (qc->flags & ATA_QCFLAG_SG) {
-		if (ata_sg_setup(qc))
-			goto err_out;
-	} else if (qc->flags & ATA_QCFLAG_SINGLE) {
-		if (ata_sg_setup_one(qc))
-			goto err_out;
+	if (ata_should_dma_map(qc)) {
+		if (qc->flags & ATA_QCFLAG_SG) {
+			if (ata_sg_setup(qc))
+				goto err_out;
+		} else if (qc->flags & ATA_QCFLAG_SINGLE) {
+			if (ata_sg_setup_one(qc))
+				goto err_out;
+		}
+	} else {
+		qc->flags &= ~ATA_QCFLAG_DMAMAP;
 	}
 
 	ap->ops->qc_prep(qc);
diff -urN linux-2.4.28-bk7/drivers/scsi/libata-scsi.c linux-2.4.29/drivers/scsi/libata-scsi.c
--- linux-2.4.28-bk7/drivers/scsi/libata-scsi.c	2005-01-19 07:07:42.150299267 -0800
+++ linux-2.4.29/drivers/scsi/libata-scsi.c	2005-01-19 07:08:10.742537623 -0800
@@ -860,7 +860,7 @@
 	};
 	memcpy(rbuf, hdr, sizeof(hdr));
 
-	if (buflen > (ATA_SERNO_LEN + 4))
+	if (buflen > (ATA_SERNO_LEN + 4 - 1))
 		ata_dev_id_string(args->id, (unsigned char *) &rbuf[4],
 				  ATA_ID_SERNO_OFS, ATA_SERNO_LEN);
 
@@ -889,7 +889,7 @@
 	rbuf[3] = 4 + strlen(inq_83_str);	/* page len */
 
 	/* our one and only identification descriptor (vendor-specific) */
-	if (buflen > (strlen(inq_83_str) + 4 + 4)) {
+	if (buflen > (strlen(inq_83_str) + 4 + 4 - 1)) {
 		rbuf[4 + 0] = 2;	/* code set: ASCII */
 		rbuf[4 + 3] = strlen(inq_83_str);
 		memcpy(rbuf + 4 + 4, inq_83_str, strlen(inq_83_str));
@@ -1256,6 +1256,11 @@
 	int using_pio = (dev->flags & ATA_DFLAG_PIO);
 	int nodata = (cmd->sc_data_direction == SCSI_DATA_NONE);
 
+	if (!using_pio)
+		/* Check whether ATAPI DMA is safe */
+		if (ata_check_atapi_dma(qc))
+			using_pio = 1;
+
 	memcpy(&qc->cdb, scsicmd, qc->ap->cdb_len);
 
 	qc->complete_fn = atapi_qc_complete;
diff -urN linux-2.4.28-bk7/drivers/scsi/libata.h linux-2.4.29/drivers/scsi/libata.h
--- linux-2.4.28-bk7/drivers/scsi/libata.h	2005-01-19 07:07:42.150299267 -0800
+++ linux-2.4.29/drivers/scsi/libata.h	2005-01-19 07:08:10.742537623 -0800
@@ -38,6 +38,7 @@
 extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
 				      struct ata_device *dev);
 extern int ata_qc_issue(struct ata_queued_cmd *qc);
+extern int ata_check_atapi_dma(struct ata_queued_cmd *qc);
 extern void ata_dev_select(struct ata_port *ap, unsigned int device,
                            unsigned int wait, unsigned int can_sleep);
 extern void ata_tf_to_host_nolock(struct ata_port *ap, struct ata_taskfile *tf);
diff -urN linux-2.4.28-bk7/drivers/scsi/sata_nv.c linux-2.4.29/drivers/scsi/sata_nv.c
--- linux-2.4.28-bk7/drivers/scsi/sata_nv.c	2005-01-19 07:07:42.151299310 -0800
+++ linux-2.4.29/drivers/scsi/sata_nv.c	2005-01-19 07:08:10.743537667 -0800
@@ -219,10 +219,18 @@
 	.host_stop		= nv_host_stop,
 };
 
+/* FIXME: The hardware provides the necessary SATA PHY controls
+ * to support ATA_FLAG_SATA_RESET.  However, it is currently
+ * necessary to disable that flag, to solve misdetection problems.
+ * See http://bugme.osdl.org/show_bug.cgi?id=3352 for more info.
+ *
+ * This problem really needs to be investigated further.  But in the
+ * meantime, we avoid ATA_FLAG_SATA_RESET to get people working.
+ */
 static struct ata_port_info nv_port_info = {
 	.sht		= &nv_sht,
 	.host_flags	= ATA_FLAG_SATA |
-			  ATA_FLAG_SATA_RESET |
+			  /* ATA_FLAG_SATA_RESET | */
 			  ATA_FLAG_SRST |
 			  ATA_FLAG_NO_LEGACY,
 	.pio_mask	= NV_PIO_MASK,
diff -urN linux-2.4.28-bk7/drivers/scsi/sata_uli.c linux-2.4.29/drivers/scsi/sata_uli.c
--- linux-2.4.28-bk7/drivers/scsi/sata_uli.c	2005-01-19 07:07:42.156299527 -0800
+++ linux-2.4.29/drivers/scsi/sata_uli.c	2005-01-19 07:08:10.774539009 -0800
@@ -32,16 +32,18 @@
 #include <linux/libata.h>
 
 #define DRV_NAME	"sata_uli"
-#define DRV_VERSION	"0.2"
+#define DRV_VERSION	"0.5"
 
 enum {
 	uli_5289		= 0,
 	uli_5287		= 1,
+	uli_5281		= 2,
 
 	/* PCI configuration registers */
-	ULI_SCR_BASE		= 0x90, /* sata0 phy SCR registers */
-	ULI_SATA1_OFS		= 0x10, /* offset from sata0->sata1 phy regs */
-
+	ULI5287_BASE		= 0x90, /* sata0 phy SCR registers */
+	ULI5287_OFFS		= 0x10, /* offset from sata0->sata1 phy regs */
+	ULI5281_BASE		= 0x60, /* sata0 phy SCR  registers */
+	ULI5281_OFFS		= 0x60, /* offset from sata0->sata1 phy regs */
 };
 
 static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
@@ -51,6 +53,7 @@
 static struct pci_device_id uli_pci_tbl[] = {
 	{ PCI_VENDOR_ID_AL, 0x5289, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5289 },
 	{ PCI_VENDOR_ID_AL, 0x5287, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5287 },
+	{ PCI_VENDOR_ID_AL, 0x5281, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5281 },
 	{ }	/* terminate list */
 };
 
@@ -126,33 +129,15 @@
 MODULE_DEVICE_TABLE(pci, uli_pci_tbl);
 MODULE_VERSION(DRV_VERSION);
 
-static unsigned int get_scr_cfg_addr(unsigned int port_no, unsigned int sc_reg)
+static unsigned int get_scr_cfg_addr(struct ata_port *ap, unsigned int sc_reg)
 {
-	unsigned int addr = ULI_SCR_BASE + (4 * sc_reg);
-
-	switch (port_no) {
-	case 0:
-		break;
-	case 1:
-		addr += ULI_SATA1_OFS;
-		break;
-	case 2:
-		addr += ULI_SATA1_OFS*4;
-		break;
-	case 3:
-		addr += ULI_SATA1_OFS*5;
-		break;
-	default:
-		BUG();
-		break;
-	}
-	return addr;
+	return ap->ioaddr.scr_addr + (4 * sc_reg);
 }
 
 static u32 uli_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg)
 {
 	struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
-	unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, sc_reg);
+	unsigned int cfg_addr = get_scr_cfg_addr(ap, sc_reg);
 	u32 val;
 
 	pci_read_config_dword(pdev, cfg_addr, &val);
@@ -162,7 +147,7 @@
 static void uli_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val)
 {
 	struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
-	unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, scr);
+	unsigned int cfg_addr = get_scr_cfg_addr(ap, scr);
 
 	pci_write_config_dword(pdev, cfg_addr, val);
 }
@@ -220,9 +205,11 @@
 		rc = -ENOMEM;
 		goto err_out_regions;
 	}
-
+	
 	switch (board_idx) {
 	case uli_5287:
+		probe_ent->port[0].scr_addr = ULI5287_BASE;
+		probe_ent->port[1].scr_addr = ULI5287_BASE + ULI5287_OFFS;
        		probe_ent->n_ports = 4;
 
        		probe_ent->port[2].cmd_addr = pci_resource_start(pdev, 0) + 8;
@@ -230,19 +217,27 @@
 		probe_ent->port[2].ctl_addr =
 			(pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS) + 4;
 		probe_ent->port[2].bmdma_addr = pci_resource_start(pdev, 4) + 16;
+		probe_ent->port[2].scr_addr = ULI5287_BASE + ULI5287_OFFS*4;
 
 		probe_ent->port[3].cmd_addr = pci_resource_start(pdev, 2) + 8;
 		probe_ent->port[3].altstatus_addr =
 		probe_ent->port[3].ctl_addr =
 			(pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS) + 4;
 		probe_ent->port[3].bmdma_addr = pci_resource_start(pdev, 4) + 24;
+		probe_ent->port[3].scr_addr = ULI5287_BASE + ULI5287_OFFS*5;
 
 		ata_std_ports(&probe_ent->port[2]);
 		ata_std_ports(&probe_ent->port[3]);
 		break;
 
 	case uli_5289:
-		/* do nothing; ata_pci_init_native_mode did it all */
+		probe_ent->port[0].scr_addr = ULI5287_BASE;
+		probe_ent->port[1].scr_addr = ULI5287_BASE + ULI5287_OFFS;
+		break;
+
+	case uli_5281:
+		probe_ent->port[0].scr_addr = ULI5281_BASE;
+		probe_ent->port[1].scr_addr = ULI5281_BASE + ULI5281_OFFS;
 		break;
 
 	default:
diff -urN linux-2.4.28-bk7/drivers/tc/zs.c linux-2.4.29/drivers/tc/zs.c
--- linux-2.4.28-bk7/drivers/tc/zs.c	2004-02-18 05:36:31.000000000 -0800
+++ linux-2.4.29/drivers/tc/zs.c	2005-01-19 07:08:10.896544293 -0800
@@ -695,10 +695,7 @@
 		return;
 
 	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
-		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-		    tty->ldisc.write_wakeup)
-			(tty->ldisc.write_wakeup)(tty);
-		wake_up_interruptible(&tty->write_wait);
+		tty_wakeup(tty);
 	}
 }
 
@@ -1020,10 +1017,7 @@
 	cli();
 	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
 	sti();
-	wake_up_interruptible(&tty->write_wait);
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	    tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup)(tty);
+	tty_wakeup(tty);
 }
 
 /*
@@ -1429,8 +1423,7 @@
 	shutdown(info);
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
+	tty_ldisc_flush(tty);
 	tty->closing = 0;
 	info->event = 0;
 	info->tty = 0;
diff -urN linux-2.4.28-bk7/drivers/usb/acm.c linux-2.4.29/drivers/usb/acm.c
--- linux-2.4.28-bk7/drivers/usb/acm.c	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.29/drivers/usb/acm.c	2005-01-19 07:08:10.955546849 -0800
@@ -285,10 +285,7 @@
 
 	if (!ACM_READY(acm)) return;
 
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup)(tty);
-
-	wake_up_interruptible(&tty->write_wait);
+	tty_wakeup(tty);
 }
 
 /*
diff -urN linux-2.4.28-bk7/drivers/usb/bluetooth.c linux-2.4.29/drivers/usb/bluetooth.c
--- linux-2.4.28-bk7/drivers/usb/bluetooth.c	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.29/drivers/usb/bluetooth.c	2005-01-19 07:08:11.006549058 -0800
@@ -1017,6 +1017,7 @@
 {
 	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)private, __FUNCTION__);
 	struct tty_struct *tty;
+	struct tty_ldisc *ld;
 
 	dbg("%s", __FUNCTION__);
 
@@ -1025,9 +1026,15 @@
 	}
 
 	tty = bluetooth->tty;
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) {
-		dbg("%s - write wakeup call.", __FUNCTION__);
-		(tty->ldisc.write_wakeup)(tty);
+	if (tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) {
+		ld = tty_ldisc_ref(tty);
+		if(ld) {
+			if(ld->write_wakeup) {
+				ld->write_wakeup(tty);
+				dbg("%s - write wakeup call.", __FUNCTION__);
+			}
+			tty_ldisc_deref(tty);
+		}
 	}
 
 	wake_up_interruptible(&tty->write_wait);
diff -urN linux-2.4.28-bk7/drivers/usb/gadget/Config.in linux-2.4.29/drivers/usb/gadget/Config.in
--- linux-2.4.28-bk7/drivers/usb/gadget/Config.in	2004-08-07 16:26:05.000000000 -0700
+++ linux-2.4.29/drivers/usb/gadget/Config.in	2005-01-19 07:08:11.019549621 -0800
@@ -52,9 +52,9 @@
   comment 'USB Gadget Drivers'
 
   dep_tristate '  Gadget Zero (DEVELOPMENT)' CONFIG_USB_ZERO $CONFIG_USB_GADGET_CONTROLLER
-  dep_tristate '  Ethernet Gadget (EXPERIMENTAL)' CONFIG_USB_ETH $CONFIG_USB_GADGET_CONTROLLER $CONFIG_NET
+  dep_tristate '  Ethernet Gadget' CONFIG_USB_ETH $CONFIG_USB_GADGET_CONTROLLER $CONFIG_NET
   if [ "$CONFIG_USB_ETH" = "y" -o "$CONFIG_USB_ETH" = "m" ] ; then
-    bool       '    RNDIS support (EXPERIMENTAL)' CONFIG_USB_ETH_RNDIS
+    dep_bool       '    RNDIS support (EXPERIMENTAL)' CONFIG_USB_ETH_RNDIS $CONFIG_EXPERIMENTAL
   fi
   dep_tristate '  File-backed Storage Gadget (DEVELOPMENT)' CONFIG_USB_FILE_STORAGE $CONFIG_USB_GADGET_CONTROLLER
   dep_mbool '    File-backed Storage Gadget test mode' CONFIG_USB_FILE_STORAGE_TEST $CONFIG_USB_FILE_STORAGE
diff -urN linux-2.4.28-bk7/drivers/usb/gadget/epautoconf.c linux-2.4.29/drivers/usb/gadget/epautoconf.c
--- linux-2.4.28-bk7/drivers/usb/gadget/epautoconf.c	2004-08-07 16:26:05.000000000 -0700
+++ linux-2.4.29/drivers/usb/gadget/epautoconf.c	2005-01-19 07:08:11.077552133 -0800
@@ -56,6 +56,9 @@
  *
  * Type suffixes are "-bulk", "-iso", or "-int".  Numbers are decimal.
  * Less common restrictions are implied by gadget_is_*().
+ *
+ * NOTE:  each endpoint is unidirectional, as specified by its USB
+ * descriptor.
  */
 static int __init
 ep_matches (
@@ -193,7 +196,7 @@
 		if (0 == strcmp (ep->name, name))
 			return ep;
 	}
-	return 0;
+	return NULL;
 }
 
 /**
@@ -281,7 +284,7 @@
 	}
 
 	/* Fail */
-	return 0;
+	return NULL;
 }
 
 /**
@@ -298,7 +301,7 @@
 	struct usb_ep	*ep;
 
 	list_for_each_entry (ep, &gadget->ep_list, ep_list) {
-		ep->driver_data = 0;
+		ep->driver_data = NULL;
 	}
 #ifdef	MANY_ENDPOINTS
 	in_epnum = 0;
diff -urN linux-2.4.28-bk7/drivers/usb/gadget/ether.c linux-2.4.29/drivers/usb/gadget/ether.c
--- linux-2.4.28-bk7/drivers/usb/gadget/ether.c	2004-08-07 16:26:05.000000000 -0700
+++ linux-2.4.29/drivers/usb/gadget/ether.c	2005-01-19 07:08:11.195557243 -0800
@@ -62,6 +62,7 @@
 
 /*
  * Ethernet gadget driver -- with CDC and non-CDC options
+ * Builds on hardware support for a full duplex link.
  *
  * CDC Ethernet is the standard USB solution for sending Ethernet frames
  * using USB.  Real hardware tends to use the same framing protocol but look
@@ -82,7 +83,7 @@
  */
 
 #define DRIVER_DESC		"Ethernet Gadget"
-#define DRIVER_VERSION		"St Patrick's Day 2004"
+#define DRIVER_VERSION		"Equinox 2004"
 
 static const char shortname [] = "ether";
 static const char driver_desc [] = DRIVER_DESC;
@@ -239,6 +240,10 @@
 #define	DEV_CONFIG_CDC
 #endif
 
+#ifdef CONFIG_USB_GADGET_LH7A40X
+#define DEV_CONFIG_CDC
+#endif
+
 #ifdef CONFIG_USB_GADGET_MQ11XX
 #define	DEV_CONFIG_CDC
 #endif
@@ -247,6 +252,14 @@
 #define	DEV_CONFIG_CDC
 #endif
 
+#ifdef CONFIG_USB_GADGET_N9604
+#define	DEV_CONFIG_CDC
+#endif
+
+#ifdef CONFIG_USB_GADGET_PXA27X
+#define DEV_CONFIG_CDC
+#endif
+
 
 /* For CDC-incapable hardware, choose the simple cdc subset.
  * Anything that talks bulk (without notable bugs) can do this.
@@ -355,6 +368,9 @@
  *
  * NOTE:  Controllers like superh_udc should probably be able to use
  * an RNDIS-only configuration.
+ *
+ * FIXME define some higher-powered configurations to make it easier
+ * to recharge batteries ...
  */
 
 #define DEV_CONFIG_VALUE	1	/* cdc or subset */
@@ -378,6 +394,14 @@
 	.bNumConfigurations =	1,
 };
 
+static struct usb_otg_descriptor
+otg_descriptor = {
+	.bLength =		sizeof otg_descriptor,
+	.bDescriptorType =	USB_DT_OTG,
+
+	.bmAttributes =		USB_OTG_SRP,
+};
+
 static struct usb_config_descriptor
 eth_config = {
 	.bLength =		sizeof eth_config,
@@ -388,11 +412,11 @@
 	.bConfigurationValue =	DEV_CONFIG_VALUE,
 	.iConfiguration =	STRING_CDC,
 	.bmAttributes =		USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
-	.bMaxPower =		1,
+	.bMaxPower =		50,
 };
 
 #ifdef	CONFIG_USB_ETH_RNDIS
-static const struct usb_config_descriptor 
+static struct usb_config_descriptor 
 rndis_config = {
 	.bLength =              sizeof rndis_config,
 	.bDescriptorType =      USB_DT_CONFIG,
@@ -402,7 +426,7 @@
 	.bConfigurationValue =  DEV_RNDIS_CONFIG_VALUE,
 	.iConfiguration =       STRING_RNDIS,
 	.bmAttributes =		USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
-	.bMaxPower =            1,
+	.bMaxPower =            50,
 };
 #endif
 
@@ -688,7 +712,8 @@
 	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 };
 
-static const struct usb_descriptor_header *fs_eth_function [10] = {
+static const struct usb_descriptor_header *fs_eth_function [11] = {
+	(struct usb_descriptor_header *) &otg_descriptor,
 #ifdef DEV_CONFIG_CDC
 	/* "cdc" mode descriptors */
 	(struct usb_descriptor_header *) &control_intf,
@@ -702,24 +727,25 @@
 	(struct usb_descriptor_header *) &data_intf,
 	(struct usb_descriptor_header *) &fs_source_desc,
 	(struct usb_descriptor_header *) &fs_sink_desc,
-	0,
+	NULL,
 #endif /* DEV_CONFIG_CDC */
 };
 
 static inline void __init fs_subset_descriptors(void)
 {
 #ifdef DEV_CONFIG_SUBSET
-	fs_eth_function[0] = (struct usb_descriptor_header *) &subset_data_intf;
-	fs_eth_function[1] = (struct usb_descriptor_header *) &fs_source_desc;
-	fs_eth_function[2] = (struct usb_descriptor_header *) &fs_sink_desc;
-	fs_eth_function[3] = 0;
+	fs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf;
+	fs_eth_function[2] = (struct usb_descriptor_header *) &fs_source_desc;
+	fs_eth_function[3] = (struct usb_descriptor_header *) &fs_sink_desc;
+	fs_eth_function[4] = NULL;
 #else
-	fs_eth_function[0] = 0;
+	fs_eth_function[1] = NULL;
 #endif
 }
 
 #ifdef	CONFIG_USB_ETH_RNDIS
 static const struct usb_descriptor_header *fs_rndis_function [] = {
+	(struct usb_descriptor_header *) &otg_descriptor,
 	/* control interface matches ACM, not Ethernet */
 	(struct usb_descriptor_header *) &rndis_control_intf,
 	(struct usb_descriptor_header *) &header_desc,
@@ -731,7 +757,7 @@
 	(struct usb_descriptor_header *) &rndis_data_intf,
 	(struct usb_descriptor_header *) &fs_source_desc,
 	(struct usb_descriptor_header *) &fs_sink_desc,
-	0,
+	NULL,
 };
 #endif
 
@@ -783,7 +809,8 @@
 	.bNumConfigurations =	1,
 };
 
-static const struct usb_descriptor_header *hs_eth_function [10] = {
+static const struct usb_descriptor_header *hs_eth_function [11] = {
+	(struct usb_descriptor_header *) &otg_descriptor,
 #ifdef DEV_CONFIG_CDC
 	/* "cdc" mode descriptors */
 	(struct usb_descriptor_header *) &control_intf,
@@ -797,24 +824,25 @@
 	(struct usb_descriptor_header *) &data_intf,
 	(struct usb_descriptor_header *) &hs_source_desc,
 	(struct usb_descriptor_header *) &hs_sink_desc,
-	0,
+	NULL,
 #endif /* DEV_CONFIG_CDC */
 };
 
 static inline void __init hs_subset_descriptors(void)
 {
 #ifdef DEV_CONFIG_SUBSET
-	hs_eth_function[0] = (struct usb_descriptor_header *) &subset_data_intf;
-	hs_eth_function[1] = (struct usb_descriptor_header *) &fs_source_desc;
-	hs_eth_function[2] = (struct usb_descriptor_header *) &fs_sink_desc;
-	hs_eth_function[3] = 0;
+	hs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf;
+	hs_eth_function[2] = (struct usb_descriptor_header *) &fs_source_desc;
+	hs_eth_function[3] = (struct usb_descriptor_header *) &fs_sink_desc;
+	hs_eth_function[4] = NULL;
 #else
-	hs_eth_function[0] = 0;
+	hs_eth_function[1] = NULL;
 #endif
 }
 
 #ifdef	CONFIG_USB_ETH_RNDIS
 static const struct usb_descriptor_header *hs_rndis_function [] = {
+	(struct usb_descriptor_header *) &otg_descriptor,
 	/* control interface matches ACM, not Ethernet */
 	(struct usb_descriptor_header *) &rndis_control_intf,
 	(struct usb_descriptor_header *) &header_desc,
@@ -826,7 +854,7 @@
 	(struct usb_descriptor_header *) &rndis_data_intf,
 	(struct usb_descriptor_header *) &hs_source_desc,
 	(struct usb_descriptor_header *) &hs_sink_desc,
-	0,
+	NULL,
 };
 #endif
 
@@ -849,7 +877,7 @@
 
 /* descriptors that are built on-demand */
 
-static char				manufacturer [40];
+static char				manufacturer [50];
 static char				product_desc [40] = DRIVER_DESC;
 
 #ifdef	DEV_CONFIG_CDC
@@ -857,7 +885,7 @@
 static char				ethaddr [2 * ETH_ALEN + 1];
 #endif
 
-/* static strings, in iso 8859/1 */
+/* static strings, in UTF-8 */
 static struct usb_string		strings [] = {
 	{ STRING_MANUFACTURER,	manufacturer, },
 	{ STRING_PRODUCT,	product_desc, },
@@ -887,19 +915,21 @@
  * complications: class descriptors, and an altsetting.
  */
 static int
-config_buf (enum usb_device_speed speed, u8 *buf, u8 type, unsigned index)
-{
-	int				len;
+config_buf (enum usb_device_speed speed,
+	u8 *buf, u8 type,
+	unsigned index, int is_otg)
+{
+	int					len;
+	const struct usb_config_descriptor	*config;
+	const struct usb_descriptor_header	**function;
 #ifdef CONFIG_USB_GADGET_DUALSPEED
 	int				hs = (speed == USB_SPEED_HIGH);
 
 	if (type == USB_DT_OTHER_SPEED_CONFIG)
 		hs = !hs;
-#define which_config(t)	(hs ? & t ## _config   : & t ## _config)
-#define which_fn(t)	(hs ? & hs_ ## t ## _function : & fs_ ## t ## _function)
+#define which_fn(t)	(hs ? hs_ ## t ## _function : fs_ ## t ## _function)
 #else
-#define	which_config(t)	(& t ## _config)
-#define	which_fn(t)	(& fs_ ## t ## _function)
+#define	which_fn(t)	(fs_ ## t ## _function)
 #endif
 
 	if (index >= device_desc.bNumConfigurations)
@@ -909,15 +939,21 @@
 	/* list the RNDIS config first, to make Microsoft's drivers
 	 * happy. DOCSIS 1.0 needs this too.
 	 */
-	if (device_desc.bNumConfigurations == 2 && index == 0)
-		len = usb_gadget_config_buf (which_config (rndis), buf,
-			USB_BUFSIZ, (const struct usb_descriptor_header **)
-				which_fn (rndis));
-	else
+	if (device_desc.bNumConfigurations == 2 && index == 0) {
+		config = &rndis_config;
+		function = which_fn (rndis);
+	} else
 #endif
-		len = usb_gadget_config_buf (which_config (eth), buf,
-			USB_BUFSIZ, (const struct usb_descriptor_header **)
-				which_fn (eth));
+	{
+		config = &eth_config;
+		function = which_fn (eth);
+	}
+
+	/* for now, don't advertise srp-only devices */
+	if (!is_otg)
+		function++;
+
+	len = usb_gadget_config_buf (config, buf, USB_BUFSIZ, function);
 	if (len < 0)
 		return len;
 	((struct usb_config_descriptor *) buf)->bDescriptorType = type;
@@ -1068,8 +1104,8 @@
 		if (dev->status_ep)
 			(void) usb_ep_disable (dev->status_ep);
 #endif
-		dev->status_ep = 0;
-		dev->status = 0;
+		dev->status_ep = NULL;
+		dev->status = NULL;
 #if defined(DEV_CONFIG_SUBSET) || defined(CONFIG_USB_ETH_RNDIS)
 		if (dev->rndis || !dev->cdc) {
 			if (dev->in_ep)
@@ -1078,10 +1114,10 @@
 				(void) usb_ep_disable (dev->out_ep);
 		}
 #endif
-		dev->in_ep = 0;
-		dev->in = 0;
-		dev->out_ep = 0;
-		dev->out = 0;
+		dev->in_ep = NULL;
+		dev->in = NULL;
+		dev->out_ep = NULL;
+		dev->out = NULL;
 	} else
 
 	/* activate non-CDC configs right away
@@ -1128,7 +1164,7 @@
 			list_del (&req->list);
 			usb_ep_free_request (dev->in_ep, req);
 		}
-		dev->in_ep = 0;
+		dev->in_ep = NULL;
 	}
 	if (dev->out_ep) {
 		usb_ep_disable (dev->out_ep);
@@ -1138,12 +1174,12 @@
 			list_del (&req->list);
 			usb_ep_free_request (dev->out_ep, req);
 		}
-		dev->out_ep = 0;
+		dev->out_ep = NULL;
 	}
 
 	if (dev->status_ep) {
 		usb_ep_disable (dev->status_ep);
-		dev->status_ep = 0;
+		dev->status_ep = NULL;
 	}
 	dev->config = 0;
 }
@@ -1187,13 +1223,20 @@
 		result = -EINVAL;
 		/* FALL THROUGH */
 	case 0:
-		return result;
+		break;
 	}
 
-	if (result)
-		eth_reset_config (dev);
-	else {
+	if (result) {
+		if (number)
+			eth_reset_config (dev);
+		usb_gadget_vbus_draw(dev->gadget,
+				dev->gadget->is_otg ? 8 : 100);
+	} else {
 		char *speed;
+		unsigned power;
+
+		power = 2 * eth_config.bMaxPower;
+		usb_gadget_vbus_draw(dev->gadget, power);
 
 		switch (gadget->speed) {
 		case USB_SPEED_FULL:	speed = "full"; break;
@@ -1204,8 +1247,8 @@
 		}
 
 		dev->config = number;
-		INFO (dev, "%s speed config #%d: %s, using %s\n",
-				speed, number, driver_desc,
+		INFO (dev, "%s speed config #%d: %d mA, %s, using %s\n",
+				speed, number, power, driver_desc,
 				dev->rndis
 					? "RNDIS"
 					: (dev->cdc
@@ -1364,8 +1407,9 @@
 static void rndis_response_complete (struct usb_ep *ep, struct usb_request *req)
 {
 	if (req->status || req->actual != req->length)
-		DEBUG (dev, "rndis response complete --> %d, %d/%d\n",
-		       req->status, req->actual, req->length);
+		DEBUG ((struct eth_dev *) ep->driver_data,
+			"rndis response complete --> %d, %d/%d\n",
+			req->status, req->actual, req->length);
 
 	/* done sending after CDC_GET_ENCAPSULATED_RESPONSE */
 }
@@ -1404,6 +1448,7 @@
 	/* descriptors just go into the pre-allocated ep0 buffer,
 	 * while config change events may enable network traffic.
 	 */
+	req->complete = eth_setup_complete;
 	switch (ctrl->bRequest) {
 
 	case USB_REQ_GET_DESCRIPTOR:
@@ -1431,7 +1476,8 @@
 		case USB_DT_CONFIG:
 			value = config_buf (gadget->speed, req->buf,
 					ctrl->wValue >> 8,
-					ctrl->wValue & 0xff);
+					ctrl->wValue & 0xff,
+					gadget->is_otg);
 			if (value >= 0)
 				value = min (ctrl->wLength, (u16) value);
 			break;
@@ -1448,6 +1494,10 @@
 	case USB_REQ_SET_CONFIGURATION:
 		if (ctrl->bRequestType != 0)
 			break;
+		if (gadget->a_hnp_support)
+			DEBUG (dev, "HNP available\n");
+		else if (gadget->a_alt_hnp_support)
+			DEBUG (dev, "HNP needs a different root port\n");
 		spin_lock (&dev->lock);
 		value = eth_set_config (dev, ctrl->wValue, GFP_ATOMIC);
 		spin_unlock (&dev->lock);
@@ -1520,7 +1570,7 @@
 		/* FIXME this is wrong, as is the assumption that
 		 * all non-PXA hardware talks real CDC ...
 		 */
-		dev_warn (&gadget->dev, "set_interface ignored!\n");
+		WARN(dev, "set_interface ignored!\n");
 #endif /* DEV_CONFIG_CDC */
 
 done_set_intf:
@@ -1614,6 +1664,8 @@
 	/* respond with data transfer before status phase? */
 	if (value >= 0) {
 		req->length = value;
+		req->zero = value < ctrl->wLength
+				&& (value % gadget->ep0->maxpacket) == 0;
 		value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
 		if (value < 0) {
 			DEBUG (dev, "ep_queue --> %d\n", value);
@@ -1651,7 +1703,7 @@
 
 static int eth_change_mtu (struct net_device *net, int new_mtu)
 {
-	struct eth_dev	*dev = (struct eth_dev *) net->priv;
+	struct eth_dev	*dev = netdev_priv(net);
 
 	// FIXME if rndis, don't change while link's live
 
@@ -1666,58 +1718,30 @@
 
 static struct net_device_stats *eth_get_stats (struct net_device *net)
 {
-	return &((struct eth_dev *) net->priv)->stats;
+	return &((struct eth_dev *)netdev_priv(net))->stats;
 }
 
-static int eth_ethtool_ioctl (struct net_device *net, void __user *useraddr)
+static void eth_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *p)
 {
-	struct eth_dev	*dev = (struct eth_dev *) net->priv;
-	u32		cmd;
-
-	if (get_user (cmd, (u32 __user *)useraddr))
-		return -EFAULT;
-	switch (cmd) {
-
-	case ETHTOOL_GDRVINFO: {	/* get driver info */
-		struct ethtool_drvinfo		info;
-
-		memset (&info, 0, sizeof info);
-		info.cmd = ETHTOOL_GDRVINFO;
-		strncpy (info.driver, shortname, sizeof info.driver);
-		strncpy (info.version, DRIVER_VERSION, sizeof info.version);
-		strncpy (info.fw_version, dev->gadget->name,
-			sizeof info.fw_version);
-		strncpy (info.bus_info, dev->gadget->dev.bus_id,
-			sizeof info.bus_info);
-		if (copy_to_user (useraddr, &info, sizeof (info)))
-			return -EFAULT;
-		return 0;
-		}
-
-	case ETHTOOL_GLINK: {		/* get link status */
-		struct ethtool_value	edata = { ETHTOOL_GLINK };
-
-		edata.data = (dev->gadget->speed != USB_SPEED_UNKNOWN);
-		if (copy_to_user (useraddr, &edata, sizeof (edata)))
-			return -EFAULT;
-		return 0;
-		}
-
-	}
-	/* Note that the ethtool user space code requires EOPNOTSUPP */
-	return -EOPNOTSUPP;
+	struct eth_dev	*dev = netdev_priv(net);
+	memset(p, 0, sizeof *p);
+	strncpy(p->driver, shortname, sizeof p->driver);
+	strncpy(p->version, DRIVER_VERSION, sizeof p->version);
+	strncpy(p->fw_version, dev->gadget->name, sizeof p->fw_version);
+	strncpy (p->bus_info, dev->gadget->dev.bus_id, sizeof p->bus_info);
 }
 
-static int eth_ioctl (struct net_device *net, struct ifreq *rq, int cmd)
+static u32 eth_get_link(struct net_device *net)
 {
-	switch (cmd) {
-	case SIOCETHTOOL:
-		return eth_ethtool_ioctl(net, rq->ifr_data);
-	default:
-		return -EOPNOTSUPP;
-	}
+	struct eth_dev	*dev = netdev_priv(net);
+	return dev->gadget->speed != USB_SPEED_UNKNOWN;
 }
 
+static struct ethtool_ops ops = {
+	.get_drvinfo = eth_get_drvinfo,
+	.get_link = eth_get_link
+};
+
 static void defer_kevent (struct eth_dev *dev, int flag)
 {
 	if (test_and_set_bit (flag, &dev->todo))
@@ -1739,9 +1763,10 @@
 
 	/* Padding up to RX_EXTRA handles minor disagreements with host.
 	 * Normally we use the USB "terminate on short read" convention;
-	 * so allow up to (N*maxpacket)-1, since that memory is normally
-	 * already allocated.  Major loss of synch means -EOVERFLOW; any
-	 * obviously corrupted packets will automatically be discarded. 
+	 * so allow up to (N*maxpacket), since that memory is normally
+	 * already allocated.  Some hardware doesn't deal well with short
+	 * reads (e.g. DMA must be N*maxpacket), so for now don't trim a
+	 * byte off the end (to force hardware errors on overflow).
 	 *
 	 * RNDIS uses internal framing, and explicitly allows senders to
 	 * pad to end-of-packet.  That's potentially nice for speed,
@@ -1754,10 +1779,6 @@
 		size += sizeof (struct rndis_packet_msg_type);
 #endif	
 	size -= size % dev->out_ep->maxpacket;
-#ifdef CONFIG_USB_ETH_RNDIS
-	if (!dev->rndis)
-#endif	
-		size--;
 
 	if ((skb = alloc_skb (size, gfp_flags)) == 0) {
 		DEBUG (dev, "no rx skb\n");
@@ -1815,7 +1836,7 @@
 		 * use skb buffers.
 		 */
 		status = netif_rx (skb);
-		skb = 0;
+		skb = NULL;
 		break;
 
 	/* software-driven interface shutdown */
@@ -1849,7 +1870,7 @@
 clean:
 		/* nobody reading rx_reqs, so no dev->lock */
 		list_add (&req->list, &dev->rx_reqs);
-		req = 0;
+		req = NULL;
 	}
 	if (req)
 		rx_submit (dev, req, GFP_ATOMIC);
@@ -1981,10 +2002,10 @@
 
 static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
 {
-	struct eth_dev		*dev = (struct eth_dev *) net->priv;
+	struct eth_dev		*dev = netdev_priv(net);
 	int			length = skb->len;
 	int			retval;
-	struct usb_request	*req = 0;
+	struct usb_request	*req = NULL;
 	unsigned long		flags;
 
 	/* FIXME check dev->cdc_filter to decide whether to send this,
@@ -2082,11 +2103,13 @@
 	}
 }
 
-static void rndis_control_ack_complete (struct usb_ep *ep, struct usb_request *req)
+static void
+rndis_control_ack_complete (struct usb_ep *ep, struct usb_request *req)
 {
 	if (req->status || req->actual != req->length)
-		DEBUG (dev, "rndis control ack complete --> %d, %d/%d\n",
-		       req->status, req->actual, req->length);
+		DEBUG ((struct eth_dev *) ep->driver_data,
+			"rndis control ack complete --> %d, %d/%d\n",
+			req->status, req->actual, req->length);
 
 	usb_ep_free_buffer(ep, req->buf, req->dma, 8);
 	usb_ep_free_request(ep, req);
@@ -2094,7 +2117,7 @@
 
 static int rndis_control_ack (struct net_device *net)
 {
-	struct eth_dev          *dev = (struct eth_dev *) net->priv;
+	struct eth_dev          *dev = netdev_priv(net);
 	u32                     length;
 	struct usb_request      *resp;
 	
@@ -2161,7 +2184,7 @@
 
 static int eth_open (struct net_device *net)
 {
-	struct eth_dev		*dev = (struct eth_dev *) net->priv;
+	struct eth_dev		*dev = netdev_priv(net);
 
 	DEBUG (dev, "%s\n", __FUNCTION__);
 	if (netif_carrier_ok (dev->net))
@@ -2171,7 +2194,7 @@
 
 static int eth_stop (struct net_device *net)
 {
-	struct eth_dev		*dev = (struct eth_dev *) net->priv;
+	struct eth_dev		*dev = netdev_priv(net);
 
 	VDEBUG (dev, "%s\n", __FUNCTION__);
 	netif_stop_queue (net);
@@ -2182,7 +2205,7 @@
 		);
 
 	/* ensure there are no more active requests */
-	if (dev->gadget->speed != USB_SPEED_UNKNOWN) {
+	if (dev->config) {
 		usb_ep_disable (dev->in_ep);
 		usb_ep_disable (dev->out_ep);
 		if (netif_carrier_ok (dev->net)) {
@@ -2227,7 +2250,7 @@
 				dev->req->buf, dev->req->dma,
 				USB_BUFSIZ);
 		usb_ep_free_request (gadget->ep0, dev->req);
-		dev->req = 0;
+		dev->req = NULL;
 	}
 
 	unregister_netdev (dev->net);
@@ -2235,7 +2258,7 @@
 
 	/* assuming we used keventd, it must quiesce too */
 	flush_scheduled_work ();
-	set_gadget_data (gadget, 0);
+	set_gadget_data (gadget, NULL);
 }
 
 static u8 __init nibble (unsigned char c)
@@ -2316,12 +2339,19 @@
 		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0207);
 	} else if (gadget_is_omap (gadget)) {
 		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0208);
+	} else if (gadget_is_lh7a40x(gadget)) {
+		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0209);
+	} else if (gadget_is_n9604(gadget)) {
+		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0210);
+	} else if (gadget_is_pxa27x(gadget)) {
+		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0211);
 	} else {
 		/* can't assume CDC works.  don't want to default to
 		 * anything less functional on CDC-capable hardware,
 		 * so we fail in this case.
 		 */
-		printk (KERN_ERR "%s: controller '%s' not recognized\n",
+		printk (KERN_ERR "%s: "
+			"controller '%s' not recognized\n",
 			shortname, gadget->name);
 		return -ENODEV;
 	}
@@ -2400,7 +2430,8 @@
 			EP_STATUS_NAME = ep->name;
 			ep->driver_data = ep;	/* claim */
 		} else if (rndis) {
-			printk (KERN_ERR "%s: can't run RNDIS on %s\n",
+			printk (KERN_ERR "%s: "
+				"can't run RNDIS on %s\n",
 				shortname, gadget->name);
 			return -ENODEV;
 		} else if (cdc) {
@@ -2444,10 +2475,20 @@
 	device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
 	usb_gadget_set_selfpowered (gadget);
 
+	if (gadget->is_otg) {
+		otg_descriptor.bmAttributes |= USB_OTG_HNP,
+		eth_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+		eth_config.bMaxPower = 4;
+#ifdef	CONFIG_USB_ETH_RNDIS
+		rndis_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+		rndis_config.bMaxPower = 4;
+#endif
+	}
+
  	net = alloc_etherdev (sizeof *dev);
  	if (!net)
 		return status;
-	dev = net->priv;
+	dev = netdev_priv(net);
 	spin_lock_init (&dev->lock);
 	INIT_WORK (&dev->work, eth_work, dev);
 	INIT_LIST_HEAD (&dev->tx_reqs);
@@ -2491,7 +2532,7 @@
 	net->stop = eth_stop;
 	// watchdog_timeo, tx_timeout ...
 	// set_multicast_list
-	net->do_ioctl = eth_ioctl;
+	SET_ETHTOOL_OPS(net, &ops);
 
 	/* preallocate control response and buffer */
 	dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL);
@@ -2572,7 +2613,7 @@
 	return status;
 
 fail1:
-	pr_debug ("%s: register_netdev failed, %d\n", shortname, status);
+	DEBUG (dev, "register_netdev failed, %d\n", status);
 fail:
 	eth_unbind (gadget);
 	return status;
diff -urN linux-2.4.28-bk7/drivers/usb/gadget/gadget_chips.h linux-2.4.29/drivers/usb/gadget/gadget_chips.h
--- linux-2.4.28-bk7/drivers/usb/gadget/gadget_chips.h	2004-08-07 16:26:05.000000000 -0700
+++ linux-2.4.29/drivers/usb/gadget/gadget_chips.h	2005-01-19 07:08:11.264560232 -0800
@@ -44,6 +44,12 @@
 #define	gadget_is_sa1100(g)	0
 #endif
 
+#ifdef CONFIG_USB_GADGET_LH7A40X
+#define	gadget_is_lh7a40x(g)	!strcmp("lh7a40x_udc", (g)->name)
+#else
+#define	gadget_is_lh7a40x(g)	0
+#endif
+
 #ifdef CONFIG_USB_GADGET_MQ11XX
 #define	gadget_is_mq11xx(g)	!strcmp("mq11xx_udc", (g)->name)
 #else
@@ -56,6 +62,18 @@
 #define	gadget_is_omap(g)	0
 #endif
 
+#ifdef CONFIG_USB_GADGET_N9604
+#define	gadget_is_n9604(g)	!strcmp("n9604_udc", (g)->name)
+#else
+#define	gadget_is_n9604(g)	0
+#endif
+
+#ifdef CONFIG_USB_GADGET_PXA27X
+#define	gadget_is_pxa27x(g)	!strcmp("pxa27x_udc", (g)->name)
+#else
+#define	gadget_is_pxa27x(g)	0
+#endif
+
 // CONFIG_USB_GADGET_AT91RM9200
 // CONFIG_USB_GADGET_SX2
 // CONFIG_USB_GADGET_AU1X00
diff -urN linux-2.4.28-bk7/drivers/usb/gadget/rndis.c linux-2.4.29/drivers/usb/gadget/rndis.c
--- linux-2.4.28-bk7/drivers/usb/gadget/rndis.c	2004-08-07 16:26:05.000000000 -0700
+++ linux-2.4.29/drivers/usb/gadget/rndis.c	2005-01-19 07:08:11.478569500 -0800
@@ -70,8 +70,6 @@
 
 #define RNDIS_MAX_CONFIGS	1
 
-static struct proc_dir_entry *rndis_connect_dir;
-static struct proc_dir_entry *rndis_connect_state [RNDIS_MAX_CONFIGS];
 
 static rndis_params rndis_per_dev_params [RNDIS_MAX_CONFIGS];
 
@@ -1275,7 +1273,12 @@
 	return 0;
 }
 
-int rndis_proc_read (char *page, char **start, off_t off, int count, int *eof, 
+
+#ifdef	CONFIG_USB_GADGET_DEBUG_FILES
+
+#include <asm/uaccess.h>
+
+static int rndis_proc_read (char *page, char **start, off_t off, int count, int *eof, 
 		     void *data)
 {
 	char *out = page;
@@ -1320,14 +1323,18 @@
 	return len;
 }
 
-int rndis_proc_write (struct file *file, const char *buffer, 
+static int rndis_proc_write (struct file *file, const char __user *buffer, 
 		      unsigned long count, void *data)
 {
+	rndis_params *p = data;
 	u32 speed = 0;
 	int i, fl_speed = 0;
 	
 	for (i = 0; i < count; i++) {
-		switch (*buffer) {
+		char c;
+		if (get_user(c, buffer))
+			return -EFAULT;
+		switch (c) {
 		case '0':
 		case '1':
 		case '2':
@@ -1339,21 +1346,19 @@
 		case '8':
 		case '9':
 			fl_speed = 1;
-			speed = speed*10 + *buffer - '0';
+			speed = speed*10 + c - '0';
 			break;
 		case 'C':
 		case 'c':
-			rndis_signal_connect (((rndis_params *) data)
-				->confignr);
+			rndis_signal_connect (p->confignr);
 			break;
 		case 'D':
 		case 'd':
-			rndis_signal_disconnect (((rndis_params *) data)
-				->confignr);
+			rndis_signal_disconnect(p->confignr);
 			break;
 		default: 
-			if (fl_speed) ((rndis_params *) data)->speed = speed;
-			else DEBUG ("%c is not valid\n", *buffer);
+			if (fl_speed) p->speed = speed;
+			else DEBUG ("%c is not valid\n", c);
 			break;
 		}
 		
@@ -1363,43 +1368,40 @@
 	return count;
 }
 
+#define	NAME_TEMPLATE	"driver/rndis-%03d"
+
+static struct proc_dir_entry *rndis_connect_state [RNDIS_MAX_CONFIGS];
+
+#endif	/* CONFIG_USB_GADGET_DEBUG_FILES */
+
+
 int __init rndis_init (void)
 {
 	u8 i;
-	char name [4];
 
-	/* FIXME this should probably be /proc/driver/rndis,
-	 * and only if debugging is enabled
-	 */
-	
-	if (!(rndis_connect_dir =  proc_mkdir ("rndis", NULL))) {
-		printk (KERN_ERR "%s: couldn't create /proc/rndis entry", 
-			__FUNCTION__);
-		return -EIO;
-	}
-	
 	for (i = 0; i < RNDIS_MAX_CONFIGS; i++) {
-		sprintf (name, "%03d", i);
+#ifdef	CONFIG_USB_GADGET_DEBUG_FILES
+		char name [20];
+
+		sprintf (name, NAME_TEMPLATE, i);
 		if (!(rndis_connect_state [i]
-				= create_proc_entry (name, 0660,
-						rndis_connect_dir))) 
+				= create_proc_entry (name, 0660, NULL))) 
 		{
 			DEBUG ("%s :remove entries", __FUNCTION__);
-			for (i--; i > 0; i--) {
-				sprintf (name, "%03d", i);
-				remove_proc_entry (name, rndis_connect_dir);
+			while (i) {
+				sprintf (name, NAME_TEMPLATE, --i);
+				remove_proc_entry (name, NULL);
 			}
 			DEBUG ("\n");
-			
-			remove_proc_entry ("000", rndis_connect_dir);
-			remove_proc_entry ("rndis", NULL);
 			return -EIO;
 		}
+
 		rndis_connect_state [i]->nlink = 1;
 		rndis_connect_state [i]->write_proc = rndis_proc_write;
 		rndis_connect_state [i]->read_proc = rndis_proc_read;
 		rndis_connect_state [i]->data = (void *)
 				(rndis_per_dev_params + i);
+#endif
 		rndis_per_dev_params [i].confignr = i;
 		rndis_per_dev_params [i].used = 0;
 		rndis_per_dev_params [i].state = RNDIS_UNINITIALIZED;
@@ -1413,14 +1415,14 @@
 
 void rndis_exit (void)
 {
+#ifdef	CONFIG_USB_GADGET_DEBUG_FILES
 	u8 i;
-	char name [4];
+	char name [20];
 	
 	for (i = 0; i < RNDIS_MAX_CONFIGS; i++) {
-		sprintf (name, "%03d", i);
-		remove_proc_entry (name, rndis_connect_dir);
+		sprintf (name, NAME_TEMPLATE, i);
+		remove_proc_entry (name, NULL);
 	}
-	remove_proc_entry ("rndis", NULL);
-	return;
+#endif
 }
 
diff -urN linux-2.4.28-bk7/drivers/usb/gadget/zero.c linux-2.4.29/drivers/usb/gadget/zero.c
--- linux-2.4.28-bk7/drivers/usb/gadget/zero.c	2004-08-07 16:26:05.000000000 -0700
+++ linux-2.4.29/drivers/usb/gadget/zero.c	2005-01-19 07:08:11.480569587 -0800
@@ -200,8 +200,13 @@
  * DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
  * Instead:  allocate your own, using normal USB-IF procedures.
  */
+#ifndef	CONFIG_USB_ZERO_HNPTEST
 #define DRIVER_VENDOR_NUM	0x0525		/* NetChip */
 #define DRIVER_PRODUCT_NUM	0xa4a0		/* Linux-USB "Gadget Zero" */
+#else
+#define DRIVER_VENDOR_NUM	0x1a0a		/* OTG test device IDs */
+#define DRIVER_PRODUCT_NUM	0xbadd
+#endif
 
 /*-------------------------------------------------------------------------*/
 
@@ -265,6 +270,14 @@
 	.bMaxPower =		1,	/* self-powered */
 };
 
+static struct usb_otg_descriptor
+otg_descriptor = {
+	.bLength =		sizeof otg_descriptor,
+	.bDescriptorType =	USB_DT_OTG,
+
+	.bmAttributes =		USB_OTG_SRP,
+};
+
 /* one interface in each configuration */
 
 static const struct usb_interface_descriptor
@@ -308,17 +321,19 @@
 };
 
 static const struct usb_descriptor_header *fs_source_sink_function [] = {
+	(struct usb_descriptor_header *) &otg_descriptor,
 	(struct usb_descriptor_header *) &source_sink_intf,
 	(struct usb_descriptor_header *) &fs_sink_desc,
 	(struct usb_descriptor_header *) &fs_source_desc,
-	0,
+	NULL,
 };
 
 static const struct usb_descriptor_header *fs_loopback_function [] = {
+	(struct usb_descriptor_header *) &otg_descriptor,
 	(struct usb_descriptor_header *) &loopback_intf,
 	(struct usb_descriptor_header *) &fs_sink_desc,
 	(struct usb_descriptor_header *) &fs_source_desc,
-	0,
+	NULL,
 };
 
 #ifdef	CONFIG_USB_GADGET_DUALSPEED
@@ -362,17 +377,19 @@
 };
 
 static const struct usb_descriptor_header *hs_source_sink_function [] = {
+	(struct usb_descriptor_header *) &otg_descriptor,
 	(struct usb_descriptor_header *) &source_sink_intf,
 	(struct usb_descriptor_header *) &hs_source_desc,
 	(struct usb_descriptor_header *) &hs_sink_desc,
-	0,
+	NULL,
 };
 
 static const struct usb_descriptor_header *hs_loopback_function [] = {
+	(struct usb_descriptor_header *) &otg_descriptor,
 	(struct usb_descriptor_header *) &loopback_intf,
 	(struct usb_descriptor_header *) &hs_source_desc,
 	(struct usb_descriptor_header *) &hs_sink_desc,
-	0,
+	NULL,
 };
 
 /* maxpacket and other transfer characteristics vary by speed. */
@@ -385,10 +402,10 @@
 
 #endif	/* !CONFIG_USB_GADGET_DUALSPEED */
 
-static char				manufacturer [40];
+static char				manufacturer [50];
 static char				serial [40];
 
-/* static strings, in iso 8859/1 */
+/* static strings, in UTF-8 */
 static struct usb_string		strings [] = {
 	{ STRING_MANUFACTURER, manufacturer, },
 	{ STRING_PRODUCT, longname, },
@@ -450,6 +467,10 @@
 			? fs_source_sink_function
 			: fs_loopback_function;
 
+	/* for now, don't advertise srp-only devices */
+	if (!gadget->is_otg)
+		function++;
+
 	len = usb_gadget_config_buf (is_source_sink
 					? &source_sink_config
 					: &loopback_config,
@@ -474,7 +495,7 @@
 				&req->dma, GFP_ATOMIC);
 		if (!req->buf) {
 			usb_ep_free_request (ep, req);
-			req = 0;
+			req = NULL;
 		}
 	}
 	return req;
@@ -491,7 +512,7 @@
 
 /* optionally require specific source/sink data patterns  */
 
-static inline int
+static int
 check_read_data (
 	struct zero_dev		*dev,
 	struct usb_ep		*ep,
@@ -525,7 +546,7 @@
 	return 0;
 }
 
-static inline void
+static void
 reinit_write_data (
 	struct zero_dev		*dev,
 	struct usb_ep		*ep,
@@ -605,7 +626,7 @@
 
 	req = alloc_ep_req (ep, buflen);
 	if (!req)
-		return 0;
+		return NULL;
 
 	memset (req->buf, 0, req->length);
 	req->complete = source_sink_complete;
@@ -619,7 +640,7 @@
 
 		ERROR (dev, "start %s --> %d\n", ep->name, status);
 		free_ep_req (ep, req);
-		req = 0;
+		req = NULL;
 	}
 
 	return req;
@@ -810,13 +831,14 @@
 	 */
 	if (dev->in_ep) {
 		usb_ep_disable (dev->in_ep);
-		dev->in_ep = 0;
+		dev->in_ep = NULL;
 	}
 	if (dev->out_ep) {
 		usb_ep_disable (dev->out_ep);
-		dev->out_ep = 0;
+		dev->out_ep = NULL;
 	}
 	dev->config = 0;
+	del_timer (&dev->resume);
 }
 
 /* change our operational config.  this code must agree with the code
@@ -908,6 +930,7 @@
 	/* usually this stores reply data in the pre-allocated ep0 buffer,
 	 * but config change events will reconfigure hardware.
 	 */
+	req->zero = 0;
 	switch (ctrl->bRequest) {
 
 	case USB_REQ_GET_DESCRIPTOR:
@@ -943,7 +966,8 @@
 		case USB_DT_STRING:
 			/* wIndex == language code.
 			 * this driver only handles one language, you can
-			 * add others even if they don't use iso8859/1
+			 * add string tables for other languages, using
+			 * any UTF-8 characters
 			 */
 			value = usb_gadget_get_string (&stringtab,
 					ctrl->wValue & 0xff, req->buf);
@@ -957,6 +981,12 @@
 	case USB_REQ_SET_CONFIGURATION:
 		if (ctrl->bRequestType != 0)
 			goto unknown;
+		if (gadget->a_hnp_support)
+			DBG (dev, "HNP available\n");
+		else if (gadget->a_alt_hnp_support)
+			DBG (dev, "HNP needs a different root port\n");
+		else
+			VDBG (dev, "HNP inactive\n");
 		spin_lock (&dev->lock);
 		value = zero_set_config (dev, ctrl->wValue, GFP_ATOMIC);
 		spin_unlock (&dev->lock);
@@ -1043,6 +1073,8 @@
 	/* respond with data transfer before status phase? */
 	if (value >= 0) {
 		req->length = value;
+		req->zero = value < ctrl->wLength
+				&& (value % gadget->ep0->maxpacket) == 0;
 		value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
 		if (value < 0) {
 			DBG (dev, "ep_queue --> %d\n", value);
@@ -1084,8 +1116,10 @@
 	/* normally the host would be woken up for something
 	 * more significant than just a timer firing...
 	 */
-	status = usb_gadget_wakeup (dev->gadget);
-	DBG (dev, "wakeup --> %d\n", status);
+	if (dev->gadget->speed != USB_SPEED_UNKNOWN) {
+		status = usb_gadget_wakeup (dev->gadget);
+		DBG (dev, "wakeup --> %d\n", status);
+	}
 }
 
 /*-------------------------------------------------------------------------*/
@@ -1102,7 +1136,7 @@
 		free_ep_req (gadget->ep0, dev->req);
 	del_timer_sync (&dev->resume);
 	kfree (dev);
-	set_gadget_data (gadget, 0);
+	set_gadget_data (gadget, NULL);
 }
 
 static int
@@ -1158,6 +1192,12 @@
 		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0207);
 	} else if (gadget_is_omap (gadget)) {
 		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0208);
+	} else if (gadget_is_lh7a40x(gadget)) {
+		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0209);
+	} else if (gadget_is_n9604(gadget)) {
+		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0210);
+	} else if (gadget_is_pxa27x(gadget)) {
+		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0211);
 	} else {
 		/* gadget zero is so simple (for now, no altsettings) that
 		 * it SHOULD NOT have problems with bulk-capable hardware.
@@ -1203,6 +1243,18 @@
 	hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
 #endif
 
+	if (gadget->is_otg) {
+		otg_descriptor.bmAttributes |= USB_OTG_HNP,
+		source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+		loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+	}
+
+	if (gadget->is_otg) {
+		otg_descriptor.bmAttributes |= USB_OTG_HNP,
+		source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+		loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+	}
+
 	usb_gadget_set_selfpowered (gadget);
 
 	init_timer (&dev->resume);
diff -urN linux-2.4.28-bk7/drivers/usb/host/ehci-q.c linux-2.4.29/drivers/usb/host/ehci-q.c
--- linux-2.4.28-bk7/drivers/usb/host/ehci-q.c	2004-02-18 05:36:31.000000000 -0800
+++ linux-2.4.29/drivers/usb/host/ehci-q.c	2005-01-19 07:08:12.251602980 -0800
@@ -83,11 +83,11 @@
 
 /*-------------------------------------------------------------------------*/
 
-/* update halted (but potentially linked) qh */
-
 static inline void
 qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd)
 {
+	BUG_ON(qh->qh_state != QH_STATE_IDLE);
+
 	qh->hw_qtd_next = QTD_NEXT (qtd->qtd_dma);
 	qh->hw_alt_next = EHCI_LIST_END;
 
@@ -96,6 +96,24 @@
 	qh->hw_token &= __constant_cpu_to_le32 (QTD_TOGGLE | QTD_STS_PING);
 }
 
+static void
+qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
+	struct ehci_qtd *qtd;
+
+	if (list_empty (&qh->qtd_list))
+		qtd = qh->dummy;
+	else {
+		qtd = list_entry (qh->qtd_list.next,
+				struct ehci_qtd, qtd_list);
+		/* first qtd may already be partially processed */
+		if (cpu_to_le32 (qtd->qtd_dma) == qh->hw_current)
+			qtd = NULL;
+	}
+	if (qtd)
+		qh_update (ehci, qh, qtd);
+}
+
 /*-------------------------------------------------------------------------*/
 
 static void qtd_copy_status (
@@ -261,6 +279,7 @@
 	spin_lock (&ehci->lock);
 }
 
+static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh);
 
 /*
  * Process and free completed qtds for a qh, returning URBs to drivers.
@@ -401,21 +420,20 @@
 	/* restore original state; caller must unlink or relink */
 	qh->qh_state = state;
 
-	/* update qh after fault cleanup */
-	if (unlikely (stopped != 0)
-			/* some EHCI 0.95 impls will overlay dummy qtds */ 
-			|| qh->hw_qtd_next == EHCI_LIST_END) {
-		if (list_empty (&qh->qtd_list))
-			end = qh->dummy;
-		else {
-			end = list_entry (qh->qtd_list.next,
-					struct ehci_qtd, qtd_list);
-			/* first qtd may already be partially processed */
-			if (cpu_to_le32 (end->qtd_dma) == qh->hw_current)
-				end = 0;
+	/* be sure the hardware's done with the qh before refreshing
+	 * it after fault cleanup, or recovering from silicon wrongly
+	 * overlaying the dummy qtd (which reduces DMA chatter).
+	 */
+	if (stopped != 0 || qh->hw_qtd_next == EHCI_LIST_END) {
+		switch (state) {
+		case QH_STATE_IDLE:
+			qh_refresh(ehci, qh);
+			break;
+		case QH_STATE_LINKED:
+			start_unlink_async (ehci, qh);
+			break;
+		/* otherwise, unlink already started */
 		}
-		if (end)
-			qh_update (ehci, qh, end);
 	}
 
 	return count;
@@ -742,8 +760,8 @@
 	qh->qh_state = QH_STATE_IDLE;
 	qh->hw_info1 = cpu_to_le32 (info1);
 	qh->hw_info2 = cpu_to_le32 (info2);
-	qh_update (ehci, qh, qh->dummy);
 	usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1);
+	qh_refresh (ehci, qh);
 	return qh;
 }
 
@@ -765,11 +783,6 @@
 		if (!(cmd & CMD_ASE)) {
 			/* in case a clear of CMD_ASE didn't take yet */
 			(void) handshake (&ehci->regs->status, STS_ASS, 0, 150);
-
-			/* force async head to be valid */
-			writel ((u32)ehci->async->qh_dma,
-					&ehci->regs->async_next);
-
 			cmd |= CMD_ASE | CMD_RUN;
 			writel (cmd, &ehci->regs->command);
 			ehci->hcd.state = USB_STATE_RUNNING;
@@ -777,7 +790,9 @@
 		}
 	}
 
-	qh->hw_token &= ~HALT_BIT;
+	/* clear halt and/or toggle; and maybe recover from silicon quirk */
+	if (qh->qh_state == QH_STATE_IDLE)
+		qh_refresh (ehci, qh);
 
 	/* splice right after start */
 	qh->qh_next = head->qh_next;
@@ -972,8 +987,6 @@
 
 /* the async qh for the qtds being reclaimed are now unlinked from the HC */
 
-static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh);
-
 static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs)
 {
 	struct ehci_qh		*qh = ehci->reclaim;
diff -urN linux-2.4.28-bk7/drivers/usb/serial/digi_acceleport.c linux-2.4.29/drivers/usb/serial/digi_acceleport.c
--- linux-2.4.28-bk7/drivers/usb/serial/digi_acceleport.c	2002-11-28 15:53:14.000000000 -0800
+++ linux-2.4.29/drivers/usb/serial/digi_acceleport.c	2005-01-19 07:08:12.868629703 -0800
@@ -614,14 +614,7 @@
 	wake_up_interruptible( &port->write_wait );
 
 	/* wake up line discipline */
-	if( (tty->flags & (1 << TTY_DO_WRITE_WAKEUP))
-	&& tty->ldisc.write_wakeup )
-		(tty->ldisc.write_wakeup)(tty);
-
-	/* wake up other tty processes */
-	wake_up_interruptible( &tty->write_wait );
-	/* For 2.2.16 backport -- wake_up_interruptible( &tty->poll_wait ); */
-
+	tty_wakeup(tty);
 }
 
 
@@ -1557,8 +1550,7 @@
 	/* flush driver and line discipline buffers */
 	if( tty->driver.flush_buffer )
 		tty->driver.flush_buffer( tty );
-	if( tty->ldisc.flush_buffer )
-		tty->ldisc.flush_buffer( tty );
+	tty_ldisc_flush(tty);
 
 	if (port->serial->dev) {
 		/* wait for transmit idle */
diff -urN linux-2.4.28-bk7/drivers/usb/serial/ftdi_sio.c linux-2.4.29/drivers/usb/serial/ftdi_sio.c
--- linux-2.4.28-bk7/drivers/usb/serial/ftdi_sio.c	2004-08-07 16:26:05.000000000 -0700
+++ linux-2.4.29/drivers/usb/serial/ftdi_sio.c	2005-01-19 07:08:12.963633818 -0800
@@ -449,6 +449,12 @@
 };
 
 
+static struct usb_device_id id_table_userdev [] = {
+	{ USB_DEVICE(-1, -1) },
+	{ }						/* Terminating entry */
+};
+
+
 static __devinitdata struct usb_device_id id_table_combined [] = {
 	{ USB_DEVICE(FTDI_VID, FTDI_IRTRANS_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_SIO_PID) },
@@ -548,6 +554,10 @@
 #define BUFSZ 512
 #define PKTSZ 64
 
+static int vendor =-1, product = -1, baud_base = 48000000/2; 
+    /* User specified VID and Product ID and baud base.  */ 
+
+
 struct ftdi_private {
 	ftdi_chip_type_t chip_type;
 				/* type of the device, either SIO or FT8U232AM */
@@ -584,6 +594,7 @@
 static int  ftdi_FT232BM_startup	(struct usb_serial *serial);
 static int  ftdi_USB_UIRT_startup	(struct usb_serial *serial);
 static int  ftdi_HE_TIRA1_startup	(struct usb_serial *serial);
+static int  ftdi_userdev_startup	(struct usb_serial *serial);
 static void ftdi_shutdown		(struct usb_serial *serial);
 static int  ftdi_open			(struct usb_serial_port *port, struct file *filp);
 static void ftdi_close			(struct usb_serial_port *port, struct file *filp);
@@ -727,6 +738,28 @@
 
 
 
+
+static struct usb_serial_device_type ftdi_userdev_device = {
+	.owner =		THIS_MODULE,
+	.name =			"FTDI SIO compatible",
+	.id_table =		id_table_userdev,
+	.num_interrupt_in =	0,
+	.num_bulk_in =		1,
+	.num_bulk_out =		1,
+	.num_ports =		1,
+	.open =			ftdi_open,
+	.close =		ftdi_close,
+	.write =		ftdi_write,
+	.write_room =		ftdi_write_room,
+	.read_bulk_callback =	ftdi_read_bulk_callback,
+	.write_bulk_callback =	ftdi_write_bulk_callback,
+	.ioctl =		ftdi_ioctl,
+	.set_termios =		ftdi_set_termios,
+	.break_ctl =		ftdi_break_ctl,
+	.startup =		ftdi_userdev_startup,
+	.shutdown =		ftdi_shutdown,
+};
+
 #define WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */
 
 /* High and low are for DTR, RTS etc etc */
@@ -1216,6 +1249,30 @@
  */
 
 
+/* Startup for the 8U232AM chip */
+static int ftdi_userdev_startup (struct usb_serial *serial)
+{
+	struct ftdi_private *priv;
+
+	priv = serial->port->private = kmalloc(sizeof(struct ftdi_private), GFP_KERNEL);
+	if (!priv){
+		err("%s- kmalloc(%Zd) failed.", __FUNCTION__, sizeof(struct ftdi_private));
+		return -ENOMEM;
+	}
+
+	priv->chip_type = FT8U232AM; /* XXX: Hmm. Keep this.... -- REW */
+	priv->baud_base = baud_base; 
+	priv->custom_divisor = 0;
+	priv->write_offset = 0;
+        init_waitqueue_head(&priv->delta_msr_wait);
+	/* This will push the characters through immediately rather
+	   than queue a task to deliver them */
+	priv->flags = ASYNC_LOW_LATENCY;
+	
+	return (0);
+}
+
+
 static void ftdi_shutdown (struct usb_serial *serial)
 { /* ftdi_shutdown */
 	
@@ -2134,6 +2191,14 @@
 	usb_serial_register (&ftdi_USB_UIRT_device);
 	usb_serial_register (&ftdi_HE_TIRA1_device);
 
+	if (vendor != -1) {
+		/* User specified USB vendor and device id */
+		/* The macro initialized "matchvendor" as the matching flags */
+		id_table_userdev[0].idVendor = vendor; 
+		id_table_userdev[0].idProduct = product;
+		usb_serial_register (&ftdi_userdev_device);
+	}
+	
 
 	info(DRIVER_VERSION ":" DRIVER_DESC);
 	return 0;
@@ -2164,3 +2229,8 @@
 MODULE_PARM(debug, "i");
 MODULE_PARM_DESC(debug, "Debug enabled or not");
 
+MODULE_PARM(vendor, "i");
+MODULE_PARM_DESC(vendor, "User specified USB idVendor");
+
+MODULE_PARM(product, "i");
+MODULE_PARM_DESC(product, "User specified USB idProduct");
diff -urN linux-2.4.28-bk7/drivers/usb/serial/io_edgeport.c linux-2.4.29/drivers/usb/serial/io_edgeport.c
--- linux-2.4.28-bk7/drivers/usb/serial/io_edgeport.c	2004-08-07 16:26:05.000000000 -0700
+++ linux-2.4.29/drivers/usb/serial/io_edgeport.c	2005-01-19 07:08:12.972634208 -0800
@@ -902,12 +902,7 @@
 
 	if (tty && edge_port->open) {
 		/* let the tty driver wakeup if it has a special write_wakeup function */
-		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) {
-			(tty->ldisc.write_wakeup)(tty);
-		}
-
-		/* tell the tty driver that something has changed */
-		wake_up_interruptible(&tty->write_wait);
+		tty_wakeup(tty);
 	}
 
 	// Release the Write URB
diff -urN linux-2.4.28-bk7/drivers/usb/serial/io_ti.c linux-2.4.29/drivers/usb/serial/io_ti.c
--- linux-2.4.28-bk7/drivers/usb/serial/io_ti.c	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.29/drivers/usb/serial/io_ti.c	2005-01-19 07:08:13.080638885 -0800
@@ -1800,12 +1800,7 @@
 	tty = port->tty;
 	if (tty) {
 		/* let the tty driver wakeup if it has a special write_wakeup function */
-		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) {
-			(tty->ldisc.write_wakeup)(tty);
-		}
-
-		/* tell the tty driver that something has changed */
-		wake_up_interruptible(&tty->write_wait);
+		tty_wakeup(tty);
 	}
 }
 
diff -urN linux-2.4.28-bk7/drivers/usb/serial/keyspan_pda.c linux-2.4.29/drivers/usb/serial/keyspan_pda.c
--- linux-2.4.28-bk7/drivers/usb/serial/keyspan_pda.c	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.29/drivers/usb/serial/keyspan_pda.c	2005-01-19 07:08:13.144641657 -0800
@@ -183,13 +183,7 @@
 	wake_up_interruptible( &port->write_wait );
 
 	/* wake up line discipline */
-	if( (tty->flags & (1 << TTY_DO_WRITE_WAKEUP))
-	&& tty->ldisc.write_wakeup )
-		(tty->ldisc.write_wakeup)(tty);
-
-	/* wake up other tty processes */
-	wake_up_interruptible( &tty->write_wait );
-	/* For 2.2.16 backport -- wake_up_interruptible( &tty->poll_wait ); */
+	tty_wakeup(tty);
 }
 
 static void keyspan_pda_request_unthrottle( struct usb_serial *serial )
diff -urN linux-2.4.28-bk7/drivers/usb/serial/mct_u232.c linux-2.4.29/drivers/usb/serial/mct_u232.c
--- linux-2.4.28-bk7/drivers/usb/serial/mct_u232.c	2004-08-07 16:26:05.000000000 -0700
+++ linux-2.4.29/drivers/usb/serial/mct_u232.c	2005-01-19 07:08:13.184643389 -0800
@@ -569,11 +569,7 @@
 
 	if (write_blocking) {
 		wake_up_interruptible(&port->write_wait);
-		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-		    tty->ldisc.write_wakeup)
-			(tty->ldisc.write_wakeup)(tty);
-		wake_up_interruptible(&tty->write_wait);
-		
+		tty_wakeup(tty);
 	} else {
 		/* from generic_write_bulk_callback */
 		queue_task(&port->tqueue, &tq_immediate);
diff -urN linux-2.4.28-bk7/drivers/usb/serial/usbserial.c linux-2.4.29/drivers/usb/serial/usbserial.c
--- linux-2.4.28-bk7/drivers/usb/serial/usbserial.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/drivers/usb/serial/usbserial.c	2005-01-19 07:08:13.499657032 -0800
@@ -1326,6 +1326,7 @@
 	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
 	struct tty_struct *tty;
 	unsigned long flags;
+	struct tty_ldisc *ld;
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
 	
@@ -1341,9 +1342,15 @@
 	if (!tty)
 		return;
 
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) {
-		dbg("%s - write wakeup call.", __FUNCTION__);
-		(tty->ldisc.write_wakeup)(tty);
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP))) {
+		ld = tty_ldisc_ref(tty);
+		if(ld) {
+			if(ld->write_wakeup) {
+				ld->write_wakeup(tty);
+				dbg("%s - write wakeup call.", __FUNCTION__);
+			}
+			tty_ldisc_deref(ld);
+		}
 	}
 
 	wake_up_interruptible(&tty->write_wait);
diff -urN linux-2.4.28-bk7/drivers/video/fbmem.c linux-2.4.29/drivers/video/fbmem.c
--- linux-2.4.28-bk7/drivers/video/fbmem.c	2004-08-07 16:26:05.000000000 -0700
+++ linux-2.4.29/drivers/video/fbmem.c	2005-01-19 07:08:13.500657076 -0800
@@ -410,6 +410,7 @@
 	struct fb_info *info = registered_fb[fbidx];
 	struct fb_ops *fb = info->fbops;
 	struct fb_fix_screeninfo fix;
+	unsigned int size;
 
 	if (! fb || ! info->disp)
 		return -ENODEV;
@@ -418,10 +419,12 @@
 		return -EINVAL;
 
 	fb->fb_get_fix(&fix,PROC_CONSOLE(info), info);
-	if (p >= fix.smem_len)
+	size = info->mapped_vram ? info->mapped_vram : fix.smem_len;
+	
+	if (p >= size)
 	    return 0;
-	if (count > fix.smem_len - p)
-		count = fix.smem_len - p;
+	if (count > size - p)
+		count = size - p;
 	if (count) {
 	    char *base_addr;
 
@@ -444,6 +447,7 @@
 	struct fb_ops *fb = info->fbops;
 	struct fb_fix_screeninfo fix;
 	int err;
+	unsigned int size;
 
 	if (! fb || ! info->disp)
 		return -ENODEV;
@@ -452,11 +456,13 @@
 		return -EINVAL;
 
 	fb->fb_get_fix(&fix, PROC_CONSOLE(info), info);
-	if (p > fix.smem_len)
+	size = info->mapped_vram ? info->mapped_vram : fix.smem_len;
+	
+	if (p > size)
 	    return -ENOSPC;
 	err = 0;
-	if (count > fix.smem_len - p) {
-	    count = fix.smem_len - p;
+	if (count > size - p) {
+	    count = size - p;
 	    err = -ENOSPC;
 	}
 	if (count) {
@@ -619,7 +625,10 @@
 
 	/* frame buffer memory */
 	start = fix.smem_start;
-	len = PAGE_ALIGN((start & ~PAGE_MASK)+fix.smem_len);
+	if (info->mapped_vram)
+		len = PAGE_ALIGN((start & ~PAGE_MASK) + info->mapped_vram);
+	else
+		len = PAGE_ALIGN((start & ~PAGE_MASK) + fix.smem_len);
 	if (off >= len) {
 		/* memory mapped io */
 		off -= len;
diff -urN linux-2.4.28-bk7/drivers/video/radeonfb.c linux-2.4.29/drivers/video/radeonfb.c
--- linux-2.4.28-bk7/drivers/video/radeonfb.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/drivers/video/radeonfb.c	2005-01-19 07:08:13.876673361 -0800
@@ -176,7 +176,8 @@
 #define RTRACE		if(0) printk
 #endif
 
-
+#define MAX_MAPPED_VRAM (2048*2048*4)
+#define MIN_MAPPED_VRAM (1024*768*1)
 
 enum radeon_chips {
 	RADEON_QD,
@@ -218,6 +219,7 @@
 	RADEON_NH,
 	RADEON_NI,
 	RADEON_AP,
+	RADEON_AQ,
 	RADEON_AR,
 };
 
@@ -279,6 +281,7 @@
 	{ "9800 NH", RADEON_R350 },
 	{ "9800 NI", RADEON_R350 },
 	{ "9600 AP", RADEON_RV350 },
+	{ "9600 AQ", RADEON_RV350 },
 	{ "9600 AR", RADEON_RV350 },
 };
 
@@ -334,6 +337,7 @@
 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Yd, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_Yd},
 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_AD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_AD},
 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_AP, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_AP},
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_AQ, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_AQ},
 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_AR, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_AR},
 	{ 0, }
 };
@@ -499,7 +503,7 @@
 
 	short chipset;
 	unsigned char arch;
-	int video_ram;
+	unsigned int video_ram;
 	u8 rev;
 	int pitch, bpp, depth;
 	int xres, yres, pixclock;
@@ -1626,6 +1630,7 @@
 				  const struct pci_device_id *ent)
 {
 	struct radeonfb_info *rinfo;
+	struct fb_info *fb_info;
 	struct radeon_chip_info *rci = &radeon_chip_info[ent->driver_data];
 	u32 tmp;
 	int i, j;
@@ -1640,6 +1645,7 @@
 
 	memset (rinfo, 0, sizeof (struct radeonfb_info));
 
+	fb_info = (struct fb_info *)rinfo;
 	rinfo->pdev = pdev;
 	strncpy(rinfo->name, rci->name, 16);
 	rinfo->arch = rci->arch;
@@ -1824,8 +1830,16 @@
 		}
 	}
 
-	rinfo->fb_base = (unsigned long) ioremap (rinfo->fb_base_phys,
-				  		  rinfo->video_ram);
+	fb_info->mapped_vram = min_t(unsigned int, MAX_MAPPED_VRAM, rinfo->video_ram);
+	do {
+		rinfo->fb_base = (unsigned long) ioremap (rinfo->fb_base_phys,
+				  		  fb_info->mapped_vram);
+		if (rinfo->fb_base)
+			break;
+
+		fb_info->mapped_vram /= 2;
+	} while(fb_info->mapped_vram > MIN_MAPPED_VRAM);
+	
 	if (!rinfo->fb_base) {
 		printk ("radeonfb: cannot map FB\n");
 		iounmap ((void*)rinfo->mmio_base);
@@ -1836,6 +1850,7 @@
 		kfree (rinfo);
 		return -ENODEV;
 	}
+	RTRACE(KERN_INFO "radeonfb: mapped %dk videoram\n", fb_info->mapped_vram/1024);
 
 	/* currcon not yet configured, will be set by first switch */
 	rinfo->currcon = -1;
@@ -2199,13 +2214,14 @@
                 {-1, -1}
         };
         int i;
+	struct fb_info *fb_info = (struct fb_info *)rinfo;
                 
         /* use highest possible virtual resolution */
         if (v->xres_virtual == -1 && v->yres_virtual == -1) {
                 printk("radeonfb: using max available virtual resolution\n");
                 for (i=0; modes[i].xres != -1; i++) {
                         if (modes[i].xres * nom / den * modes[i].yres <
-                            rinfo->video_ram / 2)
+                            fb_info->mapped_vram / 2)
                                 break;
                 }
                 if (modes[i].xres == -1) {
@@ -2218,15 +2234,15 @@
                 printk("radeonfb: virtual resolution set to max of %dx%d\n",
                         v->xres_virtual, v->yres_virtual);
         } else if (v->xres_virtual == -1) {
-                v->xres_virtual = (rinfo->video_ram * den /   
+                v->xres_virtual = (fb_info->mapped_vram * den /   
                                 (nom * v->yres_virtual * 2)) & ~15;
         } else if (v->yres_virtual == -1) {
                 v->xres_virtual = (v->xres_virtual + 15) & ~15;
-                v->yres_virtual = rinfo->video_ram * den /
+                v->yres_virtual = fb_info->mapped_vram * den /
                         (nom * v->xres_virtual *2);
         } else {
                 if (v->xres_virtual * nom / den * v->yres_virtual >
-                        rinfo->video_ram) {
+                        fb_info->mapped_vram) {
                         return -EINVAL;
                 }
         }
@@ -2430,6 +2446,9 @@
                         return -EINVAL;
         }
 
+	if (((v.xres_virtual * v.yres_virtual * nom) / den) > info->mapped_vram)
+		return -EINVAL;
+
         if (radeonfb_do_maximize(rinfo, var, &v, nom, den) < 0)
                 return -EINVAL;  
                 
diff -urN linux-2.4.28-bk7/drivers/video/vga16fb.c linux-2.4.29/drivers/video/vga16fb.c
--- linux-2.4.28-bk7/drivers/video/vga16fb.c	2005-01-19 07:07:42.294305504 -0800
+++ linux-2.4.29/drivers/video/vga16fb.c	2001-11-14 14:52:20.000000000 -0800
@@ -142,7 +142,7 @@
 	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
 	strcpy(fix->id,"VGA16 VGA");
 
-	fix->smem_start = VGA_MAP_MEM(VGA_FB_PHYS);
+	fix->smem_start = VGA_FB_PHYS;
 	fix->smem_len = VGA_FB_PHYS_LEN;
 	fix->type = FB_TYPE_VGA_PLANES;
 	fix->visual = FB_VISUAL_PSEUDOCOLOR;
@@ -896,7 +896,7 @@
 
 	/* XXX share VGA_FB_PHYS region with vgacon */
 
-        vga16fb.video_vbase = ioremap(VGA_MAP_MEM(VGA_FB_PHYS), VGA_FB_PHYS_LEN);
+        vga16fb.video_vbase = ioremap(VGA_FB_PHYS, VGA_FB_PHYS_LEN);
 	if (!vga16fb.video_vbase) {
 		printk(KERN_ERR "vga16fb: unable to map device\n");
 		return -ENOMEM;
diff -urN linux-2.4.28-bk7/fs/binfmt_aout.c linux-2.4.29/fs/binfmt_aout.c
--- linux-2.4.28-bk7/fs/binfmt_aout.c	2001-11-02 17:39:20.000000000 -0800
+++ linux-2.4.29/fs/binfmt_aout.c	2005-01-19 07:08:13.877673404 -0800
@@ -39,13 +39,21 @@
 	NULL, THIS_MODULE, load_aout_binary, load_aout_library, aout_core_dump, PAGE_SIZE
 };
 
-static void set_brk(unsigned long start, unsigned long end)
+#define BAD_ADDR(x)	((unsigned long)(x) >= TASK_SIZE)
+
+static int set_brk(unsigned long start, unsigned long end)
 {
 	start = PAGE_ALIGN(start);
 	end = PAGE_ALIGN(end);
-	if (end <= start)
-		return;
-	do_brk(start, end - start);
+	if (end > start) {
+		unsigned long addr;
+		down_write(&current->mm->mmap_sem);
+		addr = do_brk(start, end - start);
+		up_write(&current->mm->mmap_sem);
+		if (BAD_ADDR(addr))
+			return addr;
+	}
+	return 0;
 }
 
 /*
@@ -312,10 +320,14 @@
 		loff_t pos = fd_offset;
 		/* Fuck me plenty... */
 		/* <AOL></AOL> */
+		down_write(&current->mm->mmap_sem);
 		error = do_brk(N_TXTADDR(ex), ex.a_text);
+		up_write(&current->mm->mmap_sem);
 		bprm->file->f_op->read(bprm->file, (char *) N_TXTADDR(ex),
 			  ex.a_text, &pos);
+		down_write(&current->mm->mmap_sem);
 		error = do_brk(N_DATADDR(ex), ex.a_data);
+		up_write(&current->mm->mmap_sem);
 		bprm->file->f_op->read(bprm->file, (char *) N_DATADDR(ex),
 			  ex.a_data, &pos);
 		goto beyond_if;
@@ -335,8 +347,9 @@
 		pos = 32;
 		map_size = ex.a_text+ex.a_data;
 #endif
-
+		down_write(&current->mm->mmap_sem);
 		error = do_brk(text_addr & PAGE_MASK, map_size);
+		up_write(&current->mm->mmap_sem);
 		if (error != (text_addr & PAGE_MASK)) {
 			send_sig(SIGKILL, current, 0);
 			return error;
@@ -370,7 +383,9 @@
 
 		if (!bprm->file->f_op->mmap||((fd_offset & ~PAGE_MASK) != 0)) {
 			loff_t pos = fd_offset;
+			down_write(&current->mm->mmap_sem);
 			do_brk(N_TXTADDR(ex), ex.a_text+ex.a_data);
+			up_write(&current->mm->mmap_sem);
 			bprm->file->f_op->read(bprm->file,(char *)N_TXTADDR(ex),
 					ex.a_text+ex.a_data, &pos);
 			flush_icache_range((unsigned long) N_TXTADDR(ex),
@@ -405,7 +420,11 @@
 beyond_if:
 	set_binfmt(&aout_format);
 
-	set_brk(current->mm->start_brk, current->mm->brk);
+	retval = set_brk(current->mm->start_brk, current->mm->brk);
+	if (retval < 0) {
+		send_sig(SIGKILL, current, 0);
+		return retval;
+	}
 
 	retval = setup_arg_pages(bprm); 
 	if (retval < 0) { 
@@ -466,8 +485,10 @@
 			       file->f_dentry->d_name.name);
 			error_time = jiffies;
 		}
-
+		
+		down_write(&current->mm->mmap_sem);
 		do_brk(start_addr, ex.a_text + ex.a_data + ex.a_bss);
+		up_write(&current->mm->mmap_sem);
 		
 		file->f_op->read(file, (char *)start_addr,
 			ex.a_text + ex.a_data, &pos);
@@ -491,7 +512,10 @@
 	len = PAGE_ALIGN(ex.a_text + ex.a_data);
 	bss = ex.a_text + ex.a_data + ex.a_bss;
 	if (bss > len) {
+		down_write(&current->mm->mmap_sem);
 		error = do_brk(start_addr + len, bss - len);
+		up_write(&current->mm->mmap_sem);
+
 		retval = error;
 		if (error != start_addr + len)
 			goto out;
diff -urN linux-2.4.28-bk7/fs/binfmt_elf.c linux-2.4.29/fs/binfmt_elf.c
--- linux-2.4.28-bk7/fs/binfmt_elf.c	2005-01-19 07:07:42.509314817 -0800
+++ linux-2.4.29/fs/binfmt_elf.c	2005-01-19 07:08:13.878673447 -0800
@@ -84,7 +84,10 @@
 	start = ELF_PAGEALIGN(start);
 	end = ELF_PAGEALIGN(end);
 	if (end > start) {
-		unsigned long addr = do_brk(start, end - start);
+		unsigned long addr;
+		down_write(&current->mm->mmap_sem);
+		addr = do_brk(start, end - start);
+		up_write(&current->mm->mmap_sem);
 		if (BAD_ADDR(addr))
 			return addr;
 	}
@@ -290,7 +293,9 @@
 	 */
 	if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr))
 		goto out;
-	if (interp_elf_ex->e_phnum > 65536U / sizeof(struct elf_phdr))
+
+	if (interp_elf_ex->e_phnum < 1 ||
+	    interp_elf_ex->e_phnum > 65536U / sizeof(struct elf_phdr))
 		goto out;
 
 	/* Now read in all of the header information */
@@ -377,12 +382,20 @@
 
 	/* Map the last of the bss segment */
 	if (last_bss > elf_bss) {
+		down_write(&current->mm->mmap_sem);
 		error = do_brk(elf_bss, last_bss - elf_bss);
+		up_write(&current->mm->mmap_sem);
 		if (BAD_ADDR(error))
 			goto out_close;
 	}
 
 	*interp_load_addr = load_addr;
+	/*
+	 * XXX: is everything deallocated properly if this happens
+	 * to be ~0UL (that is, we succeeded, but the header is broken
+	 * and thus the caller will think that we failed)? We'd better
+	 * switch to out-of-band error reporting.
+	 */
 	error = ((unsigned long) interp_elf_ex->e_entry) + load_addr;
 
 out_close:
@@ -417,7 +430,10 @@
 		goto out;
 	}
 
+	down_write(&current->mm->mmap_sem);
 	do_brk(0, text_data);
+	up_write(&current->mm->mmap_sem);
+
 	if (!interpreter->f_op || !interpreter->f_op->read)
 		goto out;
 	if (interpreter->f_op->read(interpreter, addr, text_data, &offset) < 0)
@@ -425,8 +441,11 @@
 	flush_icache_range((unsigned long)addr,
 	                   (unsigned long)addr + text_data);
 
+	down_write(&current->mm->mmap_sem);
 	do_brk(ELF_PAGESTART(text_data + ELF_MIN_ALIGN - 1),
 		interp_ex->a_bss);
+	up_write(&current->mm->mmap_sem);
+
 	elf_entry = interp_ex->a_entry;
 
 out:
@@ -483,12 +502,13 @@
 
 	/* Now read in all of the header information */
 
-	retval = -ENOMEM;
 	if (elf_ex.e_phentsize != sizeof(struct elf_phdr))
 		goto out;
-	if (elf_ex.e_phnum > 65536U / sizeof(struct elf_phdr))
+	if (elf_ex.e_phnum < 1 ||
+	    elf_ex.e_phnum > 65536U / sizeof(struct elf_phdr))
 		goto out;
 	size = elf_ex.e_phnum * sizeof(struct elf_phdr);
+	retval = -ENOMEM;
 	elf_phdata = (struct elf_phdr *) kmalloc(size, GFP_KERNEL);
 	if (!elf_phdata)
 		goto out;
@@ -534,10 +554,12 @@
 			 * is an a.out format binary
 			 */
 
-			retval = -ENOMEM;
+			retval = -ENOEXEC;
 			if (elf_ppnt->p_filesz > PATH_MAX || 
-			    elf_ppnt->p_filesz == 0)
+			    elf_ppnt->p_filesz < 2)
 				goto out_free_file;
+
+			retval = -ENOMEM;
 			elf_interpreter = (char *) kmalloc(elf_ppnt->p_filesz,
 							   GFP_KERNEL);
 			if (!elf_interpreter)
@@ -552,7 +574,7 @@
 				goto out_free_interp;
 			}
 			/* make sure path is NULL terminated */
-			retval = -EINVAL;
+			retval = -ENOEXEC;
 			if (elf_interpreter[elf_ppnt->p_filesz - 1] != '\0')
 				goto out_free_interp;
 
@@ -795,8 +817,9 @@
 						    interpreter,
 						    &interp_load_addr);
 		if (BAD_ADDR(elf_entry)) {
-			printk(KERN_ERR "Unable to load interpreter\n");
-			send_sig(SIGSEGV, current, 0);
+			printk(KERN_ERR "Unable to load interpreter %.128s\n",
+				elf_interpreter);
+			force_sig(SIGSEGV, current);
 			retval = -ENOEXEC; /* Nobody gets to see this, but.. */
 			goto out_free_dentry;
 		}
@@ -961,8 +984,11 @@
 
 	len = ELF_PAGESTART(elf_phdata->p_filesz + elf_phdata->p_vaddr + ELF_MIN_ALIGN - 1);
 	bss = elf_phdata->p_memsz + elf_phdata->p_vaddr;
-	if (bss > len)
+	if (bss > len) {
+		down_write(&current->mm->mmap_sem);
 		do_brk(len, bss - len);
+		up_write(&current->mm->mmap_sem);
+	}
 	error = 0;
 
 out_free_ph:
diff -urN linux-2.4.28-bk7/fs/coda/upcall.c linux-2.4.29/fs/coda/upcall.c
--- linux-2.4.28-bk7/fs/coda/upcall.c	2002-08-02 17:39:45.000000000 -0700
+++ linux-2.4.29/fs/coda/upcall.c	2005-01-19 07:08:13.879673491 -0800
@@ -543,6 +543,11 @@
 		goto exit;
         }
 
+        if (data->vi.out_size > VC_MAXDATASIZE) {
+		error = -EINVAL;
+		goto exit;
+	}
+
         inp->coda_ioctl.VFid = *fid;
     
         /* the cmd field was mutated by increasing its size field to
@@ -571,26 +576,30 @@
 		       error, coda_f2s(fid));
 		goto exit; 
 	}
-        
-	/* Copy out the OUT buffer. */
+
+	if (outsize < (long)outp->coda_ioctl.data + outp->coda_ioctl.len) {
+                CDEBUG(D_FILE, "reply size %d < reply len %ld\n", outsize,
+		       (long)outp->coda_ioctl.data + outp->coda_ioctl.len);
+		error = -EINVAL;
+		goto exit;
+	}
+
         if (outp->coda_ioctl.len > data->vi.out_size) {
-                CDEBUG(D_FILE, "return len %d <= request len %d\n",
-                      outp->coda_ioctl.len, 
-                      data->vi.out_size);
+                CDEBUG(D_FILE, "return len %d > request len %d\n",
+		       outp->coda_ioctl.len, data->vi.out_size);
 		error = -EINVAL;
-        } else {
-		error = verify_area(VERIFY_WRITE, data->vi.out, 
-                                    data->vi.out_size);
-		if ( error ) goto exit;
-
-		if (copy_to_user(data->vi.out, 
-				 (char *)outp + (long)outp->coda_ioctl.data, 
-				 data->vi.out_size)) {
-			error = -EINVAL;
-			goto exit;
-		}
+		goto exit;
         }
 
+	/* Copy out the OUT buffer. */
+	error = verify_area(VERIFY_WRITE, data->vi.out, outp->coda_ioctl.len);
+	if ( error ) goto exit;
+
+	if (copy_to_user(data->vi.out, 
+			 (char *)outp + (long)outp->coda_ioctl.data, 
+			 outp->coda_ioctl.len)) {
+	    error = -EINVAL;
+	}
  exit:
 	CODA_FREE(inp, insize);
 	return error;
diff -urN linux-2.4.28-bk7/fs/exec.c linux-2.4.29/fs/exec.c
--- linux-2.4.28-bk7/fs/exec.c	2005-01-19 07:07:42.512314947 -0800
+++ linux-2.4.29/fs/exec.c	2005-01-19 07:08:13.881673577 -0800
@@ -327,7 +327,7 @@
 {
 	unsigned long stack_base;
 	struct vm_area_struct *mpnt;
-	int i;
+	int i, ret;
 
 	stack_base = STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE;
 
@@ -351,7 +351,11 @@
 		mpnt->vm_pgoff = 0;
 		mpnt->vm_file = NULL;
 		mpnt->vm_private_data = (void *) 0;
-		insert_vm_struct(current->mm, mpnt);
+		if ((ret = insert_vm_struct(current->mm, mpnt))) {
+			up_write(&current->mm->mmap_sem);
+			kmem_cache_free(vm_area_cachep, mpnt);
+			return ret;
+		}
 		current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
 	} 
 
diff -urN linux-2.4.28-bk7/fs/namei.c linux-2.4.29/fs/namei.c
--- linux-2.4.28-bk7/fs/namei.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/fs/namei.c	2005-01-19 07:08:14.150685228 -0800
@@ -326,7 +326,7 @@
 }
 
 /*
- * This limits recursive symlink follows to 8, while
+ * This limits recursive symlink follows to 5, while
  * limiting consecutive symlinks to 40.
  *
  * Without that kind of total limit, nasty chains of consecutive
diff -urN linux-2.4.28-bk7/fs/nfs/dir.c linux-2.4.29/fs/nfs/dir.c
--- linux-2.4.28-bk7/fs/nfs/dir.c	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29/fs/nfs/dir.c	2005-01-19 07:08:14.151685271 -0800
@@ -999,7 +999,7 @@
 	struct inode *old_inode = old_dentry->d_inode;
 	struct inode *new_inode = new_dentry->d_inode;
 	struct dentry *dentry = NULL, *rehash = NULL;
-	int error;
+	int error = -EBUSY;
 
 	/*
 	 * To prevent any new references to the target during the rename,
@@ -1025,12 +1025,6 @@
 	 */
 	if (!new_inode)
 		goto go_ahead;
-	/* If target is a hard link to the source, then noop */
-	error = 0;
-	if (NFS_FILEID(new_inode) == NFS_FILEID(old_inode))
-		goto out;
-
-	error = -EBUSY;
 	if (S_ISDIR(new_inode->i_mode))
 		goto out;
 	else if (atomic_read(&new_dentry->d_count) > 1) {
diff -urN linux-2.4.28-bk7/fs/nfs/unlink.c linux-2.4.29/fs/nfs/unlink.c
--- linux-2.4.28-bk7/fs/nfs/unlink.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/fs/nfs/unlink.c	2005-01-19 07:08:14.152685315 -0800
@@ -12,7 +12,6 @@
 #include <linux/sunrpc/sched.h>
 #include <linux/sunrpc/clnt.h>
 #include <linux/nfs_fs.h>
-#include <linux/wait.h>
 
 
 struct nfs_unlinkdata {
@@ -22,9 +21,6 @@
 	struct rpc_task	task;
 	struct rpc_cred	*cred;
 	unsigned int	count;
-
-	wait_queue_head_t waitq;
-	int completed;
 };
 
 static struct nfs_unlinkdata	*nfs_deletes;
@@ -130,16 +126,13 @@
 	if (nfs_async_handle_jukebox(task))
 		return;
 	if (!dir)
-		goto out;
+		return;
 	dir_i = dir->d_inode;
 	nfs_zap_caches(dir_i);
 	NFS_PROTO(dir_i)->unlink_done(dir, &task->tk_msg);
 	put_rpccred(data->cred);
 	data->cred = NULL;
 	dput(dir);
-out:
-	data->completed = 1;
-	wake_up(&data->waitq);
 }
 
 /**
@@ -182,8 +175,6 @@
 	nfs_deletes = data;
 	data->count = 1;
 
-	init_waitqueue_head(&data->waitq);
-
 	task = &data->task;
 	rpc_init_task(task, clnt, nfs_async_unlink_done , RPC_TASK_ASYNC);
 	task->tk_calldata = data;
@@ -221,10 +212,7 @@
 	data->count++;
 	nfs_copy_dname(dentry, data);
 	dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
-	if (data->task.tk_rpcwait == &nfs_delete_queue) {
-		struct rpc_clnt *clnt = data->task.tk_client;
+	if (data->task.tk_rpcwait == &nfs_delete_queue)
 		rpc_wake_up_task(&data->task);
-		nfs_wait_event(clnt, data->waitq, data->completed == 1);
-	}
 	nfs_put_unlinkdata(data);
 }
diff -urN linux-2.4.28-bk7/fs/proc/base.c linux-2.4.29/fs/proc/base.c
--- linux-2.4.28-bk7/fs/proc/base.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/fs/proc/base.c	2005-01-19 07:08:14.154685401 -0800
@@ -166,15 +166,16 @@
 	if (mm)
 		atomic_inc(&mm->mm_users);
 	task_unlock(task);
-	if (mm) {
-		unsigned int len = mm->env_end - mm->env_start;
+	if (mm && mm->env_start && mm->env_start < mm->env_end) {
+		unsigned long len = mm->env_end - mm->env_start;
 		if (len > PAGE_SIZE)
 			len = PAGE_SIZE;
 		res = access_process_vm(task, mm->env_start, buffer, len, 0);
-		if (!may_ptrace_attach(task))
+		if (res >= 0 && !may_ptrace_attach(task))
 			res = -ESRCH;
-		mmput(mm);
 	}
+	if (mm)
+		mmput(mm);
 	return res;
 }
 
@@ -187,31 +188,30 @@
 	if (mm)
 		atomic_inc(&mm->mm_users);
 	task_unlock(task);
-	if (mm) {
-		int len = mm->arg_end - mm->arg_start;
+	if (mm && mm->arg_start && mm->arg_start < mm->arg_end) {
+		unsigned long len = mm->arg_end - mm->arg_start;
 		if (len > PAGE_SIZE)
 			len = PAGE_SIZE;
 		res = access_process_vm(task, mm->arg_start, buffer, len, 0);
-		// If the nul at the end of args has been overwritten, then
-		// assume application is using setproctitle(3).
-		if ( res > 0 && buffer[res-1] != '\0' )
-		{
-			len = strnlen( buffer, res );
-			if ( len < res )
-			{
-			    res = len;
-			}
-			else
-			{
+		/* If the nul at the end of args has been overwritten, then
+		   assume application is using setproctitle(3). */
+		if (res > 0 && buffer[res - 1] != '\0') {
+			len = strnlen(buffer, res);
+			if (len < res) {
+				res = len;
+			} else
+			if (mm->env_start < mm->env_end && res <= PAGE_SIZE) {
 				len = mm->env_end - mm->env_start;
 				if (len > PAGE_SIZE - res)
 					len = PAGE_SIZE - res;
 				res += access_process_vm(task, mm->env_start, buffer+res, len, 0);
-				res = strnlen( buffer, res );
-			}
+				res = strnlen(buffer, res);
+			} else
+				res = 0;
 		}
-		mmput(mm);
 	}
+	if (mm)
+		mmput(mm);
 	return res;
 }
 
diff -urN linux-2.4.28-bk7/fs/proc/proc_tty.c linux-2.4.29/fs/proc/proc_tty.c
--- linux-2.4.28-bk7/fs/proc/proc_tty.c	2005-01-19 07:07:42.592318412 -0800
+++ linux-2.4.29/fs/proc/proc_tty.c	2005-01-19 07:08:14.155685444 -0800
@@ -15,8 +15,6 @@
 #include <asm/bitops.h>
 
 extern struct tty_driver *tty_drivers;	/* linked list of tty drivers */
-extern struct tty_ldisc ldiscs[];
-
 
 static int tty_drivers_read_proc(char *page, char **start, off_t off,
 				 int count, int *eof, void *data);
@@ -106,12 +104,15 @@
 	int	i;
 	int	len = 0;
 	off_t	begin = 0;
-
+	struct tty_ldisc *ld;
+	
 	for (i=0; i < NR_LDISCS; i++) {
-		if (!(ldiscs[i].flags & LDISC_FLAG_DEFINED))
+		ld = tty_ldisc_get(i);
+		if (ld == NULL)
 			continue;
 		len += sprintf(page+len, "%-10s %2d\n",
-			       ldiscs[i].name ? ldiscs[i].name : "???", i);
+			       ld->name ? ld->name : "???", i);
+		tty_ldisc_put(i);
 		if (len+begin > off+count)
 			break;
 		if (len+begin < off) {
diff -urN linux-2.4.28-bk7/fs/xfs/Makefile linux-2.4.29/fs/xfs/Makefile
--- linux-2.4.28-bk7/fs/xfs/Makefile	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29/fs/xfs/Makefile	2005-01-19 07:08:14.156685488 -0800
@@ -57,8 +57,6 @@
 
 obj-$(CONFIG_XFS_RT)		+= xfs_rtalloc.o
 obj-$(CONFIG_XFS_POSIX_ACL)	+= xfs_acl.o
-obj-$(CONFIG_XFS_POSIX_CAP)	+= xfs_cap.o
-obj-$(CONFIG_XFS_POSIX_MAC)	+= xfs_mac.o
 
 obj-$(CONFIG_XFS_TRACE)		+= xfs_dir2_trace.o
 
diff -urN linux-2.4.28-bk7/fs/xfs/linux-2.4/xfs_aops.c linux-2.4.29/fs/xfs/linux-2.4/xfs_aops.c
--- linux-2.4.28-bk7/fs/xfs/linux-2.4/xfs_aops.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/fs/xfs/linux-2.4/xfs_aops.c	2005-01-19 07:08:14.157685531 -0800
@@ -516,13 +516,13 @@
 xfs_submit_page(
 	struct page		*page,
 	struct buffer_head	*bh_arr[],
-	int			cnt)
+	int			bh_count)
 {
 	struct buffer_head	*bh;
 	int			i;
 
-	if (cnt) {
-		for (i = 0; i < cnt; i++) {
+	if (bh_count) {
+		for (i = 0; i < bh_count; i++) {
 			bh = bh_arr[i];
 			set_buffer_async_io(bh);
 			if (buffer_unwritten(bh))
@@ -531,12 +531,13 @@
 			clear_buffer_dirty(bh);
 		}
 
-		for (i = 0; i < cnt; i++) {
+		for (i = 0; i < bh_count; i++) {
 			refile_buffer(bh_arr[i]);
 			submit_bh(WRITE, bh_arr[i]);
 		}
-	} else
+	} else {
 		unlock_page(page);
+	}
 }
 
 /*
@@ -570,11 +571,13 @@
 	bh = head = page_buffers(page);
 	do {
 		offset = i << bbits;
+		if (offset >= end)
+			break;
 		if (!(PageUptodate(page) || buffer_uptodate(bh)))
 			continue;
 		if (buffer_mapped(bh) && all_bh &&
 		    !buffer_unwritten(bh) && !buffer_delay(bh)) {
-			if (startio && (offset < end)) {
+			if (startio) {
 				lock_buffer(bh);
 				bh_arr[index++] = bh;
 			}
@@ -602,7 +605,7 @@
 				ASSERT(private);
 			}
 		}
-		if (startio && (offset < end)) {
+		if (startio) {
 			bh_arr[index++] = bh;
 		} else {
 			unlock_buffer(bh);
diff -urN linux-2.4.28-bk7/fs/xfs/linux-2.4/xfs_buf.c linux-2.4.29/fs/xfs/linux-2.4/xfs_buf.c
--- linux-2.4.28-bk7/fs/xfs/linux-2.4/xfs_buf.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/fs/xfs/linux-2.4/xfs_buf.c	2005-01-19 07:08:14.159685618 -0800
@@ -626,7 +626,7 @@
  *	which may imply that this call will block until those buffers
  *	are unlocked.  No I/O is implied by this call.
  */
-STATIC xfs_buf_t *
+xfs_buf_t *
 _pagebuf_find(				/* find buffer for block	*/
 	xfs_buftarg_t		*target,/* target for block		*/
 	loff_t			ioff,	/* starting offset of range	*/
@@ -719,39 +719,14 @@
 	return (pb);
 }
 
-
-/*
- *	pagebuf_find
- *
- *	pagebuf_find returns a buffer matching the specified range of
- *	data for the specified target, if any of the relevant blocks
- *	are in memory.  The buffer may have unallocated holes, if
- *	some, but not all, of the blocks are in memory.  Even where
- *	pages are present in the buffer, not all of every page may be
- *	valid.
- */
-xfs_buf_t *
-pagebuf_find(				/* find buffer for block	*/
-					/* if the block is in memory	*/
-	xfs_buftarg_t		*target,/* target for block		*/
-	loff_t			ioff,	/* starting offset of range	*/
-	size_t			isize,	/* length of range		*/
-	page_buf_flags_t	flags)	/* PBF_TRYLOCK			*/
-{
-	return _pagebuf_find(target, ioff, isize, flags, NULL);
-}
-
 /*
- *	pagebuf_get
+ *	xfs_buf_get_flags assembles a buffer covering the specified range.
  *
- *	pagebuf_get assembles a buffer covering the specified range.
- *	Some or all of the blocks in the range may be valid.  Storage
- *	in memory for all portions of the buffer will be allocated,
- *	although backing storage may not be.  If PBF_READ is set in
- *	flags, pagebuf_iostart is called also.
+ *	Storage in memory for all portions of the buffer will be allocated,
+ *	although backing storage may not be.
  */
 xfs_buf_t *
-pagebuf_get(				/* allocate a buffer		*/
+xfs_buf_get_flags(			/* allocate a buffer		*/
 	xfs_buftarg_t		*target,/* target for buffer		*/
 	loff_t			ioff,	/* starting offset of range	*/
 	size_t			isize,	/* length of range		*/
@@ -781,8 +756,8 @@
 	if (!(pb->pb_flags & PBF_MAPPED)) {
 		error = _pagebuf_map_pages(pb, flags);
 		if (unlikely(error)) {
-			printk(KERN_WARNING
-			       "pagebuf_get: failed to map pages\n");
+			printk(KERN_WARNING "%s: failed to map pages\n",
+					__FUNCTION__);
 			goto no_buffer;
 		}
 	}
@@ -796,30 +771,50 @@
 	pb->pb_bn = ioff;
 	pb->pb_count_desired = pb->pb_buffer_length;
 
-	if (flags & PBF_READ) {
+	PB_TRACE(pb, "get", (unsigned long)flags);
+	return pb;
+
+ no_buffer:
+	if (flags & (PBF_LOCK | PBF_TRYLOCK))
+		pagebuf_unlock(pb);
+	pagebuf_rele(pb);
+	return NULL;
+}
+
+xfs_buf_t *
+xfs_buf_read_flags(
+	xfs_buftarg_t		*target,
+	loff_t			ioff,
+	size_t			isize,
+	page_buf_flags_t	flags)
+{
+	xfs_buf_t		*pb;
+
+	flags |= PBF_READ;
+
+	pb = xfs_buf_get_flags(target, ioff, isize, flags);
+	if (pb) {
 		if (PBF_NOT_DONE(pb)) {
-			PB_TRACE(pb, "get_read", (unsigned long)flags);
+			PB_TRACE(pb, "read", (unsigned long)flags);
 			XFS_STATS_INC(pb_get_read);
 			pagebuf_iostart(pb, flags);
 		} else if (flags & PBF_ASYNC) {
-			PB_TRACE(pb, "get_read_async", (unsigned long)flags);
+			PB_TRACE(pb, "read_async", (unsigned long)flags);
 			/*
 			 * Read ahead call which is already satisfied,
 			 * drop the buffer
 			 */
 			goto no_buffer;
 		} else {
-			PB_TRACE(pb, "get_read_done", (unsigned long)flags);
+			PB_TRACE(pb, "read_done", (unsigned long)flags);
 			/* We do not want read in the flags */
 			pb->pb_flags &= ~PBF_READ;
 		}
-	} else {
-		PB_TRACE(pb, "get_write", (unsigned long)flags);
 	}
 
 	return pb;
 
-no_buffer:
+ no_buffer:
 	if (flags & (PBF_LOCK | PBF_TRYLOCK))
 		pagebuf_unlock(pb);
 	pagebuf_rele(pb);
@@ -857,8 +852,8 @@
 	size_t			isize,
 	page_buf_flags_t	flags)
 {
-	flags |= (PBF_TRYLOCK|PBF_READ|PBF_ASYNC|PBF_READ_AHEAD);
-	pagebuf_get(target, ioff, isize, flags);
+	flags |= (PBF_TRYLOCK|PBF_ASYNC|PBF_READ_AHEAD);
+	xfs_buf_read_flags(target, ioff, isize, flags);
 }
 
 xfs_buf_t *
@@ -1078,6 +1073,7 @@
 	return(locked ? 0 : -EBUSY);
 }
 
+#ifdef DEBUG
 /*
  *	pagebuf_lock_value
  *
@@ -1089,6 +1085,7 @@
 {
 	return(atomic_read(&pb->pb_sema.count));
 }
+#endif
 
 /*
  *	pagebuf_lock
@@ -1434,6 +1431,34 @@
  *	Handling of buftargs.
  */
 
+/*
+ * Wait for any bufs with callbacks that have been submitted but
+ * have not yet returned... walk the hash list for the target.
+ */
+void
+xfs_wait_buftarg(
+	xfs_buftarg_t *target)
+{
+	xfs_buf_t	*pb, *n;
+	pb_hash_t	*h;
+	int		i;
+
+	for (i = 0; i < NHASH; i++) {
+		h = &pbhash[i];
+again:
+		spin_lock(&h->pb_hash_lock);
+		list_for_each_entry_safe(pb, n, &h->pb_hash, pb_hash_list) {
+			if (pb->pb_target == target &&
+					!(pb->pb_flags & PBF_FS_MANAGED)) {
+				spin_unlock(&h->pb_hash_lock);
+				delay(100);
+				goto again;
+			}
+		}
+		spin_unlock(&h->pb_hash_lock);
+	}
+}
+
 void
 xfs_free_buftarg(
 	xfs_buftarg_t		*btp,
@@ -1524,6 +1549,7 @@
 	case EVMS_MAJOR:
 		btp->pbr_flags = PBR_ALIGNED_ONLY;
 		break;
+	case LOOP_MAJOR:
 	case LVM_BLK_MAJOR:
 		btp->pbr_flags = PBR_SECTOR_ONLY;
 		break;
diff -urN linux-2.4.28-bk7/fs/xfs/linux-2.4/xfs_buf.h linux-2.4.29/fs/xfs/linux-2.4/xfs_buf.h
--- linux-2.4.28-bk7/fs/xfs/linux-2.4/xfs_buf.h	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/fs/xfs/linux-2.4/xfs_buf.h	2005-01-19 07:08:14.160685661 -0800
@@ -183,20 +183,36 @@
 
 /* Finding and Reading Buffers */
 
-extern xfs_buf_t *pagebuf_find(	/* find buffer for block if	*/
+extern xfs_buf_t *_pagebuf_find(	/* find buffer for block if	*/
 					/* the block is in memory	*/
 		xfs_buftarg_t *,	/* inode for block		*/
 		loff_t,			/* starting offset of range	*/
 		size_t,			/* length of range		*/
-		page_buf_flags_t);	/* PBF_LOCK			*/
+		page_buf_flags_t,	/* PBF_LOCK			*/
+	        xfs_buf_t *);		/* newly allocated buffer	*/
 
-extern xfs_buf_t *pagebuf_get(		/* allocate a buffer		*/
+#define xfs_incore(buftarg,blkno,len,lockit) \
+	_pagebuf_find(buftarg, blkno ,len, lockit, NULL)
+
+extern xfs_buf_t *xfs_buf_get_flags(	/* allocate a buffer		*/
 		xfs_buftarg_t *,	/* inode for buffer		*/
 		loff_t,			/* starting offset of range     */
 		size_t,			/* length of range              */
 		page_buf_flags_t);	/* PBF_LOCK, PBF_READ,		*/
 					/* PBF_ASYNC			*/
 
+#define xfs_buf_get(target, blkno, len, flags) \
+	xfs_buf_get_flags((target), (blkno), (len), PBF_LOCK | PBF_MAPPED)
+
+extern xfs_buf_t *xfs_buf_read_flags(	/* allocate and read a buffer	*/
+		xfs_buftarg_t *,	/* inode for buffer		*/
+		loff_t,			/* starting offset of range	*/
+		size_t,			/* length of range		*/
+		page_buf_flags_t);	/* PBF_LOCK, PBF_ASYNC		*/
+
+#define xfs_buf_read(target, blkno, len, flags) \
+	xfs_buf_read_flags((target), (blkno), (len), PBF_LOCK | PBF_MAPPED)
+
 extern xfs_buf_t *pagebuf_lookup(
 		xfs_buftarg_t *,
 		loff_t,			/* starting offset of range	*/
@@ -524,18 +540,6 @@
 #define XFS_BUF_SET_VTYPE(bp, type)
 #define XFS_BUF_SET_REF(bp, ref)
 
-#define xfs_buf_read(target, blkno, len, flags) \
-		pagebuf_get((target), (blkno), (len), \
-			PBF_LOCK | PBF_READ | PBF_MAPPED)
-#define xfs_buf_get(target, blkno, len, flags) \
-		pagebuf_get((target), (blkno), (len), \
-			PBF_LOCK | PBF_MAPPED)
-
-#define xfs_buf_read_flags(target, blkno, len, flags) \
-		pagebuf_get((target), (blkno), (len), PBF_READ | (flags))
-#define xfs_buf_get_flags(target, blkno, len, flags) \
-		pagebuf_get((target), (blkno), (len), (flags))
-
 static inline int	xfs_bawrite(void *mp, xfs_buf_t *bp)
 {
 	bp->pb_fspriv3 = mp;
@@ -560,10 +564,6 @@
 #define xfs_biodone(pb)		    \
 	    pagebuf_iodone(pb, (pb->pb_flags & PBF_FS_DATAIOD), 0)
 
-#define xfs_incore(buftarg,blkno,len,lockit) \
-	    pagebuf_find(buftarg, blkno ,len, lockit)
-
-
 #define xfs_biomove(pb, off, len, data, rw) \
 	    pagebuf_iomove((pb), (off), (len), (data), \
 		((rw) == XFS_B_WRITE) ? PBRW_WRITE : PBRW_READ)
@@ -617,6 +617,7 @@
  
 extern xfs_buftarg_t *xfs_alloc_buftarg(struct block_device *);
 extern void xfs_free_buftarg(xfs_buftarg_t *, int);
+extern void xfs_wait_buftarg(xfs_buftarg_t *);
 extern int xfs_setsize_buftarg(xfs_buftarg_t *, unsigned int, unsigned int);
 extern void xfs_incore_relse(xfs_buftarg_t *, int, int);
 extern int xfs_flush_buftarg(xfs_buftarg_t *, int);
diff -urN linux-2.4.28-bk7/fs/xfs/linux-2.4/xfs_file.c linux-2.4.29/fs/xfs/linux-2.4/xfs_file.c
--- linux-2.4.28-bk7/fs/xfs/linux-2.4/xfs_file.c	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29/fs/xfs/linux-2.4/xfs_file.c	2005-01-19 07:08:14.160685661 -0800
@@ -322,7 +322,7 @@
 	vattr_t		va = { .va_mask = XFS_AT_UPDATIME };
 	int		error;
 
-	if ((vp->v_type == VREG) && (vp->v_vfsp->vfs_flag & VFS_DMI)) {
+	if (vp->v_vfsp->vfs_flag & VFS_DMI) {
 		xfs_mount_t	*mp = XFS_VFSTOM(vp->v_vfsp);
 
 		error = -XFS_SEND_MMAP(mp, vma, 0);
@@ -333,6 +333,8 @@
 	vma->vm_ops = &linvfs_file_vm_ops;
 
 	VOP_SETATTR(vp, &va, XFS_AT_UPDATIME, NULL, error);
+	if (!error)
+		vn_revalidate(vp);	/* update Linux inode flags */
 	return 0;
 }
 
@@ -394,7 +396,7 @@
 	vnode_t		*vp = LINVFS_GET_VP(vma->vm_file->f_dentry->d_inode);
 	int		error = 0;
 
-	if ((vp->v_type == VREG) && (vp->v_vfsp->vfs_flag & VFS_DMI)) {
+	if (vp->v_vfsp->vfs_flag & VFS_DMI) {
 		if ((vma->vm_flags & VM_MAYSHARE) &&
 		    (newflags & PROT_WRITE) && !(vma->vm_flags & PROT_WRITE)) {
 			xfs_mount_t	*mp = XFS_VFSTOM(vp->v_vfsp);
diff -urN linux-2.4.28-bk7/fs/xfs/linux-2.4/xfs_fs_subr.h linux-2.4.29/fs/xfs/linux-2.4/xfs_fs_subr.h
--- linux-2.4.28-bk7/fs/xfs/linux-2.4/xfs_fs_subr.h	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29/fs/xfs/linux-2.4/xfs_fs_subr.h	2005-01-19 07:08:14.161685704 -0800
@@ -40,7 +40,6 @@
 
 extern int	fs_noerr(void);
 extern int	fs_nosys(void);
-extern int	fs_nodev(void);
 extern void	fs_noval(void);
 extern void	fs_tosspages(bhv_desc_t *, xfs_off_t, xfs_off_t, int);
 extern void	fs_flushinval_pages(bhv_desc_t *, xfs_off_t, xfs_off_t, int);
diff -urN linux-2.4.28-bk7/fs/xfs/linux-2.4/xfs_globals.c linux-2.4.29/fs/xfs/linux-2.4/xfs_globals.c
--- linux-2.4.28-bk7/fs/xfs/linux-2.4/xfs_globals.c	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29/fs/xfs/linux-2.4/xfs_globals.c	2005-01-19 07:08:14.161685704 -0800
@@ -66,6 +66,8 @@
 	.inherit_noatim = {	0,	1,	1	},
 	.xfs_buf_timer	= {	100/2,	100,	30*100	},
 	.xfs_buf_age	= {	1*100,	15*100,	300*100	},
+	.inherit_nosym	= {	0,	0,	1	},
+	.rotorstep	= {	1,	1,	255	},
 };
 
 /*
diff -urN linux-2.4.28-bk7/fs/xfs/linux-2.4/xfs_ioctl.c linux-2.4.29/fs/xfs/linux-2.4/xfs_ioctl.c
--- linux-2.4.28-bk7/fs/xfs/linux-2.4/xfs_ioctl.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/fs/xfs/linux-2.4/xfs_ioctl.c	2005-01-19 07:08:14.162685748 -0800
@@ -268,7 +268,7 @@
 	/*
 	 * Get the XFS inode, building a vnode to go with it.
 	 */
-	error = xfs_iget(mp, NULL, ino, XFS_ILOCK_SHARED, &ip, 0);
+	error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_SHARED, &ip, 0);
 	if (error)
 		return error;
 	if (ip == NULL)
@@ -497,7 +497,7 @@
 	xfs_fsop_attrmulti_handlereq_t am_hreq;
 	struct inode		*inode;
 	vnode_t			*vp;
-	int			i, size;
+	unsigned int		i, size;
 
 	error = xfs_vget_fsop_handlereq(mp, parinode, CAP_SYS_ADMIN, arg,
 					sizeof(xfs_fsop_attrmulti_handlereq_t),
@@ -507,6 +507,11 @@
 		return -error;
 
 	size = am_hreq.opcount * sizeof(attr_multiop_t);
+	if (!size || size > 16 * PAGE_SIZE) {
+		VN_RELE(vp);
+		return -XFS_ERROR(E2BIG);
+	}
+
 	ops = (xfs_attr_multiop_t *)kmalloc(size, GFP_KERNEL);
 	if (!ops) {
 		VN_RELE(vp);
diff -urN linux-2.4.28-bk7/fs/xfs/linux-2.4/xfs_iops.c linux-2.4.29/fs/xfs/linux-2.4/xfs_iops.c
--- linux-2.4.28-bk7/fs/xfs/linux-2.4/xfs_iops.c	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29/fs/xfs/linux-2.4/xfs_iops.c	2005-01-19 07:08:14.163685791 -0800
@@ -173,8 +173,9 @@
 				 */
 				teardown.d_inode = ip = LINVFS_GET_IP(vp);
 				teardown.d_name = dentry->d_name;
-				remove_inode_hash(ip);
-				make_bad_inode(ip);
+
+				vn_mark_bad(vp);
+
 				if (S_ISDIR(mode))
 					VOP_RMDIR(dvp, &teardown, NULL, err2);
 				else
@@ -302,7 +303,7 @@
 {
 	struct inode	*ip;
 	vattr_t		va;
-	vnode_t		*dvp;	/* directory containing name to remove */
+	vnode_t		*dvp;	/* directory containing name of symlink */
 	vnode_t		*cvp;	/* used to lookup symlink to put in dentry */
 	int		error;
 
diff -urN linux-2.4.28-bk7/fs/xfs/linux-2.4/xfs_linux.h linux-2.4.29/fs/xfs/linux-2.4/xfs_linux.h
--- linux-2.4.28-bk7/fs/xfs/linux-2.4/xfs_linux.h	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/fs/xfs/linux-2.4/xfs_linux.h	2005-01-19 07:08:14.163685791 -0800
@@ -79,6 +79,7 @@
 #include <linux/pagemap.h>
 #include <linux/seq_file.h>
 #include <linux/init.h>
+#include <linux/list.h>
 #include <linux/proc_fs.h>
 
 #include <asm/page.h>
@@ -141,6 +142,8 @@
 #define xfs_inherit_noatime	xfs_params.inherit_noatim.val
 #define xfs_buf_timer_centisecs	xfs_params.xfs_buf_timer.val
 #define xfs_buf_age_centisecs	xfs_params.xfs_buf_age.val
+#define xfs_inherit_nosymlinks	xfs_params.inherit_nosym.val
+#define xfs_rotorstep		xfs_params.rotorstep.val
 
 #define current_cpu()		smp_processor_id()
 #define current_pid()		(current->pid)
diff -urN linux-2.4.28-bk7/fs/xfs/linux-2.4/xfs_lrw.c linux-2.4.29/fs/xfs/linux-2.4/xfs_lrw.c
--- linux-2.4.28-bk7/fs/xfs/linux-2.4/xfs_lrw.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/fs/xfs/linux-2.4/xfs_lrw.c	2005-01-19 07:08:14.164685834 -0800
@@ -336,11 +336,12 @@
 		ret = generic_file_read(file, buf, size, offset);
 	}
 
+	if (ret > 0)
+		XFS_STATS_ADD(xs_read_bytes, ret);
+
 	if (!(ioflags & IO_ISLOCKED))
 		xfs_iunlock(ip, XFS_IOLOCK_SHARED);
 
-	XFS_STATS_ADD(xs_read_bytes, ret);
-
 	if (unlikely(ioflags & IO_INVIS)) {
 		/* generic_file_read updates the atime but we need to
 		 * undo that because this I/O was supposed to be invisible.
diff -urN linux-2.4.28-bk7/fs/xfs/linux-2.4/xfs_super.c linux-2.4.29/fs/xfs/linux-2.4/xfs_super.c
--- linux-2.4.28-bk7/fs/xfs/linux-2.4/xfs_super.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/fs/xfs/linux-2.4/xfs_super.c	2005-01-19 07:08:14.165685878 -0800
@@ -129,8 +129,7 @@
 	vnode_t			*vp = LINVFS_GET_VP(inode);
 
 	if (vp->v_type == VNON) {
-		remove_inode_hash(inode);
-		make_bad_inode(inode);
+		vn_mark_bad(vp);
 	} else if (S_ISREG(inode->i_mode)) {
 		inode->i_op = &linvfs_file_inode_operations;
 		inode->i_fop = &linvfs_file_operations;
@@ -211,21 +210,21 @@
 		bhv_insert(VN_BHV_HEAD(vp), inode_bhv);
 	}
 
-	vp->v_type = IFTOVT(ip->i_d.di_mode);
-
-	/* Have we been called during the new inode create process,
-	 * in which case we are too early to fill in the Linux inode.
+	/*
+	 * We need to set the ops vectors, and unlock the inode, but if
+	 * we have been called during the new inode create process, it is
+	 * too early to fill in the Linux inode.  We will get called a
+	 * second time once the inode is properly set up, and then we can
+	 * finish our work.
 	 */
-	if (vp->v_type == VNON)
-		return;
+	if (ip->i_d.di_mode != 0 && unlock && (inode->i_state & I_NEW)) {
+		vp->v_type = IFTOVT(ip->i_d.di_mode);
+		xfs_revalidate_inode(XFS_BHVTOM(bdp), vp, ip);
+		xfs_set_inodeops(inode);
 
-	xfs_revalidate_inode(XFS_BHVTOM(bdp), vp, ip);
+		ip->i_flags &= ~XFS_INEW;
+		barrier();
 
-	/* For new inodes we need to set the ops vectors,
-	 * and unlock the inode.
-	 */
-	if (unlock && (inode->i_state & I_NEW)) {
-		xfs_set_inodeops(inode);
 		unlock_new_inode(inode);
 	}
 }
@@ -253,25 +252,6 @@
 	return iget_locked(vfsp->vfs_super, ino);
 }
 
-void
-xfs_flush_inode(
-	xfs_inode_t	*ip)
-{
-	struct inode	*inode = LINVFS_GET_IP(XFS_ITOV(ip));
-
-	filemap_fdatawrite(inode->i_mapping);
-}
-
-void
-xfs_flush_device(
-	xfs_inode_t	*ip)
-{
-	struct inode	*inode = LINVFS_GET_IP(XFS_ITOV(ip));
-
-	fsync_no_super(inode->i_dev);
-	xfs_log_force(ip->i_mount, (xfs_lsn_t)0, XFS_LOG_FORCE|XFS_LOG_SYNC);
-}
-
 struct dentry *
 d_alloc_anon(struct inode *inode)
 {
@@ -427,14 +407,105 @@
 }
 
 
+/*
+ * Enqueue a work item to be picked up by the vfs xfssyncd thread.
+ * Doing this has two advantages:
+ * - It saves on stack space, which is tight in certain situations
+ * - It can be used (with care) as a mechanism to avoid deadlocks.
+ * Flushing while allocating in a full filesystem requires both.
+ */
+STATIC void
+xfs_syncd_queue_work(
+	struct vfs	*vfs,
+	void		*data,
+	void		(*syncer)(vfs_t *, void *))
+{
+	vfs_sync_work_t	*work;
+
+	work = kmem_alloc(sizeof(struct vfs_sync_work), KM_SLEEP);
+	INIT_LIST_HEAD(&work->w_list);
+	work->w_syncer = syncer;
+	work->w_data = data;
+	work->w_vfs = vfs;
+	spin_lock(&vfs->vfs_sync_lock);
+	list_add_tail(&work->w_list, &vfs->vfs_sync_list);
+	spin_unlock(&vfs->vfs_sync_lock);
+	wake_up_process(vfs->vfs_sync_task);
+}
+
+/*
+ * Flush delayed allocate data, attempting to free up reserved space
+ * from existing allocations.  At this point a new allocation attempt
+ * has failed with ENOSPC and we are in the process of scratching our
+ * heads, looking about for more room...
+ */
+STATIC void
+xfs_flush_inode_work(
+	vfs_t		*vfs,
+	void		*inode)
+{
+	filemap_fdatawrite(((struct inode *)inode)->i_mapping);
+	iput((struct inode *)inode);
+}
+
+void
+xfs_flush_inode(
+	xfs_inode_t	*ip)
+{
+	struct inode	*inode = LINVFS_GET_IP(XFS_ITOV(ip));
+	struct vfs	*vfs = XFS_MTOVFS(ip->i_mount);
+
+	igrab(inode);
+	xfs_syncd_queue_work(vfs, inode, xfs_flush_inode_work);
+	delay(HZ/2);
+}
+
+/*
+ * This is the "bigger hammer" version of xfs_flush_inode_work...
+ * (IOW, "If at first you don't succeed, use a Bigger Hammer").
+ */
+STATIC void
+xfs_flush_device_work(
+	vfs_t		*vfs,
+	void		*inode)
+{
+	fsync_no_super(((struct inode *)inode)->i_dev);
+	iput((struct inode *)inode);
+}
+
+void
+xfs_flush_device(
+	xfs_inode_t	*ip)
+{
+	struct inode	*inode = LINVFS_GET_IP(XFS_ITOV(ip));
+	struct vfs	*vfs = XFS_MTOVFS(ip->i_mount);
+
+	igrab(inode);
+	xfs_syncd_queue_work(vfs, inode, xfs_flush_device_work);
+	delay(HZ/2);
+	xfs_log_force(ip->i_mount, (xfs_lsn_t)0, XFS_LOG_FORCE|XFS_LOG_SYNC);
+}
+
 #define SYNCD_FLAGS	(SYNC_FSDATA|SYNC_BDFLUSH|SYNC_ATTR|SYNC_REFCACHE)
+STATIC void
+vfs_sync_worker(
+	vfs_t		*vfsp,
+	void		*unused)
+{
+	int		error;
+
+	if (!(vfsp->vfs_flag & VFS_RDONLY))
+		VFS_SYNC(vfsp, SYNCD_FLAGS, NULL, error);
+}
 
 STATIC int
 xfssyncd(
 	void			*arg)
 {
+	long			timeleft;
 	vfs_t			*vfsp = (vfs_t *) arg;
-	int			error;
+	struct list_head	tmp;
+	struct vfs_sync_work	*work, *n;
 
 	daemonize();
 	reparent_to_init();
@@ -445,18 +516,38 @@
 
 	sprintf(current->comm, "xfssyncd");
 
+	vfsp->vfs_sync_work.w_vfs = vfsp;
+	vfsp->vfs_sync_work.w_syncer = vfs_sync_worker;
 	vfsp->vfs_sync_task = current;
 	wmb();
 	wake_up(&vfsp->vfs_wait_sync_task);
 
+	INIT_LIST_HEAD(&tmp);
+	timeleft = (xfs_syncd_centisecs * HZ) / 100;
 	for (;;) {
 		set_current_state(TASK_INTERRUPTIBLE);
-		schedule_timeout((xfs_syncd_centisecs * HZ) / 100);
+		timeleft = schedule_timeout(timeleft);
 		if (vfsp->vfs_flag & VFS_UMOUNT)
 			break;
-		if (vfsp->vfs_flag & VFS_RDONLY)
-			continue;
-		VFS_SYNC(vfsp, SYNCD_FLAGS, NULL, error);
+
+		spin_lock(&vfsp->vfs_sync_lock);
+		if (!timeleft) {
+			timeleft = (xfs_syncd_centisecs * HZ) / 100;
+			INIT_LIST_HEAD(&vfsp->vfs_sync_work.w_list);
+			list_add_tail(&vfsp->vfs_sync_work.w_list,
+					&vfsp->vfs_sync_list);
+		}
+		list_for_each_entry_safe(work, n, &vfsp->vfs_sync_list, w_list)
+			list_move(&work->w_list, &tmp);
+		spin_unlock(&vfsp->vfs_sync_lock);
+
+		list_for_each_entry_safe(work, n, &tmp, w_list) {
+			(*work->w_syncer)(vfsp, work->w_data);
+			list_del(&work->w_list);
+			if (work == &vfsp->vfs_sync_work)
+				continue;
+			kmem_free(work, sizeof(struct vfs_sync_work));
+		}
 	}
 
 	vfsp->vfs_sync_task = NULL;
@@ -696,10 +787,14 @@
 		xfid.fid_gen = data[1];
 		xfid.fid_ino = (__u64)data[0];
 	} else {
-		if (fhtype == 4)
-			xfid.fid_gen = data[3];
-		else
-			xfid.fid_gen = 0;
+		if (fhtype != 4) {
+			printk(KERN_WARNING
+			       "XFS: detected filehandle without "
+			       "parent inode generation information.");
+			return ERR_PTR(-ESTALE);
+		}
+
+		xfid.fid_gen = data[3];
 		xfid.fid_ino = (__u64)data[2];
 	}
 
diff -urN linux-2.4.28-bk7/fs/xfs/linux-2.4/xfs_sysctl.c linux-2.4.29/fs/xfs/linux-2.4/xfs_sysctl.c
--- linux-2.4.28-bk7/fs/xfs/linux-2.4/xfs_sysctl.c	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29/fs/xfs/linux-2.4/xfs_sysctl.c	2005-01-19 07:08:14.166685921 -0800
@@ -160,6 +160,16 @@
 	&sysctl_intvec, NULL,
 	&xfs_params.xfs_buf_age.min, &xfs_params.xfs_buf_age.max},
 
+	{XFS_INHERIT_NOSYM, "inherit_nosymlinks", &xfs_params.inherit_nosym.val,
+	sizeof(int), 0644, NULL, &proc_dointvec_minmax,
+	&sysctl_intvec, NULL,
+	&xfs_params.inherit_nosym.min, &xfs_params.inherit_nosym.max},
+
+	{XFS_ROTORSTEP, "rotorstep", &xfs_params.rotorstep.val,
+	sizeof(int), 0644, NULL, &proc_dointvec_minmax,
+	&sysctl_intvec, NULL, 
+	&xfs_params.rotorstep.min, &xfs_params.rotorstep.max},
+
 	/* please keep this the last entry */
 #ifdef CONFIG_PROC_FS
 	{XFS_STATS_CLEAR, "stats_clear", &xfs_params.stats_clear.val,
diff -urN linux-2.4.28-bk7/fs/xfs/linux-2.4/xfs_sysctl.h linux-2.4.29/fs/xfs/linux-2.4/xfs_sysctl.h
--- linux-2.4.28-bk7/fs/xfs/linux-2.4/xfs_sysctl.h	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29/fs/xfs/linux-2.4/xfs_sysctl.h	2005-01-19 07:08:14.166685921 -0800
@@ -61,6 +61,8 @@
 	xfs_sysctl_val_t inherit_noatim;/* Inherit the "noatime" inode flag. */
 	xfs_sysctl_val_t xfs_buf_timer;	/* Interval between xfsbufd wakeups. */
 	xfs_sysctl_val_t xfs_buf_age;	/* Metadata buffer age before flush. */
+	xfs_sysctl_val_t inherit_nosym;	/* Inherit the "nosymlinks" flag. */
+	xfs_sysctl_val_t rotorstep;	/* inode32 AG rotoring control knob */
 } xfs_param_t;
 
 /*
@@ -97,6 +99,8 @@
 	XFS_BUF_TIMER = 16,
 	XFS_BUF_AGE = 17,
 	/* XFS_IO_BYPASS = 18, */
+	XFS_INHERIT_NOSYM = 19,
+	XFS_ROTORSTEP = 20,
 };
 
 extern xfs_param_t	xfs_params;
diff -urN linux-2.4.28-bk7/fs/xfs/linux-2.4/xfs_vfs.c linux-2.4.29/fs/xfs/linux-2.4/xfs_vfs.c
--- linux-2.4.28-bk7/fs/xfs/linux-2.4/xfs_vfs.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/fs/xfs/linux-2.4/xfs_vfs.c	2005-01-19 07:08:14.167685964 -0800
@@ -262,6 +262,8 @@
 
 	vfsp = kmem_zalloc(sizeof(vfs_t), KM_SLEEP);
 	bhv_head_init(VFS_BHVHEAD(vfsp), "vfs");
+	INIT_LIST_HEAD(&vfsp->vfs_sync_list);
+	vfsp->vfs_sync_lock = SPIN_LOCK_UNLOCKED;
 	init_waitqueue_head(&vfsp->vfs_wait_sync_task);
 	init_waitqueue_head(&vfsp->vfs_wait_unfrozen);
 	return vfsp;
diff -urN linux-2.4.28-bk7/fs/xfs/linux-2.4/xfs_vfs.h linux-2.4.29/fs/xfs/linux-2.4/xfs_vfs.h
--- linux-2.4.28-bk7/fs/xfs/linux-2.4/xfs_vfs.h	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/fs/xfs/linux-2.4/xfs_vfs.h	2005-01-19 07:08:14.167685964 -0800
@@ -36,6 +36,7 @@
 #include "xfs_fs.h"
 
 struct fid;
+struct vfs;
 struct cred;
 struct vnode;
 struct statfs;
@@ -45,13 +46,23 @@
 
 typedef struct statfs xfs_statfs_t;
 
+typedef struct vfs_sync_work {
+	struct list_head	w_list;
+	struct vfs		*w_vfs;
+	void			*w_data;	/* syncer routine argument */
+	void			(*w_syncer)(struct vfs *, void *);
+} vfs_sync_work_t;
+
 typedef struct vfs {
 	u_int			vfs_flag;	/* flags */
 	xfs_fsid_t		vfs_fsid;	/* file system ID */
 	xfs_fsid_t		*vfs_altfsid;	/* An ID fixed for life of FS */
 	bhv_head_t		vfs_bh;		/* head of vfs behavior chain */
-	struct super_block	*vfs_super;	/* Linux superblock structure */
-	struct task_struct	*vfs_sync_task;
+	struct super_block	*vfs_super;	/* generic superblock pointer */
+	struct task_struct	*vfs_sync_task;	/* generalised sync thread */
+	vfs_sync_work_t		vfs_sync_work;	/* work item for VFS_SYNC */
+	struct list_head	vfs_sync_list;	/* sync thread work item list */
+	spinlock_t		vfs_sync_lock;	/* work item list lock */
 	wait_queue_head_t	vfs_wait_sync_task;
 	int			vfs_frozen;
 	wait_queue_head_t	vfs_wait_unfrozen;
diff -urN linux-2.4.28-bk7/fs/xfs/linux-2.4/xfs_vnode.c linux-2.4.29/fs/xfs/linux-2.4/xfs_vnode.c
--- linux-2.4.28-bk7/fs/xfs/linux-2.4/xfs_vnode.c	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29/fs/xfs/linux-2.4/xfs_vnode.c	2005-01-19 07:08:14.168686008 -0800
@@ -186,8 +186,7 @@
 	 * returning NULL here is OK.
 	 */
 	if (inode->i_state & I_NEW) {
-		remove_inode_hash(inode);
-		make_bad_inode(inode);
+		vn_mark_bad(vp);
 		unlock_new_inode(inode);
 		iput(inode);
 		return NULL;
diff -urN linux-2.4.28-bk7/fs/xfs/linux-2.4/xfs_vnode.h linux-2.4.29/fs/xfs/linux-2.4/xfs_vnode.h
--- linux-2.4.28-bk7/fs/xfs/linux-2.4/xfs_vnode.h	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29/fs/xfs/linux-2.4/xfs_vnode.h	2005-01-19 07:08:14.169686051 -0800
@@ -594,6 +594,23 @@
 		(LINVFS_GET_IP(vp)->i_ctime = (__int32_t)(tvp)->tv_sec)
 
 /*
+ * Dealing with bad inodes
+ */
+static inline void vn_mark_bad(struct vnode *vp)
+{
+	struct inode *inode = LINVFS_GET_IP(vp);
+
+	remove_inode_hash(inode);
+	make_bad_inode(inode);
+}
+
+static inline int VN_BAD(struct vnode *vp)
+{
+	return is_bad_inode(LINVFS_GET_IP(vp));
+}
+
+
+/*
  * Some useful predicates.
  */
 #define	VN_MAPPED(vp)	((LINVFS_GET_IP(vp)->i_mapping->i_mmap != NULL) || \
diff -urN linux-2.4.28-bk7/fs/xfs/quota/xfs_qm.c linux-2.4.29/fs/xfs/quota/xfs_qm.c
--- linux-2.4.28-bk7/fs/xfs/quota/xfs_qm.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/fs/xfs/quota/xfs_qm.c	2005-01-19 07:08:14.171686137 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -85,7 +85,6 @@
 
 STATIC void	xfs_qm_list_init(xfs_dqlist_t *, char *, int);
 STATIC void	xfs_qm_list_destroy(xfs_dqlist_t *);
-STATIC int	xfs_qm_quotacheck(xfs_mount_t *);
 
 STATIC int	xfs_qm_init_quotainos(xfs_mount_t *);
 STATIC int	xfs_qm_shake(int, unsigned int);
@@ -349,7 +348,8 @@
  */
 int
 xfs_qm_mount_quotas(
-	xfs_mount_t	*mp)
+	xfs_mount_t	*mp,
+	int		mfsi_flags)
 {
 	unsigned long	s;
 	int		error = 0;
@@ -398,22 +398,16 @@
 	/*
 	 * If any of the quotas are not consistent, do a quotacheck.
 	 */
-	if (XFS_QM_NEED_QUOTACHECK(mp)) {
+	if (XFS_QM_NEED_QUOTACHECK(mp) &&
+		!(mfsi_flags & XFS_MFSI_NO_QUOTACHECK)) {
 #ifdef DEBUG
 		cmn_err(CE_NOTE, "Doing a quotacheck. Please wait.");
 #endif
 		if ((error = xfs_qm_quotacheck(mp))) {
-			cmn_err(CE_WARN, "Quotacheck unsuccessful (Error %d): "
-				"Disabling quotas.",
-				error);
-			/*
-			 * We must turn off quotas.
+			/* Quotacheck has failed and quotas have
+			 * been disabled.
 			 */
-			ASSERT(mp->m_quotainfo != NULL);
-			ASSERT(xfs_Gqm != NULL);
-			xfs_qm_destroy_quotainfo(mp);
-			mp->m_qflags = 0;
-			goto write_changes;
+			return XFS_ERROR(error);
 		}
 #ifdef DEBUG
 		cmn_err(CE_NOTE, "Done quotacheck.");
@@ -1788,7 +1782,7 @@
 	 * the case in all other instances. It's OK that we do this because
 	 * quotacheck is done only at mount time.
 	 */
-	if ((error = xfs_iget(mp, NULL, ino, XFS_ILOCK_EXCL, &ip, bno))) {
+	if ((error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_EXCL, &ip, bno))) {
 		*res = BULKSTAT_RV_NOTHING;
 		return (error);
 	}
@@ -1875,9 +1869,9 @@
 
 /*
  * Walk thru all the filesystem inodes and construct a consistent view
- * of the disk quota world.
+ * of the disk quota world. If the quotacheck fails, disable quotas.
  */
-STATIC int
+int
 xfs_qm_quotacheck(
 	xfs_mount_t	*mp)
 {
@@ -1973,7 +1967,20 @@
 	XQM_LIST_PRINT(&(XFS_QI_MPL_LIST(mp)), MPL_NEXT, "++++ Mp list +++");
 
  error_return:
-	cmn_err(CE_NOTE, "XFS quotacheck %s: Done.", mp->m_fsname);
+	if (error) {
+		cmn_err(CE_WARN, "XFS quotacheck %s: Unsuccessful (Error %d): "
+			"Disabling quotas.",
+			mp->m_fsname, error);
+		/*
+		 * We must turn off quotas.
+		 */
+		ASSERT(mp->m_quotainfo != NULL);
+		ASSERT(xfs_Gqm != NULL);
+		xfs_qm_destroy_quotainfo(mp);
+		xfs_mount_reset_sbqflags(mp);
+	} else {
+		cmn_err(CE_NOTE, "XFS quotacheck %s: Done.", mp->m_fsname);
+	}
 	return (error);
 }
 
@@ -2003,14 +2010,14 @@
 		    mp->m_sb.sb_uquotino != NULLFSINO) {
 			ASSERT(mp->m_sb.sb_uquotino > 0);
 			if ((error = xfs_iget(mp, NULL, mp->m_sb.sb_uquotino,
-					     0, &uip, 0)))
+					     0, 0, &uip, 0)))
 				return XFS_ERROR(error);
 		}
 		if (XFS_IS_GQUOTA_ON(mp) &&
 		    mp->m_sb.sb_gquotino != NULLFSINO) {
 			ASSERT(mp->m_sb.sb_gquotino > 0);
 			if ((error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino,
-					     0, &gip, 0))) {
+					     0, 0, &gip, 0))) {
 				if (uip)
 					VN_RELE(XFS_ITOV(uip));
 				return XFS_ERROR(error);
diff -urN linux-2.4.28-bk7/fs/xfs/quota/xfs_qm.h linux-2.4.29/fs/xfs/quota/xfs_qm.h
--- linux-2.4.28-bk7/fs/xfs/quota/xfs_qm.h	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/fs/xfs/quota/xfs_qm.h	2005-01-19 07:08:14.171686137 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -182,17 +182,19 @@
 #define XFS_QM_HOLD(xqm)	((xqm)->qm_nrefs++)
 #define XFS_QM_RELE(xqm)	((xqm)->qm_nrefs--)
 
+extern void		xfs_mount_reset_sbqflags(xfs_mount_t *);
+
 extern int		xfs_qm_init_quotainfo(xfs_mount_t *);
 extern void		xfs_qm_destroy_quotainfo(xfs_mount_t *);
-extern int		xfs_qm_mount_quotas(xfs_mount_t *);
+extern int		xfs_qm_mount_quotas(xfs_mount_t *, int);
 extern void		xfs_qm_mount_quotainit(xfs_mount_t *, uint);
+extern int		xfs_qm_quotacheck(xfs_mount_t *);
 extern void		xfs_qm_unmount_quotadestroy(xfs_mount_t *);
 extern int		xfs_qm_unmount_quotas(xfs_mount_t *);
 extern int		xfs_qm_write_sb_changes(xfs_mount_t *, __int64_t);
 extern int		xfs_qm_sync(xfs_mount_t *, short);
 
 /* dquot stuff */
-extern void		xfs_qm_dqunlink(xfs_dquot_t *);
 extern boolean_t	xfs_qm_dqalloc_incore(xfs_dquot_t **);
 extern int		xfs_qm_dqattach(xfs_inode_t *, uint);
 extern void		xfs_qm_dqdetach(xfs_inode_t *);
diff -urN linux-2.4.28-bk7/fs/xfs/quota/xfs_qm_bhv.c linux-2.4.29/fs/xfs/quota/xfs_qm_bhv.c
--- linux-2.4.28-bk7/fs/xfs/quota/xfs_qm_bhv.c	2004-02-18 05:36:32.000000000 -0800
+++ linux-2.4.29/fs/xfs/quota/xfs_qm_bhv.c	2005-01-19 07:08:14.172686181 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -207,10 +207,9 @@
 }
 
 /*
- * When xfsquotas isn't installed and the superblock had quotas, we need to
- * clear the quotaflags from superblock.
+ * Clear the quotaflags in memory and in the superblock.
  */
-STATIC void
+void
 xfs_mount_reset_sbqflags(
 	xfs_mount_t		*mp)
 {
@@ -241,6 +240,8 @@
 	if (xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0,
 				      XFS_DEFAULT_LOG_COUNT)) {
 		xfs_trans_cancel(tp, 0);
+		xfs_fs_cmn_err(CE_ALERT, mp,
+			"xfs_mount_reset_sbqflags: Superblock update failed!");
 		return;
 	}
 	xfs_mod_sb(tp, XFS_SB_QFLAGS);
@@ -294,15 +295,12 @@
 		 */
 		if (quotaondisk && !XFS_QM_NEED_QUOTACHECK(mp)) {
 			/*
-			 * If the xfs quota code isn't installed,
-			 * we have to reset the quotachk'd bit.
 			 * If an error occured, qm_mount_quotas code
 			 * has already disabled quotas. So, just finish
 			 * mounting, and get on with the boring life
 			 * without disk quotas.
 			 */
-			if (xfs_qm_mount_quotas(mp))
-				xfs_mount_reset_sbqflags(mp);
+			xfs_qm_mount_quotas(mp, 0);
 		} else {
 			/*
 			 * Clear the quota flags, but remember them. This
@@ -324,13 +322,13 @@
 xfs_qm_endmount(
 	xfs_mount_t	*mp,
 	uint		needquotamount,
-	uint		quotaflags)
+	uint		quotaflags,
+	int		mfsi_flags)
 {
 	if (needquotamount) {
 		ASSERT(mp->m_qflags == 0);
 		mp->m_qflags = quotaflags;
-		if (xfs_qm_mount_quotas(mp))
-			xfs_mount_reset_sbqflags(mp);
+		xfs_qm_mount_quotas(mp, mfsi_flags);
 	}
 
 #if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
diff -urN linux-2.4.28-bk7/fs/xfs/quota/xfs_qm_syscalls.c linux-2.4.29/fs/xfs/quota/xfs_qm_syscalls.c
--- linux-2.4.28-bk7/fs/xfs/quota/xfs_qm_syscalls.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/fs/xfs/quota/xfs_qm_syscalls.c	2005-01-19 07:08:14.173686224 -0800
@@ -404,7 +404,7 @@
 	}
 
 	if ((flags & XFS_DQ_USER) && mp->m_sb.sb_uquotino != NULLFSINO) {
-		error = xfs_iget(mp, NULL, mp->m_sb.sb_uquotino, 0, &qip, 0);
+		error = xfs_iget(mp, NULL, mp->m_sb.sb_uquotino, 0, 0, &qip, 0);
 		if (! error) {
 			(void) xfs_truncate_file(mp, qip);
 			VN_RELE(XFS_ITOV(qip));
@@ -412,7 +412,7 @@
 	}
 
 	if ((flags & XFS_DQ_GROUP) && mp->m_sb.sb_gquotino != NULLFSINO) {
-		error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, 0, &qip, 0);
+		error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, 0, 0, &qip, 0);
 		if (! error) {
 			(void) xfs_truncate_file(mp, qip);
 			VN_RELE(XFS_ITOV(qip));
@@ -555,11 +555,13 @@
 		gip = mp->m_quotainfo->qi_gquotaip;
 	}
 	if (!uip && mp->m_sb.sb_uquotino != NULLFSINO) {
-		if (xfs_iget(mp, NULL, mp->m_sb.sb_uquotino, 0, &uip, 0) == 0)
+		if (xfs_iget(mp, NULL, mp->m_sb.sb_uquotino,
+					0, 0, &uip, 0) == 0)
 			tempuqip = B_TRUE;
 	}
 	if (!gip && mp->m_sb.sb_gquotino != NULLFSINO) {
-		if (xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, 0, &gip, 0) == 0)
+		if (xfs_iget(mp, NULL, mp->m_sb.sb_gquotino,
+					0, 0, &gip, 0) == 0)
 			tempgqip = B_TRUE;
 	}
 	if (uip) {
@@ -1338,7 +1340,7 @@
 	ipreleased = B_FALSE;
  again:
 	lock_flags = XFS_ILOCK_SHARED;
-	if ((error = xfs_iget(mp, NULL, ino, lock_flags, &ip, bno))) {
+	if ((error = xfs_iget(mp, NULL, ino, 0, lock_flags, &ip, bno))) {
 		*res = BULKSTAT_RV_NOTHING;
 		return (error);
 	}
diff -urN linux-2.4.28-bk7/fs/xfs/xfs_acl.h linux-2.4.29/fs/xfs/xfs_acl.h
--- linux-2.4.28-bk7/fs/xfs/xfs_acl.h	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/fs/xfs/xfs_acl.h	2005-01-19 07:08:14.174686267 -0800
@@ -74,8 +74,6 @@
 
 extern int xfs_acl_inherit(struct vnode *, struct vattr *, xfs_acl_t *);
 extern int xfs_acl_iaccess(struct xfs_inode *, mode_t, cred_t *);
-extern int xfs_acl_get(struct vnode *, xfs_acl_t *, xfs_acl_t *);
-extern int xfs_acl_set(struct vnode *, xfs_acl_t *, xfs_acl_t *);
 extern int xfs_acl_vtoacl(struct vnode *, xfs_acl_t *, xfs_acl_t *);
 extern int xfs_acl_vhasacl_access(struct vnode *);
 extern int xfs_acl_vhasacl_default(struct vnode *);
diff -urN linux-2.4.28-bk7/fs/xfs/xfs_alloc.c linux-2.4.29/fs/xfs/xfs_alloc.c
--- linux-2.4.28-bk7/fs/xfs/xfs_alloc.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/fs/xfs/xfs_alloc.c	2005-01-19 07:08:14.176686354 -0800
@@ -2247,6 +2247,7 @@
 	xfs_alloctype_t	type;	/* input allocation type */
 	int		bump_rotor = 0;
 	int		no_min = 0;
+	xfs_agnumber_t	rotorstep = xfs_rotorstep; /* inode32 agf stepper */
 
 	mp = args->mp;
 	type = args->otype = args->type;
@@ -2310,7 +2311,9 @@
 		 */
 		if ((args->userdata  == XFS_ALLOC_INITIAL_USER_DATA) &&
 		    (mp->m_flags & XFS_MOUNT_32BITINODES)) {
-			args->fsbno = XFS_AGB_TO_FSB(mp, mp->m_agfrotor, 0);
+			args->fsbno = XFS_AGB_TO_FSB(mp,
+					((mp->m_agfrotor / rotorstep) %
+					mp->m_sb.sb_agcount), 0);
 			bump_rotor = 1;
 		}
 		args->agbno = XFS_FSB_TO_AGBNO(mp, args->fsbno);
@@ -2326,7 +2329,8 @@
 			/*
 			 * Start with the last place we left off.
 			 */
-			args->agno = sagno = mp->m_agfrotor;
+			args->agno = sagno = (mp->m_agfrotor / rotorstep) %
+					mp->m_sb.sb_agcount;
 			args->type = XFS_ALLOCTYPE_THIS_AG;
 			flags = XFS_ALLOC_FLAG_TRYLOCK;
 		} else if (type == XFS_ALLOCTYPE_FIRST_AG) {
@@ -2400,8 +2404,14 @@
 			}
 		}
 		up_read(&mp->m_peraglock);
-		if (bump_rotor || (type == XFS_ALLOCTYPE_ANY_AG))
-			mp->m_agfrotor = (args->agno + 1) % mp->m_sb.sb_agcount;
+		if (bump_rotor || (type == XFS_ALLOCTYPE_ANY_AG)) {
+			if (args->agno == sagno)
+				mp->m_agfrotor = (mp->m_agfrotor + 1) %
+					(mp->m_sb.sb_agcount * rotorstep);
+			else
+				mp->m_agfrotor = (args->agno * rotorstep + 1) %
+					(mp->m_sb.sb_agcount * rotorstep);
+		}
 		break;
 	default:
 		ASSERT(0);
diff -urN linux-2.4.28-bk7/fs/xfs/xfs_attr.c linux-2.4.29/fs/xfs/xfs_attr.c
--- linux-2.4.28-bk7/fs/xfs/xfs_attr.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/fs/xfs/xfs_attr.c	2005-01-19 07:08:14.321692634 -0800
@@ -121,22 +121,14 @@
 	xfs_da_args_t   args;
 	int             error;
 
-	if (XFS_FORCED_SHUTDOWN(ip->i_mount))
-		return(EIO);
-
 	if ((XFS_IFORK_Q(ip) == 0) ||
 	    (ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
 	     ip->i_d.di_anextents == 0))
 		return(ENOATTR);
 
-	if (!(flags & ATTR_KERNACCESS)) {
-		xfs_ilock(ip, XFS_ILOCK_SHARED);
-
-		if (!(flags & ATTR_SECURE) &&
-		    ((error = xfs_iaccess(ip, S_IRUSR, cred)))) {
-			xfs_iunlock(ip, XFS_ILOCK_SHARED);
+	if (!(flags & (ATTR_KERNACCESS|ATTR_SECURE))) {
+		if ((error = xfs_iaccess(ip, S_IRUSR, cred)))
 			return(XFS_ERROR(error));
-		}
 	}
 
 	/*
@@ -167,9 +159,6 @@
 		error = xfs_attr_node_get(&args);
 	}
 
-	if (!(flags & ATTR_KERNACCESS))
-		xfs_iunlock(ip, XFS_ILOCK_SHARED);
-
 	/*
 	 * Return the number of bytes in the value to the caller.
 	 */
@@ -185,7 +174,7 @@
 	     int flags, struct cred *cred)
 {
 	xfs_inode_t	*ip = XFS_BHVTOI(bdp);
-	int		namelen;
+	int		error, namelen;
 
 	XFS_STATS_INC(xs_attr_get);
 
@@ -195,7 +184,13 @@
 	if (namelen >= MAXNAMELEN)
 		return(EFAULT);		/* match IRIX behaviour */
 
-	return xfs_attr_fetch(ip, name, namelen, value, valuelenp, flags, cred);
+	if (XFS_FORCED_SHUTDOWN(ip->i_mount))
+		return(EIO);
+
+	xfs_ilock(ip, XFS_ILOCK_SHARED);
+	error = xfs_attr_fetch(ip, name, namelen, value, valuelenp, flags, cred);
+	xfs_iunlock(ip, XFS_ILOCK_SHARED);
+	return(error);
 }
 
 /*ARGSUSED*/
@@ -718,16 +713,15 @@
 	mp = dp->i_mount;
 	ASSERT(! XFS_NOT_DQATTACHED(mp, dp));
 
-	/* XXXsup - why on earth are we taking ILOCK_EXCL here??? */
-	xfs_ilock(dp, XFS_ILOCK_EXCL);
+	xfs_ilock(dp, XFS_ILOCK_SHARED);
 	if ((XFS_IFORK_Q(dp) == 0) ||
 	    (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) ||
 	    (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
 	     dp->i_d.di_anextents == 0)) {
-		xfs_iunlock(dp, XFS_ILOCK_EXCL);
+		xfs_iunlock(dp, XFS_ILOCK_SHARED);
 		return(0);
 	}
-	xfs_iunlock(dp, XFS_ILOCK_EXCL);
+	xfs_iunlock(dp, XFS_ILOCK_SHARED);
 
 	/*
 	 * Start our first transaction of the day.
diff -urN linux-2.4.28-bk7/fs/xfs/xfs_attr_leaf.h linux-2.4.29/fs/xfs/xfs_attr_leaf.h
--- linux-2.4.28-bk7/fs/xfs/xfs_attr_leaf.h	2004-02-18 05:36:32.000000000 -0800
+++ linux-2.4.29/fs/xfs/xfs_attr_leaf.h	2005-01-19 07:08:14.322692677 -0800
@@ -246,7 +246,6 @@
 int	xfs_attr_shortform_to_leaf(struct xfs_da_args *args);
 int	xfs_attr_shortform_remove(struct xfs_da_args *remove);
 int	xfs_attr_shortform_list(struct xfs_attr_list_context *context);
-int	xfs_attr_shortform_replace(struct xfs_da_args *args);
 int	xfs_attr_shortform_allfit(struct xfs_dabuf *bp, struct xfs_inode *dp);
 
 /*
diff -urN linux-2.4.28-bk7/fs/xfs/xfs_bmap_btree.h linux-2.4.29/fs/xfs/xfs_bmap_btree.h
--- linux-2.4.28-bk7/fs/xfs/xfs_bmap_btree.h	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29/fs/xfs/xfs_bmap_btree.h	2005-01-19 07:08:14.532701773 -0800
@@ -551,13 +551,6 @@
 	struct xfs_btree_cur *,
 	int *);
 
-int
-xfs_bmbt_insert_many(
-	struct xfs_btree_cur *,
-	int,
-	xfs_bmbt_rec_t *,
-	int *);
-
 void
 xfs_bmbt_log_block(
 	struct xfs_btree_cur *,
diff -urN linux-2.4.28-bk7/fs/xfs/xfs_cap.c linux-2.4.29/fs/xfs/xfs_cap.c
--- linux-2.4.28-bk7/fs/xfs/xfs_cap.c	2004-02-18 05:36:32.000000000 -0800
+++ linux-2.4.29/fs/xfs/xfs_cap.c	1969-12-31 16:00:00.000000000 -0800
@@ -1,206 +0,0 @@
-/*
- * Copyright (c) 2002 Silicon Graphics, Inc.  All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like.  Any license provided herein, whether implied or
- * otherwise, applies only to this software file.  Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
- * Mountain View, CA  94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
- */
-
-#include "xfs.h"
-
-STATIC int xfs_cap_allow_set(vnode_t *);
-
-
-/*
- * Test for existence of capability attribute as efficiently as possible.
- */
-int
-xfs_cap_vhascap(
-	vnode_t		*vp)
-{
-	int		error;
-	int		len = sizeof(xfs_cap_set_t);
-	int		flags = ATTR_KERNOVAL|ATTR_ROOT;
-
-	VOP_ATTR_GET(vp, SGI_CAP_LINUX, NULL, &len, flags, sys_cred, error);
-	return (error == 0);
-}
-
-/*
- * Convert from extended attribute representation to in-memory for XFS.
- */
-STATIC int
-posix_cap_xattr_to_xfs(
-	posix_cap_xattr		*src,
-	size_t			size,
-	xfs_cap_set_t		*dest)
-{
-	if (!src || !dest)
-		return EINVAL;
-
-	if (src->c_version != cpu_to_le32(POSIX_CAP_XATTR_VERSION))
-		return EINVAL;
-	if (src->c_abiversion != cpu_to_le32(_LINUX_CAPABILITY_VERSION))
-		return EINVAL;
-
-	if (size < sizeof(posix_cap_xattr))
-		return EINVAL;
-
-	ASSERT(sizeof(dest->cap_effective) == sizeof(src->c_effective));
-
-	dest->cap_effective	= src->c_effective;
-	dest->cap_permitted	= src->c_permitted;
-	dest->cap_inheritable	= src->c_inheritable;
-
-	return 0;
-}
-
-/*
- * Convert from in-memory XFS to extended attribute representation.
- */
-STATIC int
-posix_cap_xfs_to_xattr(
-	xfs_cap_set_t		*src,
-	posix_cap_xattr		*xattr_cap,
-	size_t			size)
-{
-	size_t			new_size = posix_cap_xattr_size();
-
-	if (size < new_size)
-		return -ERANGE;
-
-	ASSERT(sizeof(xattr_cap->c_effective) == sizeof(src->cap_effective));
-
-	xattr_cap->c_version	= cpu_to_le32(POSIX_CAP_XATTR_VERSION);
-	xattr_cap->c_abiversion	= cpu_to_le32(_LINUX_CAPABILITY_VERSION);
-	xattr_cap->c_effective	= src->cap_effective;
-	xattr_cap->c_permitted	= src->cap_permitted;
-	xattr_cap->c_inheritable= src->cap_inheritable;
-
-	return new_size;
-}
-
-int
-xfs_cap_vget(
-	vnode_t		*vp,
-	void		*cap,
-	size_t		size)
-{
-	int		error;
-	int		len = sizeof(xfs_cap_set_t);
-	int		flags = ATTR_ROOT;
-	xfs_cap_set_t	xfs_cap = { 0 };
-	posix_cap_xattr	*xattr_cap = cap;
-	char		*data = (char *)&xfs_cap;
-
-	VN_HOLD(vp);
-	if ((error = _MAC_VACCESS(vp, NULL, VREAD)))
-		goto out;
-
-	if (!size) {
-		flags |= ATTR_KERNOVAL;
-		data = NULL;
-	}
-	VOP_ATTR_GET(vp, SGI_CAP_LINUX, data, &len, flags, sys_cred, error);
-	if (error)
-		goto out;
-	ASSERT(len == sizeof(xfs_cap_set_t));
-
-	error = (size)? -posix_cap_xattr_size() :
-			-posix_cap_xfs_to_xattr(&xfs_cap, xattr_cap, size);
-out:
-	VN_RELE(vp);
-	return -error;
-}
-
-int
-xfs_cap_vremove(
-	vnode_t		*vp)
-{
-	int		error;
-
-	VN_HOLD(vp);
-	error = xfs_cap_allow_set(vp);
-	if (!error) {
-		VOP_ATTR_REMOVE(vp, SGI_CAP_LINUX, ATTR_ROOT, sys_cred, error);
-		if (error == ENOATTR)
-			error = 0;	/* 'scool */
-	}
-	VN_RELE(vp);
-	return -error;
-}
-
-int
-xfs_cap_vset(
-	vnode_t			*vp,
-	void			*cap,
-	size_t			size)
-{
-	posix_cap_xattr		*xattr_cap = cap;
-	xfs_cap_set_t		xfs_cap;
-	int			error;
-
-	if (!cap)
-		return -EINVAL;
-
-	error = posix_cap_xattr_to_xfs(xattr_cap, size, &xfs_cap);
-	if (error)
-		return -error;
-
-	VN_HOLD(vp);
-	error = xfs_cap_allow_set(vp);
-	if (error)
-		goto out;
-
-	VOP_ATTR_SET(vp, SGI_CAP_LINUX, (char *)&xfs_cap,
-			sizeof(xfs_cap_set_t), ATTR_ROOT, sys_cred, error);
-out:
-	VN_RELE(vp);
-	return -error;
-}
-
-STATIC int
-xfs_cap_allow_set(
-	vnode_t		*vp)
-{
-	vattr_t		va;
-	int		error;
-
-	if (vp->v_vfsp->vfs_flag & VFS_RDONLY)
-		return EROFS;
-	if (vp->v_inode.i_flags & (S_IMMUTABLE|S_APPEND))
-		return EPERM;
-	if ((error = _MAC_VACCESS(vp, NULL, VWRITE)))
-		return error;
-	va.va_mask = XFS_AT_UID;
-	VOP_GETATTR(vp, &va, 0, NULL, error);
-	if (error)
-		return error;
-	if (va.va_uid != current->fsuid && !capable(CAP_FOWNER))
-		return EPERM;
-	return error;
-}
diff -urN linux-2.4.28-bk7/fs/xfs/xfs_dinode.h linux-2.4.29/fs/xfs/xfs_dinode.h
--- linux-2.4.28-bk7/fs/xfs/xfs_dinode.h	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/fs/xfs/xfs_dinode.h	2005-01-19 07:08:14.533701816 -0800
@@ -457,6 +457,8 @@
 #define XFS_DIFLAG_NOATIME_BIT   6	/* do not update atime */
 #define XFS_DIFLAG_NODUMP_BIT    7	/* do not dump */
 #define XFS_DIFLAG_RTINHERIT_BIT 8	/* create with realtime bit set */
+#define XFS_DIFLAG_PROJINHERIT_BIT  9	/* create with parents projid */
+#define XFS_DIFLAG_NOSYMLINKS_BIT  10	/* disallow symlink creation */
 #define XFS_DIFLAG_REALTIME      (1 << XFS_DIFLAG_REALTIME_BIT)
 #define XFS_DIFLAG_PREALLOC      (1 << XFS_DIFLAG_PREALLOC_BIT)
 #define XFS_DIFLAG_NEWRTBM       (1 << XFS_DIFLAG_NEWRTBM_BIT)
@@ -466,10 +468,13 @@
 #define XFS_DIFLAG_NOATIME       (1 << XFS_DIFLAG_NOATIME_BIT)
 #define XFS_DIFLAG_NODUMP        (1 << XFS_DIFLAG_NODUMP_BIT)
 #define XFS_DIFLAG_RTINHERIT     (1 << XFS_DIFLAG_RTINHERIT_BIT)
+#define XFS_DIFLAG_PROJINHERIT   (1 << XFS_DIFLAG_PROJINHERIT_BIT)
+#define XFS_DIFLAG_NOSYMLINKS    (1 << XFS_DIFLAG_NOSYMLINKS_BIT)
 
 #define XFS_DIFLAG_ANY \
 	(XFS_DIFLAG_REALTIME | XFS_DIFLAG_PREALLOC | XFS_DIFLAG_NEWRTBM | \
 	 XFS_DIFLAG_IMMUTABLE | XFS_DIFLAG_APPEND | XFS_DIFLAG_SYNC | \
-	 XFS_DIFLAG_NOATIME | XFS_DIFLAG_NODUMP | XFS_DIFLAG_RTINHERIT)
+	 XFS_DIFLAG_NOATIME | XFS_DIFLAG_NODUMP | XFS_DIFLAG_RTINHERIT | \
+	 XFS_DIFLAG_PROJINHERIT | XFS_DIFLAG_NOSYMLINKS)
 
 #endif	/* __XFS_DINODE_H__ */
diff -urN linux-2.4.28-bk7/fs/xfs/xfs_fs.h linux-2.4.29/fs/xfs/xfs_fs.h
--- linux-2.4.28-bk7/fs/xfs/xfs_fs.h	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/fs/xfs/xfs_fs.h	2005-01-19 07:08:14.534701859 -0800
@@ -77,6 +77,8 @@
 #define XFS_XFLAG_NOATIME	0x00000040	/* do not update access time */
 #define XFS_XFLAG_NODUMP	0x00000080	/* do not include in backups */
 #define XFS_XFLAG_RTINHERIT	0x00000100	/* create with rt bit set */
+#define XFS_XFLAG_PROJINHERIT	0x00000200	/* create with parents projid */
+#define XFS_XFLAG_NOSYMLINKS	0x00000400	/* disallow symlink creation */
 #define XFS_XFLAG_HASATTR	0x80000000	/* no DIFLAG for this	*/
 
 /*
diff -urN linux-2.4.28-bk7/fs/xfs/xfs_iget.c linux-2.4.29/fs/xfs/xfs_iget.c
--- linux-2.4.28-bk7/fs/xfs/xfs_iget.c	2004-02-18 05:36:32.000000000 -0800
+++ linux-2.4.29/fs/xfs/xfs_iget.c	2005-01-19 07:08:14.535701903 -0800
@@ -169,6 +169,7 @@
 	xfs_mount_t	*mp,
 	xfs_trans_t	*tp,
 	xfs_ino_t	ino,
+	uint		flags,
 	uint		lock_flags,
 	xfs_inode_t	**ipp,
 	xfs_daddr_t	bno)
@@ -180,7 +181,6 @@
 	ulong		version;
 	int		error;
 	/* REFERENCED */
-	int		newnode;
 	xfs_chash_t	*ch;
 	xfs_chashlist_t	*chl, *chlnew;
 	SPLDECL(s);
@@ -193,11 +193,22 @@
 
 	for (ip = ih->ih_next; ip != NULL; ip = ip->i_next) {
 		if (ip->i_ino == ino) {
+			/*
+			 * If INEW is set this inode is being set up
+			 * we need to pause and try again.
+			 */
+			if (ip->i_flags & XFS_INEW) {
+				read_unlock(&ih->ih_lock);
+				delay(1);
+				XFS_STATS_INC(xs_ig_frecycle);
 
-			inode_vp = XFS_ITOV_NULL(ip);
+				goto again;
+			}
 
+			inode_vp = XFS_ITOV_NULL(ip);
 			if (inode_vp == NULL) {
-				/* If IRECLAIM is set this inode is
+				/*
+				 * If IRECLAIM is set this inode is
 				 * on its way out of the system,
 				 * we need to pause and try again.
 				 */
@@ -250,14 +261,15 @@
 			XFS_STATS_INC(xs_ig_found);
 
 finish_inode:
-			if (lock_flags != 0) {
-				xfs_ilock(ip, lock_flags);
-			}
-
-			newnode = (ip->i_d.di_mode == 0);
-			if (newnode) {
+			if (ip->i_d.di_mode == 0) {
+				if (!(flags & IGET_CREATE))
+					return ENOENT;
 				xfs_iocore_inode_reinit(ip);
 			}
+	
+			if (lock_flags != 0)
+				xfs_ilock(ip, lock_flags);
+
 			ip->i_flags &= ~XFS_ISTALE;
 
 			vn_trace_exit(vp, "xfs_iget.found",
@@ -293,6 +305,11 @@
 	if (lock_flags != 0) {
 		xfs_ilock(ip, lock_flags);
 	}
+		
+	if ((ip->i_d.di_mode == 0) && !(flags & IGET_CREATE)) {
+		xfs_idestroy(ip);
+		return ENOENT;
+	}
 
 	/*
 	 * Put ip on its hash chain, unless someone else hashed a duplicate
@@ -324,6 +341,7 @@
 	ih->ih_next = ip;
 	ip->i_udquot = ip->i_gdquot = NULL;
 	ih->ih_version++;
+	ip->i_flags |= XFS_INEW;
 
 	write_unlock(&ih->ih_lock);
 
@@ -404,8 +422,6 @@
 
 	XFS_MOUNT_IUNLOCK(mp);
 
-	newnode = 1;
-
  return_ip:
 	ASSERT(ip->i_df.if_ext_max ==
 	       XFS_IFORK_DSIZE(ip) / sizeof(xfs_bmbt_rec_t));
@@ -434,6 +450,7 @@
 	xfs_mount_t	*mp,
 	xfs_trans_t	*tp,
 	xfs_ino_t	ino,
+	uint		flags,
 	uint		lock_flags,
 	xfs_inode_t	**ipp,
 	xfs_daddr_t	bno)
@@ -454,11 +471,10 @@
 		if (inode->i_state & I_NEW) {
 inode_allocate:
 			vn_initialize(inode);
-			error = xfs_iget_core(vp, mp, tp, ino,
-						lock_flags, ipp, bno);
+			error = xfs_iget_core(vp, mp, tp, ino, flags,
+					lock_flags, ipp, bno);
 			if (error) {
-				remove_inode_hash(inode);
-				make_bad_inode(inode);
+				vn_mark_bad(vp);
 				if (inode->i_state & I_NEW)
 					unlock_new_inode(inode);
 				iput(inode);
@@ -582,12 +598,12 @@
 
 	vn_trace_entry(vp, "xfs_iput_new", (inst_t *)__return_address);
 
-	/* We shouldn't get here without this being true, but just in case */
-	if (inode->i_state & I_NEW) {
-		remove_inode_hash(inode);
-		make_bad_inode(inode);
-		unlock_new_inode(inode);
+	if ((ip->i_d.di_mode == 0)) {
+		ASSERT(!(ip->i_flags & XFS_IRECLAIMABLE));
+		vn_mark_bad(vp);
 	}
+	if (inode->i_state & I_NEW)
+		unlock_new_inode(inode);
 	if (lock_flags)
 		xfs_iunlock(ip, lock_flags);
 	VN_RELE(vp);
diff -urN linux-2.4.28-bk7/fs/xfs/xfs_inode.c linux-2.4.29/fs/xfs/xfs_inode.c
--- linux-2.4.28-bk7/fs/xfs/xfs_inode.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/fs/xfs/xfs_inode.c	2005-01-19 07:08:14.538702033 -0800
@@ -881,6 +881,10 @@
 			flags |= XFS_XFLAG_NODUMP;
 		if (di_flags & XFS_DIFLAG_RTINHERIT)
 			flags |= XFS_XFLAG_RTINHERIT;
+		if (di_flags & XFS_DIFLAG_PROJINHERIT)
+			flags |= XFS_XFLAG_PROJINHERIT;
+		if (di_flags & XFS_DIFLAG_NOSYMLINKS)
+			flags |= XFS_XFLAG_NOSYMLINKS;
 	}
 	return flags;
 }
@@ -1159,7 +1163,8 @@
 	 * This is because we're setting fields here we need
 	 * to prevent others from looking at until we're done.
 	 */
-	error = xfs_trans_iget(tp->t_mountp, tp, ino, XFS_ILOCK_EXCL, &ip);
+	error = xfs_trans_iget(tp->t_mountp, tp, ino,
+			IGET_CREATE, XFS_ILOCK_EXCL, &ip);
 	if (error != 0) {
 		return error;
 	}
@@ -1257,6 +1262,9 @@
 			if ((pip->i_d.di_flags & XFS_DIFLAG_SYNC) &&
 			    xfs_inherit_sync)
 				ip->i_d.di_flags |= XFS_DIFLAG_SYNC;
+			if ((pip->i_d.di_flags & XFS_DIFLAG_NOSYMLINKS) &&
+			    xfs_inherit_nosymlinks)
+				ip->i_d.di_flags |= XFS_DIFLAG_NOSYMLINKS;
 		}
 		/* FALLTHROUGH */
 	case S_IFLNK:
diff -urN linux-2.4.28-bk7/fs/xfs/xfs_inode.h linux-2.4.29/fs/xfs/xfs_inode.h
--- linux-2.4.28-bk7/fs/xfs/xfs_inode.h	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29/fs/xfs/xfs_inode.h	2005-01-19 07:08:14.539702076 -0800
@@ -381,6 +381,7 @@
 #define XFS_IRECLAIM    0x0008  /* we have started reclaiming this inode    */
 #define XFS_ISTALE	0x0010	/* inode has been staled */
 #define XFS_IRECLAIMABLE 0x0020 /* inode can be reclaimed */
+#define XFS_INEW	0x0040
 
 /*
  * Flags for inode locking.
@@ -465,6 +466,9 @@
 /*
  * xfs_iget.c prototypes.
  */
+
+#define IGET_CREATE	1
+
 void		xfs_ihash_init(struct xfs_mount *);
 void		xfs_ihash_free(struct xfs_mount *);
 void		xfs_chash_init(struct xfs_mount *);
@@ -473,7 +477,7 @@
 				  struct xfs_trans *);
 void            xfs_inode_lock_init(xfs_inode_t *, struct vnode *);
 int		xfs_iget(struct xfs_mount *, struct xfs_trans *, xfs_ino_t,
-			 uint, xfs_inode_t **, xfs_daddr_t);
+			 uint, uint, xfs_inode_t **, xfs_daddr_t);
 void		xfs_iput(xfs_inode_t *, uint);
 void		xfs_iput_new(xfs_inode_t *, uint);
 void		xfs_ilock(xfs_inode_t *, uint);
@@ -508,7 +512,6 @@
 uint		xfs_dic2xflags(struct xfs_dinode_core *, xfs_arch_t);
 int		xfs_ifree(struct xfs_trans *, xfs_inode_t *,
 			   struct xfs_bmap_free *);
-int		xfs_atruncate_start(xfs_inode_t *);
 void		xfs_itruncate_start(xfs_inode_t *, uint, xfs_fsize_t);
 int		xfs_itruncate_finish(struct xfs_trans **, xfs_inode_t *,
 				     xfs_fsize_t, int, int);
diff -urN linux-2.4.28-bk7/fs/xfs/xfs_itable.c linux-2.4.29/fs/xfs/xfs_itable.c
--- linux-2.4.28-bk7/fs/xfs/xfs_itable.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/fs/xfs/xfs_itable.c	2005-01-19 07:08:14.540702119 -0800
@@ -102,7 +102,7 @@
 		/* We're not being passed a pointer to a dinode.  This happens
 		 * if BULKSTAT_FG_IGET is selected.  Do the iget.
 		 */
-		error = xfs_iget(mp, NULL, ino, XFS_ILOCK_SHARED, &ip, bno);
+		error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_SHARED, &ip, bno);
 		if (error) {
 			*stat = BULKSTAT_RV_NOTHING;
 			return error;
diff -urN linux-2.4.28-bk7/fs/xfs/xfs_log.c linux-2.4.29/fs/xfs/xfs_log.c
--- linux-2.4.28-bk7/fs/xfs/xfs_log.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/fs/xfs/xfs_log.c	2005-01-19 07:08:14.542702206 -0800
@@ -902,20 +902,15 @@
 	} else {
 		/*
 		 * The reservation head is behind the tail.
-		 * This can only happen when the AIL is empty so the tail
-		 * is equal to the head and the l_roundoff value in the
-		 * log structure is taking up the difference between the
-		 * reservation head and the tail.  The bytes accounted for
-		 * by the l_roundoff field are temporarily 'lost' to the
-		 * reservation mechanism, but they are cleaned up when the
-		 * log buffers that created them are reused.  These lost
-		 * bytes are what allow the reservation head to fall behind
-		 * the tail in the case that the log is 'empty'.
 		 * In this case we just want to return the size of the
 		 * log as the amount of space left.
 		 */
-		ASSERT((tail_cycle == (cycle + 1)) ||
-		       ((bytes + log->l_roundoff) >= tail_bytes));
+		xfs_fs_cmn_err(CE_ALERT, log->l_mp,
+			"xlog_space_left: head behind tail\n"
+			"  tail_cycle = %d, tail_bytes = %d\n"
+			"  GH   cycle = %d, GH   bytes = %d",
+			tail_cycle, tail_bytes, cycle, bytes);
+		ASSERT(0);
 		free_bytes = log->l_logsize;
 	}
 	return free_bytes;
@@ -1355,8 +1350,8 @@
 
 
 /*
- * Flush out the in-core log (iclog) to the on-disk log in a synchronous or
- * asynchronous fashion.  Previously, we should have moved the current iclog
+ * Flush out the in-core log (iclog) to the on-disk log in an asynchronous 
+ * fashion.  Previously, we should have moved the current iclog
  * ptr in the log to point to the next available iclog.  This allows further
  * write to continue while this code syncs out an iclog ready to go.
  * Before an in-core log can be written out, the data section must be scanned
@@ -1388,8 +1383,11 @@
 	int		i, ops;
 	uint		count;		/* byte count of bwrite */
 	uint		count_init;	/* initial count before roundup */
+	int		roundoff;       /* roundoff to BB or stripe */
 	int		split = 0;	/* split write into two regions */
 	int		error;
+	SPLDECL(s);
+	int		v2 = XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb);
 
 	XFS_STATS_INC(xs_log_writes);
 	ASSERT(iclog->ic_refcnt == 0);
@@ -1398,23 +1396,34 @@
 	count_init = log->l_iclog_hsize + iclog->ic_offset;
 
 	/* Round out the log write size */
-	if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb) &&
-	    log->l_mp->m_sb.sb_logsunit > 1) {
+	if (v2 && log->l_mp->m_sb.sb_logsunit > 1) {
 		/* we have a v2 stripe unit to use */
 		count = XLOG_LSUNITTOB(log, XLOG_BTOLSUNIT(log, count_init));
 	} else {
 		count = BBTOB(BTOBB(count_init));
 	}
-	iclog->ic_roundoff = count - count_init;
-	log->l_roundoff += iclog->ic_roundoff;
+	roundoff = count - count_init;
+	ASSERT(roundoff >= 0);
+	ASSERT((v2 && log->l_mp->m_sb.sb_logsunit > 1 && 
+                roundoff < log->l_mp->m_sb.sb_logsunit)
+		|| 
+		(log->l_mp->m_sb.sb_logsunit <= 1 && 
+		 roundoff < BBTOB(1)));
 
-	xlog_pack_data(log, iclog);       /* put cycle number in every block */
+	/* move grant heads by roundoff in sync */
+	s = GRANT_LOCK(log);
+	XLOG_GRANT_ADD_SPACE(log, roundoff, 'w');
+	XLOG_GRANT_ADD_SPACE(log, roundoff, 'r');
+	GRANT_UNLOCK(log, s);
+
+	/* put cycle number in every block */
+	xlog_pack_data(log, iclog, roundoff); 
 
 	/* real byte length */
-	if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb)) {
+	if (v2) {
 		INT_SET(iclog->ic_header.h_len, 
 			ARCH_CONVERT,
-			iclog->ic_offset + iclog->ic_roundoff);
+			iclog->ic_offset + roundoff);
 	} else {
 		INT_SET(iclog->ic_header.h_len, ARCH_CONVERT, iclog->ic_offset);
 	}
@@ -2278,11 +2287,6 @@
 		INT_SET(head->h_cycle, ARCH_CONVERT, log->l_curr_cycle);
 		ASSIGN_LSN(head->h_lsn, log, ARCH_CONVERT);
 		ASSERT(log->l_curr_block >= 0);
-
-		/* round off error from last write with this iclog */
-		ticket->t_curr_res -= iclog->ic_roundoff;
-		log->l_roundoff -= iclog->ic_roundoff;
-		iclog->ic_roundoff = 0;
 	}
 
 	/* If there is enough room to write everything, then do it.  Otherwise,
@@ -2853,7 +2857,6 @@
 				 * has already taken care of the roundoff from
 				 * the previous sync.
 				 */
-				ASSERT(iclog->ic_roundoff == 0);
 				iclog->ic_refcnt++;
 				lsn = INT_GET(iclog->ic_header.h_lsn, ARCH_CONVERT);
 				xlog_state_switch_iclogs(log, iclog, 0);
diff -urN linux-2.4.28-bk7/fs/xfs/xfs_log_priv.h linux-2.4.29/fs/xfs/xfs_log_priv.h
--- linux-2.4.28-bk7/fs/xfs/xfs_log_priv.h	2004-04-14 06:05:40.000000000 -0700
+++ linux-2.4.29/fs/xfs/xfs_log_priv.h	2005-01-19 07:08:14.543702249 -0800
@@ -430,7 +430,6 @@
 	int			ic_size;
 	int			ic_offset;
 	int			ic_refcnt;
-	int			ic_roundoff;
 	int			ic_bwritecnt;
 	ushort_t		ic_state;
 	char			*ic_datap;	/* pointer to iclog data */
@@ -462,7 +461,6 @@
 #define	ic_size		hic_fields.ic_size
 #define	ic_offset	hic_fields.ic_offset
 #define	ic_refcnt	hic_fields.ic_refcnt
-#define	ic_roundoff	hic_fields.ic_roundoff
 #define	ic_bwritecnt	hic_fields.ic_bwritecnt
 #define	ic_state	hic_fields.ic_state
 #define ic_datap	hic_fields.ic_datap
@@ -498,7 +496,6 @@
 	xfs_daddr_t		l_logBBstart;   /* start block of log */
 	int			l_logsize;      /* size of log in bytes */
 	int			l_logBBsize;    /* size of log in BB chunks */
-	int			l_roundoff;	/* round off error of iclogs */
 	int			l_curr_cycle;   /* Cycle number of log writes */
 	int			l_prev_cycle;   /* Cycle number before last
 						 * block increment */
@@ -543,10 +540,9 @@
 				xfs_daddr_t *head_blk,
 				xfs_daddr_t *tail_blk,
 				int readonly);
-extern int	 xlog_print_find_oldest(xlog_t *log, xfs_daddr_t *last_blk);
 extern int	 xlog_recover(xlog_t *log, int readonly);
 extern int	 xlog_recover_finish(xlog_t *log, int mfsi_flags);
-extern void	 xlog_pack_data(xlog_t *log, xlog_in_core_t *iclog);
+extern void	 xlog_pack_data(xlog_t *log, xlog_in_core_t *iclog, int);
 extern void	 xlog_recover_process_iunlinks(xlog_t *log);
 
 extern struct xfs_buf *xlog_get_bp(xlog_t *, int);
diff -urN linux-2.4.28-bk7/fs/xfs/xfs_log_recover.c linux-2.4.29/fs/xfs/xfs_log_recover.c
--- linux-2.4.28-bk7/fs/xfs/xfs_log_recover.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/fs/xfs/xfs_log_recover.c	2005-01-19 07:08:14.546702379 -0800
@@ -3262,7 +3262,7 @@
 				xfs_buf_relse(agibp);
 
 				ino = XFS_AGINO_TO_INO(mp, agno, agino);
-				error = xfs_iget(mp, NULL, ino, 0, &ip, 0);
+				error = xfs_iget(mp, NULL, ino, 0, 0, &ip, 0);
 				ASSERT(error || (ip != NULL));
 
 				if (!error) {
@@ -3384,10 +3384,11 @@
 void
 xlog_pack_data(
 	xlog_t			*log,
-	xlog_in_core_t		*iclog)
+	xlog_in_core_t		*iclog,
+	int			roundoff)
 {
 	int			i, j, k;
-	int			size = iclog->ic_offset + iclog->ic_roundoff;
+	int			size = iclog->ic_offset + roundoff;
 	uint			cycle_lsn;
 	xfs_caddr_t		dp;
 	xlog_in_core_2_t	*xhdr;
diff -urN linux-2.4.28-bk7/fs/xfs/xfs_mac.c linux-2.4.29/fs/xfs/xfs_mac.c
--- linux-2.4.28-bk7/fs/xfs/xfs_mac.c	2004-02-18 05:36:32.000000000 -0800
+++ linux-2.4.29/fs/xfs/xfs_mac.c	1969-12-31 16:00:00.000000000 -0800
@@ -1,72 +0,0 @@
-/*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like.  Any license provided herein, whether implied or
- * otherwise, applies only to this software file.  Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
- * Mountain View, CA  94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
- */
-
-#include "xfs.h"
-
-static xfs_mac_label_t *mac_low_high_lp;
-static xfs_mac_label_t *mac_high_low_lp;
-static xfs_mac_label_t *mac_admin_high_lp;
-static xfs_mac_label_t *mac_equal_equal_lp;
-
-/*
- * Test for the existence of a MAC label as efficiently as possible.
- */
-int
-xfs_mac_vhaslabel(
-	vnode_t		*vp)
-{
-	int		error;
-	int		len = sizeof(xfs_mac_label_t);
-	int		flags = ATTR_KERNOVAL|ATTR_ROOT;
-
-	VOP_ATTR_GET(vp, SGI_MAC_FILE, NULL, &len, flags, sys_cred, error);
-	return (error == 0);
-}
-
-int
-xfs_mac_iaccess(xfs_inode_t *ip, mode_t mode, struct cred *cr)
-{
-	xfs_mac_label_t mac;
-	xfs_mac_label_t *mp = mac_high_low_lp;
-
-	if (cr == NULL || sys_cred == NULL ) {
-		return EACCES;
-	}
-
-	if (xfs_attr_fetch(ip, SGI_MAC_FILE, (char *)&mac, sizeof(mac)) == 0) {
-		if ((mp = mac_add_label(&mac)) == NULL) {
-			return mac_access(mac_high_low_lp, cr, mode);
-		}
-	}
-
-	return mac_access(mp, cr, mode);
-}
diff -urN linux-2.4.28-bk7/fs/xfs/xfs_mount.c linux-2.4.29/fs/xfs/xfs_mount.c
--- linux-2.4.28-bk7/fs/xfs/xfs_mount.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/fs/xfs/xfs_mount.c	2005-01-19 07:08:14.548702466 -0800
@@ -975,7 +975,7 @@
 	 * Get and sanity-check the root inode.
 	 * Save the pointer to it in the mount structure.
 	 */
-	error = xfs_iget(mp, NULL, sbp->sb_rootino, XFS_ILOCK_EXCL, &rip, 0);
+	error = xfs_iget(mp, NULL, sbp->sb_rootino, 0, XFS_ILOCK_EXCL, &rip, 0);
 	if (error) {
 		cmn_err(CE_WARN, "XFS: failed to read root inode");
 		goto error3;
@@ -1036,7 +1036,7 @@
 	/*
 	 * Complete the quota initialisation, post-log-replay component.
 	 */
-	if ((error = XFS_QM_MOUNT(mp, quotamount, quotaflags)))
+	if ((error = XFS_QM_MOUNT(mp, quotamount, quotaflags, mfsi_flags)))
 		goto error4;
 
 	return 0;
@@ -1098,6 +1098,8 @@
 
 	xfs_unmountfs_writesb(mp);
 
+	xfs_unmountfs_wait(mp); 		/* wait for async bufs */
+
 	xfs_log_unmount(mp);			/* Done! No more fs ops. */
 
 	xfs_freesb(mp);
@@ -1142,6 +1144,16 @@
 	xfs_free_buftarg(mp->m_ddev_targp, 0);
 }
 
+void
+xfs_unmountfs_wait(xfs_mount_t *mp)
+{
+	if (mp->m_logdev_targp != mp->m_ddev_targp)
+		xfs_wait_buftarg(mp->m_logdev_targp);
+	if (mp->m_rtdev_targp)
+		xfs_wait_buftarg(mp->m_rtdev_targp);
+	xfs_wait_buftarg(mp->m_ddev_targp);
+}
+
 int
 xfs_unmountfs_writesb(xfs_mount_t *mp)
 {
diff -urN linux-2.4.28-bk7/fs/xfs/xfs_mount.h linux-2.4.29/fs/xfs/xfs_mount.h
--- linux-2.4.28-bk7/fs/xfs/xfs_mount.h	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/fs/xfs/xfs_mount.h	2005-01-19 07:08:14.549702509 -0800
@@ -133,7 +133,7 @@
 struct xfs_quotainfo;
 
 typedef int	(*xfs_qminit_t)(struct xfs_mount *, uint *, uint *);
-typedef int	(*xfs_qmmount_t)(struct xfs_mount *, uint, uint);
+typedef int	(*xfs_qmmount_t)(struct xfs_mount *, uint, uint, int);
 typedef int	(*xfs_qmunmount_t)(struct xfs_mount *);
 typedef void	(*xfs_qmdone_t)(struct xfs_mount *);
 typedef void	(*xfs_dqrele_t)(struct xfs_dquot *);
@@ -171,8 +171,8 @@
 
 #define XFS_QM_INIT(mp, mnt, fl) \
 	(*(mp)->m_qm_ops.xfs_qminit)(mp, mnt, fl)
-#define XFS_QM_MOUNT(mp, mnt, fl) \
-	(*(mp)->m_qm_ops.xfs_qmmount)(mp, mnt, fl)
+#define XFS_QM_MOUNT(mp, mnt, fl, mfsi_flags) \
+	(*(mp)->m_qm_ops.xfs_qmmount)(mp, mnt, fl, mfsi_flags)
 #define XFS_QM_UNMOUNT(mp) \
 	(*(mp)->m_qm_ops.xfs_qmunmount)(mp)
 #define XFS_QM_DONE(mp) \
@@ -466,6 +466,7 @@
 #define XFS_MFSI_CLIENT		0x02	/* Is a client -- skip lots of stuff */
 #define XFS_MFSI_NOUNLINK	0x08	/* Skip unlinked inode processing in */
 					/* log recovery */
+#define XFS_MFSI_NO_QUOTACHECK	0x10	/* Skip quotacheck processing */
 
 /*
  * Macros for getting from mount to vfs and back.
@@ -540,6 +541,7 @@
 extern int	xfs_mountfs(struct vfs *, xfs_mount_t *mp, int);
 
 extern int	xfs_unmountfs(xfs_mount_t *, struct cred *);
+extern void	xfs_unmountfs_wait(xfs_mount_t *);
 extern void	xfs_unmountfs_close(xfs_mount_t *, struct cred *);
 extern int	xfs_unmountfs_writesb(xfs_mount_t *);
 extern int	xfs_unmount_flush(xfs_mount_t *, int);
diff -urN linux-2.4.28-bk7/fs/xfs/xfs_rtalloc.c linux-2.4.29/fs/xfs/xfs_rtalloc.c
--- linux-2.4.28-bk7/fs/xfs/xfs_rtalloc.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/fs/xfs/xfs_rtalloc.c	2005-01-19 07:08:14.550702552 -0800
@@ -149,7 +149,7 @@
 		/*
 		 * Lock the inode.
 		 */
-		if ((error = xfs_trans_iget(mp, tp, ino, XFS_ILOCK_EXCL, &ip)))
+		if ((error = xfs_trans_iget(mp, tp, ino, 0, XFS_ILOCK_EXCL, &ip)))
 			goto error_exit;
 		XFS_BMAP_INIT(&flist, &firstblock);
 		/*
@@ -189,7 +189,7 @@
 			/*
 			 * Lock the bitmap inode.
 			 */
-			if ((error = xfs_trans_iget(mp, tp, ino, XFS_ILOCK_EXCL,
+			if ((error = xfs_trans_iget(mp, tp, ino, 0, XFS_ILOCK_EXCL,
 					&ip)))
 				goto error_exit;
 			/*
@@ -1966,7 +1966,8 @@
 	/*
 	 * Calculate new parameters.  These are the final values to be reached.
 	 */
-	nrextents = do_div(nrblocks, in->extsize);
+	nrextents = nrblocks;
+	do_div(nrextents, in->extsize);
 	nrbmblocks = roundup_64(nrextents, NBBY * sbp->sb_blocksize);
 	nrextslog = xfs_highbit32(nrextents);
 	nrsumlevels = nrextslog + 1;
@@ -2021,7 +2022,8 @@
 			XFS_RTMIN(nrblocks,
 				  nsbp->sb_rbmblocks * NBBY *
 				  nsbp->sb_blocksize * nsbp->sb_rextsize);
-		nsbp->sb_rextents = do_div(nsbp->sb_rblocks, nsbp->sb_rextsize);
+		nsbp->sb_rextents = nsbp->sb_rblocks;
+		do_div(nsbp->sb_rextents, nsbp->sb_rextsize);
 		nsbp->sb_rextslog = xfs_highbit32(nsbp->sb_rextents);
 		nrsumlevels = nmp->m_rsumlevels = nsbp->sb_rextslog + 1;
 		nrsumsize =
@@ -2040,7 +2042,7 @@
 		/*
 		 * Lock out other callers by grabbing the bitmap inode lock.
 		 */
-		if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino,
+		if ((error = xfs_trans_iget(mp, tp, 0, mp->m_sb.sb_rbmino,
 				XFS_ILOCK_EXCL, &ip)))
 			goto error_exit;
 		ASSERT(ip == mp->m_rbmip);
@@ -2055,7 +2057,7 @@
 		 * Get the summary inode into the transaction.
 		 */
 		if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rsumino,
-				XFS_ILOCK_EXCL, &ip)))
+				0, XFS_ILOCK_EXCL, &ip)))
 			goto error_exit;
 		ASSERT(ip == mp->m_rsumip);
 		/*
@@ -2175,7 +2177,7 @@
 	/*
 	 * Lock out other callers by grabbing the bitmap inode lock.
 	 */
-	error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, XFS_ILOCK_EXCL, &ip);
+	error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0, XFS_ILOCK_EXCL, &ip);
 	if (error) {
 		return error;
 	}
@@ -2238,7 +2240,7 @@
 	/*
 	 * Synchronize by locking the bitmap inode.
 	 */
-	error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, XFS_ILOCK_EXCL, &ip);
+	error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0, XFS_ILOCK_EXCL, &ip);
 	if (error) {
 		return error;
 	}
@@ -2346,12 +2348,12 @@
 	sbp = &mp->m_sb;
 	if (sbp->sb_rbmino == NULLFSINO)
 		return 0;
-	error = xfs_iget(mp, NULL, sbp->sb_rbmino, 0, &mp->m_rbmip, 0);
+	error = xfs_iget(mp, NULL, sbp->sb_rbmino, 0, 0, &mp->m_rbmip, 0);
 	if (error)
 		return error;
 	ASSERT(mp->m_rbmip != NULL);
 	ASSERT(sbp->sb_rsumino != NULLFSINO);
-	error = xfs_iget(mp, NULL, sbp->sb_rsumino, 0, &mp->m_rsumip, 0);
+	error = xfs_iget(mp, NULL, sbp->sb_rsumino, 0, 0, &mp->m_rsumip, 0);
 	if (error) {
 		VN_RELE(XFS_ITOV(mp->m_rbmip));
 		return error;
@@ -2382,7 +2384,7 @@
 	__uint64_t	seq;		/* sequence number of file creation */
 	__uint64_t	*seqp;		/* pointer to seqno in inode */
 
-	error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, XFS_ILOCK_EXCL, &ip);
+	error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0, XFS_ILOCK_EXCL, &ip);
 	if (error)
 		return error;
 	ASSERT(ip == mp->m_rbmip);
diff -urN linux-2.4.28-bk7/fs/xfs/xfs_trans.h linux-2.4.29/fs/xfs/xfs_trans.h
--- linux-2.4.28-bk7/fs/xfs/xfs_trans.h	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29/fs/xfs/xfs_trans.h	2005-01-19 07:08:14.551702596 -0800
@@ -1007,7 +1007,7 @@
 void		xfs_trans_dquot_buf(xfs_trans_t *, struct xfs_buf *, uint);
 void		xfs_trans_inode_alloc_buf(xfs_trans_t *, struct xfs_buf *);
 int		xfs_trans_iget(struct xfs_mount *, xfs_trans_t *,
-			       xfs_ino_t , uint, struct xfs_inode **);
+			       xfs_ino_t , uint, uint, struct xfs_inode **);
 void		xfs_trans_ijoin(xfs_trans_t *, struct xfs_inode *, uint);
 void		xfs_trans_ihold(xfs_trans_t *, struct xfs_inode *);
 void		xfs_trans_ihold_release(xfs_trans_t *, struct xfs_inode *);
diff -urN linux-2.4.28-bk7/fs/xfs/xfs_trans_inode.c linux-2.4.29/fs/xfs/xfs_trans_inode.c
--- linux-2.4.28-bk7/fs/xfs/xfs_trans_inode.c	2004-02-18 05:36:32.000000000 -0800
+++ linux-2.4.29/fs/xfs/xfs_trans_inode.c	2005-01-19 07:08:14.552702639 -0800
@@ -95,6 +95,7 @@
 	xfs_mount_t	*mp,
 	xfs_trans_t	*tp,
 	xfs_ino_t	ino,
+	uint		flags,
 	uint		lock_flags,
 	xfs_inode_t	**ipp)
 {
@@ -106,9 +107,8 @@
 	 * If the transaction pointer is NULL, just call the normal
 	 * xfs_iget().
 	 */
-	if (tp == NULL) {
-		return (xfs_iget(mp, NULL, ino, lock_flags, ipp, 0));
-	}
+	if (tp == NULL)
+		return xfs_iget(mp, NULL, ino, flags, lock_flags, ipp, 0);
 
 	/*
 	 * If we find the inode in core with this transaction
@@ -148,7 +148,7 @@
 	}
 
 	ASSERT(lock_flags & XFS_ILOCK_EXCL);
-	error = xfs_iget(tp->t_mountp, tp, ino, lock_flags, &ip, 0);
+	error = xfs_iget(tp->t_mountp, tp, ino, flags, lock_flags, &ip, 0);
 	if (error) {
 		return error;
 	}
@@ -186,7 +186,6 @@
 	return 0;
 }
 
-
 /*
  * Add the locked inode to the transaction.
  * The inode must be locked, and it cannot be associated with any
diff -urN linux-2.4.28-bk7/fs/xfs/xfs_utils.c linux-2.4.29/fs/xfs/xfs_utils.c
--- linux-2.4.28-bk7/fs/xfs/xfs_utils.c	2004-02-18 05:36:32.000000000 -0800
+++ linux-2.4.29/fs/xfs/xfs_utils.c	2005-01-19 07:08:14.553702682 -0800
@@ -110,7 +110,7 @@
 		 * reservation in the inactive routine.
 		 */
 		xfs_iunlock(dp, lock_mode);
-		error = xfs_iget(dp->i_mount, NULL, *inum, 0, ipp, 0);
+		error = xfs_iget(dp->i_mount, NULL, *inum, 0, 0, ipp, 0);
 		xfs_ilock(dp, lock_mode);
 
 		if (error) {
diff -urN linux-2.4.28-bk7/fs/xfs/xfs_vfsops.c linux-2.4.29/fs/xfs/xfs_vfsops.c
--- linux-2.4.28-bk7/fs/xfs/xfs_vfsops.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/fs/xfs/xfs_vfsops.c	2005-01-19 07:08:14.554702726 -0800
@@ -1053,6 +1053,11 @@
 			continue;
 		}
 
+		if (VN_BAD(vp)) {
+			ip = ip->i_mnext;
+			continue;
+		}
+
 		if (XFS_FORCED_SHUTDOWN(mp) && !(flags & SYNC_CLOSE)) {
 			XFS_MOUNT_IUNLOCK(mp);
 			kmem_free(ipointer, sizeof(xfs_iptr_t));
@@ -1575,7 +1580,7 @@
 }
 
 /*
- * xfs_vget - called by DMAPI to get vnode from file handle
+ * xfs_vget - called by DMAPI and NFSD to get vnode from file handle
  */
 STATIC int
 xfs_vget(
@@ -1583,37 +1588,41 @@
 	vnode_t		**vpp,
 	fid_t		*fidp)
 {
-	xfs_fid_t	*xfid;
+	xfs_mount_t	*mp = XFS_BHVTOM(bdp);
+	xfs_fid_t	*xfid = (struct xfs_fid *)fidp;
 	xfs_inode_t	*ip;
 	int		error;
 	xfs_ino_t	ino;
 	unsigned int	igen;
-	xfs_mount_t	*mp;
 
-	xfid  = (struct xfs_fid *)fidp;
-	if (xfid->xfs_fid_len == sizeof(*xfid) - sizeof(xfid->xfs_fid_len)) {
-		ino  = xfid->xfs_fid_ino;
-		igen = xfid->xfs_fid_gen;
-	} else {
-		/*
-		 * Invalid.  Since handles can be created in user space
-		 * and passed in via gethandle(), this is not cause for
-		 * a panic.
-		 */
+	/*
+	 * Invalid.  Since handles can be created in user space and passed in
+	 * via gethandle(), this is not cause for a panic.
+	 */
+	if (xfid->xfs_fid_len != sizeof(*xfid) - sizeof(xfid->xfs_fid_len))
 		return XFS_ERROR(EINVAL);
-	}
-	mp = XFS_BHVTOM(bdp);
-	error = xfs_iget(mp, NULL, ino, XFS_ILOCK_SHARED, &ip, 0);
+
+	ino  = xfid->xfs_fid_ino;
+	igen = xfid->xfs_fid_gen;
+
+	/*
+	 * NFS can sometimes send requests for ino 0.  Fail them gracefully.
+	 */
+	if (ino == 0)
+		return XFS_ERROR(ESTALE);
+
+	error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_SHARED, &ip, 0);
 	if (error) {
 		*vpp = NULL;
 		return error;
 	}
+
 	if (ip == NULL) {
 		*vpp = NULL;
 		return XFS_ERROR(EIO);
 	}
 
-	if (ip->i_d.di_mode == 0 || (igen && (ip->i_d.di_gen != igen))) {
+	if (ip->i_d.di_mode == 0 || ip->i_d.di_gen != igen) {
 		xfs_iput_new(ip, XFS_ILOCK_SHARED);
 		*vpp = NULL;
 		return XFS_ERROR(ENOENT);
diff -urN linux-2.4.28-bk7/fs/xfs/xfs_vnodeops.c linux-2.4.29/fs/xfs/xfs_vnodeops.c
--- linux-2.4.28-bk7/fs/xfs/xfs_vnodeops.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/fs/xfs/xfs_vnodeops.c	2005-01-19 07:08:14.557702856 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -826,29 +826,34 @@
 				mp->m_sb.sb_blocklog;
 		}
 		if (mask & XFS_AT_XFLAGS) {
+			uint	di_flags;
+
 			/* can't set PREALLOC this way, just preserve it */
-			ip->i_d.di_flags =
-				(ip->i_d.di_flags & XFS_DIFLAG_PREALLOC);
-			if (vap->va_xflags & XFS_XFLAG_REALTIME &&
-			    (ip->i_d.di_mode & S_IFMT) == S_IFREG) {
-				ip->i_d.di_flags |= XFS_DIFLAG_REALTIME;
-				ip->i_iocore.io_flags |= XFS_IOCORE_RT;
-			} else {
-				ip->i_iocore.io_flags &= ~XFS_IOCORE_RT;
-			}
+			di_flags = (ip->i_d.di_flags & XFS_DIFLAG_PREALLOC);
 			if (vap->va_xflags & XFS_XFLAG_IMMUTABLE)
-				ip->i_d.di_flags |= XFS_DIFLAG_IMMUTABLE;
+				di_flags |= XFS_DIFLAG_IMMUTABLE;
 			if (vap->va_xflags & XFS_XFLAG_APPEND)
-				ip->i_d.di_flags |= XFS_DIFLAG_APPEND;
+				di_flags |= XFS_DIFLAG_APPEND;
 			if (vap->va_xflags & XFS_XFLAG_SYNC)
-				ip->i_d.di_flags |= XFS_DIFLAG_SYNC;
+				di_flags |= XFS_DIFLAG_SYNC;
 			if (vap->va_xflags & XFS_XFLAG_NOATIME)
-				ip->i_d.di_flags |= XFS_DIFLAG_NOATIME;
+				di_flags |= XFS_DIFLAG_NOATIME;
 			if (vap->va_xflags & XFS_XFLAG_NODUMP)
-				ip->i_d.di_flags |= XFS_DIFLAG_NODUMP;
-			if ((vap->va_xflags & XFS_XFLAG_RTINHERIT) &&
-			    (ip->i_d.di_mode & S_IFMT) == S_IFDIR)
-				ip->i_d.di_flags |= XFS_DIFLAG_RTINHERIT;
+				di_flags |= XFS_DIFLAG_NODUMP;
+			if ((ip->i_d.di_mode & S_IFMT) == S_IFDIR) {
+				if (vap->va_xflags & XFS_XFLAG_RTINHERIT)
+					di_flags |= XFS_DIFLAG_RTINHERIT;
+				if (vap->va_xflags & XFS_XFLAG_NOSYMLINKS)
+					di_flags |= XFS_DIFLAG_NOSYMLINKS;
+			} else {
+				if (vap->va_xflags & XFS_XFLAG_REALTIME) {
+					di_flags |= XFS_DIFLAG_REALTIME;
+					ip->i_iocore.io_flags |= XFS_IOCORE_RT;
+				} else {
+					ip->i_iocore.io_flags &= ~XFS_IOCORE_RT;
+				}
+			}
+			ip->i_d.di_flags = di_flags;
 		}
 		xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
 		timeflags |= XFS_ICHGTIME_CHG;
@@ -1606,7 +1611,7 @@
 	 * If the inode is already free, then there can be nothing
 	 * to clean up here.
 	 */
-	if (ip->i_d.di_mode == 0) {
+	if (ip->i_d.di_mode == 0 || VN_BAD(vp)) {
 		ASSERT(ip->i_df.if_real_bytes == 0);
 		ASSERT(ip->i_df.if_broot_bytes == 0);
 		return VN_INACTIVE_CACHE;
@@ -3390,6 +3395,14 @@
 	xfs_ilock(dp, XFS_ILOCK_EXCL);
 
 	/*
+	 * Check whether the directory allows new symlinks or not.
+	 */
+	if (dp->i_d.di_flags & XFS_DIFLAG_NOSYMLINKS) {
+		error = XFS_ERROR(EPERM);
+		goto error_return;
+	}
+
+	/*
 	 * Reserve disk quota : blocks and inode.
 	 */
 	error = XFS_TRANS_RESERVE_QUOTA(mp, tp, udqp, gdqp, resblks, 1, 0);
@@ -3795,11 +3808,17 @@
 	vnode_t		*vp;
 
 	vp = BHV_TO_VNODE(bdp);
+	ip = XFS_BHVTOI(bdp);
 
 	vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address);
 
 	ASSERT(!VN_MAPPED(vp));
-	ip = XFS_BHVTOI(bdp);
+
+	/* bad inode, get out here ASAP */
+	if (VN_BAD(vp)) {
+		xfs_ireclaim(ip);
+		return 0;
+	}
 
 	if ((ip->i_d.di_mode & S_IFMT) == S_IFREG) {
 		if (ip->i_d.di_size > 0) {
@@ -3877,8 +3896,12 @@
 	int		sync_mode)
 {
 	xfs_ihash_t	*ih = ip->i_hash;
+	vnode_t		*vp = XFS_ITOV_NULL(ip);
 	int		error;
 
+	if (vp && VN_BAD(vp))
+		goto reclaim;
+
 	/* The hash lock here protects a thread in xfs_iget_core from
 	 * racing with us on linking the inode back with a vnode.
 	 * Once we have the XFS_IRECLAIM flag set it will not touch
@@ -3886,8 +3909,7 @@
 	 */
 	write_lock(&ih->ih_lock);
 	if ((ip->i_flags & XFS_IRECLAIM) ||
-	    (!(ip->i_flags & XFS_IRECLAIMABLE) &&
-	      (XFS_ITOV_NULL(ip) == NULL))) {
+	    (!(ip->i_flags & XFS_IRECLAIMABLE) && vp == NULL)) {
 		write_unlock(&ih->ih_lock);
 		if (locked) {
 			xfs_ifunlock(ip);
@@ -3926,8 +3948,7 @@
 			 */
 			if (error) {
 				xfs_iunlock(ip, XFS_ILOCK_EXCL);
-				xfs_ireclaim(ip);
-				return (0);
+				goto reclaim;
 			}
 			xfs_iflock(ip); /* synchronize with xfs_iflush_done */
 		}
@@ -3946,6 +3967,7 @@
 		xfs_iunlock(ip, XFS_ILOCK_EXCL);
 	}
 
+ reclaim:
 	xfs_ireclaim(ip);
 	return 0;
 }
@@ -3954,15 +3976,13 @@
 xfs_finish_reclaim_all(xfs_mount_t *mp, int noblock)
 {
 	int		purged;
-	struct list_head	*curr, *next;
-	xfs_inode_t	*ip;
+	xfs_inode_t	*ip, *n;
 	int		done = 0;
 
 	while (!done) {
 		purged = 0;
 		XFS_MOUNT_ILOCK(mp);
-		list_for_each_safe(curr, next, &mp->m_del_inodes) {
-			ip = list_entry(curr, xfs_inode_t, i_reclaim);
+		list_for_each_entry_safe(ip, n, &mp->m_del_inodes, i_reclaim) {
 			if (noblock) {
 				if (xfs_ilock_nowait(ip, XFS_ILOCK_EXCL) == 0)
 					continue;
diff -urN linux-2.4.28-bk7/include/asm-sparc/elf.h linux-2.4.29/include/asm-sparc/elf.h
--- linux-2.4.28-bk7/include/asm-sparc/elf.h	2000-07-11 19:02:37.000000000 -0700
+++ linux-2.4.29/include/asm-sparc/elf.h	2005-01-19 07:08:14.596704545 -0800
@@ -81,7 +81,7 @@
    the loader.  We need to make sure that it is out of the way of the program
    that it will "exec", and that there is sufficient room for the brk.  */
 
-#define ELF_ET_DYN_BASE         (0x08000000)
+#define ELF_ET_DYN_BASE         (TASK_UNMAPPED_BASE)
 
 /* This yields a mask that user programs can use to figure out what
    instruction set this cpu supports.  This can NOT be done in userspace
diff -urN linux-2.4.28-bk7/include/asm-x86_64/socket32.h linux-2.4.29/include/asm-x86_64/socket32.h
--- linux-2.4.28-bk7/include/asm-x86_64/socket32.h	2002-11-28 15:53:15.000000000 -0800
+++ linux-2.4.29/include/asm-x86_64/socket32.h	2005-01-19 07:08:14.596704545 -0800
@@ -45,6 +45,11 @@
 				    (struct cmsghdr32 *)(ctl) : \
 				    (struct cmsghdr32 *)NULL)
 #define CMSG32_FIRSTHDR(msg)	__CMSG32_FIRSTHDR((msg)->msg_control, (msg)->msg_controllen)
+#define CMSG32_OK(ucmlen, ucmsg, mhdr) \
+	((ucmlen) >= sizeof(struct cmsghdr32) && \
+	 (ucmlen) <= (unsigned long) \
+	 ((mhdr)->msg_controllen - \
+	  ((char *)(ucmsg) - (char *)(mhdr)->msg_control)))
 
 __inline__ struct cmsghdr32 *__cmsg32_nxthdr(void *__ctl, __kernel_size_t __size,
 					      struct cmsghdr32 *__cmsg, int __cmsg_len)
diff -urN linux-2.4.28-bk7/include/linux/auto_fs4.h linux-2.4.29/include/linux/auto_fs4.h
--- linux-2.4.28-bk7/include/linux/auto_fs4.h	2001-11-22 11:46:40.000000000 -0800
+++ linux-2.4.29/include/linux/auto_fs4.h	2005-01-19 07:08:14.597704588 -0800
@@ -41,7 +41,10 @@
 	struct autofs_packet_expire_multi expire_multi;
 };
 
-#define AUTOFS_IOC_EXPIRE_MULTI _IOW(0x93,0x66,int)
-
+#define AUTOFS_IOC_EXPIRE_MULTI		_IOW(0x93,0x66,int)
+#define AUTOFS_IOC_PROTOSUBVER		_IOR(0x93,0x67,int)
+#define AUTOFS_IOC_ASKREGHOST		_IOR(0x93,0x68,int)
+#define AUTOFS_IOC_TOGGLEREGHOST	_IOR(0x93,0x69,int)
+#define AUTOFS_IOC_ASKUMOUNT		_IOR(0x93,0x70,int)
 
 #endif /* _LINUX_AUTO_FS4_H */
diff -urN linux-2.4.28-bk7/include/linux/coda.h linux-2.4.29/include/linux/coda.h
--- linux-2.4.28-bk7/include/linux/coda.h	2001-04-25 16:18:54.000000000 -0700
+++ linux-2.4.29/include/linux/coda.h	2005-01-19 07:08:14.599704675 -0800
@@ -767,8 +767,8 @@
 #define PIOCPARM_MASK 0x0000ffff
 struct ViceIoctl {
         caddr_t in, out;        /* Data to be transferred in, or out */
-        short in_size;          /* Size of input buffer <= 2K */
-        short out_size;         /* Maximum size of output buffer, <= 2K */
+        u_short in_size;        /* Size of input buffer <= 2K */
+        u_short out_size;       /* Maximum size of output buffer, <= 2K */
 };
 
 struct PioctlData {
diff -urN linux-2.4.28-bk7/include/linux/delay.h linux-2.4.29/include/linux/delay.h
--- linux-2.4.28-bk7/include/linux/delay.h	2001-01-04 12:50:17.000000000 -0800
+++ linux-2.4.29/include/linux/delay.h	2005-01-19 07:08:14.600704718 -0800
@@ -9,9 +9,64 @@
 
 extern unsigned long loops_per_jiffy;
 
+#include <linux/time.h>
+#include <linux/sched.h>
 #include <asm/delay.h>
 
 /*
+ * Convert jiffies to milliseconds and back.
+ *
+ * Avoid unnecessary multiplications/divisions in the
+ * two most common HZ cases:
+ */
+static inline unsigned int jiffies_to_msecs(const unsigned long j)
+{
+#if HZ <= 1000 && !(1000 % HZ)
+	return (1000 / HZ) * j;
+#elif HZ > 1000 && !(HZ % 1000)
+	return (j + (HZ / 1000) - 1)/(HZ / 1000);
+#else
+	return (j * 1000) / HZ;
+#endif
+}
+
+static inline unsigned int jiffies_to_usecs(const unsigned long j)
+{
+#if HZ <= 1000 && !(1000 % HZ)
+	return (1000000 / HZ) * j;
+#elif HZ > 1000 && !(HZ % 1000)
+	return (j*1000 + (HZ - 1000))/(HZ / 1000);
+#else
+	return (j * 1000000) / HZ;
+#endif
+}
+
+static inline unsigned long msecs_to_jiffies(const unsigned int m)
+{
+	if (m > jiffies_to_msecs(MAX_JIFFY_OFFSET))
+		return MAX_JIFFY_OFFSET;
+#if HZ <= 1000 && !(1000 % HZ)
+	return (m + (1000 / HZ) - 1) / (1000 / HZ);
+#elif HZ > 1000 && !(HZ % 1000)
+	return m * (HZ / 1000);
+#else
+	return (m * HZ + 999) / 1000;
+#endif
+}
+
+static inline void msleep(unsigned long msecs)
+{
+        set_current_state(TASK_UNINTERRUPTIBLE);
+        schedule_timeout(msecs_to_jiffies(msecs) + 1);
+}
+
+static inline void ssleep(unsigned long secs)
+{
+        set_current_state(TASK_UNINTERRUPTIBLE);
+        schedule_timeout((HZ * secs) + 1);
+}
+
+/*
  * Using udelay() for intervals greater than a few milliseconds can
  * risk overflow for high loops_per_jiffy (high bogomips) machines. The
  * mdelay() provides a wrapper to prevent this.  For delays greater
diff -urN linux-2.4.28-bk7/include/linux/dqblk_xfs.h linux-2.4.29/include/linux/dqblk_xfs.h
--- linux-2.4.28-bk7/include/linux/dqblk_xfs.h	2004-02-18 05:36:32.000000000 -0800
+++ linux-2.4.29/include/linux/dqblk_xfs.h	2005-01-19 07:08:14.601704761 -0800
@@ -1,34 +1,22 @@
 /*
- * Copyright (c) 1995-2001 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 1995-2001,2004 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2.1 of the GNU Lesser General Public License
  * as published by the Free Software Foundation.
  *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * 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
  *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like.  Any license provided herein, whether implied or
- * otherwise, applies only to this software file.  Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
- * USA.
- *
- * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
- * Mountain View, CA  94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ * Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ * Mountain View, CA 94043, USA, or: http://www.sgi.com
  */
 #ifndef _LINUX_DQBLK_XFS_H
 #define _LINUX_DQBLK_XFS_H
@@ -40,12 +28,12 @@
  */
 
 #define XQM_CMD(x)	(('X'<<8)+(x))	/* note: forms first QCMD argument */
-#define Q_XQUOTAON	XQM_CMD(0x1)	/* enable accounting/enforcement */
-#define Q_XQUOTAOFF	XQM_CMD(0x2)	/* disable accounting/enforcement */
-#define Q_XGETQUOTA	XQM_CMD(0x3)	/* get disk limits and usage */
-#define Q_XSETQLIM	XQM_CMD(0x4)	/* set disk limits */
-#define Q_XGETQSTAT	XQM_CMD(0x5)	/* get quota subsystem status */
-#define Q_XQUOTARM	XQM_CMD(0x6)	/* free disk space used by dquots */
+#define Q_XQUOTAON	XQM_CMD(1)	/* enable accounting/enforcement */
+#define Q_XQUOTAOFF	XQM_CMD(2)	/* disable accounting/enforcement */
+#define Q_XGETQUOTA	XQM_CMD(3)	/* get disk limits and usage */
+#define Q_XSETQLIM	XQM_CMD(4)	/* set disk limits */
+#define Q_XGETQSTAT	XQM_CMD(5)	/* get quota subsystem status */
+#define Q_XQUOTARM	XQM_CMD(6)	/* free disk space used by dquots */
 
 /*
  * fs_disk_quota structure:
@@ -105,15 +93,30 @@
 #define FS_DQ_TIMER_MASK	(FS_DQ_BTIMER | FS_DQ_ITIMER | FS_DQ_RTBTIMER)
 
 /*
+ * Warning counts are set in both super user's dquot and others. For others,
+ * warnings are set/cleared by the administrators (or automatically by going
+ * below the soft limit).  Superusers warning values set the warning limits
+ * for the rest.  In case these values are zero, the DQ_{F,B}WARNLIMIT values
+ * defined below are used. 
+ * These values also apply only to the d_fieldmask field for Q_XSETQLIM.
+ */
+#define FS_DQ_BWARNS	(1<<9)
+#define FS_DQ_IWARNS	(1<<10)
+#define FS_DQ_RTBWARNS	(1<<11)
+#define FS_DQ_WARNS_MASK	(FS_DQ_BWARNS | FS_DQ_IWARNS | FS_DQ_RTBWARNS)
+
+/*
  * Various flags related to quotactl(2).  Only relevant to XFS filesystems.
  */
 #define XFS_QUOTA_UDQ_ACCT	(1<<0)  /* user quota accounting */
 #define XFS_QUOTA_UDQ_ENFD	(1<<1)  /* user quota limits enforcement */
 #define XFS_QUOTA_GDQ_ACCT	(1<<2)  /* group quota accounting */
 #define XFS_QUOTA_GDQ_ENFD	(1<<3)  /* group quota limits enforcement */
+#define XFS_QUOTA_PDQ_ACCT	(1<<4)  /* project quota accounting */
+#define XFS_QUOTA_PDQ_ENFD	(1<<5)  /* project quota limits enforcement */
 
 #define XFS_USER_QUOTA		(1<<0)	/* user quota type */
-#define XFS_PROJ_QUOTA		(1<<1)	/* (IRIX) project quota type */
+#define XFS_PROJ_QUOTA		(1<<1)	/* project quota type */
 #define XFS_GROUP_QUOTA		(1<<2)	/* group quota type */
 
 /*
diff -urN linux-2.4.28-bk7/include/linux/fb.h linux-2.4.29/include/linux/fb.h
--- linux-2.4.28-bk7/include/linux/fb.h	2004-02-18 05:36:32.000000000 -0800
+++ linux-2.4.29/include/linux/fb.h	2005-01-19 07:08:14.601704761 -0800
@@ -323,6 +323,7 @@
    struct fb_cmap cmap;                 /* Current cmap */
    struct fb_ops *fbops;
    char *screen_base;                   /* Virtual address */
+   u32 mapped_vram;			/* ioremap()'ed VRAM */
    struct display *disp;		/* initial display variable */
    struct vc_data *display_fg;		/* Console visible on this display */
    char fontname[40];			/* default font name */
diff -urN linux-2.4.28-bk7/include/linux/if_arp.h linux-2.4.29/include/linux/if_arp.h
--- linux-2.4.28-bk7/include/linux/if_arp.h	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29/include/linux/if_arp.h	2005-01-19 07:08:14.603704848 -0800
@@ -40,6 +40,7 @@
 #define ARPHRD_METRICOM	23		/* Metricom STRIP (new IANA id)	*/
 #define	ARPHRD_IEEE1394	24		/* IEEE 1394 IPv4 - RFC 2734	*/
 #define ARPHRD_EUI64	27		/* EUI-64                       */
+#define ARPHRD_INFINIBAND	32		/* InfiniBand                   */
 
 /* Dummy types for non ARP hardware */
 #define ARPHRD_SLIP	256
diff -urN linux-2.4.28-bk7/include/linux/if_ether.h linux-2.4.29/include/linux/if_ether.h
--- linux-2.4.28-bk7/include/linux/if_ether.h	2003-08-25 04:44:44.000000000 -0700
+++ linux-2.4.29/include/linux/if_ether.h	2005-01-19 07:08:14.603704848 -0800
@@ -61,6 +61,8 @@
 #define ETH_P_IPV6	0x86DD		/* IPv6 over bluebook		*/
 #define ETH_P_PPP_DISC	0x8863		/* PPPoE discovery messages     */
 #define ETH_P_PPP_SES	0x8864		/* PPPoE session messages	*/
+#define ETH_P_MPLS_UC	0x8847		/* MPLS Unicast traffic         */
+#define ETH_P_MPLS_MC	0x8848		/* MPLS Multicast traffic       */
 #define ETH_P_ATMMPOA	0x884c		/* MultiProtocol Over ATM	*/
 #define ETH_P_ATMFATE	0x8884		/* Frame-based ATM Transport
 					 * over Ethernet
diff -urN linux-2.4.28-bk7/include/linux/libata-compat.h linux-2.4.29/include/linux/libata-compat.h
--- linux-2.4.28-bk7/include/linux/libata-compat.h	2005-01-19 07:07:43.290348645 -0800
+++ linux-2.4.29/include/linux/libata-compat.h	2005-01-19 07:08:14.606704978 -0800
@@ -6,31 +6,15 @@
 
 #define MODULE_VERSION(ver_str)
 
-static inline unsigned long msecs_to_jiffies(unsigned long msecs)
-{
-	return ((HZ * msecs + 999) / 1000);
-}
 struct device {
 	struct pci_dev pdev;
 };
 
-static inline void msleep(unsigned long msecs)
-{
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(msecs_to_jiffies(msecs) + 1);
-}
-
 static inline void libata_msleep(unsigned long msecs)
 {
 	msleep(msecs);
 }
 
-static inline void ssleep(unsigned long secs)
-{
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((HZ * secs) + 1);
-}
-
 static inline struct pci_dev *to_pci_dev(struct device *dev)
 {
 	return (struct pci_dev *) dev;
diff -urN linux-2.4.28-bk7/include/linux/libata.h linux-2.4.29/include/linux/libata.h
--- linux-2.4.28-bk7/include/linux/libata.h	2005-01-19 07:07:43.291348688 -0800
+++ linux-2.4.29/include/linux/libata.h	2005-01-19 07:08:14.607705021 -0800
@@ -113,6 +113,7 @@
 	ATA_FLAG_SRST		= (1 << 5), /* use ATA SRST, not E.D.D. */
 	ATA_FLAG_MMIO		= (1 << 6), /* use MMIO, not PIO */
 	ATA_FLAG_SATA_RESET	= (1 << 7), /* use COMRESET */
+	ATA_FLAG_PIO_DMA	= (1 << 8), /* PIO cmds via DMA */
 
 	ATA_QCFLAG_ACTIVE	= (1 << 1), /* cmd not yet ack'd to scsi lyer */
 	ATA_QCFLAG_SG		= (1 << 3), /* have s/g table? */
@@ -339,6 +340,8 @@
 	void (*phy_reset) (struct ata_port *ap);
 	void (*post_set_mode) (struct ata_port *ap);
 
+	int (*check_atapi_dma) (struct ata_queued_cmd *qc);
+
 	void (*bmdma_setup) (struct ata_queued_cmd *qc);
 	void (*bmdma_start) (struct ata_queued_cmd *qc);
 
diff -urN linux-2.4.28-bk7/include/linux/mm.h linux-2.4.29/include/linux/mm.h
--- linux-2.4.28-bk7/include/linux/mm.h	2005-01-19 07:07:43.292348732 -0800
+++ linux-2.4.29/include/linux/mm.h	2005-01-19 07:08:14.608705064 -0800
@@ -548,7 +548,7 @@
 /* mmap.c */
 extern void lock_vma_mappings(struct vm_area_struct *);
 extern void unlock_vma_mappings(struct vm_area_struct *);
-extern void insert_vm_struct(struct mm_struct *, struct vm_area_struct *);
+extern int insert_vm_struct(struct mm_struct *, struct vm_area_struct *);
 extern void __insert_vm_struct(struct mm_struct *, struct vm_area_struct *);
 extern void build_mmap_rb(struct mm_struct *);
 extern void exit_mmap(struct mm_struct *);
@@ -647,18 +647,33 @@
 	unsigned long grow;
 
 	/*
-	 * vma->vm_start/vm_end cannot change under us because the caller is required
-	 * to hold the mmap_sem in write mode. We need to get the spinlock only
-	 * before relocating the vma range ourself.
+	 * vma->vm_start/vm_end cannot change under us because the caller
+	 * is required to hold the mmap_sem in read mode.  We need the
+	 * page_table_lock lock to serialize against concurrent expand_stacks.
 	 */
 	address &= PAGE_MASK;
  	spin_lock(&vma->vm_mm->page_table_lock);
+
+	/* already expanded while we were spinning? */
+	if (vma->vm_start <= address) {
+		spin_unlock(&vma->vm_mm->page_table_lock);
+		return 0;
+	}
+
 	grow = (vma->vm_start - address) >> PAGE_SHIFT;
 	if (vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur ||
 	    ((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) > current->rlim[RLIMIT_AS].rlim_cur) {
 		spin_unlock(&vma->vm_mm->page_table_lock);
 		return -ENOMEM;
 	}
+
+	if ((vma->vm_flags & VM_LOCKED) &&
+      	    ((vma->vm_mm->locked_vm + grow) << PAGE_SHIFT) > current->rlim[RLIMIT_MEMLOCK].rlim_cur) {
+		spin_unlock(&vma->vm_mm->page_table_lock);
+		return -ENOMEM;
+	}
+
+
 	vma->vm_start = address;
 	vma->vm_pgoff -= grow;
 	vma->vm_mm->total_vm += grow;
diff -urN linux-2.4.28-bk7/include/linux/netfilter.h linux-2.4.29/include/linux/netfilter.h
--- linux-2.4.28-bk7/include/linux/netfilter.h	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29/include/linux/netfilter.h	2005-01-19 07:08:14.609705108 -0800
@@ -153,6 +153,7 @@
 extern inline struct arpt_target *
 arpt_find_target_lock(const char *name, int *error, struct semaphore *mutex);
 extern void (*ip_ct_attach)(struct sk_buff *, struct nf_ct_info *);
+extern void nf_ct_attach(struct sk_buff *, struct sk_buff *);
 
 #ifdef CONFIG_NETFILTER_DEBUG
 extern void nf_dump_skb(int pf, struct sk_buff *skb);
@@ -163,6 +164,7 @@
 
 #else /* !CONFIG_NETFILTER */
 #define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb)
+static inline void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb) {}
 #endif /*CONFIG_NETFILTER*/
 
 /* From arch/i386/kernel/smp.c:
diff -urN linux-2.4.28-bk7/include/linux/netfilter_ipv4/ip_conntrack_core.h linux-2.4.29/include/linux/netfilter_ipv4/ip_conntrack_core.h
--- linux-2.4.28-bk7/include/linux/netfilter_ipv4/ip_conntrack_core.h	2003-08-25 04:44:44.000000000 -0700
+++ linux-2.4.29/include/linux/netfilter_ipv4/ip_conntrack_core.h	2005-01-19 07:08:14.609705108 -0800
@@ -25,9 +25,9 @@
 extern struct ip_conntrack *icmp_error_track(struct sk_buff *skb,
 					     enum ip_conntrack_info *ctinfo,
 					     unsigned int hooknum);
-extern int get_tuple(const struct iphdr *iph, size_t len,
-		     struct ip_conntrack_tuple *tuple,
-		     struct ip_conntrack_protocol *protocol);
+extern int ip_ct_get_tuple(const struct iphdr *iph, size_t len,
+                           struct ip_conntrack_tuple *tuple,
+                           struct ip_conntrack_protocol *protocol);
 
 /* Find a connection corresponding to a tuple. */
 struct ip_conntrack_tuple_hash *
diff -urN linux-2.4.28-bk7/include/linux/netfilter_ipv4/ip_nat.h linux-2.4.29/include/linux/netfilter_ipv4/ip_nat.h
--- linux-2.4.28-bk7/include/linux/netfilter_ipv4/ip_nat.h	2004-04-14 06:05:40.000000000 -0700
+++ linux-2.4.29/include/linux/netfilter_ipv4/ip_nat.h	2005-01-19 07:08:14.610705151 -0800
@@ -11,13 +11,8 @@
 	IP_NAT_MANIP_DST
 };
 
-#ifndef CONFIG_IP_NF_NAT_LOCAL
-/* SRC manip occurs only on POST_ROUTING */
-#define HOOK2MANIP(hooknum) ((hooknum) != NF_IP_POST_ROUTING)
-#else
 /* SRC manip occurs POST_ROUTING or LOCAL_IN */
 #define HOOK2MANIP(hooknum) ((hooknum) != NF_IP_POST_ROUTING && (hooknum) != NF_IP_LOCAL_IN)
-#endif
 
 /* 2.3.19 (I hope) will define this in linux/netfilter_ipv4.h. */
 #ifndef SO_ORIGINAL_DST
diff -urN linux-2.4.28-bk7/include/linux/pci_ids.h linux-2.4.29/include/linux/pci_ids.h
--- linux-2.4.28-bk7/include/linux/pci_ids.h	2005-01-19 07:07:43.294348818 -0800
+++ linux-2.4.29/include/linux/pci_ids.h	2005-01-19 07:08:14.612705238 -0800
@@ -303,6 +303,7 @@
 #define PCI_DEVICE_ID_ATI_RADEON_NI	0x4e49
 /* Radeon RV350 (9600) */
 #define PCI_DEVICE_ID_ATI_RADEON_AP	0x4150
+#define PCI_DEVICE_ID_ATI_RADEON_AQ	0x4151
 #define PCI_DEVICE_ID_ATI_RADEON_AR	0x4152
 /* Radeon M6 */
 #define PCI_DEVICE_ID_ATI_RADEON_LY	0x4c59
@@ -760,6 +761,7 @@
 #define PCI_DEVICE_ID_APPLE_UNI_N_AGP_P	0x0027
 #define PCI_DEVICE_ID_APPLE_UNI_N_AGP15	0x002d
 #define PCI_DEVICE_ID_APPLE_UNI_N_FW2	0x0030
+#define PCI_DEVICE_ID_APPLE_UNI_N_GMAC2	0x0032
 #define PCI_DEVICE_ID_APPLE_TIGON3	0x1645
 
 #define PCI_VENDOR_ID_YAMAHA		0x1073
@@ -2063,6 +2065,9 @@
 #define PCI_DEVICE_ID_TIGERJET_300	0x0001
 #define PCI_DEVICE_ID_TIGERJET_100	0x0002
 
+#define PCI_VENDOR_ID_TTTECH		0x0357
+#define PCI_DEVICE_ID_TTTECH_MC322	0x000A
+
 #define PCI_VENDOR_ID_ARK		0xedd8
 #define PCI_DEVICE_ID_ARK_STING		0xa091
 #define PCI_DEVICE_ID_ARK_STINGARK	0xa099
diff -urN linux-2.4.28-bk7/include/linux/proc_fs.h linux-2.4.29/include/linux/proc_fs.h
--- linux-2.4.28-bk7/include/linux/proc_fs.h	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/include/linux/proc_fs.h	2005-01-19 07:08:14.612705238 -0800
@@ -144,6 +144,8 @@
 extern struct proc_dir_entry *proc_mknod(const char *,mode_t,
 		struct proc_dir_entry *,kdev_t);
 extern struct proc_dir_entry *proc_mkdir(const char *,struct proc_dir_entry *);
+extern struct proc_dir_entry *proc_mkdir_mode(const char *name, mode_t mode,
+			struct proc_dir_entry *parent);
 
 static inline struct proc_dir_entry *create_proc_read_entry(const char *name,
 	mode_t mode, struct proc_dir_entry *base, 
diff -urN linux-2.4.28-bk7/include/linux/sctp.h linux-2.4.29/include/linux/sctp.h
--- linux-2.4.28-bk7/include/linux/sctp.h	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/include/linux/sctp.h	2005-01-19 07:08:14.615705368 -0800
@@ -364,7 +364,7 @@
  */
 typedef struct sctp_abort_chunk {
         sctp_chunkhdr_t uh;
-} __attribute__((packed)) sctp_abort_chunkt_t;
+} __attribute__((packed)) sctp_abort_chunk_t;
 
 
 /* For the graceful shutdown we must carry the tag (in common header)
diff -urN linux-2.4.28-bk7/include/linux/socket.h linux-2.4.29/include/linux/socket.h
--- linux-2.4.28-bk7/include/linux/socket.h	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/include/linux/socket.h	2005-01-19 07:08:14.616705411 -0800
@@ -87,6 +87,10 @@
 				  (struct cmsghdr *)(ctl) : \
 				  (struct cmsghdr *)NULL)
 #define CMSG_FIRSTHDR(msg)	__CMSG_FIRSTHDR((msg)->msg_control, (msg)->msg_controllen)
+#define CMSG_OK(mhdr, cmsg) ((cmsg)->cmsg_len >= sizeof(struct cmsghdr) && \
+			     (cmsg)->cmsg_len <= (unsigned long) \
+			     ((mhdr)->msg_controllen - \
+			      ((char *)(cmsg) - (char *)(mhdr)->msg_control)))
 
 /*
  *	This mess will go away with glibc
diff -urN linux-2.4.28-bk7/include/linux/spinlock.h linux-2.4.29/include/linux/spinlock.h
--- linux-2.4.28-bk7/include/linux/spinlock.h	2004-02-18 05:36:32.000000000 -0800
+++ linux-2.4.29/include/linux/spinlock.h	2005-01-19 07:08:14.639706407 -0800
@@ -147,7 +147,7 @@
 
 #define rwlock_init(lock)	do { } while(0)
 #define read_lock(lock)		(void)(lock) /* Not "unused variable". */
-#define read_unlock(lock)	do { } while(0)
+#define read_unlock(lock)	(void)(lock) /* Not "unused variable". */
 #define write_lock(lock)	(void)(lock) /* Not "unused variable". */
 #define write_unlock(lock)	do { } while(0)
 
diff -urN linux-2.4.28-bk7/include/linux/tty.h linux-2.4.29/include/linux/tty.h
--- linux-2.4.28-bk7/include/linux/tty.h	2003-06-13 07:51:39.000000000 -0700
+++ linux-2.4.29/include/linux/tty.h	2005-01-19 07:08:14.641706494 -0800
@@ -260,6 +260,7 @@
 	int	magic;
 	struct tty_driver driver;
 	struct tty_ldisc ldisc;
+	struct semaphore termios_sem;
 	struct termios *termios, *termios_locked;
 	int pgrp;
 	int session;
@@ -322,26 +323,28 @@
  * tty->write.  Thus, you must use the inline functions set_bit() and
  * clear_bit() to make things atomic.
  */
-#define TTY_THROTTLED 0
-#define TTY_IO_ERROR 1
-#define TTY_OTHER_CLOSED 2
-#define TTY_EXCLUSIVE 3
-#define TTY_DEBUG 4
-#define TTY_DO_WRITE_WAKEUP 5
-#define TTY_PUSH 6
-#define TTY_CLOSING 7
-#define TTY_DONT_FLIP 8
-#define TTY_HW_COOK_OUT 14
-#define TTY_HW_COOK_IN 15
-#define TTY_PTY_LOCK 16
-#define TTY_NO_WRITE_SPLIT 17
+#define TTY_THROTTLED 		0	/* Call unthrottle() at threshold min */
+#define TTY_IO_ERROR 		1	/* Canse an I/O error (may be no ldisc too) */
+#define TTY_OTHER_CLOSED 	2	/* Other side (if any) has closed */
+#define TTY_EXCLUSIVE 		3	/* Exclusive open mode */
+#define TTY_DEBUG 		4	/* Debugging */
+#define TTY_DO_WRITE_WAKEUP 	5	/* Call write_wakeup after queuing new */
+#define TTY_PUSH 		6	/* n_tty private */
+#define TTY_CLOSING 		7	/* ->close() in progress */
+#define TTY_DONT_FLIP 		8	/* Defer buffer flip */
+#define TTY_LDISC 		9	/* Line discipline attached */
+#define TTY_HW_COOK_OUT 	14	/* Hardware can do output cooking */
+#define TTY_HW_COOK_IN 	15	/* Hardware can do input cooking */
+#define TTY_PTY_LOCK 		16	/* pty private */
+#define TTY_NO_WRITE_SPLIT 	17	/* Preserve write boundaries to driver */
+#define TTY_HUPPED 		18	/* Post driver->hangup() */
 
 #define TTY_WRITE_FLUSH(tty) tty_write_flush((tty))
 
 extern void tty_write_flush(struct tty_struct *);
 
 extern struct termios tty_std_termios;
-extern struct tty_ldisc ldiscs[];
+extern struct tty_ldisc tty_ldiscs[];
 extern int fg_console, last_console, want_console;
 
 extern int kmsg_redirect;
@@ -396,6 +399,17 @@
 extern void tty_flip_buffer_push(struct tty_struct *tty);
 extern int tty_get_baud_rate(struct tty_struct *tty);
 
+extern struct tty_ldisc *tty_ldisc_ref(struct tty_struct *);
+extern void tty_ldisc_deref(struct tty_ldisc *);
+extern struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *);
+
+extern struct tty_ldisc *tty_ldisc_get(int);
+extern void tty_ldisc_put(int);
+
+extern void tty_wakeup(struct tty_struct *tty);
+extern void tty_ldisc_flush(struct tty_struct *tty);
+
+
 /* n_tty.c */
 extern struct tty_ldisc tty_ldisc_N_TTY;
 
diff -urN linux-2.4.28-bk7/include/linux/tty_ldisc.h linux-2.4.29/include/linux/tty_ldisc.h
--- linux-2.4.28-bk7/include/linux/tty_ldisc.h	2001-11-22 11:46:19.000000000 -0800
+++ linux-2.4.29/include/linux/tty_ldisc.h	2005-01-19 07:08:14.642706537 -0800
@@ -95,6 +95,13 @@
  * 	that line discpline should try to send more characters to the
  * 	low-level driver for transmission.  If the line discpline does
  * 	not have any more data to send, it can just return.
+ *
+ * int (*hangup)(struct tty_struct *)
+ *
+ *	Called on a hangup. Tells the discipline that it should
+ *	cease I/O to the tty driver. Can sleep. The driver should
+ *	seek to perform this action quickly but should wait until
+ *	any pending driver I/O is completed.
  */
 
 #include <linux/fs.h>
@@ -121,6 +128,7 @@
 	void	(*set_termios)(struct tty_struct *tty, struct termios * old);
 	unsigned int (*poll)(struct tty_struct *, struct file *,
 			     struct poll_table_struct *);
+	int     (*hangup)(struct tty_struct *tty);
 	
 	/*
 	 * The following routines are called from below.
@@ -129,6 +137,7 @@
 			       char *fp, int count);
 	int	(*receive_room)(struct tty_struct *);
 	void	(*write_wakeup)(struct tty_struct *);
+	int	refcount;
 };
 
 #define TTY_LDISC_MAGIC	0x5403
diff -urN linux-2.4.28-bk7/include/linux/usb_ch9.h linux-2.4.29/include/linux/usb_ch9.h
--- linux-2.4.28-bk7/include/linux/usb_ch9.h	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29/include/linux/usb_ch9.h	2005-01-19 07:08:14.643706580 -0800
@@ -79,6 +79,7 @@
 #define USB_DEVICE_B_HNP_ENABLE		3	/* dev may initiate HNP */
 #define USB_DEVICE_A_HNP_SUPPORT	4	/* RH port supports HNP */
 #define USB_DEVICE_A_ALT_HNP_SUPPORT	5	/* other RH port does */
+#define USB_DEVICE_DEBUG_MODE		6	/* (special devices only) */
 
 #define USB_ENDPOINT_HALT		0	/* IN/OUT will STALL */
 
@@ -323,6 +324,18 @@
 
 /*-------------------------------------------------------------------------*/
 
+/* USB_DT_DEBUG:  for special highspeed devices, replacing serial console */
+struct usb_debug_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+
+	/* bulk endpoints with 8 byte maxpacket */
+	__u8  bDebugInEndpoint;
+	__u8  bDebugOutEndpoint;
+};
+
+/*-------------------------------------------------------------------------*/
+
 /* USB_DT_INTERFACE_ASSOCIATION: groups interfaces */
 struct usb_interface_assoc_descriptor {
 	__u8  bLength;
diff -urN linux-2.4.28-bk7/include/linux/usb_gadget.h linux-2.4.29/include/linux/usb_gadget.h
--- linux-2.4.28-bk7/include/linux/usb_gadget.h	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29/include/linux/usb_gadget.h	2005-01-19 07:08:14.644706624 -0800
@@ -6,7 +6,7 @@
  * master many USB gadgets, but the gadgets are only slaved to one host.
  *
  *
- * (c) Copyright 2002-2003 by David Brownell
+ * (C) Copyright 2002-2004 by David Brownell
  * All Rights Reserved.
  *
  * This software is licensed under the GNU GPL version 2.
@@ -73,8 +73,6 @@
  */
 	// NOTE this is analagous to 'struct urb' on the host side,
 	// except that it's thinner and promotes more pre-allocation.
-	//
-	// ISSUE should this be allocated through the device?
 
 struct usb_request {
 	void			*buf;
@@ -116,8 +114,8 @@
 		dma_addr_t *dma, int gfp_flags);
 	void (*free_buffer) (struct usb_ep *ep, void *buf, dma_addr_t dma,
 		unsigned bytes);
-	// NOTE:  on 2.5, drivers may also use dma_map() and
-	// dma_sync_single() to manage dma overhead. 
+	// NOTE:  on 2.6, drivers may also use dma_map() and
+	// dma_sync_single_*() to directly manage dma overhead. 
 
 	int (*queue) (struct usb_ep *ep, struct usb_request *req,
 		int gfp_flags);
@@ -453,7 +451,10 @@
 struct usb_gadget_ops {
 	int	(*get_frame)(struct usb_gadget *);
 	int	(*wakeup)(struct usb_gadget *);
-	int	(*set_selfpowered) (struct usb_gadget *, int value);
+	int	(*set_selfpowered) (struct usb_gadget *, int is_selfpowered);
+	int	(*vbus_session) (struct usb_gadget *, int is_active);
+	int	(*vbus_draw) (struct usb_gadget *, unsigned mA);
+	int	(*pullup) (struct usb_gadget *, int is_on);
 	int	(*ioctl)(struct usb_gadget *,
 				unsigned code, unsigned long param);
 };
@@ -467,6 +468,17 @@
  * @speed: Speed of current connection to USB host.
  * @is_dualspeed: True if the controller supports both high and full speed
  *	operation.  If it does, the gadget driver must also support both.
+ * @is_otg: True if the USB device port uses a Mini-AB jack, so that the
+ *	gadget driver must provide a USB OTG descriptor.
+ * @is_a_peripheral: False unless is_otg, the "A" end of a USB cable
+ *	is in the Mini-AB jack, and HNP has been used to switch roles
+ *	so that the "A" device currently acts as A-Peripheral, not A-Host.
+ * @a_hnp_support: OTG device feature flag, indicating that the A-Host
+ *	supports HNP at this port.
+ * @a_alt_hnp_support: OTG device feature flag, indicating that the A-Host
+ *	only supports HNP on a different root port.
+ * @b_hnp_enable: OTG device feature flag, indicating that the A-Host
+ *	enabled HNP support.
  * @name: Identifies the controller hardware type.  Used in diagnostics
  * 	and sometimes configuration.
  * @dev: Driver model state for this abstract device.
@@ -480,9 +492,14 @@
  *
  * Except for the driver data, all fields in this structure are
  * read-only to the gadget driver.  That driver data is part of the
- * "driver model" infrastructure in 2.5 (and later) kernels, and for
+ * "driver model" infrastructure in 2.6 (and later) kernels, and for
  * earlier systems is grouped in a similar structure that's not known
  * to the rest of the kernel.
+ *
+ * Values of the three OTG device feature flags are updated before the
+ * setup() call corresponding to USB_REQ_SET_CONFIGURATION, and before
+ * driver suspend() calls.  They are valid only when is_otg, and when the
+ * device is acting as a B-Peripheral (so is_a_peripheral is false).
  */
 struct usb_gadget {
 	/* readonly to gadget driver */
@@ -491,6 +508,11 @@
 	struct list_head		ep_list;	/* of usb_ep */
 	enum usb_device_speed		speed;
 	unsigned			is_dualspeed:1;
+	unsigned			is_otg:1;
+	unsigned			is_a_peripheral:1;
+	unsigned			b_hnp_enable:1;
+	unsigned			a_hnp_support:1;
+	unsigned			a_alt_hnp_support:1;
 	const char			*name;
 
 	struct __gadget_device {
@@ -540,6 +562,10 @@
  * doesn't support such attempts, or its support has not been enabled
  * by the usb host.  Drivers must return device descriptors that report
  * their ability to support this, or hosts won't enable it.
+ *
+ * This may also try to use SRP to wake the host and start enumeration,
+ * even if OTG isn't otherwise in use.  OTG devices may also start
+ * remote wakeup even when hosts don't explicitly enable it.
  */
 static inline int usb_gadget_wakeup (struct usb_gadget *gadget)
 {
@@ -583,6 +609,107 @@
 	return gadget->ops->set_selfpowered (gadget, 0);
 }
 
+/**
+ * usb_gadget_vbus_connect - Notify controller that VBUS is powered
+ * @gadget:The device which now has VBUS power.
+ *
+ * This call is used by a driver for an external transceiver (or GPIO)
+ * that detects a VBUS power session starting.  Common responses include
+ * resuming the controller, activating the D+ (or D-) pullup to let the
+ * host detect that a USB device is attached, and starting to draw power
+ * (8mA or possibly more, especially after SET_CONFIGURATION).
+ *
+ * Returns zero on success, else negative errno.
+ */
+static inline int
+usb_gadget_vbus_connect(struct usb_gadget *gadget)
+{
+	if (!gadget->ops->vbus_session)
+		return -EOPNOTSUPP;
+	return gadget->ops->vbus_session (gadget, 1);
+}
+
+/**
+ * usb_gadget_vbus_draw - constrain controller's VBUS power usage
+ * @gadget:The device whose VBUS usage is being described
+ * @mA:How much current to draw, in milliAmperes.  This should be twice
+ *	the value listed in the configuration descriptor bMaxPower field.
+ *
+ * This call is used by gadget drivers during SET_CONFIGURATION calls,
+ * reporting how much power the device may consume.  For example, this
+ * could affect how quickly batteries are recharged.
+ *
+ * Returns zero on success, else negative errno.
+ */
+static inline int
+usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA)
+{
+	if (!gadget->ops->vbus_draw)
+		return -EOPNOTSUPP;
+	return gadget->ops->vbus_draw (gadget, mA);
+}
+
+/**
+ * usb_gadget_vbus_disconnect - notify controller about VBUS session end
+ * @gadget:the device whose VBUS supply is being described
+ *
+ * This call is used by a driver for an external transceiver (or GPIO)
+ * that detects a VBUS power session ending.  Common responses include
+ * reversing everything done in usb_gadget_vbus_connect().
+ *
+ * Returns zero on success, else negative errno.
+ */
+static inline int
+usb_gadget_vbus_disconnect(struct usb_gadget *gadget)
+{
+	if (!gadget->ops->vbus_session)
+		return -EOPNOTSUPP;
+	return gadget->ops->vbus_session (gadget, 0);
+}
+
+/**
+ * usb_gadget_connect - software-controlled connect to USB host
+ * @gadget:the peripheral being connected
+ *
+ * Enables the D+ (or potentially D-) pullup.  The host will start
+ * enumerating this gadget when the pullup is active and a VBUS session
+ * is active (the link is powered).  This pullup is always enabled unless
+ * usb_gadget_disconnect() has been used to disable it.
+ *
+ * Returns zero on success, else negative errno.
+ */
+static inline int
+usb_gadget_connect (struct usb_gadget *gadget)
+{
+	if (!gadget->ops->pullup)
+		return -EOPNOTSUPP;
+	return gadget->ops->pullup (gadget, 1);
+}
+
+/**
+ * usb_gadget_disconnect - software-controlled disconnect from USB host
+ * @gadget:the peripheral being disconnected
+ *
+ * Disables the D+ (or potentially D-) pullup, which the host may see
+ * as a disconnect (when a VBUS session is active).  Not all systems
+ * support software pullup controls.
+ *
+ * This routine may be used during the gadget driver bind() call to prevent
+ * the peripheral from ever being visible to the USB host, unless later
+ * usb_gadget_connect() is called.  For example, user mode components may
+ * need to be activated before the system can talk to hosts.
+ *
+ * Returns zero on success, else negative errno.
+ */
+static inline int
+usb_gadget_disconnect (struct usb_gadget *gadget)
+{
+	if (!gadget->ops->pullup)
+		return -EOPNOTSUPP;
+	return gadget->ops->pullup (gadget, 0);
+}
+
+
 
 /*-------------------------------------------------------------------------*/
 
@@ -610,11 +737,18 @@
  * 	Called in a context that permits sleeping.
  * @suspend: Invoked on USB suspend.  May be called in_interrupt.
  * @resume: Invoked on USB resume.  May be called in_interrupt.
+ * @driver: Driver model state for this driver.
  *
  * Devices are disabled till a gadget driver successfully bind()s, which
  * means the driver will handle setup() requests needed to enumerate (and
  * meet "chapter 9" requirements) then do some useful work.
  *
+ * If gadget->is_otg is true, the gadget driver must provide an OTG
+ * descriptor during enumeration, or else fail the bind() call.  In such
+ * cases, no USB traffic may flow until both bind() returns without
+ * having called usb_gadget_disconnect(), and the USB host stack has
+ * initialized.
+ *
  * Drivers use hardware-specific knowledge to configure the usb hardware.
  * endpoint addressing is only one of several hardware characteristics that
  * are in descriptors the ep0 implementation returns from setup() calls.
diff -urN linux-2.4.28-bk7/include/net/inet_ecn.h linux-2.4.29/include/net/inet_ecn.h
--- linux-2.4.28-bk7/include/net/inet_ecn.h	2001-10-30 15:08:12.000000000 -0800
+++ linux-2.4.29/include/net/inet_ecn.h	2005-01-19 07:08:14.644706624 -0800
@@ -1,6 +1,14 @@
 #ifndef _INET_ECN_H_
 #define _INET_ECN_H_
 
+enum {
+	INET_ECN_NOT_ECT = 0,
+	INET_ECN_ECT_1 = 1,
+	INET_ECN_ECT_0 = 2,
+	INET_ECN_CE = 3,
+	INET_ECN_MASK = 3,
+};
+
 static inline int INET_ECN_is_ce(__u8 dsfield)
 {
 	return (dsfield&3) == 3;
diff -urN linux-2.4.28-bk7/include/net/ip.h linux-2.4.29/include/net/ip.h
--- linux-2.4.28-bk7/include/net/ip.h	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/include/net/ip.h	2005-01-19 07:08:14.645706667 -0800
@@ -102,7 +102,8 @@
 				      int getfrag (const void *,
 						   char *,
 						   unsigned int,
-						   unsigned int),
+						   unsigned int,
+						   struct sk_buff *),
 				      const void *frag,
 				      unsigned length,
 				      struct ipcm_cookie *ipc,
diff -urN linux-2.4.28-bk7/include/net/ip_vs.h linux-2.4.29/include/net/ip_vs.h
--- linux-2.4.28-bk7/include/net/ip_vs.h	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/include/net/ip_vs.h	2005-01-19 07:08:14.646706710 -0800
@@ -97,6 +97,7 @@
 	int             state;          /* sync daemon state */
 	char            mcast_ifn[IP_VS_IFNAME_MAXLEN];
 					/* multicast interface name */
+	int		syncid;
 
 	/* virtual service options */
 	u_int16_t	protocol;
@@ -213,8 +214,9 @@
 
 /* The argument to IP_VS_SO_GET_DAEMON */
 struct ip_vs_daemon_user {
-	int	state;				/* sync daemon state */
-	char	mcast_ifn[IP_VS_IFNAME_MAXLEN];	/* multicast interface name */
+	int	state;					/* sync daemon state */
+	char	mcast_master_ifn[IP_VS_IFNAME_MAXLEN];	/* mcast master interface name */
+	char	mcast_backup_ifn[IP_VS_IFNAME_MAXLEN];	/* mcast backup interface name */
 };
 
 
@@ -317,6 +319,7 @@
 	NET_IPV4_VS_EXPIRE_NODEST_CONN=23,
 	NET_IPV4_VS_SYNC_THRESHOLD=24,
 	NET_IPV4_VS_NAT_ICMP_SEND=25,
+	NET_IPV4_VS_EXPIRE_QUIESCENT_TEMPLATE=26,
 	NET_IPV4_VS_LAST
 };
 
@@ -700,6 +703,7 @@
  */
 extern int sysctl_ip_vs_cache_bypass;
 extern int sysctl_ip_vs_expire_nodest_conn;
+extern int sysctl_ip_vs_expire_quiescent_template;
 extern int sysctl_ip_vs_sync_threshold;
 extern int sysctl_ip_vs_nat_icmp_send;
 extern struct ip_vs_stats ip_vs_stats;
@@ -724,9 +728,10 @@
  *      (from ip_vs_sync.c)
  */
 extern volatile int ip_vs_sync_state;
-extern char ip_vs_mcast_ifn[IP_VS_IFNAME_MAXLEN];
-extern int start_sync_thread(int state, char *mcast_ifn);
-extern int stop_sync_thread(void);
+extern char ip_vs_mcast_master_ifn[IP_VS_IFNAME_MAXLEN];
+extern char ip_vs_mcast_backup_ifn[IP_VS_IFNAME_MAXLEN];
+extern int start_sync_thread(int state, char *mcast_ifn, __u8 syncid);
+extern int stop_sync_thread(int state);
 extern void ip_vs_sync_conn(struct ip_vs_conn *cp);
 
 
diff -urN linux-2.4.28-bk7/include/net/sctp/command.h linux-2.4.29/include/net/sctp/command.h
--- linux-2.4.28-bk7/include/net/sctp/command.h	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/include/net/sctp/command.h	2005-01-19 07:08:14.647706754 -0800
@@ -189,11 +189,6 @@
 } sctp_cmd_seq_t;
 
 
-/* Create a new sctp_command_sequence.
- * Return NULL if creating a new sequence fails.
- */
-sctp_cmd_seq_t *sctp_new_cmd_seq(int gfp);
-
 /* Initialize a block of memory as a command sequence.
  * Return 0 if the initialization fails.
  */
@@ -207,18 +202,10 @@
  */
 int sctp_add_cmd(sctp_cmd_seq_t *seq, sctp_verb_t verb, sctp_arg_t obj);
 
-/* Rewind an sctp_cmd_seq_t to iterate from the start.
- * Return 0 if the rewind fails.
- */
-int sctp_rewind_sequence(sctp_cmd_seq_t *seq);
-
 /* Return the next command structure in an sctp_cmd_seq.
  * Return NULL at the end of the sequence.
  */
 sctp_cmd_t *sctp_next_cmd(sctp_cmd_seq_t *seq);
 
-/* Dispose of a command sequence.  */
-void sctp_free_cmd_seq(sctp_cmd_seq_t *seq);
-
 #endif /* __net_sctp_command_h__ */
 
diff -urN linux-2.4.28-bk7/include/net/sctp/compat.h linux-2.4.29/include/net/sctp/compat.h
--- linux-2.4.28-bk7/include/net/sctp/compat.h	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/include/net/sctp/compat.h	2005-01-19 07:08:14.647706754 -0800
@@ -64,37 +64,6 @@
 #define __unsafe(x)
 #define dst_pmtu(x) ((x)->pmtu)
 
-#define sk_family family
-#define sk_state state
-#define sk_type type
-#define sk_socket socket
-#define sk_prot prot
-#define sk_rcvbuf rcvbuf
-#define sk_sndbuf sndbuf
-#define sk_ack_backlog ack_backlog
-#define sk_max_ack_backlog max_ack_backlog
-#define sk_write_space write_space
-#define sk_use_write_queue use_write_queue
-#define sk_err err
-#define sk_err_soft err_soft
-#define sk_error_report error_report
-#define sk_error_queue error_queue
-#define sk_shutdown shutdown
-#define sk_state_change state_change
-#define sk_receive_queue receive_queue
-#define sk_data_ready data_ready
-#define sk_no_check no_check
-#define sk_reuse reuse
-#define sk_destruct destruct
-#define sk_zapped zapped
-#define sk_protocol protocol
-#define sk_backlog_rcv backlog_rcv
-#define sk_allocation allocation
-#define sk_lingertime lingertime
-#define sk_sleep sleep
-#define sk_wmem_queued wmem_queued
-#define sk_bound_dev_if bound_dev_if
-
 /*
  * find last bit set.
  */
diff -urN linux-2.4.28-bk7/include/net/sctp/constants.h linux-2.4.29/include/net/sctp/constants.h
--- linux-2.4.28-bk7/include/net/sctp/constants.h	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/include/net/sctp/constants.h	2005-01-19 07:08:14.648706797 -0800
@@ -105,9 +105,10 @@
 
 typedef enum {
 	SCTP_EVENT_NO_PENDING_TSN = 0,
+	SCTP_EVENT_ICMP_PROTO_UNREACH,
 } sctp_event_other_t;
 
-#define SCTP_EVENT_OTHER_MAX		SCTP_EVENT_NO_PENDING_TSN
+#define SCTP_EVENT_OTHER_MAX		SCTP_EVENT_ICMP_PROTO_UNREACH
 #define SCTP_NUM_OTHER_TYPES		(SCTP_EVENT_OTHER_MAX + 1)
 
 /* These are primitive requests from the ULP.  */
@@ -155,10 +156,6 @@
 		       		- (unsigned long)(c->chunk_hdr)\
 				- sizeof(sctp_data_chunk_t)))
 
-/* This is a table of printable names of sctp_param_t's.  */
-extern const char *sctp_param_tbl[];
-
-
 #define SCTP_MAX_ERROR_CAUSE  SCTP_ERROR_NONEXIST_IP
 #define SCTP_NUM_ERROR_CAUSE  10
 
@@ -179,6 +176,7 @@
 	SCTP_IERROR_IGNORE_TSN,
 	SCTP_IERROR_NO_DATA,
 	SCTP_IERROR_BAD_STREAM,
+	SCTP_IERROR_BAD_PORTS,
 
 } sctp_ierror_t;
 
diff -urN linux-2.4.28-bk7/include/net/sctp/sctp.h linux-2.4.29/include/net/sctp/sctp.h
--- linux-2.4.28-bk7/include/net/sctp/sctp.h	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29/include/net/sctp/sctp.h	2005-01-19 07:08:14.648706797 -0800
@@ -166,17 +166,9 @@
 int sctp_rcv(struct sk_buff *skb);
 void sctp_v4_err(struct sk_buff *skb, u32 info);
 void sctp_hash_established(struct sctp_association *);
-void __sctp_hash_established(struct sctp_association *);
 void sctp_unhash_established(struct sctp_association *);
-void __sctp_unhash_established(struct sctp_association *);
 void sctp_hash_endpoint(struct sctp_endpoint *);
-void __sctp_hash_endpoint(struct sctp_endpoint *);
 void sctp_unhash_endpoint(struct sctp_endpoint *);
-void __sctp_unhash_endpoint(struct sctp_endpoint *);
-struct sctp_association *__sctp_lookup_association(
-	const union sctp_addr *,
-	const union sctp_addr *,
-	struct sctp_transport **);
 struct sock *sctp_err_lookup(int family, struct sk_buff *,
 			     struct sctphdr *, struct sctp_endpoint **,
 			     struct sctp_association **,
@@ -185,6 +177,10 @@
 			    struct sctp_association *);
 void sctp_icmp_frag_needed(struct sock *, struct sctp_association *,
 			   struct sctp_transport *t, __u32 pmtu);
+void sctp_icmp_proto_unreachable(struct sock *sk,
+				 struct sctp_endpoint *ep,
+				 struct sctp_association *asoc,
+				 struct sctp_transport *t);
 
 /*
  *  Section:  Macros, externs, and inlines
@@ -332,8 +328,6 @@
 
 int sctp_v6_init(void);
 void sctp_v6_exit(void);
-void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
-			int type, int code, int offset, __u32 info);
 
 #else /* #ifdef defined(CONFIG_IPV6) */
 
@@ -477,7 +471,8 @@
 #define _sctp_walk_params(pos, chunk, end, member)\
 for (pos.v = chunk->member;\
      pos.v <= (void *)chunk + end - sizeof(sctp_paramhdr_t) &&\
-     pos.v <= (void *)chunk + end - WORD_ROUND(ntohs(pos.p->length)); \
+     pos.v <= (void *)chunk + end - WORD_ROUND(ntohs(pos.p->length)) &&\
+     ntohs(pos.p->length) >= sizeof(sctp_paramhdr_t);\
      pos.v += WORD_ROUND(ntohs(pos.p->length)))
 
 #define sctp_walk_errors(err, chunk_hdr)\
@@ -487,10 +482,9 @@
 for (err = (sctp_errhdr_t *)((void *)chunk_hdr + \
 	    sizeof(sctp_chunkhdr_t));\
      (void *)err <= (void *)chunk_hdr + end - sizeof(sctp_errhdr_t) &&\
-     (void *)err <= (void *)chunk_hdr + end - \
-		    WORD_ROUND(ntohs(err->length));\
-     err = (sctp_errhdr_t *)((void *)err + \
-	    WORD_ROUND(ntohs(err->length))))
+     (void *)err <= (void *)chunk_hdr + end - WORD_ROUND(ntohs(err->length)) &&\
+     ntohs(err->length) >= sizeof(sctp_errhdr_t); \
+     err = (sctp_errhdr_t *)((void *)err + WORD_ROUND(ntohs(err->length))))
 
 #define sctp_walk_fwdtsn(pos, chunk)\
 _sctp_walk_fwdtsn((pos), (chunk), ntohs((chunk)->chunk_hdr->length) - sizeof(struct sctp_fwdtsn_chunk))
@@ -622,7 +616,7 @@
 #define sctp_sstate(sk, state) __sctp_sstate((sk), (SCTP_SS_##state))
 int static inline __sctp_sstate(const struct sock *sk, sctp_sock_state_t state)
 {
-	return sk->sk_state == state;
+	return sk->state == state;
 }
 
 /* Map v4-mapped v6 address back to v4 address */
diff -urN linux-2.4.28-bk7/include/net/sctp/sm.h linux-2.4.29/include/net/sctp/sm.h
--- linux-2.4.28-bk7/include/net/sctp/sm.h	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/include/net/sctp/sm.h	2005-01-19 07:08:14.649706840 -0800
@@ -128,9 +128,9 @@
 sctp_state_fn_t sctp_sf_do_ecn_cwr;
 sctp_state_fn_t sctp_sf_do_ecne;
 sctp_state_fn_t sctp_sf_ootb;
-sctp_state_fn_t sctp_sf_shut_8_4_5;
 sctp_state_fn_t sctp_sf_pdiscard;
 sctp_state_fn_t sctp_sf_violation;
+sctp_state_fn_t sctp_sf_violation_chunklen;
 sctp_state_fn_t sctp_sf_discard_chunk;
 sctp_state_fn_t sctp_sf_do_5_2_1_siminit;
 sctp_state_fn_t sctp_sf_do_5_2_2_dupinit;
@@ -138,7 +138,6 @@
 sctp_state_fn_t sctp_sf_unk_chunk;
 sctp_state_fn_t sctp_sf_do_8_5_1_E_sa;
 sctp_state_fn_t sctp_sf_cookie_echoed_err;
-sctp_state_fn_t sctp_sf_do_5_2_6_stale;
 sctp_state_fn_t sctp_sf_do_asconf;
 sctp_state_fn_t sctp_sf_do_asconf_ack;
 sctp_state_fn_t sctp_sf_do_9_2_reshutack;
@@ -167,6 +166,7 @@
 sctp_state_fn_t sctp_sf_do_9_2_start_shutdown;
 sctp_state_fn_t sctp_sf_do_9_2_shutdown_ack;
 sctp_state_fn_t sctp_sf_ignore_other;
+sctp_state_fn_t sctp_sf_cookie_wait_icmp_abort;
 
 /* Prototypes for timeout event state functions.  */
 sctp_state_fn_t sctp_sf_do_6_3_3_rtx;
@@ -200,19 +200,10 @@
 struct sctp_chunk *sctp_make_cwr(const struct sctp_association *,
 				 const __u32 lowest_tsn,
 				 const struct sctp_chunk *);
-struct sctp_chunk *sctp_make_datafrag(struct sctp_association *,
-				 const struct sctp_sndrcvinfo *sinfo,
-				 int len, const __u8 *data,
-				 __u8 flags, __u16 ssn);
 struct sctp_chunk * sctp_make_datafrag_empty(struct sctp_association *,
 					const struct sctp_sndrcvinfo *sinfo,
 					int len, const __u8 flags,
 					__u16 ssn);
-struct sctp_chunk *sctp_make_data(struct sctp_association *,
-			     const struct sctp_sndrcvinfo *sinfo,
-			     int len, const __u8 *data);
-struct sctp_chunk *sctp_make_data_empty(struct sctp_association *,
-				   const struct sctp_sndrcvinfo *, int len);
 struct sctp_chunk *sctp_make_ecne(const struct sctp_association *,
 				  const __u32);
 struct sctp_chunk *sctp_make_sack(const struct sctp_association *);
@@ -232,6 +223,10 @@
 struct sctp_chunk *sctp_make_abort_user(const struct sctp_association *,
 				   const struct sctp_chunk *,
 				   const struct msghdr *);
+struct sctp_chunk *sctp_make_abort_violation(const struct sctp_association *,
+				   const struct sctp_chunk *,
+				   const __u8 *,
+				   const size_t );
 struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *,
 				  const struct sctp_transport *,
 				  const void *payload,
@@ -246,17 +241,12 @@
 				 const void *payload,
 				 size_t paylen);
 
-struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc,
-				    union sctp_addr *addr,
-				    int vparam_len);
 struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *,
 					      union sctp_addr *,
 					      struct sockaddr *,
 					      int, __u16);
 struct sctp_chunk *sctp_make_asconf_set_prim(struct sctp_association *asoc,
 					     union sctp_addr *addr);
-struct sctp_chunk *sctp_make_asconf_ack(const struct sctp_association *asoc,
-					__u32 serial, int vparam_len);
 struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
 				       struct sctp_chunk *asconf);
 int sctp_process_asconf_ack(struct sctp_association *asoc,
@@ -268,6 +258,8 @@
 void sctp_chunk_assign_tsn(struct sctp_chunk *);
 void sctp_chunk_assign_ssn(struct sctp_chunk *);
 
+void sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands, __u16 error);
+
 /* Prototypes for statetable processing. */
 
 int sctp_do_sm(sctp_event_t event_type, sctp_subtype_t subtype,
@@ -277,71 +269,26 @@
                void *event_arg,
                int gfp);
 
-int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype,
-		      sctp_state_t state,
-                      struct sctp_endpoint *,
-                      struct sctp_association *asoc,
-                      void *event_arg,
-                      sctp_disposition_t status,
-		      sctp_cmd_seq_t *commands,
-                      int gfp);
-
 /* 2nd level prototypes */
-int sctp_cmd_interpreter(sctp_event_t, sctp_subtype_t, sctp_state_t,
-			 struct sctp_endpoint *, struct sctp_association *,
-			 void *event_arg, sctp_disposition_t,
-			 sctp_cmd_seq_t *retval, int gfp);
-
-
-int sctp_gen_sack(struct sctp_association *, int force, sctp_cmd_seq_t *);
 void sctp_generate_t3_rtx_event(unsigned long peer);
 void sctp_generate_heartbeat_event(unsigned long peer);
 
-sctp_sackhdr_t *sctp_sm_pull_sack(struct sctp_chunk *);
-struct sctp_packet *sctp_abort_pkt_new(const struct sctp_endpoint *,
-				       const struct sctp_association *,
-				       struct sctp_chunk *chunk,
-				       const void *payload,
-				       size_t paylen);
-struct sctp_packet *sctp_ootb_pkt_new(const struct sctp_association *,
-				      const struct sctp_chunk *);
 void sctp_ootb_pkt_free(struct sctp_packet *);
 
-struct sctp_cookie_param *
-sctp_pack_cookie(const struct sctp_endpoint *, const struct sctp_association *,
-		 const struct sctp_chunk *, int *cookie_len,
-		 const __u8 *, int addrs_len);
 struct sctp_association *sctp_unpack_cookie(const struct sctp_endpoint *,
 				       const struct sctp_association *,
 				       struct sctp_chunk *, int gfp, int *err,
 				       struct sctp_chunk **err_chk_p);
 int sctp_addip_addr_config(struct sctp_association *, sctp_param_t,
 			   struct sockaddr_storage*, int);
-void sctp_send_stale_cookie_err(const struct sctp_endpoint *ep,
-				const struct sctp_association *asoc,
-				const struct sctp_chunk *chunk,
-				sctp_cmd_seq_t *commands,
-				struct sctp_chunk *err_chunk);
-int sctp_eat_data(const struct sctp_association *asoc,
-		  struct sctp_chunk *chunk,
-		  sctp_cmd_seq_t *commands);
 
 /* 3rd level prototypes */
 __u32 sctp_generate_tag(const struct sctp_endpoint *);
 __u32 sctp_generate_tsn(const struct sctp_endpoint *);
 
 /* Extern declarations for major data structures.  */
-const sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t, sctp_state_t);
-extern const sctp_sm_table_entry_t
-primitive_event_table[SCTP_NUM_PRIMITIVE_TYPES][SCTP_STATE_NUM_STATES];
-extern const sctp_sm_table_entry_t
-other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_STATE_NUM_STATES];
-extern const sctp_sm_table_entry_t
-timeout_event_table[SCTP_NUM_TIMEOUT_TYPES][SCTP_STATE_NUM_STATES];
 extern sctp_timer_event_t *sctp_timer_events[SCTP_NUM_TIMEOUT_TYPES];
 
-/* These are some handy utility macros... */
-
 
 /* Get the size of a DATA chunk payload. */
 static inline __u16 sctp_data_size(struct sctp_chunk *chunk)
diff -urN linux-2.4.28-bk7/include/net/sctp/structs.h linux-2.4.29/include/net/sctp/structs.h
--- linux-2.4.28-bk7/include/net/sctp/structs.h	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/include/net/sctp/structs.h	2005-01-19 07:08:14.651706927 -0800
@@ -322,10 +322,19 @@
 	/* This holds the originating address of the INIT packet.  */
 	union sctp_addr peer_addr;
 
+	/* IG Section 2.35.3 
+	 * Include the source port of the INIT-ACK
+	 */
+	__u16		my_port;
+
 	__u8 prsctp_capable;
 
+	/* Padding for future use */
+	__u8 padding;  		
+
 	__u32 adaption_ind;	
 
+
 	/* This is a shim for my peer's INIT packet, followed by
 	 * a copy of the raw address list of the association.
 	 * The length of the raw address list is saved in the
@@ -406,7 +415,6 @@
 	int malloced;
 };
 
-struct sctp_ssnmap *sctp_ssnmap_init(struct sctp_ssnmap *, __u16, __u16);
 struct sctp_ssnmap *sctp_ssnmap_new(__u16 in, __u16 out, int gfp);
 void sctp_ssnmap_free(struct sctp_ssnmap *map);
 void sctp_ssnmap_clear(struct sctp_ssnmap *map);
@@ -538,12 +546,9 @@
 struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *,
 					    struct sctp_sndrcvinfo *,
 					    struct msghdr *, int len);
-struct sctp_datamsg *sctp_datamsg_new(int gfp);
 void sctp_datamsg_put(struct sctp_datamsg *);
-void sctp_datamsg_hold(struct sctp_datamsg *);
 void sctp_datamsg_free(struct sctp_datamsg *);
 void sctp_datamsg_track(struct sctp_chunk *);
-void sctp_datamsg_assign(struct sctp_datamsg *, struct sctp_chunk *);
 void sctp_chunk_fail(struct sctp_chunk *, int error);
 int sctp_chunk_abandoned(struct sctp_chunk *);
 
@@ -651,8 +656,6 @@
 void sctp_chunk_put(struct sctp_chunk *);
 int sctp_user_addto_chunk(struct sctp_chunk *chunk, int off, int len,
 			  struct iovec *data);
-struct sctp_chunk *sctp_make_chunk(const struct sctp_association *, __u8 type,
-				   __u8 flags, int size);
 void sctp_chunk_free(struct sctp_chunk *);
 void  *sctp_addto_chunk(struct sctp_chunk *, int len, const void *data);
 struct sctp_chunk *sctp_chunkify(struct sk_buff *,
@@ -853,12 +856,6 @@
 	/* Error count : The current error count for this destination.	*/
 	unsigned short error_count;
 
-	/* Error       : Current error threshold for this destination
-	 * Threshold   : i.e. what value marks the destination down if
-	 *	       : errorCount reaches this value.
-	 */
-	unsigned short error_threshold;
-
 	/* This is the max_retrans value for the transport and will
 	 * be initialized to proto.max_retrans.path.  This can be changed
 	 * using SCTP_SET_PEER_ADDR_PARAMS socket option.
@@ -922,15 +919,12 @@
 };
 
 struct sctp_transport *sctp_transport_new(const union sctp_addr *, int);
-struct sctp_transport *sctp_transport_init(struct sctp_transport *,
-					   const union sctp_addr *, int);
 void sctp_transport_set_owner(struct sctp_transport *,
 			      struct sctp_association *);
 void sctp_transport_route(struct sctp_transport *, union sctp_addr *,
 			  struct sctp_opt *);
 void sctp_transport_pmtu(struct sctp_transport *);
 void sctp_transport_free(struct sctp_transport *);
-void sctp_transport_destroy(struct sctp_transport *);
 void sctp_transport_reset_timers(struct sctp_transport *);
 void sctp_transport_hold(struct sctp_transport *);
 void sctp_transport_put(struct sctp_transport *);
@@ -961,7 +955,6 @@
 	int malloced;	     /* Is this structure kfree()able?	*/
 };
 
-struct sctp_inq *sctp_inq_new(void);
 void sctp_inq_init(struct sctp_inq *);
 void sctp_inq_free(struct sctp_inq *);
 void sctp_inq_push(struct sctp_inq *, struct sctp_chunk *packet);
@@ -1029,7 +1022,6 @@
 	char malloced;
 };
 
-struct sctp_outq *sctp_outq_new(struct sctp_association *);
 void sctp_outq_init(struct sctp_association *, struct sctp_outq *);
 void sctp_outq_teardown(struct sctp_outq *);
 void sctp_outq_free(struct sctp_outq*);
@@ -1070,7 +1062,6 @@
 	int malloced;	     /* Are we kfree()able?  */
 };
 
-struct sctp_bind_addr *sctp_bind_addr_new(int gfp_mask);
 void sctp_bind_addr_init(struct sctp_bind_addr *, __u16 port);
 void sctp_bind_addr_free(struct sctp_bind_addr *);
 int sctp_bind_addr_copy(struct sctp_bind_addr *dest,
@@ -1220,8 +1211,6 @@
 
 /* These are function signatures for manipulating endpoints.  */
 struct sctp_endpoint *sctp_endpoint_new(struct sock *, int);
-struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *,
-					 struct sock *, int gfp);
 void sctp_endpoint_free(struct sctp_endpoint *);
 void sctp_endpoint_put(struct sctp_endpoint *);
 void sctp_endpoint_hold(struct sctp_endpoint *);
@@ -1243,8 +1232,6 @@
 int sctp_process_init(struct sctp_association *, sctp_cid_t cid,
 		      const union sctp_addr *peer,
 		      sctp_init_chunk_t *init, int gfp);
-int sctp_process_param(struct sctp_association *, union sctp_params param,
-		       const union sctp_addr *from, int gfp);
 __u32 sctp_generate_tag(const struct sctp_endpoint *);
 __u32 sctp_generate_tsn(const struct sctp_endpoint *);
 
@@ -1693,10 +1680,6 @@
 struct sctp_association *
 sctp_association_new(const struct sctp_endpoint *, const struct sock *,
 		     sctp_scope_t scope, int gfp);
-struct sctp_association *
-sctp_association_init(struct sctp_association *, const struct sctp_endpoint *,
-		      const struct sock *, sctp_scope_t scope,
-		      int gfp);
 void sctp_association_free(struct sctp_association *);
 void sctp_association_put(struct sctp_association *);
 void sctp_association_hold(struct sctp_association *);
@@ -1725,7 +1708,6 @@
 		       struct sctp_association *new);
 
 __u32 sctp_association_get_next_tsn(struct sctp_association *);
-__u32 sctp_association_get_tsn_block(struct sctp_association *, int);
 
 void sctp_assoc_sync_pmtu(struct sctp_association *);
 void sctp_assoc_rwnd_increase(struct sctp_association *, unsigned);
@@ -1739,7 +1721,6 @@
 int sctp_cmp_addr_exact(const union sctp_addr *ss1,
 			const union sctp_addr *ss2);
 struct sctp_chunk *sctp_get_ecne_prepend(struct sctp_association *asoc);
-struct sctp_chunk *sctp_get_no_prepend(struct sctp_association *asoc);
 
 /* A convenience structure to parse out SCTP specific CMSGs. */
 typedef struct sctp_cmsgs {
diff -urN linux-2.4.28-bk7/include/net/sctp/tsnmap.h linux-2.4.29/include/net/sctp/tsnmap.h
--- linux-2.4.28-bk7/include/net/sctp/tsnmap.h	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29/include/net/sctp/tsnmap.h	2005-01-19 07:08:14.652706970 -0800
@@ -120,12 +120,6 @@
 	__u32 start;
 };
 
-/* Create a new tsnmap.  */
-struct sctp_tsnmap *sctp_tsnmap_new(__u16 len, __u32 init_tsn, int gfp);
-
-/* Dispose of a tsnmap.  */
-void sctp_tsnmap_free(struct sctp_tsnmap *);
-
 /* This macro assists in creation of external storage for variable length
  * internal buffers.  We double allocate so the overflow map works.
  */
@@ -210,14 +204,4 @@
 /* Is there a gap in the TSN map? */
 int sctp_tsnmap_has_gap(const struct sctp_tsnmap *);
 
-/* Initialize a gap ack block interator from user-provided memory.  */
-void sctp_tsnmap_iter_init(const struct sctp_tsnmap *,
-			   struct sctp_tsnmap_iter *);
-
-/* Get the next gap ack blocks.  We return 0 if there are no more
- * gap ack blocks.
- */
-int sctp_tsnmap_next_gap_ack(const struct sctp_tsnmap *,
-	struct sctp_tsnmap_iter *,__u16 *start, __u16 *end);
-
 #endif /* __sctp_tsnmap_h__ */
diff -urN linux-2.4.28-bk7/include/net/sctp/ulpevent.h linux-2.4.29/include/net/sctp/ulpevent.h
--- linux-2.4.28-bk7/include/net/sctp/ulpevent.h	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/include/net/sctp/ulpevent.h	2005-01-19 07:08:14.652706970 -0800
@@ -77,8 +77,6 @@
 	return (struct sctp_ulpevent *)skb->cb;
 }
 
-struct sctp_ulpevent *sctp_ulpevent_new(int size, int flags, int gfp);
-void sctp_ulpevent_init(struct sctp_ulpevent *, int flags);
 void sctp_ulpevent_free(struct sctp_ulpevent *);
 int sctp_ulpevent_is_notification(const struct sctp_ulpevent *);
 void sctp_queue_purge_ulpevents(struct sk_buff_head *list);
diff -urN linux-2.4.28-bk7/include/net/sctp/ulpqueue.h linux-2.4.29/include/net/sctp/ulpqueue.h
--- linux-2.4.28-bk7/include/net/sctp/ulpqueue.h	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29/include/net/sctp/ulpqueue.h	2005-01-19 07:08:14.653707013 -0800
@@ -57,7 +57,6 @@
 };
 
 /* Prototypes. */
-struct sctp_ulpq *sctp_ulpq_new(struct sctp_association *asoc, int gfp);
 struct sctp_ulpq *sctp_ulpq_init(struct sctp_ulpq *,
 				 struct sctp_association *);
 void sctp_ulpq_free(struct sctp_ulpq *);
diff -urN linux-2.4.28-bk7/include/net/udp.h linux-2.4.29/include/net/udp.h
--- linux-2.4.28-bk7/include/net/udp.h	2001-11-22 11:47:15.000000000 -0800
+++ linux-2.4.29/include/net/udp.h	2005-01-19 07:08:14.653707013 -0800
@@ -23,6 +23,7 @@
 #define _UDP_H
 
 #include <linux/udp.h>
+#include <linux/poll.h>
 #include <net/sock.h>
 
 #define UDP_HTABLE_SIZE		128
@@ -68,6 +69,8 @@
 extern int	udp_rcv(struct sk_buff *skb);
 extern int	udp_ioctl(struct sock *sk, int cmd, unsigned long arg);
 extern int	udp_disconnect(struct sock *sk, int flags);
+extern unsigned int udp_poll(struct file *file, struct socket *sock,
+			     poll_table *wait);
 
 extern struct udp_mib udp_statistics[NR_CPUS*2];
 #define UDP_INC_STATS(field)		SNMP_INC_STATS(udp_statistics, field)
diff -urN linux-2.4.28-bk7/kernel/fork.c linux-2.4.29/kernel/fork.c
--- linux-2.4.28-bk7/kernel/fork.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/kernel/fork.c	2005-01-19 07:08:14.654707057 -0800
@@ -513,8 +513,17 @@
 
 	for (i = open_files; i != 0; i--) {
 		struct file *f = *old_fds++;
-		if (f)
+		if (f) {
 			get_file(f);
+		} else {
+			/*
+			 * The fd may be claimed in the fd bitmap but not yet
+			 * instantiated in the files array if a sibling thread
+			 * is partway through open().  So make sure that this
+			 * fd is available to the new process.
+			 */
+                        FD_CLR(open_files - i, newf->open_fds);
+		}
 		*new_fds++ = f;
 	}
 	read_unlock(&oldf->file_lock);
diff -urN linux-2.4.28-bk7/kernel/sysctl.c linux-2.4.29/kernel/sysctl.c
--- linux-2.4.28-bk7/kernel/sysctl.c	2005-01-19 07:07:43.571360816 -0800
+++ linux-2.4.29/kernel/sysctl.c	2005-01-19 07:08:14.655707100 -0800
@@ -379,6 +379,9 @@
 		int old_len;
 		if (!oldlenp || get_user(old_len, oldlenp))
 			return -EFAULT;
+		/* XXX: insufficient for SMP, but should be redundant anyway */
+		if ((ssize_t)old_len < 0)
+			return -EINVAL;
 	}
 	tmp = &root_table_header.ctl_entry;
 	do {
diff -urN linux-2.4.28-bk7/mm/memory.c linux-2.4.29/mm/memory.c
--- linux-2.4.28-bk7/mm/memory.c	2005-01-19 07:07:43.573360903 -0800
+++ linux-2.4.29/mm/memory.c	2005-01-19 07:08:14.657707187 -0800
@@ -454,9 +454,8 @@
 int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start,
 		int len, int write, int force, struct page **pages, struct vm_area_struct **vmas)
 {
-	int i, s;
+	int i;
 	unsigned int flags;
-	struct vm_area_struct *savevma = NULL;
 
 	/*
 	 * Require read or write permissions.
@@ -464,7 +463,7 @@
 	 */
 	flags = write ? (VM_WRITE | VM_MAYWRITE) : (VM_READ | VM_MAYREAD);
 	flags &= force ? (VM_MAYREAD | VM_MAYWRITE) : (VM_READ | VM_WRITE);
-	i = s = 0;
+	i = 0;
 
 	do {
 		struct vm_area_struct *	vma;
@@ -500,13 +499,9 @@
 				/* FIXME: call the correct function,
 				 * depending on the type of the found page
 				 */
-				if (!pages[i] || PageReserved(pages[i])) {
-					if (pages[i] != ZERO_PAGE(start)) {
-						savevma = vma;
-						goto bad_page;
-					}
-				} else
-					page_cache_get(pages[i]);
+				if (!pages[i])
+					goto bad_page;
+				page_cache_get(pages[i]);
 			}
 			if (vmas)
 				vmas[i] = vma;
@@ -525,15 +520,9 @@
 	 */
 bad_page:
 	spin_unlock(&mm->page_table_lock);
-	s = i;
 	while (i--)
 		page_cache_release(pages[i]);
-	/* catch bad uses of PG_reserved on !VM_IO vma's */
-	printk(KERN_ERR "get_user_pages PG_reserved page on"
-			"vma:%p flags:%lx page:%d\n", savevma,
-			savevma->vm_flags, s);
-	BUG();
-	i = -EFAULT; 
+	i = -EFAULT;
 	goto out;
 }
 
diff -urN linux-2.4.28-bk7/mm/mmap.c linux-2.4.29/mm/mmap.c
--- linux-2.4.28-bk7/mm/mmap.c	2004-02-18 05:36:32.000000000 -0800
+++ linux-2.4.29/mm/mmap.c	2005-01-19 07:08:14.658707230 -0800
@@ -650,7 +650,7 @@
 unsigned long get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags)
 {
 	if (flags & MAP_FIXED) {
-		if (addr > TASK_SIZE - len)
+		if (addr > TASK_SIZE - len || addr >= TASK_SIZE)
 			return -ENOMEM;
 		if (addr & ~PAGE_MASK)
 			return -EINVAL;
@@ -931,7 +931,7 @@
 {
 	struct vm_area_struct *mpnt, *prev, **npp, *free, *extra;
 
-	if ((addr & ~PAGE_MASK) || addr > TASK_SIZE || len > TASK_SIZE-addr)
+	if ((addr & ~PAGE_MASK) || addr >= TASK_SIZE || len > TASK_SIZE-addr)
 		return -EINVAL;
 
 	if ((len = PAGE_ALIGN(len)) == 0)
@@ -1031,6 +1031,15 @@
 	return ret;
 }
 
+
+static inline void verify_mmap_write_lock_held(struct mm_struct *mm)
+{
+	if (down_read_trylock(&mm->mmap_sem)) {
+		WARN_ON(1);
+		up_read(&mm->mmap_sem);
+	}
+}
+
 /*
  *  this is really a simplified "do_mmap".  it only handles
  *  anonymous maps.  eventually we may be able to do some
@@ -1061,6 +1070,12 @@
 	}
 
 	/*
+	 * mm->mmap_sem is required to protect against another thread
+	 * changing the mappings while we sleep (on kmalloc for one).
+	 */
+	verify_mmap_write_lock_held(mm);
+
+	/*
 	 * Clear old maps.  this also does some error checking for us
 	 */
  munmap_back:
@@ -1193,14 +1208,15 @@
 	validate_mm(mm);
 }
 
-void insert_vm_struct(struct mm_struct * mm, struct vm_area_struct * vma)
+int insert_vm_struct(struct mm_struct * mm, struct vm_area_struct * vma)
 {
 	struct vm_area_struct * __vma, * prev;
 	rb_node_t ** rb_link, * rb_parent;
 
 	__vma = find_vma_prepare(mm, vma->vm_start, &prev, &rb_link, &rb_parent);
 	if (__vma && __vma->vm_start < vma->vm_end)
-		BUG();
+		return -ENOMEM;
 	vma_link(mm, vma, prev, rb_link, rb_parent);
 	validate_mm(mm);
+	return 0;
 }
diff -urN linux-2.4.28-bk7/mm/mremap.c linux-2.4.29/mm/mremap.c
--- linux-2.4.28-bk7/mm/mremap.c	2004-04-14 06:05:41.000000000 -0700
+++ linux-2.4.29/mm/mremap.c	2005-01-19 07:08:14.658707230 -0800
@@ -196,6 +196,7 @@
 			insert_vm_struct(current->mm, new_vma);
 		}
 
+		/* XXX: possible errors masked, mapping might remain */
 		do_munmap(current->mm, addr, old_len);
 
 		current->mm->total_vm += new_len >> PAGE_SHIFT;
@@ -236,6 +237,12 @@
 	old_len = PAGE_ALIGN(old_len);
 	new_len = PAGE_ALIGN(new_len);
 
+	if (old_len > TASK_SIZE || addr > TASK_SIZE - old_len)
+		goto out;
+
+	if (addr >= TASK_SIZE)
+		goto out;
+
 	/* new_addr is only valid if MREMAP_FIXED is specified */
 	if (flags & MREMAP_FIXED) {
 		if (new_addr & ~PAGE_MASK)
@@ -245,6 +252,10 @@
 
 		if (new_len > TASK_SIZE || new_addr > TASK_SIZE - new_len)
 			goto out;
+
+		if (new_addr >= TASK_SIZE)
+			goto out;
+
 		/*
 		 * Allow new_len == 0 only if new_addr == addr
 		 * to preserve truncation in place (that was working
diff -urN linux-2.4.28-bk7/net/802/p8022.c linux-2.4.29/net/802/p8022.c
--- linux-2.4.28-bk7/net/802/p8022.c	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29/net/802/p8022.c	2005-01-19 07:08:14.660707317 -0800
@@ -97,7 +97,14 @@
 	return 0;
 }
 
+static void __exit p8022_exit(void)
+{
+	dev_remove_pack(&p8022_packet_type);
+	return;
+}
+
 module_init(p8022_init);
+module_exit(p8022_exit);
 
 struct datalink_proto *register_8022_client(unsigned char type, int (*rcvfunc)(struct sk_buff *, struct net_device *, struct packet_type *))
 {
diff -urN linux-2.4.28-bk7/net/802/psnap.c linux-2.4.29/net/802/psnap.c
--- linux-2.4.28-bk7/net/802/psnap.c	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29/net/802/psnap.c	2005-01-19 07:08:14.660707317 -0800
@@ -96,7 +96,15 @@
 		printk("SNAP - unable to register with 802.2\n");
 	return 0;
 }
+
+static void __exit snap_exit(void)
+{
+	unregister_8022_client(0xAA);
+}
+
 module_init(snap_init);
+module_exit(snap_exit);
+
 
 /*
  *	Register SNAP clients. We don't yet use this for IP.
diff -urN linux-2.4.28-bk7/net/Config.in linux-2.4.29/net/Config.in
--- linux-2.4.28-bk7/net/Config.in	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29/net/Config.in	2005-01-19 07:08:14.661707360 -0800
@@ -61,7 +61,9 @@
 fi
 
 tristate 'Appletalk protocol support' CONFIG_ATALK
-source drivers/net/appletalk/Config.in
+if [ "$CONFIG_ATALK" != "n" ]; then
+   source drivers/net/appletalk/Config.in
+fi
 
 tristate 'DECnet Support' CONFIG_DECNET
 if [ "$CONFIG_DECNET" != "n" ]; then
diff -urN linux-2.4.28-bk7/net/bluetooth/rfcomm/tty.c linux-2.4.29/net/bluetooth/rfcomm/tty.c
--- linux-2.4.28-bk7/net/bluetooth/rfcomm/tty.c	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29/net/bluetooth/rfcomm/tty.c	2005-01-19 07:08:14.662707403 -0800
@@ -532,10 +532,8 @@
 
 	BT_DBG("dev %p tty %p", dev, tty);
 
-	if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && tty->ldisc.write_wakeup)
-                (tty->ldisc.write_wakeup)(tty);
+	tty_wakeup(tty);
 
-	wake_up_interruptible(&tty->write_wait);
 #ifdef SERIAL_HAVE_POLL_WAIT
 	wake_up_interruptible(&tty->poll_wait);
 #endif
@@ -853,8 +851,7 @@
 
 	skb_queue_purge(&dev->dlc->tx_queue);
 
-	if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && tty->ldisc.write_wakeup)
-		tty->ldisc.write_wakeup(tty);
+	tty_wakeup(tty);
 }
 
 static void rfcomm_tty_send_xchar(struct tty_struct *tty, char ch)
diff -urN linux-2.4.28-bk7/net/core/neighbour.c linux-2.4.29/net/core/neighbour.c
--- linux-2.4.28-bk7/net/core/neighbour.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/net/core/neighbour.c	2005-01-19 07:08:14.663707446 -0800
@@ -427,11 +427,12 @@
 
 	n->confirmed = jiffies - (n->parms->base_reachable_time<<1);
 
-	hash_val = tbl->hash(pkey, dev) & tbl->hash_mask;
-
 	write_lock_bh(&tbl->lock);
 	if (atomic_read(&tbl->entries) > (tbl->hash_mask + 1))
 		neigh_hash_grow(tbl, (tbl->hash_mask + 1) << 1);
+
+	hash_val = tbl->hash(pkey, dev) & tbl->hash_mask;
+
 	for (n1 = tbl->hash_buckets[hash_val]; n1; n1 = n1->next) {
 		if (dev == n1->dev &&
 		    memcmp(n1->primary_key, pkey, key_len) == 0) {
diff -urN linux-2.4.28-bk7/net/core/netfilter.c linux-2.4.29/net/core/netfilter.c
--- linux-2.4.28-bk7/net/core/netfilter.c	2003-08-25 04:44:44.000000000 -0700
+++ linux-2.4.29/net/core/netfilter.c	2005-01-19 07:08:14.664707490 -0800
@@ -622,12 +622,21 @@
 }
 #endif /*CONFIG_INET*/
 
-/* This does not belong here, but ipt_REJECT needs it if connection
-   tracking in use: without this, connection may not be in hash table,
-   and hence manufactured ICMP or RST packets will not be associated
-   with it. */
+/* This does not belong here, but locally generated errors need it if connection
+   tracking in use: without this, connection may not be in hash table, and hence
+   manufactured ICMP or RST packets will not be associated with it. */
 void (*ip_ct_attach)(struct sk_buff *, struct nf_ct_info *);
 
+void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb)
+{
+	void (*attach)(struct sk_buff *, struct nf_ct_info *);
+
+	if (skb->nfct && (attach = ip_ct_attach) != NULL) {
+		mb(); /* Just to be sure: must be read before executing this */
+		attach(new, skb->nfct);
+	}
+}
+
 void __init netfilter_init(void)
 {
 	int i, h;
diff -urN linux-2.4.28-bk7/net/core/scm.c linux-2.4.29/net/core/scm.c
--- linux-2.4.28-bk7/net/core/scm.c	2001-12-21 09:42:05.000000000 -0800
+++ linux-2.4.29/net/core/scm.c	2005-01-19 07:08:14.664707490 -0800
@@ -124,9 +124,7 @@
 		   for too short ancillary data object at all! Oops.
 		   OK, let's add it...
 		 */
-		if (cmsg->cmsg_len < sizeof(struct cmsghdr) ||
-		    (unsigned long)(((char*)cmsg - (char*)msg->msg_control)
-				    + cmsg->cmsg_len) > msg->msg_controllen)
+		if (!CMSG_OK(msg, cmsg))
 			goto error;
 
 		if (cmsg->cmsg_level != SOL_SOCKET)
diff -urN linux-2.4.28-bk7/net/ipv4/af_inet.c linux-2.4.29/net/ipv4/af_inet.c
--- linux-2.4.28-bk7/net/ipv4/af_inet.c	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29/net/ipv4/af_inet.c	2005-01-19 07:08:14.666707576 -0800
@@ -972,6 +972,27 @@
 	socketpair:	sock_no_socketpair,
 	accept:		sock_no_accept,
 	getname:	inet_getname, 
+	poll:		udp_poll,
+	ioctl:		inet_ioctl,
+	listen:		sock_no_listen,
+	shutdown:	inet_shutdown,
+	setsockopt:	inet_setsockopt,
+	getsockopt:	inet_getsockopt,
+	sendmsg:	inet_sendmsg,
+	recvmsg:	inet_recvmsg,
+	mmap:		sock_no_mmap,
+	sendpage:	sock_no_sendpage,
+};
+
+struct proto_ops inet_sockraw_ops = {
+	family:		PF_INET,
+
+	release:	inet_release,
+	bind:		inet_bind,
+	connect:	inet_dgram_connect,
+	socketpair:	sock_no_socketpair,
+	accept:		sock_no_accept,
+	getname:	inet_getname, 
 	poll:		datagram_poll,
 	ioctl:		inet_ioctl,
 	listen:		sock_no_listen,
@@ -1023,7 +1044,7 @@
                type:        SOCK_RAW,
                protocol:    IPPROTO_IP,	/* wild card */
                prot:        &raw_prot,
-               ops:         &inet_dgram_ops,
+               ops:         &inet_sockraw_ops,
                capability:  CAP_NET_RAW,
                no_check:    UDP_CSUM_DEFAULT,
                flags:       INET_PROTOSW_REUSE,
diff -urN linux-2.4.28-bk7/net/ipv4/icmp.c linux-2.4.29/net/ipv4/icmp.c
--- linux-2.4.28-bk7/net/ipv4/icmp.c	2004-04-14 06:05:41.000000000 -0700
+++ linux-2.4.29/net/ipv4/icmp.c	2005-01-19 07:08:14.667707620 -0800
@@ -281,12 +281,16 @@
  *	Checksum each fragment, and on the first include the headers and final checksum.
  */
  
-static int icmp_glue_bits(const void *p, char *to, unsigned int offset, unsigned int fraglen)
+static int icmp_glue_bits(const void *p, char *to, unsigned int offset,
+                          unsigned int fraglen, struct sk_buff *skb)
 {
 	struct icmp_bxm *icmp_param = (struct icmp_bxm *)p;
 	struct icmphdr *icmph;
 	unsigned int csum;
 
+	if (icmp_pointers[icmp_param->data.icmph.type].error)
+		nf_ct_attach(skb, icmp_param->skb);
+
 	if (offset) {
 		icmp_param->csum=skb_copy_and_csum_bits(icmp_param->skb,
 							icmp_param->offset+(offset-icmp_param->head_len), 
diff -urN linux-2.4.28-bk7/net/ipv4/igmp.c linux-2.4.29/net/ipv4/igmp.c
--- linux-2.4.28-bk7/net/ipv4/igmp.c	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29/net/ipv4/igmp.c	2005-01-19 07:08:14.669707706 -0800
@@ -1757,12 +1757,12 @@
 			goto done;
 		rv = !0;
 		for (i=0; i<psl->sl_count; i++) {
-			rv = memcmp(&psl->sl_addr, &mreqs->imr_multiaddr,
+			rv = memcmp(&psl->sl_addr[i], &mreqs->imr_sourceaddr,
 				sizeof(__u32));
-			if (rv >= 0)
+			if (rv == 0)
 				break;
 		}
-		if (!rv)	/* source not found */
+		if (rv)		/* source not found */
 			goto done;
 
 		/* update the interface filter */
@@ -1804,9 +1804,9 @@
 	}
 	rv = 1;	/* > 0 for insert logic below if sl_count is 0 */
 	for (i=0; i<psl->sl_count; i++) {
-		rv = memcmp(&psl->sl_addr, &mreqs->imr_multiaddr,
+		rv = memcmp(&psl->sl_addr[i], &mreqs->imr_sourceaddr,
 			sizeof(__u32));
-		if (rv >= 0)
+		if (rv == 0)
 			break;
 	}
 	if (rv == 0)		/* address already there is an error */
diff -urN linux-2.4.28-bk7/net/ipv4/ip_options.c linux-2.4.29/net/ipv4/ip_options.c
--- linux-2.4.28-bk7/net/ipv4/ip_options.c	2002-11-28 15:53:15.000000000 -0800
+++ linux-2.4.29/net/ipv4/ip_options.c	2005-01-19 07:08:14.670707750 -0800
@@ -514,6 +514,8 @@
 		kfree(opt);
 		return -EINVAL;
 	}
+	if (*optp)
+		kfree(*optp);
 	*optp = opt;
 	return 0;
 }
diff -urN linux-2.4.28-bk7/net/ipv4/ip_output.c linux-2.4.29/net/ipv4/ip_output.c
--- linux-2.4.28-bk7/net/ipv4/ip_output.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/net/ipv4/ip_output.c	2005-01-19 07:08:14.671707793 -0800
@@ -438,7 +438,8 @@
 		  int getfrag (const void *,
 			       char *,
 			       unsigned int,	
-			       unsigned int),
+			       unsigned int,
+			       struct sk_buff *),
 		  const void *frag,
 		  unsigned length,
 		  struct ipcm_cookie *ipc,
@@ -607,7 +608,7 @@
 		 *	User data callback
 		 */
 
-		if (getfrag(frag, data, offset, fraglen-fragheaderlen)) {
+		if (getfrag(frag, data, offset, fraglen-fragheaderlen, skb)) {
 			err = -EFAULT;
 			kfree_skb(skb);
 			goto error;
@@ -647,7 +648,8 @@
 		  int getfrag (const void *,
 			       char *,
 			       unsigned int,	
-			       unsigned int),
+			       unsigned int,
+			       struct sk_buff *),
 		  const void *frag,
 		  unsigned length,
 		  struct ipcm_cookie *ipc,
@@ -721,10 +723,10 @@
 		iph->daddr=rt->rt_dst;
 		iph->check=0;
 		iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
-		err = getfrag(frag, ((char *)iph)+iph->ihl*4,0, length-iph->ihl*4);
+		err = getfrag(frag, ((char *)iph)+iph->ihl*4,0, length-iph->ihl*4, skb);
 	}
 	else
-		err = getfrag(frag, (void *)iph, 0, length);
+		err = getfrag(frag, (void *)iph, 0, length, skb);
 
 	if (err)
 		goto error_fault;
@@ -921,7 +923,7 @@
  *	Fetch data from kernel space and fill in checksum if needed.
  */
 static int ip_reply_glue_bits(const void *dptr, char *to, unsigned int offset, 
-			      unsigned int fraglen)
+			      unsigned int fraglen, struct sk_buff *skb)
 {
         struct ip_reply_arg *dp = (struct ip_reply_arg*)dptr;
 	u16 *pktp = (u16 *)to;
diff -urN linux-2.4.28-bk7/net/ipv4/ip_sockglue.c linux-2.4.29/net/ipv4/ip_sockglue.c
--- linux-2.4.28-bk7/net/ipv4/ip_sockglue.c	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29/net/ipv4/ip_sockglue.c	2005-01-19 07:08:14.672707836 -0800
@@ -143,11 +143,8 @@
 	struct cmsghdr *cmsg;
 
 	for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
-		if (cmsg->cmsg_len < sizeof(struct cmsghdr) ||
-		    (unsigned long)(((char*)cmsg - (char*)msg->msg_control)
-				    + cmsg->cmsg_len) > msg->msg_controllen) {
+		if (!CMSG_OK(msg, cmsg))
 			return -EINVAL;
-		}
 		if (cmsg->cmsg_level != SOL_IP)
 			continue;
 		switch (cmsg->cmsg_type) {
diff -urN linux-2.4.28-bk7/net/ipv4/ipvs/ip_vs_conn.c linux-2.4.29/net/ipv4/ipvs/ip_vs_conn.c
--- linux-2.4.28-bk7/net/ipv4/ipvs/ip_vs_conn.c	2004-04-14 06:05:41.000000000 -0700
+++ linux-2.4.29/net/ipv4/ipvs/ip_vs_conn.c	2005-01-19 07:08:14.673707880 -0800
@@ -1131,7 +1131,9 @@
 	 * Checking the dest server status.
 	 */
 	if ((dest == NULL) ||
-	    !(dest->flags & IP_VS_DEST_F_AVAILABLE)) {
+	    !(dest->flags & IP_VS_DEST_F_AVAILABLE) || 
+	    (sysctl_ip_vs_expire_quiescent_template && 
+	     (atomic_read(&dest->weight) == 0))) {
 		IP_VS_DBG(9, "check_template: dest not available for "
 			  "protocol %s s:%u.%u.%u.%u:%d v:%u.%u.%u.%u:%d "
 			  "-> d:%u.%u.%u.%u:%d\n",
diff -urN linux-2.4.28-bk7/net/ipv4/ipvs/ip_vs_core.c linux-2.4.29/net/ipv4/ipvs/ip_vs_core.c
--- linux-2.4.28-bk7/net/ipv4/ipvs/ip_vs_core.c	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.29/net/ipv4/ipvs/ip_vs_core.c	2005-01-19 07:08:14.673707880 -0800
@@ -1131,7 +1131,7 @@
 	/* increase its packet counter and check if it is needed
 	   to be synchronized */
 	atomic_inc(&cp->in_pkts);
-	if (ip_vs_sync_state == IP_VS_STATE_MASTER &&
+	if (ip_vs_sync_state & IP_VS_STATE_MASTER &&
 	    (cp->protocol != IPPROTO_TCP ||
 	     cp->state == IP_VS_S_ESTABLISHED) &&
 	    (atomic_read(&cp->in_pkts) % 50 == sysctl_ip_vs_sync_threshold))
diff -urN linux-2.4.28-bk7/net/ipv4/ipvs/ip_vs_ctl.c linux-2.4.29/net/ipv4/ipvs/ip_vs_ctl.c
--- linux-2.4.28-bk7/net/ipv4/ipvs/ip_vs_ctl.c	2004-04-14 06:05:41.000000000 -0700
+++ linux-2.4.29/net/ipv4/ipvs/ip_vs_ctl.c	2005-01-19 07:08:14.675707966 -0800
@@ -74,6 +74,7 @@
 static int sysctl_ip_vs_am_droprate = 10;
 int sysctl_ip_vs_cache_bypass = 0;
 int sysctl_ip_vs_expire_nodest_conn = 0;
+int sysctl_ip_vs_expire_quiescent_template = 0;
 int sysctl_ip_vs_sync_threshold = 3;
 int sysctl_ip_vs_nat_icmp_send = 0;
 
@@ -1440,6 +1441,9 @@
 	 {NET_IPV4_VS_NAT_ICMP_SEND, "nat_icmp_send",
 	  &sysctl_ip_vs_nat_icmp_send, sizeof(int), 0644, NULL,
 	  &proc_dointvec},
+	 {NET_IPV4_VS_EXPIRE_QUIESCENT_TEMPLATE, "expire_quiescent_template",
+	  &sysctl_ip_vs_expire_quiescent_template, sizeof(int), 0644, NULL,
+	  &proc_dointvec},
 	 {0}},
 	{{NET_IPV4_VS, "vs", NULL, 0, 0555, ipv4_vs_table.vs_vars},
 	 {0}},
@@ -1727,10 +1731,11 @@
 		ret = ip_vs_set_timeouts(urule);
 		goto out_unlock;
 	} else if (cmd == IP_VS_SO_SET_STARTDAEMON) {
-		ret = start_sync_thread(urule->state, urule->mcast_ifn);
+		ret = start_sync_thread(urule->state, urule->mcast_ifn,
+					urule->syncid);
 		goto out_unlock;
 	} else if (cmd == IP_VS_SO_SET_STOPDAEMON) {
-		ret = stop_sync_thread();
+		ret = stop_sync_thread(urule->state);
 		goto out_unlock;
 	} else if (cmd == IP_VS_SO_SET_ZERO) {
 		/* if no service address is set, zero counters in all */
@@ -2078,7 +2083,10 @@
 			goto out;
 		}
 		u.state = ip_vs_sync_state;
-		strcpy(u.mcast_ifn, ip_vs_mcast_ifn);
+		if (ip_vs_sync_state & IP_VS_STATE_MASTER)
+			strcpy(u.mcast_master_ifn, ip_vs_mcast_master_ifn);
+		if (ip_vs_sync_state & IP_VS_STATE_BACKUP)
+			strcpy(u.mcast_backup_ifn, ip_vs_mcast_backup_ifn);
 		if (copy_to_user(user, &u, sizeof(u)) != 0)
 			ret = -EFAULT;
 	}
diff -urN linux-2.4.28-bk7/net/ipv4/ipvs/ip_vs_sync.c linux-2.4.29/net/ipv4/ipvs/ip_vs_sync.c
--- linux-2.4.28-bk7/net/ipv4/ipvs/ip_vs_sync.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/net/ipv4/ipvs/ip_vs_sync.c	2005-01-19 07:08:14.676708010 -0800
@@ -13,6 +13,9 @@
  *              through multicast
  *
  * Changes:
+ *	Alexandre Cassen        :       Added master & backup support at a time.
+ *	Alexandre Cassen        :       Added SyncID support for incoming sync
+ *					messages filtering.
  *	Justin Ossevoort	:	Fix endian problem on sync message size.
  */
 
@@ -74,7 +77,7 @@
        0                   1                   2                   3
        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-      |  Count Conns  |   Reserved    |            Size               |
+      |  Count Conns  |    Sync ID    |            Size               |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                                                               |
       |                    IPVS Sync Connection (1)                   |
@@ -86,11 +89,16 @@
       |                                                               |
       |                    IPVS Sync Connection (n)                   |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+   Count Conns : Number of IPVS sync Connection entries.
+   Sync ID     : IPVS sync group we belong to.
+   Size        : Size of packet.
+
 */
 #define SYNC_MESG_MAX_SIZE      (24*50+4)
 struct ip_vs_sync_mesg {
 	__u8                    nr_conns;
-	__u8                    reserved;
+	__u8                    syncid;
 	__u16                   size;
 
 	/* ip_vs_sync_conn entries start here */
@@ -116,6 +124,18 @@
 static struct ip_vs_sync_buff   *curr_sb = NULL;
 static spinlock_t curr_sb_lock = SPIN_LOCK_UNLOCKED;
 
+/* ipvs sync daemon state */
+volatile int ip_vs_sync_state = IP_VS_STATE_NONE;
+volatile int ip_vs_master_syncid = 0;
+volatile int ip_vs_backup_syncid = 0;
+
+/* multicast interface name */
+char ip_vs_mcast_master_ifn[IP_VS_IFNAME_MAXLEN];
+char ip_vs_mcast_backup_ifn[IP_VS_IFNAME_MAXLEN];
+
+/* multicast addr */
+static struct sockaddr_in mcast_addr;
+
 static inline void sb_queue_tail(struct ip_vs_sync_buff *sb)
 {
 	spin_lock(&ip_vs_sync_lock);
@@ -153,6 +173,7 @@
 		return NULL;
 	}
 	sb->mesg->nr_conns = 0;
+	sb->mesg->syncid = ip_vs_master_syncid;
 	sb->mesg->size = 4;
 	sb->head = (unsigned char *)sb->mesg + 4;
 	sb->end = (unsigned char *)sb->mesg + SYNC_MESG_MAX_SIZE;
@@ -265,6 +286,13 @@
 		return;
 	}
 
+	/* SyncID sanity check */
+	if (ip_vs_backup_syncid != 0 && m->syncid != ip_vs_backup_syncid) {
+		IP_VS_DBG(7, "Ignoring incoming msg with syncid = %d\n",
+			  m->syncid);
+		return;
+	}
+
 	p = (char *)buffer + sizeof(struct ip_vs_sync_mesg);
 	for (i=0; i<m->nr_conns; i++) {
 		s = (struct ip_vs_sync_conn *)p;
@@ -308,16 +336,6 @@
 }
 
 
-/* ipvs sync daemon state */
-volatile int ip_vs_sync_state = IP_VS_STATE_NONE;
-
-/* multicast interface name */
-char ip_vs_mcast_ifn[IP_VS_IFNAME_MAXLEN];
-
-/* multicast addr */
-static struct sockaddr_in mcast_addr;
-
-
 /*
  *      Setup loopback of outgoing multicasts on a sending socket
  */
@@ -429,7 +447,7 @@
 		return NULL;
 	}
 
-	if (set_mcast_if(sock->sk, ip_vs_mcast_ifn) < 0) {
+	if (set_mcast_if(sock->sk, ip_vs_mcast_master_ifn) < 0) {
 		IP_VS_ERR("Error setting outbound mcast interface\n");
 		goto error;
 	}
@@ -437,7 +455,7 @@
 	set_mcast_loop(sock->sk, 0);
 	set_mcast_ttl(sock->sk, 1);
 
-	if (bind_mcastif_addr(sock, ip_vs_mcast_ifn) < 0) {
+	if (bind_mcastif_addr(sock, ip_vs_mcast_master_ifn) < 0) {
 		IP_VS_ERR("Error binding address of the mcast interface\n");
 		goto error;
 	}
@@ -483,7 +501,7 @@
 	/* join the multicast group */
 	if (join_mcast_group(sock->sk,
 			     (struct in_addr*)&mcast_addr.sin_addr,
-			     ip_vs_mcast_ifn) < 0) {
+			     ip_vs_mcast_backup_ifn) < 0) {
 		IP_VS_ERR("Error joining to the multicast group\n");
 		goto error;
 	}
@@ -571,10 +589,12 @@
 
 
 static DECLARE_WAIT_QUEUE_HEAD(sync_wait);
-static pid_t sync_pid = 0;
+static pid_t sync_master_pid = 0;
+static pid_t sync_backup_pid = 0;
 
 static DECLARE_WAIT_QUEUE_HEAD(stop_sync_wait);
-static int stop_sync = 0;
+static int stop_master_sync = 0;
+static int stop_backup_sync = 0;
 
 static void sync_master_loop(void)
 {
@@ -586,6 +606,10 @@
 	if (!sock)
 		return;
 
+	IP_VS_INFO("sync thread started: state = MASTER, mcast_ifn = %s, "
+		   "syncid = %d\n",
+		   ip_vs_mcast_master_ifn, ip_vs_master_syncid);
+
 	for (;;) {
 		while ((sb=sb_dequeue())) {
 			ip_vs_send_sync_msg(sock, sb->mesg);
@@ -598,7 +622,7 @@
 			ip_vs_sync_buff_release(sb);
 		}
 
-		if (stop_sync)
+		if (stop_master_sync)
 			break;
 
 		__set_current_state(TASK_INTERRUPTIBLE);
@@ -637,6 +661,10 @@
 	if (!sock)
 		goto out;
 
+	IP_VS_INFO("sync thread started: state = BACKUP, mcast_ifn = %s, "
+		   "syncid = %d\n",
+		   ip_vs_mcast_backup_ifn, ip_vs_backup_syncid);
+
 	for (;;) {
 		/* do you have data now? */
 		while (!skb_queue_empty(&(sock->sk->receive_queue))) {
@@ -652,7 +680,7 @@
 			local_bh_enable();
 		}
 
-		if (stop_sync)
+		if (stop_backup_sync)
 			break;
 
 		__set_current_state(TASK_INTERRUPTIBLE);
@@ -667,12 +695,31 @@
 	kfree(buf);
 }
 
+static void sync_pid_set(int sync_state, pid_t sync_pid)
+{
+	if (sync_state == IP_VS_STATE_MASTER)
+		sync_master_pid = sync_pid;
+	else if (sync_state == IP_VS_STATE_BACKUP)
+		sync_backup_pid = sync_pid;
+}
+
+static void sync_stop_set(int sync_state, int set)
+{
+	if (sync_state == IP_VS_STATE_MASTER)
+		stop_master_sync = set;
+	else if (sync_state == IP_VS_STATE_BACKUP)
+		stop_backup_sync = set;
+	else {
+		stop_master_sync = set;
+		stop_backup_sync = set;
+	}
+}
 
 static int sync_thread(void *startup)
 {
 	DECLARE_WAITQUEUE(wait, current);
 	mm_segment_t oldmm;
-	int state;
+	int state = IP_VS_STATE_NONE;
 
 	MOD_INC_USE_COUNT;
 	daemonize();
@@ -680,12 +727,15 @@
 	oldmm = get_fs();
 	set_fs(KERNEL_DS);
 
-	if (ip_vs_sync_state == IP_VS_STATE_MASTER)
+	if (ip_vs_sync_state & IP_VS_STATE_MASTER && !sync_master_pid) {
+		state = IP_VS_STATE_MASTER;
 		sprintf(current->comm, "ipvs_syncmaster");
-	else if (ip_vs_sync_state == IP_VS_STATE_BACKUP)
+	} else if (ip_vs_sync_state & IP_VS_STATE_BACKUP) {
+		state = IP_VS_STATE_BACKUP;
 		sprintf(current->comm, "ipvs_syncbackup");
-	else IP_VS_BUG();
+	} else IP_VS_BUG();
 
+	/* Block all signals */
 	spin_lock_irq(&current->sigmask_lock);
 	siginitsetinv(&current->blocked, 0);
 	recalc_sigpending(current);
@@ -698,9 +748,7 @@
 
 	add_wait_queue(&sync_wait, &wait);
 
-	state = ip_vs_sync_state;
-	sync_pid = current->pid;
-	IP_VS_INFO("sync thread started.\n");
+	sync_pid_set(state, current->pid);
 	complete((struct completion *)startup);
 
 	/* processing master/backup loop here */
@@ -713,13 +761,13 @@
 	remove_wait_queue(&sync_wait, &wait);
 
 	/* thread exits */
-	sync_pid = 0;
+	sync_pid_set(state, 0);
 	IP_VS_INFO("sync thread stopped!\n");
 
 	set_fs(oldmm);
 	MOD_DEC_USE_COUNT;
 
-	stop_sync = 0;
+	sync_stop_set(state, 0);
 	wake_up(&stop_sync_wait);
 
 	return 0;
@@ -745,20 +793,27 @@
 }
 
 
-int start_sync_thread(int state, char *mcast_ifn)
+int start_sync_thread(int state, char *mcast_ifn, __u8 syncid)
 {
 	DECLARE_COMPLETION(startup);
 	pid_t pid;
 
-	if (sync_pid)
+	if ((state == IP_VS_STATE_MASTER && sync_master_pid) ||
+	    (state == IP_VS_STATE_BACKUP && sync_backup_pid))
 		return -EEXIST;
 
 	IP_VS_DBG(7, "%s: pid %d\n", __FUNCTION__, current->pid);
 	IP_VS_DBG(7, "Each ip_vs_sync_conn entry need %d bytes\n",
 		  sizeof(struct ip_vs_sync_conn));
 
-	ip_vs_sync_state = state;
-	strcpy(ip_vs_mcast_ifn, mcast_ifn);
+	ip_vs_sync_state |= state;
+	if (state == IP_VS_STATE_MASTER) {
+		strcpy(ip_vs_mcast_master_ifn, mcast_ifn);
+		ip_vs_master_syncid = syncid;
+	} else {
+		strcpy(ip_vs_mcast_backup_ifn, mcast_ifn);
+		ip_vs_backup_syncid = syncid;
+	}
 
   repeat:
 	if ((pid = kernel_thread(fork_sync_thread, &startup, 0)) < 0) {
@@ -775,20 +830,22 @@
 }
 
 
-int stop_sync_thread(void)
+int stop_sync_thread(int state)
 {
 	DECLARE_WAITQUEUE(wait, current);
 
-	if (!sync_pid)
+	if ((state == IP_VS_STATE_MASTER && !sync_master_pid) ||
+	    (state == IP_VS_STATE_BACKUP && !sync_backup_pid))
 		return -ESRCH;
 
 	IP_VS_DBG(7, "%s: pid %d\n", __FUNCTION__, current->pid);
-	IP_VS_INFO("stopping sync thread %d ...\n", sync_pid);
+	IP_VS_INFO("stopping sync thread %d ...\n",
+		   (state == IP_VS_STATE_MASTER) ? sync_master_pid : sync_backup_pid);
 
 	__set_current_state(TASK_UNINTERRUPTIBLE);
 	add_wait_queue(&stop_sync_wait, &wait);
-	ip_vs_sync_state = IP_VS_STATE_NONE;
-	stop_sync = 1;
+	sync_stop_set(state, 1);
+	ip_vs_sync_state -= state;
 	wake_up(&sync_wait);
 	schedule();
 	__set_current_state(TASK_RUNNING);
@@ -797,7 +854,8 @@
 	/* Note: no need to reap the sync thread, because its parent
 	   process is the init process */
 
-	if (stop_sync)
+	if ((state == IP_VS_STATE_MASTER && stop_master_sync) ||
+	    (state == IP_VS_STATE_BACKUP && stop_backup_sync))
 		IP_VS_BUG();
 
 	return 0;
diff -urN linux-2.4.28-bk7/net/ipv4/netfilter/Config.in linux-2.4.29/net/ipv4/netfilter/Config.in
--- linux-2.4.28-bk7/net/ipv4/netfilter/Config.in	2003-08-25 04:44:44.000000000 -0700
+++ linux-2.4.29/net/ipv4/netfilter/Config.in	2005-01-19 07:08:14.677708053 -0800
@@ -66,7 +66,6 @@
           define_tristate CONFIG_IP_NF_NAT_AMANDA $CONFIG_IP_NF_NAT
         fi
       fi
-      bool '    NAT of local connections (READ HELP)' CONFIG_IP_NF_NAT_LOCAL
       if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
         dep_tristate '    Basic SNMP-ALG support (EXPERIMENTAL)' CONFIG_IP_NF_NAT_SNMP_BASIC $CONFIG_IP_NF_NAT
       fi
diff -urN linux-2.4.28-bk7/net/ipv4/netfilter/ip_conntrack_core.c linux-2.4.29/net/ipv4/netfilter/ip_conntrack_core.c
--- linux-2.4.28-bk7/net/ipv4/netfilter/ip_conntrack_core.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/net/ipv4/netfilter/ip_conntrack_core.c	2005-01-19 07:08:14.678708096 -0800
@@ -122,9 +122,9 @@
 }
 
 inline int
-get_tuple(const struct iphdr *iph, size_t len,
-	  struct ip_conntrack_tuple *tuple,
-	  struct ip_conntrack_protocol *protocol)
+ip_ct_get_tuple(const struct iphdr *iph, size_t len,
+                struct ip_conntrack_tuple *tuple,
+                struct ip_conntrack_protocol *protocol)
 {
 	int ret;
 
@@ -546,7 +546,7 @@
 	innerproto = ip_ct_find_proto(inner->protocol);
 	/* Are they talking about one of our connections? */
 	if (inner->ihl * 4 + 8 > datalen
-	    || !get_tuple(inner, datalen, &origtuple, innerproto)) {
+	    || !ip_ct_get_tuple(inner, datalen, &origtuple, innerproto)) {
 		DEBUGP("icmp_error: ! get_tuple p=%u (%u*4+%u dlen=%u)\n",
 		       inner->protocol, inner->ihl, 8,
 		       datalen);
@@ -757,7 +757,7 @@
 
 	IP_NF_ASSERT((skb->nh.iph->frag_off & htons(IP_OFFSET)) == 0);
 
-	if (!get_tuple(skb->nh.iph, skb->len, &tuple, proto))
+	if (!ip_ct_get_tuple(skb->nh.iph, skb->len, &tuple, proto))
 		return NULL;
 
 	/* look for tuple match */
diff -urN linux-2.4.28-bk7/net/ipv4/netfilter/ip_conntrack_standalone.c linux-2.4.29/net/ipv4/netfilter/ip_conntrack_standalone.c
--- linux-2.4.28-bk7/net/ipv4/netfilter/ip_conntrack_standalone.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/net/ipv4/netfilter/ip_conntrack_standalone.c	2005-01-19 07:08:14.679708139 -0800
@@ -468,6 +468,7 @@
 EXPORT_SYMBOL(ip_conntrack_protocol_register);
 EXPORT_SYMBOL(ip_conntrack_protocol_unregister);
 EXPORT_SYMBOL(invert_tuplepr);
+EXPORT_SYMBOL(ip_ct_get_tuple);
 EXPORT_SYMBOL(ip_conntrack_alter_reply);
 EXPORT_SYMBOL(ip_conntrack_destroyed);
 EXPORT_SYMBOL(ip_conntrack_get);
diff -urN linux-2.4.28-bk7/net/ipv4/netfilter/ip_fw_compat_masq.c linux-2.4.29/net/ipv4/netfilter/ip_fw_compat_masq.c
--- linux-2.4.28-bk7/net/ipv4/netfilter/ip_fw_compat_masq.c	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29/net/ipv4/netfilter/ip_fw_compat_masq.c	2005-01-19 07:08:14.679708139 -0800
@@ -157,7 +157,7 @@
 	case IPPROTO_UDP:
 		IP_NF_ASSERT(((*pskb)->nh.iph->frag_off & htons(IP_OFFSET)) == 0);
 
-		if (!get_tuple(iph, (*pskb)->len, &tuple, protocol)) {
+		if (!ip_ct_get_tuple(iph, (*pskb)->len, &tuple, protocol)) {
 			if (net_ratelimit())
 				printk("ip_fw_compat_masq: Can't get tuple\n");
 			return NF_ACCEPT;
diff -urN linux-2.4.28-bk7/net/ipv4/netfilter/ip_nat_core.c linux-2.4.29/net/ipv4/netfilter/ip_nat_core.c
--- linux-2.4.28-bk7/net/ipv4/netfilter/ip_nat_core.c	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29/net/ipv4/netfilter/ip_nat_core.c	2005-01-19 07:08:14.680708183 -0800
@@ -198,7 +198,6 @@
 		return NULL;
 }
 
-#ifdef CONFIG_IP_NF_NAT_LOCAL
 /* If it's really a local destination manip, it may need to do a
    source manip too. */
 static int
@@ -217,7 +216,6 @@
 	ip_rt_put(rt);
 	return 1;
 }
-#endif
 
 /* Simple way to iterate through all. */
 static inline int fake_cmp(const struct ip_nat_hash *i,
@@ -317,7 +315,6 @@
 			 * do_extra_mangle last time. */
 			*other_ipp = saved_ip;
 
-#ifdef CONFIG_IP_NF_NAT_LOCAL
 			if (hooknum == NF_IP_LOCAL_OUT
 			    && *var_ipp != orig_dstip
 			    && !do_extra_mangle(*var_ipp, other_ipp)) {
@@ -328,7 +325,6 @@
 				 * anyway. */
 				continue;
 			}
-#endif
 
 			/* Count how many others map onto this. */
 			score = count_maps(tuple->src.ip, tuple->dst.ip,
@@ -372,13 +368,11 @@
 		else {
 			/* Only do extra mangle when required (breaks
                            socket binding) */
-#ifdef CONFIG_IP_NF_NAT_LOCAL
 			if (tuple->dst.ip != mr->range[0].min_ip
 			    && hooknum == NF_IP_LOCAL_OUT
 			    && !do_extra_mangle(mr->range[0].min_ip,
 						&tuple->src.ip))
 				return NULL;
-#endif
 			tuple->dst.ip = mr->range[0].min_ip;
 		}
 	}
@@ -501,10 +495,8 @@
 static unsigned int opposite_hook[NF_IP_NUMHOOKS]
 = { [NF_IP_PRE_ROUTING] = NF_IP_POST_ROUTING,
     [NF_IP_POST_ROUTING] = NF_IP_PRE_ROUTING,
-#ifdef CONFIG_IP_NF_NAT_LOCAL
     [NF_IP_LOCAL_OUT] = NF_IP_LOCAL_IN,
     [NF_IP_LOCAL_IN] = NF_IP_LOCAL_OUT,
-#endif
 };
 
 unsigned int
@@ -868,6 +860,23 @@
 	/* not reached */
 }
 
+static inline int tuple_src_equal_dst(const struct ip_conntrack_tuple *t1,
+                                      const struct ip_conntrack_tuple *t2)
+{
+	if (t1->dst.protonum != t2->dst.protonum || t1->src.ip != t2->dst.ip)
+		return 0;
+	if (t1->dst.protonum != IPPROTO_ICMP)
+		return t1->src.u.all == t2->dst.u.all;
+	else {
+		struct ip_conntrack_tuple inv;
+
+		/* ICMP tuples are asymetric */
+		invert_tuplepr(&inv, t1);
+		return inv.src.u.all == t2->src.u.all &&
+		       inv.dst.u.all == t2->dst.u.all;
+	}
+}
+
 unsigned int
 icmp_reply_translation(struct sk_buff *skb,
 		       struct ip_conntrack *conntrack,
@@ -880,6 +889,7 @@
 	size_t datalen = skb->len - ((void *)inner - (void *)iph);
 	unsigned int i;
 	struct ip_nat_info *info = &conntrack->nat.info;
+	struct ip_conntrack_tuple *cttuple, innertuple;
 
 	IP_NF_ASSERT(skb->len >= iph->ihl*4 + sizeof(struct icmphdr));
 	/* Must be RELATED */
@@ -914,6 +924,11 @@
 	   such addresses are not too uncommon, as Alan Cox points
 	   out) */
 
+	if (!ip_ct_get_tuple(inner, datalen, &innertuple,
+	                     ip_ct_find_proto(inner->protocol)))
+		return 0;
+	cttuple = &conntrack->tuplehash[dir].tuple;
+
 	READ_LOCK(&ip_nat_lock);
 	for (i = 0; i < info->num_manips; i++) {
 		DEBUGP("icmp_reply: manip %u dir %s hook %u\n",
@@ -923,35 +938,49 @@
 		if (info->manips[i].direction != dir)
 			continue;
 
-		/* Mapping the inner packet is just like a normal
-		   packet, except it was never src/dst reversed, so
-		   where we would normally apply a dst manip, we apply
-		   a src, and vice versa. */
-		if (info->manips[i].hooknum == hooknum) {
-			DEBUGP("icmp_reply: inner %s -> %u.%u.%u.%u %u\n",
-			       info->manips[i].maniptype == IP_NAT_MANIP_SRC
-			       ? "DST" : "SRC",
-			       NIPQUAD(info->manips[i].manip.ip),
-			       ntohs(info->manips[i].manip.u.udp.port));
-			manip_pkt(inner->protocol, inner,
-				  skb->len - ((void *)inner - (void *)iph),
-				  &info->manips[i].manip,
-				  !info->manips[i].maniptype,
-				  &skb->nfcache);
-			/* Outer packet needs to have IP header NATed like
-	                   it's a reply. */
-
-			/* Use mapping to map outer packet: 0 give no
-                           per-proto mapping */
-			DEBUGP("icmp_reply: outer %s -> %u.%u.%u.%u\n",
-			       info->manips[i].maniptype == IP_NAT_MANIP_SRC
-			       ? "SRC" : "DST",
-			       NIPQUAD(info->manips[i].manip.ip));
-			manip_pkt(0, iph, skb->len,
-				  &info->manips[i].manip,
-				  info->manips[i].maniptype,
-				  &skb->nfcache);
+		/* Mapping the inner packet is just like a normal packet, except
+		 * it was never src/dst reversed, so where we would normally
+		 * apply a dst manip, we apply a src, and vice versa. */
+
+		/* Only true for forwarded packets, locally generated packets
+		 * never hit PRE_ROUTING, we need to apply their PRE_ROUTING
+		 * manips in LOCAL_OUT. */
+		if (hooknum == NF_IP_LOCAL_OUT &&
+		    info->manips[i].hooknum == NF_IP_PRE_ROUTING)
+			hooknum = info->manips[i].hooknum;
+
+		if (info->manips[i].hooknum != hooknum)
+			continue;
+
+		/* ICMP errors may be generated locally for packets that
+		 * don't have all NAT manips applied yet. Verify manips
+		 * have been applied before reversing them */
+		if (info->manips[i].maniptype == IP_NAT_MANIP_SRC) {
+			if (!tuple_src_equal_dst(cttuple, &innertuple))
+				continue;
+		} else {
+			if (!tuple_src_equal_dst(&innertuple, cttuple))
+				continue;
 		}
+
+		DEBUGP("icmp_reply: inner %s -> %u.%u.%u.%u %u\n",
+		       info->manips[i].maniptype == IP_NAT_MANIP_SRC
+		       ? "DST" : "SRC", NIPQUAD(info->manips[i].manip.ip),
+		       ntohs(info->manips[i].manip.u.udp.port));
+		manip_pkt(inner->protocol, inner,
+			  skb->len - ((void *)inner - (void *)iph),
+			  &info->manips[i].manip, !info->manips[i].maniptype,
+			  &skb->nfcache);
+		/* Outer packet needs to have IP header NATed like
+                   it's a reply. */
+
+		/* Use mapping to map outer packet: 0 give no
+                          per-proto mapping */
+		DEBUGP("icmp_reply: outer %s -> %u.%u.%u.%u\n",
+		       info->manips[i].maniptype == IP_NAT_MANIP_SRC
+		       ? "SRC" : "DST", NIPQUAD(info->manips[i].manip.ip));
+		manip_pkt(0, iph, skb->len, &info->manips[i].manip,
+			  info->manips[i].maniptype, &skb->nfcache);
 	}
 	READ_UNLOCK(&ip_nat_lock);
 
diff -urN linux-2.4.28-bk7/net/ipv4/netfilter/ip_nat_rule.c linux-2.4.29/net/ipv4/netfilter/ip_nat_rule.c
--- linux-2.4.28-bk7/net/ipv4/netfilter/ip_nat_rule.c	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29/net/ipv4/netfilter/ip_nat_rule.c	2005-01-19 07:08:14.681708226 -0800
@@ -138,12 +138,8 @@
 	struct ip_conntrack *ct;
 	enum ip_conntrack_info ctinfo;
 
-#ifdef CONFIG_IP_NF_NAT_LOCAL
 	IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING
 		     || hooknum == NF_IP_LOCAL_OUT);
-#else
-	IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING);
-#endif
 
 	ct = ip_conntrack_get(*pskb, &ctinfo);
 
@@ -221,13 +217,6 @@
 		return 0;
 	}
 	
-#ifndef CONFIG_IP_NF_NAT_LOCAL
-	if (hook_mask & (1 << NF_IP_LOCAL_OUT)) {
-		DEBUGP("DNAT: CONFIG_IP_NF_NAT_LOCAL not enabled\n");
-		return 0;
-	}
-#endif
-
 	return 1;
 }
 
diff -urN linux-2.4.28-bk7/net/ipv4/netfilter/ip_nat_standalone.c linux-2.4.29/net/ipv4/netfilter/ip_nat_standalone.c
--- linux-2.4.28-bk7/net/ipv4/netfilter/ip_nat_standalone.c	2004-04-14 06:05:41.000000000 -0700
+++ linux-2.4.29/net/ipv4/netfilter/ip_nat_standalone.c	2005-01-19 07:08:14.682708269 -0800
@@ -114,16 +114,7 @@
 		WRITE_LOCK(&ip_nat_lock);
 		/* Seen it before?  This can happen for loopback, retrans,
 		   or local packets.. */
-		if (!(info->initialized & (1 << maniptype))
-#ifndef CONFIG_IP_NF_NAT_LOCAL
-		    /* If this session has already been confirmed we must not
-		     * touch it again even if there is no mapping set up.
-		     * Can only happen on local->local traffic with
-		     * CONFIG_IP_NF_NAT_LOCAL disabled.
-		     */
-		    && !(ct->status & IPS_CONFIRMED)
-#endif
-		    ) {
+		if (!(info->initialized & (1 << maniptype))) {
 			unsigned int ret;
 
 			if (ct->master
@@ -132,15 +123,14 @@
 				ret = call_expect(master_ct(ct), pskb, 
 						  hooknum, ct, info);
 			} else {
-#ifdef CONFIG_IP_NF_NAT_LOCAL
 				/* LOCAL_IN hook doesn't have a chain!  */
 				if (hooknum == NF_IP_LOCAL_IN)
 					ret = alloc_null_binding(ct, info,
 								 hooknum);
 				else
-#endif
-				ret = ip_nat_rule_find(pskb, hooknum, in, out,
-						       ct, info);
+					ret = ip_nat_rule_find(pskb, hooknum,
+					                       in, out,
+					                       ct, info);
 			}
 
 			if (ret != NF_ACCEPT) {
@@ -166,6 +156,29 @@
 }
 
 static unsigned int
+ip_nat_in(unsigned int hooknum,
+          struct sk_buff **pskb,
+          const struct net_device *in,
+          const struct net_device *out,
+          int (*okfn)(struct sk_buff *))
+{
+	u_int32_t saddr, daddr;
+	unsigned int ret;
+
+	saddr = (*pskb)->nh.iph->saddr;
+	daddr = (*pskb)->nh.iph->daddr;
+
+	ret = ip_nat_fn(hooknum, pskb, in, out, okfn);
+	if (ret != NF_DROP && ret != NF_STOLEN
+	    && ((*pskb)->nh.iph->saddr != saddr
+	        || (*pskb)->nh.iph->daddr != daddr)) {
+		dst_release((*pskb)->dst);
+		(*pskb)->dst = NULL;
+	}
+	return ret;
+}
+
+static unsigned int
 ip_nat_out(unsigned int hooknum,
 	   struct sk_buff **pskb,
 	   const struct net_device *in,
@@ -197,7 +210,6 @@
 	return ip_nat_fn(hooknum, pskb, in, out, okfn);
 }
 
-#ifdef CONFIG_IP_NF_NAT_LOCAL
 static unsigned int
 ip_nat_local_fn(unsigned int hooknum,
 		struct sk_buff **pskb,
@@ -223,25 +235,21 @@
 		return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP;
 	return ret;
 }
-#endif
 
 /* We must be after connection tracking and before packet filtering. */
 
 /* Before packet filtering, change destination */
 static struct nf_hook_ops ip_nat_in_ops
-= { { NULL, NULL }, ip_nat_fn, PF_INET, NF_IP_PRE_ROUTING, NF_IP_PRI_NAT_DST };
+= { { NULL, NULL }, ip_nat_in, PF_INET, NF_IP_PRE_ROUTING, NF_IP_PRI_NAT_DST };
 /* After packet filtering, change source */
 static struct nf_hook_ops ip_nat_out_ops
 = { { NULL, NULL }, ip_nat_out, PF_INET, NF_IP_POST_ROUTING, NF_IP_PRI_NAT_SRC};
-
-#ifdef CONFIG_IP_NF_NAT_LOCAL
 /* Before packet filtering, change destination */
 static struct nf_hook_ops ip_nat_local_out_ops
 = { { NULL, NULL }, ip_nat_local_fn, PF_INET, NF_IP_LOCAL_OUT, NF_IP_PRI_NAT_DST };
 /* After packet filtering, change source for reply packets of LOCAL_OUT DNAT */
 static struct nf_hook_ops ip_nat_local_in_ops
 = { { NULL, NULL }, ip_nat_fn, PF_INET, NF_IP_LOCAL_IN, NF_IP_PRI_NAT_SRC };
-#endif
 
 /* Protocol registration. */
 int ip_nat_protocol_register(struct ip_nat_protocol *proto)
@@ -306,7 +314,6 @@
 		printk("ip_nat_init: can't register out hook.\n");
 		goto cleanup_inops;
 	}
-#ifdef CONFIG_IP_NF_NAT_LOCAL
 	ret = nf_register_hook(&ip_nat_local_out_ops);
 	if (ret < 0) {
 		printk("ip_nat_init: can't register local out hook.\n");
@@ -317,16 +324,13 @@
 		printk("ip_nat_init: can't register local in hook.\n");
 		goto cleanup_localoutops;
 	}
-#endif
 	return ret;
 
  cleanup:
-#ifdef CONFIG_IP_NF_NAT_LOCAL
 	nf_unregister_hook(&ip_nat_local_in_ops);
  cleanup_localoutops:
 	nf_unregister_hook(&ip_nat_local_out_ops);
  cleanup_outops:
-#endif
 	nf_unregister_hook(&ip_nat_out_ops);
  cleanup_inops:
 	nf_unregister_hook(&ip_nat_in_ops);
diff -urN linux-2.4.28-bk7/net/ipv4/netfilter/ip_tables.c linux-2.4.29/net/ipv4/netfilter/ip_tables.c
--- linux-2.4.28-bk7/net/ipv4/netfilter/ip_tables.c	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29/net/ipv4/netfilter/ip_tables.c	2005-01-19 07:08:14.683708313 -0800
@@ -1274,7 +1274,7 @@
 			       sizeof(info.underflow));
 			info.num_entries = t->private->number;
 			info.size = t->private->size;
-			strcpy(info.name, name);
+			memcpy(info.name, name, sizeof(info.name));
 
 			if (copy_to_user(user, &info, *len) != 0)
 				ret = -EFAULT;
diff -urN linux-2.4.28-bk7/net/ipv4/netfilter/ipt_MASQUERADE.c linux-2.4.29/net/ipv4/netfilter/ipt_MASQUERADE.c
--- linux-2.4.28-bk7/net/ipv4/netfilter/ipt_MASQUERADE.c	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29/net/ipv4/netfilter/ipt_MASQUERADE.c	2005-01-19 07:08:14.684708356 -0800
@@ -125,35 +125,58 @@
 }
 
 static inline int
-device_cmp(const struct ip_conntrack *i, void *_ina)
+device_cmp(const struct ip_conntrack *i, void *ifindex)
 {
-	int ret = 0;
-	struct in_ifaddr *ina = _ina;
+	int ret;
 
 	READ_LOCK(&masq_lock);
-	/* If it's masquerading out this interface with a different address,
-	 * or we don't know the new address of this interface. */
-	if (i->nat.masq_index == ina->ifa_dev->dev->ifindex
-	    && i->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip != ina->ifa_address)
-		ret = 1;
+	ret = (i->nat.masq_index == (int)(long)ifindex);
 	READ_UNLOCK(&masq_lock);
 
 	return ret;
 }
 
+static int masq_device_event(struct notifier_block *this,
+			     unsigned long event,
+			     void *ptr)
+{
+	struct net_device *dev = ptr;
+
+	if (event == NETDEV_DOWN) {
+		/* Device was downed.  Search entire table for
+		   conntracks which were associated with that device,
+		   and forget them. */
+		IP_NF_ASSERT(dev->ifindex != 0);
+ 
+		ip_ct_selective_cleanup(device_cmp, (void *)(long)dev->ifindex);
+	}
+
+	return NOTIFY_DONE;
+}
+
+
 static int masq_inet_event(struct notifier_block *this,
 			   unsigned long event,
 			   void *ptr)
 {
-	/* For some configurations, interfaces often come back with
-	 * the same address.  If not, clean up old conntrack
-	 * entries. */
-	if (event == NETDEV_UP)
-		ip_ct_selective_cleanup(device_cmp, ptr);
+	struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev;
+
+	if (event == NETDEV_DOWN) {
+		/* IP address was deleted.  Search entire table for
+		   conntracks which were associated with that device,
+		   and forget them. */
+		IP_NF_ASSERT(dev->ifindex != 0);
+
+		ip_ct_selective_cleanup(device_cmp, (void *)(long)dev->ifindex);
+	}
 
 	return NOTIFY_DONE;
 }
 
+static struct notifier_block masq_dev_notifier = {
+	.notifier_call  = masq_device_event,
+};
+
 static struct notifier_block masq_inet_notifier = {
 	.notifier_call = masq_inet_event
 };
@@ -168,9 +191,12 @@
 
 	ret = ipt_register_target(&masquerade);
 
-	if (ret == 0)
+	if (ret == 0) {
+		/* Register for device down reports */
+		register_netdevice_notifier(&masq_dev_notifier);
 		/* Register IP address change reports */
 		register_inetaddr_notifier(&masq_inet_notifier);
+	}
 
 	return ret;
 }
@@ -178,6 +204,7 @@
 static void __exit fini(void)
 {
 	ipt_unregister_target(&masquerade);
+	unregister_netdevice_notifier(&masq_dev_notifier);
 	unregister_inetaddr_notifier(&masq_inet_notifier);	
 }
 
diff -urN linux-2.4.28-bk7/net/ipv4/netfilter/ipt_REJECT.c linux-2.4.29/net/ipv4/netfilter/ipt_REJECT.c
--- linux-2.4.28-bk7/net/ipv4/netfilter/ipt_REJECT.c	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29/net/ipv4/netfilter/ipt_REJECT.c	2005-01-19 07:08:14.684708356 -0800
@@ -22,18 +22,6 @@
 #define DEBUGP(format, args...)
 #endif
 
-/* If the original packet is part of a connection, but the connection
-   is not confirmed, our manufactured reply will not be associated
-   with it, so we need to do this manually. */
-static void connection_attach(struct sk_buff *new_skb, struct nf_ct_info *nfct)
-{
-	void (*attach)(struct sk_buff *, struct nf_ct_info *);
-
-	/* Avoid module unload race with ip_ct_attach being NULLed out */
-	if (nfct && (attach = ip_ct_attach) != NULL)
-		attach(new_skb, nfct);
-}
-
 static inline struct rtable *route_reverse(struct sk_buff *skb, int hook)
 {
 	struct iphdr *iph = skb->nh.iph;
@@ -187,7 +175,7 @@
 	if (nskb->len > nskb->dst->pmtu)
 		goto free_nskb;
 
-	connection_attach(nskb, oldskb->nfct);
+	nf_ct_attach(nskb, oldskb);
 
 	NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
 		ip_finish_output);
@@ -323,7 +311,7 @@
 	icmph->checksum = ip_compute_csum((unsigned char *)icmph,
 					  length - sizeof(struct iphdr));
 
-	connection_attach(nskb, skb_in->nfct);
+	nf_ct_attach(nskb, skb_in);
 
 	NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
 		ip_finish_output);
diff -urN linux-2.4.28-bk7/net/ipv4/raw.c linux-2.4.29/net/ipv4/raw.c
--- linux-2.4.28-bk7/net/ipv4/raw.c	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29/net/ipv4/raw.c	2005-01-19 07:08:14.685708399 -0800
@@ -266,7 +266,7 @@
  */
   
 static int raw_getfrag(const void *p, char *to, unsigned int offset,
-			unsigned int fraglen)
+		       unsigned int fraglen, struct sk_buff *skb)
 {
 	struct rawfakehdr *rfh = (struct rawfakehdr *) p;
 	return memcpy_fromiovecend(to, rfh->iov, offset, fraglen);
@@ -277,7 +277,7 @@
  */
  
 static int raw_getrawfrag(const void *p, char *to, unsigned int offset,
-				unsigned int fraglen)
+				unsigned int fraglen, struct sk_buff *skb)
 {
 	struct rawfakehdr *rfh = (struct rawfakehdr *) p;
 
diff -urN linux-2.4.28-bk7/net/ipv4/tcp_input.c linux-2.4.29/net/ipv4/tcp_input.c
--- linux-2.4.28-bk7/net/ipv4/tcp_input.c	2005-01-19 07:07:43.579361163 -0800
+++ linux-2.4.29/net/ipv4/tcp_input.c	2005-01-19 07:08:14.688708529 -0800
@@ -2908,8 +2908,8 @@
 							tp->snd_wscale = *(__u8 *)ptr;
 							if(tp->snd_wscale > 14) {
 								if(net_ratelimit())
-									printk("tcp_parse_options: Illegal window "
-									       "scaling value %d >14 received.",
+									printk(KERN_INFO "tcp_parse_options: Illegal window "
+									       "scaling value %d >14 received.\n",
 									       tp->snd_wscale);
 								tp->snd_wscale = 14;
 							}
@@ -3145,7 +3145,7 @@
 			/* Only TCP_LISTEN and TCP_CLOSE are left, in these
 			 * cases we should never reach this piece of code.
 			 */
-			printk("tcp_fin: Impossible, sk->state=%d\n", sk->state);
+			printk(KERN_ERR "tcp_fin: Impossible, sk->state=%d\n", sk->state);
 			break;
 	};
 
diff -urN linux-2.4.28-bk7/net/ipv4/udp.c linux-2.4.29/net/ipv4/udp.c
--- linux-2.4.28-bk7/net/ipv4/udp.c	2004-08-07 16:26:07.000000000 -0700
+++ linux-2.4.29/net/ipv4/udp.c	2005-01-19 07:08:14.690708616 -0800
@@ -371,7 +371,6 @@
 	sock_put(sk);
 }
 
-
 static unsigned short udp_check(struct udphdr *uh, int len, unsigned long saddr, unsigned long daddr, unsigned long base)
 {
 	return(csum_tcpudp_magic(saddr, daddr, len, IPPROTO_UDP, base));
@@ -390,7 +389,8 @@
  *	Copy and checksum a UDP packet from user space into a buffer.
  */
  
-static int udp_getfrag(const void *p, char * to, unsigned int offset, unsigned int fraglen) 
+static int udp_getfrag(const void *p, char * to, unsigned int offset,
+                       unsigned int fraglen, struct sk_buff *skb)
 {
 	struct udpfakehdr *ufh = (struct udpfakehdr *)p;
 	if (offset==0) {
@@ -417,7 +417,8 @@
  *	Copy a UDP packet from user space into a buffer without checksumming.
  */
  
-static int udp_getfrag_nosum(const void *p, char * to, unsigned int offset, unsigned int fraglen) 
+static int udp_getfrag_nosum(const void *p, char * to, unsigned int offset,
+                             unsigned int fraglen, struct sk_buff *skb) 
 {
 	struct udpfakehdr *ufh = (struct udpfakehdr *)p;
 
@@ -636,6 +637,55 @@
 		__udp_checksum_complete(skb);
 }
 
+
+/**
+ * 	udp_poll - wait for a UDP event.
+ *	@file - file struct
+ *	@sock - socket
+ *	@wait - poll table
+ *
+ *	This is same as datagram poll, except for the special case of 
+ *	blocking sockets. If application is using a blocking fd
+ *	and a packet with checksum error is in the queue;
+ *	then it could get return from select indicating data available
+ *	but then block when reading it. Add special case code
+ *	to work around these arguably broken applications.
+ */
+unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait)
+{
+	unsigned int mask = datagram_poll(file, sock, wait);
+	struct sock *sk = sock->sk;
+	
+	/* Check for false positives due to checksum errors */
+	if ( (mask & POLLRDNORM) &&
+	     !(file->f_flags & O_NONBLOCK) &&
+	     !(sk->shutdown & RCV_SHUTDOWN)){
+		struct sk_buff_head *rcvq = &sk->receive_queue;
+		struct sk_buff *skb;
+
+		spin_lock_irq(&rcvq->lock);
+		while ((skb = skb_peek(rcvq)) != NULL) {
+			if (udp_checksum_complete(skb)) {
+				UDP_INC_STATS_BH(UdpInErrors);
+				IP_INC_STATS_BH(IpInDiscards);
+				__skb_unlink(skb, rcvq);
+				kfree_skb(skb);
+			} else {
+				skb->ip_summed = CHECKSUM_UNNECESSARY;
+				break;
+			}
+		}
+		spin_unlock_irq(&rcvq->lock);
+
+		/* nothing to see, move along */
+		if (skb == NULL)
+			mask &= ~(POLLIN | POLLRDNORM);
+	}
+
+	return mask;
+	
+}
+
 /*
  * 	This should be easy, if there is something there we
  * 	return it, otherwise we block.
diff -urN linux-2.4.28-bk7/net/ipv6/af_inet6.c linux-2.4.29/net/ipv6/af_inet6.c
--- linux-2.4.28-bk7/net/ipv6/af_inet6.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/net/ipv6/af_inet6.c	2005-01-19 07:08:14.691708659 -0800
@@ -497,6 +497,27 @@
 	socketpair:	sock_no_socketpair,		/* a do nothing	*/
 	accept:		sock_no_accept,			/* a do nothing	*/
 	getname:	inet6_getname, 
+	poll:		udp_poll,			/* ok		*/
+	ioctl:		inet6_ioctl,			/* must change  */
+	listen:		sock_no_listen,			/* ok		*/
+	shutdown:	inet_shutdown,			/* ok		*/
+	setsockopt:	inet_setsockopt,		/* ok		*/
+	getsockopt:	inet_getsockopt,		/* ok		*/
+	sendmsg:	inet_sendmsg,			/* ok		*/
+	recvmsg:	inet_recvmsg,			/* ok		*/
+	mmap:		sock_no_mmap,
+	sendpage:	sock_no_sendpage,
+};
+
+struct proto_ops inet6_sockraw_ops = {
+	family:		PF_INET6,
+
+	release:	inet6_release,
+	bind:		inet6_bind,
+	connect:	inet_dgram_connect,		/* ok		*/
+	socketpair:	sock_no_socketpair,		/* a do nothing	*/
+	accept:		sock_no_accept,			/* a do nothing	*/
+	getname:	inet6_getname, 
 	poll:		datagram_poll,			/* ok		*/
 	ioctl:		inet6_ioctl,			/* must change  */
 	listen:		sock_no_listen,			/* ok		*/
@@ -532,7 +553,7 @@
 	type:        SOCK_RAW,
 	protocol:    IPPROTO_IP,	/* wild card */
 	prot:        &rawv6_prot,
-	ops:         &inet6_dgram_ops,
+	ops:         &inet6_sockraw_ops,
 	capability:  CAP_NET_RAW,
 	no_check:    UDP_CSUM_DEFAULT,
 	flags:       INET_PROTOSW_REUSE,
diff -urN linux-2.4.28-bk7/net/ipv6/datagram.c linux-2.4.29/net/ipv6/datagram.c
--- linux-2.4.28-bk7/net/ipv6/datagram.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/net/ipv6/datagram.c	2005-01-19 07:08:14.691708659 -0800
@@ -260,9 +260,7 @@
 
 	for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
 
-		if (cmsg->cmsg_len < sizeof(struct cmsghdr) ||
-		    (unsigned long)(((char*)cmsg - (char*)msg->msg_control)
-				    + cmsg->cmsg_len) > msg->msg_controllen) {
+		if (!CMSG_OK(msg, cmsg)) {
 			err = -EINVAL;
 			goto exit_f;
 		}
diff -urN linux-2.4.28-bk7/net/ipv6/mcast.c linux-2.4.29/net/ipv6/mcast.c
--- linux-2.4.28-bk7/net/ipv6/mcast.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/net/ipv6/mcast.c	2005-01-19 07:08:14.692708703 -0800
@@ -386,12 +386,12 @@
 			goto done;
 		rv = !0;
 		for (i=0; i<psl->sl_count; i++) {
-			rv = memcmp(&psl->sl_addr, group,
+			rv = memcmp(&psl->sl_addr[i], source,
 				sizeof(struct in6_addr));
-			if (rv >= 0)
+			if (rv == 0)
 				break;
 		}
-		if (!rv)	/* source not found */
+		if (rv)		/* source not found */
 			goto done;
 
 		/* update the interface filter */
@@ -432,8 +432,8 @@
 	}
 	rv = 1;	/* > 0 for insert logic below if sl_count is 0 */
 	for (i=0; i<psl->sl_count; i++) {
-		rv = memcmp(&psl->sl_addr, group, sizeof(struct in6_addr));
-		if (rv >= 0)
+		rv = memcmp(&psl->sl_addr[i], source, sizeof(struct in6_addr));
+		if (rv == 0)
 			break;
 	}
 	if (rv == 0)		/* address already there is an error */
diff -urN linux-2.4.28-bk7/net/ipv6/netfilter/ip6_tables.c linux-2.4.29/net/ipv6/netfilter/ip6_tables.c
--- linux-2.4.28-bk7/net/ipv6/netfilter/ip6_tables.c	2004-08-07 16:26:07.000000000 -0700
+++ linux-2.4.29/net/ipv6/netfilter/ip6_tables.c	2005-01-19 07:08:14.694708789 -0800
@@ -149,14 +149,15 @@
 /* Returns whether matches rule or not. */
 static inline int
 ip6_packet_match(const struct sk_buff *skb,
-		 const struct ipv6hdr *ipv6,
 		 const char *indev,
 		 const char *outdev,
 		 const struct ip6t_ip6 *ip6info,
-		 int isfrag)
+		 unsigned int *protoff,
+		 int *fragoff)
 {
 	size_t i;
 	unsigned long ret;
+	const struct ipv6hdr *ipv6 = skb->nh.ipv6h;
 
 #define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg))
 
@@ -210,6 +211,7 @@
 		struct ipv6_opt_hdr *hdrptr;
 		u_int16_t ptr;		/* Header offset in skb */
 		u_int16_t hdrlen;	/* Header */
+		u_int16_t foff = 0;
 
 		ptr = IPV6_HDR_LEN;
 
@@ -229,6 +231,16 @@
 
 			/* Size calculation */
 	                if (currenthdr == IPPROTO_FRAGMENT) {
+				unsigned int foff_off;
+
+				foff_off = ptr + offsetof(struct frag_hdr,
+							  frag_off);
+				if (skb->len - foff_off < sizeof(foff))
+					return 0;
+
+				foff = ntohs(*(u_int16_t *)(skb->data
+							    + foff_off))
+				       & ~0x7;
 	                        hdrlen = 8;
 	                } else if (currenthdr == IPPROTO_AH)
 	                        hdrlen = (hdrptr->hdrlen+2)<<2;
@@ -240,8 +252,16 @@
 			/* ptr is too large */
 	                if ( ptr > skb->len ) 
 				return 0;
+			if (foff) {
+				if (ip6t_ext_hdr(currenthdr))
+					return 0;
+				break;
+			}
 		}
 
+		*protoff = ptr;
+		*fragoff = foff;
+
 		/* currenthdr contains the protocol header */
 
 		dprintf("Packet protocol %hi ?= %s%hi.\n",
@@ -329,10 +349,8 @@
 	      void *userdata)
 {
 	static const char nulldevname[IFNAMSIZ] = { 0 };
-	u_int16_t offset = 0;
-	struct ipv6hdr *ipv6;
-	void *protohdr;
-	u_int16_t datalen;
+	int offset = 0;
+	unsigned int protoff = 0;
 	int hotdrop = 0;
 	/* Initializing verdict to NF_DROP keeps gcc happy. */
 	unsigned int verdict = NF_DROP;
@@ -341,9 +359,6 @@
 	struct ip6t_entry *e, *back;
 
 	/* Initialization */
-	ipv6 = (*pskb)->nh.ipv6h;
-	protohdr = (u_int32_t *)((char *)ipv6 + IPV6_HDR_LEN);
-	datalen = (*pskb)->len - IPV6_HDR_LEN;
 	indev = in ? in->name : nulldevname;
 	outdev = out ? out->name : nulldevname;
 
@@ -381,17 +396,20 @@
 		IP_NF_ASSERT(e);
 		IP_NF_ASSERT(back);
 		(*pskb)->nfcache |= e->nfcache;
-		if (ip6_packet_match(*pskb, ipv6, indev, outdev, 
-			&e->ipv6, offset)) {
+		if (ip6_packet_match(*pskb, indev, outdev, &e->ipv6,
+				     &protoff, &offset)) {
 			struct ip6t_entry_target *t;
 
 			if (IP6T_MATCH_ITERATE(e, do_match,
 					       *pskb, in, out,
-					       offset, protohdr,
-					       datalen, &hotdrop) != 0)
+					       offset,
+					       (void *)((*pskb)->data
+							+ protoff),
+					       (*pskb)->len - protoff,
+					       &hotdrop) != 0)
 				goto no_match;
 
-			ADD_COUNTER(e->counters, ntohs(ipv6->payload_len) + IPV6_HDR_LEN, 1);
+			ADD_COUNTER(e->counters, ntohs((*pskb)->nh.ipv6h->payload_len) + IPV6_HDR_LEN, 1);
 
 			t = ip6t_get_target(e);
 			IP_NF_ASSERT(t->u.kernel.target);
@@ -447,11 +465,6 @@
 				((struct ip6t_entry *)table_base)->comefrom
 					= 0x57acc001;
 #endif
-				/* Target might have changed stuff. */
-				ipv6 = (*pskb)->nh.ipv6h;
-				protohdr = (u_int32_t *)((void *)ipv6 + IPV6_HDR_LEN);
-				datalen = (*pskb)->len - IPV6_HDR_LEN;
-
 				if (verdict == IP6T_CONTINUE)
 					e = (void *)e + e->next_offset;
 				else
@@ -1343,7 +1356,7 @@
 			       sizeof(info.underflow));
 			info.num_entries = t->private->number;
 			info.size = t->private->size;
-			strcpy(info.name, name);
+			memcpy(info.name, name, sizeof(info.name));
 
 			if (copy_to_user(user, &info, *len) != 0)
 				ret = -EFAULT;
@@ -1567,10 +1580,8 @@
 	  u_int16_t datalen,
 	  int *hotdrop)
 {
-	const struct tcphdr *tcp;
+	const struct tcphdr *tcp = hdr;
 	const struct ip6t_tcp *tcpinfo = matchinfo;
-	int tcpoff;
-	u8 nexthdr = skb->nh.ipv6h->nexthdr;
 
 	/* To quote Alan:
 
@@ -1591,24 +1602,6 @@
 		return 0;
 	}
 
-	tcpoff = (u8*)(skb->nh.ipv6h + 1) - skb->data;
-	tcpoff = ipv6_skip_exthdr(skb, tcpoff, &nexthdr, skb->len - tcpoff);
-	if (tcpoff < 0 || tcpoff > skb->len) {
-		duprintf("tcp_match: cannot skip exthdr. Dropping.\n");
-		*hotdrop = 1;
-		return 0;
-	} else if (nexthdr == IPPROTO_FRAGMENT)
-		return 0;
-	else if (nexthdr != IPPROTO_TCP ||
-		 skb->len - tcpoff < sizeof(struct tcphdr)) {
-		/* cannot be occured */
-		duprintf("tcp_match: cannot get TCP header. Dropping.\n");
-		*hotdrop = 1;
-		return 0;
-	}
-
-	tcp = (struct tcphdr *)(skb->data + tcpoff);
-
 	/* FIXME: Try tcp doff >> packet len against various stacks --RR */
 
 #define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg))
@@ -1659,10 +1652,8 @@
 	  u_int16_t datalen,
 	  int *hotdrop)
 {
-	const struct udphdr *udp;
+	const struct udphdr *udp = hdr;
 	const struct ip6t_udp *udpinfo = matchinfo;
-	int udpoff;
-	u8 nexthdr = skb->nh.ipv6h->nexthdr;
 
 	if (offset == 0 && datalen < sizeof(struct udphdr)) {
 		/* We've been asked to examine this packet, and we
@@ -1672,23 +1663,6 @@
 		return 0;
 	}
 
-	udpoff = (u8*)(skb->nh.ipv6h + 1) - skb->data;
-	udpoff = ipv6_skip_exthdr(skb, udpoff, &nexthdr, skb->len - udpoff);
-	if (udpoff < 0 || udpoff > skb->len) {
-		duprintf("udp_match: cannot skip exthdr. Dropping.\n");
-		*hotdrop = 1;
-		return 0;
-	} else if (nexthdr == IPPROTO_FRAGMENT)
-		return 0;
-	else if (nexthdr != IPPROTO_UDP ||
-		 skb->len - udpoff < sizeof(struct udphdr)) {
-		duprintf("udp_match: cannot get UDP header. Dropping.\n");
-		*hotdrop = 1;
-		return 0;
-	}
-
-	udp = (struct udphdr *)(skb->data + udpoff);
-
 	/* Must not be a fragment. */
 	return !offset
 		&& port_match(udpinfo->spts[0], udpinfo->spts[1],
diff -urN linux-2.4.28-bk7/net/ipv6/netfilter/ip6t_LOG.c linux-2.4.29/net/ipv6/netfilter/ip6t_LOG.c
--- linux-2.4.28-bk7/net/ipv6/netfilter/ip6t_LOG.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/net/ipv6/netfilter/ip6t_LOG.c	2005-01-19 07:08:14.695708832 -0800
@@ -35,54 +35,40 @@
 	ntohs((addr).s6_addr16[6]), \
 	ntohs((addr).s6_addr16[7])
 
-struct esphdr {
-	__u32   spi;
-}; /* FIXME evil kludge */
-        
-/* Use lock to serialize, so printks don't overlap */
-static spinlock_t log_lock = SPIN_LOCK_UNLOCKED;
+/* FIXME evil kludge */
 
-/* takes in current header and pointer to the header */
-/* if another header exists, sets hdrptr to the next header
-   and returns the new header value, else returns 0 */
-static u_int8_t ip6_nexthdr(u_int8_t currenthdr, u_int8_t **hdrptr)
-{
-	u_int8_t hdrlen, nexthdr = 0;
+struct ahhdr {
+	__u8  nexthdr;
+	__u8  hdrlen;
+	__u16 reserved;
+	__u32 spi;
+	__u32 seq_no;
+};
 
-	switch(currenthdr){
-		case IPPROTO_AH:
-		/* whoever decided to do the length of AUTH for ipv6
-		in 32bit units unlike other headers should be beaten...
-		repeatedly...with a large stick...no, an even LARGER
-		stick...no, you're still not thinking big enough */
-			nexthdr = **hdrptr;
-			hdrlen = (*hdrptr)[1] * 4 + 8;
-			*hdrptr = *hdrptr + hdrlen;
-			break;
-		/*stupid rfc2402 */
-		case IPPROTO_DSTOPTS:
-		case IPPROTO_ROUTING:
-		case IPPROTO_HOPOPTS:
-			nexthdr = **hdrptr;
-			hdrlen = (*hdrptr)[1] * 8 + 8;
-			*hdrptr = *hdrptr + hdrlen;
-			break;
-		case IPPROTO_FRAGMENT:
-			nexthdr = **hdrptr;
-			*hdrptr = *hdrptr + 8;
-			break;
-	}	
-	return nexthdr;
+struct esphdr {
+	__u32 spi;
+	__u32 seq_no;
+};
 
-}
+/* Use lock to serialize, so printks don't overlap */
+static spinlock_t log_lock = SPIN_LOCK_UNLOCKED;
 
 /* One level of recursion won't kill us */
 static void dump_packet(const struct ip6t_log_info *info,
-			struct ipv6hdr *ipv6h, int recurse)
+			const struct sk_buff *skb, unsigned int ip6hoff,
+			int recurse)
 {
-	u_int8_t currenthdr = ipv6h->nexthdr;
-	u_int8_t *hdrptr;
+	u_int8_t currenthdr;
 	int fragment;
+	struct ipv6hdr *ipv6h;
+	unsigned int ptr;
+	unsigned int hdrlen = 0;
+
+	if (skb->len - ip6hoff < sizeof(*ipv6h)) {
+		printk("TRUNCATED");
+		return;
+	}
+	ipv6h = (struct ipv6hdr *)(skb->data + ip6hoff);
 
 	/* Max length: 88 "SRC=0000.0000.0000.0000.0000.0000.0000.0000 DST=0000.0000.0000.0000.0000.0000.0000.0000" */
 	printk("SRC=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(ipv6h->saddr));
@@ -96,60 +82,131 @@
 	       (ntohl(*(u_int32_t *)ipv6h) & 0x000fffff));
 
 	fragment = 0;
-	hdrptr = (u_int8_t *)(ipv6h + 1);
-	while (currenthdr) {
-		if ((currenthdr == IPPROTO_TCP) ||
-		    (currenthdr == IPPROTO_UDP) ||
-		    (currenthdr == IPPROTO_ICMPV6))
-			break;
+	ptr = ip6hoff + sizeof(struct ipv6hdr);
+	currenthdr = ipv6h->nexthdr;
+	while (currenthdr != NEXTHDR_NONE && ip6t_ext_hdr(currenthdr)) {
+		struct ipv6_opt_hdr *hdr;
+
+		if (skb->len - ptr < sizeof(*hdr)) {
+			printk("TRUNCATED");
+			return;
+		}
+		hdr = (struct ipv6_opt_hdr *)(skb->data + ptr);
+
 		/* Max length: 48 "OPT (...) " */
-		printk("OPT ( ");
+		if (info->logflags & IP6T_LOG_IPOPT)
+			printk("OPT ( ");
+
 		switch (currenthdr) {
 		case IPPROTO_FRAGMENT: {
-			struct frag_hdr *fhdr = (struct frag_hdr *)hdrptr;
+			struct frag_hdr *fhdr;
 
-			/* Max length: 11 "FRAG:65535 " */
-			printk("FRAG:%u ", ntohs(fhdr->frag_off) & 0xFFF8);
+			printk("FRAG:");
+			if (skb->len - ptr < sizeof(*fhdr)) {
+				printk("TRUNCATED ");
+				return;
+			}
+			fhdr = (struct frag_hdr *)(skb->data + ptr);
+
+			/* Max length: 6 "65535 " */
+			printk("%u ", ntohs(fhdr->frag_off) & 0xFFF8);
 
 			/* Max length: 11 "INCOMPLETE " */
 			if (fhdr->frag_off & htons(0x0001))
 				printk("INCOMPLETE ");
 
-			printk("ID:%08x ", fhdr->identification);
+			printk("ID:%08x ", ntohl(fhdr->identification));
 
 			if (ntohs(fhdr->frag_off) & 0xFFF8)
 				fragment = 1;
 
+			hdrlen = 8;
+
 			break;
 		}
 		case IPPROTO_DSTOPTS:
 		case IPPROTO_ROUTING:
 		case IPPROTO_HOPOPTS:
+			if (fragment) {
+				if (info->logflags & IP6T_LOG_IPOPT)
+					printk(")");
+				return;
+			}
+			hdrlen = ipv6_optlen(hdr);
 			break;
 		/* Max Length */
 		case IPPROTO_AH:
+			if (info->logflags & IP6T_LOG_IPOPT) {
+				struct ahhdr *ah;
+
+				/* Max length: 3 "AH " */
+				printk("AH ");
+
+				if (fragment) {
+					printk(")");
+					return;
+				}
+
+				if (skb->len - ptr < sizeof(*ah)) {
+					/*
+					 * Max length: 26 "INCOMPLETE [65535 	
+					 *  bytes] )"
+					 */
+					printk("INCOMPLETE [%u bytes] )",
+					       skb->len - ptr);
+					return;
+				}
+				ah = (struct ahhdr *)(skb->data + ptr);
+
+				/* Length: 15 "SPI=0xF1234567 */
+				printk("SPI=0x%x ", ntohl(ah->spi));
+
+			}
+
+			hdrlen = (hdr->hdrlen+2)<<2;
+			break;
 		case IPPROTO_ESP:
 			if (info->logflags & IP6T_LOG_IPOPT) {
-				struct esphdr *esph = (struct esphdr *)hdrptr;
-				int esp = (currenthdr == IPPROTO_ESP);
+				struct esphdr *esph;
 
 				/* Max length: 4 "ESP " */
-				printk("%s ",esp ? "ESP" : "AH");
+				printk("ESP ");
+
+				if (fragment) {
+					printk(")");
+					return;
+				}
+
+				/*
+				 * Max length: 26 "INCOMPLETE [65535 bytes] )"
+				 */
+				if (skb->len - ptr < sizeof(*esph)) {
+					printk("INCOMPLETE [%u bytes] )",
+					       skb->len - ptr);
+					return;
+				}
+				esph = (struct esphdr *)(skb->data + ptr);
+
+				/* Length: 16 "SPI=0xF1234567 )" */
+				printk("SPI=0x%x )", ntohl(esph->spi) );
 
-				/* Length: 15 "SPI=0xF1234567 " */
-				printk("SPI=0x%x ", ntohl(esph->spi) );
-				break;
 			}
+			return;
 		default:
-			break;
+			/* Max length: 20 "Unknown Ext Hdr 255" */
+			printk("Unknown Ext Hdr %u", currenthdr);
+			return;
 		}
-		printk(") ");
-		currenthdr = ip6_nexthdr(currenthdr, &hdrptr);
+		if (info->logflags & IP6T_LOG_IPOPT)
+			printk(") ");
+
+		currenthdr = hdr->nexthdr;
+		ptr += hdrlen;
 	}
 
 	switch (currenthdr) {
 	case IPPROTO_TCP: {
-		struct tcphdr *tcph = (struct tcphdr *)hdrptr;
+		struct tcphdr *tcph;
 
 		/* Max length: 10 "PROTO=TCP " */
 		printk("PROTO=TCP ");
@@ -157,6 +214,13 @@
 		if (fragment)
 			break;
 
+		/* Max length: 25 "INCOMPLETE [65535 bytes] " */
+		if (skb->len - ptr < sizeof(*tcph)) {
+			printk("INCOMPLETE [%u bytes] ", skb->len - ptr);
+			return;
+		}
+		tcph = (struct tcphdr *)(skb->data + ptr);
+
 		/* Max length: 20 "SPT=65535 DPT=65535 " */
 		printk("SPT=%u DPT=%u ",
 		       ntohs(tcph->source), ntohs(tcph->dest));
@@ -166,7 +230,7 @@
 			       ntohl(tcph->seq), ntohl(tcph->ack_seq));
 		/* Max length: 13 "WINDOW=65535 " */
 		printk("WINDOW=%u ", ntohs(tcph->window));
-		/* Max length: 9 "RES=0x3F " */
+		/* Max length: 9 "RES=0x3C " */
 		printk("RES=0x%02x ", (u_int8_t)(ntohl(tcp_flag_word(tcph) & TCP_RESERVED_BITS) >> 22));
 		/* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */
 		if (tcph->cwr)
@@ -189,19 +253,29 @@
 		printk("URGP=%u ", ntohs(tcph->urg_ptr));
 
 		if ((info->logflags & IP6T_LOG_TCPOPT)
-		    && tcph->doff * 4 != sizeof(struct tcphdr)) {
+		    && tcph->doff * 4 > sizeof(struct tcphdr)) {
+			u_int8_t *op;
 			unsigned int i;
+			unsigned int optsize = tcph->doff * 4
+					       - sizeof(struct tcphdr);
+
+			if (skb->len - ptr - sizeof(struct tcphdr) < optsize) {
+				printk("OPT (TRUNCATED)");
+				return;
+			}
+			op = (u_int8_t *)(skb->data + ptr
+					  + sizeof(struct tcphdr));
 
 			/* Max length: 127 "OPT (" 15*4*2chars ") " */
 			printk("OPT (");
-			for (i =sizeof(struct tcphdr); i < tcph->doff * 4; i++)
-				printk("%02X", ((u_int8_t *)tcph)[i]);
+			for (i =0; i < optsize; i++)
+				printk("%02X", op[i]);
 			printk(") ");
 		}
 		break;
 	}
 	case IPPROTO_UDP: {
-		struct udphdr *udph = (struct udphdr *)hdrptr;
+		struct udphdr *udph;
 
 		/* Max length: 10 "PROTO=UDP " */
 		printk("PROTO=UDP ");
@@ -209,6 +283,13 @@
 		if (fragment)
 			break;
 
+		/* Max length: 25 "INCOMPLETE [65535 bytes] " */
+		if (skb->len - ptr < sizeof(*udph)) {
+			printk("INCOMPLETE [%u bytes] ", skb->len - ptr);
+			return;
+		}
+		udph = (struct udphdr *)(skb->data + ptr);
+
 		/* Max length: 20 "SPT=65535 DPT=65535 " */
 		printk("SPT=%u DPT=%u LEN=%u ",
 		       ntohs(udph->source), ntohs(udph->dest),
@@ -216,7 +297,7 @@
 		break;
 	}
 	case IPPROTO_ICMPV6: {
-		struct icmp6hdr *icmp6h = (struct icmp6hdr *)hdrptr;
+		struct icmp6hdr *icmp6h;
 
 		/* Max length: 13 "PROTO=ICMPv6 " */
 		printk("PROTO=ICMPv6 ");
@@ -224,6 +305,13 @@
 		if (fragment)
 			break;
 
+		/* Max length: 25 "INCOMPLETE [65535 bytes] " */
+		if (skb->len - ptr < sizeof(*icmp6h)) {
+			printk("INCOMPLETE [%u bytes] ", skb->len - ptr);
+			return;
+		}
+		icmp6h = (struct icmp6hdr *)(skb->data + ptr);
+
 		/* Max length: 18 "TYPE=255 CODE=255 " */
 		printk("TYPE=%u CODE=%u ", icmp6h->icmp6_type, icmp6h->icmp6_code);
 
@@ -250,7 +338,8 @@
 			/* Max length: 3+maxlen */
 			if (recurse) {
 				printk("[");
-				dump_packet(info, (struct ipv6hdr *)(icmp6h + 1), 0);
+				dump_packet(info, skb, ptr + sizeof(*icmp6h),
+					    0);
 				printk("] ");
 			}
 
@@ -260,7 +349,7 @@
 		}
 		break;
 	}
-	/* Max length: 10 "PROTO 255 " */
+	/* Max length: 10 "PROTO=255 " */
 	default:
 		printk("PROTO=%u ", currenthdr);
 	}
@@ -326,7 +415,8 @@
 			printk(" ");
 	}
 
-	dump_packet(loginfo, ipv6h, 1);
+	dump_packet(loginfo, (*pskb), (u8*)(*pskb)->nh.ipv6h - (*pskb)->data,
+		    1);
 	printk("\n");
 	spin_unlock_bh(&log_lock);
 
diff -urN linux-2.4.28-bk7/net/ipv6/netfilter/ip6t_dst.c linux-2.4.29/net/ipv6/netfilter/ip6t_dst.c
--- linux-2.4.28-bk7/net/ipv6/netfilter/ip6t_dst.c	2003-06-13 07:51:39.000000000 -0700
+++ linux-2.4.29/net/ipv6/netfilter/ip6t_dst.c	2005-01-19 07:08:14.696708876 -0800
@@ -11,8 +11,6 @@
 #include <linux/netfilter_ipv6/ip6_tables.h>
 #include <linux/netfilter_ipv6/ip6t_opts.h>
 
-#define LOW(n)		(n & 0x00FF)
-
 #define HOPBYHOP	0
 
 EXPORT_NO_SYMBOLS;
@@ -40,8 +38,8 @@
  *  	0	-> invariant
  *  	1	-> can change the routing
  *  (Type & 0x1F) Type
- *      0	-> PAD0 (only 1 byte!)
- *      1	-> PAD1 LENGTH info (total length = length + 2)
+ *      0	-> Pad1 (only 1 byte!)
+ *      1	-> PadN LENGTH info (total length = length + 2)
  *      C0 | 2	-> JUMBO 4 x x x x ( xxxx > 64k )
  *      5	-> RTALERT 2 x x
  */
@@ -64,7 +62,8 @@
        unsigned int ptr;
        unsigned int hdrlen = 0;
        unsigned int ret = 0;
-       u_int16_t *optdesc = NULL;
+       u8 *opttype = NULL;
+       unsigned int optlen;
        
        /* type of the 1st exthdr */
        nexthdr = skb->nh.ipv6h->nexthdr;
@@ -91,7 +90,7 @@
                      break;
               }
 
-              hdr=(void *)(skb->data)+ptr;
+	      hdr = (void *)(skb->data + ptr);
 
               /* Calculate the header length */
                 if (nexthdr == NEXTHDR_FRAGMENT) {
@@ -153,7 +152,7 @@
        		return 0;
        }
 
-       optsh=(void *)(skb->data)+ptr;
+       optsh = (void *)(skb->data + ptr);
 
        DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, optsh->hdrlen);
 
@@ -169,7 +168,6 @@
                            ((optinfo->hdrlen == hdrlen) ^
                            !!(optinfo->invflags & IP6T_OPTS_INV_LEN)));
 
-       temp = len = 0;
        ptr += 2;
        hdrlen -= 2;
        if ( !(optinfo->flags & IP6T_OPTS_OPTS) ){
@@ -180,48 +178,52 @@
 		DEBUGP("Strict ");
 		DEBUGP("#%d ",optinfo->optsnr);
 		for(temp=0; temp<optinfo->optsnr; temp++){
-			optdesc = (void *)(skb->data)+ptr;
+			/* type field exists ? */
+			if (ptr > skb->len - 1 || hdrlen < 1)
+				break;
+			opttype = (void *)(skb->data + ptr);
+
 			/* Type check */
-			if ( (unsigned char)*optdesc != 
-				(optinfo->opts[temp] & 0xFF00)>>8 ){
+			if (*opttype != (optinfo->opts[temp] & 0xFF00)>>8){
 				DEBUGP("Tbad %02X %02X\n",
-						(unsigned char)*optdesc,
-						(optinfo->opts[temp] &
-						 0xFF00)>>8);
+				       *opttype,
+				       (optinfo->opts[temp] & 0xFF00)>>8);
 				return 0;
 			} else {
 				DEBUGP("Tok ");
 			}
 			/* Length check */
-			if (((optinfo->opts[temp] & 0x00FF) != 0xFF) &&
-				(unsigned char)*optdesc != 0){
-				if ( ntohs((u16)*optdesc) != 
-						optinfo->opts[temp] ){
-					DEBUGP("Lbad %02X %04X %04X\n",
-							(unsigned char)*optdesc,
-							ntohs((u16)*optdesc),
-							optinfo->opts[temp]);
+			if (*opttype) {
+				u16 spec_len;
+
+				/* length field exists ? */
+				if (ptr > skb->len - 2 || hdrlen < 2)
+					break;
+				optlen = *((u8 *)(skb->data + ptr + 1));
+				spec_len = optinfo->opts[temp] & 0x00FF;
+
+				if (spec_len != 0x00FF && spec_len != optlen) {
+					DEBUGP("Lbad %02X %04X\n", optlen,
+					       spec_len);
 					return 0;
-				} else {
-					DEBUGP("Lok ");
 				}
-			}
-			/* Step to the next */
-			if ((unsigned char)*optdesc == 0){
-				DEBUGP("PAD0 \n");
-				ptr++;
-				hdrlen--;
+				DEBUGP("Lok ");
+				optlen += 2;
 			} else {
-				ptr += LOW(ntohs(*optdesc));
-				hdrlen -= LOW(ntohs(*optdesc));
-				DEBUGP("len%04X \n", 
-					LOW(ntohs(*optdesc)));
+				DEBUGP("Pad1\n");
+				optlen = 1;
 			}
-			if (ptr > skb->len || ( !hdrlen && 
-				(temp != optinfo->optsnr - 1))) {
+
+			/* Step to the next */
+			DEBUGP("len%04X \n", optlen);
+
+			if ((ptr > skb->len - optlen || hdrlen < optlen) &&
+			    (temp < optinfo->optsnr - 1)) {
 				DEBUGP("new pointer is too large! \n");
 				break;
 			}
+			ptr += optlen;
+			hdrlen -= optlen;
 		}
 		if (temp == optinfo->optsnr)
 			return ret;
diff -urN linux-2.4.28-bk7/net/ipv6/netfilter/ip6t_esp.c linux-2.4.29/net/ipv6/netfilter/ip6t_esp.c
--- linux-2.4.28-bk7/net/ipv6/netfilter/ip6t_esp.c	2003-08-25 04:44:44.000000000 -0700
+++ linux-2.4.29/net/ipv6/netfilter/ip6t_esp.c	2005-01-19 07:08:14.696708876 -0800
@@ -22,6 +22,7 @@
 
 struct esphdr {
 	__u32   spi;
+	__u32   seq_no;
 };
 
 /* Returns 1 if the spi is matched by the range, 0 otherwise */
diff -urN linux-2.4.28-bk7/net/ipv6/netfilter/ip6t_eui64.c linux-2.4.29/net/ipv6/netfilter/ip6t_eui64.c
--- linux-2.4.28-bk7/net/ipv6/netfilter/ip6t_eui64.c	2002-11-28 15:53:15.000000000 -0800
+++ linux-2.4.29/net/ipv6/netfilter/ip6t_eui64.c	2005-01-19 07:08:14.697708919 -0800
@@ -58,7 +58,7 @@
 {
 	if (hook_mask
 	    & ~((1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_IN) |
-		(1 << NF_IP6_PRE_ROUTING) )) {
+		(1 << NF_IP6_FORWARD))) {
 		printk("ip6t_eui64: only valid for PRE_ROUTING, LOCAL_IN or FORWARD.\n");
 		return 0;
 	}
diff -urN linux-2.4.28-bk7/net/ipv6/netfilter/ip6t_frag.c linux-2.4.29/net/ipv6/netfilter/ip6t_frag.c
--- linux-2.4.28-bk7/net/ipv6/netfilter/ip6t_frag.c	2003-08-25 04:44:44.000000000 -0700
+++ linux-2.4.29/net/ipv6/netfilter/ip6t_frag.c	2005-01-19 07:08:14.698708962 -0800
@@ -6,8 +6,6 @@
 #include <net/checksum.h>
 #include <net/ipv6.h>
 
-#include <asm/byteorder.h>
-
 #include <linux/netfilter_ipv6/ip6_tables.h>
 #include <linux/netfilter_ipv6/ip6t_frag.h>
 
@@ -22,28 +20,7 @@
 #define DEBUGP(format, args...)
 #endif
 
-#if 0
-#if     BYTE_ORDER == BIG_ENDIAN
-#define IP6F_OFF_MASK       0xfff8  /* mask out offset from _offlg */
-#define IP6F_RESERVED_MASK  0x0006  /* reserved bits in ip6f_offlg */
-#define IP6F_MORE_FRAG      0x0001  /* more-fragments flag */
-#else   /* BYTE_ORDER == LITTLE_ENDIAN */
-#define IP6F_OFF_MASK       0xf8ff  /* mask out offset from _offlg */
-#define IP6F_RESERVED_MASK  0x0600  /* reserved bits in ip6f_offlg */
-#define IP6F_MORE_FRAG      0x0100  /* more-fragments flag */
-#endif
-#endif
-
-#define IP6F_OFF_MASK       0xf8ff  /* mask out offset from _offlg */
-#define IP6F_RESERVED_MASK  0x0600  /* reserved bits in ip6f_offlg */
-#define IP6F_MORE_FRAG      0x0100  /* more-fragments flag */
-
-struct fraghdr {
-       __u8    nexthdr;
-       __u8    hdrlen;
-       __u16   info;
-       __u32   id;
-};
+#define IP6_MF	0x0001
 
 /* Returns 1 if the id is matched by the range, 0 otherwise */
 static inline int
@@ -67,7 +44,7 @@
       u_int16_t datalen,
       int *hotdrop)
 {
-       struct fraghdr *frag = NULL;
+       struct frag_hdr *frag = NULL;
        const struct ip6t_frag *fraginfo = matchinfo;
        unsigned int temp;
        int len;
@@ -100,7 +77,7 @@
                      break;
               }
 
-              hdr=(struct ipv6_opt_hdr *)skb->data+ptr;
+              hdr=(struct ipv6_opt_hdr *)(skb->data+ptr);
 
               /* Calculate the header length */
                 if (nexthdr == NEXTHDR_FRAGMENT) {
@@ -143,59 +120,62 @@
        /* FRAG header not found */
        if ( temp != MASK_FRAGMENT ) return 0;
 
-       if (len < (int)sizeof(struct fraghdr)){
+       if (len < sizeof(struct frag_hdr)){
 	       *hotdrop = 1;
        		return 0;
        }
 
-       frag = (struct fraghdr *) (skb->data + ptr);
+       frag = (struct frag_hdr *) (skb->data + ptr);
 
-       DEBUGP("IPv6 FRAG LEN %u %u ", hdrlen, frag->hdrlen);
-       DEBUGP("INFO %04X ", frag->info);
-       DEBUGP("OFFSET %04X ", frag->info & IP6F_OFF_MASK);
-       DEBUGP("RES %04X ", frag->info & IP6F_RESERVED_MASK);
-       DEBUGP("MF %04X ", frag->info & IP6F_MORE_FRAG);
-       DEBUGP("ID %u %08X\n", ntohl(frag->id), ntohl(frag->id));
+       DEBUGP("INFO %04X ", frag->frag_off);
+       DEBUGP("OFFSET %04X ", ntohs(frag->frag_off) & ~0x7);
+       DEBUGP("RES %02X %04X", frag->reserved, ntohs(frag->frag_off) & 0x6);
+       DEBUGP("MF %04X ", frag->frag_off & htons(IP6_MF));
+       DEBUGP("ID %u %08X\n", ntohl(frag->identification),
+	      ntohl(frag->identification));
 
        DEBUGP("IPv6 FRAG id %02X ",
        		(id_match(fraginfo->ids[0], fraginfo->ids[1],
-                           ntohl(frag->id),
+                           ntohl(frag->identification),
                            !!(fraginfo->invflags & IP6T_FRAG_INV_IDS))));
-       DEBUGP("len %02X %04X %02X ",
-       		fraginfo->hdrlen, hdrlen,
-       		(!fraginfo->hdrlen ||
-                           (fraginfo->hdrlen == hdrlen) ^
-                           !!(fraginfo->invflags & IP6T_FRAG_INV_LEN)));
-       DEBUGP("res %02X %02X %02X ", 
-       		(fraginfo->flags & IP6T_FRAG_RES), frag->info & IP6F_RESERVED_MASK,
-       		!((fraginfo->flags & IP6T_FRAG_RES) && (frag->info & IP6F_RESERVED_MASK)));
+       DEBUGP("res %02X %02X%04X %02X ", 
+       		(fraginfo->flags & IP6T_FRAG_RES), frag->reserved,
+		ntohs(frag->frag_off) & 0x6,
+       		!((fraginfo->flags & IP6T_FRAG_RES)
+			&& (frag->reserved || (ntohs(frag->frag_off) & 0x6))));
        DEBUGP("first %02X %02X %02X ", 
-       		(fraginfo->flags & IP6T_FRAG_FST), frag->info & IP6F_OFF_MASK,
-       		!((fraginfo->flags & IP6T_FRAG_FST) && (frag->info & IP6F_OFF_MASK)));
+       		(fraginfo->flags & IP6T_FRAG_FST),
+		ntohs(frag->frag_off) & ~0x7,
+       		!((fraginfo->flags & IP6T_FRAG_FST)
+			&& (ntohs(frag->frag_off) & ~0x7)));
        DEBUGP("mf %02X %02X %02X ", 
-       		(fraginfo->flags & IP6T_FRAG_MF), frag->info & IP6F_MORE_FRAG,
-       		!((fraginfo->flags & IP6T_FRAG_MF) && !((frag->info & IP6F_MORE_FRAG))));
+       		(fraginfo->flags & IP6T_FRAG_MF),
+		ntohs(frag->frag_off) & IP6_MF,
+       		!((fraginfo->flags & IP6T_FRAG_MF)
+			&& !((ntohs(frag->frag_off) & IP6_MF))));
        DEBUGP("last %02X %02X %02X\n", 
-       		(fraginfo->flags & IP6T_FRAG_NMF), frag->info & IP6F_MORE_FRAG,
-       		!((fraginfo->flags & IP6T_FRAG_NMF) && (frag->info & IP6F_MORE_FRAG)));
+       		(fraginfo->flags & IP6T_FRAG_NMF),
+		ntohs(frag->frag_off) & IP6_MF,
+       		!((fraginfo->flags & IP6T_FRAG_NMF)
+			&& (ntohs(frag->frag_off) & IP6_MF)));
 
        return (frag != NULL)
        		&&
        		(id_match(fraginfo->ids[0], fraginfo->ids[1],
-                           ntohl(frag->id),
+			  ntohl(frag->identification),
                            !!(fraginfo->invflags & IP6T_FRAG_INV_IDS)))
 		&&
-	      	(!fraginfo->hdrlen ||
-                           (fraginfo->hdrlen == hdrlen) ^
-                           !!(fraginfo->invflags & IP6T_FRAG_INV_LEN))
-		&&
-		!((fraginfo->flags & IP6T_FRAG_RES) && (frag->info & IP6F_RESERVED_MASK))
+		!((fraginfo->flags & IP6T_FRAG_RES)
+			&& (frag->reserved || (ntohs(frag->frag_off) & 0x6)))
 		&&
-		!((fraginfo->flags & IP6T_FRAG_FST) && (frag->info & IP6F_OFF_MASK))
+		!((fraginfo->flags & IP6T_FRAG_FST)
+			&& (ntohs(frag->frag_off) & ~0x7))
 		&&
-		!((fraginfo->flags & IP6T_FRAG_MF) && !((frag->info & IP6F_MORE_FRAG)))
+		!((fraginfo->flags & IP6T_FRAG_MF)
+			&& !(ntohs(frag->frag_off) & IP6_MF))
 		&&
-		!((fraginfo->flags & IP6T_FRAG_NMF) && (frag->info & IP6F_MORE_FRAG));
+		!((fraginfo->flags & IP6T_FRAG_NMF)
+			&& (ntohs(frag->frag_off) & IP6_MF));
 }
 
 /* Called when user tries to insert an entry of this type. */
diff -urN linux-2.4.28-bk7/net/ipv6/netfilter/ip6t_hbh.c linux-2.4.29/net/ipv6/netfilter/ip6t_hbh.c
--- linux-2.4.28-bk7/net/ipv6/netfilter/ip6t_hbh.c	2003-06-13 07:51:39.000000000 -0700
+++ linux-2.4.29/net/ipv6/netfilter/ip6t_hbh.c	2005-01-19 07:08:14.698708962 -0800
@@ -11,8 +11,6 @@
 #include <linux/netfilter_ipv6/ip6_tables.h>
 #include <linux/netfilter_ipv6/ip6t_opts.h>
 
-#define LOW(n)		(n & 0x00FF)
-
 #define HOPBYHOP	1
 
 EXPORT_NO_SYMBOLS;
@@ -40,8 +38,8 @@
  *  	0	-> invariant
  *  	1	-> can change the routing
  *  (Type & 0x1F) Type
- *      0	-> PAD0 (only 1 byte!)
- *      1	-> PAD1 LENGTH info (total length = length + 2)
+ *      0	-> Pad1 (only 1 byte!)
+ *      1	-> PadN LENGTH info (total length = length + 2)
  *      C0 | 2	-> JUMBO 4 x x x x ( xxxx > 64k )
  *      5	-> RTALERT 2 x x
  */
@@ -64,7 +62,8 @@
        unsigned int ptr;
        unsigned int hdrlen = 0;
        unsigned int ret = 0;
-       u_int16_t *optdesc = NULL;
+       u8 *opttype = NULL;
+       unsigned int optlen;
        
        /* type of the 1st exthdr */
        nexthdr = skb->nh.ipv6h->nexthdr;
@@ -91,7 +90,7 @@
                      break;
               }
 
-              hdr=(void *)(skb->data)+ptr;
+	      hdr = (void *)(skb->data + ptr);
 
               /* Calculate the header length */
                 if (nexthdr == NEXTHDR_FRAGMENT) {
@@ -153,7 +152,7 @@
        		return 0;
        }
 
-       optsh=(void *)(skb->data)+ptr;
+       optsh = (void *)(skb->data + ptr);
 
        DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, optsh->hdrlen);
 
@@ -169,7 +168,6 @@
                            ((optinfo->hdrlen == hdrlen) ^
                            !!(optinfo->invflags & IP6T_OPTS_INV_LEN)));
 
-       temp = len = 0;
        ptr += 2;
        hdrlen -= 2;
        if ( !(optinfo->flags & IP6T_OPTS_OPTS) ){
@@ -180,48 +178,52 @@
 		DEBUGP("Strict ");
 		DEBUGP("#%d ",optinfo->optsnr);
 		for(temp=0; temp<optinfo->optsnr; temp++){
-			optdesc = (void *)(skb->data)+ptr;
+			/* type field exists ? */
+			if (ptr > skb->len - 1 || hdrlen < 1)
+				break;
+			opttype = (void *)(skb->data + ptr);
+
 			/* Type check */
-			if ( (unsigned char)*optdesc != 
-				(optinfo->opts[temp] & 0xFF00)>>8 ){
+			if (*opttype != (optinfo->opts[temp] & 0xFF00)>>8){
 				DEBUGP("Tbad %02X %02X\n",
-						(unsigned char)*optdesc,
-						(optinfo->opts[temp] &
-						 0xFF00)>>8);
+				       *opttype,
+				       (optinfo->opts[temp] & 0xFF00)>>8);
 				return 0;
 			} else {
 				DEBUGP("Tok ");
 			}
 			/* Length check */
-			if (((optinfo->opts[temp] & 0x00FF) != 0xFF) &&
-				(unsigned char)*optdesc != 0){
-				if ( ntohs((u16)*optdesc) != 
-						optinfo->opts[temp] ){
-					DEBUGP("Lbad %02X %04X %04X\n",
-							(unsigned char)*optdesc,
-							ntohs((u16)*optdesc),
-							optinfo->opts[temp]);
+			if (*opttype) {
+				u16 spec_len;
+
+				/* length field exists ? */
+				if (ptr > skb->len - 2 || hdrlen < 2)
+					break;
+				optlen = *((u8 *)(skb->data + ptr + 1));
+				spec_len = optinfo->opts[temp] & 0x00FF;
+
+				if (spec_len != 0x00FF && spec_len != optlen) {
+					DEBUGP("Lbad %02X %04X\n", optlen,
+					       spec_len);
 					return 0;
-				} else {
-					DEBUGP("Lok ");
 				}
-			}
-			/* Step to the next */
-			if ((unsigned char)*optdesc == 0){
-				DEBUGP("PAD0 \n");
-				ptr++;
-				hdrlen--;
+				DEBUGP("Lok ");
+				optlen += 2;
 			} else {
-				ptr += LOW(ntohs(*optdesc));
-				hdrlen -= LOW(ntohs(*optdesc));
-				DEBUGP("len%04X \n", 
-					LOW(ntohs(*optdesc)));
+				DEBUGP("Pad1\n");
+				optlen = 1;
 			}
-			if (ptr > skb->len || ( !hdrlen && 
-				(temp != optinfo->optsnr - 1))) {
+
+			/* Step to the next */
+			DEBUGP("len%04X \n", optlen);
+
+			if ((ptr > skb->len - optlen || hdrlen < optlen) &&
+			    (temp < optinfo->optsnr - 1)) {
 				DEBUGP("new pointer is too large! \n");
 				break;
 			}
+			ptr += optlen;
+			hdrlen -= optlen;
 		}
 		if (temp == optinfo->optsnr)
 			return ret;
diff -urN linux-2.4.28-bk7/net/ipv6/netfilter/ip6t_ipv6header.c linux-2.4.29/net/ipv6/netfilter/ip6t_ipv6header.c
--- linux-2.4.28-bk7/net/ipv6/netfilter/ip6t_ipv6header.c	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.29/net/ipv6/netfilter/ip6t_ipv6header.c	2005-01-19 07:08:14.699709006 -0800
@@ -63,7 +63,7 @@
 			break;
 		}
 
-		hdr=(struct ipv6_opt_hdr *)skb->data+ptr;
+		hdr=(struct ipv6_opt_hdr *)(skb->data+ptr);
 
 		/* Calculate the header length */
                 if (nexthdr == NEXTHDR_FRAGMENT) {
@@ -107,10 +107,14 @@
 		temp |= MASK_PROTO;
 
 	if (info->modeflag)
-		return (!( (temp & info->matchflags)
-			^ info->matchflags) ^ info->invflags);
-	else
-		return (!( temp ^ info->matchflags) ^ info->invflags);
+		return !((temp ^ info->matchflags ^ info->invflags)
+			 & info->matchflags);
+	else {
+		if (info->invflags)
+			return temp != info->matchflags;
+		else
+			return temp == info->matchflags;
+	}
 }
 
 static int
@@ -120,11 +124,17 @@
 		      unsigned int matchsize,
 		      unsigned int hook_mask)
 {
+	const struct ip6t_ipv6header_info *info = matchinfo;
+
 	/* Check for obvious errors */
 	/* This match is valid in all hooks! */
-	if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_ipv6header_info))) {
+	if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_ipv6header_info)))
+		return 0;
+
+	/* invflags is 0 or 0xff in hard mode */
+	if ((!info->modeflag) && info->invflags != 0x00
+			      && info->invflags != 0xFF)
 		return 0;
-	}
 
 	return 1;
 }
diff -urN linux-2.4.28-bk7/net/ipv6/netfilter/ip6t_multiport.c linux-2.4.29/net/ipv6/netfilter/ip6t_multiport.c
--- linux-2.4.28-bk7/net/ipv6/netfilter/ip6t_multiport.c	2001-10-30 15:08:12.000000000 -0800
+++ linux-2.4.29/net/ipv6/netfilter/ip6t_multiport.c	2005-01-19 07:08:14.699709006 -0800
@@ -74,9 +74,12 @@
 {
 	const struct ip6t_multiport *multiinfo = matchinfo;
 
+	if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_multiport)))
+		return 0;
+
 	/* Must specify proto == TCP/UDP, no unknown flags or bad count */
 	return (ip->proto == IPPROTO_TCP || ip->proto == IPPROTO_UDP)
-		&& !(ip->flags & IP6T_INV_PROTO)
+		&& !(ip->invflags & IP6T_INV_PROTO)
 		&& matchsize == IP6T_ALIGN(sizeof(struct ip6t_multiport))
 		&& (multiinfo->flags == IP6T_MULTIPORT_SOURCE
 		    || multiinfo->flags == IP6T_MULTIPORT_DESTINATION
diff -urN linux-2.4.28-bk7/net/ipv6/netfilter/ip6t_rt.c linux-2.4.29/net/ipv6/netfilter/ip6t_rt.c
--- linux-2.4.28-bk7/net/ipv6/netfilter/ip6t_rt.c	2003-08-25 04:44:44.000000000 -0700
+++ linux-2.4.29/net/ipv6/netfilter/ip6t_rt.c	2005-01-19 07:08:14.700709049 -0800
@@ -78,7 +78,7 @@
                      break;
               }
 
-              hdr=(struct ipv6_opt_hdr *)skb->data+ptr;
+              hdr=(struct ipv6_opt_hdr *)(skb->data+ptr);
 
               /* Calculate the header length */
                 if (nexthdr == NEXTHDR_FRAGMENT) {
@@ -135,11 +135,11 @@
 
        DEBUGP("IPv6 RT LEN %u %u ", hdrlen, route->hdrlen);
        DEBUGP("TYPE %04X ", route->type);
-       DEBUGP("SGS_LEFT %u %08X\n", ntohl(route->segments_left), ntohl(route->segments_left));
+       DEBUGP("SGS_LEFT %u %02X\n", route->segments_left, route->segments_left);
 
        DEBUGP("IPv6 RT segsleft %02X ",
        		(segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1],
-                           ntohl(route->segments_left),
+                           route->segments_left,
                            !!(rtinfo->invflags & IP6T_RT_INV_SGS))));
        DEBUGP("type %02X %02X %02X ",
        		rtinfo->rt_type, route->type, 
@@ -158,7 +158,7 @@
        ret = (route != NULL)
        		&&
        		(segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1],
-                           ntohl(route->segments_left),
+                           route->segments_left,
                            !!(rtinfo->invflags & IP6T_RT_INV_SGS)))
 		&&
 	      	(!(rtinfo->flags & IP6T_RT_LEN) ||
diff -urN linux-2.4.28-bk7/net/ipv6/sit.c linux-2.4.29/net/ipv6/sit.c
--- linux-2.4.28-bk7/net/ipv6/sit.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/net/ipv6/sit.c	2005-01-19 07:08:14.701709092 -0800
@@ -139,10 +139,10 @@
 {
 	struct ip_tunnel **tp = ipip6_bucket(t);
 
-	write_lock_bh(&ipip6_lock);
 	t->next = *tp;
-	write_unlock_bh(&ipip6_lock);
+	write_lock_bh(&ipip6_lock);
 	*tp = t;
+	write_unlock_bh(&ipip6_lock);
 }
 
 struct ip_tunnel * ipip6_tunnel_locate(struct ip_tunnel_parm *parms, int create)
diff -urN linux-2.4.28-bk7/net/irda/ircomm/ircomm_tty.c linux-2.4.29/net/irda/ircomm/ircomm_tty.c
--- linux-2.4.28-bk7/net/irda/ircomm/ircomm_tty.c	2003-08-25 04:44:44.000000000 -0700
+++ linux-2.4.29/net/irda/ircomm/ircomm_tty.c	2005-01-19 07:08:14.702709136 -0800
@@ -566,8 +566,7 @@
 
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
+	tty_ldisc_flush(tty);
 
 	tty->closing = 0;
 	self->tty = 0;
@@ -662,12 +661,7 @@
 		ircomm_tty_do_event(self, IRCOMM_TTY_DATA_REQUEST, skb, NULL);
 		
 	/* Check if user (still) wants to be waken up */
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && 
-	    tty->ldisc.write_wakeup)
-	{
-		(tty->ldisc.write_wakeup)(tty);
-	}
-	wake_up_interruptible(&tty->write_wait);
+	tty_wakeup(tty);
 }
 
 /*
diff -urN linux-2.4.28-bk7/net/netsyms.c linux-2.4.29/net/netsyms.c
--- linux-2.4.28-bk7/net/netsyms.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/net/netsyms.c	2005-01-19 07:08:14.704709222 -0800
@@ -327,6 +327,7 @@
 EXPORT_SYMBOL(tcp_listen_wlock);
 EXPORT_SYMBOL(udp_hash);
 EXPORT_SYMBOL(udp_hash_lock);
+EXPORT_SYMBOL(udp_poll);
 
 EXPORT_SYMBOL(tcp_destroy_sock);
 EXPORT_SYMBOL(ip_queue_xmit);
@@ -606,6 +607,7 @@
 EXPORT_SYMBOL(nf_setsockopt);
 EXPORT_SYMBOL(nf_getsockopt);
 EXPORT_SYMBOL(ip_ct_attach);
+EXPORT_SYMBOL(nf_ct_attach);
 #ifdef CONFIG_INET
 #include <linux/netfilter_ipv4.h>
 EXPORT_SYMBOL(ip_route_me_harder);
diff -urN linux-2.4.28-bk7/net/rose/rose_route.c linux-2.4.29/net/rose/rose_route.c
--- linux-2.4.28-bk7/net/rose/rose_route.c	2001-06-29 19:38:26.000000000 -0700
+++ linux-2.4.29/net/rose/rose_route.c	2005-01-19 07:08:14.705709266 -0800
@@ -655,6 +655,9 @@
 			if (rose_route.mask > 10) /* Mask can't be more than 10 digits */
 				return -EINVAL;
 
+			if(rose_route.ndigis > 8) /* No more than 8 digipeats */
+				return -EINVAL;
+
 			err = rose_add_node(&rose_route, dev);
 			dev_put(dev);
 			return err;
diff -urN linux-2.4.28-bk7/net/sched/cls_tcindex.c linux-2.4.29/net/sched/cls_tcindex.c
--- linux-2.4.28-bk7/net/sched/cls_tcindex.c	2001-12-21 09:42:06.000000000 -0800
+++ linux-2.4.29/net/sched/cls_tcindex.c	2005-01-19 07:08:14.706709309 -0800
@@ -161,7 +161,8 @@
 }
 
 
-static int tcindex_delete(struct tcf_proto *tp, unsigned long arg)
+static int
+__tcindex_delete(struct tcf_proto *tp, unsigned long arg, int lock)
 {
 	struct tcindex_data *p = PRIV(tp);
 	struct tcindex_filter_result *r = (struct tcindex_filter_result *) arg;
@@ -184,9 +185,11 @@
 
 found:
 		f = *walk;
-		tcf_tree_lock(tp); 
+		if (lock)
+			tcf_tree_lock(tp);
 		*walk = f->next;
-		tcf_tree_unlock(tp);
+		if (lock)
+			tcf_tree_unlock(tp);
 	}
 	cl = __cls_set_class(&r->res.class,0);
 	if (cl)
@@ -199,6 +202,10 @@
 	return 0;
 }
 
+static int tcindex_delete(struct tcf_proto *tp, unsigned long arg)
+{
+	return __tcindex_delete(tp, arg, 1);
+}
 
 /*
  * There are no parameters for tcindex_init, so we overload tcindex_change
@@ -397,7 +404,7 @@
 static int tcindex_destroy_element(struct tcf_proto *tp,
     unsigned long arg, struct tcf_walker *walker)
 {
-	return tcindex_delete(tp,arg);
+	return __tcindex_delete(tp, arg, 0);
 }
 
 
diff -urN linux-2.4.28-bk7/net/sched/sch_dsmark.c linux-2.4.29/net/sched/sch_dsmark.c
--- linux-2.4.28-bk7/net/sched/sch_dsmark.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/net/sched/sch_dsmark.c	2005-01-19 07:08:14.708709395 -0800
@@ -13,6 +13,7 @@
 #include <linux/rtnetlink.h>
 #include <net/pkt_sched.h>
 #include <net/dsfield.h>
+#include <net/inet_ecn.h>
 #include <asm/byteorder.h>
 
 
@@ -196,10 +197,12 @@
 	if (p->set_tc_index) {
 		switch (skb->protocol) {
 			case __constant_htons(ETH_P_IP):
-				skb->tc_index = ipv4_get_dsfield(skb->nh.iph);
+				skb->tc_index = ipv4_get_dsfield(skb->nh.iph)
+					& ~INET_ECN_MASK;
 				break;
 			case __constant_htons(ETH_P_IPV6):
-				skb->tc_index = ipv6_get_dsfield(skb->nh.ipv6h);
+				skb->tc_index = ipv6_get_dsfield(skb->nh.ipv6h)
+					& ~INET_ECN_MASK;
 				break;
 			default:
 				skb->tc_index = 0;
diff -urN linux-2.4.28-bk7/net/sched/sch_netem.c linux-2.4.29/net/sched/sch_netem.c
--- linux-2.4.28-bk7/net/sched/sch_netem.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/net/sched/sch_netem.c	2005-01-19 07:08:14.708709395 -0800
@@ -259,12 +259,13 @@
 {
 	struct Qdisc *sch = (struct Qdisc *)arg;
 	struct netem_sched_data *q = qdisc_priv(sch);
+	struct net_device *dev = sch->dev;
 	struct sk_buff *skb;
 	psched_time_t now;
 
 	pr_debug("netem_watchdog: fired @%lu\n", jiffies);
 
-	spin_lock_bh(&sch->dev->queue_lock);
+	spin_lock_bh(&dev->queue_lock);
 	PSCHED_GET_TIME(now);
 
 	while ((skb = skb_peek(&q->delayed)) != NULL) {
@@ -284,8 +285,11 @@
 
 		if (q->qdisc->enqueue(skb, q->qdisc))
 			sch->stats.drops++;
+		else
+			sch->q.qlen++;
 	}
-	spin_unlock_bh(&sch->dev->queue_lock);
+	qdisc_run(dev);
+	spin_unlock_bh(&dev->queue_lock);
 }
 
 static void netem_reset(struct Qdisc *sch)
@@ -505,7 +509,7 @@
 	sch_tree_lock(sch);
 	*old = xchg(&q->qdisc, new);
 	qdisc_reset(*old);
-	sch->q.qlen = q->delayed.qlen;
+	sch->q.qlen = 0;
 	sch_tree_unlock(sch);
 
 	return 0;
diff -urN linux-2.4.28-bk7/net/sctp/associola.c linux-2.4.29/net/sctp/associola.c
--- linux-2.4.28-bk7/net/sctp/associola.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/net/sctp/associola.c	2005-01-19 07:08:14.710709482 -0800
@@ -66,33 +66,8 @@
 
 /* 1st Level Abstractions. */
 
-/* Allocate and initialize a new association */
-struct sctp_association *sctp_association_new(const struct sctp_endpoint *ep,
-					 const struct sock *sk,
-					 sctp_scope_t scope, int gfp)
-{
-	struct sctp_association *asoc;
-
-	asoc = t_new(struct sctp_association, gfp);
-	if (!asoc)
-		goto fail;
-
-	if (!sctp_association_init(asoc, ep, sk, scope, gfp))
-		goto fail_init;
-
-	asoc->base.malloced = 1;
-	SCTP_DBG_OBJCNT_INC(assoc);
-
-	return asoc;
-
-fail_init:
-	kfree(asoc);
-fail:
-	return NULL;
-}
-
 /* Initialize a new association from provided memory. */
-struct sctp_association *sctp_association_init(struct sctp_association *asoc,
+static struct sctp_association *sctp_association_init(struct sctp_association *asoc,
 					  const struct sctp_endpoint *ep,
 					  const struct sock *sk,
 					  sctp_scope_t scope,
@@ -182,10 +157,10 @@
 	 * RFC 6 - A SCTP receiver MUST be able to receive a minimum of
 	 * 1500 bytes in one SCTP packet.
 	 */
-	if (sk->sk_rcvbuf < SCTP_DEFAULT_MINWINDOW)
+	if (sk->rcvbuf < SCTP_DEFAULT_MINWINDOW)
 		asoc->rwnd = SCTP_DEFAULT_MINWINDOW;
 	else
-		asoc->rwnd = sk->sk_rcvbuf;
+		asoc->rwnd = sk->rcvbuf;
 
 	asoc->a_rwnd = asoc->rwnd;
 
@@ -204,6 +179,7 @@
 	asoc->c.peer_vtag = 0;
 	asoc->c.my_ttag   = 0;
 	asoc->c.peer_ttag = 0;
+	asoc->c.my_port = ep->base.bind_addr.port;
 
 	asoc->c.initial_tsn = sctp_generate_tsn(ep);
 
@@ -296,6 +272,31 @@
 	return NULL;
 }
 
+/* Allocate and initialize a new association */
+struct sctp_association *sctp_association_new(const struct sctp_endpoint *ep,
+					 const struct sock *sk,
+					 sctp_scope_t scope, int gfp)
+{
+	struct sctp_association *asoc;
+
+	asoc = t_new(struct sctp_association, gfp);
+	if (!asoc)
+		goto fail;
+
+	if (!sctp_association_init(asoc, ep, sk, scope, gfp))
+		goto fail_init;
+
+	asoc->base.malloced = 1;
+	SCTP_DBG_OBJCNT_INC(assoc);
+
+	return asoc;
+
+fail_init:
+	kfree(asoc);
+fail:
+	return NULL;
+}
+
 /* Free this association if possible.  There may still be users, so
  * the actual deallocation may be delayed.
  */
@@ -310,7 +311,7 @@
 
 	/* Decrement the backlog value for a TCP-style listening socket. */
 	if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING))
-		sk->sk_ack_backlog--;
+		sk->ack_backlog--;
 
 	/* Mark as dead, so other users can know this structure is
 	 * going away.
@@ -496,7 +497,6 @@
 
 	peer->partial_bytes_acked = 0;
 	peer->flight_size = 0;
-	peer->error_threshold = peer->max_retrans;
 
 	/* By default, enable heartbeat for peer address. */
 	peer->hb_allowed = 1;
@@ -507,7 +507,7 @@
 	peer->hb_interval = SCTP_MSECS_TO_JIFFIES(sp->paddrparam.spp_hbinterval);
 
 	/* Set the path max_retrans.  */
-	peer->max_retrans = asoc->max_retrans;
+	peer->max_retrans = sp->paddrparam.spp_pathmaxrxt;
 
 	/* Set the transport's RTO.initial value */
 	peer->rto = asoc->rto_initial;
@@ -710,18 +710,6 @@
 	return retval;
 }
 
-/* Allocate 'num' TSNs by incrementing the association's TSN by num. */
-__u32 sctp_association_get_tsn_block(struct sctp_association *asoc, int num)
-{
-	__u32 retval = asoc->next_tsn;
-
-	asoc->next_tsn += num;
-	asoc->unack_data += num;
-
-	return retval;
-}
-
-
 /* Compare two addresses to see if they match.  Wildcard addresses
  * only match themselves.
  */
@@ -756,14 +744,6 @@
 	return chunk;
 }
 
-/* Use this function for the packet prepend callback when no ECNE
- * packet is desired (e.g. some packets don't like to be bundled).
- */
-struct sctp_chunk *sctp_get_no_prepend(struct sctp_association *asoc)
-{
-	return NULL;
-}
-
 /*
  * Find which transport this TSN was sent on.
  */
@@ -877,7 +857,8 @@
 	struct sctp_chunk *chunk;
 	struct sock *sk;
 	struct sctp_inq *inqueue;
-	int state, subtype;
+	int state;
+	sctp_subtype_t subtype;
 	int error = 0;
 
 	/* The association should be held so we should be safe. */
@@ -887,7 +868,7 @@
 	inqueue = &asoc->base.inqueue;
 	while (NULL != (chunk = sctp_inq_pop(inqueue))) {
 		state = asoc->state;
-		subtype = chunk->chunk_hdr->type;
+		subtype = SCTP_ST_CHUNK(chunk->chunk_hdr->type);
 
 		/* Remember where the last DATA chunk came from so we
 		 * know where to send the SACK.
@@ -901,7 +882,7 @@
 			chunk->transport->last_time_heard = jiffies;
 
 		/* Run through the state machine. */
-		error = sctp_do_sm(SCTP_EVENT_T_CHUNK, SCTP_ST_CHUNK(subtype),
+		error = sctp_do_sm(SCTP_EVENT_T_CHUNK, subtype,
 				   state, ep, asoc, chunk, GFP_ATOMIC);
 
 		/* Check to see if the association is freed in response to
@@ -930,7 +911,7 @@
 
 	/* Decrement the backlog value for a TCP-style socket. */
 	if (sctp_style(oldsk, TCP))
-		oldsk->sk_ack_backlog--;
+		oldsk->ack_backlog--;
 
 	/* Release references to the old endpoint and the sock.  */
 	sctp_endpoint_put(assoc->ep);
@@ -1112,7 +1093,7 @@
 	case SCTP_STATE_SHUTDOWN_SENT:
 		if ((asoc->rwnd > asoc->a_rwnd) &&
 		    ((asoc->rwnd - asoc->a_rwnd) >=
-		     min_t(__u32, (asoc->base.sk->sk_rcvbuf >> 1), asoc->pmtu)))
+		     min_t(__u32, (asoc->base.sk->rcvbuf >> 1), asoc->pmtu)))
 			return 1;
 		break;
 	default:
@@ -1195,7 +1176,7 @@
 	 * the endpoint.
 	 */
 	scope = sctp_scope(&asoc->peer.active_path->ipaddr);
-	flags = (PF_INET6 == asoc->base.sk->sk_family) ? SCTP_ADDR6_ALLOWED : 0;
+	flags = (PF_INET6 == asoc->base.sk->family) ? SCTP_ADDR6_ALLOWED : 0;
 	if (asoc->peer.ipv4_address)
 		flags |= SCTP_ADDR4_PEERSUPP;
 	if (asoc->peer.ipv6_address)
diff -urN linux-2.4.28-bk7/net/sctp/bind_addr.c linux-2.4.29/net/sctp/bind_addr.c
--- linux-2.4.28-bk7/net/sctp/bind_addr.c	2004-04-14 06:05:41.000000000 -0700
+++ linux-2.4.29/net/sctp/bind_addr.c	2005-01-19 07:08:14.711709525 -0800
@@ -104,23 +104,6 @@
 	return error;
 }
 
-/* Create a new SCTP_bind_addr from nothing.  */
-struct sctp_bind_addr *sctp_bind_addr_new(int gfp)
-{
-	struct sctp_bind_addr *retval;
-
-	retval = t_new(struct sctp_bind_addr, gfp);
-	if (!retval)
-		goto nomem;
-
-	sctp_bind_addr_init(retval, 0);
-	retval->malloced = 1;
-	SCTP_DBG_OBJCNT_INC(bind_addr);
-
-nomem:
-	return retval;
-}
-
 /* Initialize the SCTP_bind_addr structure for either an endpoint or
  * an association.
  */
diff -urN linux-2.4.28-bk7/net/sctp/chunk.c linux-2.4.29/net/sctp/chunk.c
--- linux-2.4.28-bk7/net/sctp/chunk.c	2004-08-07 16:26:07.000000000 -0700
+++ linux-2.4.29/net/sctp/chunk.c	2005-01-19 07:08:14.711709525 -0800
@@ -51,7 +51,7 @@
  */
 
 /* Initialize datamsg from memory. */
-void sctp_datamsg_init(struct sctp_datamsg *msg)
+static void sctp_datamsg_init(struct sctp_datamsg *msg)
 {
 	atomic_set(&msg->refcnt, 1);
 	msg->send_failed = 0;
@@ -62,7 +62,7 @@
 }
 
 /* Allocate and initialize datamsg. */
-struct sctp_datamsg *sctp_datamsg_new(int gfp)
+SCTP_STATIC struct sctp_datamsg *sctp_datamsg_new(int gfp)
 {
 	struct sctp_datamsg *msg;
 	msg = kmalloc(sizeof(struct sctp_datamsg), gfp);
@@ -124,7 +124,7 @@
 }
 
 /* Hold a reference. */
-void sctp_datamsg_hold(struct sctp_datamsg *msg)
+static void sctp_datamsg_hold(struct sctp_datamsg *msg)
 {
 	atomic_inc(&msg->refcnt);
 }
@@ -151,7 +151,7 @@
 }
 
 /* Assign a chunk to this datamsg. */
-void sctp_datamsg_assign(struct sctp_datamsg *msg, struct sctp_chunk *chunk)
+static void sctp_datamsg_assign(struct sctp_datamsg *msg, struct sctp_chunk *chunk)
 {
 	sctp_datamsg_hold(msg);
 	chunk->msg = msg;
diff -urN linux-2.4.28-bk7/net/sctp/command.c linux-2.4.29/net/sctp/command.c
--- linux-2.4.28-bk7/net/sctp/command.c	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.29/net/sctp/command.c	2005-01-19 07:08:14.712709569 -0800
@@ -42,17 +42,6 @@
 #include <net/sctp/sctp.h>
 #include <net/sctp/sm.h>
 
-/* Create a new sctp_command_sequence.  */
-sctp_cmd_seq_t *sctp_new_cmd_seq(int gfp)
-{
-	sctp_cmd_seq_t *retval = t_new(sctp_cmd_seq_t, gfp);
-
-	if (retval)
-		sctp_init_cmd_seq(retval);
-
-	return retval;
-}
-
 /* Initialize a block of memory as a command sequence. */
 int sctp_init_cmd_seq(sctp_cmd_seq_t *seq)
 {
@@ -77,13 +66,6 @@
 	return 0;
 }
 
-/* Rewind an sctp_cmd_seq_t to iterate from the start.  */
-int sctp_rewind_sequence(sctp_cmd_seq_t *seq)
-{
-	seq->next_cmd = 0;
-	return 1;		/* We always succeed. */
-}
-
 /* Return the next command structure in a sctp_cmd_seq.
  * Returns NULL at the end of the sequence.
  */
@@ -97,8 +79,3 @@
 	return retval;
 }
 
-/* Dispose of a command sequence.  */
-void sctp_free_cmd_seq(sctp_cmd_seq_t *seq)
-{
-	kfree(seq);
-}
diff -urN linux-2.4.28-bk7/net/sctp/debug.c linux-2.4.29/net/sctp/debug.c
--- linux-2.4.28-bk7/net/sctp/debug.c	2004-08-07 16:26:07.000000000 -0700
+++ linux-2.4.29/net/sctp/debug.c	2005-01-19 07:08:14.712709569 -0800
@@ -98,23 +98,6 @@
 	return "unknown chunk";
 }
 
-/* These are printable form of variable-length parameters. */
-const char *sctp_param_tbl[SCTP_PARAM_ECN_CAPABLE + 1] = {
-	"",
-	"PARAM_HEARTBEAT_INFO",
-	"",
-	"",
-	"",
-	"PARAM_IPV4_ADDRESS",
-	"PARAM_IPV6_ADDRESS",
-	"PARAM_STATE_COOKIE",
-	"PARAM_UNRECOGNIZED_PARAMETERS",
-	"PARAM_COOKIE_PRESERVATIVE",
-	"",
-	"PARAM_HOST_NAME_ADDRESS",
-	"PARAM_SUPPORTED_ADDRESS_TYPES",
-};
-
 /* These are printable forms of the states.  */
 const char *sctp_state_tbl[SCTP_STATE_NUM_STATES] = {
 	"STATE_EMPTY",
@@ -171,6 +154,7 @@
 
 static const char *sctp_other_tbl[] = {
 	"NO_PENDING_TSN",
+        "ICMP_PROTO_UNREACH",
 };
 
 /* Lookup "other" debug name. */
@@ -178,7 +162,7 @@
 {
 	if (id.other < 0)
 		return "illegal 'other' event";
-	if (id.other < SCTP_EVENT_OTHER_MAX)
+	if (id.other <= SCTP_EVENT_OTHER_MAX)
 		return sctp_other_tbl[id.other];
 	return "unknown 'other' event";
 }
diff -urN linux-2.4.28-bk7/net/sctp/endpointola.c linux-2.4.29/net/sctp/endpointola.c
--- linux-2.4.28-bk7/net/sctp/endpointola.c	2004-04-14 06:05:41.000000000 -0700
+++ linux-2.4.29/net/sctp/endpointola.c	2005-01-19 07:08:14.713709612 -0800
@@ -63,34 +63,11 @@
 /* Forward declarations for internal helpers. */
 static void sctp_endpoint_bh_rcv(struct sctp_endpoint *ep);
 
-/* Create a sctp_endpoint with all that boring stuff initialized.
- * Returns NULL if there isn't enough memory.
- */
-struct sctp_endpoint *sctp_endpoint_new(struct sock *sk, int gfp)
-{
-	struct sctp_endpoint *ep;
-
-	/* Build a local endpoint. */
-	ep = t_new(struct sctp_endpoint, gfp);
-	if (!ep)
-		goto fail;
-	if (!sctp_endpoint_init(ep, sk, gfp))
-		goto fail_init;
-	ep->base.malloced = 1;
-	SCTP_DBG_OBJCNT_INC(ep);
-	return ep;
-
-fail_init:
-	kfree(ep);
-fail:
-	return NULL;
-}
-
 /*
  * Initialize the base fields of the endpoint structure.
  */
-struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
-					 struct sock *sk, int gfp)
+static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
+						struct sock *sk, int gfp)
 {
 	struct sctp_opt *sp = sctp_sk(sk);
 	memset(ep, 0, sizeof(struct sctp_endpoint));
@@ -148,8 +125,8 @@
 		sp->autoclose * HZ;
 
 	/* Use SCTP specific send buffer space queues.  */
-	sk->sk_write_space = sctp_write_space;
-	sk->sk_use_write_queue = 1;
+	sk->write_space = sctp_write_space;
+	sk->use_write_queue = 1;
 
 	/* Initialize the secret key used with cookie. */
 	get_random_bytes(&ep->secret_key[0], SCTP_SECRET_SIZE);
@@ -160,6 +137,29 @@
 	return ep;
 }
 
+/* Create a sctp_endpoint with all that boring stuff initialized.
+ * Returns NULL if there isn't enough memory.
+ */
+struct sctp_endpoint *sctp_endpoint_new(struct sock *sk, int gfp)
+{
+	struct sctp_endpoint *ep;
+
+	/* Build a local endpoint. */
+	ep = t_new(struct sctp_endpoint, gfp);
+	if (!ep)
+		goto fail;
+	if (!sctp_endpoint_init(ep, sk, gfp))
+		goto fail_init;
+	ep->base.malloced = 1;
+	SCTP_DBG_OBJCNT_INC(ep);
+	return ep;
+
+fail_init:
+	kfree(ep);
+fail:
+	return NULL;
+}
+
 /* Add an association to an endpoint.  */
 void sctp_endpoint_add_asoc(struct sctp_endpoint *ep,
 			    struct sctp_association *asoc)
@@ -171,7 +171,7 @@
 
 	/* Increment the backlog value for a TCP-style listening socket. */
 	if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING))
-		sk->sk_ack_backlog++;
+		sk->ack_backlog++;
 }
 
 /* Free the endpoint structure.  Delay cleanup until
@@ -184,11 +184,11 @@
 }
 
 /* Final destructor for endpoint.  */
-void sctp_endpoint_destroy(struct sctp_endpoint *ep)
+static void sctp_endpoint_destroy(struct sctp_endpoint *ep)
 {
 	SCTP_ASSERT(ep->base.dead, "Endpoint is not dead", return);
 
-	ep->base.sk->sk_state = SCTP_SS_CLOSED;
+	ep->base.sk->state = SCTP_SS_CLOSED;
 
 	/* Unlink this endpoint, so we can't find it again! */
 	sctp_unhash_endpoint(ep);
@@ -257,7 +257,7 @@
  * We do a linear search of the associations for this endpoint.
  * We return the matching transport address too.
  */
-struct sctp_association *__sctp_endpoint_lookup_assoc(
+static struct sctp_association *__sctp_endpoint_lookup_assoc(
 	const struct sctp_endpoint *ep,
 	const union sctp_addr *paddr,
 	struct sctp_transport **transport)
@@ -345,7 +345,7 @@
 	sk = ep->base.sk;
 
 	while (NULL != (chunk = sctp_inq_pop(inqueue))) {
-		subtype.chunk = chunk->chunk_hdr->type;
+		subtype = SCTP_ST_CHUNK(chunk->chunk_hdr->type);
 
 		/* We might have grown an association since last we
 		 * looked, so try again.
diff -urN linux-2.4.28-bk7/net/sctp/input.c linux-2.4.29/net/sctp/input.c
--- linux-2.4.28-bk7/net/sctp/input.c	2004-04-14 06:05:41.000000000 -0700
+++ linux-2.4.29/net/sctp/input.c	2005-01-19 07:08:14.714709655 -0800
@@ -63,11 +63,15 @@
 
 /* Forward declarations for internal helpers. */
 static int sctp_rcv_ootb(struct sk_buff *);
-struct sctp_association *__sctp_rcv_lookup(struct sk_buff *skb,
+static struct sctp_association *__sctp_rcv_lookup(struct sk_buff *skb,
 				      const union sctp_addr *laddr,
 				      const union sctp_addr *paddr,
 				      struct sctp_transport **transportp);
-struct sctp_endpoint *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr);
+static struct sctp_endpoint *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr);
+static struct sctp_association *__sctp_lookup_association(
+					const union sctp_addr *local,
+					const union sctp_addr *peer,
+					struct sctp_transport **pt);
 
 
 /* Calculate the SCTP checksum of an SCTP packet.  */
@@ -130,6 +134,10 @@
 
 	skb_pull(skb, sizeof(struct sctphdr));
 
+	/* Make sure we at least have chunk headers worth of data left. */
+	if (skb->len < sizeof(struct sctp_chunkhdr))
+		goto discard_it;
+
 	family = ipver2af(skb->nh.iph->version);
 	af = sctp_get_af_specific(family);
 	if (unlikely(!af))
@@ -278,6 +286,31 @@
 	}
 }
 
+/*
+ * SCTP Implementer's Guide, 2.37 ICMP handling procedures
+ *
+ * ICMP8) If the ICMP code is a "Unrecognized next header type encountered"
+ *        or a "Protocol Unreachable" treat this message as an abort
+ *        with the T bit set.
+ *
+ * This function sends an event to the state machine, which will abort the
+ * association.
+ *
+ */
+void sctp_icmp_proto_unreachable(struct sock *sk,
+                           struct sctp_endpoint *ep,
+                           struct sctp_association *asoc,
+                           struct sctp_transport *t)
+{
+	SCTP_DEBUG_PRINTK("%s\n",  __FUNCTION__);
+
+	sctp_do_sm(SCTP_EVENT_T_OTHER,
+		   SCTP_ST_OTHER(SCTP_EVENT_ICMP_PROTO_UNREACH),
+		   asoc->state, asoc->ep, asoc, NULL,
+		   GFP_ATOMIC);
+
+}
+
 /* Common lookup code for icmp/icmpv6 error handler. */
 struct sock *sctp_err_lookup(int family, struct sk_buff *skb,
 			     struct sctphdr *sctphdr,
@@ -320,11 +353,12 @@
 	}
 
 	if (asoc) {
+		sk = asoc->base.sk;
+
 		if (ntohl(sctphdr->vtag) != asoc->c.peer_vtag) {
 			ICMP_INC_STATS_BH(IcmpInErrors);
 			goto out;
 		}
-		sk = asoc->base.sk;
 	} else
 		sk = ep->base.sk;
 
@@ -426,7 +460,13 @@
 			sctp_icmp_frag_needed(sk, asoc, transport, info);
 			goto out_unlock;
 		}
-
+		else {
+			if (ICMP_PROT_UNREACH == code) {
+				sctp_icmp_proto_unreachable(sk, ep, asoc,
+							    transport);
+				goto out_unlock;
+			}
+		}
 		err = icmp_err_convert[code].errno;
 		break;
 	case ICMP_TIME_EXCEEDED:
@@ -444,10 +484,10 @@
 
 	inet = inet_sk(sk);
 	if (!sock_owned_by_user(sk) && inet->recverr) {
-		sk->sk_err = err;
-		sk->sk_error_report(sk);
+		sk->err = err;
+		sk->error_report(sk);
 	} else {  /* Only an error on timeout */
-		sk->sk_err_soft = err;
+		sk->err_soft = err;
 	}
 
 out_unlock:
@@ -473,10 +513,10 @@
 	sctp_errhdr_t *err;
 
 	ch = (sctp_chunkhdr_t *) skb->data;
+	ch_end = ((__u8 *) ch) + WORD_ROUND(ntohs(ch->length));
 
 	/* Scan through all the chunks in the packet.  */
-	do {
-		ch_end = ((__u8 *) ch) + WORD_ROUND(ntohs(ch->length));
+	while (ch_end > (__u8 *)ch && ch_end < skb->tail) {
 
 		/* RFC 8.4, 2) If the OOTB packet contains an ABORT chunk, the
 		 * receiver MUST silently discard the OOTB packet and take no
@@ -507,7 +547,8 @@
 		}
 
 		ch = (sctp_chunkhdr_t *) ch_end;
-	} while (ch_end < skb->tail);
+	        ch_end = ((__u8 *) ch) + WORD_ROUND(ntohs(ch->length));
+	}
 
 	return 0;
 
@@ -516,7 +557,7 @@
 }
 
 /* Insert endpoint into the hash table.  */
-void __sctp_hash_endpoint(struct sctp_endpoint *ep)
+static void __sctp_hash_endpoint(struct sctp_endpoint *ep)
 {
 	struct sctp_ep_common **epp;
 	struct sctp_ep_common *epb;
@@ -546,7 +587,7 @@
 }
 
 /* Remove endpoint from the hash table.  */
-void __sctp_unhash_endpoint(struct sctp_endpoint *ep)
+static void __sctp_unhash_endpoint(struct sctp_endpoint *ep)
 {
 	struct sctp_hashbucket *head;
 	struct sctp_ep_common *epb;
@@ -578,7 +619,7 @@
 }
 
 /* Look up an endpoint. */
-struct sctp_endpoint *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr)
+static struct sctp_endpoint *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr)
 {
 	struct sctp_hashbucket *head;
 	struct sctp_ep_common *epb;
@@ -604,16 +645,8 @@
 	return ep;
 }
 
-/* Add an association to the hash. Local BH-safe. */
-void sctp_hash_established(struct sctp_association *asoc)
-{
-	sctp_local_bh_disable();
-	__sctp_hash_established(asoc);
-	sctp_local_bh_enable();
-}
-
 /* Insert association into the hash table.  */
-void __sctp_hash_established(struct sctp_association *asoc)
+static void __sctp_hash_established(struct sctp_association *asoc)
 {
 	struct sctp_ep_common **epp;
 	struct sctp_ep_common *epb;
@@ -636,16 +669,16 @@
 	sctp_write_unlock(&head->lock);
 }
 
-/* Remove association from the hash table.  Local BH-safe. */
-void sctp_unhash_established(struct sctp_association *asoc)
+/* Add an association to the hash. Local BH-safe. */
+void sctp_hash_established(struct sctp_association *asoc)
 {
 	sctp_local_bh_disable();
-	__sctp_unhash_established(asoc);
+	__sctp_hash_established(asoc);
 	sctp_local_bh_enable();
 }
 
 /* Remove association from the hash table.  */
-void __sctp_unhash_established(struct sctp_association *asoc)
+static void __sctp_unhash_established(struct sctp_association *asoc)
 {
 	struct sctp_hashbucket *head;
 	struct sctp_ep_common *epb;
@@ -669,8 +702,16 @@
 	sctp_write_unlock(&head->lock);
 }
 
+/* Remove association from the hash table.  Local BH-safe. */
+void sctp_unhash_established(struct sctp_association *asoc)
+{
+	sctp_local_bh_disable();
+	__sctp_unhash_established(asoc);
+	sctp_local_bh_enable();
+}
+
 /* Look up an association. */
-struct sctp_association *__sctp_lookup_association(
+static struct sctp_association *__sctp_lookup_association(
 					const union sctp_addr *local,
 					const union sctp_addr *peer,
 					struct sctp_transport **pt)
@@ -707,8 +748,9 @@
 }
 
 /* Look up an association. BH-safe. */
+SCTP_STATIC
 struct sctp_association *sctp_lookup_association(const union sctp_addr *laddr,
-					    const union sctp_addr *paddr,
+						 const union sctp_addr *paddr,
 					    struct sctp_transport **transportp)
 {
 	struct sctp_association *asoc;
@@ -778,6 +820,14 @@
 		return NULL;
 	}
 
+	/* The code below will attempt to walk the chunk and extract
+	 * parameter information.  Before we do that, we need to verify
+	 * that the chunk length doesn't cause overflow.  Otherwise, we'll
+	 * walk off the end.
+	 */
+	if (WORD_ROUND(ntohs(ch->length)) > skb->len)
+		return NULL;
+
 	/*
 	 * This code will NOT touch anything inside the chunk--it is
 	 * strictly READ-ONLY.
@@ -815,7 +865,7 @@
 }
 
 /* Lookup an association for an inbound skb. */
-struct sctp_association *__sctp_rcv_lookup(struct sk_buff *skb,
+static struct sctp_association *__sctp_rcv_lookup(struct sk_buff *skb,
 				      const union sctp_addr *paddr,
 				      const union sctp_addr *laddr,
 				      struct sctp_transport **transportp)
diff -urN linux-2.4.28-bk7/net/sctp/inqueue.c linux-2.4.29/net/sctp/inqueue.c
--- linux-2.4.28-bk7/net/sctp/inqueue.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/net/sctp/inqueue.c	2005-01-19 07:08:14.715709699 -0800
@@ -62,19 +62,6 @@
 	queue->malloced = 0;
 }
 
-/* Create an initialized sctp_inq.  */
-struct sctp_inq *sctp_inq_new(void)
-{
-	struct sctp_inq *retval;
-
-	retval = t_new(struct sctp_inq, GFP_ATOMIC);
-	if (retval) {
-		sctp_inq_init(retval);
-		retval->malloced = 1;
-	}
-        return retval;
-}
-
 /* Release the memory associated with an SCTP inqueue.  */
 void sctp_inq_free(struct sctp_inq *queue)
 {
@@ -160,14 +147,36 @@
 	}
 
         chunk->chunk_hdr = ch;
-        chunk->chunk_end = ((__u8 *) ch)
-		+ WORD_ROUND(ntohs(ch->length));
+        chunk->chunk_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length));
+	/* In the unlikely case of an IP reassembly, the skb could be
+	 * non-linear. If so, update chunk_end so that it doesn't go past
+	 * the skb->tail.
+	 */
+	if (unlikely(skb_is_nonlinear(chunk->skb))) {
+		if (chunk->chunk_end > chunk->skb->tail)
+			chunk->chunk_end = chunk->skb->tail;
+	}
 	skb_pull(chunk->skb, sizeof(sctp_chunkhdr_t));
 	chunk->subh.v = NULL; /* Subheader is no longer valid.  */
 
 	if (chunk->chunk_end < chunk->skb->tail) {
 		/* This is not a singleton */
 		chunk->singleton = 0;
+	} else if (chunk->chunk_end > chunk->skb->tail) {
+                /* RFC 2960, Section 6.10  Bundling
+		 *
+		 * Partial chunks MUST NOT be placed in an SCTP packet.
+		 * If the receiver detects a partial chunk, it MUST drop
+		 * the chunk.  
+		 *
+		 * Since the end of the chunk is past the end of our buffer
+		 * (which contains the whole packet, we can freely discard
+		 * the whole packet.
+		 */
+		sctp_chunk_free(chunk);
+		chunk = queue->in_progress = NULL;
+
+		return NULL;
 	} else {
 		/* We are at the end of the packet, so mark the chunk
 		 * in case we need to send a SACK.
diff -urN linux-2.4.28-bk7/net/sctp/ipv6.c linux-2.4.29/net/sctp/ipv6.c
--- linux-2.4.28-bk7/net/sctp/ipv6.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/net/sctp/ipv6.c	2005-01-19 07:08:14.716709742 -0800
@@ -95,8 +95,8 @@
 	ntohs((addr)->s6_addr16[7])
 
 /* ICMP error handler. */
-void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
-		 int type, int code, int offset, __u32 info)
+SCTP_STATIC void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+			     int type, int code, int offset, __u32 info)
 {
 	struct inet6_dev *idev;
 	struct ipv6hdr *iph = (struct ipv6hdr *)skb->data;
@@ -133,6 +133,12 @@
 	case ICMPV6_PKT_TOOBIG:
 		sctp_icmp_frag_needed(sk, asoc, transport, ntohl(info));
 		goto out_unlock;
+	case ICMPV6_PARAMPROB:
+		if (ICMPV6_UNK_NEXTHDR == code) {
+			sctp_icmp_proto_unreachable(sk, ep, asoc, transport);
+			goto out_unlock;
+		}
+		break;
 	default:
 		break;
 	}
@@ -140,10 +146,10 @@
 	np = inet6_sk(sk);
 	icmpv6_err_convert(type, code, &err);
 	if (!sock_owned_by_user(sk) && np->recverr) {
-		sk->sk_err = err;
-		sk->sk_error_report(sk);
+		sk->err = err;
+		sk->error_report(sk);
 	} else {  /* Only an error on timeout */
-		sk->sk_err_soft = err;
+		sk->err_soft = err;
 	}
 
 out_unlock:
@@ -163,7 +169,7 @@
 
 	memset(&fl, 0, sizeof(fl));
 
-	fl.proto = sk->sk_protocol;
+	fl.proto = sk->protocol;
 
 	/* Fill in the dest address from the route entry passed with the skb
 	 * and the source address from the transport.
@@ -176,7 +182,7 @@
 	if (ipv6_addr_type(fl.fl6_src) & IPV6_ADDR_LINKLOCAL)
 		fl.oif = transport->saddr.v6.sin6_scope_id;
 	else
-		fl.oif = sk->sk_bound_dev_if;
+		fl.oif = sk->bound_dev_if;
 	fl.uli_u.ports.sport = sk->sport;
 	fl.uli_u.ports.dport = transport->ipaddr.v6.sin6_port;
 
@@ -199,9 +205,9 @@
 /* Returns the dst cache entry for the given source and destination ip
  * addresses.
  */
-struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc,
-				  union sctp_addr *daddr,
-				  union sctp_addr *saddr)
+static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc,
+					 union sctp_addr *daddr,
+					 union sctp_addr *saddr)
 {
 	struct dst_entry *dst;
 	struct flowi fl;
@@ -262,8 +268,10 @@
 /* Fills in the source address(saddr) based on the destination address(daddr)
  * and asoc's bind address list.
  */
-void sctp_v6_get_saddr(struct sctp_association *asoc, struct dst_entry *dst,
-		       union sctp_addr *daddr, union sctp_addr *saddr)
+static void sctp_v6_get_saddr(struct sctp_association *asoc,
+			      struct dst_entry *dst,
+			      union sctp_addr *daddr,
+			      union sctp_addr *saddr)
 {
 	struct sctp_bind_addr *bp;
 	rwlock_t *addr_lock;
@@ -588,8 +596,8 @@
 }
 
 /* Create and initialize a new sk for the socket to be returned by accept(). */
-struct sock *sctp_v6_create_accept_sk(struct sock *sk,
-				      struct sctp_association *asoc)
+static struct sock *sctp_v6_create_accept_sk(struct sock *sk,
+					     struct sctp_association *asoc)
 {
 	struct sock *newsk;
 	struct inet_opt *newinet;
@@ -602,18 +610,18 @@
 	sock_init_data(NULL, newsk);
 	sk_set_owner(newsk, THIS_MODULE);
 
-	newsk->sk_type = SOCK_STREAM;
+	newsk->type = SOCK_STREAM;
 
-	newsk->sk_prot = sk->sk_prot;
-	newsk->sk_no_check = sk->sk_no_check;
-	newsk->sk_reuse = sk->sk_reuse;
-
-	newsk->sk_destruct = inet_sock_destruct;
-	newsk->sk_zapped = 0;
-	newsk->sk_family = PF_INET6;
-	newsk->sk_protocol = IPPROTO_SCTP;
-	newsk->sk_backlog_rcv = sk->sk_prot->backlog_rcv;
-	newsk->sk_shutdown = sk->sk_shutdown;
+	newsk->prot = sk->prot;
+	newsk->no_check = sk->no_check;
+	newsk->reuse = sk->reuse;
+
+	newsk->destruct = inet_sock_destruct;
+	newsk->zapped = 0;
+	newsk->family = PF_INET6;
+	newsk->protocol = IPPROTO_SCTP;
+	newsk->backlog_rcv = sk->prot->backlog_rcv;
+	newsk->shutdown = sk->shutdown;
 
 	newinet = inet_sk(newsk);
 	newnp = inet6_sk(newsk);
@@ -648,7 +656,7 @@
 	atomic_inc(&inet_sock_nr);
 #endif
 
-	if (newsk->sk_prot->init(newsk)) {
+	if (newsk->prot->init(newsk)) {
 		inet_sock_release(newsk);
 		newsk = NULL;
 	}
@@ -823,8 +831,8 @@
 			 */
 
 			if (addr->v6.sin6_scope_id)
-				sk->sk_bound_dev_if = addr->v6.sin6_scope_id;
-			if (!sk->sk_bound_dev_if)
+				sk->bound_dev_if = addr->v6.sin6_scope_id;
+			if (!sk->bound_dev_if)
 				return 0;
 		}
 		af = opt->pf->af;
@@ -853,8 +861,8 @@
 			 */
 
 			if (addr->v6.sin6_scope_id)
-				sk->sk_bound_dev_if = addr->v6.sin6_scope_id;
-			if (!sk->sk_bound_dev_if)
+				sk->bound_dev_if = addr->v6.sin6_scope_id;
+			if (!sk->bound_dev_if)
 				return 0;
 		}
 		af = opt->pf->af;
diff -urN linux-2.4.28-bk7/net/sctp/objcnt.c linux-2.4.29/net/sctp/objcnt.c
--- linux-2.4.28-bk7/net/sctp/objcnt.c	2004-08-07 16:26:07.000000000 -0700
+++ linux-2.4.29/net/sctp/objcnt.c	2005-01-19 07:08:14.716709742 -0800
@@ -61,7 +61,7 @@
 /* An array to make it easy to pretty print the debug information
  * to the proc fs.
  */
-sctp_dbg_objcnt_entry_t sctp_dbg_objcnt[] = {
+static sctp_dbg_objcnt_entry_t sctp_dbg_objcnt[] = {
 	SCTP_DBG_OBJCNT_ENTRY(sock),
 	SCTP_DBG_OBJCNT_ENTRY(ep),
 	SCTP_DBG_OBJCNT_ENTRY(assoc),
diff -urN linux-2.4.28-bk7/net/sctp/output.c linux-2.4.29/net/sctp/output.c
--- linux-2.4.28-bk7/net/sctp/output.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/net/sctp/output.c	2005-01-19 07:08:14.717709785 -0800
@@ -161,7 +161,7 @@
 		if (!packet->has_cookie_echo) {
 			error = sctp_packet_transmit(packet);
 			if (error < 0)
-				chunk->skb->sk->sk_err = -error;
+				chunk->skb->sk->err = -error;
 
 			/* If we have an empty packet, then we can NOT ever
 			 * return PMTU_FULL.
diff -urN linux-2.4.28-bk7/net/sctp/outqueue.c linux-2.4.29/net/sctp/outqueue.c
--- linux-2.4.28-bk7/net/sctp/outqueue.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/net/sctp/outqueue.c	2005-01-19 07:08:14.718709829 -0800
@@ -200,19 +200,6 @@
 	return 0;
 }
 
-/* Generate a new outqueue.  */
-struct sctp_outq *sctp_outq_new(struct sctp_association *asoc)
-{
-	struct sctp_outq *q;
-
-	q = t_new(struct sctp_outq, GFP_KERNEL);
-	if (q) {
-		sctp_outq_init(asoc, q);
-		q->malloced = 1;
-	}
-	return q;
-}
-
 /* Initialize an existing sctp_outq.  This does the boring stuff.
  * You still need to define handlers if you really want to DO
  * something with this structure...
@@ -372,7 +359,7 @@
 /* Insert a chunk into the sorted list based on the TSNs.  The retransmit list
  * and the abandoned list are in ascending order.
  */
-void sctp_insert_list(struct list_head *head, struct list_head *new)
+static void sctp_insert_list(struct list_head *head, struct list_head *new)
 {
 	struct list_head *pos;
 	struct sctp_chunk *nchunk, *lchunk;
@@ -510,7 +497,7 @@
 	error = sctp_outq_flush(q, /* rtx_timeout */ 1);
 
 	if (error)
-		q->asoc->base.sk->sk_err = -error;
+		q->asoc->base.sk->err = -error;
 }
 
 /*
diff -urN linux-2.4.28-bk7/net/sctp/proc.c linux-2.4.29/net/sctp/proc.c
--- linux-2.4.28-bk7/net/sctp/proc.c	2004-04-14 06:05:41.000000000 -0700
+++ linux-2.4.29/net/sctp/proc.c	2005-01-19 07:08:14.719709872 -0800
@@ -177,7 +177,7 @@
 			ep = sctp_ep(epb);
 			sk = epb->sk;
 			seq_printf(seq, "%8p %8p %-3d %-3d %-4d %-5d ", ep, sk,
-				   sctp_sk(sk)->type, sk->sk_state, hash,
+				   sctp_sk(sk)->type, sk->state, hash,
 				   epb->bind_addr.port);
 			sctp_seq_dump_local_addrs(seq, epb);
 			seq_printf(seq, "\n");
@@ -240,7 +240,7 @@
 			sk = epb->sk;
 			seq_printf(seq,
 				   "%8p %8p %-3d %-3d %-2d %-4d %-5d %-5d ",
-				   assoc, sk, sctp_sk(sk)->type, sk->sk_state,
+				   assoc, sk, sctp_sk(sk)->type, sk->state,
 				   assoc->state, hash, epb->bind_addr.port,
 				   assoc->peer.port);
 			sctp_seq_dump_local_addrs(seq, epb);
diff -urN linux-2.4.28-bk7/net/sctp/protocol.c linux-2.4.29/net/sctp/protocol.c
--- linux-2.4.28-bk7/net/sctp/protocol.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/net/sctp/protocol.c	2005-01-19 07:08:14.720709915 -0800
@@ -93,7 +93,7 @@
 }
 
 /* Set up the proc fs entry for the SCTP protocol. */
-__init int sctp_proc_init(void)
+static __init int sctp_proc_init(void)
 {
 	if (!proc_net_sctp) {
 		struct proc_dir_entry *ent;
@@ -122,7 +122,7 @@
  * Note: Do not make this __exit as it is used in the init error
  * path.
  */
-void sctp_proc_exit(void)
+static void sctp_proc_exit(void)
 {
 	sctp_snmp_proc_exit();
 	sctp_eps_proc_exit();
@@ -428,9 +428,9 @@
  * addresses. If an association is passed, trys to get a dst entry with a
  * source address that matches an address in the bind address list.
  */
-struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
-				  union sctp_addr *daddr,
-				  union sctp_addr *saddr)
+static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
+					 union sctp_addr *daddr,
+					 union sctp_addr *saddr)
 {
 	struct rtable *rt;
 	struct rt_key key;
@@ -520,10 +520,10 @@
 /* For v4, the source address is cached in the route entry(dst). So no need
  * to cache it separately and hence this is an empty routine.
  */
-void sctp_v4_get_saddr(struct sctp_association *asoc,
-		       struct dst_entry *dst,
-		       union sctp_addr *daddr,
-		       union sctp_addr *saddr)
+static void sctp_v4_get_saddr(struct sctp_association *asoc,
+			      struct dst_entry *dst,
+			      union sctp_addr *daddr,
+			      union sctp_addr *saddr)
 {
 	struct rtable *rt = (struct rtable *)dst;
 
@@ -547,8 +547,8 @@
 }
 
 /* Create and initialize a new sk for the socket returned by accept(). */
-struct sock *sctp_v4_create_accept_sk(struct sock *sk,
-				      struct sctp_association *asoc)
+static struct sock *sctp_v4_create_accept_sk(struct sock *sk,
+					     struct sctp_association *asoc)
 {
 	struct sock *newsk;
 	struct inet_opt *inet = inet_sk(sk);
@@ -561,18 +561,18 @@
 	sock_init_data(NULL, newsk);
 	sk_set_owner(newsk, THIS_MODULE);
 
-	newsk->sk_type = SOCK_STREAM;
+	newsk->type = SOCK_STREAM;
 
-	newsk->sk_prot = sk->sk_prot;
-	newsk->sk_no_check = sk->sk_no_check;
-	newsk->sk_reuse = sk->sk_reuse;
-	newsk->sk_shutdown = sk->sk_shutdown;
-
-	newsk->sk_destruct = inet_sock_destruct;
-	newsk->sk_zapped = 0;
-	newsk->sk_family = PF_INET;
-	newsk->sk_protocol = IPPROTO_SCTP;
-	newsk->sk_backlog_rcv = sk->sk_prot->backlog_rcv;
+	newsk->prot = sk->prot;
+	newsk->no_check = sk->no_check;
+	newsk->reuse = sk->reuse;
+	newsk->shutdown = sk->shutdown;
+
+	newsk->destruct = inet_sock_destruct;
+	newsk->zapped = 0;
+	newsk->family = PF_INET;
+	newsk->protocol = IPPROTO_SCTP;
+	newsk->backlog_rcv = sk->prot->backlog_rcv;
 
 	newinet = inet_sk(newsk);
 
@@ -597,7 +597,7 @@
 	atomic_inc(&inet_sock_nr);
 #endif
 
-	if (newsk->sk_prot->init(newsk)) {
+	if (newsk->prot->init(newsk)) {
 		inet_sock_release(newsk);
 		newsk = NULL;
 	}
@@ -638,7 +638,7 @@
  * Initialize the control inode/socket with a control endpoint data
  * structure.  This endpoint is reserved exclusively for the OOTB processing.
  */
-int sctp_ctl_sock_init(void)
+static int sctp_ctl_sock_init(void)
 {
 	int err;
 	sa_family_t family;
@@ -655,7 +655,7 @@
 		       "SCTP: Failed to create the SCTP control socket.\n");
 		return err;
 	}
-	sctp_ctl_socket->sk->sk_allocation = GFP_ATOMIC;
+	sctp_ctl_socket->sk->allocation = GFP_ATOMIC;
 	inet_sk(sctp_ctl_socket->sk)->ttl = MAXTTL;
 
 	return 0;
@@ -807,7 +807,7 @@
 	return ip_queue_xmit(skb, ipfragok);
 }
 
-struct sctp_af sctp_ipv4_specific;
+static struct sctp_af sctp_ipv4_specific;
 
 static struct sctp_pf sctp_pf_inet = {
 	.event_msgname = sctp_inet_event_msgname,
@@ -828,7 +828,7 @@
 };
 
 /* Socket operations.  */
-struct proto_ops inet_seqpacket_ops = {
+static struct proto_ops inet_seqpacket_ops = {
 	.family      = PF_INET,
 	.release     = inet_release,       /* Needs to be wrapped... */
 	.bind        = inet_bind,
@@ -877,7 +877,7 @@
 };
 
 /* IPv4 address related functions.  */
-struct sctp_af sctp_ipv4_specific = {
+static struct sctp_af sctp_ipv4_specific = {
 	.sctp_xmit      = sctp_v4_xmit,
 	.setsockopt     = ip_setsockopt,
 	.getsockopt     = ip_getsockopt,
@@ -948,7 +948,7 @@
 }
 
 /* Initialize the universe into something sensible.  */
-__init int sctp_init(void)
+SCTP_STATIC __init int sctp_init(void)
 {
 	int i;
 	int status = 0;
@@ -1161,7 +1161,7 @@
 }
 
 /* Exit handler for the SCTP protocol.  */
-__exit void sctp_exit(void)
+SCTP_STATIC __exit void sctp_exit(void)
 {
 	/* BUG.  This should probably do something useful like clean
 	 * up all the remaining associations and all that memory.
diff -urN linux-2.4.28-bk7/net/sctp/sm_make_chunk.c linux-2.4.29/net/sctp/sm_make_chunk.c
--- linux-2.4.28-bk7/net/sctp/sm_make_chunk.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/net/sctp/sm_make_chunk.c	2005-01-19 07:08:14.722710002 -0800
@@ -67,6 +67,19 @@
 
 extern kmem_cache_t *sctp_chunk_cachep;
 
+SCTP_STATIC
+struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc,
+				   __u8 type, __u8 flags, int paylen);
+static sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep,
+					const struct sctp_association *asoc,
+					const struct sctp_chunk *init_chunk,
+					int *cookie_len,
+					const __u8 *raw_addrs, int addrs_len);
+static int sctp_process_param(struct sctp_association *asoc,
+			      union sctp_params param,
+			      const union sctp_addr *peer_addr,
+			      int gfp);
+
 /* What was the inbound interface for this chunk? */
 int sctp_chunk_iif(const struct sctp_chunk *chunk)
 {
@@ -559,52 +572,6 @@
 	return retval;
 }
 
-/* Make a DATA chunk for the given association.  Populate the data
- * payload.
- */
-struct sctp_chunk *sctp_make_datafrag(struct sctp_association *asoc,
-				 const struct sctp_sndrcvinfo *sinfo,
-				 int data_len, const __u8 *data,
-				 __u8 flags, __u16 ssn)
-{
-	struct sctp_chunk *retval;
-
-	retval = sctp_make_datafrag_empty(asoc, sinfo, data_len, flags, ssn);
-	if (retval)
-		sctp_addto_chunk(retval, data_len, data);
-
-	return retval;
-}
-
-/* Make a DATA chunk for the given association to ride on stream id
- * 'stream', with a payload id of 'payload', and a body of 'data'.
- */
-struct sctp_chunk *sctp_make_data(struct sctp_association *asoc,
-			     const struct sctp_sndrcvinfo *sinfo,
-			     int data_len, const __u8 *data)
-{
-	struct sctp_chunk *retval = NULL;
-
-	retval = sctp_make_data_empty(asoc, sinfo, data_len);
-	if (retval)
-		sctp_addto_chunk(retval, data_len, data);
-        return retval;
-}
-
-/* Make a DATA chunk for the given association to ride on stream id
- * 'stream', with a payload id of 'payload', and a body big enough to
- * hold 'data_len' octets of data.  We use this version when we need
- * to build the message AFTER allocating memory.
- */
-struct sctp_chunk *sctp_make_data_empty(struct sctp_association *asoc,
-				   const struct sctp_sndrcvinfo *sinfo,
-				   int data_len)
-{
-	__u8 flags = SCTP_DATA_NOT_FRAG;
-
-	return sctp_make_datafrag_empty(asoc, sinfo, data_len, flags, 0);
-}
-
 /* Create a selective ackowledgement (SACK) for the given
  * association.  This reports on which TSN's we've seen to date,
  * including duplicates and gaps.
@@ -881,6 +848,31 @@
 	return retval;
 }
 
+/* Make an ABORT chunk with a PROTOCOL VIOLATION cause code. */ 
+struct sctp_chunk *sctp_make_abort_violation(
+	const struct sctp_association *asoc,
+	const struct sctp_chunk *chunk,
+	const __u8   *payload,
+	const size_t paylen)
+{
+	struct sctp_chunk  *retval;
+	struct sctp_paramhdr phdr;
+
+	retval = sctp_make_abort(asoc, chunk, sizeof(sctp_errhdr_t) + paylen
+					+ sizeof(sctp_chunkhdr_t));
+	if (!retval)
+		goto end;
+
+	sctp_init_cause(retval, SCTP_ERROR_PROTO_VIOLATION, payload, paylen);
+
+	phdr.type = htons(chunk->chunk_hdr->type);
+	phdr.length = chunk->chunk_hdr->length;
+	sctp_addto_chunk(retval, sizeof(sctp_paramhdr_t), &phdr);
+
+end:
+	return retval;
+}
+
 /* Make a HEARTBEAT chunk.  */
 struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc,
 				  const struct sctp_transport *transport,
@@ -933,7 +925,7 @@
 /* Create an Operation Error chunk with the specified space reserved.
  * This routine can be used for containing multiple causes in the chunk.
  */
-struct sctp_chunk *sctp_make_op_error_space(
+static struct sctp_chunk *sctp_make_op_error_space(
 	const struct sctp_association *asoc,
 	const struct sctp_chunk *chunk,
 	size_t size)
@@ -1034,7 +1026,6 @@
 	SCTP_DBG_OBJCNT_INC(chunk);
 	atomic_set(&retval->refcnt, 1);
 
-
 nodata:
 	return retval;
 }
@@ -1062,6 +1053,7 @@
 /* Create a new chunk, setting the type and flags headers from the
  * arguments, reserving enough space for a 'paylen' byte payload.
  */
+SCTP_STATIC
 struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc,
 				   __u8 type, __u8 flags, int paylen)
 {
@@ -1261,7 +1253,7 @@
 /* Build a cookie representing asoc.
  * This INCLUDES the param header needed to put the cookie in the INIT ACK.
  */
-sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep,
+static sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep,
 				      const struct sctp_association *asoc,
 				      const struct sctp_chunk *init_chunk,
 				      int *cookie_len,
@@ -1409,6 +1401,24 @@
 	}
 
 no_hmac:
+	/* IG Section 2.35.2:
+	 *  3) Compare the port numbers and the verification tag contained
+	 *     within the COOKIE ECHO chunk to the actual port numbers and the
+	 *     verification tag within the SCTP common header of the received
+	 *     packet. If these values do not match the packet MUST be silently
+	 *     discarded,
+	 */
+	if (ntohl(chunk->sctp_hdr->vtag) != bear_cookie->my_vtag) {
+		*error = -SCTP_IERROR_BAD_TAG;
+		goto fail;
+	}
+
+	if (ntohs(chunk->sctp_hdr->source) != bear_cookie->peer_addr.v4.sin_port ||
+	    ntohs(chunk->sctp_hdr->dest) != bear_cookie->my_port) {
+		*error = -SCTP_IERROR_BAD_PORTS;
+		goto fail;
+	}
+
 	/* Check to see if the cookie is stale.  If there is already
 	 * an association, there is no need to check cookie's expiration
 	 * for init collision case of lost COOKIE ACK.
@@ -1547,6 +1557,30 @@
 	return 0;
 }
 
+static int sctp_process_inv_paramlength(const struct sctp_association *asoc,
+					struct sctp_paramhdr *param,
+					const struct sctp_chunk *chunk,
+					struct sctp_chunk **errp)
+{
+	char		error[] = "The following parameter had invalid length:";
+	size_t		payload_len = WORD_ROUND(sizeof(error)) + 
+						sizeof(sctp_paramhdr_t);
+
+
+	/* Create an error chunk and fill it in with our payload. */
+	if (!*errp)
+		*errp = sctp_make_op_error_space(asoc, chunk, payload_len);
+
+	if (*errp) {
+		sctp_init_cause(*errp, SCTP_ERROR_PROTO_VIOLATION, error,
+				sizeof(error));
+		sctp_addto_chunk(*errp, sizeof(sctp_paramhdr_t), param);
+	}
+
+	return 0;
+}
+
+
 /* Do not attempt to handle the HOST_NAME parm.  However, do
  * send back an indicator to the peer.
  */
@@ -1725,6 +1759,18 @@
 
 	} /* for (loop through all parameters) */
 
+	/* There is a possibility that a parameter length was bad and
+	 * in that case we would have stoped walking the parameters.
+	 * The current param.p would point at the bad one.
+	 * Current consensus on the mailing list is to generate a PROTOCOL
+	 * VIOLATION error.  We build the ERROR chunk here and let the normal
+	 * error handling code build and send the packet.
+	 */
+	if (param.v < (void*)chunk->chunk_end - sizeof(sctp_paramhdr_t)) {
+		sctp_process_inv_paramlength(asoc, param.p, chunk, errp);
+		return 0;
+	}
+
 	/* The only missing mandatory param possible today is
 	 * the state cookie for an INIT-ACK chunk.
 	 */
@@ -1896,8 +1942,10 @@
  * work we do.  In particular, we should not build transport
  * structures for the addresses.
  */
-int sctp_process_param(struct sctp_association *asoc, union sctp_params param,
-		       const union sctp_addr *peer_addr, int gfp)
+static int sctp_process_param(struct sctp_association *asoc,
+			      union sctp_params param,
+			      const union sctp_addr *peer_addr,
+			      int gfp)
 {
 	union sctp_addr addr;
 	int i;
@@ -1913,7 +1961,7 @@
 	 */
 	switch (param.p->type) {
 	case SCTP_PARAM_IPV6_ADDRESS:
-		if (PF_INET6 != asoc->base.sk->sk_family)
+		if (PF_INET6 != asoc->base.sk->family)
 			break;
 		/* Fall through. */
 	case SCTP_PARAM_IPV4_ADDRESS:
@@ -2062,8 +2110,9 @@
  *
  * Address Parameter and other parameter will not be wrapped in this function 
  */
-struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc,
-				    union sctp_addr *addr, int vparam_len)
+static struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc,
+					   union sctp_addr *addr,
+					   int vparam_len)
 {
 	sctp_addiphdr_t asconf;
 	struct sctp_chunk *retval;
@@ -2232,8 +2281,8 @@
  *
  * Create an ASCONF_ACK chunk with enough space for the parameter responses. 
  */
-struct sctp_chunk *sctp_make_asconf_ack(const struct sctp_association *asoc,
-					__u32 serial, int vparam_len)
+static struct sctp_chunk *sctp_make_asconf_ack(const struct sctp_association *asoc,
+					       __u32 serial, int vparam_len)
 {
 	sctp_addiphdr_t		asconf;
 	struct sctp_chunk	*retval;
diff -urN linux-2.4.28-bk7/net/sctp/sm_sideeffect.c linux-2.4.29/net/sctp/sm_sideeffect.c
--- linux-2.4.28-bk7/net/sctp/sm_sideeffect.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/net/sctp/sm_sideeffect.c	2005-01-19 07:08:14.724710088 -0800
@@ -55,6 +55,24 @@
 #include <net/sctp/sctp.h>
 #include <net/sctp/sm.h>
 
+static int sctp_cmd_interpreter(sctp_event_t event_type,
+				sctp_subtype_t subtype,
+				sctp_state_t state,
+				struct sctp_endpoint *ep,
+				struct sctp_association *asoc,
+				void *event_arg,
+			 	sctp_disposition_t status,
+				sctp_cmd_seq_t *commands,
+				int gfp);
+static int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype,
+			     sctp_state_t state,
+			     struct sctp_endpoint *ep,
+			     struct sctp_association *asoc,
+			     void *event_arg,
+			     sctp_disposition_t status,
+			     sctp_cmd_seq_t *commands,
+			     int gfp);
+
 /********************************************************************
  * Helper functions
  ********************************************************************/
@@ -134,8 +152,8 @@
 }
 
 /* Generate SACK if necessary.  We call this at the end of a packet.  */
-int sctp_gen_sack(struct sctp_association *asoc, int force,
-		  sctp_cmd_seq_t *commands)
+static int sctp_gen_sack(struct sctp_association *asoc, int force,
+			 sctp_cmd_seq_t *commands)
 {
 	__u32 ctsn, max_tsn_seen;
 	struct sctp_chunk *sack;
@@ -229,7 +247,7 @@
 			   transport, GFP_ATOMIC);
 
 	if (error)
-		asoc->base.sk->sk_err = -error;
+		asoc->base.sk->err = -error;
 
 out_unlock:
 	sctp_bh_unlock_sock(asoc->base.sk);
@@ -269,38 +287,38 @@
 			   (void *)timeout_type, GFP_ATOMIC);
 
 	if (error)
-		asoc->base.sk->sk_err = -error;
+		asoc->base.sk->err = -error;
 
 out_unlock:
 	sctp_bh_unlock_sock(asoc->base.sk);
 	sctp_association_put(asoc);
 }
 
-void sctp_generate_t1_cookie_event(unsigned long data)
+static void sctp_generate_t1_cookie_event(unsigned long data)
 {
 	struct sctp_association *asoc = (struct sctp_association *) data;
 	sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T1_COOKIE);
 }
 
-void sctp_generate_t1_init_event(unsigned long data)
+static void sctp_generate_t1_init_event(unsigned long data)
 {
 	struct sctp_association *asoc = (struct sctp_association *) data;
 	sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T1_INIT);
 }
 
-void sctp_generate_t2_shutdown_event(unsigned long data)
+static void sctp_generate_t2_shutdown_event(unsigned long data)
 {
 	struct sctp_association *asoc = (struct sctp_association *) data;
 	sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T2_SHUTDOWN);
 }
 
-void sctp_generate_t4_rto_event(unsigned long data)
+static void sctp_generate_t4_rto_event(unsigned long data)
 {
 	struct sctp_association *asoc = (struct sctp_association *) data;
 	sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T4_RTO);
 }
 
-void sctp_generate_t5_shutdown_guard_event(unsigned long data)
+static void sctp_generate_t5_shutdown_guard_event(unsigned long data)
 {
         struct sctp_association *asoc = (struct sctp_association *)data;
         sctp_generate_timeout_event(asoc,
@@ -308,7 +326,7 @@
 
 } /* sctp_generate_t5_shutdown_guard_event() */
 
-void sctp_generate_autoclose_event(unsigned long data)
+static void sctp_generate_autoclose_event(unsigned long data)
 {
 	struct sctp_association *asoc = (struct sctp_association *) data;
 	sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_AUTOCLOSE);
@@ -345,7 +363,7 @@
 			   transport, GFP_ATOMIC);
 
          if (error)
-		 asoc->base.sk->sk_err = -error;
+		 asoc->base.sk->err = -error;
 
 out_unlock:
 	sctp_bh_unlock_sock(asoc->base.sk);
@@ -353,7 +371,7 @@
 }
 
 /* Inject a SACK Timeout event into the state machine.  */
-void sctp_generate_sack_event(unsigned long data)
+static void sctp_generate_sack_event(unsigned long data)
 {
 	struct sctp_association *asoc = (struct sctp_association *) data;
 	sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_SACK);
@@ -397,7 +415,7 @@
 	asoc->overall_error_count++;
 
 	if (transport->active &&
-	    (transport->error_count++ >= transport->error_threshold)) {
+	    (transport->error_count++ >= transport->max_retrans)) {
 		SCTP_DEBUG_PRINTK("transport_strike: transport "
 				  "IP:%d.%d.%d.%d failed.\n",
 				  NIPQUAD(transport->ipaddr.v4.sin_addr));
@@ -460,9 +478,9 @@
 	sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
 			SCTP_STATE(SCTP_STATE_CLOSED));
 
-	/* Set sk_err to ECONNRESET on a 1-1 style socket. */
+	/* Set sk->err to ECONNRESET on a 1-1 style socket. */
 	if (!sctp_style(asoc->base.sk, UDP))
-		asoc->base.sk->sk_err = ECONNRESET; 
+		asoc->base.sk->err = ECONNRESET; 
 
 	/* SEND_FAILED sent later when cleaning up the association. */
 	asoc->outqueue.error = error;
@@ -648,16 +666,16 @@
 	asoc->state = state;
 
 	if (sctp_style(sk, TCP)) {
-		/* Change the sk->sk_state of a TCP-style socket that has 
+		/* Change the sk->state of a TCP-style socket that has 
 		 * sucessfully completed a connect() call.
 		 */
 		if (sctp_state(asoc, ESTABLISHED) && sctp_sstate(sk, CLOSED))
-			sk->sk_state = SCTP_SS_ESTABLISHED;
+			sk->state = SCTP_SS_ESTABLISHED;
 
 		/* Set the RCV_SHUTDOWN flag when a SHUTDOWN is received. */
 		if (sctp_state(asoc, SHUTDOWN_RECEIVED) &&
 		    sctp_sstate(sk, ESTABLISHED))
-			sk->sk_shutdown |= RCV_SHUTDOWN;
+			sk->shutdown |= RCV_SHUTDOWN;
 	}
 
 	if (sctp_state(asoc, ESTABLISHED) ||
@@ -676,7 +694,7 @@
 		 * notifications.
 		 */
 		if (!sctp_style(sk, UDP))
-			sk->sk_state_change(sk);
+			sk->state_change(sk);
 	}
 }
 
@@ -691,7 +709,7 @@
 	 * can pick it up later.
 	 */ 
 	if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING) &&
-	    (!asoc->temp) && (sk->sk_shutdown != SHUTDOWN_MASK))
+	    (!asoc->temp) && (sk->shutdown != SHUTDOWN_MASK))
 		return;
 
 	sctp_unhash_established(asoc);
@@ -857,14 +875,14 @@
 /*****************************************************************
  * This the master state function side effect processing function.
  *****************************************************************/
-int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype,
-		      sctp_state_t state,
-		      struct sctp_endpoint *ep,
-		      struct sctp_association *asoc,
-		      void *event_arg,
-		      sctp_disposition_t status,
-		      sctp_cmd_seq_t *commands,
-		      int gfp)
+static int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype,
+			     sctp_state_t state,
+			     struct sctp_endpoint *ep,
+			     struct sctp_association *asoc,
+			     void *event_arg,
+			     sctp_disposition_t status,
+			     sctp_cmd_seq_t *commands,
+			     int gfp)
 {
 	int error;
 
@@ -944,11 +962,15 @@
  ********************************************************************/
 
 /* This is the side-effect interpreter.  */
-int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
-			 sctp_state_t state, struct sctp_endpoint *ep,
-			 struct sctp_association *asoc, void *event_arg,
-			 sctp_disposition_t status, sctp_cmd_seq_t *commands,
-			 int gfp)
+static int sctp_cmd_interpreter(sctp_event_t event_type,
+				sctp_subtype_t subtype,
+				sctp_state_t state,
+				struct sctp_endpoint *ep,
+				struct sctp_association *asoc,
+				void *event_arg,
+			 	sctp_disposition_t status,
+				sctp_cmd_seq_t *commands,
+				int gfp)
 {
 	int error = 0;
 	int force;
diff -urN linux-2.4.28-bk7/net/sctp/sm_statefuns.c linux-2.4.29/net/sctp/sm_statefuns.c
--- linux-2.4.28-bk7/net/sctp/sm_statefuns.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/net/sctp/sm_statefuns.c	2005-01-19 07:08:14.733710478 -0800
@@ -65,6 +65,53 @@
 #include <net/sctp/sm.h>
 #include <net/sctp/structs.h>
 
+static struct sctp_packet *sctp_abort_pkt_new(const struct sctp_endpoint *ep,
+				  const struct sctp_association *asoc,
+				  struct sctp_chunk *chunk,
+				  const void *payload,
+				  size_t paylen);
+static int sctp_eat_data(const struct sctp_association *asoc,
+			 struct sctp_chunk *chunk,
+			 sctp_cmd_seq_t *commands);
+static struct sctp_packet *sctp_ootb_pkt_new(const struct sctp_association *asoc,
+					     const struct sctp_chunk *chunk);
+static void sctp_send_stale_cookie_err(const struct sctp_endpoint *ep,
+				       const struct sctp_association *asoc,
+				       const struct sctp_chunk *chunk,
+				       sctp_cmd_seq_t *commands,
+				       struct sctp_chunk *err_chunk);
+static sctp_disposition_t sctp_sf_do_5_2_6_stale(const struct sctp_endpoint *ep,
+						 const struct sctp_association *asoc,
+						 const sctp_subtype_t type,
+						 void *arg,
+						 sctp_cmd_seq_t *commands);
+static sctp_disposition_t sctp_sf_shut_8_4_5(const struct sctp_endpoint *ep,
+					     const struct sctp_association *asoc,
+					     const sctp_subtype_t type,
+					     void *arg,
+					     sctp_cmd_seq_t *commands);
+static struct sctp_sackhdr *sctp_sm_pull_sack(struct sctp_chunk *chunk);
+
+
+/* Small helper function that checks if the chunk length
+ * is of the appropriate length.  The 'required_length' argument
+ * is set to be the size of a specific chunk we are testing.
+ * Return Values:  1 = Valid length
+ * 		   0 = Invalid length
+ *
+ */
+static inline int
+sctp_chunk_length_valid(struct sctp_chunk *chunk,
+			   __u16 required_length)
+{
+	__u16 chunk_length = ntohs(chunk->chunk_hdr->length);
+
+	if (unlikely(chunk_length < required_length))
+		return 0;
+
+	return 1;
+}
+
 /**********************************************************
  * These are the state functions for handling chunk events.
  **********************************************************/
@@ -199,9 +246,14 @@
 	/* 6.10 Bundling
 	 * An endpoint MUST NOT bundle INIT, INIT ACK or
 	 * SHUTDOWN COMPLETE with any other chunks.
+	 * 
+	 * IG Section 2.11.2
+	 * Furthermore, we require that the receiver of an INIT chunk MUST
+	 * enforce these rules by silently discarding an arriving packet
+	 * with an INIT chunk that is bundled with other chunks.
 	 */
 	if (!chunk->singleton)
-		return SCTP_DISPOSITION_VIOLATION;
+		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
 	/* If the packet is an OOTB packet which is temporarily on the
 	 * control endpoint, respond with an ABORT.
@@ -216,7 +268,7 @@
 	 */
 	if (!sctp_sstate(sk, LISTENING) ||
 	    (sctp_style(sk, TCP) &&
-	     (sk->sk_ack_backlog >= sk->sk_max_ack_backlog)))
+	     (sk->ack_backlog >= sk->max_ack_backlog)))
 		return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);
 
 	/* 3.1 A packet containing an INIT chunk MUST have a zero Verification
@@ -225,6 +277,14 @@
 	if (chunk->sctp_hdr->vtag != 0)
 		return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);
 
+	/* Make sure that the INIT chunk has a valid length.
+	 * Normally, this would cause an ABORT with a Protocol Violation
+	 * error, but since we don't have an association, we'll
+	 * just discard the packet.
+	 */
+	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_init_chunk_t)))
+		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+
 	/* Verify the INIT chunk before processing it. */
 	err_chunk = NULL;
 	if (!sctp_verify_init(asoc, chunk->chunk_hdr->type,
@@ -376,6 +436,13 @@
 	struct sctp_packet *packet;
 	sctp_disposition_t ret;
 
+	if (!sctp_vtag_verify(chunk, asoc))
+		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+
+	/* Make sure that the INIT-ACK chunk has a valid length */
+	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_initack_chunk_t)))
+		return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+						  commands);
 	/* 6.10 Bundling
 	 * An endpoint MUST NOT bundle INIT, INIT ACK or
 	 * SHUTDOWN COMPLETE with any other chunks.
@@ -383,9 +450,6 @@
 	if (!chunk->singleton)
 		return SCTP_DISPOSITION_VIOLATION;
 
-	if (!sctp_vtag_verify(chunk, asoc))
-		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
-
 	/* Grab the INIT header.  */
 	chunk->subh.init_hdr = (sctp_inithdr_t *) chunk->skb->data;
 
@@ -542,6 +606,14 @@
 	if (ep == sctp_sk((sctp_get_ctl_sock()))->ep)
 		return sctp_sf_ootb(ep, asoc, type, arg, commands);
 
+	/* Make sure that the COOKIE_ECHO chunk has a valid length.
+	 * In this case, we check that we have enough for at least a
+	 * chunk header.  More detailed verification is done
+	 * in sctp_unpack_cookie().
+	 */
+	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t)))
+		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+
 	/* "Decode" the chunk.  We have no optional parameters so we
 	 * are in good shape.
 	 */
@@ -687,6 +759,13 @@
 	if (!sctp_vtag_verify(chunk, asoc))
 		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
+	/* Verify that the chunk length for the COOKIE-ACK is OK.
+	 * If we don't do this, any bundled chunks may be junked.
+	 */
+	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t)))
+		return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+						  commands);
+
 	/* Reset init error count upon receipt of COOKIE-ACK,
 	 * to avoid problems with the managemement of this
 	 * counter in stale cookie situations when a transition back
@@ -748,11 +827,11 @@
 }
 
 /* Generate and sendout a heartbeat packet.  */
-sctp_disposition_t sctp_sf_heartbeat(const struct sctp_endpoint *ep,
-				     const struct sctp_association *asoc,
-				     const sctp_subtype_t type,
-				     void *arg,
-				     sctp_cmd_seq_t *commands)
+static sctp_disposition_t sctp_sf_heartbeat(const struct sctp_endpoint *ep,
+					    const struct sctp_association *asoc,
+					    const sctp_subtype_t type,
+					    void *arg,
+					    sctp_cmd_seq_t *commands)
 {
 	struct sctp_transport *transport = (struct sctp_transport *) arg;
 	struct sctp_chunk *reply;
@@ -859,6 +938,11 @@
 	if (!sctp_vtag_verify(chunk, asoc))
 		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
+	/* Make sure that the HEARTBEAT chunk has a valid length. */
+	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_heartbeat_chunk_t)))
+		return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+						  commands);
+
 	/* 8.3 The receiver of the HEARTBEAT should immediately
 	 * respond with a HEARTBEAT ACK that contains the Heartbeat
 	 * Information field copied from the received HEARTBEAT chunk.
@@ -922,6 +1006,11 @@
 	if (!sctp_vtag_verify(chunk, asoc))
 		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
+	/* Make sure that the HEARTBEAT-ACK chunk has a valid length.  */
+	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_heartbeat_chunk_t)))
+		return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+						  commands);
+
 	hbinfo = (sctp_sender_hb_info_t *) chunk->skb->data;
 	from_addr = hbinfo->daddr;
 	link = sctp_assoc_lookup_paddr(asoc, &from_addr);
@@ -1165,9 +1254,14 @@
 	/* 6.10 Bundling
 	 * An endpoint MUST NOT bundle INIT, INIT ACK or
 	 * SHUTDOWN COMPLETE with any other chunks.
+	 *
+	 * IG Section 2.11.2
+	 * Furthermore, we require that the receiver of an INIT chunk MUST
+	 * enforce these rules by silently discarding an arriving packet
+	 * with an INIT chunk that is bundled with other chunks.
 	 */
 	if (!chunk->singleton)
-		return SCTP_DISPOSITION_VIOLATION;
+		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
 	/* 3.1 A packet containing an INIT chunk MUST have a zero Verification
 	 * Tag. 
@@ -1175,6 +1269,13 @@
 	if (chunk->sctp_hdr->vtag != 0)
 		return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);
 
+	/* Make sure that the INIT chunk has a valid length.
+	 * In this case, we generate a protocol violation since we have
+	 * an association established.
+	 */
+	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_init_chunk_t)))
+		return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+						  commands);
 	/* Grab the INIT header.  */
 	chunk->subh.init_hdr = (sctp_inithdr_t *) chunk->skb->data;
 
@@ -1718,6 +1819,15 @@
 	char action;
 	struct sctp_chunk *err_chk_p;
 
+	/* Make sure that the chunk has a valid length from the protocol
+	 * perspective.  In this case check to make sure we have at least
+	 * enough for the chunk header.  Cookie length verification is
+	 * done later.
+	 */
+	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t)))
+		return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+						  commands);
+
 	/* "Decode" the chunk.  We have no optional parameters so we
 	 * are in good shape.
 	 */
@@ -1815,6 +1925,19 @@
 	if (!sctp_vtag_verify_either(chunk, asoc))
 		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
+	/* Make sure that the ABORT chunk has a valid length.
+	 * Since this is an ABORT chunk, we have to discard it
+	 * because of the following text:
+	 * RFC 2960, Section 3.3.7
+	 *    If an endpoint receives an ABORT with a format error or for an
+	 *    association that doesn't exist, it MUST silently discard it.
+	 * Becasue the length is "invalid", we can't really discard just
+	 * as we do not know its true length.  So, to be safe, discard the
+	 * packet.
+	 */
+	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_abort_chunk_t)))
+		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+
 	/* Stop the T5-shutdown guard timer.  */
 	sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
 			SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD));
@@ -1838,6 +1961,19 @@
 	if (!sctp_vtag_verify_either(chunk, asoc))
 		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
+	/* Make sure that the ABORT chunk has a valid length.
+	 * Since this is an ABORT chunk, we have to discard it
+	 * because of the following text:
+	 * RFC 2960, Section 3.3.7
+	 *    If an endpoint receives an ABORT with a format error or for an
+	 *    association that doesn't exist, it MUST silently discard it.
+	 * Becasue the length is "invalid", we can't really discard just
+	 * as we do not know its true length.  So, to be safe, discard the
+	 * packet.
+	 */
+	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_abort_chunk_t)))
+		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+
 	/* Stop the T2-shutdown timer. */
 	sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
 			SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN));
@@ -1890,6 +2026,16 @@
 	struct sctp_chunk *chunk = arg;
 	sctp_errhdr_t *err;
 
+	if (!sctp_vtag_verify(chunk, asoc))
+		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+
+	/* Make sure that the ERROR chunk has a valid length.
+	 * The parameter walking depends on this as well.
+	 */
+	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_operr_chunk_t)))
+		return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+						  commands);
+
 	/* Process the error here */
 	/* FUTURE FIXME:  When PR-SCTP related and other optional
 	 * parms are emitted, this will have to change to handle multiple
@@ -1900,6 +2046,12 @@
 			return sctp_sf_do_5_2_6_stale(ep, asoc, type, 
 							arg, commands);
 	}
+
+	/* It is possible to have malformed error causes, and that
+	 * will cause us to end the walk early.  However, since
+	 * we are discarding the packet, there should be no adverse
+	 * affects.
+	 */
 	return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 }
 
@@ -1928,11 +2080,11 @@
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_do_5_2_6_stale(const struct sctp_endpoint *ep,
-					  const struct sctp_association *asoc,
-					  const sctp_subtype_t type,
-					  void *arg,
-					  sctp_cmd_seq_t *commands)
+static sctp_disposition_t sctp_sf_do_5_2_6_stale(const struct sctp_endpoint *ep,
+						 const struct sctp_association *asoc,
+						 const sctp_subtype_t type,
+						 void *arg,
+						 sctp_cmd_seq_t *commands)
 {
 	struct sctp_chunk *chunk = arg;
 	time_t stale;
@@ -2064,12 +2216,24 @@
 	if (!sctp_vtag_verify_either(chunk, asoc))
 		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
-	/* Check that chunk header looks valid.  */
+	/* Make sure that the ABORT chunk has a valid length.
+	 * Since this is an ABORT chunk, we have to discard it
+	 * because of the following text:
+	 * RFC 2960, Section 3.3.7
+	 *    If an endpoint receives an ABORT with a format error or for an
+	 *    association that doesn't exist, it MUST silently discard it.
+	 * Becasue the length is "invalid", we can't really discard just
+	 * as we do not know its true length.  So, to be safe, discard the
+	 * packet.
+	 */
+	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_abort_chunk_t)))
+		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+
+	/* See if we have an error cause code in the chunk.  */
 	len = ntohs(chunk->chunk_hdr->length);
 	if (len >= sizeof(struct sctp_chunkhdr) + sizeof(struct sctp_errhdr))
 		error = ((sctp_errhdr_t *)chunk->skb->data)->cause;
 
-
  	/* ASSOC_FAILED will DELETE_TCB. */
 	sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_U32(error));
 	SCTP_INC_STATS(SctpAborteds);
@@ -2096,27 +2260,44 @@
 	if (!sctp_vtag_verify_either(chunk, asoc))
 		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
-	sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
-			SCTP_STATE(SCTP_STATE_CLOSED));
-	SCTP_INC_STATS(SctpAborteds);
-	sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
-			SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT));
+	/* Make sure that the ABORT chunk has a valid length.
+	 * Since this is an ABORT chunk, we have to discard it
+	 * because of the following text:
+	 * RFC 2960, Section 3.3.7
+	 *    If an endpoint receives an ABORT with a format error or for an
+	 *    association that doesn't exist, it MUST silently discard it.
+	 * Becasue the length is "invalid", we can't really discard just
+	 * as we do not know its true length.  So, to be safe, discard the
+	 * packet.
+	 */
+	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_abort_chunk_t)))
+		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
-	/* Check that chunk header looks valid.  */
+	/* See if we have an error cause code in the chunk.  */
 	len = ntohs(chunk->chunk_hdr->length);
 	if (len >= sizeof(struct sctp_chunkhdr) + sizeof(struct sctp_errhdr))
 		error = ((sctp_errhdr_t *)chunk->skb->data)->cause;
 
-	/* CMD_INIT_FAILED will DELETE_TCB. */
-	sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_U32(error));
+	sctp_stop_t1_and_abort(commands, error);
 
 	return SCTP_DISPOSITION_ABORT;
 }
 
 /*
+ * Process an incoming ICMP as an ABORT.  (COOKIE-WAIT state)
+ */
+sctp_disposition_t sctp_sf_cookie_wait_icmp_abort(const struct sctp_endpoint *ep,
+					const struct sctp_association *asoc,
+					const sctp_subtype_t type,
+					void *arg,
+					sctp_cmd_seq_t *commands)
+{
+	sctp_stop_t1_and_abort(commands, SCTP_ERROR_NO_ERROR);
+	return SCTP_DISPOSITION_ABORT;
+}
+
+/*
  * Process an ABORT.  (COOKIE-ECHOED state)
- *
- * See sctp_sf_do_9_1_abort() above.
  */
 sctp_disposition_t sctp_sf_cookie_echoed_abort(const struct sctp_endpoint *ep,
 					       const struct sctp_association *asoc,
@@ -2131,6 +2312,23 @@
 }
 
 /*
+ * Stop T1 timer and abort association with "INIT failed".
+ *
+ * This is common code called by several sctp_sf_*_abort() functions above.
+ */
+void sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands, __u16 error)
+{
+	sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
+			SCTP_STATE(SCTP_STATE_CLOSED));
+	SCTP_INC_STATS(SctpAborteds);
+	sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
+			SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT));
+	/* CMD_INIT_FAILED will DELETE_TCB. */
+	sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED,
+			SCTP_U32(error));
+}
+
+/*
  * sctp_sf_do_9_2_shut
  *
  * Section: 9.2
@@ -2174,14 +2372,20 @@
 	sctp_disposition_t disposition;
 	struct sctp_ulpevent *ev;
 
+	if (!sctp_vtag_verify(chunk, asoc))
+		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+
+	/* Make sure that the SHUTDOWN chunk has a valid length. */
+	if (!sctp_chunk_length_valid(chunk,
+				      sizeof(struct sctp_shutdown_chunk_t)))
+		return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+						  commands);
+
 	/* Convert the elaborate header.  */
 	sdh = (sctp_shutdownhdr_t *)chunk->skb->data;
 	skb_pull(chunk->skb, sizeof(sctp_shutdownhdr_t));
 	chunk->subh.shutdown_hdr = sdh;
 
-	if (!sctp_vtag_verify(chunk, asoc))
-		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
-
 	/* Upon the reception of the SHUTDOWN, the peer endpoint shall
 	 *  - enter the SHUTDOWN-RECEIVED state,
 	 *  - stop accepting new data from its SCTP user
@@ -2238,6 +2442,10 @@
 	struct sctp_chunk *chunk = (struct sctp_chunk *) arg;
 	struct sctp_chunk *reply;
 
+	/* Since we are not going to really process this INIT, there
+	 * is no point in verifying chunk boundries.  Just generate
+	 * the SHUTDOWN ACK.
+	 */
 	reply = sctp_make_shutdown_ack(asoc, chunk);
 	if (NULL == reply)
 		goto nomem;
@@ -2295,6 +2503,10 @@
 	if (!sctp_vtag_verify(chunk, asoc))
 		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
+	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_ecne_chunk_t)))
+		return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+						  commands);
+		
 	cwr = (sctp_cwrhdr_t *) chunk->skb->data;
 	skb_pull(chunk->skb, sizeof(sctp_cwrhdr_t));
 
@@ -2345,6 +2557,10 @@
 	if (!sctp_vtag_verify(chunk, asoc))
 		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
+	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_ecne_chunk_t)))
+		return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+						  commands);
+
 	ecne = (sctp_ecnehdr_t *) chunk->skb->data;
 	skb_pull(chunk->skb, sizeof(sctp_ecnehdr_t));
 
@@ -2400,6 +2616,10 @@
 		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
         }
 
+	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_data_chunk_t)))
+		return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+						  commands);
+
 	error = sctp_eat_data(asoc, chunk, commands );
 	switch (error) {
 	case SCTP_IERROR_NO_ERROR:
@@ -2518,6 +2738,10 @@
 	}
 
 
+	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_data_chunk_t)))
+		return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+						  commands);
+
 	error = sctp_eat_data(asoc, chunk, commands );
 	switch (error) {
 	case SCTP_IERROR_NO_ERROR:
@@ -2599,6 +2823,11 @@
 	if (!sctp_vtag_verify(chunk, asoc))
 		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
+	/* Make sure that the SACK chunk has a valid length. */
+	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_sack_chunk_t)))
+		return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+						  commands);
+
 	/* Pull the SACK chunk from the data buffer */
 	sackh = sctp_sm_pull_sack(chunk);
 	/* Was this a bogus SACK? */
@@ -2701,6 +2930,14 @@
 	struct sctp_chunk *chunk = arg;
 	struct sctp_ulpevent *ev;
 
+	if (!sctp_vtag_verify(chunk, asoc))
+		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+
+	/* Make sure that the ERROR chunk has a valid length. */
+	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_operr_chunk_t)))
+		return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+						  commands);
+
 	while (chunk->chunk_end > chunk->skb->data) {
 		ev = sctp_ulpevent_make_remote_error(asoc, chunk, 0,
 						     GFP_ATOMIC);
@@ -2745,6 +2982,11 @@
 	if (!sctp_vtag_verify(chunk, asoc))
 		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
+	/* Make sure that the SHUTDOWN_ACK chunk has a valid length. */
+	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t)))
+		return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+						  commands);
+
 	/* 10.2 H) SHUTDOWN COMPLETE notification
 	 *
 	 * When SCTP completes the shutdown procedures (section 9.2) this
@@ -2819,11 +3061,23 @@
 
 	ch = (sctp_chunkhdr_t *) chunk->chunk_hdr;
 	do {
+		/* Break out if chunk length is less then minimal. */
+		if (ntohs(ch->length) < sizeof(sctp_chunkhdr_t))
+			break;
+
 		ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length));
 
 		if (SCTP_CID_SHUTDOWN_ACK == ch->type)
 			ootb_shut_ack = 1;
 
+		/* RFC 2960, Section 3.3.7
+		 *   Moreover, under any circumstances, an endpoint that
+		 *   receives an ABORT  MUST NOT respond to that ABORT by
+		 *   sending an ABORT of its own.
+		 */
+		if (SCTP_CID_ABORT == ch->type)
+			return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+			
 		ch = (sctp_chunkhdr_t *) ch_end;
 	} while (ch_end < skb->tail);
 
@@ -2854,11 +3108,11 @@
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_shut_8_4_5(const struct sctp_endpoint *ep,
-				      const struct sctp_association *asoc,
-				      const sctp_subtype_t type,
-				      void *arg,
-				      sctp_cmd_seq_t *commands)
+static sctp_disposition_t sctp_sf_shut_8_4_5(const struct sctp_endpoint *ep,
+					     const struct sctp_association *asoc,
+					     const sctp_subtype_t type,
+					     void *arg,
+					     sctp_cmd_seq_t *commands)
 {
 	struct sctp_packet *packet = NULL;
 	struct sctp_chunk *chunk = arg;
@@ -2886,6 +3140,12 @@
 
 		SCTP_INC_STATS(SctpOutCtrlChunks);
 
+		/* If the chunk length is invalid, we don't want to process
+		 * the reset of the packet.
+		 */
+		if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t)))
+			return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+
 		return SCTP_DISPOSITION_CONSUME;
 	}
 
@@ -2928,6 +3188,17 @@
 	sctp_addiphdr_t		*hdr;
 	__u32			serial;
 
+	if (!sctp_vtag_verify(chunk, asoc)) {
+		sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG,
+				SCTP_NULL());
+		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+	}
+
+	/* Make sure that the ASCONF ADDIP chunk has a valid length.  */
+	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_addip_chunk_t)))
+		return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+						  commands);
+
 	hdr = (sctp_addiphdr_t *)chunk->skb->data;
 	serial = ntohl(hdr->serial);
 
@@ -2948,7 +3219,8 @@
 		/* ADDIP 4.2 C3) If the value found in the serial number is
 		 * equal to the value stored in the 'Peer-Serial-Number'
 		 * IMPLEMENTATION NOTE: As an optimization a receiver may wish
-		 * to save the last ASCONF-ACK for some predetermined period of 		 * time and instead of re-processing the ASCONF (with the same
+		 * to save the last ASCONF-ACK for some predetermined period of
+		 * time and instead of re-processing the ASCONF (with the same
 		 * serial number) it may just re-transmit the ASCONF-ACK.
 		 */
 		if (asoc->addip_last_asconf_ack)
@@ -2987,6 +3259,17 @@
 	sctp_addiphdr_t		*addip_hdr;
 	__u32			sent_serial, rcvd_serial;
 
+	if (!sctp_vtag_verify(asconf_ack, asoc)) {
+		sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG,
+				SCTP_NULL());
+		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+	}
+
+	/* Make sure that the ADDIP chunk has a valid length.  */
+	if (!sctp_chunk_length_valid(asconf_ack, sizeof(sctp_addip_chunk_t)))
+		return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+						  commands);
+
 	addip_hdr = (sctp_addiphdr_t *)asconf_ack->skb->data;
 	rcvd_serial = ntohl(addip_hdr->serial);
 
@@ -3085,6 +3368,11 @@
 		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 	}
 
+	/* Make sure that the FORWARD_TSN chunk has valid length.  */
+	if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_fwdtsn_chunk)))
+		return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+						  commands);
+
 	fwdtsn_hdr = (struct sctp_fwdtsn_hdr *)chunk->skb->data;
 	chunk->subh.fwdtsn_hdr = fwdtsn_hdr;
 	len = ntohs(chunk->chunk_hdr->length);
@@ -3143,6 +3431,11 @@
 		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 	}
 
+	/* Make sure that the FORWARD_TSN chunk has a valid length.  */
+	if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_fwdtsn_chunk)))
+		return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+						  commands);
+
 	fwdtsn_hdr = (struct sctp_fwdtsn_hdr *)chunk->skb->data;
 	chunk->subh.fwdtsn_hdr = fwdtsn_hdr;
 	len = ntohs(chunk->chunk_hdr->length);
@@ -3217,6 +3510,14 @@
 	if (!sctp_vtag_verify(unk_chunk, asoc))
 		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
+	/* Make sure that the chunk has a valid length.
+	 * Since we don't know the chunk type, we use a general
+	 * chunkhdr structure to make a comparison.
+	 */
+	if (!sctp_chunk_length_valid(unk_chunk, sizeof(sctp_chunkhdr_t)))
+		return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+						  commands);
+
 	switch (type.chunk & SCTP_CID_ACTION_MASK) {
 	case SCTP_CID_ACTION_DISCARD:
 		/* Discard the packet.  */
@@ -3339,6 +3640,66 @@
 	return SCTP_DISPOSITION_VIOLATION;
 }
 
+
+/*
+ * Handle a protocol violation when the chunk length is invalid.
+ * "Invalid" length is identified as smaller then the minimal length a
+ * given chunk can be.  For example, a SACK chunk has invalid length
+ * if it's length is set to be smaller then the size of sctp_sack_chunk_t.
+ *
+ * We inform the other end by sending an ABORT with a Protocol Violation
+ * error code. 
+ *
+ * Section: Not specified
+ * Verification Tag:  Nothing to do
+ * Inputs
+ * (endpoint, asoc, chunk)
+ *
+ * Outputs
+ * (reply_msg, msg_up, counters)
+ *
+ * Generate an  ABORT chunk and terminate the association.
+ */
+sctp_disposition_t sctp_sf_violation_chunklen(const struct sctp_endpoint *ep,
+				     const struct sctp_association *asoc,
+				     const sctp_subtype_t type,
+				     void *arg,
+				     sctp_cmd_seq_t *commands)
+{
+	struct sctp_chunk *chunk =  arg;
+	struct sctp_chunk *abort = NULL;
+	char 		   err_str[]="The following chunk had invalid length:";
+
+	/* Make the abort chunk. */
+	abort = sctp_make_abort_violation(asoc, chunk, err_str,
+					  sizeof(err_str));
+	if (!abort)
+		goto nomem;
+
+	sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort));
+	SCTP_INC_STATS(SctpOutCtrlChunks);
+
+	if (asoc->state <= SCTP_STATE_COOKIE_ECHOED) {
+		sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
+				SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT));
+		sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED,
+				SCTP_U32(SCTP_ERROR_PROTO_VIOLATION));
+	} else {
+		sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
+				SCTP_U32(SCTP_ERROR_PROTO_VIOLATION));
+		SCTP_DEC_STATS(SctpCurrEstab);
+	}
+
+	sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET, SCTP_NULL());
+
+	SCTP_INC_STATS(SctpAborteds);
+	
+	return SCTP_DISPOSITION_ABORT;
+
+nomem:
+	return SCTP_DISPOSITION_NOMEM;
+}
+
 /***************************************************************************
  * These are the state functions for handling primitive (Section 10) events.
  ***************************************************************************/
@@ -4051,6 +4412,23 @@
 	struct sctp_chunk *chunk = (struct sctp_chunk *) arg;
 	struct sctp_chunk *reply;
 
+	/* There are 2 ways of getting here:
+	 *    1) called in response to a SHUTDOWN chunk
+	 *    2) called when SCTP_EVENT_NO_PENDING_TSN event is issued.
+	 *
+	 * For the case (2), the arg parameter is set to NULL.  We need
+	 * to check that we have a chunk before accessing it's fields.
+	 */
+	if (chunk) {
+		if (!sctp_vtag_verify(chunk, asoc))
+			return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+
+		/* Make sure that the SHUTDOWN chunk has a valid length. */
+		if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_shutdown_chunk_t)))
+			return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+							  commands);
+	}
+
 	/* If it has no more outstanding DATA chunks, the SHUTDOWN receiver
 	 * shall send a SHUTDOWN ACK ...
 	 */
@@ -4538,7 +4916,7 @@
  ********************************************************************/
 
 /* Pull the SACK chunk based on the SACK header. */
-struct sctp_sackhdr *sctp_sm_pull_sack(struct sctp_chunk *chunk)
+static struct sctp_sackhdr *sctp_sm_pull_sack(struct sctp_chunk *chunk)
 {
 	struct sctp_sackhdr *sack;
 	unsigned int len;
@@ -4565,7 +4943,7 @@
 /* Create an ABORT packet to be sent as a response, with the specified
  * error causes.
  */
-struct sctp_packet *sctp_abort_pkt_new(const struct sctp_endpoint *ep,
+static struct sctp_packet *sctp_abort_pkt_new(const struct sctp_endpoint *ep,
 				  const struct sctp_association *asoc,
 				  struct sctp_chunk *chunk,
 				  const void *payload,
@@ -4601,8 +4979,8 @@
 }
 
 /* Allocate a packet for responding in the OOTB conditions.  */
-struct sctp_packet *sctp_ootb_pkt_new(const struct sctp_association *asoc,
-				 const struct sctp_chunk *chunk)
+static struct sctp_packet *sctp_ootb_pkt_new(const struct sctp_association *asoc,
+					     const struct sctp_chunk *chunk)
 {
 	struct sctp_packet *packet;
 	struct sctp_transport *transport;
@@ -4665,11 +5043,11 @@
 }
 
 /* Send a stale cookie error when a invalid COOKIE ECHO chunk is found  */
-void sctp_send_stale_cookie_err(const struct sctp_endpoint *ep,
-				const struct sctp_association *asoc,
-				const struct sctp_chunk *chunk,
-				sctp_cmd_seq_t *commands,
-				struct sctp_chunk *err_chunk)
+static void sctp_send_stale_cookie_err(const struct sctp_endpoint *ep,
+				       const struct sctp_association *asoc,
+				       const struct sctp_chunk *chunk,
+				       sctp_cmd_seq_t *commands,
+				       struct sctp_chunk *err_chunk)
 {
 	struct sctp_packet *packet;
 
@@ -4695,9 +5073,9 @@
 
 
 /* Process a data chunk */
-int sctp_eat_data(const struct sctp_association *asoc,
-		  struct sctp_chunk *chunk,
-		  sctp_cmd_seq_t *commands)
+static int sctp_eat_data(const struct sctp_association *asoc,
+			 struct sctp_chunk *chunk,
+			 sctp_cmd_seq_t *commands)
 {
 	sctp_datahdr_t *data_hdr;
 	struct sctp_chunk *err;
diff -urN linux-2.4.28-bk7/net/sctp/sm_statetable.c linux-2.4.29/net/sctp/sm_statetable.c
--- linux-2.4.28-bk7/net/sctp/sm_statetable.c	2004-08-07 16:26:07.000000000 -0700
+++ linux-2.4.29/net/sctp/sm_statetable.c	2005-01-19 07:08:14.734710522 -0800
@@ -50,6 +50,17 @@
 #include <net/sctp/sctp.h>
 #include <net/sctp/sm.h>
 
+static const sctp_sm_table_entry_t
+primitive_event_table[SCTP_NUM_PRIMITIVE_TYPES][SCTP_STATE_NUM_STATES];
+static const sctp_sm_table_entry_t
+other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_STATE_NUM_STATES];
+static const sctp_sm_table_entry_t
+timeout_event_table[SCTP_NUM_TIMEOUT_TYPES][SCTP_STATE_NUM_STATES];
+
+static const sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t cid,
+							    sctp_state_t state);
+
+
 static const sctp_sm_table_entry_t bug = {
 	.fn = sctp_sf_bug,
 	.name = "sctp_sf_bug"
@@ -419,7 +430,7 @@
  *
  * For base protocol (RFC 2960).
  */
-const sctp_sm_table_entry_t chunk_event_table[SCTP_NUM_BASE_CHUNK_TYPES][SCTP_STATE_NUM_STATES] = {
+static const sctp_sm_table_entry_t chunk_event_table[SCTP_NUM_BASE_CHUNK_TYPES][SCTP_STATE_NUM_STATES] = {
 	TYPE_SCTP_DATA,
 	TYPE_SCTP_INIT,
 	TYPE_SCTP_INIT_ACK,
@@ -482,7 +493,7 @@
 /* The primary index for this table is the chunk type.
  * The secondary index for this table is the state.
  */
-const sctp_sm_table_entry_t addip_chunk_event_table[SCTP_NUM_ADDIP_CHUNK_TYPES][SCTP_STATE_NUM_STATES] = {
+static const sctp_sm_table_entry_t addip_chunk_event_table[SCTP_NUM_ADDIP_CHUNK_TYPES][SCTP_STATE_NUM_STATES] = {
 	TYPE_SCTP_ASCONF,
 	TYPE_SCTP_ASCONF_ACK,
 }; /*state_fn_t addip_chunk_event_table[][] */
@@ -511,7 +522,7 @@
 /* The primary index for this table is the chunk type.
  * The secondary index for this table is the state.
  */
-const sctp_sm_table_entry_t prsctp_chunk_event_table[SCTP_NUM_PRSCTP_CHUNK_TYPES][SCTP_STATE_NUM_STATES] = {
+static const sctp_sm_table_entry_t prsctp_chunk_event_table[SCTP_NUM_PRSCTP_CHUNK_TYPES][SCTP_STATE_NUM_STATES] = {
 	TYPE_SCTP_FWD_TSN,
 }; /*state_fn_t prsctp_chunk_event_table[][] */
 
@@ -684,7 +695,7 @@
 /* The primary index for this table is the primitive type.
  * The secondary index for this table is the state.
  */
-const sctp_sm_table_entry_t primitive_event_table[SCTP_NUM_PRIMITIVE_TYPES][SCTP_STATE_NUM_STATES] = {
+static const sctp_sm_table_entry_t primitive_event_table[SCTP_NUM_PRIMITIVE_TYPES][SCTP_STATE_NUM_STATES] = {
 	TYPE_SCTP_PRIMITIVE_ASSOCIATE,
 	TYPE_SCTP_PRIMITIVE_SHUTDOWN,
 	TYPE_SCTP_PRIMITIVE_ABORT,
@@ -716,8 +727,31 @@
 	{.fn = sctp_sf_ignore_other, .name = "sctp_sf_ignore_other"}, \
 }
 
-const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_STATE_NUM_STATES] = {
+#define TYPE_SCTP_OTHER_ICMP_PROTO_UNREACH  { \
+	/* SCTP_STATE_EMPTY */ \
+	{.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
+	/* SCTP_STATE_CLOSED */ \
+	{.fn = sctp_sf_ignore_other, .name = "sctp_sf_ignore_other"}, \
+	/* SCTP_STATE_COOKIE_WAIT */ \
+	{.fn = sctp_sf_cookie_wait_icmp_abort, \
+	 .name = "sctp_sf_cookie_wait_icmp_abort"}, \
+	/* SCTP_STATE_COOKIE_ECHOED */ \
+	{.fn = sctp_sf_ignore_other, .name = "sctp_sf_ignore_other"}, \
+	/* SCTP_STATE_ESTABLISHED */ \
+	{.fn = sctp_sf_ignore_other, .name = "sctp_sf_ignore_other"}, \
+	/* SCTP_STATE_SHUTDOWN_PENDING */ \
+	{.fn = sctp_sf_ignore_other, .name = "sctp_sf_ignore_other"}, \
+	/* SCTP_STATE_SHUTDOWN_SENT */ \
+	{.fn = sctp_sf_ignore_other, .name = "sctp_sf_ignore_other"}, \
+	/* SCTP_STATE_SHUTDOWN_RECEIVED */ \
+	{.fn = sctp_sf_ignore_other, .name = "sctp_sf_ignore_other"}, \
+	/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
+	{.fn = sctp_sf_ignore_other, .name = "sctp_sf_ignore_other"}, \
+}
+
+static const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_STATE_NUM_STATES] = {
 	TYPE_SCTP_OTHER_NO_PENDING_TSN,
+	TYPE_SCTP_OTHER_ICMP_PROTO_UNREACH,
 };
 
 #define TYPE_SCTP_EVENT_TIMEOUT_NONE { \
@@ -931,7 +965,7 @@
 	{.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
 }
 
-const sctp_sm_table_entry_t timeout_event_table[SCTP_NUM_TIMEOUT_TYPES][SCTP_STATE_NUM_STATES] = {
+static const sctp_sm_table_entry_t timeout_event_table[SCTP_NUM_TIMEOUT_TYPES][SCTP_STATE_NUM_STATES] = {
 	TYPE_SCTP_EVENT_TIMEOUT_NONE,
 	TYPE_SCTP_EVENT_TIMEOUT_T1_COOKIE,
 	TYPE_SCTP_EVENT_TIMEOUT_T1_INIT,
@@ -944,8 +978,8 @@
 	TYPE_SCTP_EVENT_TIMEOUT_AUTOCLOSE,
 };
 
-const sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t cid, 
-						     sctp_state_t state)
+static const sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t cid, 
+							    sctp_state_t state)
 {
 	if (state > SCTP_STATE_MAX)
 		return &bug;
diff -urN linux-2.4.28-bk7/net/sctp/socket.c linux-2.4.29/net/sctp/socket.c
--- linux-2.4.28-bk7/net/sctp/socket.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/net/sctp/socket.c	2005-01-19 07:08:14.744710955 -0800
@@ -116,7 +116,7 @@
 	struct sock *sk = asoc->base.sk;
 	int amt = 0;
 
-	amt = sk->sk_sndbuf - asoc->sndbuf_used;
+	amt = sk->sndbuf - asoc->sndbuf_used;
 	if (amt < 0)
 		amt = 0;
 	return amt;
@@ -144,7 +144,7 @@
 	*((struct sctp_chunk **)(chunk->skb->cb)) = chunk;
 
 	asoc->sndbuf_used += SCTP_DATA_SNDSIZE(chunk);
-	sk->sk_wmem_queued += SCTP_DATA_SNDSIZE(chunk);
+	sk->wmem_queued += SCTP_DATA_SNDSIZE(chunk);
 }
 
 /* Verify that this is a valid address. */
@@ -203,7 +203,7 @@
  * id are specified, the associations matching the address and the id should be
  * the same.
  */
-struct sctp_transport *sctp_addr_id2transport(struct sock *sk,
+static struct sctp_transport *sctp_addr_id2transport(struct sock *sk,
 					      struct sockaddr_storage *addr,
 					      sctp_assoc_t id)
 {
@@ -224,7 +224,7 @@
 	if (id_asoc && (id_asoc != addr_asoc))
 		return NULL;
 
-	sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk),
+	sctp_get_pf_specific(sk->family)->addr_v4map(sctp_sk(sk),
 						(union sctp_addr *)addr);
 
 	return transport;
@@ -240,7 +240,7 @@
  *             sockaddr_in6 [RFC 2553]),
  *   addr_len - the size of the address structure.
  */
-int sctp_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+SCTP_STATIC int sctp_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
 {
 	int retval = 0;
 
@@ -338,8 +338,8 @@
 	}
 
 	/* Refresh ephemeral port.  */
-	if (!snum)
-		snum = sk->num;
+	if (!bp->port)
+		bp->port = sk->num;
 
 	/* Add the address to the bind address list.  */
 	sctp_local_bh_disable();
@@ -349,8 +349,6 @@
 	addr->v4.sin_port = ntohs(addr->v4.sin_port);
 	ret = sctp_add_bind_addr(bp, addr, GFP_ATOMIC);
 	addr->v4.sin_port = htons(addr->v4.sin_port);
-	if (!ret && !bp->port)
-		bp->port = snum;
 	sctp_write_unlock(&ep->base.addr_lock);
 	sctp_local_bh_enable();
 
@@ -612,7 +610,7 @@
 		}
 
 		/* FIXME - There is probably a need to check if sk->sk_saddr and
-		 * sk->sk_rcv_addr are currently set to one of the addresses to
+		 * sk->rcv_addr are currently set to one of the addresses to
 		 * be removed. This is something which needs to be looked into
 		 * when we are fixing the outstanding issues with multi-homing
 		 * socket routing and failover schemes. Refer to comments in
@@ -951,7 +949,7 @@
 	SCTP_DEBUG_PRINTK("sctp_close(sk: 0x%p, timeout:%ld)\n", sk, timeout);
 
 	sctp_lock_sock(sk);
-	sk->sk_shutdown = SHUTDOWN_MASK;
+	sk->shutdown = SHUTDOWN_MASK;
 
 	ep = sctp_sk(sk)->ep;
 
@@ -969,7 +967,7 @@
 				sctp_unhash_established(asoc);
 				sctp_association_free(asoc);
 
-			} else if (sk->linger && !sk->sk_lingertime)
+			} else if (sk->linger && !sk->lingertime)
 				sctp_primitive_ABORT(asoc, NULL);
 			else
 				sctp_primitive_SHUTDOWN(asoc, NULL);
@@ -978,7 +976,7 @@
 	}
 
 	/* Clean up any skbs sitting on the receive queue.  */
-	sctp_queue_purge_ulpevents(&sk->sk_receive_queue);
+	sctp_queue_purge_ulpevents(&sk->receive_queue);
 	sctp_queue_purge_ulpevents(&sctp_sk(sk)->pd_lobby);
 
 	/* On a TCP-style socket, block for at most linger_time if set. */
@@ -1314,7 +1312,7 @@
 	/* API 7.1.7, the sndbuf size per association bounds the
 	 * maximum size of data that can be sent in a single send call.
 	 */
-	if (msg_len > sk->sk_sndbuf) {
+	if (msg_len > sk->sndbuf) {
 		err = -EMSGSIZE;
 		goto out_free;
 	}
@@ -1551,7 +1549,7 @@
 		if (flags & MSG_PEEK)
 			goto out_free;
 		sctp_skb_pull(skb, copied);
-		skb_queue_head(&sk->sk_receive_queue, skb);
+		skb_queue_head(&sk->receive_queue, skb);
 
 		/* When only partial message is copied to the user, increase
 		 * rwnd by that amount. If all the data in the skb is read,
@@ -1704,10 +1702,13 @@
 	/* update default value for endpoint (all future associations) */
 	if (!params.spp_assoc_id && 
 	    sctp_is_any(( union sctp_addr *)&params.spp_address)) {
-		if (params.spp_hbinterval)
+		/* Manual heartbeat on an endpoint is invalid. */
+		if (0xffffffff == params.spp_hbinterval)
+			return -EINVAL;
+		else if (params.spp_hbinterval)
 			sctp_sk(sk)->paddrparam.spp_hbinterval =
 						params.spp_hbinterval;
-		if (sctp_max_retrans_path)
+		if (params.spp_pathmaxrxt)
 			sctp_sk(sk)->paddrparam.spp_pathmaxrxt =
 						params.spp_pathmaxrxt;
 		return 0;
@@ -1749,7 +1750,8 @@
 	/* spp_pathmaxrxt contains the maximum number of retransmissions
 	 * before this address shall be considered unreachable.
 	 */
-	trans->error_threshold = params.spp_pathmaxrxt;
+	if (params.spp_pathmaxrxt)
+		trans->max_retrans = params.spp_pathmaxrxt;
 
 	return 0;
 }
@@ -2355,7 +2357,7 @@
 	af = sctp_get_af_specific(to.sa.sa_family);
 	af->to_sk_daddr(&to, sk);
 
-	timeo = sock_sndtimeo(sk, sk->sk_socket->file->f_flags & O_NONBLOCK);
+	timeo = sock_sndtimeo(sk, sk->socket->file->f_flags & O_NONBLOCK);
 	err = sctp_wait_for_connect(asoc, &timeo);
 
 out_unlock:
@@ -2401,7 +2403,7 @@
 		goto out;
 	}
 
-	timeo = sock_rcvtimeo(sk, sk->sk_socket->file->f_flags & O_NONBLOCK);
+	timeo = sock_rcvtimeo(sk, sk->socket->file->f_flags & O_NONBLOCK);
 
 	error = sctp_wait_for_accept(sk, timeo);
 	if (error)
@@ -2449,7 +2451,7 @@
 	sp = sctp_sk(sk);
 
 	/* Initialize the SCTP per socket area.  */
-	switch (sk->sk_type) {
+	switch (sk->type) {
 	case SOCK_SEQPACKET:
 		sp->type = SCTP_SOCKET_UDP;
 		break;
@@ -2529,7 +2531,7 @@
 
 	sp->adaption_ind = 0;
 
-	sp->pf = sctp_get_pf_specific(sk->sk_family);
+	sp->pf = sctp_get_pf_specific(sk->family);
 
 	/* Control variables for partial data delivery. */
 	sp->pd_mode           = 0;
@@ -2646,7 +2648,7 @@
 	memcpy(&status.sstat_primary.spinfo_address,
 	       &(transport->ipaddr), sizeof(union sctp_addr));
 	/* Map ipv4 address into v4-mapped-on-v6 address.  */
-	sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk),
+	sctp_get_pf_specific(sk->family)->addr_v4map(sctp_sk(sk),
 		(union sctp_addr *)&status.sstat_primary.spinfo_address);
 	status.sstat_primary.spinfo_state = transport->active;
 	status.sstat_primary.spinfo_cwnd = transport->cwnd;
@@ -2800,7 +2802,7 @@
 		return -EINVAL;
 
 	/* Create a new socket.  */
-	err = sock_create(sk->sk_family, SOCK_SEQPACKET, IPPROTO_SCTP, &sock);
+	err = sock_create(sk->family, SOCK_SEQPACKET, IPPROTO_SCTP, &sock);
 	if (err < 0)
 		return err;
 
@@ -2926,7 +2928,7 @@
 	/* spp_pathmaxrxt contains the maximum number of retransmissions
 	 * before this address shall be considered unreachable.
 	 */
-	params.spp_pathmaxrxt = trans->error_threshold;
+	params.spp_pathmaxrxt = trans->max_retrans;
 
 done:
 	if (copy_to_user(optval, &params, len))
@@ -3014,8 +3016,8 @@
 	list_for_each(pos, &asoc->peer.transport_addr_list) {
 		from = list_entry(pos, struct sctp_transport, transports);
 		memcpy(&temp, &from->ipaddr, sizeof(temp));
-		sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
-		addrlen = sctp_get_af_specific(sk->sk_family)->sockaddr_len;
+		sctp_get_pf_specific(sk->family)->addr_v4map(sp, &temp);
+		addrlen = sctp_get_af_specific(sk->family)->sockaddr_len;
 		temp.v4.sin_port = htons(temp.v4.sin_port);
 		if (copy_to_user(to, &temp, addrlen))
 			return -EFAULT;
@@ -3037,6 +3039,9 @@
 	struct sctp_bind_addr *bp;
 	struct sctp_association *asoc;
 	struct list_head *pos;
+	struct sctp_sockaddr_entry *addr;
+	rwlock_t *addr_lock;
+	unsigned long flags;
 	int cnt = 0;
 
 	if (len != sizeof(sctp_assoc_t))
@@ -3053,33 +3058,103 @@
 	 */
 	if (0 == id) {
 		bp = &sctp_sk(sk)->ep->base.bind_addr;
+		addr_lock = &sctp_sk(sk)->ep->base.addr_lock;
 	} else {
 		asoc = sctp_id2assoc(sk, id);
 		if (!asoc)
 			return -EINVAL;
 		bp = &asoc->base.bind_addr;
+		addr_lock = &asoc->base.addr_lock;
 	}
 
+	sctp_read_lock(addr_lock);
+
+	/* If the endpoint is bound to 0.0.0.0 or ::0, count the valid
+	 * addresses from the global local address list.
+	 */
+	if (sctp_list_single_entry(&bp->address_list)) {
+		addr = list_entry(bp->address_list.next,
+				  struct sctp_sockaddr_entry, list);
+		if (sctp_is_any(&addr->a)) {
+			sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags);
+			list_for_each(pos, &sctp_local_addr_list) {
+				addr = list_entry(pos,
+						  struct sctp_sockaddr_entry,
+						  list);
+				if ((PF_INET == sk->family) &&
+				    (AF_INET6 == addr->a.sa.sa_family))
+					continue;
+				cnt++;
+			}
+			sctp_spin_unlock_irqrestore(&sctp_local_addr_lock,
+						    flags);
+		} else {
+			cnt = 1;
+		}
+		goto done;
+        }
+
 	list_for_each(pos, &bp->address_list) {
 		cnt ++;
 	}
 
+done:
+	sctp_read_unlock(addr_lock);
+	return cnt;
+}
+
+/* Helper function that copies local addresses to user and returns the number
+ * of addresses copied.
+ */
+static int sctp_copy_laddrs_to_user(struct sock *sk, __u16 port, int max_addrs,
+				    void __user *to)
+{
+	struct list_head *pos;
+	struct sctp_sockaddr_entry *addr;
+	unsigned long flags;
+	union sctp_addr temp;
+	int cnt = 0;
+	int addrlen;
+
+	sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags);
+	list_for_each(pos, &sctp_local_addr_list) {
+		addr = list_entry(pos, struct sctp_sockaddr_entry, list);
+		if ((PF_INET == sk->family) &&
+		    (AF_INET6 == addr->a.sa.sa_family))
+			continue;
+		memcpy(&temp, &addr->a, sizeof(temp));
+		sctp_get_pf_specific(sk->family)->addr_v4map(sctp_sk(sk),
+								&temp);
+		addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;		temp.v4.sin_port = htons(port);
+		if (copy_to_user(to, &temp, addrlen)) {
+			sctp_spin_unlock_irqrestore(&sctp_local_addr_lock,
+						    flags);
+			return -EFAULT;
+		}
+		to += addrlen;
+		cnt ++;
+		if (cnt >= max_addrs) break;
+	}
+	sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, flags);
+
 	return cnt;
 }
 
 static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
-					char *optval, int *optlen)
+				       char *optval, int *optlen)
 {
 	struct sctp_bind_addr *bp;
 	struct sctp_association *asoc;
 	struct list_head *pos;
 	int cnt = 0;
 	struct sctp_getaddrs getaddrs;
-	struct sctp_sockaddr_entry *from;
+	struct sctp_sockaddr_entry *addr;
 	void *to;
 	union sctp_addr temp;
 	struct sctp_opt *sp = sctp_sk(sk);
 	int addrlen;
+	rwlock_t *addr_lock;
+	int err = 0;
 
 	if (len != sizeof(struct sctp_getaddrs))
 		return -EINVAL;
@@ -3096,33 +3171,59 @@
 	 */
 	if (0 == getaddrs.assoc_id) {
 		bp = &sctp_sk(sk)->ep->base.bind_addr;
+		addr_lock = &sctp_sk(sk)->ep->base.addr_lock;
 	} else {
 		asoc = sctp_id2assoc(sk, getaddrs.assoc_id);
 		if (!asoc)
 			return -EINVAL;
 		bp = &asoc->base.bind_addr;
+		addr_lock = &asoc->base.addr_lock;
 	}
 
 	to = (void *)getaddrs.addrs;
+
+	sctp_read_lock(addr_lock);
+
+	/* If the endpoint is bound to 0.0.0.0 or ::0, get the valid
+	 * addresses from the global local address list.
+	 */
+	if (sctp_list_single_entry(&bp->address_list)) {
+		addr = list_entry(bp->address_list.next,
+				  struct sctp_sockaddr_entry, list);
+		if (sctp_is_any(&addr->a)) {
+			cnt = sctp_copy_laddrs_to_user(sk, bp->port,
+						       getaddrs.addr_num, to);
+			if (cnt < 0) {
+				err = cnt;
+				goto unlock;
+			}
+			goto copy_getaddrs;
+		}
+	}
+
 	list_for_each(pos, &bp->address_list) {
-		from = list_entry(pos,
-				struct sctp_sockaddr_entry,
-				list);
-		memcpy(&temp, &from->a, sizeof(temp));
-		sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
+		addr = list_entry(pos, struct sctp_sockaddr_entry, list);
+		memcpy(&temp, &addr->a, sizeof(temp));
+		sctp_get_pf_specific(sk->family)->addr_v4map(sp, &temp);
 		addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
 		temp.v4.sin_port = htons(temp.v4.sin_port);
-		if (copy_to_user(to, &temp, addrlen))
-			return -EFAULT;
+		if (copy_to_user(to, &temp, addrlen)) {
+			err = -EFAULT;
+			goto unlock;
+		}
 		to += addrlen;
 		cnt ++;
 		if (cnt >= getaddrs.addr_num) break;
 	}
+
+copy_getaddrs:
 	getaddrs.addr_num = cnt;
 	if (copy_to_user(optval, &getaddrs, sizeof(struct sctp_getaddrs)))
-		return -EFAULT;
+		err = -EFAULT;
 
-	return 0;
+unlock:
+	sctp_read_unlock(addr_lock);
+	return err;
 }
 
 /* 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR)
@@ -3158,7 +3259,7 @@
 	asoc->peer.primary_path->ipaddr.v4.sin_port =
 		ntohs(asoc->peer.primary_path->ipaddr.v4.sin_port);
 
-	sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp,
+	sctp_get_pf_specific(sk->family)->addr_v4map(sp,
 			(union sctp_addr *)&prim.ssp_addr);
 
 	if (copy_to_user(optval, &prim, sizeof(struct sctp_prim)))
@@ -3662,12 +3763,12 @@
 		 * used by other socket (pp->sk != NULL); that other
 		 * socket is going to be sk2.
 		 */
-		int sk_reuse = sk->sk_reuse;
+		int reuse = sk->reuse;
 		struct sock *sk2 = pp->sk;
 
 		SCTP_DEBUG_PRINTK("sctp_get_port() found a "
 				  "possible match\n");
-		if (pp->fastreuse != 0 && sk->sk_reuse != 0)
+		if (pp->fastreuse != 0 && sk->reuse != 0)
 			goto success;
 
 		/* Run through the list of sockets bound to the port
@@ -3684,7 +3785,7 @@
 			struct sctp_endpoint *ep2;
 			ep2 = sctp_sk(sk2)->ep;
 
-			if (sk_reuse && sk2->sk_reuse)
+			if (reuse && sk2->reuse)
 				continue;
 
 			if (sctp_bind_addr_match(&ep2->base.bind_addr, addr,
@@ -3708,12 +3809,12 @@
 		goto fail_unlock;
 
 	/* In either case (hit or miss), make sure fastreuse is 1 only
-	 * if sk->sk_reuse is too (that is, if the caller requested
+	 * if sk->reuse is too (that is, if the caller requested
 	 * SO_REUSEADDR on this socket -sk-).
 	 */
 	if (!pp->sk)
-		pp->fastreuse = sk->sk_reuse ? 1 : 0;
-	else if (pp->fastreuse && sk->sk_reuse == 0)
+		pp->fastreuse = sk->reuse ? 1 : 0;
+	else if (pp->fastreuse && sk->reuse == 0)
 		pp->fastreuse = 0;
 
 	/* We are set, so fill up all the data in the hash table
@@ -3785,7 +3886,7 @@
 			return 0;
 		
 		sctp_unhash_endpoint(ep);
-		sk->sk_state = SCTP_SS_CLOSED;
+		sk->state = SCTP_SS_CLOSED;
 	}
 
 	/* Return if we are already listening. */
@@ -3806,7 +3907,7 @@
 		if (sctp_autobind(sk))
 			return -EAGAIN;
 	}
-	sk->sk_state = SCTP_SS_LISTENING;
+	sk->state = SCTP_SS_LISTENING;
 	sctp_hash_endpoint(ep);
 	return 0;
 }
@@ -3828,7 +3929,7 @@
 			return 0;
 		
 		sctp_unhash_endpoint(ep);
-		sk->sk_state = SCTP_SS_CLOSED;
+		sk->state = SCTP_SS_CLOSED;
 	}
 
 	if (sctp_sstate(sk, LISTENING))
@@ -3848,8 +3949,8 @@
 		if (sctp_autobind(sk))
 			return -EAGAIN;
 	}
-	sk->sk_state = SCTP_SS_LISTENING;
-	sk->sk_max_ack_backlog = backlog;
+	sk->state = SCTP_SS_LISTENING;
+	sk->max_ack_backlog = backlog;
 	sctp_hash_endpoint(ep);
 	return 0;
 }
@@ -3923,7 +4024,7 @@
 	struct sctp_opt *sp = sctp_sk(sk);
 	unsigned int mask;
 
-	poll_wait(file, sk->sk_sleep, wait);
+	poll_wait(file, sk->sleep, wait);
 
 	/* A TCP-style listening socket becomes readable when the accept queue
 	 * is not empty.
@@ -3935,14 +4036,14 @@
 	mask = 0;
 
 	/* Is there any exceptional events?  */
-	if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
+	if (sk->err || !skb_queue_empty(&sk->error_queue))
 		mask |= POLLERR;
-	if (sk->sk_shutdown == SHUTDOWN_MASK)
+	if (sk->shutdown == SHUTDOWN_MASK)
 		mask |= POLLHUP;
 
 	/* Is it readable?  Reconsider this code with TCP-style support.  */
-	if (!skb_queue_empty(&sk->sk_receive_queue) ||
-	    (sk->sk_shutdown & RCV_SHUTDOWN))
+	if (!skb_queue_empty(&sk->receive_queue) ||
+	    (sk->shutdown & RCV_SHUTDOWN))
 		mask |= POLLIN | POLLRDNORM;
 
 	/* The association is either gone or not ready.  */
@@ -3953,7 +4054,7 @@
 	if (sctp_writeable(sk)) {
 		mask |= POLLOUT | POLLWRNORM;
 	} else {
-		set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
+		set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
 		/*
 		 * Since the socket is not locked, the buffer
 		 * might be made available after the writeable check and
@@ -4090,12 +4191,8 @@
 	for (cmsg = CMSG_FIRSTHDR(msg);
 	     cmsg != NULL;
 	     cmsg = CMSG_NXTHDR((struct msghdr*)msg, cmsg)) {
-		/* Check for minimum length.  The SCM code has this check.  */
-		if (cmsg->cmsg_len < sizeof(struct cmsghdr) ||
-		    (unsigned long)(((char*)cmsg - (char*)msg->msg_control)
-				    + cmsg->cmsg_len) > msg->msg_controllen) {
+		if (!CMSG_OK(msg, cmsg))
 			return -EINVAL;
-		}
 
 		/* Should we parse this header or ignore?  */
 		if (cmsg->cmsg_level != IPPROTO_SCTP)
@@ -4166,7 +4263,7 @@
 	int error;
 	DECLARE_WAITQUEUE(wait, current);
 
-	add_wait_queue_exclusive(sk->sk_sleep, &wait);
+	add_wait_queue_exclusive(sk->sleep, &wait);
 	__set_current_state(TASK_INTERRUPTIBLE);
 
 	/* Socket errors? */
@@ -4174,11 +4271,11 @@
 	if (error)
 		goto out;
 
-	if (!skb_queue_empty(&sk->sk_receive_queue))
+	if (!skb_queue_empty(&sk->receive_queue))
 		goto ready;
 
 	/* Socket shut down?  */
-	if (sk->sk_shutdown & RCV_SHUTDOWN)
+	if (sk->shutdown & RCV_SHUTDOWN)
 		goto out;
 
 	/* Sequenced packets can come disconnected.  If so we report the
@@ -4204,7 +4301,7 @@
 	sctp_lock_sock(sk);
 
 ready:
-	remove_wait_queue(sk->sk_sleep, &wait);
+	remove_wait_queue(sk->sleep, &wait);
 	__set_current_state(TASK_RUNNING);
 	return 0;
 
@@ -4212,7 +4309,7 @@
 	error = sock_intr_errno(*timeo_p);
 
 out:
-	remove_wait_queue(sk->sk_sleep, &wait);
+	remove_wait_queue(sk->sleep, &wait);
 	__set_current_state(TASK_RUNNING);
 	*err = error;
 	return error;
@@ -4229,7 +4326,7 @@
 	struct sk_buff *skb;
 	long timeo;
 
-	/* Caller is allowed not to check sk->sk_err before calling.  */
+	/* Caller is allowed not to check sk->err before calling.  */
 	error = sock_error(sk);
 	if (error)
 		goto no_packet;
@@ -4250,21 +4347,21 @@
 		if (flags & MSG_PEEK) {
 			unsigned long cpu_flags;
 
-			sctp_spin_lock_irqsave(&sk->sk_receive_queue.lock,
+			sctp_spin_lock_irqsave(&sk->receive_queue.lock,
 					       cpu_flags);
-			skb = skb_peek(&sk->sk_receive_queue);
+			skb = skb_peek(&sk->receive_queue);
 			if (skb)
 				atomic_inc(&skb->users);
-			sctp_spin_unlock_irqrestore(&sk->sk_receive_queue.lock,
+			sctp_spin_unlock_irqrestore(&sk->receive_queue.lock,
 						    cpu_flags);
 		} else {
-			skb = skb_dequeue(&sk->sk_receive_queue);
+			skb = skb_dequeue(&sk->receive_queue);
 		}
 
 		if (skb)
 			return skb;
 
-		if (sk->sk_shutdown & RCV_SHUTDOWN)
+		if (sk->shutdown & RCV_SHUTDOWN)
 			break;
 
 		/* User doesn't want to wait.  */
@@ -4284,22 +4381,22 @@
 static void __sctp_write_space(struct sctp_association *asoc)
 {
 	struct sock *sk = asoc->base.sk;
-	struct socket *sock = sk->sk_socket;
+	struct socket *sock = sk->socket;
 
 	if ((sctp_wspace(asoc) > 0) && sock) {
 		if (waitqueue_active(&asoc->wait))
 			wake_up_interruptible(&asoc->wait);
 
 		if (sctp_writeable(sk)) {
-			if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
-				wake_up_interruptible(sk->sk_sleep);
+			if (sk->sleep && waitqueue_active(sk->sleep))
+				wake_up_interruptible(sk->sleep);
 
 			/* Note that we try to include the Async I/O support
 			 * here by modeling from the current TCP/UDP code.
 			 * We have not tested with it yet.
 			 */
 			if (sock->fasync_list &&
-			    !(sk->sk_shutdown & SEND_SHUTDOWN))
+			    !(sk->shutdown & SEND_SHUTDOWN))
 				sock_wake_async(sock, 2, POLL_OUT);
 		}
 	}
@@ -4320,7 +4417,7 @@
 	asoc = chunk->asoc;
 	sk = asoc->base.sk;
 	asoc->sndbuf_used -= SCTP_DATA_SNDSIZE(chunk);
-	sk->sk_wmem_queued -= SCTP_DATA_SNDSIZE(chunk);
+	sk->wmem_queued -= SCTP_DATA_SNDSIZE(chunk);
 	__sctp_write_space(asoc);
 
 	sctp_association_put(asoc);
@@ -4349,7 +4446,7 @@
 		__set_current_state(TASK_INTERRUPTIBLE);
 		if (!*timeo_p)
 			goto do_nonblock;
-		if (sk->sk_err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING ||
+		if (sk->err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING ||
 		    asoc->base.dead)
 			goto do_error;
 		if (signal_pending(current))
@@ -4417,7 +4514,7 @@
 {
 	int amt = 0;
 
-	amt = sk->sk_sndbuf - sk->sk_wmem_queued;
+	amt = sk->sndbuf - sk->wmem_queued;
 	if (amt < 0)
 		amt = 0;
 	return amt;
@@ -4444,9 +4541,9 @@
 		__set_current_state(TASK_INTERRUPTIBLE);
 		if (!*timeo_p)
 			goto do_nonblock;
-		if (sk->sk_shutdown & RCV_SHUTDOWN)
+		if (sk->shutdown & RCV_SHUTDOWN)
 			break;
-		if (sk->sk_err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING ||
+		if (sk->err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING ||
 		    asoc->base.dead)
 			goto do_error;
 		if (signal_pending(current))
@@ -4499,7 +4596,7 @@
 
 	ep = sctp_sk(sk)->ep;
 
-	add_wait_queue_exclusive(sk->sk_sleep, &wait);
+	add_wait_queue_exclusive(sk->sleep, &wait);
 
 	for (;;) {
 		__set_current_state(TASK_INTERRUPTIBLE);
@@ -4526,7 +4623,7 @@
 			break;
 	}
 
-	remove_wait_queue(sk->sk_sleep, &wait);
+	remove_wait_queue(sk->sleep, &wait);
 	__set_current_state(TASK_RUNNING);	
 
 	return err;
@@ -4536,7 +4633,7 @@
 {
 	DECLARE_WAITQUEUE(wait, current);
 
-	add_wait_queue_exclusive(sk->sk_sleep, &wait);
+	add_wait_queue_exclusive(sk->sleep, &wait);
 
 	do {
 		__set_current_state(TASK_INTERRUPTIBLE);
@@ -4547,7 +4644,7 @@
 		sctp_lock_sock(sk);
 	} while (!signal_pending(current) && timeout);
 
-	remove_wait_queue(sk->sk_sleep, &wait);
+	remove_wait_queue(sk->sleep, &wait);
 	__set_current_state(TASK_RUNNING);	
 }
 
@@ -4567,8 +4664,8 @@
 	/* Migrate socket buffer sizes and all the socket level options to the
 	 * new socket.
 	 */
-	newsk->sk_sndbuf = oldsk->sk_sndbuf;
-	newsk->sk_rcvbuf = oldsk->sk_rcvbuf;
+	newsk->sndbuf = oldsk->sndbuf;
+	newsk->rcvbuf = oldsk->rcvbuf;
 	/* Brute force copy old sctp opt. */
 	memcpy(newsp, oldsp, sizeof(struct sctp_opt));
 
@@ -4583,11 +4680,11 @@
 	/* Move any messages in the old socket's receive queue that are for the
 	 * peeled off association to the new socket's receive queue.
 	 */
-	sctp_skb_for_each(skb, &oldsk->sk_receive_queue, tmp) {
+	sctp_skb_for_each(skb, &oldsk->receive_queue, tmp) {
 		event = sctp_skb2event(skb);
 		if (event->asoc == assoc) {
 			__skb_unlink(skb, skb->list);
-			__skb_queue_tail(&newsk->sk_receive_queue, skb);
+			__skb_queue_tail(&newsk->receive_queue, skb);
 		}
 	}
 
@@ -4607,7 +4704,7 @@
 		if (assoc->ulpq.pd_mode) {
 			queue = &newsp->pd_lobby;
 		} else
-			queue = &newsk->sk_receive_queue;
+			queue = &newsk->receive_queue;
 
 		/* Walk through the pd_lobby, looking for skbs that
 		 * need moved to the new socket.
@@ -4641,9 +4738,9 @@
 	 * is called, set RCV_SHUTDOWN flag.
 	 */
 	if (sctp_state(assoc, CLOSED) && sctp_style(newsk, TCP))
-		newsk->sk_shutdown |= RCV_SHUTDOWN;
+		newsk->shutdown |= RCV_SHUTDOWN;
 
-	newsk->sk_state = SCTP_SS_ESTABLISHED;
+	newsk->state = SCTP_SS_ESTABLISHED;
 }
 
 /* This proto struct describes the ULP interface for SCTP.  */
diff -urN linux-2.4.28-bk7/net/sctp/ssnmap.c linux-2.4.29/net/sctp/ssnmap.c
--- linux-2.4.28-bk7/net/sctp/ssnmap.c	2004-04-14 06:05:41.000000000 -0700
+++ linux-2.4.29/net/sctp/ssnmap.c	2005-01-19 07:08:14.745710998 -0800
@@ -42,6 +42,9 @@
 
 #define MAX_KMALLOC_SIZE	131072
 
+static struct sctp_ssnmap *sctp_ssnmap_init(struct sctp_ssnmap *map, __u16 in,
+					    __u16 out);
+
 /* Storage size needed for map includes 2 headers and then the
  * specific needs of in or out streams.
  */
@@ -87,8 +90,8 @@
 
 
 /* Initialize a block of memory as a ssnmap.  */
-struct sctp_ssnmap *sctp_ssnmap_init(struct sctp_ssnmap *map, __u16 in,
-				     __u16 out)
+static struct sctp_ssnmap *sctp_ssnmap_init(struct sctp_ssnmap *map, __u16 in,
+					    __u16 out)
 {
 	memset(map, 0x00, sctp_ssnmap_size(in, out));
 
diff -urN linux-2.4.28-bk7/net/sctp/transport.c linux-2.4.29/net/sctp/transport.c
--- linux-2.4.28-bk7/net/sctp/transport.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/net/sctp/transport.c	2005-01-19 07:08:14.746711041 -0800
@@ -54,34 +54,10 @@
 
 /* 1st Level Abstractions.  */
 
-/* Allocate and initialize a new transport.  */
-struct sctp_transport *sctp_transport_new(const union sctp_addr *addr, int gfp)
-{
-        struct sctp_transport *transport;
-
-        transport = t_new(struct sctp_transport, gfp);
-	if (!transport)
-		goto fail;
-
-	if (!sctp_transport_init(transport, addr, gfp))
-		goto fail_init;
-
-	transport->malloced = 1;
-	SCTP_DBG_OBJCNT_INC(transport);
-
-	return transport;
-
-fail_init:
-	kfree(transport);
-
-fail:
-	return NULL;
-}
-
 /* Initialize a new transport from provided memory.  */
-struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
-					   const union sctp_addr *addr,
-					   int gfp)
+static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
+						  const union sctp_addr *addr,
+						  int gfp)
 {
 	/* Copy in the address.  */
 	peer->ipaddr = *addr;
@@ -112,7 +88,6 @@
 
 	/* Initialize the default path max_retrans.  */
 	peer->max_retrans = sctp_max_retrans_path;
-	peer->error_threshold = 0;
 	peer->error_count = 0;
 
 	INIT_LIST_HEAD(&peer->transmitted);
@@ -144,6 +119,30 @@
 	return peer;
 }
 
+/* Allocate and initialize a new transport.  */
+struct sctp_transport *sctp_transport_new(const union sctp_addr *addr, int gfp)
+{
+        struct sctp_transport *transport;
+
+        transport = t_new(struct sctp_transport, gfp);
+	if (!transport)
+		goto fail;
+
+	if (!sctp_transport_init(transport, addr, gfp))
+		goto fail_init;
+
+	transport->malloced = 1;
+	SCTP_DBG_OBJCNT_INC(transport);
+
+	return transport;
+
+fail_init:
+	kfree(transport);
+
+fail:
+	return NULL;
+}
+
 /* This transport is no longer needed.  Free up if possible, or
  * delay until it last reference count.
  */
@@ -155,13 +154,23 @@
 	if (del_timer(&transport->hb_timer))
 		sctp_transport_put(transport);
 
+	/* Delete the T3_rtx timer if it's active.
+	 * There is no point in not doing this now and letting
+	 * structure hang around in memory since we know
+	 * the tranport is going away.
+	 */
+	if (timer_pending(&transport->T3_rtx_timer) &&
+	    del_timer(&transport->T3_rtx_timer))
+		sctp_transport_put(transport);
+
+
 	sctp_transport_put(transport);
 }
 
 /* Destroy the transport data structure.
  * Assumes there are no more users of this structure.
  */
-void sctp_transport_destroy(struct sctp_transport *transport)
+static void sctp_transport_destroy(struct sctp_transport *transport)
 {
 	SCTP_ASSERT(transport->dead, "Transport is not dead", return);
 
diff -urN linux-2.4.28-bk7/net/sctp/tsnmap.c linux-2.4.29/net/sctp/tsnmap.c
--- linux-2.4.28-bk7/net/sctp/tsnmap.c	2004-08-07 16:26:07.000000000 -0700
+++ linux-2.4.29/net/sctp/tsnmap.c	2005-01-19 07:08:14.746711041 -0800
@@ -52,29 +52,6 @@
 				     int *started, __u16 *start,
 				     int *ended, __u16 *end);
 
-/* Create a new sctp_tsnmap.
- * Allocate room to store at least 'len' contiguous TSNs.
- */
-struct sctp_tsnmap *sctp_tsnmap_new(__u16 len, __u32 initial_tsn, int gfp)
-{
-	struct sctp_tsnmap *retval;
-
-	retval = kmalloc(sizeof(struct sctp_tsnmap) +
-			 sctp_tsnmap_storage_size(len), gfp);
-	if (!retval)
-		goto fail;
-
-	if (!sctp_tsnmap_init(retval, len, initial_tsn))
-		goto fail_map;
-	retval->malloced = 1;
-	return retval;
-
-fail_map:
-	kfree(retval);
-fail:
-	return NULL;
-}
-
 /* Initialize a block of memory as a tsnmap.  */
 struct sctp_tsnmap *sctp_tsnmap_init(struct sctp_tsnmap *map, __u16 len,
 				     __u32 initial_tsn)
@@ -168,16 +145,9 @@
 }
 
 
-/* Dispose of a tsnmap.  */
-void sctp_tsnmap_free(struct sctp_tsnmap *map)
-{
-	if (map->malloced)
-		kfree(map);
-}
-
 /* Initialize a Gap Ack Block iterator from memory being provided.  */
-void sctp_tsnmap_iter_init(const struct sctp_tsnmap *map,
-			   struct sctp_tsnmap_iter *iter)
+SCTP_STATIC void sctp_tsnmap_iter_init(const struct sctp_tsnmap *map,
+				       struct sctp_tsnmap_iter *iter)
 {
 	/* Only start looking one past the Cumulative TSN Ack Point.  */
 	iter->start = map->cumulative_tsn_ack_point + 1;
@@ -186,8 +156,9 @@
 /* Get the next Gap Ack Blocks. Returns 0 if there was not another block
  * to get.
  */
-int sctp_tsnmap_next_gap_ack(const struct sctp_tsnmap *map,
-	struct sctp_tsnmap_iter *iter, __u16 *start, __u16 *end)
+SCTP_STATIC int sctp_tsnmap_next_gap_ack(const struct sctp_tsnmap *map,
+					 struct sctp_tsnmap_iter *iter,
+					 __u16 *start, __u16 *end)
 {
 	int started, ended;
 	__u16 _start, _end, offset;
diff -urN linux-2.4.28-bk7/net/sctp/ulpevent.c linux-2.4.29/net/sctp/ulpevent.c
--- linux-2.4.28-bk7/net/sctp/ulpevent.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/net/sctp/ulpevent.c	2005-01-19 07:08:14.747711085 -0800
@@ -65,8 +65,16 @@
  */
 }
 
+/* Initialize an ULP event from an given skb.  */
+SCTP_STATIC void sctp_ulpevent_init(struct sctp_ulpevent *event, int msg_flags)
+{
+	memset(event, 0, sizeof(struct sctp_ulpevent));
+	event->msg_flags = msg_flags;
+}
+
 /* Create a new sctp_ulpevent.  */
-struct sctp_ulpevent *sctp_ulpevent_new(int size, int msg_flags, int gfp)
+SCTP_STATIC struct sctp_ulpevent *sctp_ulpevent_new(int size, int msg_flags,
+						    int gfp)
 {
 	struct sctp_ulpevent *event;
 	struct sk_buff *skb;
@@ -84,13 +92,6 @@
 	return NULL;
 }
 
-/* Initialize an ULP event from an given skb.  */
-void sctp_ulpevent_init(struct sctp_ulpevent *event, int msg_flags)
-{
-	memset(event, 0, sizeof(struct sctp_ulpevent));
-	event->msg_flags = msg_flags;
-}
-
 /* Is this a MSG_NOTIFICATION?  */
 int sctp_ulpevent_is_notification(const struct sctp_ulpevent *event)
 {
@@ -322,7 +323,7 @@
 	memcpy(&spc->spc_aaddr, aaddr, sizeof(struct sockaddr_storage));
 
 	/* Map ipv4 address into v4-mapped-on-v6 address.  */
-	sctp_get_pf_specific(asoc->base.sk->sk_family)->addr_v4map(
+	sctp_get_pf_specific(asoc->base.sk->family)->addr_v4map(
 					sctp_sk(asoc->base.sk),
 					(union sctp_addr *)&spc->spc_aaddr);
 
diff -urN linux-2.4.28-bk7/net/sctp/ulpqueue.c linux-2.4.29/net/sctp/ulpqueue.c
--- linux-2.4.28-bk7/net/sctp/ulpqueue.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29/net/sctp/ulpqueue.c	2005-01-19 07:08:14.748711128 -0800
@@ -56,25 +56,6 @@
 
 /* 1st Level Abstractions */
 
-/* Create a new ULP queue.  */
-struct sctp_ulpq *sctp_ulpq_new(struct sctp_association *asoc, int gfp)
-{
-	struct sctp_ulpq *ulpq;
-
-	ulpq = kmalloc(sizeof(struct sctp_ulpq), gfp);
-	if (!ulpq)
-		goto fail;
-	if (!sctp_ulpq_init(ulpq, asoc))
-		goto fail_init;
-	ulpq->malloced = 1;
-	return ulpq;
-
-fail_init:
-	kfree(ulpq);
-fail:
-	return NULL;
-}
-
 /* Initialize a ULP queue from a block of memory.  */
 struct sctp_ulpq *sctp_ulpq_init(struct sctp_ulpq *ulpq,
 				 struct sctp_association *asoc)
@@ -92,7 +73,7 @@
 
 
 /* Flush the reassembly and ordering queues.  */
-void sctp_ulpq_flush(struct sctp_ulpq *ulpq)
+static void sctp_ulpq_flush(struct sctp_ulpq *ulpq)
 {
 	struct sk_buff *skb;
 	struct sctp_ulpevent *event;
@@ -163,7 +144,7 @@
 	sp->pd_mode = 0;
 	if (!skb_queue_empty(&sp->pd_lobby)) {
 		struct list_head *list;
-		sctp_skb_list_tail(&sp->pd_lobby, &sk->sk_receive_queue);
+		sctp_skb_list_tail(&sp->pd_lobby, &sk->receive_queue);
 		list = (struct list_head *)&sctp_sk(sk)->pd_lobby;
 		INIT_LIST_HEAD(list);
 		return 1;
@@ -189,7 +170,7 @@
 	/* If the socket is just going to throw this away, do not
 	 * even try to deliver it.
 	 */
-	if (sk->dead || (sk->sk_shutdown & RCV_SHUTDOWN))
+	if (sk->dead || (sk->shutdown & RCV_SHUTDOWN))
 		goto out_free;
 
 	/* Check if the user wishes to receive this event.  */
@@ -202,13 +183,13 @@
 	 */
 
 	if (!sctp_sk(sk)->pd_mode) {
-		queue = &sk->sk_receive_queue;
+		queue = &sk->receive_queue;
 	} else if (ulpq->pd_mode) {
 		if (event->msg_flags & MSG_NOTIFICATION)
 		       	queue = &sctp_sk(sk)->pd_lobby;
 		else {
 			clear_pd = event->msg_flags & MSG_EOR;
-			queue = &sk->sk_receive_queue;
+			queue = &sk->receive_queue;
 		}
 	} else
 		queue = &sctp_sk(sk)->pd_lobby;
@@ -229,8 +210,8 @@
 	if (clear_pd)
 		sctp_ulpq_clear_pd(ulpq);
 
-	if (queue == &sk->sk_receive_queue)
-		sk->sk_data_ready(sk, 0);
+	if (queue == &sk->receive_queue)
+		sk->data_ready(sk, 0);
 	return 1;
 
 out_free:
@@ -837,7 +818,7 @@
 
 	freed = 0;
 
-	if (skb_queue_empty(&asoc->base.sk->sk_receive_queue)) {
+	if (skb_queue_empty(&asoc->base.sk->receive_queue)) {
 		freed = sctp_ulpq_renege_order(ulpq, needed);
 		if (freed < needed) {
 			freed += sctp_ulpq_renege_frags(ulpq, needed - freed);
@@ -876,9 +857,9 @@
 					      SCTP_PARTIAL_DELIVERY_ABORTED,
 					      gfp);
 	if (ev)
-		__skb_queue_tail(&sk->sk_receive_queue, sctp_event2skb(ev));
+		__skb_queue_tail(&sk->receive_queue, sctp_event2skb(ev));
 
 	/* If there is data waiting, send it up the socket now. */
 	if (sctp_ulpq_clear_pd(ulpq) || ev)
-		sk->sk_data_ready(sk, 0);
+		sk->data_ready(sk, 0);
 }
